interactive DataFrame: .loc with interactive boolean Series and column not working
Versions
hvplot = 0.8.2
Description
the .loc method can take a row plus a column parameter in Pandas. When using an interactive DataFrame, this behavior should be conserved. But when using an interactive boolean Series as the row parameter, specifying a column leads to an error message.
Example
import hvplot.pandas
from bokeh.sampledata.penguins import data as df
dfi = df.interactive()
# ERROR
dfi.loc[dfi['body_mass_g'] > 4000,'bill_length_mm'] # interactive boolean Series + column
On the other hand, those slight modifications all work.
# normal DataFrame: works
df.loc[df['body_mass_g'] > 4000,'bill_length_mm'] # works: no interactive DataFrame
# interactive DataFrame: variations that work
dfi.loc[[10,11,12],'bill_length_mm'] # works: list + column
dfi.loc[dfi['body_mass_g'] > 4000] # works: interactive boolean Series
dfi.loc[df['body_mass_g'] > 4000,'bill_length_mm'] # works: normal boolean Series + column
dfi.loc[dfi['body_mass_g'] > 4000]['bill_length_mm'] # works: interactive boolean Series, column selected on output
Traceback
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Input In [33], in <cell line: 8>()
4 df.loc[df['body_mass_g'] > 4000,'bill_length_mm']
6 dfi = df.interactive()
----> 8 dfi.loc[dfi['body_mass_g'] > 4000,'bill_length_mm']
File ~/Dropbox/Berry-Vaziri-Collaboration/.venv/lib/python3.9/site-packages/hvplot/interactive.py:634, in Interactive.__getitem__(self, other)
632 def __getitem__(self, other):
633 other = other._transform if isinstance(other, Interactive) else other
--> 634 return self._apply_operator(operator.getitem, other)
File ~/Dropbox/Berry-Vaziri-Collaboration/.venv/lib/python3.9/site-packages/hvplot/interactive.py:521, in Interactive._apply_operator(self, operator, reverse, *args, **kwargs)
519 transform = new._transform
520 transform = type(transform)(transform, operator, *args, reverse=reverse)
--> 521 return new._clone(transform)
File ~/Dropbox/Berry-Vaziri-Collaboration/.venv/lib/python3.9/site-packages/hvplot/interactive.py:370, in Interactive._clone(self, transform, plot, loc, center, dmap, copy, max_rows, **kwargs)
368 else:
369 kwargs = dict(self._inherit_kwargs, **dict(self._kwargs, **kwargs))
--> 370 return type(self)(self._obj, fn=self._fn, transform=transform, plot=plot, depth=depth,
371 loc=loc, center=center, dmap=dmap, _shared_obj=self._shared_obj,
372 max_rows=max_rows, **kwargs)
File ~/Dropbox/Berry-Vaziri-Collaboration/.venv/lib/python3.9/site-packages/hvplot/interactive.py:276, in Interactive.__init__(self, obj, transform, fn, plot, depth, loc, center, dmap, inherit_kwargs, max_rows, method, _shared_obj, _current, **kwargs)
274 self._current = _current
275 else:
--> 276 self._current = self._transform.apply(ds, keep_index=True, compute=False)
277 self._init = True
278 self.hvplot = _hvplot(self)
File ~/Dropbox/Berry-Vaziri-Collaboration/.venv/lib/python3.9/site-packages/holoviews/util/transform.py:773, in dim.apply(self, dataset, flat, expanded, ranges, all_values, keep_index, compute, strict)
771 drange = ranges.get(eldim, {})
772 drange = drange.get('combined', drange)
--> 773 data = self._apply_fn(dataset, data, fn, fn_name, args,
774 kwargs, accessor, drange)
775 drop_index = keep_index_for_compute and not keep_index
776 compute = not compute_for_compute and compute
File ~/Dropbox/Berry-Vaziri-Collaboration/.venv/lib/python3.9/site-packages/holoviews/util/transform.py:673, in dim._apply_fn(self, dataset, data, fn, fn_name, args, kwargs, accessor, drange)
671 raise e
672 else:
--> 673 data = fn(*args, **kwargs)
675 return data
File ~/Dropbox/Berry-Vaziri-Collaboration/.venv/lib/python3.9/site-packages/pandas/core/indexing.py:1065, in _LocationIndexer.__getitem__(self, key)
1063 if type(key) is tuple:
1064 key = tuple(list(x) if is_iterator(x) else x for x in key)
-> 1065 key = tuple(com.apply_if_callable(x, self.obj) for x in key)
1066 if self._is_scalar_access(key):
1067 return self.obj._get_value(*key, takeable=self._takeable)
File ~/Dropbox/Berry-Vaziri-Collaboration/.venv/lib/python3.9/site-packages/pandas/core/indexing.py:1065, in <genexpr>(.0)
1063 if type(key) is tuple:
1064 key = tuple(list(x) if is_iterator(x) else x for x in key)
-> 1065 key = tuple(com.apply_if_callable(x, self.obj) for x in key)
1066 if self._is_scalar_access(key):
1067 return self.obj._get_value(*key, takeable=self._takeable)
File ~/Dropbox/Berry-Vaziri-Collaboration/.venv/lib/python3.9/site-packages/pandas/core/common.py:364, in apply_if_callable(maybe_callable, obj, **kwargs)
353 """
354 Evaluate possibly callable input using obj and kwargs if it is callable,
355 otherwise return as it is.
(...)
361 **kwargs
362 """
363 if callable(maybe_callable):
--> 364 return maybe_callable(obj, **kwargs)
366 return maybe_callable
File ~/Dropbox/Berry-Vaziri-Collaboration/.venv/lib/python3.9/site-packages/hvplot/interactive.py:490, in Interactive.__call__(self, *args, **kwargs)
488 return self._clone(*args, **kwargs)
489 # TODO: When is this error raised?
--> 490 raise AttributeError
491 elif self._method == 'plot':
492 # This - {ax: get_ax} - is passed as kwargs to the plot method in
493 # the dim expression.
494 kwargs['ax'] = self._get_ax_fn()
AttributeError:
This is very much related to my previous issue #926.
In the tests that I show here, it becomes clear that interactive boolean Series as input to .loc actually does work, but that the actual issue is the simultaneous specification of rows and columns (with one being an interactive boolean Series). Maybe both issues should be merged somehow?
Thanks for the bug report! Indeed the two issues look similar, I think it's ok to keep them both open until someone digs into that and finds out whether they have the exact same root cause. Hoping to spend more time on hvPlot once Panel 1.0 is released :)
@maximlt Seems to work now as far as I can see. Close the issue?