hvplot
hvplot copied to clipboard
Support `pandas.Interval` arrays in `step` plots
xarray support generating step plots from dimensions that consist of array containing pandas Interval objects.
import hvplot.xarray
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import xarray as xr
airtemps = xr.tutorial.open_dataset("air_temperature")
air = airtemps.air - 273.15
air.attrs = airtemps.air.attrs
air.attrs["units"] = "deg C"
air_grp = air.mean(["time", "lon"]).groupby_bins("lat", [0, 23.5, 66.5, 90])
air_mean = air_grp.mean()
air_mean.plot.step()
This is what air_mean.lat_bins.values looks like:
array([Interval(0.0, 23.5, closed='right'),
Interval(23.5, 66.5, closed='right'),
Interval(66.5, 90.0, closed='right')], dtype=object)
air_mean.hvplot.step() fails with a TypeError in HoloViews:
TypeError Traceback (most recent call last)
File ~/miniconda3/envs/hv-dev38/lib/python3.8/site-packages/IPython/core/formatters.py:973, in MimeBundleFormatter.__call__(self, obj, include, exclude)
970 method = get_real_method(obj, self.print_method)
972 if method is not None:
--> 973 return method(include=include, exclude=exclude)
974 return None
975 else:
File ~/work/dev/holoviews/holoviews/core/dimension.py:1294, in Dimensioned._repr_mimebundle_(self, include, exclude)
1287 def _repr_mimebundle_(self, include=None, exclude=None):
1288 """
1289 Resolves the class hierarchy for the class rendering the
1290 object using any display hooks registered on Store.display
1291 hooks. The output of all registered display_hooks is then
1292 combined and returned.
1293 """
-> 1294 return Store.render(self)
File ~/work/dev/holoviews/holoviews/core/options.py:1426, in Store.render(cls, obj)
1424 data, metadata = {}, {}
1425 for hook in hooks:
-> 1426 ret = hook(obj)
1427 if ret is None:
1428 continue
File ~/work/dev/holoviews/holoviews/ipython/display_hooks.py:277, in pprint_display(obj)
275 if not ip.display_formatter.formatters['text/plain'].pprint:
276 return None
--> 277 return display(obj, raw_output=True)
File ~/work/dev/holoviews/holoviews/ipython/display_hooks.py:247, in display(obj, raw_output, **kwargs)
245 elif isinstance(obj, (CompositeOverlay, ViewableElement)):
246 with option_state(obj):
--> 247 output = element_display(obj)
248 elif isinstance(obj, (Layout, NdLayout, AdjointLayout)):
249 with option_state(obj):
File ~/work/dev/holoviews/holoviews/ipython/display_hooks.py:141, in display_hook.<locals>.wrapped(element)
139 try:
140 max_frames = OutputSettings.options['max_frames']
--> 141 mimebundle = fn(element, max_frames=max_frames)
142 if mimebundle is None:
143 return {}, {}
File ~/work/dev/holoviews/holoviews/ipython/display_hooks.py:187, in element_display(element, max_frames)
184 if type(element) not in Store.registry[backend]:
185 return None
--> 187 return render(element)
File ~/work/dev/holoviews/holoviews/ipython/display_hooks.py:68, in render(obj, **kwargs)
65 if renderer.fig == 'pdf':
66 renderer = renderer.instance(fig='png')
---> 68 return renderer.components(obj, **kwargs)
File ~/work/dev/holoviews/holoviews/plotting/renderer.py:398, in Renderer.components(self, obj, fmt, comm, **kwargs)
395 embed = (not (dynamic or streams or self.widget_mode == 'live') or config.embed)
397 if embed or config.comms == 'default':
--> 398 return self._render_panel(plot, embed, comm)
399 return self._render_ipywidget(plot)
File ~/work/dev/holoviews/holoviews/plotting/renderer.py:405, in Renderer._render_panel(self, plot, embed, comm)
403 doc = Document()
404 with config.set(embed=embed):
--> 405 model = plot.layout._render_model(doc, comm)
406 if embed:
407 return render_model(model, comm)
File ~/miniconda3/envs/hv-dev38/lib/python3.8/site-packages/panel/viewable.py:505, in Renderable._render_model(self, doc, comm)
503 if comm is None:
504 comm = state._comm_manager.get_server_comm()
--> 505 model = self.get_root(doc, comm)
507 if config.embed:
508 embed_state(self, model, doc,
509 json=config.embed_json,
510 json_prefix=config.embed_json_prefix,
511 save_path=config.embed_save_path,
512 load_path=config.embed_load_path,
513 progress=False)
File ~/miniconda3/envs/hv-dev38/lib/python3.8/site-packages/panel/viewable.py:556, in Renderable.get_root(self, doc, comm, preprocess)
539 """
540 Returns the root model and applies pre-processing hooks
541
(...)
553 Returns the bokeh model corresponding to this panel object
554 """
555 doc = init_doc(doc)
--> 556 root = self._get_model(doc, comm=comm)
557 if preprocess:
558 self._preprocess(root)
File ~/miniconda3/envs/hv-dev38/lib/python3.8/site-packages/panel/layout/base.py:146, in Panel._get_model(self, doc, root, parent, comm)
144 if root is None:
145 root = model
--> 146 objects = self._get_objects(model, [], doc, root, comm)
147 props = dict(self._init_params(), objects=objects)
148 model.update(**self._process_param_change(props))
File ~/miniconda3/envs/hv-dev38/lib/python3.8/site-packages/panel/layout/base.py:131, in Panel._get_objects(self, model, old_objects, doc, root, comm)
129 else:
130 try:
--> 131 child = pane._get_model(doc, root, model, comm)
132 except RerenderError:
133 return self._get_objects(model, current_objects[:i], doc, root, comm)
File ~/miniconda3/envs/hv-dev38/lib/python3.8/site-packages/panel/pane/holoviews.py:265, in HoloViews._get_model(self, doc, root, parent, comm)
263 plot = self.object
264 else:
--> 265 plot = self._render(doc, comm, root)
267 plot.pane = self
268 backend = plot.renderer.backend
File ~/miniconda3/envs/hv-dev38/lib/python3.8/site-packages/panel/pane/holoviews.py:342, in HoloViews._render(self, doc, comm, root)
339 if comm:
340 kwargs['comm'] = comm
--> 342 return renderer.get_plot(self.object, **kwargs)
File ~/work/dev/holoviews/holoviews/plotting/bokeh/renderer.py:70, in BokehRenderer.get_plot(self_or_cls, obj, doc, renderer, **kwargs)
63 @bothmethod
64 def get_plot(self_or_cls, obj, doc=None, renderer=None, **kwargs):
65 """
66 Given a HoloViews Viewable return a corresponding plot instance.
67 Allows supplying a document attach the plot to, useful when
68 combining the bokeh model with another plot.
69 """
---> 70 plot = super().get_plot(obj, doc, renderer, **kwargs)
71 if plot.document is None:
72 plot.document = Document() if self_or_cls.notebook_context else curdoc()
File ~/work/dev/holoviews/holoviews/plotting/renderer.py:240, in Renderer.get_plot(self_or_cls, obj, doc, renderer, comm, **kwargs)
237 defaults = [kd.default for kd in plot.dimensions]
238 init_key = tuple(v if d is None else d for v, d in
239 zip(plot.keys[0], defaults))
--> 240 plot.update(init_key)
241 else:
242 plot = obj
File ~/work/dev/holoviews/holoviews/plotting/plot.py:948, in DimensionedPlot.update(self, key)
946 def update(self, key):
947 if len(self) == 1 and ((key == 0) or (key == self.keys[0])) and not self.drawn:
--> 948 return self.initialize_plot()
949 item = self.__getitem__(key)
950 self.traverse(lambda x: setattr(x, '_updated', True))
File ~/work/dev/holoviews/holoviews/plotting/bokeh/element.py:1382, in ElementPlot.initialize_plot(self, ranges, plot, plots, source)
1380 element = self.hmap.last
1381 key = util.wrap_tuple(self.hmap.last_key)
-> 1382 ranges = self.compute_ranges(self.hmap, key, ranges)
1383 self.current_ranges = ranges
1384 self.current_frame = element
File ~/work/dev/holoviews/holoviews/plotting/plot.py:607, in DimensionedPlot.compute_ranges(self, obj, key, ranges)
603 # Only compute ranges if not axiswise on a composite plot
604 # or not framewise on a Overlay or ElementPlot
605 if (not (axiswise and not isinstance(obj, HoloMap)) or
606 (not framewise and isinstance(obj, HoloMap))):
--> 607 self._compute_group_range(group, elements, ranges, framewise,
608 axiswise, robust, self.top_level,
609 prev_frame)
610 self.ranges.update(ranges)
611 return ranges
File ~/work/dev/holoviews/holoviews/plotting/plot.py:824, in DimensionedPlot._compute_group_range(cls, group, elements, ranges, framewise, axiswise, robust, top_level, prev_frame)
821 if t in ('factors', 'id'):
822 continue
823 matching &= (
--> 824 len({'date' if isinstance(v, util.datetime_types) else 'number'
825 for rng in rs for v in rng if util.isfinite(v)}) < 2
826 )
827 if matching:
828 group_dim_ranges[gdim] = values
File ~/work/dev/holoviews/holoviews/plotting/plot.py:825, in <setcomp>(.0)
821 if t in ('factors', 'id'):
822 continue
823 matching &= (
824 len({'date' if isinstance(v, util.datetime_types) else 'number'
--> 825 for rng in rs for v in rng if util.isfinite(v)}) < 2
826 )
827 if matching:
828 group_dim_ranges[gdim] = values
File ~/work/dev/holoviews/holoviews/core/util.py:886, in isfinite(val)
884 elif isinstance(val, (str, bytes)):
885 return True
--> 886 finite = np.isfinite(val)
887 if pd and pandas_version >= LooseVersion('1.0.0'):
888 if finite is pd.NA:
TypeError: ufunc 'isfinite' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
I'm not sure whether it's up to hvPlot or HoloViews to add support to this data type. Any opinion @jlstevens ?