Skip to content

Commit

Permalink
Added support for Empty adjoint plots in bokeh (#1561)
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr authored and jlstevens committed Jun 17, 2017
1 parent 5c1ada6 commit e258f78
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 11 deletions.
2 changes: 1 addition & 1 deletion holoviews/core/layout.py
Expand Up @@ -31,7 +31,7 @@ def __add__(self, obj):


def __lshift__(self, other):
if isinstance(other, (ViewableElement, NdMapping)):
if isinstance(other, (ViewableElement, NdMapping, Empty)):
return AdjointLayout([self, other])
elif isinstance(other, AdjointLayout):
return AdjointLayout(other.data.values()+[self])
Expand Down
27 changes: 18 additions & 9 deletions holoviews/plotting/bokeh/plot.py
Expand Up @@ -7,7 +7,8 @@
from bokeh.models.widgets import Panel, Tabs

from ...core import (OrderedDict, CompositeOverlay, Store, Layout, GridMatrix,
AdjointLayout, NdLayout, Empty, GridSpace, HoloMap, Element)
AdjointLayout, NdLayout, Empty, GridSpace, HoloMap, Element,
Empty)
from ...core.options import Compositor
from ...core.util import basestring, wrap_tuple, unique_iterator
from ...element import Histogram
Expand Down Expand Up @@ -61,7 +62,8 @@ def document(self, doc):
self._document = doc
if self.subplots:
for plot in self.subplots.values():
plot.document = doc
if plot is not None:
plot.document = doc


def __init__(self, *args, **params):
Expand Down Expand Up @@ -561,7 +563,7 @@ def _create_subplots(self, layout, positions, layout_dimensions, ranges, num=0):
for pos in positions:
# Pos will be one of 'main', 'top' or 'right' or None
element = layout.get(pos, None)
if element is None or not element.traverse(lambda x: x, [Element]):
if element is None or not element.traverse(lambda x: x, [Element, Empty]):
continue

subplot_opts = dict(adjoined=main_plot)
Expand All @@ -573,22 +575,27 @@ def _create_subplots(self, layout, positions, layout_dimensions, ranges, num=0):
if pos != 'main':
plot_type = AdjointLayoutPlot.registry.get(vtype, plot_type)
if pos == 'right':
yaxis = 'right-bare' if 'bare' in plot_type.yaxis else 'right'
yaxis = 'right-bare' if plot_type and 'bare' in plot_type.yaxis else 'right'
width = plot_type.width if plot_type else 0
side_opts = dict(height=main_plot.height, yaxis=yaxis,
width=plot_type.width, invert_axes=True,
width=width, invert_axes=True,
labelled=['y'], xticks=1, xaxis=main_plot.xaxis)
else:
xaxis = 'top-bare' if 'bare' in plot_type.xaxis else 'top'
xaxis = 'top-bare' if plot_type and 'bare' in plot_type.xaxis else 'top'
height = plot_type.height if plot_type else 0
side_opts = dict(width=main_plot.width, xaxis=xaxis,
height=plot_type.height, labelled=['x'],
height=height, labelled=['x'],
yticks=1, yaxis=main_plot.yaxis)

# Override the plotopts as required
# Customize plotopts depending on position.
plotopts = dict(side_opts, **plotopts)
plotopts.update(subplot_opts)

if plot_type is None:
if vtype is Empty:
subplots[pos] = None
continue
elif plot_type is None:
self.warning("Bokeh plotting class for %s type not found, object will "
"not be rendered." % vtype.__name__)
continue
Expand Down Expand Up @@ -754,13 +761,15 @@ def initialize_plot(self, ranges=None, plots=[]):
"""
if plots is None: plots = []
adjoined_plots = []
for pos in ['main', 'right', 'top']:
for pos in self.view_positions:
# Pos will be one of 'main', 'top' or 'right' or None
subplot = self.subplots.get(pos, None)
# If no view object or empty position, disable the axis
if subplot:
passed_plots = plots + adjoined_plots
adjoined_plots.append(subplot.initialize_plot(ranges=ranges, plots=passed_plots))
else:
adjoined_plots.append(empty_plot(0, 0))
self.drawn = True
if not adjoined_plots: adjoined_plots = [None]
return adjoined_plots
Expand Down
2 changes: 2 additions & 0 deletions holoviews/plotting/plot.py
Expand Up @@ -262,6 +262,8 @@ def traverse(self, fn=None, specs=None, full_breadth=True):
# Assumes composite objects are iterables
if hasattr(self, 'subplots') and self.subplots:
for el in self.subplots.values():
if el is None:
continue
accumulator += el.traverse(fn, specs, full_breadth)
if not full_breadth: break
return accumulator
Expand Down
14 changes: 13 additions & 1 deletion tests/testplotinstantiation.py
Expand Up @@ -14,7 +14,7 @@
import numpy as np
from holoviews import (Dimension, Overlay, DynamicMap, Store, Dataset,
NdOverlay, GridSpace, HoloMap, Layout, Cycle,
Palette, Element)
Palette, Element, Empty)
from holoviews.core.util import pd
from holoviews.element import (Curve, Scatter, Image, VLine, Points,
HeatMap, QuadMesh, Spikes, ErrorBars,
Expand Down Expand Up @@ -1479,6 +1479,18 @@ def test_shared_axes_disable(self):
self.assertEqual((x_range.start, x_range.end), (-.5, .5))
self.assertEqual((y_range.start, y_range.end), (-.5, .5))

def test_empty_adjoint_plot(self):
adjoint = Curve([0,1,1,2,3]) << Empty() << Curve([0,1,1,0,1])
plot = bokeh_renderer.get_plot(adjoint)
adjoint_plot = plot.subplots[(0, 0)]
self.assertEqual(len(adjoint_plot.subplots), 3)
column = plot.state.children[1]
row1, row2 = column.children
self.assertEqual(row1.children[0].plot_height, row1.children[1].plot_height)
self.assertEqual(row1.children[1].plot_width, 0)
self.assertEqual(row2.children[1].plot_width, 0)
self.assertEqual(row2.children[0].plot_height, row2.children[1].plot_height)

def test_layout_shared_source_synced_update(self):
hmap = HoloMap({i: Dataset({chr(65+j): np.random.rand(i+2)
for j in range(4)}, kdims=['A', 'B', 'C', 'D'])
Expand Down

0 comments on commit e258f78

Please sign in to comment.