Skip to content

Commit d336e11

Browse files
authored
Implement bokeh3 compatible layout (#1076)
1 parent d9bd81a commit d336e11

File tree

3 files changed

+79
-1
lines changed

3 files changed

+79
-1
lines changed

hvplot/interactive.py

+49-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@
112112

113113
from .converter import HoloViewsConverter
114114
from .util import (
115-
_flatten, is_tabular, is_xarray, is_xarray_dataarray,
115+
_flatten, bokeh3, is_tabular, is_xarray, is_xarray_dataarray,
116116
_convert_col_names_to_str,
117117
)
118118

@@ -709,6 +709,11 @@ def layout(self, **kwargs):
709709
to the center and widget location specified in the
710710
interactive call.
711711
"""
712+
if bokeh3:
713+
return self._layout_bk3(**kwargs)
714+
return self._layout_bk2(**kwargs)
715+
716+
def _layout_bk2(self, **kwargs):
712717
widget_box = self.widgets()
713718
panel = self.output()
714719
loc = self._loc
@@ -751,6 +756,49 @@ def layout(self, **kwargs):
751756
components = [Column(panel, widgets)]
752757
return Row(*components, **kwargs)
753758

759+
def _layout_bk3(self, **kwargs):
760+
widget_box = self.widgets()
761+
panel = self.output()
762+
loc = self._loc
763+
center = self._center
764+
alignments = {
765+
'left': (Row, ('start', 'center'), True),
766+
'right': (Row, ('end', 'center'), False),
767+
'top': (Column, ('center', 'start'), True),
768+
'bottom': (Column, ('center', 'end'), False),
769+
'top_left': (Column, 'start', True),
770+
'top_right': (Column, ('end', 'start'), True),
771+
'bottom_left': (Column, ('start', 'end'), False),
772+
'bottom_right': (Column, 'end', False),
773+
'left_top': (Row, 'start', True),
774+
'left_bottom': (Row, ('start', 'end'), True),
775+
'right_top': (Row, ('end', 'start'), False),
776+
'right_bottom': (Row, 'end', False)
777+
}
778+
layout, align, widget_first = alignments[loc]
779+
widget_box.align = align
780+
if not len(widget_box):
781+
if center:
782+
components = [HSpacer(), panel, HSpacer()]
783+
else:
784+
components = [panel]
785+
return Row(*components, **kwargs)
786+
787+
items = (widget_box, panel) if widget_first else (panel, widget_box)
788+
sizing_mode = kwargs.get('sizing_mode')
789+
if not center:
790+
if layout is Row:
791+
components = list(items)
792+
else:
793+
components = [layout(*items, sizing_mode=sizing_mode)]
794+
elif layout is Column:
795+
components = [HSpacer(), layout(*items, sizing_mode=sizing_mode), HSpacer()]
796+
elif loc.startswith('left'):
797+
components = [widget_box, HSpacer(), panel, HSpacer()]
798+
else:
799+
components = [HSpacer(), panel, HSpacer(), widget_box]
800+
return Row(*components, **kwargs)
801+
754802
def holoviews(self):
755803
"""
756804
Returns a HoloViews object to render the output of this

hvplot/tests/testinteractive.py

+27
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
from hvplot import bind
1515
from hvplot.interactive import Interactive
1616
from hvplot.xarray import XArrayInteractive
17+
from hvplot.util import bokeh3
18+
19+
is_bokeh2 = pytest.mark.skipif(bokeh3, reason="requires bokeh 2.x")
20+
is_bokeh3 = pytest.mark.skipif(not bokeh3, reason="requires bokeh 3.x")
1721

1822

1923
@pytest.fixture(scope='module')
@@ -1247,6 +1251,7 @@ def test_interactive_pandas_layout_default_no_widgets_kwargs(df):
12471251
assert layout.width == 200
12481252

12491253

1254+
@is_bokeh2
12501255
def test_interactive_pandas_layout_default_with_widgets(df):
12511256
w = pn.widgets.IntSlider(value=2, start=1, end=5)
12521257
dfi = Interactive(df)
@@ -1270,6 +1275,27 @@ def test_interactive_pandas_layout_default_with_widgets(df):
12701275
assert isinstance(layout[0][0][1], pn.layout.HSpacer)
12711276

12721277

1278+
@is_bokeh3
1279+
def test_interactive_pandas_layout_default_with_widgets_bk3(df):
1280+
w = pn.widgets.IntSlider(value=2, start=1, end=5)
1281+
dfi = Interactive(df)
1282+
dfi = dfi.head(w)
1283+
1284+
assert dfi._center is False
1285+
assert dfi._loc == 'top_left'
1286+
1287+
layout = dfi.layout()
1288+
1289+
assert isinstance(layout, pn.Row)
1290+
assert len(layout) == 1
1291+
assert isinstance(layout[0], pn.Column)
1292+
assert len(layout[0]) == 2
1293+
assert isinstance(layout[0][0], pn.Column)
1294+
assert isinstance(layout[0][1], pn.pane.PaneBase)
1295+
assert len(layout[0][0]) == 1
1296+
assert isinstance(layout[0][0][0], pn.widgets.IntSlider)
1297+
1298+
@is_bokeh2
12731299
def test_interactive_pandas_layout_center_with_widgets(df):
12741300
w = pn.widgets.IntSlider(value=2, start=1, end=5)
12751301
dfi = df.interactive(center=True)
@@ -1298,6 +1324,7 @@ def test_interactive_pandas_layout_center_with_widgets(df):
12981324
assert isinstance(layout[1][1][2], pn.layout.HSpacer)
12991325

13001326

1327+
@is_bokeh2
13011328
def test_interactive_pandas_layout_loc_with_widgets(df):
13021329
w = pn.widgets.IntSlider(value=2, start=1, end=5)
13031330
dfi = df.interactive(loc='top_right')

hvplot/util.py

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from packaging.version import Version
1111
from types import FunctionType
1212

13+
import bokeh
1314
import numpy as np
1415
import pandas as pd
1516
import param
@@ -21,6 +22,8 @@
2122
panel_available = False
2223

2324
hv_version = Version(hv.__version__)
25+
bokeh_version = Version(bokeh.__version__)
26+
bokeh3 = bokeh_version >= Version("3.0")
2427

2528

2629
def with_hv_extension(func, extension='bokeh', logo=False):

0 commit comments

Comments
 (0)