66from contextlib import contextmanager , suppress
77from itertools import permutations
88
9- import bokeh
109import numpy as np
11- from bokeh .core .json_encoder import serialize_json # noqa (API import)
1210from bokeh .core .property .datetime import Datetime
1311from bokeh .core .validation import silence
1412from bokeh .core .validation .check import is_silenced
15- from bokeh .layouts import Column , Row , group_tools
16- from bokeh .models import (
13+ from bokeh .layouts import group_tools
14+ from bokeh .model import Model
15+ from bokeh .models import CustomJS , tools
16+ from bokeh .models .axes import (
1717 CategoricalAxis ,
18- CopyTool ,
19- CustomJS ,
20- DataRange1d ,
2118 DatetimeAxis ,
22- ExamineTool ,
23- FactorRange ,
24- FullscreenTool ,
25- GridBox ,
26- GridPlot ,
27- LayoutDOM ,
2819 LinearAxis ,
2920 LogAxis ,
3021 MercatorAxis ,
31- Model ,
32- Plot ,
33- Range1d ,
34- SaveTool ,
35- Spacer ,
36- Tabs ,
37- Toolbar ,
38- tools ,
3922)
4023from bokeh .models .formatters import PrintfTickFormatter , TickFormatter
24+ from bokeh .models .layouts import Column , GridBox , LayoutDOM , Row , Spacer , Tabs
25+ from bokeh .models .plots import GridPlot , Plot
26+ from bokeh .models .ranges import DataRange1d , FactorRange , Range1d
4127from bokeh .models .scales import CategoricalScale , LinearScale , LogScale
4228from bokeh .models .tickers import BasicTicker , FixedTicker , Ticker
4329from bokeh .models .widgets import DataTable , Div
4430from bokeh .plotting import figure
4531from bokeh .themes import built_in_themes
4632from bokeh .themes .theme import Theme
47- from packaging .version import Version
4833
4934from ...core import util
5035from ...core .layout import Layout
6045 isnumeric ,
6146 unique_array ,
6247)
48+ from ...core .util .dependencies import _no_import_version
6349from ...util .warnings import warn
6450from ..util import dim_axis_label
6551
66- BOKEH_VERSION = Version ( bokeh . __version__ ). release
52+ BOKEH_VERSION = _no_import_version ( " bokeh" )
6753BOKEH_GE_3_2_0 = BOKEH_VERSION >= (3 , 2 , 0 )
6854BOKEH_GE_3_3_0 = BOKEH_VERSION >= (3 , 3 , 0 )
6955BOKEH_GE_3_4_0 = BOKEH_VERSION >= (3 , 4 , 0 )
7258BOKEH_GE_3_7_0 = BOKEH_VERSION >= (3 , 7 , 0 )
7359BOKEH_GE_3_8_0 = BOKEH_VERSION >= (3 , 8 , 0 )
7460
61+
62+ if BOKEH_GE_3_8_0 :
63+ from bokeh .models .axes import TimedeltaAxis
64+
65+
7566TOOL_TYPES = {
7667 'pan' : tools .PanTool ,
7768 'xpan' : tools .PanTool ,
@@ -201,12 +192,12 @@ def compute_plot_size(plot):
201192 width = sum ([max ([compute_plot_size (f )[0 ] for f in col ]) for col in cols ])
202193 height = sum ([max ([compute_plot_size (f )[1 ] for f in row ]) for row in rows ])
203194 return width , height
204- elif isinstance (plot , (Div , Toolbar )):
195+ elif isinstance (plot , (Div , tools . Toolbar )):
205196 # Cannot compute size for Div or Toolbar
206197 return 0 , 0
207198 elif isinstance (plot , (Row , Column , Tabs )):
208199 if not plot .children : return 0 , 0
209- if isinstance (plot , Row ) or (isinstance (plot , Toolbar ) and plot .toolbar_location not in ['right' , 'left' ]):
200+ if isinstance (plot , Row ) or (isinstance (plot , tools . Toolbar ) and plot .toolbar_location not in ['right' , 'left' ]):
210201 w_agg , h_agg = (np .sum , np .max )
211202 elif isinstance (plot , Tabs ):
212203 w_agg , h_agg = (np .max , np .max )
@@ -430,19 +421,19 @@ def merge_tools(plot_grid, *, disambiguation_properties=None, hide_toolbar=False
430421 and `description` can be used to prevent tools from being merged.
431422
432423 """
433- tools = []
424+ plot_tools = []
434425 for row in plot_grid :
435426 for item in row :
436427 if isinstance (item , LayoutDOM ):
437428 for p in item .select (dict (type = Plot )):
438- tools .extend (p .toolbar .tools )
429+ plot_tools .extend (p .toolbar .tools )
439430 if hide_toolbar and hasattr (item , 'toolbar_location' ):
440431 item .toolbar_location = None
441432 if isinstance (item , GridPlot ):
442433 item .toolbar_location = None
443434
444435 def merge (tool , group ):
445- if issubclass (tool , (SaveTool , CopyTool , ExamineTool , FullscreenTool )):
436+ if issubclass (tool , (tools . SaveTool , tools . CopyTool , tools . ExamineTool , tools . FullscreenTool )):
446437 return tool ()
447438 else :
448439 return None
@@ -451,15 +442,15 @@ def merge(tool, group):
451442 disambiguation_properties = {'name' , 'icon' , 'tags' , 'description' }
452443
453444 ignore = set ()
454- for tool in tools :
445+ for tool in plot_tools :
455446 for p in tool .properties_with_values ():
456447 if p not in disambiguation_properties :
457448 ignore .add (p )
458449
459450 toolbar_kwargs = {"autohide" : autohide }
460- if tools :
461- toolbar_kwargs ["tools" ] = group_tools (tools , merge = merge , ignore = ignore )
462- return Toolbar (** toolbar_kwargs )
451+ if plot_tools :
452+ toolbar_kwargs ["tools" ] = group_tools (plot_tools , merge = merge , ignore = ignore )
453+ return tools . Toolbar (** toolbar_kwargs )
463454
464455
465456def sync_legends (bokeh_layout ):
@@ -750,7 +741,7 @@ def filter_toolboxes(plots):
750741 plots .toolbar_location = None
751742 elif hasattr (plots , 'children' ):
752743 plots .children = [filter_toolboxes (child ) for child in plots .children
753- if not isinstance (child , Toolbar )]
744+ if not isinstance (child , tools . Toolbar )]
754745 return plots
755746
756747
@@ -1135,7 +1126,7 @@ def match_dim_specs(specs1, specs2):
11351126
11361127
11371128def get_scale (range_input , axis_type ):
1138- if isinstance (range_input , (DataRange1d , Range1d )) and axis_type in ["linear" , "datetime" , "mercator" , "auto" , None ]:
1129+ if isinstance (range_input , (DataRange1d , Range1d )) and axis_type in ["linear" , "datetime" , "mercator" , "auto" , "timedelta" , None ]:
11391130 return LinearScale ()
11401131 elif isinstance (range_input , (DataRange1d , Range1d )) and axis_type == "log" :
11411132 return LogScale ()
@@ -1154,6 +1145,8 @@ def get_axis_class(axis_type, range_input, dim): # Copied from bokeh
11541145 return LogAxis , {}
11551146 elif axis_type == "datetime" :
11561147 return DatetimeAxis , {}
1148+ elif BOKEH_GE_3_8_0 and axis_type == "timedelta" :
1149+ return TimedeltaAxis , {}
11571150 elif axis_type == "mercator" :
11581151 return MercatorAxis , dict (dimension = 'lon' if dim == 0 else 'lat' )
11591152 elif axis_type == "auto" :
@@ -1183,6 +1176,8 @@ def match_ax_type(ax, range_type):
11831176 return range_type == 'categorical'
11841177 elif isinstance (ax , DatetimeAxis ):
11851178 return range_type == 'datetime'
1179+ elif BOKEH_GE_3_8_0 and isinstance (ax , TimedeltaAxis ):
1180+ return range_type == 'timedelta'
11861181 else :
11871182 return range_type in ('auto' , 'log' )
11881183
0 commit comments