Skip to content

Commit

Permalink
Allow to link to an Overlay (#5881)
Browse files Browse the repository at this point in the history
  • Loading branch information
maximlt authored Sep 14, 2023
1 parent 923cd27 commit 3f96806
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 4 deletions.
6 changes: 6 additions & 0 deletions holoviews/core/overlay.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,12 @@ def ddims(self):
def shape(self):
raise NotImplementedError

def clone(self, data=None, shared_data=True, new_type=None, link=True,
*args, **overrides):
if data is None and link:
overrides['plot_id'] = self._plot_id
return super().clone(data, shared_data=shared_data, new_type=new_type, link=link, *args, **overrides)

This comment has been minimized.

Copy link
@hoxbro


class NdOverlay(Overlayable, UniformNdMapping, CompositeOverlay):
"""
Expand Down
2 changes: 1 addition & 1 deletion holoviews/plotting/bokeh/links.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def find_links(cls, root_plot):
Traverses the supplied plot and searches for any Links on
the plotted objects.
"""
plot_fn = lambda x: isinstance(x, GenericElementPlot) and not isinstance(x, GenericOverlayPlot)
plot_fn = lambda x: isinstance(x, (GenericElementPlot, GenericOverlayPlot))
plots = root_plot.traverse(lambda x: x, [plot_fn])
potentials = [cls.find_link(plot) for plot in plots]
source_links = [p for p in potentials if p is not None]
Expand Down
2 changes: 1 addition & 1 deletion holoviews/plotting/bokeh/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,11 +331,11 @@ def init_links(self):
cb = Link._callbacks['bokeh'][type(link)]
if src_plot is None or (link._requires_target and tgt_plot is None):
continue
# The link callback (`cb`) is instantiated (with side-effects).
callbacks.append(cb(self.root, link, src_plot, tgt_plot))
return callbacks



class CompositePlot(BokehPlot):
"""
CompositePlot is an abstract baseclass for plot types that draw
Expand Down
2 changes: 1 addition & 1 deletion holoviews/plotting/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -994,7 +994,7 @@ def link_sources(self):
zorders = [self.zorder]

if isinstance(self, GenericOverlayPlot) and not self.batched:
sources = []
sources = [self.hmap.last]
elif not self.static or isinstance(self.hmap, DynamicMap):
sources = [o for i, inputs in self.stream_sources.items()
for o in inputs if i in zorders]
Expand Down
30 changes: 29 additions & 1 deletion holoviews/tests/plotting/bokeh/test_links.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import pytest

from holoviews.core.spaces import DynamicMap
from holoviews.element import Curve, Polygons, Table, Scatter, Path, Points
from holoviews.element import Curve, Image, Polygons, Table, Scatter, Path, Points
from holoviews.plotting.links import (Link, RangeToolLink, DataLink)

from bokeh.models import ColumnDataSource
Expand All @@ -26,6 +26,34 @@ def test_range_tool_link_callback_single_axis(self):
self.assertEqual(range_tool.x_range, tgt_plot.handles['x_range'])
self.assertIs(range_tool.y_range, None)

def test_range_tool_link_callback_single_axis_overlay_target(self):
from bokeh.models import RangeTool
array = np.random.rand(100, 2)
src = Curve(array)
target = Scatter(array, label='a') * Scatter(array, label='b')
RangeToolLink(src, target)
layout = target + src
plot = bokeh_renderer.get_plot(layout)
tgt_plot = plot.subplots[(0, 0)].subplots['main']
src_plot = plot.subplots[(0, 1)].subplots['main']
range_tool = src_plot.state.select_one({'type': RangeTool})
self.assertEqual(range_tool.x_range, tgt_plot.handles['x_range'])
self.assertIs(range_tool.y_range, None)

def test_range_tool_link_callback_single_axis_overlay_target_image_source(self):
from bokeh.models import RangeTool
data = np.random.rand(50, 50)
target = Curve(data) * Curve(data)
source = Image(np.random.rand(50, 50), bounds=(0, 0, 1, 1))
RangeToolLink(source, target)
layout = target + source
plot = bokeh_renderer.get_plot(layout)
tgt_plot = plot.subplots[(0, 0)].subplots['main']
src_plot = plot.subplots[(0, 1)].subplots['main']
range_tool = src_plot.state.select_one({'type': RangeTool})
self.assertEqual(range_tool.x_range, tgt_plot.handles['x_range'])
self.assertIs(range_tool.y_range, None)

def test_range_tool_link_callback_both_axes(self):
from bokeh.models import RangeTool
array = np.random.rand(100, 2)
Expand Down

0 comments on commit 3f96806

Please sign in to comment.