From e34111cc355bd2c9448746130bd3aa4df5241613 Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Tue, 3 Dec 2024 15:04:30 +0100 Subject: [PATCH 1/4] check cmap type before comparing to categories --- hvplot/converter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hvplot/converter.py b/hvplot/converter.py index 9aadbc358..7802475e6 100644 --- a/hvplot/converter.py +++ b/hvplot/converter.py @@ -1485,7 +1485,7 @@ def _process_style(self, kwds, plot_opts): if 'color' in style_opts: color = style_opts['color'] elif not isinstance(cmap, dict): - if cmap and any(c in cmap for c in categories): + if isinstance(cmap, str) and any(c in cmap for c in categories): color = process_cmap(cmap or self._default_cmaps['categorical'], categorical=True) else: color = cmap From e654de01f74264cc6c4b7ace76dc470648e79c49 Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Thu, 5 Dec 2024 12:52:20 +0100 Subject: [PATCH 2/4] add test --- hvplot/tests/testcharts.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hvplot/tests/testcharts.py b/hvplot/tests/testcharts.py index 0067d6444..fead2d0a6 100644 --- a/hvplot/tests/testcharts.py +++ b/hvplot/tests/testcharts.py @@ -606,3 +606,14 @@ def test_table_datetime_index_displayed(self): def test_table_multi_index_displayed(self): raise SkipTest('Dask does not support MultiIndex Dataframes.') + + +def test_cmap_LinearSegmentedColormap(): + # test for https://github.com/holoviz/hvplot/pull/1461 + xr = pytest.importorskip('xarray') + mpl = pytest.importorskip('matplotlib') + import hvplot.xarray # noqa + + data = np.arange(25).reshape(5, 5) + xr_da = xr.DataArray(data) + xr_da.hvplot.image(cmap=mpl.colormaps['viridis']) From 6f50b095686a867a6a120cf8402033c2663de7d5 Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Thu, 5 Dec 2024 13:27:40 +0100 Subject: [PATCH 3/4] code refactor --- hvplot/converter.py | 7 +++++-- hvplot/util.py | 9 +++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/hvplot/converter.py b/hvplot/converter.py index 7802475e6..9f15b40d6 100644 --- a/hvplot/converter.py +++ b/hvplot/converter.py @@ -76,6 +76,7 @@ process_derived_datetime_pandas, _convert_col_names_to_str, import_datashader, + _mpl_cmap, ) from .utilities import hvplot_extension @@ -1420,7 +1421,7 @@ def _process_style(self, kwds, plot_opts): valid_opts = [] cmap_opts = ('cmap', 'colormap', 'color_key') - categories = [ + categorical_cmaps = [ 'accent', 'category', 'dark', @@ -1485,7 +1486,9 @@ def _process_style(self, kwds, plot_opts): if 'color' in style_opts: color = style_opts['color'] elif not isinstance(cmap, dict): - if isinstance(cmap, str) and any(c in cmap for c in categories): + if (isinstance(cmap, str) or _mpl_cmap(cmap)) and any( + c in getattr(cmap, 'name', cmap) for c in categorical_cmaps + ): color = process_cmap(cmap or self._default_cmaps['categorical'], categorical=True) else: color = cmap diff --git a/hvplot/util.py b/hvplot/util.py index e0392e300..7c4c74661 100644 --- a/hvplot/util.py +++ b/hvplot/util.py @@ -750,3 +750,12 @@ def relabel_redim(hv_obj, relabel_kwargs, redim_kwargs): if redim_kwargs: hv_obj = hv_obj.redim(**redim_kwargs) return hv_obj + + +def _mpl_cmap(obj): + """Check if the object is a Matplotlib LinearSegmentedColormap.""" + if 'matplotlib' not in sys.modules: + return False + from matplotlib.colors import LinearSegmentedColormap + + return isinstance(obj, LinearSegmentedColormap) From 1393fd1a12896da9b1be625824239087ebf18a4d Mon Sep 17 00:00:00 2001 From: Isaiah Akorita Date: Mon, 9 Dec 2024 16:47:49 +0100 Subject: [PATCH 4/4] post-review --- hvplot/converter.py | 10 +++++++--- hvplot/util.py | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/hvplot/converter.py b/hvplot/converter.py index 9f15b40d6..0d225a94a 100644 --- a/hvplot/converter.py +++ b/hvplot/converter.py @@ -76,7 +76,7 @@ process_derived_datetime_pandas, _convert_col_names_to_str, import_datashader, - _mpl_cmap, + is_mpl_cmap, ) from .utilities import hvplot_extension @@ -1486,8 +1486,12 @@ def _process_style(self, kwds, plot_opts): if 'color' in style_opts: color = style_opts['color'] elif not isinstance(cmap, dict): - if (isinstance(cmap, str) or _mpl_cmap(cmap)) and any( - c in getattr(cmap, 'name', cmap) for c in categorical_cmaps + # Checks if any of the categorical cmaps matches cmap; + # uses any() instead of `cmap in categorical_cmaps` to handle reversed colormaps (suffixed with `_r`). + # If cmap is LinearSegmentedColormap, get the name attr, else return the str typed cmap. + if (isinstance(cmap, str) or is_mpl_cmap(cmap)) and any( + categorical_cmap in getattr(cmap, 'name', cmap) + for categorical_cmap in categorical_cmaps ): color = process_cmap(cmap or self._default_cmaps['categorical'], categorical=True) else: diff --git a/hvplot/util.py b/hvplot/util.py index 7c4c74661..db347c608 100644 --- a/hvplot/util.py +++ b/hvplot/util.py @@ -752,7 +752,7 @@ def relabel_redim(hv_obj, relabel_kwargs, redim_kwargs): return hv_obj -def _mpl_cmap(obj): +def is_mpl_cmap(obj): """Check if the object is a Matplotlib LinearSegmentedColormap.""" if 'matplotlib' not in sys.modules: return False