hvplot icon indicating copy to clipboard operation
hvplot copied to clipboard

Unable to group xarray.DataArray by date coordinate in hvplot.line()

Open Samcro5C opened this issue 10 months ago • 1 comments

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

Samcro5C avatar May 15 '25 18:05 Samcro5C

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).

maximlt avatar May 20 '25 12:05 maximlt