hvPlot for derived classes
For hvplot=0.6.0, I expected to be able to use .hvplot on both library-provided classes and on user-derived classes. For instance, I expected to be able to define my own subclass of an xr.DataArray, streamz.dataframe.Dataframe, or pd.DataFrame class, and to use .hvplot() on those objects the same as on the superclass objects as long as I didn't do anything crazy in the subclass.
For a no-op derived class (just "pass"), it seems to work fine for pd.DataFrame:

But it doesn't work for the other two types:

---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-2-f306fc2739a7> in <module>
2 pass
3
----> 4 MyDataArray(np.random.randn(2, 3), dims=("x", "y"), coords={"x": [10, 20]}, name="rand").hvplot()
~/miniconda3/envs/holoviz-tutorial/lib/python3.7/site-packages/hvplot/plotting/core.py in __call__(self, x, y, kind, **kwds)
70 return pn.panel(plot, **panel_dict)
71
---> 72 return self._get_converter(x, y, kind, **kwds)(kind, x, y)
73
74 def _get_converter(self, x=None, y=None, kind=None, **kwds):
~/miniconda3/envs/holoviz-tutorial/lib/python3.7/site-packages/hvplot/plotting/core.py in _get_converter(self, x, y, kind, **kwds)
78 kind = kind or params.pop('kind', None)
79 return HoloViewsConverter(
---> 80 self._data, x, y, kind=kind, **params
81 )
82
~/miniconda3/envs/holoviz-tutorial/lib/python3.7/site-packages/hvplot/converter.py in __init__(self, data, x, y, kind, by, use_index, group_label, value_label, backlog, persist, use_dask, crs, fields, groupby, dynamic, grid, legend, rot, title, xlim, ylim, clim, symmetric, logx, logy, loglog, hover, subplots, label, invert, stacked, colorbar, datashade, rasterize, row, col, figsize, debug, framewise, aggregator, projection, global_extent, geo, precompute, flip_xaxis, flip_yaxis, dynspread, hover_cols, x_sampling, y_sampling, project, tools, attr_labels, coastline, tiles, sort_date, check_symmetric_max, **kwds)
322 self._process_data(kind, data, x, y, by, groupby, row, col,
323 use_dask, persist, backlog, label, value_label,
--> 324 hover_cols, attr_labels, kwds)
325
326 self.dynamic = dynamic
~/miniconda3/envs/holoviz-tutorial/lib/python3.7/site-packages/hvplot/converter.py in _process_data(self, kind, data, x, y, by, groupby, row, col, use_dask, persist, backlog, label, value_label, hover_cols, attr_labels, kwds)
657 self.data = data
658 else:
--> 659 raise ValueError('Supplied data type %s not understood' % type(data).__name__)
660
661 # Validate data and arguments
ValueError: Supplied data type MyDataArray not understood

---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-2-c6573a02656f> in <module>
2 pass
3
----> 4 MyRandom(interval='200ms', freq='50ms').hvplot()
~/miniconda3/envs/holoviz-tutorial/lib/python3.7/site-packages/hvplot/plotting/core.py in __call__(self, x, y, kind, **kwds)
70 return pn.panel(plot, **panel_dict)
71
---> 72 return self._get_converter(x, y, kind, **kwds)(kind, x, y)
73
74 def _get_converter(self, x=None, y=None, kind=None, **kwds):
~/miniconda3/envs/holoviz-tutorial/lib/python3.7/site-packages/hvplot/plotting/core.py in _get_converter(self, x, y, kind, **kwds)
78 kind = kind or params.pop('kind', None)
79 return HoloViewsConverter(
---> 80 self._data, x, y, kind=kind, **params
81 )
82
~/miniconda3/envs/holoviz-tutorial/lib/python3.7/site-packages/hvplot/converter.py in __init__(self, data, x, y, kind, by, use_index, group_label, value_label, backlog, persist, use_dask, crs, fields, groupby, dynamic, grid, legend, rot, title, xlim, ylim, clim, symmetric, logx, logy, loglog, hover, subplots, label, invert, stacked, colorbar, datashade, rasterize, row, col, figsize, debug, framewise, aggregator, projection, global_extent, geo, precompute, flip_xaxis, flip_yaxis, dynspread, hover_cols, x_sampling, y_sampling, project, tools, attr_labels, coastline, tiles, sort_date, check_symmetric_max, **kwds)
322 self._process_data(kind, data, x, y, by, groupby, row, col,
323 use_dask, persist, backlog, label, value_label,
--> 324 hover_cols, attr_labels, kwds)
325
326 self.dynamic = dynamic
~/miniconda3/envs/holoviz-tutorial/lib/python3.7/site-packages/hvplot/converter.py in _process_data(self, kind, data, x, y, by, groupby, row, col, use_dask, persist, backlog, label, value_label, hover_cols, attr_labels, kwds)
657 self.data = data
658 else:
--> 659 raise ValueError('Supplied data type %s not understood' % type(data).__name__)
660
661 # Validate data and arguments
ValueError: Supplied data type MyRandom not understood
My guess is that it's because this code in hvplot/util.py is only checking by the source module, not isinstance:
def check_library(obj, library):
if not isinstance(library, list):
library = [library]
return any([obj.__module__.split('.')[0].startswith(l) for l in library])
But if so I don't have any explanation for why classes derived from pd.DataFrame seem to work, given that all the classes defined above should be in module __main__.
Ah, looks like hvplot/converter.py is using isinstance(data, pd.DataFrame) for pandas, but check_library for the rest. That explains the different behavior, leaving this as a request for hvplot to check by class in all the cases, at least if the module lookup fails. Looks tricky, as we'll now need to store a list of the (super)classes supported, not just the modules, but I think it's important.
For now a workaround is to falsely claim your subclass is defined where the superclass is, as in MyRandom.__module__= 'streamz.dataframe.core'. Seems to work, but obviously not recommended in the long term!
It seems to be that check_library could be replaced by:
def check_module(data, module):
if module =='dask' and module in sys.modules:
import dask.dataframe as dd
return isinstance(data, (dd.Series, dd.DataFrame))
elif ...
as we'll now need to store a list of the (super)classes supported, not just the modules, but I think it's important.
Having a mapping of modules and their supported classes wouldn't be a bad idea!