From c1bfc3139f0f5441e01b03cc82b8513619fcab62 Mon Sep 17 00:00:00 2001 From: maximlt Date: Thu, 21 Dec 2023 11:38:34 +0100 Subject: [PATCH 1/2] add a test and avoid patching --- hvplot/plotting/__init__.py | 2 +- hvplot/plotting/core.py | 42 +++++++++++++++++++++++++++++++ hvplot/polars.py | 48 ++---------------------------------- hvplot/tests/testplotting.py | 21 ++++++++++++++-- 4 files changed, 64 insertions(+), 49 deletions(-) diff --git a/hvplot/plotting/__init__.py b/hvplot/plotting/__init__.py index 68e6f9c53..0f0f7b45b 100644 --- a/hvplot/plotting/__init__.py +++ b/hvplot/plotting/__init__.py @@ -31,7 +31,7 @@ def plot(data, kind, **kwargs): no_none_kwargs[k] = v if is_polars(data): - from hvplot.polars import hvPlotTabularPolars + from .core import hvPlotTabularPolars return hvPlotTabularPolars(data)(kind=kind, **no_none_kwargs) return hvPlotTabular(data)(kind=kind, **no_none_kwargs) diff --git a/hvplot/plotting/core.py b/hvplot/plotting/core.py index a02cebf3a..5eb0b46e6 100644 --- a/hvplot/plotting/core.py +++ b/hvplot/plotting/core.py @@ -1,3 +1,4 @@ +import itertools from collections import defaultdict import param @@ -1862,6 +1863,47 @@ def labels(self, x=None, y=None, text=None, **kwds): return self(x, y, text=text, kind="labels", **kwds) +class hvPlotTabularPolars(hvPlotTabular): + def _get_converter(self, x=None, y=None, kind=None, **kwds): + import polars as pl + + params = dict(self._metadata, **kwds) + x = x or params.pop("x", None) + y = y or params.pop("y", None) + kind = kind or params.pop("kind", None) + + # Find columns which should be converted for LazyDataFrame and DataFrame + if isinstance(self._data, (pl.LazyFrame, pl.DataFrame)): + if params.get("hover_cols") == "all": + columns = list(self._data.columns) + else: + possible_columns = [ + [v] if isinstance(v, str) else v + for v in params.values() + if isinstance(v, (str, list)) + ] + columns = ( + set(self._data.columns) & set(itertools.chain(*possible_columns)) + ) or {self._data.columns[0]} + xs = x if is_list_like(x) else (x,) + ys = y if is_list_like(y) else (y,) + columns |= {*xs, *ys} + columns.discard(None) + + if isinstance(self._data, pl.DataFrame): + data = self._data.select(columns).to_pandas() + elif isinstance(self._data, pl.Series): + data = self._data.to_pandas() + elif isinstance(self._data, pl.LazyFrame): + data = self._data.select(columns).collect().to_pandas() + else: + raise ValueError( + "Only Polars DataFrame, Series, and LazyFrame are supported" + ) + + return HoloViewsConverter(data, x, y, kind=kind, **params) + + class hvPlot(hvPlotTabular): """ The plotting method: `df.hvplot(...)` creates a plot similarly to the familiar Pandas diff --git a/hvplot/polars.py b/hvplot/polars.py index 8ec9d4ff7..0a480ff64 100644 --- a/hvplot/polars.py +++ b/hvplot/polars.py @@ -1,50 +1,6 @@ """Adds the `.hvplot` method to pl.DataFrame, pl.LazyFrame and pl.Series""" -import itertools - -from hvplot import hvPlotTabular, post_patch -from hvplot.converter import HoloViewsConverter -from hvplot.util import is_list_like - - -class hvPlotTabularPolars(hvPlotTabular): - def _get_converter(self, x=None, y=None, kind=None, **kwds): - import polars as pl - - params = dict(self._metadata, **kwds) - x = x or params.pop("x", None) - y = y or params.pop("y", None) - kind = kind or params.pop("kind", None) - - # Find columns which should be converted for LazyDataFrame and DataFrame - if isinstance(self._data, (pl.LazyFrame, pl.DataFrame)): - if params.get("hover_cols") == "all": - columns = list(self._data.columns) - else: - possible_columns = [ - [v] if isinstance(v, str) else v - for v in params.values() - if isinstance(v, (str, list)) - ] - columns = ( - set(self._data.columns) & set(itertools.chain(*possible_columns)) - ) or {self._data.columns[0]} - xs = x if is_list_like(x) else (x,) - ys = y if is_list_like(y) else (y,) - columns |= {*xs, *ys} - columns.discard(None) - - if isinstance(self._data, pl.DataFrame): - data = self._data.select(columns).to_pandas() - elif isinstance(self._data, pl.Series): - data = self._data.to_pandas() - elif isinstance(self._data, pl.LazyFrame): - data = self._data.select(columns).collect().to_pandas() - else: - raise ValueError( - "Only Polars DataFrame, Series, and LazyFrame are supported" - ) - - return HoloViewsConverter(data, x, y, kind=kind, **params) +from hvplot import post_patch +from hvplot.plotting.core import hvPlotTabularPolars def patch(name="hvplot", extension="bokeh", logo=False): diff --git a/hvplot/tests/testplotting.py b/hvplot/tests/testplotting.py index 135319041..6e183da76 100644 --- a/hvplot/tests/testplotting.py +++ b/hvplot/tests/testplotting.py @@ -1,13 +1,23 @@ """ Tests pandas.options.backend setting """ -from packaging.version import Version from unittest import TestCase, SkipTest + +import holoviews as hv import pandas as pd +import pytest +from packaging.version import Version from parameterized import parameterized -from ..converter import HoloViewsConverter +from hvplot.converter import HoloViewsConverter +from hvplot.plotting import plot + +try: + import polars as pl + skip_polar = False +except ImportError: + skip_polar = True no_args = ['line', 'area', 'hist', 'box', 'kde', 'density', 'bar', 'barh'] @@ -58,3 +68,10 @@ def setUp(self): raise SkipTest('entrypoints for plotting.backends was added ' 'in pandas 0.25.1') pd.options.plotting.backend = 'hvplot' + + +@pytest.mark.skipif(skip_polar, reason="polars not installed") +def test_plot_supports_polars(): + dfp = pl.DataFrame(pd._testing.makeDataFrame()) + out = plot(dfp, 'line') + assert isinstance(out, hv.Curve) From d9169f9a435defd398a8f3c6d5c93470480471f8 Mon Sep 17 00:00:00 2001 From: maximlt Date: Thu, 21 Dec 2023 12:13:16 +0100 Subject: [PATCH 2/2] use pytest.importorskip --- hvplot/tests/testplotting.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/hvplot/tests/testplotting.py b/hvplot/tests/testplotting.py index 6e183da76..5ef8d6584 100644 --- a/hvplot/tests/testplotting.py +++ b/hvplot/tests/testplotting.py @@ -13,13 +13,6 @@ from hvplot.converter import HoloViewsConverter from hvplot.plotting import plot -try: - import polars as pl - skip_polar = False -except ImportError: - skip_polar = True - - no_args = ['line', 'area', 'hist', 'box', 'kde', 'density', 'bar', 'barh'] x_y = ['scatter', 'hexbin'] @@ -70,8 +63,8 @@ def setUp(self): pd.options.plotting.backend = 'hvplot' -@pytest.mark.skipif(skip_polar, reason="polars not installed") def test_plot_supports_polars(): + pl = pytest.importorskip("polars") dfp = pl.DataFrame(pd._testing.makeDataFrame()) out = plot(dfp, 'line') assert isinstance(out, hv.Curve)