I’m not entirely sure I understand your situation correctly, I’m especially unsure what kind of glyphs you are using on your plot as that could be limiting your options.
If you select your figures with the selection tools you should be able to get a list of them and make every figure not in the list opaque.
If that’s not an option you can do what I did (I worked with image-glyphs so selection was a no-no) which is pretty much the same as the alternative you mentioned:
Using a multi-polygon and creating holes for the selected area.
My selection-area is always rectangular, since I’m using the EditBoxTool so the code would be different for you. If you use a SelectionTool you could do the same by checking the bounds from the SelectionGeometry-Event
This is what I used, it’s ripped out of context and can’t be used as-is but it should be a decent start. If something is not clear (but you think the example could help) I’m happy to assist
Example
self.img_shadow = self.plot.multi_polygons(color=['grey'], alpha=0.4)
self.roi_renderer = self.plot.rect('x', 'y', 'width', 'height',
source=ColumnDataSource(data=dict(x=[], y=[], width=[], height=[])),
fill_alpha=0.0)
self.roi_renderer.data_source.on_change("data", lambda attr, old, new: __adjust_roi_shadow_overlay(new))
BoxEditTool(num_objects=1, renderers=[self.roi_renderer]) # add this to your plot
def __adjust_roi_shadow_overlay(self, roi_bounds):
data = dict(self.img_shadow.data_source.data)
# reset polygon bounds
data['xs'] = [[[]]]
data['ys'] = [[[]]]
# if roi was not deleted (has a height)
if roi_bounds['height']:
sx = self.img.data_source.data['dw']
sy = self.img.data_source.data['dh']
img_poly_xs = [0, sx, sx, 0]
img_poly_ys = [0, 0, sy, sy]
x_start = roi_bounds['x'][0] - 0.5 * roi_bounds['width'][0]
x_end = roi_bounds['x'][0] + 0.5 * roi_bounds['width'][0]
y_start = roi_bounds['y'][0] - 0.5 * roi_bounds['height'][0]
y_end = roi_bounds['y'][0] + 0.5 * roi_bounds['height'][0]
hole_xs = [x_start, x_end, x_end, x_start]
hole_ys = [y_start, y_start, y_end, y_end]
data['xs'][0][0].extend((img_poly_xs, hole_xs))
data['ys'][0][0].extend((img_poly_ys, hole_ys))
self.img_shadow.visible = True
else: # roi deleted
# necessary hack to not reset fill_color
data['xs'][0][0].append([0])
data['ys'][0][0].append([0])
self.img_shadow.visible = False
self.img_shadow.data_source.data = dict(data)