From f8fdcd70ea19f87435af71db5fd486caed3d3053 Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Sat, 17 Sep 2022 14:41:17 +0200 Subject: [PATCH 1/9] CI: Fix matplolib release issues --- pandas/compat/__init__.py | 2 ++ pandas/compat/matplotlib.py | 13 +++++++++++++ pandas/tests/plotting/frame/test_frame.py | 14 +++++++++----- pandas/tests/plotting/test_datetimelike.py | 3 +++ pandas/tests/plotting/test_hist_method.py | 2 ++ pandas/tests/plotting/test_series.py | 2 ++ 6 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 pandas/compat/matplotlib.py diff --git a/pandas/compat/__init__.py b/pandas/compat/__init__.py index 80f66c945ba27..6ab37bed91d0c 100644 --- a/pandas/compat/__init__.py +++ b/pandas/compat/__init__.py @@ -15,6 +15,7 @@ from typing import TYPE_CHECKING from pandas._typing import F +from pandas.compat.matplotlib import is_at_least_matplotlib_36 from pandas.compat.numpy import ( is_numpy_dev, np_version_under1p21, @@ -152,6 +153,7 @@ def get_lzma_file() -> type[lzma.LZMAFile]: __all__ = [ + "is_at_least_matplotlib_36", "is_numpy_dev", "np_version_under1p21", "pa_version_under1p01", diff --git a/pandas/compat/matplotlib.py b/pandas/compat/matplotlib.py new file mode 100644 index 0000000000000..ff080e5e9dfcc --- /dev/null +++ b/pandas/compat/matplotlib.py @@ -0,0 +1,13 @@ +from __future__ import annotations + +from pandas.util.version import Version + +try: + import matplotlib + + _matplotlib_version = matplotlib.__version__ + _matplotliblv = Version(_matplotlib_version) + is_at_least_matplotlib_36 = _matplotliblv >= Version("3.6.0") + +except ImportError: + is_at_least_matplotlib_36 = True diff --git a/pandas/tests/plotting/frame/test_frame.py b/pandas/tests/plotting/frame/test_frame.py index 94226ae1a2575..a767e88cfd28c 100644 --- a/pandas/tests/plotting/frame/test_frame.py +++ b/pandas/tests/plotting/frame/test_frame.py @@ -1534,8 +1534,8 @@ def test_errorbar_plot_iterator(self): def test_errorbar_with_integer_column_names(self): # test with integer column names - df = DataFrame(np.random.randn(10, 2)) - df_err = DataFrame(np.random.randn(10, 2)) + df = DataFrame(np.abs(np.random.randn(10, 2))) + df_err = DataFrame(np.abs(np.random.randn(10, 2))) ax = _check_plot_works(df.plot, yerr=df_err) self._check_has_errorbars(ax, xerr=0, yerr=2) ax = _check_plot_works(df.plot, y=0, yerr=1) @@ -1632,9 +1632,11 @@ def test_table(self): assert len(ax.tables) == 1 def test_errorbar_scatter(self): - df = DataFrame(np.random.randn(5, 2), index=range(5), columns=["x", "y"]) + df = DataFrame( + np.abs(np.random.randn(5, 2)), index=range(5), columns=["x", "y"] + ) df_err = DataFrame( - np.random.randn(5, 2) / 5, index=range(5), columns=["x", "y"] + np.abs(np.random.randn(5, 2)) / 5, index=range(5), columns=["x", "y"] ) ax = _check_plot_works(df.plot.scatter, x="x", y="y") @@ -1661,7 +1663,9 @@ def _check_errorbar_color(containers, expected, has_err="has_xerr"): ) # GH 8081 - df = DataFrame(np.random.randn(10, 5), columns=["a", "b", "c", "d", "e"]) + df = DataFrame( + np.abs(np.random.randn(10, 5)), columns=["a", "b", "c", "d", "e"] + ) ax = df.plot.scatter(x="a", y="b", xerr="d", yerr="e", c="red") self._check_has_errorbars(ax, xerr=1, yerr=1) _check_errorbar_color(ax.containers, "red", has_err="has_xerr") diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index cb428daac84ba..516134cfb82e8 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -14,6 +14,7 @@ BaseOffset, to_offset, ) +from pandas.compat import is_at_least_matplotlib_36 import pandas.util._test_decorators as td from pandas import ( @@ -260,6 +261,7 @@ def test_plot_multiple_inferred_freq(self): ser = Series(np.random.randn(len(dr)), index=dr) _check_plot_works(ser.plot) + @pytest.mark.xfail(is_at_least_matplotlib_36, reason="Api changed") def test_uhf(self): import pandas.plotting._matplotlib.converter as conv @@ -1209,6 +1211,7 @@ def test_secondary_legend(self): # TODO: color cycle problems assert len(colors) == 4 + @pytest.mark.xfail(is_at_least_matplotlib_36, reason="Api changed") def test_format_date_axis(self): rng = date_range("1/1/2012", periods=12, freq="M") df = DataFrame(np.random.randn(len(rng), 3), rng) diff --git a/pandas/tests/plotting/test_hist_method.py b/pandas/tests/plotting/test_hist_method.py index 9c11d589716fe..9d696dff2d75e 100644 --- a/pandas/tests/plotting/test_hist_method.py +++ b/pandas/tests/plotting/test_hist_method.py @@ -4,6 +4,7 @@ import numpy as np import pytest +from pandas.compat import is_at_least_matplotlib_36 import pandas.util._test_decorators as td from pandas import ( @@ -191,6 +192,7 @@ def test_hist_kwargs(self, ts): ax = ts.plot.hist(align="left", stacked=True, ax=ax) tm.close() + @pytest.mark.xfail(is_at_least_matplotlib_36, reason="Api changed") @td.skip_if_no_scipy def test_hist_kde(self, ts): diff --git a/pandas/tests/plotting/test_series.py b/pandas/tests/plotting/test_series.py index 2c196a7b46d9c..7128e5a51a11e 100644 --- a/pandas/tests/plotting/test_series.py +++ b/pandas/tests/plotting/test_series.py @@ -5,6 +5,7 @@ import numpy as np import pytest +from pandas.compat import is_at_least_matplotlib_36 import pandas.util._test_decorators as td import pandas as pd @@ -493,6 +494,7 @@ def test_kde_missing_vals(self): # gh-14821: check if the values have any missing values assert any(~np.isnan(axes.lines[0].get_xdata())) + @pytest.mark.xfail(is_at_least_matplotlib_36, reason="Api changed") def test_boxplot_series(self, ts): _, ax = self.plt.subplots() ax = ts.plot.box(logy=True, ax=ax) From 780dbf94989741f6539b1407e667e68ef3ca1e3c Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Sat, 17 Sep 2022 15:02:27 +0200 Subject: [PATCH 2/9] Fix remaining tests --- pandas/tests/plotting/frame/test_frame.py | 6 ++++-- pandas/tests/plotting/test_series.py | 10 ++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/pandas/tests/plotting/frame/test_frame.py b/pandas/tests/plotting/frame/test_frame.py index a767e88cfd28c..5abb0c2704f97 100644 --- a/pandas/tests/plotting/frame/test_frame.py +++ b/pandas/tests/plotting/frame/test_frame.py @@ -10,6 +10,7 @@ import numpy as np import pytest +from pandas.compat import is_at_least_matplotlib_36 import pandas.util._test_decorators as td from pandas.core.dtypes.api import is_list_like @@ -35,6 +36,7 @@ @td.skip_if_no_mpl class TestDataFramePlots(TestPlotBase): + @pytest.mark.xfail(is_at_least_matplotlib_36, reason="Api changed") @pytest.mark.slow def test_plot(self): df = tm.makeTimeDataFrame() @@ -1543,8 +1545,8 @@ def test_errorbar_with_integer_column_names(self): @pytest.mark.slow def test_errorbar_with_partial_columns(self): - df = DataFrame(np.random.randn(10, 3)) - df_err = DataFrame(np.random.randn(10, 2), columns=[0, 2]) + df = DataFrame(np.abs(np.random.randn(10, 3))) + df_err = DataFrame(np.abs(np.random.randn(10, 2)), columns=[0, 2]) kinds = ["line", "bar"] for kind in kinds: ax = _check_plot_works(df.plot, yerr=df_err, kind=kind) diff --git a/pandas/tests/plotting/test_series.py b/pandas/tests/plotting/test_series.py index 7128e5a51a11e..b7c2e1df54368 100644 --- a/pandas/tests/plotting/test_series.py +++ b/pandas/tests/plotting/test_series.py @@ -577,8 +577,10 @@ def test_errorbar_asymmetrical(self): def test_errorbar_plot(self): s = Series(np.arange(10), name="x") - s_err = np.random.randn(10) - d_err = DataFrame(np.random.randn(10, 2), index=s.index, columns=["x", "y"]) + s_err = np.abs(np.random.randn(10)) + d_err = DataFrame( + np.abs(np.random.randn(10, 2)), index=s.index, columns=["x", "y"] + ) # test line and bar plots kinds = ["line", "bar"] for kind in kinds: @@ -599,8 +601,8 @@ def test_errorbar_plot(self): # test time series plotting ix = date_range("1/1/2000", "1/1/2001", freq="M") ts = Series(np.arange(12), index=ix, name="x") - ts_err = Series(np.random.randn(12), index=ix) - td_err = DataFrame(np.random.randn(12, 2), index=ix, columns=["x", "y"]) + ts_err = Series(np.abs(np.random.randn(12)), index=ix) + td_err = DataFrame(np.abs(np.random.randn(12, 2)), index=ix, columns=["x", "y"]) ax = _check_plot_works(ts.plot, yerr=ts_err) self._check_has_errorbars(ax, xerr=0, yerr=1) From fb392d509dbb8f4e1edde84280083aa790773e6d Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Sat, 17 Sep 2022 15:55:54 +0200 Subject: [PATCH 3/9] Fix doctests --- pandas/compat/__init__.py | 2 - pandas/compat/matplotlib.py | 13 ------- pandas/plotting/_core.py | 2 +- pandas/plotting/_misc.py | 44 +++++++++++----------- pandas/tests/plotting/common.py | 13 +++++++ pandas/tests/plotting/frame/test_frame.py | 4 +- pandas/tests/plotting/test_datetimelike.py | 10 +++-- pandas/tests/plotting/test_hist_method.py | 4 +- pandas/tests/plotting/test_series.py | 4 +- 9 files changed, 48 insertions(+), 48 deletions(-) delete mode 100644 pandas/compat/matplotlib.py diff --git a/pandas/compat/__init__.py b/pandas/compat/__init__.py index 6ab37bed91d0c..80f66c945ba27 100644 --- a/pandas/compat/__init__.py +++ b/pandas/compat/__init__.py @@ -15,7 +15,6 @@ from typing import TYPE_CHECKING from pandas._typing import F -from pandas.compat.matplotlib import is_at_least_matplotlib_36 from pandas.compat.numpy import ( is_numpy_dev, np_version_under1p21, @@ -153,7 +152,6 @@ def get_lzma_file() -> type[lzma.LZMAFile]: __all__ = [ - "is_at_least_matplotlib_36", "is_numpy_dev", "np_version_under1p21", "pa_version_under1p01", diff --git a/pandas/compat/matplotlib.py b/pandas/compat/matplotlib.py deleted file mode 100644 index ff080e5e9dfcc..0000000000000 --- a/pandas/compat/matplotlib.py +++ /dev/null @@ -1,13 +0,0 @@ -from __future__ import annotations - -from pandas.util.version import Version - -try: - import matplotlib - - _matplotlib_version = matplotlib.__version__ - _matplotliblv = Version(_matplotlib_version) - is_at_least_matplotlib_36 = _matplotliblv >= Version("3.6.0") - -except ImportError: - is_at_least_matplotlib_36 = True diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index 17befb3d27da4..4120afd559da0 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -1017,7 +1017,7 @@ def __call__(self, *args, **kwargs): >>> s = pd.Series([1, 3, 2]) >>> s.plot.line() - + .. plot:: :context: close-figs diff --git a/pandas/plotting/_misc.py b/pandas/plotting/_misc.py index 9dbf43c5d70c5..b2090fa33fe88 100644 --- a/pandas/plotting/_misc.py +++ b/pandas/plotting/_misc.py @@ -139,22 +139,22 @@ def scatter_matrix( >>> df = pd.DataFrame(np.random.randn(1000, 4), columns=['A','B','C','D']) >>> pd.plotting.scatter_matrix(df, alpha=0.2) - array([[, - , - , - ], - [, - , - , - ], - [, - , - , - ], - [, - , - , - ]], dtype=object) + array([[, + , + , + ], + [, + , + , + ], + [, + , + , + ], + [, + , + , + ]], dtype=object) """ plot_backend = _get_plot_backend("matplotlib") return plot_backend.scatter_matrix( @@ -247,7 +247,7 @@ def radviz( ... } ... ) >>> pd.plotting.radviz(df, 'Category') - + """ plot_backend = _get_plot_backend("matplotlib") return plot_backend.radviz( @@ -315,7 +315,7 @@ def andrews_curves( ... 'pandas/main/pandas/tests/io/data/csv/iris.csv' ... ) >>> pd.plotting.andrews_curves(df, 'Name') - + """ plot_backend = _get_plot_backend("matplotlib") return plot_backend.andrews_curves( @@ -449,7 +449,7 @@ def parallel_coordinates( >>> pd.plotting.parallel_coordinates( ... df, 'Name', color=('#556270', '#4ECDC4', '#C7F464') ... ) - + """ plot_backend = _get_plot_backend("matplotlib") return plot_backend.parallel_coordinates( @@ -500,7 +500,7 @@ def lag_plot(series: Series, lag: int = 1, ax: Axes | None = None, **kwds) -> Ax >>> x = np.cumsum(np.random.normal(loc=1, scale=5, size=50)) >>> s = pd.Series(x) >>> s.plot() - + A lag plot with ``lag=1`` returns @@ -508,7 +508,7 @@ def lag_plot(series: Series, lag: int = 1, ax: Axes | None = None, **kwds) -> Ax :context: close-figs >>> pd.plotting.lag_plot(s, lag=1) - + """ plot_backend = _get_plot_backend("matplotlib") return plot_backend.lag_plot(series=series, lag=lag, ax=ax, **kwds) @@ -543,7 +543,7 @@ def autocorrelation_plot(series: Series, ax: Axes | None = None, **kwargs) -> Ax >>> spacing = np.linspace(-9 * np.pi, 9 * np.pi, num=1000) >>> s = pd.Series(0.7 * np.random.rand(1000) + 0.3 * np.sin(spacing)) >>> pd.plotting.autocorrelation_plot(s) - + """ plot_backend = _get_plot_backend("matplotlib") return plot_backend.autocorrelation_plot(series=series, ax=ax, **kwargs) diff --git a/pandas/tests/plotting/common.py b/pandas/tests/plotting/common.py index df853770b85f1..78f1d14729ccc 100644 --- a/pandas/tests/plotting/common.py +++ b/pandas/tests/plotting/common.py @@ -598,3 +598,16 @@ def _gen_two_subplots(f, fig, **kwargs): else: kwargs["ax"] = fig.add_subplot(212) yield f(**kwargs) + + +try: + import matplotlib as mpl + + from pandas.util.version import Version + + _mpl_version = mpl.__version__ + _mpllv = Version(_mpl_version) + is_at_least_mpl_36 = _mpllv >= Version("3.6.0") + +except ImportError: + is_at_least_mpl_36 = True diff --git a/pandas/tests/plotting/frame/test_frame.py b/pandas/tests/plotting/frame/test_frame.py index 5abb0c2704f97..f0a1d1dd2f619 100644 --- a/pandas/tests/plotting/frame/test_frame.py +++ b/pandas/tests/plotting/frame/test_frame.py @@ -10,7 +10,6 @@ import numpy as np import pytest -from pandas.compat import is_at_least_matplotlib_36 import pandas.util._test_decorators as td from pandas.core.dtypes.api import is_list_like @@ -28,6 +27,7 @@ from pandas.tests.plotting.common import ( TestPlotBase, _check_plot_works, + is_at_least_mpl_36, ) from pandas.io.formats.printing import pprint_thing @@ -36,7 +36,7 @@ @td.skip_if_no_mpl class TestDataFramePlots(TestPlotBase): - @pytest.mark.xfail(is_at_least_matplotlib_36, reason="Api changed") + @pytest.mark.xfail(is_at_least_mpl_36, reason="Api changed") @pytest.mark.slow def test_plot(self): df = tm.makeTimeDataFrame() diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index 516134cfb82e8..f2891ee18ef8b 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -14,7 +14,6 @@ BaseOffset, to_offset, ) -from pandas.compat import is_at_least_matplotlib_36 import pandas.util._test_decorators as td from pandas import ( @@ -38,7 +37,10 @@ period_range, ) from pandas.core.indexes.timedeltas import timedelta_range -from pandas.tests.plotting.common import TestPlotBase +from pandas.tests.plotting.common import ( + TestPlotBase, + is_at_least_mpl_36, +) from pandas.tseries.offsets import WeekOfMonth @@ -261,7 +263,7 @@ def test_plot_multiple_inferred_freq(self): ser = Series(np.random.randn(len(dr)), index=dr) _check_plot_works(ser.plot) - @pytest.mark.xfail(is_at_least_matplotlib_36, reason="Api changed") + @pytest.mark.xfail(is_at_least_mpl_36, reason="Api changed") def test_uhf(self): import pandas.plotting._matplotlib.converter as conv @@ -1211,7 +1213,7 @@ def test_secondary_legend(self): # TODO: color cycle problems assert len(colors) == 4 - @pytest.mark.xfail(is_at_least_matplotlib_36, reason="Api changed") + @pytest.mark.xfail(is_at_least_mpl_36, reason="Api changed") def test_format_date_axis(self): rng = date_range("1/1/2012", periods=12, freq="M") df = DataFrame(np.random.randn(len(rng), 3), rng) diff --git a/pandas/tests/plotting/test_hist_method.py b/pandas/tests/plotting/test_hist_method.py index 9d696dff2d75e..4c8c5830cf088 100644 --- a/pandas/tests/plotting/test_hist_method.py +++ b/pandas/tests/plotting/test_hist_method.py @@ -4,7 +4,6 @@ import numpy as np import pytest -from pandas.compat import is_at_least_matplotlib_36 import pandas.util._test_decorators as td from pandas import ( @@ -17,6 +16,7 @@ from pandas.tests.plotting.common import ( TestPlotBase, _check_plot_works, + is_at_least_mpl_36, ) @@ -192,7 +192,7 @@ def test_hist_kwargs(self, ts): ax = ts.plot.hist(align="left", stacked=True, ax=ax) tm.close() - @pytest.mark.xfail(is_at_least_matplotlib_36, reason="Api changed") + @pytest.mark.xfail(is_at_least_mpl_36, reason="Api changed") @td.skip_if_no_scipy def test_hist_kde(self, ts): diff --git a/pandas/tests/plotting/test_series.py b/pandas/tests/plotting/test_series.py index b7c2e1df54368..d711a5e5b8f29 100644 --- a/pandas/tests/plotting/test_series.py +++ b/pandas/tests/plotting/test_series.py @@ -5,7 +5,6 @@ import numpy as np import pytest -from pandas.compat import is_at_least_matplotlib_36 import pandas.util._test_decorators as td import pandas as pd @@ -18,6 +17,7 @@ from pandas.tests.plotting.common import ( TestPlotBase, _check_plot_works, + is_at_least_mpl_36, ) import pandas.plotting as plotting @@ -494,7 +494,7 @@ def test_kde_missing_vals(self): # gh-14821: check if the values have any missing values assert any(~np.isnan(axes.lines[0].get_xdata())) - @pytest.mark.xfail(is_at_least_matplotlib_36, reason="Api changed") + @pytest.mark.xfail(is_at_least_mpl_36, reason="Api changed") def test_boxplot_series(self, ts): _, ax = self.plt.subplots() ax = ts.plot.box(logy=True, ax=ax) From 71b7913cec8bcc24c89eea1bdaa07e70c79ab53a Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Sat, 17 Sep 2022 17:34:13 +0200 Subject: [PATCH 4/9] Refactor --- pandas/plotting/_matplotlib/compat.py | 1 + pandas/tests/plotting/common.py | 13 ------------- pandas/tests/plotting/frame/test_frame.py | 4 ++-- pandas/tests/plotting/test_datetimelike.py | 10 ++++------ pandas/tests/plotting/test_hist_method.py | 5 +++-- pandas/tests/plotting/test_series.py | 4 ++-- 6 files changed, 12 insertions(+), 25 deletions(-) diff --git a/pandas/plotting/_matplotlib/compat.py b/pandas/plotting/_matplotlib/compat.py index 6015662999a7d..86b218db4ebe6 100644 --- a/pandas/plotting/_matplotlib/compat.py +++ b/pandas/plotting/_matplotlib/compat.py @@ -19,3 +19,4 @@ def inner(): mpl_ge_3_4_0 = _mpl_version("3.4.0", operator.ge) mpl_ge_3_5_0 = _mpl_version("3.5.0", operator.ge) +mpl_ge_3_6_0 = _mpl_version("3.6.0", operator.ge) diff --git a/pandas/tests/plotting/common.py b/pandas/tests/plotting/common.py index 78f1d14729ccc..df853770b85f1 100644 --- a/pandas/tests/plotting/common.py +++ b/pandas/tests/plotting/common.py @@ -598,16 +598,3 @@ def _gen_two_subplots(f, fig, **kwargs): else: kwargs["ax"] = fig.add_subplot(212) yield f(**kwargs) - - -try: - import matplotlib as mpl - - from pandas.util.version import Version - - _mpl_version = mpl.__version__ - _mpllv = Version(_mpl_version) - is_at_least_mpl_36 = _mpllv >= Version("3.6.0") - -except ImportError: - is_at_least_mpl_36 = True diff --git a/pandas/tests/plotting/frame/test_frame.py b/pandas/tests/plotting/frame/test_frame.py index f0a1d1dd2f619..738e065b80677 100644 --- a/pandas/tests/plotting/frame/test_frame.py +++ b/pandas/tests/plotting/frame/test_frame.py @@ -27,16 +27,16 @@ from pandas.tests.plotting.common import ( TestPlotBase, _check_plot_works, - is_at_least_mpl_36, ) from pandas.io.formats.printing import pprint_thing import pandas.plotting as plotting +from pandas.plotting._matplotlib.compat import mpl_ge_3_6_0 @td.skip_if_no_mpl class TestDataFramePlots(TestPlotBase): - @pytest.mark.xfail(is_at_least_mpl_36, reason="Api changed") + @pytest.mark.xfail(mpl_ge_3_6_0, reason="Api changed") @pytest.mark.slow def test_plot(self): df = tm.makeTimeDataFrame() diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index f2891ee18ef8b..5b1a562d518df 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -37,11 +37,9 @@ period_range, ) from pandas.core.indexes.timedeltas import timedelta_range -from pandas.tests.plotting.common import ( - TestPlotBase, - is_at_least_mpl_36, -) +from pandas.tests.plotting.common import TestPlotBase +from pandas.plotting._matplotlib.compat import mpl_ge_3_6_0 from pandas.tseries.offsets import WeekOfMonth @@ -263,7 +261,7 @@ def test_plot_multiple_inferred_freq(self): ser = Series(np.random.randn(len(dr)), index=dr) _check_plot_works(ser.plot) - @pytest.mark.xfail(is_at_least_mpl_36, reason="Api changed") + @pytest.mark.xfail(mpl_ge_3_6_0, reason="Api changed") def test_uhf(self): import pandas.plotting._matplotlib.converter as conv @@ -1213,7 +1211,7 @@ def test_secondary_legend(self): # TODO: color cycle problems assert len(colors) == 4 - @pytest.mark.xfail(is_at_least_mpl_36, reason="Api changed") + @pytest.mark.xfail(mpl_ge_3_6_0, reason="Api changed") def test_format_date_axis(self): rng = date_range("1/1/2012", periods=12, freq="M") df = DataFrame(np.random.randn(len(rng), 3), rng) diff --git a/pandas/tests/plotting/test_hist_method.py b/pandas/tests/plotting/test_hist_method.py index 4c8c5830cf088..1db87f7ddeb8d 100644 --- a/pandas/tests/plotting/test_hist_method.py +++ b/pandas/tests/plotting/test_hist_method.py @@ -16,9 +16,10 @@ from pandas.tests.plotting.common import ( TestPlotBase, _check_plot_works, - is_at_least_mpl_36, ) +from pandas.plotting._matplotlib.compat import mpl_ge_3_6_0 + @pytest.fixture def ts(): @@ -192,7 +193,7 @@ def test_hist_kwargs(self, ts): ax = ts.plot.hist(align="left", stacked=True, ax=ax) tm.close() - @pytest.mark.xfail(is_at_least_mpl_36, reason="Api changed") + @pytest.mark.xfail(mpl_ge_3_6_0, reason="Api changed") @td.skip_if_no_scipy def test_hist_kde(self, ts): diff --git a/pandas/tests/plotting/test_series.py b/pandas/tests/plotting/test_series.py index d711a5e5b8f29..cddadc771ca6a 100644 --- a/pandas/tests/plotting/test_series.py +++ b/pandas/tests/plotting/test_series.py @@ -17,10 +17,10 @@ from pandas.tests.plotting.common import ( TestPlotBase, _check_plot_works, - is_at_least_mpl_36, ) import pandas.plotting as plotting +from pandas.plotting._matplotlib.compat import mpl_ge_3_6_0 @pytest.fixture @@ -494,7 +494,7 @@ def test_kde_missing_vals(self): # gh-14821: check if the values have any missing values assert any(~np.isnan(axes.lines[0].get_xdata())) - @pytest.mark.xfail(is_at_least_mpl_36, reason="Api changed") + @pytest.mark.xfail(mpl_ge_3_6_0, reason="Api changed") def test_boxplot_series(self, ts): _, ax = self.plt.subplots() ax = ts.plot.box(logy=True, ax=ax) From 52ced150805c5c7803c66fcb11af41b9f4d499d7 Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Sat, 17 Sep 2022 18:28:58 +0200 Subject: [PATCH 5/9] Fix Userwarnings --- doc/source/user_guide/visualization.rst | 1 + pandas/plotting/_matplotlib/core.py | 10 +++++++--- pandas/tests/plotting/frame/test_frame.py | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/doc/source/user_guide/visualization.rst b/doc/source/user_guide/visualization.rst index 5ce2f7ca599a7..147981f29476f 100644 --- a/doc/source/user_guide/visualization.rst +++ b/doc/source/user_guide/visualization.rst @@ -625,6 +625,7 @@ To plot multiple column groups in a single axes, repeat ``plot`` method specifyi It is recommended to specify ``color`` and ``label`` keywords to distinguish each groups. .. ipython:: python + :okwarning: ax = df.plot.scatter(x="a", y="b", color="DarkBlue", label="Group 1") @savefig scatter_plot_repeated.png diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index 2b90c6dd66540..2bf5024928cbf 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -1209,9 +1209,6 @@ def _make_plot(self): color_by_categorical = c_is_column and is_categorical_dtype(self.data[c]) - # pandas uses colormap, matplotlib uses cmap. - cmap = self.colormap or "Greys" - cmap = self.plt.cm.get_cmap(cmap) color = self.kwds.pop("color", None) if c is not None and color is not None: raise TypeError("Specify exactly one of `c` and `color`") @@ -1226,6 +1223,13 @@ def _make_plot(self): else: c_values = c + if is_integer_dtype(c_values): + # pandas uses colormap, matplotlib uses cmap. + cmap = self.colormap or "Greys" + cmap = self.plt.cm.get_cmap(cmap) + else: + cmap = None + if color_by_categorical: from matplotlib import colors diff --git a/pandas/tests/plotting/frame/test_frame.py b/pandas/tests/plotting/frame/test_frame.py index 738e065b80677..13b96dde5f78b 100644 --- a/pandas/tests/plotting/frame/test_frame.py +++ b/pandas/tests/plotting/frame/test_frame.py @@ -736,7 +736,7 @@ def test_plot_scatter_with_c(self): from pandas.plotting._matplotlib.compat import mpl_ge_3_4_0 df = DataFrame( - np.random.randn(6, 4), + np.random.randint(low=0, high=100, size=(6, 4)), index=list(string.ascii_letters[:6]), columns=["x", "y", "z", "four"], ) From b327813e3f273e204aff1cdcca61c969d7176402 Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Sat, 17 Sep 2022 18:29:23 +0200 Subject: [PATCH 6/9] Add note --- pandas/plotting/_matplotlib/core.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index 2bf5024928cbf..4a21c519bf146 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -1223,6 +1223,7 @@ def _make_plot(self): else: c_values = c + # cmap is only used if c_values are integers, otherwise UserWarning if is_integer_dtype(c_values): # pandas uses colormap, matplotlib uses cmap. cmap = self.colormap or "Greys" From 21f2e2b776d9590de0ed21a047d3680165493819 Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Sat, 17 Sep 2022 18:42:06 +0200 Subject: [PATCH 7/9] Get rid of deprecation warnings --- pandas/plotting/_matplotlib/compat.py | 1 + pandas/plotting/_matplotlib/core.py | 12 ++++++++++-- pandas/plotting/_matplotlib/style.py | 8 +++++++- pandas/tests/plotting/frame/test_frame_color.py | 4 ++-- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/pandas/plotting/_matplotlib/compat.py b/pandas/plotting/_matplotlib/compat.py index 86b218db4ebe6..a77489e53ef34 100644 --- a/pandas/plotting/_matplotlib/compat.py +++ b/pandas/plotting/_matplotlib/compat.py @@ -20,3 +20,4 @@ def inner(): mpl_ge_3_4_0 = _mpl_version("3.4.0", operator.ge) mpl_ge_3_5_0 = _mpl_version("3.5.0", operator.ge) mpl_ge_3_6_0 = _mpl_version("3.6.0", operator.ge) +mpl_ge_3_6_0 = _mpl_version("3.6.0", operator.ge) diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index 4a21c519bf146..747049c6ac81a 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -14,6 +14,7 @@ ) import warnings +import matplotlib as mpl from matplotlib.artist import Artist import numpy as np @@ -54,6 +55,7 @@ from pandas.core.frame import DataFrame from pandas.io.formats.printing import pprint_thing +from pandas.plotting._matplotlib.compat import mpl_ge_3_6_0 from pandas.plotting._matplotlib.converter import register_pandas_matplotlib_converters from pandas.plotting._matplotlib.groupby import reconstruct_data_with_by from pandas.plotting._matplotlib.misc import unpack_single_str_list @@ -1227,7 +1229,10 @@ def _make_plot(self): if is_integer_dtype(c_values): # pandas uses colormap, matplotlib uses cmap. cmap = self.colormap or "Greys" - cmap = self.plt.cm.get_cmap(cmap) + if mpl_ge_3_6_0: + cmap = mpl.colormaps[cmap] + else: + cmap = self.plt.cm.get_cmap(cmap) else: cmap = None @@ -1295,7 +1300,10 @@ def _make_plot(self) -> None: ax = self.axes[0] # pandas uses colormap, matplotlib uses cmap. cmap = self.colormap or "BuGn" - cmap = self.plt.cm.get_cmap(cmap) + if mpl_ge_3_6_0: + cmap = mpl.colormaps[cmap] + else: + cmap = self.plt.cm.get_cmap(cmap) cb = self.kwds.pop("colorbar", True) if C is None: diff --git a/pandas/plotting/_matplotlib/style.py b/pandas/plotting/_matplotlib/style.py index 2f29aafbdf5cf..f5babd3138036 100644 --- a/pandas/plotting/_matplotlib/style.py +++ b/pandas/plotting/_matplotlib/style.py @@ -12,6 +12,7 @@ ) import warnings +import matplotlib as mpl import matplotlib.cm as cm import matplotlib.colors import numpy as np @@ -22,6 +23,8 @@ import pandas.core.common as com +from pandas.plotting._matplotlib.compat import mpl_ge_3_6_0 + if TYPE_CHECKING: from matplotlib.colors import Colormap @@ -155,7 +158,10 @@ def _get_cmap_instance(colormap: str | Colormap) -> Colormap: """Get instance of matplotlib colormap.""" if isinstance(colormap, str): cmap = colormap - colormap = cm.get_cmap(colormap) + if mpl_ge_3_6_0: + colormap = mpl.colormaps[colormap] + else: + colormap = cm.get_cmap(colormap) if colormap is None: raise ValueError(f"Colormap {cmap} is not recognized") return colormap diff --git a/pandas/tests/plotting/frame/test_frame_color.py b/pandas/tests/plotting/frame/test_frame_color.py index 1cc8381642bbe..e384861d8a57c 100644 --- a/pandas/tests/plotting/frame/test_frame_color.py +++ b/pandas/tests/plotting/frame/test_frame_color.py @@ -655,6 +655,6 @@ def test_colors_of_columns_with_same_name(self): def test_invalid_colormap(self): df = DataFrame(np.random.randn(3, 2), columns=["A", "B"]) - msg = "'invalid_colormap' is not a valid value for name; supported values are " - with pytest.raises(ValueError, match=msg): + msg = "(is not a valid value)|(is not a known colormap)" + with pytest.raises((ValueError, KeyError), match=msg): df.plot(colormap="invalid_colormap") From c4a3128e9d40fc772a240a6f738a6e1f22aad91b Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Sat, 17 Sep 2022 19:20:40 +0200 Subject: [PATCH 8/9] Catch import errors --- pandas/tests/plotting/frame/test_frame.py | 6 +++++- pandas/tests/plotting/test_datetimelike.py | 6 +++++- pandas/tests/plotting/test_hist_method.py | 5 ++++- pandas/tests/plotting/test_series.py | 6 +++++- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/pandas/tests/plotting/frame/test_frame.py b/pandas/tests/plotting/frame/test_frame.py index 13b96dde5f78b..210c4a0e50e2c 100644 --- a/pandas/tests/plotting/frame/test_frame.py +++ b/pandas/tests/plotting/frame/test_frame.py @@ -31,7 +31,11 @@ from pandas.io.formats.printing import pprint_thing import pandas.plotting as plotting -from pandas.plotting._matplotlib.compat import mpl_ge_3_6_0 + +try: + from pandas.plotting._matplotlib.compat import mpl_ge_3_6_0 +except ImportError: + mpl_ge_3_6_0 = True @td.skip_if_no_mpl diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index 5b1a562d518df..3f8fd899b00bf 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -39,7 +39,11 @@ from pandas.core.indexes.timedeltas import timedelta_range from pandas.tests.plotting.common import TestPlotBase -from pandas.plotting._matplotlib.compat import mpl_ge_3_6_0 +try: + from pandas.plotting._matplotlib.compat import mpl_ge_3_6_0 +except ImportError: + mpl_ge_3_6_0 = True + from pandas.tseries.offsets import WeekOfMonth diff --git a/pandas/tests/plotting/test_hist_method.py b/pandas/tests/plotting/test_hist_method.py index 1db87f7ddeb8d..45a54fad37cf5 100644 --- a/pandas/tests/plotting/test_hist_method.py +++ b/pandas/tests/plotting/test_hist_method.py @@ -18,7 +18,10 @@ _check_plot_works, ) -from pandas.plotting._matplotlib.compat import mpl_ge_3_6_0 +try: + from pandas.plotting._matplotlib.compat import mpl_ge_3_6_0 +except ImportError: + mpl_ge_3_6_0 = True @pytest.fixture diff --git a/pandas/tests/plotting/test_series.py b/pandas/tests/plotting/test_series.py index cddadc771ca6a..cfda55dc8d734 100644 --- a/pandas/tests/plotting/test_series.py +++ b/pandas/tests/plotting/test_series.py @@ -20,7 +20,11 @@ ) import pandas.plotting as plotting -from pandas.plotting._matplotlib.compat import mpl_ge_3_6_0 + +try: + from pandas.plotting._matplotlib.compat import mpl_ge_3_6_0 +except ImportError: + mpl_ge_3_6_0 = True @pytest.fixture From 7d6b5a06ff0dd0e19f66620f68ae50ae37b3e814 Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Sat, 17 Sep 2022 20:38:03 +0200 Subject: [PATCH 9/9] Fix --- pandas/plotting/_matplotlib/compat.py | 1 - pandas/plotting/_matplotlib/core.py | 4 ++-- pandas/plotting/_matplotlib/style.py | 2 +- pandas/tests/plotting/frame/test_frame.py | 4 ++-- pandas/tests/plotting/test_datetimelike.py | 6 +++--- pandas/tests/plotting/test_hist_method.py | 4 ++-- pandas/tests/plotting/test_series.py | 4 ++-- 7 files changed, 12 insertions(+), 13 deletions(-) diff --git a/pandas/plotting/_matplotlib/compat.py b/pandas/plotting/_matplotlib/compat.py index a77489e53ef34..86b218db4ebe6 100644 --- a/pandas/plotting/_matplotlib/compat.py +++ b/pandas/plotting/_matplotlib/compat.py @@ -20,4 +20,3 @@ def inner(): mpl_ge_3_4_0 = _mpl_version("3.4.0", operator.ge) mpl_ge_3_5_0 = _mpl_version("3.5.0", operator.ge) mpl_ge_3_6_0 = _mpl_version("3.6.0", operator.ge) -mpl_ge_3_6_0 = _mpl_version("3.6.0", operator.ge) diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index 747049c6ac81a..62a9a5946c5c8 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -1229,7 +1229,7 @@ def _make_plot(self): if is_integer_dtype(c_values): # pandas uses colormap, matplotlib uses cmap. cmap = self.colormap or "Greys" - if mpl_ge_3_6_0: + if mpl_ge_3_6_0(): cmap = mpl.colormaps[cmap] else: cmap = self.plt.cm.get_cmap(cmap) @@ -1300,7 +1300,7 @@ def _make_plot(self) -> None: ax = self.axes[0] # pandas uses colormap, matplotlib uses cmap. cmap = self.colormap or "BuGn" - if mpl_ge_3_6_0: + if mpl_ge_3_6_0(): cmap = mpl.colormaps[cmap] else: cmap = self.plt.cm.get_cmap(cmap) diff --git a/pandas/plotting/_matplotlib/style.py b/pandas/plotting/_matplotlib/style.py index f5babd3138036..d8823c7ec8d3d 100644 --- a/pandas/plotting/_matplotlib/style.py +++ b/pandas/plotting/_matplotlib/style.py @@ -158,7 +158,7 @@ def _get_cmap_instance(colormap: str | Colormap) -> Colormap: """Get instance of matplotlib colormap.""" if isinstance(colormap, str): cmap = colormap - if mpl_ge_3_6_0: + if mpl_ge_3_6_0(): colormap = mpl.colormaps[colormap] else: colormap = cm.get_cmap(colormap) diff --git a/pandas/tests/plotting/frame/test_frame.py b/pandas/tests/plotting/frame/test_frame.py index 210c4a0e50e2c..78116ead70cd4 100644 --- a/pandas/tests/plotting/frame/test_frame.py +++ b/pandas/tests/plotting/frame/test_frame.py @@ -35,12 +35,12 @@ try: from pandas.plotting._matplotlib.compat import mpl_ge_3_6_0 except ImportError: - mpl_ge_3_6_0 = True + mpl_ge_3_6_0 = lambda: True @td.skip_if_no_mpl class TestDataFramePlots(TestPlotBase): - @pytest.mark.xfail(mpl_ge_3_6_0, reason="Api changed") + @pytest.mark.xfail(mpl_ge_3_6_0(), reason="Api changed") @pytest.mark.slow def test_plot(self): df = tm.makeTimeDataFrame() diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index 3f8fd899b00bf..f75e5cd3491a4 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -42,7 +42,7 @@ try: from pandas.plotting._matplotlib.compat import mpl_ge_3_6_0 except ImportError: - mpl_ge_3_6_0 = True + mpl_ge_3_6_0 = lambda: True from pandas.tseries.offsets import WeekOfMonth @@ -265,7 +265,7 @@ def test_plot_multiple_inferred_freq(self): ser = Series(np.random.randn(len(dr)), index=dr) _check_plot_works(ser.plot) - @pytest.mark.xfail(mpl_ge_3_6_0, reason="Api changed") + @pytest.mark.xfail(mpl_ge_3_6_0(), reason="Api changed") def test_uhf(self): import pandas.plotting._matplotlib.converter as conv @@ -1215,7 +1215,7 @@ def test_secondary_legend(self): # TODO: color cycle problems assert len(colors) == 4 - @pytest.mark.xfail(mpl_ge_3_6_0, reason="Api changed") + @pytest.mark.xfail(mpl_ge_3_6_0(), reason="Api changed") def test_format_date_axis(self): rng = date_range("1/1/2012", periods=12, freq="M") df = DataFrame(np.random.randn(len(rng), 3), rng) diff --git a/pandas/tests/plotting/test_hist_method.py b/pandas/tests/plotting/test_hist_method.py index 45a54fad37cf5..dc586d15ba115 100644 --- a/pandas/tests/plotting/test_hist_method.py +++ b/pandas/tests/plotting/test_hist_method.py @@ -21,7 +21,7 @@ try: from pandas.plotting._matplotlib.compat import mpl_ge_3_6_0 except ImportError: - mpl_ge_3_6_0 = True + mpl_ge_3_6_0 = lambda: True @pytest.fixture @@ -196,7 +196,7 @@ def test_hist_kwargs(self, ts): ax = ts.plot.hist(align="left", stacked=True, ax=ax) tm.close() - @pytest.mark.xfail(mpl_ge_3_6_0, reason="Api changed") + @pytest.mark.xfail(mpl_ge_3_6_0(), reason="Api changed") @td.skip_if_no_scipy def test_hist_kde(self, ts): diff --git a/pandas/tests/plotting/test_series.py b/pandas/tests/plotting/test_series.py index cfda55dc8d734..816ce95dbb83a 100644 --- a/pandas/tests/plotting/test_series.py +++ b/pandas/tests/plotting/test_series.py @@ -24,7 +24,7 @@ try: from pandas.plotting._matplotlib.compat import mpl_ge_3_6_0 except ImportError: - mpl_ge_3_6_0 = True + mpl_ge_3_6_0 = lambda: True @pytest.fixture @@ -498,7 +498,7 @@ def test_kde_missing_vals(self): # gh-14821: check if the values have any missing values assert any(~np.isnan(axes.lines[0].get_xdata())) - @pytest.mark.xfail(mpl_ge_3_6_0, reason="Api changed") + @pytest.mark.xfail(mpl_ge_3_6_0(), reason="Api changed") def test_boxplot_series(self, ts): _, ax = self.plt.subplots() ax = ts.plot.box(logy=True, ax=ax)