I’m having some trouble understanding how the link_selection
instance is supposed to work with the index_cols
argument. My initial understanding was that if you used this argument you would create a linked selection across plots that are created from the same data. However, I am running into a problem with the most trivial implementation of this approach I can think of. An MRE is provided below:
import holoviews as hv
from holoviews.selection import link_selections
import numpy as np
import pandas as pd
import panel as pn
hv.extension('bokeh')
pn.extension()
# some fake data
data = np.random.default_rng(seed=42).normal(size=(100, 3))
cols = ['x', 'y', 'z']
df = pd.DataFrame(data, columns=cols)
df['id'] = np.arange(100)
df['foo'] = np.random.default_rng(seed=42).integers(low=1, high=10, size=100)
# want to link two plots across the `id` column
ls = link_selections.instance(index_cols=['id'])
img1 = hv.Points(df, kdims=['x', 'y'], vdims=['id']).opts(tools=['box_select'])
img2 = hv.Points(df, kdims=['x', 'z'], vdims=['id']).opts(tools=['box_select'])
pn.Row(ls(img1), ls(img2)).servable()
If I do this, I get the following error (truncated somewhat):
File "/Users/jerry/Development/project/venv/lib/python3.10/site-packages/holoviews/element/selection.py", line 334, in _get_selection_expr_for_stream_value
expr, _, _ = self._get_index_selection(kwargs['index'], index_cols)
File "/Users/jerry/Development/project/venv/lib/python3.10/site-packages/holoviews/element/selection.py", line 39, in _get_index_selection
vals = dim(index_dim).apply(ds.iloc[index], expanded=False)
File "/Users/jerry/Development/project/venv/lib/python3.10/site-packages/holoviews/core/data/interface.py", line 33, in __getitem__
res = self._perform_getitem(self.dataset, index)
File "/Users/jerry/Development/project/venv/lib/python3.10/site-packages/holoviews/core/data/interface.py", line 98, in _perform_getitem
return dataset.clone(data, kdims=kdims, vdims=vdims, datatype=datatype)
File "/Users/jerry/Development/project/venv/lib/python3.10/site-packages/holoviews/core/data/__init__.py", line 1203, in clone
return super().clone(data, shared_data, new_type, *args, **overrides)
File "/Users/jerry/Development/project/venv/lib/python3.10/site-packages/holoviews/core/dimension.py", line 561, in clone
return clone_type(data, *args, **{k:v for k,v in settings.items()
File "/Users/jerry/Development/project/venv/lib/python3.10/site-packages/holoviews/core/data/__init__.py", line 329, in __init__
initialized = Interface.initialize(type(self), data, kdims, vdims,
File "/Users/jerry/Development/project/venv/lib/python3.10/site-packages/holoviews/core/data/interface.py", line 253, in initialize
(data, dims, extra_kws) = interface.init(eltype, data, kdims, vdims)
File "/Users/jerry/Development/project/venv/lib/python3.10/site-packages/holoviews/core/data/pandas.py", line 83, in init
raise DataError('Dimensions may not reference duplicated DataFrame '
holoviews.core.data.interface.DataError: Dimensions may not reference duplicated DataFrame columns (found duplicate 'id' columns). If you want to plot a column against itself simply declare two dimensions with the same name.
Ok, so it’s mad that I have the same dimension declared twice. This comes about because in _get_index_selection
the following appears:
ds = self.clone(kdims=index_cols, new_type=Dataset)
This clones the dataset with kdims
equal to the supplied index_cols
, so now the resulting dataset has duplicate id
dimensions, because by default, if vdims
are not specified, the whole dataset is cloned. And if any of the index_cols
are present in the vdims
then we have duplicate columns. However, if I make vdims
blank or explicitly leave them out (say, specify vdims=['foo']
to hv.Points
) then I get a different error message about not being able to resolve the id
column. And that makes sense because I left it off, so of course it can’t.
This feels like a bug to me but I also feel like I could be missing something about the internals, so I would love to hear from people who are more familiar with it than me. I have worked around this by making the change that can be seen in this PR but I’m not sure if it has any downsides or knock-on effects that I’m failing to consider.