hvplot
hvplot copied to clipboard
Unable to group xarray.DataArray by date coordinate in hvplot.line()
ALL software version info
Software Version Info
hvplot=0.11.3
holoviews=1.20.2
xarray=2025.4.0
Description of expected behavior and the observed behavior
As described here I am trying to group my timeseries data by dates from an xarray.DataArray using da.hvplot.line().
In previous versions that worked fine (hvplot=0.10.0, holoviews=1.19.1, xarray=2022.9.0), now I get an IndexError: Boolean index has wrong length:...
Complete, minimal, self-contained example code that reproduces the issue
Does not work in python (using panel), nor in jupyter
import numpy as np
import xarray as xr
import hvplot.xarray
import pandas as pd
import holoviews as hv
hv.extension('bokeh')
time = pd.date_range("2023-01-01", periods=48, freq="1h")
sample = np.arange(3)
# Create dummy 3D data
data = np.random.rand(len(time), len(sample))
da = xr.DataArray(data, dims=("time", "sample"), coords={
"time": time,
"sample": sample,
})
da = da.assign_coords(date=("time", da.time.dt.strftime('%Y-%m-%d').data))
# This works
# da.hvplot.line(x="time", groupby=["date"], grid=True)
# This works too
# da.hvplot.line(x="time", groupby=["sample"], grid=True)
# This works not
da.hvplot.line(x="time", groupby=["date", "sample"], grid=True)
Stack traceback and/or browser JavaScript console output
WARNING:param.load_subset: Callable raised "IndexError('Boolean index has wrong length: 144 instead of 48')".
Invoked as load_subset(np.str_('2023-01-01'), np.int64(0))
WARNING:param.dynamic_operation: Callable raised "IndexError('Boolean index has wrong length: 144 instead of 48')".
Invoked as dynamic_operation(np.str_('2023-01-01'), np.int64(0))
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/IPython/core/formatters.py:1036, in MimeBundleFormatter.__call__(self, obj, include, exclude)
1033 method = get_real_method(obj, self.print_method)
1035 if method is not None:
-> 1036 return method(include=include, exclude=exclude)
1037 return None
1038 else:
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/core/dimension.py:1277, in Dimensioned._repr_mimebundle_(self, include, exclude)
1270 def _repr_mimebundle_(self, include=None, exclude=None):
1271 """
1272 Resolves the class hierarchy for the class rendering the
1273 object using any display hooks registered on Store.display
1274 hooks. The output of all registered display_hooks is then
1275 combined and returned.
1276 """
-> 1277 return Store.render(self)
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/core/options.py:1423, in Store.render(cls, obj)
1421 data, metadata = {}, {}
1422 for hook in hooks:
-> 1423 ret = hook(obj)
1424 if ret is None:
1425 continue
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/ipython/display_hooks.py:287, in pprint_display(obj)
285 if not ip.display_formatter.formatters['text/plain'].pprint:
286 return None
--> 287 return display(obj, raw_output=True)
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/ipython/display_hooks.py:261, in display(obj, raw_output, **kwargs)
259 elif isinstance(obj, (HoloMap, DynamicMap)):
260 with option_state(obj):
--> 261 output = map_display(obj)
262 elif isinstance(obj, Plot):
263 output = render(obj)
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/ipython/display_hooks.py:149, in display_hook.<locals>.wrapped(element)
147 try:
148 max_frames = OutputSettings.options['max_frames']
--> 149 mimebundle = fn(element, max_frames=max_frames)
150 if mimebundle is None:
151 return {}, {}
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/ipython/display_hooks.py:209, in map_display(vmap, max_frames)
206 max_frame_warning(max_frames)
207 return None
--> 209 return render(vmap)
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/ipython/display_hooks.py:76, in render(obj, **kwargs)
73 if renderer.fig == 'pdf':
74 renderer = renderer.instance(fig='png')
---> 76 return renderer.components(obj, **kwargs)
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/plotting/renderer.py:396, in Renderer.components(self, obj, fmt, comm, **kwargs)
394 embed = (not (dynamic or streams or self.widget_mode == 'live') or config.embed)
395 if embed or config.comms == 'default':
--> 396 return self._render_panel(plot, embed, comm)
397 return self._render_ipywidget(plot)
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/plotting/renderer.py:403, in Renderer._render_panel(self, plot, embed, comm)
401 doc = Document()
402 with config.set(embed=embed):
--> 403 model = plot.layout._render_model(doc, comm)
404 if embed:
405 return render_model(model, comm)
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/panel/viewable.py:768, in Viewable._render_model(self, doc, comm)
766 if comm is None:
767 comm = state._comm_manager.get_server_comm()
--> 768 model = self.get_root(doc, comm)
770 if self._design and self._design.theme.bokeh_theme:
771 doc.theme = self._design.theme.bokeh_theme
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/panel/layout/base.py:329, in Panel.get_root(self, doc, comm, preprocess)
325 def get_root(
326 self, doc: Document | None = None, comm: Comm | None = None,
327 preprocess: bool = True
328 ) -> Model:
--> 329 root = super().get_root(doc, comm, preprocess)
330 # ALERT: Find a better way to handle this
331 if hasattr(root, 'styles') and 'overflow-x' in root.styles:
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/panel/viewable.py:698, in Renderable.get_root(self, doc, comm, preprocess)
696 wrapper = self._design._wrapper(self)
697 if wrapper is self:
--> 698 root = self._get_model(doc, comm=comm)
699 if preprocess:
700 self._preprocess(root)
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/panel/layout/base.py:313, in Panel._get_model(self, doc, root, parent, comm)
311 root = root or model
312 self._models[root.ref['id']] = (model, parent)
--> 313 objects, _ = self._get_objects(model, [], doc, root, comm)
314 props = self._get_properties(doc)
315 props[self._property_mapping['objects']] = objects
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/panel/layout/base.py:295, in Panel._get_objects(self, model, old_objects, doc, root, comm)
293 else:
294 try:
--> 295 child = pane._get_model(doc, root, model, comm)
296 except RerenderError as e:
297 if e.layout is not None and e.layout is not self:
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/panel/pane/holoviews.py:437, in HoloViews._get_model(self, doc, root, parent, comm)
435 plot = self.object
436 else:
--> 437 plot = self._render(doc, comm, root)
439 plot.pane = self
440 backend = plot.renderer.backend
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/panel/pane/holoviews.py:531, in HoloViews._render(self, doc, comm, root)
528 if comm:
529 kwargs['comm'] = comm
--> 531 return renderer.get_plot(self.object, **kwargs)
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/plotting/bokeh/renderer.py:68, in BokehRenderer.get_plot(self_or_cls, obj, doc, renderer, **kwargs)
61 @bothmethod
62 def get_plot(self_or_cls, obj, doc=None, renderer=None, **kwargs):
63 """
64 Given a HoloViews Viewable return a corresponding plot instance.
65 Allows supplying a document attach the plot to, useful when
66 combining the bokeh model with another plot.
67 """
---> 68 plot = super().get_plot(obj, doc, renderer, **kwargs)
69 if plot.document is None:
70 plot.document = Document() if self_or_cls.notebook_context else curdoc()
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/plotting/renderer.py:216, in Renderer.get_plot(self_or_cls, obj, doc, renderer, comm, **kwargs)
213 raise SkipRendering(msg.format(dims=dims))
215 # Initialize DynamicMaps with first data item
--> 216 initialize_dynamic(obj)
218 if not renderer:
219 renderer = self_or_cls
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/plotting/util.py:277, in initialize_dynamic(obj)
275 continue
276 if not len(dmap):
--> 277 dmap[dmap._initial_key()]
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/core/spaces.py:1216, in DynamicMap.__getitem__(self, key)
1214 # Not a cross product and nothing cached so compute element.
1215 if cache is not None: return cache
-> 1216 val = self._execute_callback(*tuple_key)
1217 if data_slice:
1218 val = self._dataslice(val, data_slice)
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/core/spaces.py:983, in DynamicMap._execute_callback(self, *args)
980 kwargs['_memoization_hash_'] = hash_items
982 with dynamicmap_memoization(self.callback, self.streams):
--> 983 retval = self.callback(*args, **kwargs)
984 return self._style(retval)
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/core/spaces.py:581, in Callable.__call__(self, *args, **kwargs)
578 args, kwargs = (), dict(pos_kwargs, **kwargs)
580 try:
--> 581 ret = self.callable(*args, **kwargs)
582 except KeyError:
583 # KeyError is caught separately because it is used to signal
584 # invalid keys on DynamicMap and should not warn
585 raise
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/util/__init__.py:1052, in Dynamic._dynamic_operation.<locals>.dynamic_operation(*key, **kwargs)
1051 def dynamic_operation(*key, **kwargs):
-> 1052 key, obj = resolve(key, kwargs)
1053 return apply(obj, *key, **kwargs)
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/util/__init__.py:1041, in Dynamic._dynamic_operation.<locals>.resolve(key, kwargs)
1039 elif isinstance(map_obj, DynamicMap) and map_obj._posarg_keys and not key:
1040 key = tuple(kwargs[k] for k in map_obj._posarg_keys)
-> 1041 return key, map_obj[key]
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/core/spaces.py:1216, in DynamicMap.__getitem__(self, key)
1214 # Not a cross product and nothing cached so compute element.
1215 if cache is not None: return cache
-> 1216 val = self._execute_callback(*tuple_key)
1217 if data_slice:
1218 val = self._dataslice(val, data_slice)
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/core/spaces.py:983, in DynamicMap._execute_callback(self, *args)
980 kwargs['_memoization_hash_'] = hash_items
982 with dynamicmap_memoization(self.callback, self.streams):
--> 983 retval = self.callback(*args, **kwargs)
984 return self._style(retval)
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/core/spaces.py:581, in Callable.__call__(self, *args, **kwargs)
578 args, kwargs = (), dict(pos_kwargs, **kwargs)
580 try:
--> 581 ret = self.callable(*args, **kwargs)
582 except KeyError:
583 # KeyError is caught separately because it is used to signal
584 # invalid keys on DynamicMap and should not warn
585 raise
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/core/data/__init__.py:987, in Dataset.groupby.<locals>.load_subset(*args)
985 def load_subset(*args):
986 constraint = dict(zip(dim_names, args))
--> 987 group = self.select(**constraint)
988 if np.isscalar(group):
989 return group_type(([group],), group=self.group,
990 label=self.label, vdims=self.vdims)
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/core/data/__init__.py:195, in PipelineMeta.pipelined.<locals>.pipelined_fn(*args, **kwargs)
192 inst._in_method = True
194 try:
--> 195 result = method_fn(*args, **kwargs)
196 if PipelineMeta.disable:
197 return result
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/core/data/__init__.py:622, in Dataset.select(self, selection_expr, selection_specs, **selection)
620 # Handle selection kwargs
621 if selection:
--> 622 data = self.interface.select(self, **selection)
623 else:
624 data = self.data
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/holoviews/core/data/pandas.py:418, in PandasInterface.select(cls, dataset, selection_mask, **selection)
416 df = df[selection_mask]
417 elif selection_mask is not None:
--> 418 df = df.iloc[selection_mask]
419 if indexed and len(df) == 1 and len(dataset.vdims) == 1:
420 return df[dataset.vdims[0].name].iloc[0]
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/pandas/core/indexing.py:1191, in _LocationIndexer.__getitem__(self, key)
1189 maybe_callable = com.apply_if_callable(key, self.obj)
1190 maybe_callable = self._check_deprecated_callable_usage(key, maybe_callable)
-> 1191 return self._getitem_axis(maybe_callable, axis=axis)
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/pandas/core/indexing.py:1739, in _iLocIndexer._getitem_axis(self, key, axis)
1737 if com.is_bool_indexer(key):
1738 self._validate_key(key, axis)
-> 1739 return self._getbool_axis(key, axis=axis)
1741 # a list of integers
1742 elif is_list_like_indexer(key):
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/pandas/core/indexing.py:1209, in _LocationIndexer._getbool_axis(self, key, axis)
1205 @final
1206 def _getbool_axis(self, key, axis: AxisInt):
1207 # caller is responsible for ensuring non-None axis
1208 labels = self.obj._get_axis(axis)
-> 1209 key = check_bool_indexer(labels, key)
1210 inds = key.nonzero()[0]
1211 return self.obj._take_with_is_copy(inds, axis=axis)
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/pandas/core/indexing.py:2681, in check_bool_indexer(index, key)
2677 elif not is_array_like(result):
2678 # GH 33924
2679 # key may contain nan elements, check_array_indexer needs bool array
2680 result = pd_array(result, dtype=bool)
-> 2681 return check_array_indexer(index, result)
File /localdata1/miniforge3/conda-envs/fabe_y1/irr_pred/lib/python3.10/site-packages/pandas/core/indexers/utils.py:539, in check_array_indexer(array, indexer)
537 # GH26658
538 if len(indexer) != len(array):
--> 539 raise IndexError(
540 f"Boolean index has wrong length: "
541 f"{len(indexer)} instead of {len(array)}"
542 )
543 elif is_integer_dtype(dtype):
544 try:
IndexError: Boolean index has wrong length: 144 instead of 48
Hi @Samcro5C, thanks for reporting this bug, that should be fixed by https://github.com/holoviz/holoviews/pull/6579. This issue will be kept open until HoloViews is released with a fix (or a fix is implemented directly in hvPlot if needed).