Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions holoviews/plotting/bokeh/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -648,13 +648,18 @@ def _get_hover_data(self, data, element, dimensions=None):
If empty initializes with no data.

"""
if 'hover' not in self.handles or self.static_source:
has_hover = 'hover' in self.handles
if not has_hover and not self.overlay_dims:
return

for d in (dimensions or element.dimensions()):
dim = util.dimension_sanitizer(d.name)
if dim not in data:
data[dim] = element.dimension_values(d)
if has_hover and not self.static_source:
for d in (dimensions or element.dimensions()):
dim = util.dimension_sanitizer(d.name)
if dim not in data:
data[dim] = element.dimension_values(d)

if not data:
return

for k, v in self.overlay_dims.items():
dim = util.dimension_sanitizer(k.name)
Expand Down Expand Up @@ -3596,6 +3601,14 @@ def update_frame(self, key, ranges=None, element=None):
if not self.tabs:
init_kwargs['plot'] = self.handles['plot']
self._create_dynamic_subplots(key, items, ranges, **init_kwargs)
if overlay_hover := self.handles.get('hover'):
if overlay_hover.renderers == 'auto':
overlay_hover.renderers = []
for k, _ in items:
if k in self.subplots and 'glyph_renderer' in self.subplots[k].handles:
renderer = self.subplots[k].handles['glyph_renderer']
if renderer not in overlay_hover.renderers:
overlay_hover.renderers.append(renderer)
if not self.overlaid and not self.tabs:
self._process_legend(element)

Expand Down
37 changes: 37 additions & 0 deletions holoviews/tests/ui/bokeh/test_hover.py
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,43 @@ def test_hover_heatmap_image(serve_hv, x_axis_type, y_axis_type):
expect(tooltip).to_contain_text("z: 53")


@pytest.mark.usefixtures("bokeh_backend")
def test_hover_across_dynamicmaps(serve_panel):
data = pd.DataFrame({"x": range(2), "y": range(2), "category": ["A", "B"]})
el = (
hv.Dataset(data)
.to(hv.Points, kdims=["x", "y"], groupby="category")
.opts(tools=["hover"], size=10, show_legend=False, xlim=(-1, 3), ylim=(-1, 3), hit_dilation=100)
)
widget = pn.widgets.MultiSelect(value=["A"], options=["A", "B"])
dmap = hv.DynamicMap(
lambda value: el.get(value).overlay(),
streams=[widget.param.value]
)
col = pn.Column(widget, dmap)
page = serve_panel(col)

hv_plot = page.locator(".bk-events")
expect(hv_plot).to_have_count(1)
bbox = hv_plot.bounding_box()

for i, cat in enumerate(("A", "B")):
widget.value = [cat]
page.mouse.move(bbox["x"] + bbox["width"] / 2, bbox["y"] + bbox["height"] / 2)
page.mouse.up()
tooltip = page.locator(".bk-Tooltip")
expect(tooltip).to_have_count(1)
expect(tooltip.first).to_contain_text(f"category: {cat} x: {i} y: {i}")

widget.value = ["A", "B"]
page.mouse.move(bbox["x"] + bbox["width"] / 2, bbox["y"] + bbox["height"] / 2)
page.mouse.up()
tooltip = page.locator(".bk-Tooltip")
expect(tooltip).to_have_count(2)
expect(tooltip.first).to_contain_text("category: A x: 0 y: 0")
expect(tooltip.last).to_contain_text("category: B x: 1 y: 1")


@pytest.mark.usefixtures("bokeh_backend")
def test_hover_heatmap_categorical_outside_plot_area(serve_hv, caplog):
# Test for https://github.com/holoviz/holoviews/pull/6438
Expand Down
Loading