Example #1
0
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
Example #2
0
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)
Example #3
0
    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