From b7a75b20c09df6fc5e3352837b66580e97830ab1 Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Sat, 26 Nov 2022 09:31:01 +0100 Subject: [PATCH 01/10] fix ibis --- hvplot/converter.py | 2 +- hvplot/ibis.py | 4 ++-- hvplot/tests/testibis.py | 22 ++++++++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 hvplot/tests/testibis.py diff --git a/hvplot/converter.py b/hvplot/converter.py index 1c2624816..b8f186fc9 100644 --- a/hvplot/converter.py +++ b/hvplot/converter.py @@ -851,7 +851,7 @@ def _process_data(self, kind, data, x, y, by, groupby, row, col, 'e.g. a NumPy array or xarray Dataset, ' 'found %s type' % (kind, type(self.data).__name__)) - if hasattr(data, 'columns') and data.columns.name and not group_label: + if hasattr(data, 'columns') and hasattr(data.columns, 'name') and data.columns.name and not group_label: group_label = data.columns.name elif not group_label: group_label = 'Variable' diff --git a/hvplot/ibis.py b/hvplot/ibis.py index c8f8a3717..0717ff0b7 100644 --- a/hvplot/ibis.py +++ b/hvplot/ibis.py @@ -4,8 +4,8 @@ def patch(name='hvplot', extension='bokeh', logo=False): try: import ibis except: - raise ImportError('Could not patch plotting API onto dask. ' - 'Dask could not be imported.') + raise ImportError('Could not patch plotting API onto ibis. ' + 'Ibis could not be imported.') _patch_plot = lambda self: hvPlotTabular(self) _patch_plot.__doc__ = hvPlotTabular.__call__.__doc__ patch_property = property(_patch_plot) diff --git a/hvplot/tests/testibis.py b/hvplot/tests/testibis.py new file mode 100644 index 000000000..0f73997c6 --- /dev/null +++ b/hvplot/tests/testibis.py @@ -0,0 +1,22 @@ +"""Ibis works with hvplot""" +import pytest + +try: + import ibis + import hvplot.ibis # noqa + import pandas as pd +except: + pytest.skip(reason='Ibis test dependencies not available', allow_module_level=True) + + +@pytest.fixture +def table(): + df = pd.DataFrame({ + "x": [pd.Timestamp("2022-01-01"), pd.Timestamp("2022-01-02")], "y": [1,2] + }) + con = ibis.pandas.connect({"df": df}) + return con.table("df") + +def test_can_hvplot(table): + """hvplot works with Ibis""" + table.hvplot(x="x", y="y") From 818c640932bbf0266e393d04efaebac28b40fb03 Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Sat, 26 Nov 2022 19:16:05 +0100 Subject: [PATCH 02/10] support python 3.6 --- hvplot/tests/testibis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hvplot/tests/testibis.py b/hvplot/tests/testibis.py index 0f73997c6..5ad5757c7 100644 --- a/hvplot/tests/testibis.py +++ b/hvplot/tests/testibis.py @@ -6,7 +6,7 @@ import hvplot.ibis # noqa import pandas as pd except: - pytest.skip(reason='Ibis test dependencies not available', allow_module_level=True) + pytest.skip(allow_module_level=True) @pytest.fixture From 1ce44cd786fc0ebf87c2d71faff278b5bcdef0e8 Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Thu, 1 Dec 2022 07:17:18 +0100 Subject: [PATCH 03/10] wip fix hist for ibis --- hvplot/converter.py | 4 +++ hvplot/tests/testibis.py | 65 ++++++++++++++++++++++++++++++++++------ 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/hvplot/converter.py b/hvplot/converter.py index b8f186fc9..403b6a5bf 100644 --- a/hvplot/converter.py +++ b/hvplot/converter.py @@ -1807,6 +1807,8 @@ def hist(self, x=None, y=None, data=None): ymin, ymax = (ys.min(), ys.max()) if is_dask(ys): ymin, ymax = ymin.compute(), ymax.compute() + elif is_ibis(ys): + ymin, ymax = ymin.execute(), ymax.execute() hist_opts['bin_range'] = ymin, ymax ds = Dataset(data, self.by) @@ -1830,6 +1832,8 @@ def hist(self, x=None, y=None, data=None): ymin, ymax = (ys.min(), ys.max()) if is_dask(ys): ymin, ymax = ymin.compute(), ymax.compute() + elif is_ibis(ys): + ymin, ymax = ymin.execute(), ymax.execute() ranges.append((ymin, ymax)) if ranges: hist_opts['bin_range'] = max_range(ranges) diff --git a/hvplot/tests/testibis.py b/hvplot/tests/testibis.py index 5ad5757c7..f1be4f2dd 100644 --- a/hvplot/tests/testibis.py +++ b/hvplot/tests/testibis.py @@ -1,22 +1,69 @@ """Ibis works with hvplot""" +import sqlite3 +from pathlib import Path + +import holoviews as hv import pytest try: + import duckdb + import hvplot.ibis # noqa + import hvplot.pandas import ibis - import hvplot.ibis # noqa import pandas as pd except: pytest.skip(allow_module_level=True) - @pytest.fixture -def table(): - df = pd.DataFrame({ - "x": [pd.Timestamp("2022-01-01"), pd.Timestamp("2022-01-02")], "y": [1,2] - }) - con = ibis.pandas.connect({"df": df}) +def reference_df(): + return pd.DataFrame( + { + "actual": [100, 150, 125, 140, 145, 135, 123], + "forecast": [90, 160, 125, 150, 141, 141, 120], + "numerical": [1.1, 1.9, 3.2, 3.8, 4.3, 5.0, 5.5], + "date": pd.date_range("2022-01-03", "2022-01-09"), + "string": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], + }, + ) + +def pandas_data(df: pd.DataFrame, *args, **kwargs): + return df + +def ibis_sqlite_data(df: pd.DataFrame, *args, **kwargs): + tmpdir = kwargs["tmpdir"] + filename = str(Path(tmpdir)/"db.db") + con = sqlite3.Connection(filename) + df.to_sql("df", con, index=False) + con = ibis.sqlite.connect(filename) return con.table("df") -def test_can_hvplot(table): +def ibis_pandas_data(df: pd.DataFrame, *args, **kwargs): + return ibis.pandas.connect({"df": df}).table("df") + +def ibis_duckdb_data(df: pd.DataFrame, *args, **kwargs): + tmpdir = kwargs["tmpdir"] + filename = str(Path(tmpdir)/"db.db") + duckdb_con = duckdb.connect(filename) + duckdb_con.execute("CREATE TABLE df AS SELECT * FROM df") + + return ibis.duckdb.connect(filename).table("df") + +@pytest.fixture(params=[pandas_data, ibis_pandas_data, ibis_duckdb_data, ibis_sqlite_data]) +def data(request, reference_df, tmpdir): + return request.param(reference_df, tmpdir=tmpdir) + +@pytest.fixture(params=["bokeh", "matplotlib", "plotly"]) +def backend(request): + return request.param + +@pytest.mark.parametrize(["x", "y"], [ + ("numerical", "actual"), +]) +def test_can_hvplot(x, y, data, backend): """hvplot works with Ibis""" - table.hvplot(x="x", y="y") + plot = data.hvplot(x=x, y=y) + hv.render(plot, backend=backend) + +def test_can_hist(data, backend): + plot = data.hvplot.hist("forecast", bins=3) + hv.render(plot, backend=backend) From 27c1f67baff785e90a42841a53fcd956de6f5d16 Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Thu, 1 Dec 2022 07:22:05 +0100 Subject: [PATCH 04/10] fix flake --- hvplot/tests/testibis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hvplot/tests/testibis.py b/hvplot/tests/testibis.py index f1be4f2dd..b7e161995 100644 --- a/hvplot/tests/testibis.py +++ b/hvplot/tests/testibis.py @@ -8,7 +8,7 @@ try: import duckdb import hvplot.ibis # noqa - import hvplot.pandas + import hvplot.pandas # noqa import ibis import pandas as pd except: From a04dde79a724b036665cb6deb036bfa8a6b92b19 Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Thu, 1 Dec 2022 07:36:08 +0100 Subject: [PATCH 05/10] fix matplotlib + test x types --- hvplot/tests/testibis.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/hvplot/tests/testibis.py b/hvplot/tests/testibis.py index b7e161995..58acd2b60 100644 --- a/hvplot/tests/testibis.py +++ b/hvplot/tests/testibis.py @@ -3,12 +3,15 @@ from pathlib import Path import holoviews as hv +import matplotlib import pytest +matplotlib.use('agg') + try: import duckdb import hvplot.ibis # noqa - import hvplot.pandas # noqa + import hvplot.pandas # noqa import ibis import pandas as pd except: @@ -27,7 +30,7 @@ def reference_df(): ) def pandas_data(df: pd.DataFrame, *args, **kwargs): - return df + return df.copy() def ibis_sqlite_data(df: pd.DataFrame, *args, **kwargs): tmpdir = kwargs["tmpdir"] @@ -56,14 +59,15 @@ def data(request, reference_df, tmpdir): def backend(request): return request.param -@pytest.mark.parametrize(["x", "y"], [ - ("numerical", "actual"), -]) -def test_can_hvplot(x, y, data, backend): +@pytest.fixture(params=["date", "numerical", "string"]) +def xseries(request): + return request.param + +def test_can_hvplot(xseries, data, backend): """hvplot works with Ibis""" - plot = data.hvplot(x=x, y=y) + plot = data.hvplot(x=xseries, y="actual") hv.render(plot, backend=backend) def test_can_hist(data, backend): - plot = data.hvplot.hist("forecast", bins=3) + plot = data.hvplot.hist("actual", bins=3) hv.render(plot, backend=backend) From 58c7dd52b08ad25edfb876cc1834024d2e1f0fe8 Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Fri, 2 Dec 2022 19:43:04 +0100 Subject: [PATCH 06/10] wip --- examples/user_guide/Pandas_API.ipynb | 15 ++++++++++++++- hvplot/tests/testibis.py | 14 +++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/examples/user_guide/Pandas_API.ipynb b/examples/user_guide/Pandas_API.ipynb index bc181ed75..ac2cc46fe 100644 --- a/examples/user_guide/Pandas_API.ipynb +++ b/examples/user_guide/Pandas_API.ipynb @@ -1172,9 +1172,22 @@ } ], "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", "name": "python", - "pygments_lexer": "ipython3" + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" } }, "nbformat": 4, diff --git a/hvplot/tests/testibis.py b/hvplot/tests/testibis.py index 58acd2b60..a1244273f 100644 --- a/hvplot/tests/testibis.py +++ b/hvplot/tests/testibis.py @@ -51,7 +51,18 @@ def ibis_duckdb_data(df: pd.DataFrame, *args, **kwargs): return ibis.duckdb.connect(filename).table("df") -@pytest.fixture(params=[pandas_data, ibis_pandas_data, ibis_duckdb_data, ibis_sqlite_data]) +class IbisMemConnection(param.Parameterized): + def __init__(self, df): + super().__init__() + self._table = ibis.memtable(df) + + def table(self, df): + return self._table + +def ibis_mem_table(df: pd.DataFrame, *args, **kwargs): + return IbisMemConnection(df=df) + +@pytest.fixture(params=[pandas_data, ibis_pandas_data, ibis_duckdb_data, ibis_sqlite_data, ibis_mem_table]) def data(request, reference_df, tmpdir): return request.param(reference_df, tmpdir=tmpdir) @@ -69,5 +80,6 @@ def test_can_hvplot(xseries, data, backend): hv.render(plot, backend=backend) def test_can_hist(data, backend): + """hist works with Ibis""" plot = data.hvplot.hist("actual", bins=3) hv.render(plot, backend=backend) From 726266fddc25534603a4c4aace5d334017bfb58c Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Fri, 2 Dec 2022 19:43:20 +0100 Subject: [PATCH 07/10] wip --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index d0de6624f..076e93762 100644 --- a/.gitignore +++ b/.gitignore @@ -129,3 +129,5 @@ hvplot/.version # Examples artefacts examples/user_guide/plot.html +*duckdb.db* +trip-data.duckdb* From 302a89213fccfdca9a1f3dc34df81db23b9fcb74 Mon Sep 17 00:00:00 2001 From: maximlt Date: Sun, 8 Oct 2023 18:30:25 +0200 Subject: [PATCH 08/10] simplify the tests --- hvplot/ibis.py | 4 +++ hvplot/tests/testibis.py | 71 ++++------------------------------------ setup.cfg | 1 + setup.py | 1 + 4 files changed, 13 insertions(+), 64 deletions(-) diff --git a/hvplot/ibis.py b/hvplot/ibis.py index 0717ff0b7..7cd3f2516 100644 --- a/hvplot/ibis.py +++ b/hvplot/ibis.py @@ -1,3 +1,7 @@ +""" +Experimental support for ibis. +""" + def patch(name='hvplot', extension='bokeh', logo=False): from . import hvPlotTabular, post_patch diff --git a/hvplot/tests/testibis.py b/hvplot/tests/testibis.py index 1b870208b..28da779bf 100644 --- a/hvplot/tests/testibis.py +++ b/hvplot/tests/testibis.py @@ -1,74 +1,17 @@ -"""Ibis works with hvplot""" -import sqlite3 -from pathlib import Path +"""Basic ibis tests""" -import holoviews as hv -import matplotlib +import numpy as np import pandas as pd import pytest -matplotlib.use('agg') - try: - import duckdb import hvplot.ibis # noqa - import hvplot.pandas # noqa import ibis -except: +except ImportError: pytest.skip(allow_module_level=True) -@pytest.fixture -def reference_df(): - return pd.DataFrame( - { - "actual": [100, 150, 125, 140, 145, 135, 123], - "forecast": [90, 160, 125, 150, 141, 141, 120], - "numerical": [1.1, 1.9, 3.2, 3.8, 4.3, 5.0, 5.5], - "date": pd.date_range("2022-01-03", "2022-01-09"), - "string": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], - }, - ) - -def pandas_data(df: pd.DataFrame, *args, **kwargs): - return df.copy() - -def ibis_sqlite_data(df: pd.DataFrame, *args, **kwargs): - tmpdir = kwargs["tmpdir"] - filename = str(Path(tmpdir)/"db.db") - con = sqlite3.Connection(filename) - df.to_sql("df", con, index=False) - con = ibis.sqlite.connect(filename) - return con.table("df") - -def ibis_pandas_data(df: pd.DataFrame, *args, **kwargs): - return ibis.pandas.connect({"df": df}).table("df") - -def ibis_duckdb_data(df: pd.DataFrame, *args, **kwargs): - tmpdir = kwargs["tmpdir"] - filename = str(Path(tmpdir)/"db.db") - duckdb_con = duckdb.connect(filename) - duckdb_con.execute("CREATE TABLE df AS SELECT * FROM df") - - return ibis.duckdb.connect(filename).table("df") - -@pytest.fixture(params=[pandas_data, ibis_pandas_data, ibis_duckdb_data, ibis_sqlite_data]) -def data(request, reference_df, tmpdir): - return request.param(reference_df, tmpdir=tmpdir) - -@pytest.fixture(params=["bokeh", "matplotlib", "plotly"]) -def backend(request): - return request.param - -@pytest.fixture(params=["date", "numerical", "string"]) -def xseries(request): - return request.param - -def test_can_hvplot(xseries, data, backend): - """hvplot works with Ibis""" - plot = data.hvplot(x=xseries, y="actual") - hv.render(plot, backend=backend) -def test_can_hist(data, backend): - """hist works with Ibis""" - plot = data.hvplot.hist("actual", bins=3) - hv.render(plot, backend=backend) +def test_ibis_hist(): + df = pd.DataFrame(dict(x=np.arange(10))) + table = ibis.memtable(df) + table.hvplot.hist('x') diff --git a/setup.cfg b/setup.cfg index 489f85a1b..d31925c26 100644 --- a/setup.cfg +++ b/setup.cfg @@ -5,3 +5,4 @@ license_file = LICENSE [tool:pyctdev.conda] namespace_map = geoviews=geoviews-core + ibis-framework=ibis-framework-core diff --git a/setup.py b/setup.py index 06cd312ca..0c844ee94 100644 --- a/setup.py +++ b/setup.py @@ -63,6 +63,7 @@ def get_setup_version(reponame): 'dask', 'polars', 'fugue', + 'ibis-framework', # ibis-framework-core on conda ] # Dependencies required to run the notebooks From 42aafdaf3bcb4a4e40ae0804a4576d12caf23bdd Mon Sep 17 00:00:00 2001 From: maximlt Date: Sun, 8 Oct 2023 18:42:07 +0200 Subject: [PATCH 09/10] clean up --- .gitignore | 2 -- examples/user_guide/Pandas_API.ipynb | 15 +-------------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 290395c53..ec5e1b785 100644 --- a/.gitignore +++ b/.gitignore @@ -129,5 +129,3 @@ hvplot/.version # Examples artefacts examples/user_guide/plot.html -*duckdb.db* -trip-data.duckdb* diff --git a/examples/user_guide/Pandas_API.ipynb b/examples/user_guide/Pandas_API.ipynb index ac2cc46fe..bc181ed75 100644 --- a/examples/user_guide/Pandas_API.ipynb +++ b/examples/user_guide/Pandas_API.ipynb @@ -1172,22 +1172,9 @@ } ], "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.7" + "pygments_lexer": "ipython3" } }, "nbformat": 4, From a5f2e40f6df4212c0c3844b9bbd5369dacdfd46e Mon Sep 17 00:00:00 2001 From: maximlt Date: Sun, 8 Oct 2023 19:09:50 +0200 Subject: [PATCH 10/10] set backend --- hvplot/tests/testibis.py | 2 ++ setup.cfg | 2 +- setup.py | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/hvplot/tests/testibis.py b/hvplot/tests/testibis.py index 28da779bf..2b2ed8b99 100644 --- a/hvplot/tests/testibis.py +++ b/hvplot/tests/testibis.py @@ -9,6 +9,8 @@ import ibis except ImportError: pytest.skip(allow_module_level=True) +else: + ibis.set_backend('sqlite') def test_ibis_hist(): diff --git a/setup.cfg b/setup.cfg index d31925c26..1c7abd0d8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -5,4 +5,4 @@ license_file = LICENSE [tool:pyctdev.conda] namespace_map = geoviews=geoviews-core - ibis-framework=ibis-framework-core + ibis-framework=ibis-sqlite diff --git a/setup.py b/setup.py index 0c844ee94..1d57c0b11 100644 --- a/setup.py +++ b/setup.py @@ -63,7 +63,7 @@ def get_setup_version(reponame): 'dask', 'polars', 'fugue', - 'ibis-framework', # ibis-framework-core on conda + 'ibis-framework', # ibis-sqlite on conda ] # Dependencies required to run the notebooks