FutureWarning when creating a DynamicMap

Hi,

I noticed that a FutureWarning is displayed when creating a DynamicMap from an xarray DataArray (no warning is raised when creating a HoloMap, i.e. dynamic=False).

Here is a minimum working example (the problem initially came up in a more complex context):

import numpy as np
import xarray as xr
import holoviews as hv

nx = 10
ny = 15
nz = 20

xarray = xr.DataArray(
    np.ones((nx, ny, nz)),
    coords={'x': range(nx), 'y': range(ny), 'z': range(nz)},
    name='data'
)

hv.Dataset(xarray).to(hv.Image, dynamic=True)

This creates the following warning:

~/miniconda3/envs/ubermagdev310/lib/python3.10/site-packages/holoviews/core/util.py:1175: FutureWarning: unique with argument that is not not a Series, Index, ExtensionArray, or np.ndarray is deprecated and will raise in a future version.
  return pd.unique(values)

Is this related to some of the HoloViews internals or a problem of my input data?
If it is related to HoloViews internals, is it safe to hide it using warnings.simplefilter?

System and software:

  • Linux (Debian 11)
  • Python 3.10 (from conda-forge)
  • Packages installed from PyPI:
    • xarray 2023.9.0
    • numpy 1.26.0
    • holoviews 1.17.1
    • pandas 2.1.1

[Broader context: we include a HoloViews wrapper in a library for finite-difference scalar and vector fields (GitHub - ubermag/discretisedfield: Python package for the analysis and visualisation of finite-difference fields.) that we are working on and would not want our users to see this warning.]

Many thanks,
Martin

Appendix:

Raising an exception for the warning using:

warnings.simplefilter("error")
hv.Dataset(xarray).to(hv.Image, dynamic=True)

produces the following traceback:

---------------------------------------------------------------------------
FutureWarning                             Traceback (most recent call last)
Cell In[10], line 2
      1 warnings.simplefilter("error")
----> 2 hv.Dataset(xarray).to(hv.Image, dynamic=True)

File ~/miniconda3/envs/ubermagdev310/lib/python3.10/site-packages/holoviews/core/data/__init__.py:144, in DataConversion.__call__(self, new_type, kdims, vdims, groupby, sort, **kwargs)
    142     element = new_type(selected, **params)
    143     return element.sort() if sort else element
--> 144 group = selected.groupby(groupby, container_type=HoloMap,
    145                          group_type=new_type, **params)
    146 if sort:
    147     return group.map(lambda x: x.sort(), [new_type])

File ~/miniconda3/envs/ubermagdev310/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 ~/miniconda3/envs/ubermagdev310/lib/python3.10/site-packages/holoviews/core/data/__init__.py:986, in Dataset.groupby(self, dimensions, container_type, group_type, dynamic, **kwargs)
    984             data = data.columns()
    985         return group_type(data, **group_kwargs)
--> 986     dynamic_dims = [d.clone(values=list(self.interface.values(self, d.name, False)))
    987                     for d in dimensions]
    988     return DynamicMap(load_subset, kdims=dynamic_dims)
    990 return self.interface.groupby(self, dim_names, container_type,
    991                               group_type, **kwargs)

File ~/miniconda3/envs/ubermagdev310/lib/python3.10/site-packages/holoviews/core/data/__init__.py:986, in <listcomp>(.0)
    984             data = data.columns()
    985         return group_type(data, **group_kwargs)
--> 986     dynamic_dims = [d.clone(values=list(self.interface.values(self, d.name, False)))
    987                     for d in dimensions]
    988     return DynamicMap(load_subset, kdims=dynamic_dims)
    990 return self.interface.groupby(self, dim_names, container_type,
    991                               group_type, **kwargs)

File ~/miniconda3/envs/ubermagdev310/lib/python3.10/site-packages/holoviews/core/dimension.py:331, in Dimension.clone(self, spec, **overrides)
    327         self.param.warning(
    328             f'Using label as supplied by keyword ({overrides["label"]!r}), '
    329             f'ignoring tuple value {spec[1]!r}')
    330     spec = (spec[0],  overrides['label'])
--> 331 return self.__class__(spec, **{k:v for k,v in settings.items()
    332                                if k not in ['name', 'label']})

File ~/miniconda3/envs/ubermagdev310/lib/python3.10/site-packages/holoviews/core/dimension.py:287, in Dimension.__init__(self, spec, **params)
    283     self.param.warning("The 'initial' string for dimension values "
    284                        "is no longer supported.")
    285     values = []
--> 287 all_params['values'] = list(util.unique_array(values))
    288 super().__init__(**all_params)
    289 if self.default is not None:

File ~/miniconda3/envs/ubermagdev310/lib/python3.10/site-packages/holoviews/core/util.py:1175, in unique_array(arr)
   1173         v = pd.Timestamp(v).to_datetime64()
   1174     values.append(v)
-> 1175 return pd.unique(values)

File ~/miniconda3/envs/ubermagdev310/lib/python3.10/site-packages/pandas/core/algorithms.py:401, in unique(values)
    307 def unique(values):
    308     """
    309     Return unique values based on a hash table.
    310 
   (...)
    399     array([('a', 'b'), ('b', 'a'), ('a', 'c')], dtype=object)
    400     """
--> 401     return unique_with_mask(values)

File ~/miniconda3/envs/ubermagdev310/lib/python3.10/site-packages/pandas/core/algorithms.py:429, in unique_with_mask(values, mask)
    427 def unique_with_mask(values, mask: npt.NDArray[np.bool_] | None = None):
    428     """See algorithms.unique for docs. Takes a mask for masked arrays."""
--> 429     values = _ensure_arraylike(values, func_name="unique")
    431     if isinstance(values.dtype, ExtensionDtype):
    432         # Dispatch to extension dtype's unique.
    433         return values.unique()

File ~/miniconda3/envs/ubermagdev310/lib/python3.10/site-packages/pandas/core/algorithms.py:225, in _ensure_arraylike(values, func_name)
    221 if not isinstance(values, (ABCIndex, ABCSeries, ABCExtensionArray, np.ndarray)):
    222     # GH#52986
    223     if func_name != "isin-targets":
    224         # Make an exception for the comps argument in isin.
--> 225         warnings.warn(
    226             f"{func_name} with argument that is not not a Series, Index, "
    227             "ExtensionArray, or np.ndarray is deprecated and will raise in a "
    228             "future version.",
    229             FutureWarning,
    230             stacklevel=find_stack_level(),
    231         )
    233     inferred = lib.infer_dtype(values, skipna=False)
    234     if inferred in ["mixed", "string", "mixed-integer"]:
    235         # "mixed-integer" to ensure we do not cast ["ss", 42] to str GH#22160

FutureWarning: unique with argument that is not not a Series, Index, ExtensionArray, or np.ndarray is deprecated and will raise in a future version.

Seems safe enough to ignore it. It is getting raised by pandas itself.

I assume that when the pandas devs convert the warning to an error, they will also remove any triggers in their codebase.

It is safe to ignore. Will be fixed in the next HoloViews release.