def link_axes(root_view, root_model): """ Pre-processing hook to allow linking axes across HoloViews bokeh plots. """ panes = root_view.select(HoloViews) if not panes: return from holoviews.core.options import Store from holoviews.plotting.bokeh.element import ElementPlot ref = root_model.ref['id'] range_map = defaultdict(list) for pane in panes: if ref not in pane._plots: continue plot = pane._plots[ref][0] if (not pane.linked_axes or plot.renderer.backend != 'bokeh' or not getattr(plot, 'shared_axes', False)): continue for p in plot.traverse(specs=[ElementPlot]): if p.current_frame is None: continue axiswise = Store.lookup_options('bokeh', p.current_frame, 'norm').kwargs.get('axiswise') if not p.shared_axes or axiswise: continue fig = p.state if fig.x_range.tags: range_map[fig.x_range.tags[0]].append((fig, p, fig.x_range)) if fig.y_range.tags: range_map[fig.y_range.tags[0]].append((fig, p, fig.y_range)) for tag, axes in range_map.items(): fig, p, axis = axes[0] for fig, p, _ in axes[1:]: if tag in fig.x_range.tags and not axis is fig.x_range: fig.x_range = axis p.handles['x_range'] = axis if tag in fig.y_range.tags and not axis is fig.y_range: fig.y_range = axis p.handles['y_range'] = axis
def link_axes(root_view, root_model): """ Pre-processing hook to allow linking axes across HoloViews bokeh plots. """ panes = root_view.select(HoloViews) if not panes: return from holoviews.core.options import Store from holoviews.plotting.bokeh.element import ElementPlot ref = root_model.ref['id'] range_map = defaultdict(list) for pane in panes: if ref not in pane._plots: continue plot = pane._plots[ref][0] if (not pane.linked_axes or plot.renderer.backend != 'bokeh' or not getattr(plot, 'shared_axes', False)): continue for p in plot.traverse(specs=[ElementPlot]): if p.current_frame is None: continue axiswise = Store.lookup_options('bokeh', p.current_frame, 'norm').kwargs.get('axiswise') if not p.shared_axes or axiswise: continue fig = p.state if fig.x_range.tags: range_map[(fig.x_range.tags[0], plot.root.ref['id'])].append( (fig, p, fig.x_range)) if fig.y_range.tags: range_map[(fig.y_range.tags[0], plot.root.ref['id'])].append( (fig, p, fig.y_range)) for (tag, _), axes in range_map.items(): fig, p, axis = axes[0] for fig, p, _ in axes[1:]: changed = [] if tag in fig.x_range.tags and not axis is fig.x_range: fig.x_range = axis p.handles['x_range'] = axis changed.append('x_range') if tag in fig.y_range.tags and not axis is fig.y_range: fig.y_range = axis p.handles['y_range'] = axis changed.append('y_range') # Reinitialize callbacks linked to replaced axes subplots = getattr(p, 'subplots') if subplots: plots = subplots.values() else: plots = [p] for sp in plots: for callback in sp.callbacks: if not any( c in callback.models or c in callback.extra_models for c in changed): continue if 'x_range' in changed: sp.handles['x_range'] = p.handles['x_range'] if 'y_range' in changed: sp.handles['y_range'] = p.handles['y_range'] callback.reset() callback.initialize(plot_id=p.id)
def _update_layout(self): from holoviews.core import DynamicMap, Store from holoviews.plotting.util import initialize_dynamic loc = self.widget_location if not len(self.widget_box): widgets = [] elif loc in ('left', 'right'): widgets = Column(VSpacer(), self.widget_box, VSpacer()) elif loc in ('top', 'bottom'): widgets = Row(HSpacer(), self.widget_box, HSpacer()) elif loc in ('top_left', 'bottom_left'): widgets = Row(self.widget_box, HSpacer()) elif loc in ('top_right', 'bottom_right'): widgets = Row(HSpacer(), self.widget_box) elif loc in ('left_top', 'right_top'): widgets = Column(self.widget_box, VSpacer()) elif loc in ('left_bottom', 'right_bottom'): widgets = Column(VSpacer(), self.widget_box) # Do not center if content is responsive backend = self.backend or Store.current_backend if self.object is None: opts = {} else: initialize_dynamic(self.object) obj = self.object.last if isinstance(self.object, DynamicMap) else self.object try: opts = Store.lookup_options(backend, obj, 'plot').kwargs except: opts = {} responsive_modes = ('stretch_width', 'stretch_both', 'scale_width', 'scale_both') center = self.center if ((opts.get('responsive') and not (opts.get('width') or opts.get('frame_width'))) or opts.get('sizing_mode') in responsive_modes): center = False self._widget_container = widgets if not widgets: if center: components = [HSpacer(), self, HSpacer()] else: components = [self] elif center: if loc.startswith('left'): components = [widgets, HSpacer(), self, HSpacer()] elif loc.startswith('right'): components = [HSpacer(), self, HSpacer(), widgets] elif loc.startswith('top'): components = [ HSpacer(), Column(widgets, Row(HSpacer(), self, HSpacer())), HSpacer() ] elif loc.startswith('bottom'): components = [ HSpacer(), Column(Row(HSpacer(), self, HSpacer()), widgets), HSpacer() ] else: if loc.startswith('left'): components = [widgets, self] elif loc.startswith('right'): components = [self, widgets] elif loc.startswith('top'): components = [Column(widgets, self)] elif loc.startswith('bottom'): components = [Column(self, widgets)] self.layout[:] = components