From 7934bf8c94963d5c32aced337c1e347d45cb3f34 Mon Sep 17 00:00:00 2001 From: Matthew Roeschke Date: Sun, 13 Feb 2022 22:48:44 -0800 Subject: [PATCH 1/3] TST: Plotting --- pandas/plotting/_matplotlib/compat.py | 5 -- pandas/tests/plotting/common.py | 83 ++++--------------- pandas/tests/plotting/conftest.py | 35 ++++++++ pandas/tests/plotting/frame/test_frame.py | 82 +++++++++--------- .../tests/plotting/frame/test_frame_color.py | 31 ++++--- .../plotting/frame/test_frame_groupby.py | 17 ---- .../plotting/frame/test_frame_subplots.py | 21 +---- .../tests/plotting/frame/test_hist_box_by.py | 75 +++++++---------- pandas/tests/plotting/test_boxplot_method.py | 28 +++---- pandas/tests/plotting/test_datetimelike.py | 27 ++---- pandas/tests/plotting/test_hist_method.py | 50 +++++------ pandas/tests/plotting/test_misc.py | 6 +- 12 files changed, 189 insertions(+), 271 deletions(-) create mode 100644 pandas/tests/plotting/conftest.py diff --git a/pandas/plotting/_matplotlib/compat.py b/pandas/plotting/_matplotlib/compat.py index 5569b1f2979b0..9583010b58062 100644 --- a/pandas/plotting/_matplotlib/compat.py +++ b/pandas/plotting/_matplotlib/compat.py @@ -18,10 +18,5 @@ def inner(): return inner -mpl_ge_2_2_3 = _mpl_version("2.2.3", operator.ge) -mpl_ge_3_0_0 = _mpl_version("3.0.0", operator.ge) -mpl_ge_3_1_0 = _mpl_version("3.1.0", operator.ge) -mpl_ge_3_2_0 = _mpl_version("3.2.0", operator.ge) -mpl_ge_3_3_0 = _mpl_version("3.3.0", operator.ge) mpl_ge_3_4_0 = _mpl_version("3.4.0", operator.ge) mpl_ge_3_5_0 = _mpl_version("3.5.0", operator.ge) diff --git a/pandas/tests/plotting/common.py b/pandas/tests/plotting/common.py index ae9db5e728efe..521cd4a7244fd 100644 --- a/pandas/tests/plotting/common.py +++ b/pandas/tests/plotting/common.py @@ -22,11 +22,7 @@ from pandas.core.dtypes.api import is_list_like import pandas as pd -from pandas import ( - DataFrame, - Series, - to_datetime, -) +from pandas import Series import pandas._testing as tm if TYPE_CHECKING: @@ -39,61 +35,11 @@ class TestPlotBase: This is a common base class used for various plotting tests """ - def setup_method(self, method): - + def setup_method(self): import matplotlib as mpl - from pandas.plotting._matplotlib import compat - - self.compat = compat - mpl.rcdefaults() - self.start_date_to_int64 = 812419200000000000 - self.end_date_to_int64 = 819331200000000000 - - self.mpl_ge_2_2_3 = compat.mpl_ge_2_2_3() - self.mpl_ge_3_0_0 = compat.mpl_ge_3_0_0() - self.mpl_ge_3_1_0 = compat.mpl_ge_3_1_0() - self.mpl_ge_3_2_0 = compat.mpl_ge_3_2_0() - - self.bp_n_objects = 7 - self.polycollection_factor = 2 - self.default_figsize = (6.4, 4.8) - self.default_tick_position = "left" - - n = 100 - with tm.RNGContext(42): - gender = np.random.choice(["Male", "Female"], size=n) - classroom = np.random.choice(["A", "B", "C"], size=n) - - self.hist_df = DataFrame( - { - "gender": gender, - "classroom": classroom, - "height": np.random.normal(66, 4, size=n), - "weight": np.random.normal(161, 32, size=n), - "category": np.random.randint(4, size=n), - "datetime": to_datetime( - np.random.randint( - self.start_date_to_int64, - self.end_date_to_int64, - size=n, - dtype=np.int64, - ) - ), - } - ) - - self.tdf = tm.makeTimeDataFrame() - self.hexbin_df = DataFrame( - { - "A": np.random.uniform(size=20), - "B": np.random.uniform(size=20), - "C": np.arange(20) + np.random.uniform(size=20), - } - ) - def teardown_method(self, method): tm.close() @@ -387,7 +333,7 @@ def _check_axes_shape(self, axes, axes_num=None, layout=None, figsize=None): from pandas.plotting._matplotlib.tools import flatten_axes if figsize is None: - figsize = self.default_figsize + figsize = (6.4, 4.8) visible_axes = self._flatten_visible(axes) if axes_num is not None: @@ -525,15 +471,8 @@ def _check_grid_settings(self, obj, kinds, kws={}): def is_grid_on(): xticks = self.plt.gca().xaxis.get_major_ticks() yticks = self.plt.gca().yaxis.get_major_ticks() - # for mpl 2.2.2, gridOn and gridline.get_visible disagree. - # for new MPL, they are the same. - - if self.mpl_ge_3_1_0: - xoff = all(not g.gridline.get_visible() for g in xticks) - yoff = all(not g.gridline.get_visible() for g in yticks) - else: - xoff = all(not g.gridOn for g in xticks) - yoff = all(not g.gridOn for g in yticks) + xoff = all(not g.gridline.get_visible() for g in xticks) + yoff = all(not g.gridline.get_visible() for g in yticks) return not (xoff and yoff) @@ -572,10 +511,18 @@ def _unpack_cycler(self, rcParams, field="color"): return [v[field] for v in rcParams["axes.prop_cycle"]] def get_x_axis(self, ax): - return ax._shared_axes["x"] if self.compat.mpl_ge_3_5_0() else ax._shared_x_axes + from pandas.plotting._matplotlib.compat import mpl_ge_3_5_0 + + if mpl_ge_3_5_0(): + return ax._shared_axes["x"] + return ax._shared_x_axes def get_y_axis(self, ax): - return ax._shared_axes["y"] if self.compat.mpl_ge_3_5_0() else ax._shared_y_axes + from pandas.plotting._matplotlib.compat import mpl_ge_3_5_0 + + if mpl_ge_3_5_0(): + return ax._shared_axes["y"] + return ax._shared_y_axes def _check_plot_works(f, filterwarnings="always", default_axes=False, **kwargs): diff --git a/pandas/tests/plotting/conftest.py b/pandas/tests/plotting/conftest.py new file mode 100644 index 0000000000000..75d53e3efdb33 --- /dev/null +++ b/pandas/tests/plotting/conftest.py @@ -0,0 +1,35 @@ +import numpy as np +import pytest + +from pandas import ( + DataFrame, + to_datetime, +) +import pandas._testing as tm + + +@pytest.mark.parametrize +def hist_df(): + n = 100 + with tm.RNGContext(42): + gender = np.random.choice(["Male", "Female"], size=n) + classroom = np.random.choice(["A", "B", "C"], size=n) + + hist_df = DataFrame( + { + "gender": gender, + "classroom": classroom, + "height": np.random.normal(66, 4, size=n), + "weight": np.random.normal(161, 32, size=n), + "category": np.random.randint(4, size=n), + "datetime": to_datetime( + np.random.randint( + 812419200000000000, + 819331200000000000, + size=n, + dtype=np.int64, + ) + ), + } + ) + return hist_df diff --git a/pandas/tests/plotting/frame/test_frame.py b/pandas/tests/plotting/frame/test_frame.py index 5cbfb5286bb10..87056612266f0 100644 --- a/pandas/tests/plotting/frame/test_frame.py +++ b/pandas/tests/plotting/frame/test_frame.py @@ -38,25 +38,8 @@ @td.skip_if_no_mpl class TestDataFramePlots(TestPlotBase): - def setup_method(self, method): - TestPlotBase.setup_method(self, method) - import matplotlib as mpl - - mpl.rcdefaults() - - self.tdf = tm.makeTimeDataFrame() - self.hexbin_df = DataFrame( - { - "A": np.random.uniform(size=20), - "B": np.random.uniform(size=20), - "C": np.arange(20) + np.random.uniform(size=20), - } - ) - def test_plot(self): - from pandas.plotting._matplotlib.compat import mpl_ge_3_1_0 - - df = self.tdf + df = tm.makeTimeDataFrame() _check_plot_works(df.plot, grid=False) # _check_plot_works adds an ax so use default_axes=True to avoid warning @@ -81,10 +64,7 @@ def test_plot(self): self._check_axes_shape(axes, axes_num=4, layout=(4, 1)) df = DataFrame({"x": [1, 2], "y": [3, 4]}) - if mpl_ge_3_1_0(): - msg = "'Line2D' object has no property 'blarg'" - else: - msg = "Unknown property blarg" + msg = "'Line2D' object has no property 'blarg'" with pytest.raises(AttributeError, match=msg): df.plot.line(blarg=True) @@ -220,7 +200,7 @@ def test_donot_overwrite_index_name(self): def test_plot_xy(self): # columns.inferred_type == 'string' - df = self.tdf + df = tm.makeTimeDataFrame() self._check_data(df.plot(x=0, y=1), df.set_index("A")["B"].plot()) self._check_data(df.plot(x=0), df.set_index("A").plot()) self._check_data(df.plot(y=0), df.B.plot()) @@ -272,7 +252,7 @@ def test_invalid_logscale(self, input_param): def test_xcompat(self): - df = self.tdf + df = tm.makeTimeDataFrame() ax = df.plot(x_compat=True) lines = ax.get_lines() assert not isinstance(lines[0].get_xdata(), PeriodIndex) @@ -839,8 +819,8 @@ def test_plot_bar(self): ax = df.plot.barh(rot=55, fontsize=11) self._check_ticks_props(ax, yrot=55, ylabelsize=11, xlabelsize=11) - def test_boxplot(self): - df = self.hist_df + def test_boxplot(self, hist_df): + df = hist_df series = df["height"] numeric_cols = df._get_numeric_data().columns labels = [pprint_thing(c) for c in numeric_cols] @@ -850,7 +830,7 @@ def test_boxplot(self): tm.assert_numpy_array_equal( ax.xaxis.get_ticklocs(), np.arange(1, len(numeric_cols) + 1) ) - assert len(ax.lines) == self.bp_n_objects * len(numeric_cols) + assert len(ax.lines) == 7 * len(numeric_cols) tm.close() axes = series.plot.box(rot=40) @@ -865,10 +845,10 @@ def test_boxplot(self): labels = [pprint_thing(c) for c in numeric_cols] self._check_text_labels(ax.get_xticklabels(), labels) tm.assert_numpy_array_equal(ax.xaxis.get_ticklocs(), positions) - assert len(ax.lines) == self.bp_n_objects * len(numeric_cols) + assert len(ax.lines) == 7 * len(numeric_cols) - def test_boxplot_vertical(self): - df = self.hist_df + def test_boxplot_vertical(self, hist_df): + df = hist_df numeric_cols = df._get_numeric_data().columns labels = [pprint_thing(c) for c in numeric_cols] @@ -876,7 +856,7 @@ def test_boxplot_vertical(self): ax = df.plot.box(rot=50, fontsize=8, vert=False) self._check_ticks_props(ax, xrot=0, yrot=50, ylabelsize=8) self._check_text_labels(ax.get_yticklabels(), labels) - assert len(ax.lines) == self.bp_n_objects * len(numeric_cols) + assert len(ax.lines) == 7 * len(numeric_cols) axes = _check_plot_works( df.plot.box, @@ -889,13 +869,13 @@ def test_boxplot_vertical(self): self._check_ax_scales(axes, xaxis="log") for ax, label in zip(axes, labels): self._check_text_labels(ax.get_yticklabels(), [label]) - assert len(ax.lines) == self.bp_n_objects + assert len(ax.lines) == 7 positions = np.array([3, 2, 8]) ax = df.plot.box(positions=positions, vert=False) self._check_text_labels(ax.get_yticklabels(), labels) tm.assert_numpy_array_equal(ax.yaxis.get_ticklocs(), positions) - assert len(ax.lines) == self.bp_n_objects * len(numeric_cols) + assert len(ax.lines) == 7 * len(numeric_cols) def test_boxplot_return_type(self): df = DataFrame( @@ -1310,7 +1290,13 @@ def test_xy_args_integer(self, x, y, colnames): _check_plot_works(df.plot, x=x, y=y) def test_hexbin_basic(self): - df = self.hexbin_df + df = DataFrame( + { + "A": np.random.uniform(size=20), + "B": np.random.uniform(size=20), + "C": np.arange(20) + np.random.uniform(size=20), + } + ) ax = df.plot.hexbin(x="A", y="B", gridsize=10) # TODO: need better way to test. This just does existence. @@ -1325,7 +1311,13 @@ def test_hexbin_basic(self): self._check_axes_shape(axes, axes_num=1, layout=(1, 1)) def test_hexbin_with_c(self): - df = self.hexbin_df + df = DataFrame( + { + "A": np.random.uniform(size=20), + "B": np.random.uniform(size=20), + "C": np.arange(20) + np.random.uniform(size=20), + } + ) ax = df.plot.hexbin(x="A", y="B", C="C") assert len(ax.collections) == 1 @@ -1342,7 +1334,13 @@ def test_hexbin_with_c(self): ], ) def test_hexbin_cmap(self, kwargs, expected): - df = self.hexbin_df + df = DataFrame( + { + "A": np.random.uniform(size=20), + "B": np.random.uniform(size=20), + "C": np.arange(20) + np.random.uniform(size=20), + } + ) ax = df.plot.hexbin(x="A", y="B", **kwargs) assert ax.collections[0].cmap.name == expected @@ -1762,12 +1760,18 @@ def test_memory_leak(self): args = {} if kind in ["hexbin", "scatter", "pie"]: - df = self.hexbin_df + df = DataFrame( + { + "A": np.random.uniform(size=20), + "B": np.random.uniform(size=20), + "C": np.arange(20) + np.random.uniform(size=20), + } + ) args = {"x": "A", "y": "B"} elif kind == "area": - df = self.tdf.abs() + df = tm.makeTimeDataFrame().abs() else: - df = self.tdf + df = tm.makeTimeDataFrame() # Use a weakref so we can see if the object gets collected without # also preventing it from being collected diff --git a/pandas/tests/plotting/frame/test_frame_color.py b/pandas/tests/plotting/frame/test_frame_color.py index b46bb95829991..867570b06ff31 100644 --- a/pandas/tests/plotting/frame/test_frame_color.py +++ b/pandas/tests/plotting/frame/test_frame_color.py @@ -20,21 +20,6 @@ @td.skip_if_no_mpl class TestDataFrameColor(TestPlotBase): - def setup_method(self, method): - TestPlotBase.setup_method(self, method) - import matplotlib as mpl - - mpl.rcdefaults() - - self.tdf = tm.makeTimeDataFrame() - self.hexbin_df = DataFrame( - { - "A": np.random.uniform(size=20), - "B": np.random.uniform(size=20), - "C": np.arange(20) + np.random.uniform(size=20), - } - ) - def test_mpl2_color_cycle_str(self): # GH 15516 df = DataFrame(np.random.randn(10, 3), columns=["a", "b", "c"]) @@ -621,12 +606,24 @@ def test_default_color_cycle(self): self._check_colors(ax.get_lines(), linecolors=expected) def test_no_color_bar(self): - df = self.hexbin_df + df = DataFrame( + { + "A": np.random.uniform(size=20), + "B": np.random.uniform(size=20), + "C": np.arange(20) + np.random.uniform(size=20), + } + ) ax = df.plot.hexbin(x="A", y="B", colorbar=None) assert ax.collections[0].colorbar is None def test_mixing_cmap_and_colormap_raises(self): - df = self.hexbin_df + df = DataFrame( + { + "A": np.random.uniform(size=20), + "B": np.random.uniform(size=20), + "C": np.arange(20) + np.random.uniform(size=20), + } + ) msg = "Only specify one of `cmap` and `colormap`" with pytest.raises(TypeError, match=msg): df.plot.hexbin(x="A", y="B", cmap="YlGn", colormap="BuGn") diff --git a/pandas/tests/plotting/frame/test_frame_groupby.py b/pandas/tests/plotting/frame/test_frame_groupby.py index bc35e02e6a581..e18bdbc5d7579 100644 --- a/pandas/tests/plotting/frame/test_frame_groupby.py +++ b/pandas/tests/plotting/frame/test_frame_groupby.py @@ -1,12 +1,10 @@ """ Test cases for DataFrame.plot """ -import numpy as np import pytest import pandas.util._test_decorators as td from pandas import DataFrame -import pandas._testing as tm from pandas.tests.plotting.common import TestPlotBase pytestmark = pytest.mark.slow @@ -14,21 +12,6 @@ @td.skip_if_no_mpl class TestDataFramePlotsGroupby(TestPlotBase): - def setup_method(self, method): - TestPlotBase.setup_method(self, method) - import matplotlib as mpl - - mpl.rcdefaults() - - self.tdf = tm.makeTimeDataFrame() - self.hexbin_df = DataFrame( - { - "A": np.random.uniform(size=20), - "B": np.random.uniform(size=20), - "C": np.arange(20) + np.random.uniform(size=20), - } - ) - def _assert_ytickslabels_visibility(self, axes, expected): for ax, exp in zip(axes, expected): self._check_visible(ax.get_yticklabels(), visible=exp) diff --git a/pandas/tests/plotting/frame/test_frame_subplots.py b/pandas/tests/plotting/frame/test_frame_subplots.py index fa4a132001be5..4805eb558c465 100644 --- a/pandas/tests/plotting/frame/test_frame_subplots.py +++ b/pandas/tests/plotting/frame/test_frame_subplots.py @@ -24,21 +24,6 @@ @td.skip_if_no_mpl class TestDataFramePlotsSubplots(TestPlotBase): - def setup_method(self, method): - TestPlotBase.setup_method(self, method) - import matplotlib as mpl - - mpl.rcdefaults() - - self.tdf = tm.makeTimeDataFrame() - self.hexbin_df = DataFrame( - { - "A": np.random.uniform(size=20), - "B": np.random.uniform(size=20), - "C": np.arange(20) + np.random.uniform(size=20), - } - ) - def test_subplots(self): df = DataFrame(np.random.rand(10, 3), index=list(string.ascii_letters[:10])) @@ -53,7 +38,7 @@ def test_subplots(self): for ax in axes[:-2]: self._check_visible(ax.xaxis) # xaxis must be visible for grid self._check_visible(ax.get_xticklabels(), visible=False) - if not (kind == "bar" and self.mpl_ge_3_1_0): + if kind != "bar": # change https://github.com/pandas-dev/pandas/issues/26714 self._check_visible(ax.get_xticklabels(minor=True), visible=False) self._check_visible(ax.xaxis.get_label(), visible=False) @@ -405,8 +390,8 @@ def test_bar_log_subplots(self): tm.assert_numpy_array_equal(ax[0].yaxis.get_ticklocs(), expected) tm.assert_numpy_array_equal(ax[1].yaxis.get_ticklocs(), expected) - def test_boxplot_subplots_return_type(self): - df = self.hist_df + def test_boxplot_subplots_return_type(self, hist_df): + df = hist_df # normal style: return_type=None result = df.plot.box(subplots=True) diff --git a/pandas/tests/plotting/frame/test_hist_box_by.py b/pandas/tests/plotting/frame/test_hist_box_by.py index c92d952587967..282c977f89552 100644 --- a/pandas/tests/plotting/frame/test_hist_box_by.py +++ b/pandas/tests/plotting/frame/test_hist_box_by.py @@ -13,7 +13,8 @@ ) -def _create_hist_box_with_by_df(): +@pytest.fixture +def hist_df(): np.random.seed(0) df = DataFrame(np.random.randn(30, 2), columns=["A", "B"]) df["C"] = np.random.choice(["a", "b", "c"], 30) @@ -23,13 +24,6 @@ def _create_hist_box_with_by_df(): @td.skip_if_no_mpl class TestHistWithBy(TestPlotBase): - def setup_method(self, method): - TestPlotBase.setup_method(self, method) - import matplotlib as mpl - - mpl.rcdefaults() - self.hist_df = _create_hist_box_with_by_df() - @pytest.mark.parametrize( "by, column, titles, legends", [ @@ -86,9 +80,9 @@ def setup_method(self, method): ), ], ) - def test_hist_plot_by_argument(self, by, column, titles, legends): + def test_hist_plot_by_argument(self, by, column, titles, legends, hist_df): # GH 15079 - axes = _check_plot_works(self.hist_df.plot.hist, column=column, by=by) + axes = _check_plot_works(hist_df.plot.hist, column=column, by=by) result_titles = [ax.get_title() for ax in axes] result_legends = [ [legend.get_text() for legend in ax.get_legend().texts] for ax in axes @@ -120,9 +114,9 @@ def test_hist_plot_by_argument(self, by, column, titles, legends): ), ], ) - def test_hist_plot_by_0(self, by, column, titles, legends): + def test_hist_plot_by_0(self, by, column, titles, legends, hist_df): # GH 15079 - df = self.hist_df.copy() + df = hist_df.copy() df = df.rename(columns={"C": 0}) axes = _check_plot_works(df.plot.hist, column=column, by=by) @@ -143,11 +137,11 @@ def test_hist_plot_by_0(self, by, column, titles, legends): ((), ["A", "B"]), ], ) - def test_hist_plot_empty_list_string_tuple_by(self, by, column): + def test_hist_plot_empty_list_string_tuple_by(self, by, column, hist_df): # GH 15079 msg = "No group keys passed" with pytest.raises(ValueError, match=msg): - _check_plot_works(self.hist_df.plot.hist, column=column, by=by) + _check_plot_works(hist_df.plot.hist, column=column, by=by) @pytest.mark.slow @pytest.mark.parametrize( @@ -166,12 +160,12 @@ def test_hist_plot_empty_list_string_tuple_by(self, by, column): (["C", "D"], ["A", "B"], (5, 2), 9), ], ) - def test_hist_plot_layout_with_by(self, by, column, layout, axes_num): + def test_hist_plot_layout_with_by(self, by, column, layout, axes_num, hist_df): # GH 15079 # _check_plot_works adds an ax so catch warning. see GH #13188 with tm.assert_produces_warning(UserWarning): axes = _check_plot_works( - self.hist_df.plot.hist, column=column, by=by, layout=layout + hist_df.plot.hist, column=column, by=by, layout=layout ) self._check_axes_shape(axes, axes_num=axes_num, layout=layout) @@ -183,16 +177,16 @@ def test_hist_plot_layout_with_by(self, by, column, layout, axes_num): ("At least one dimension of layout must be positive", "C", (-1, -1)), ], ) - def test_hist_plot_invalid_layout_with_by_raises(self, msg, by, layout): + def test_hist_plot_invalid_layout_with_by_raises(self, msg, by, layout, hist_df): # GH 15079, test if error is raised when invalid layout is given with pytest.raises(ValueError, match=msg): - self.hist_df.plot.hist(column=["A", "B"], by=by, layout=layout) + hist_df.plot.hist(column=["A", "B"], by=by, layout=layout) @pytest.mark.slow - def test_axis_share_x_with_by(self): + def test_axis_share_x_with_by(self, hist_df): # GH 15079 - ax1, ax2, ax3 = self.hist_df.plot.hist(column="A", by="C", sharex=True) + ax1, ax2, ax3 = hist_df.plot.hist(column="A", by="C", sharex=True) # share x assert self.get_x_axis(ax1).joined(ax1, ax2) @@ -207,9 +201,9 @@ def test_axis_share_x_with_by(self): assert not self.get_y_axis(ax3).joined(ax2, ax3) @pytest.mark.slow - def test_axis_share_y_with_by(self): + def test_axis_share_y_with_by(self, hist_df): # GH 15079 - ax1, ax2, ax3 = self.hist_df.plot.hist(column="A", by="C", sharey=True) + ax1, ax2, ax3 = hist_df.plot.hist(column="A", by="C", sharey=True) # share y assert self.get_y_axis(ax1).joined(ax1, ax2) @@ -224,21 +218,14 @@ def test_axis_share_y_with_by(self): assert not self.get_x_axis(ax3).joined(ax2, ax3) @pytest.mark.parametrize("figsize", [(12, 8), (20, 10)]) - def test_figure_shape_hist_with_by(self, figsize): + def test_figure_shape_hist_with_by(self, figsize, hist_df): # GH 15079 - axes = self.hist_df.plot.hist(column="A", by="C", figsize=figsize) + axes = hist_df.plot.hist(column="A", by="C", figsize=figsize) self._check_axes_shape(axes, axes_num=3, figsize=figsize) @td.skip_if_no_mpl class TestBoxWithBy(TestPlotBase): - def setup_method(self, method): - TestPlotBase.setup_method(self, method) - import matplotlib as mpl - - mpl.rcdefaults() - self.box_df = _create_hist_box_with_by_df() - @pytest.mark.parametrize( "by, column, titles, xticklabels", [ @@ -284,9 +271,9 @@ def setup_method(self, method): (["C"], None, ["A", "B"], [["a", "b", "c"]] * 2), ], ) - def test_box_plot_by_argument(self, by, column, titles, xticklabels): + def test_box_plot_by_argument(self, by, column, titles, xticklabels, hist_df): # GH 15079 - axes = _check_plot_works(self.box_df.plot.box, column=column, by=by) + axes = _check_plot_works(hist_df.plot.box, column=column, by=by) result_titles = [ax.get_title() for ax in axes] result_xticklabels = [ [label.get_text() for label in ax.get_xticklabels()] for ax in axes @@ -320,9 +307,9 @@ def test_box_plot_by_argument(self, by, column, titles, xticklabels): (0, None, ["A", "B"], [["a", "b", "c"]] * 2), ], ) - def test_box_plot_by_0(self, by, column, titles, xticklabels): + def test_box_plot_by_0(self, by, column, titles, xticklabels, hist_df): # GH 15079 - df = self.box_df.copy() + df = hist_df.copy() df = df.rename(columns={"C": 0}) axes = _check_plot_works(df.plot.box, column=column, by=by) @@ -343,11 +330,11 @@ def test_box_plot_by_0(self, by, column, titles, xticklabels): ((), ["A", "B"]), ], ) - def test_box_plot_with_none_empty_list_by(self, by, column): + def test_box_plot_with_none_empty_list_by(self, by, column, hist_df): # GH 15079 msg = "No group keys passed" with pytest.raises(ValueError, match=msg): - _check_plot_works(self.box_df.plot.box, column=column, by=by) + _check_plot_works(hist_df.plot.box, column=column, by=by) @pytest.mark.slow @pytest.mark.parametrize( @@ -361,11 +348,9 @@ def test_box_plot_with_none_empty_list_by(self, by, column): (["C", "D"], None, (1, 2), 2), ], ) - def test_box_plot_layout_with_by(self, by, column, layout, axes_num): + def test_box_plot_layout_with_by(self, by, column, layout, axes_num, hist_df): # GH 15079 - axes = _check_plot_works( - self.box_df.plot.box, column=column, by=by, layout=layout - ) + axes = _check_plot_works(hist_df.plot.box, column=column, by=by, layout=layout) self._check_axes_shape(axes, axes_num=axes_num, layout=layout) @pytest.mark.parametrize( @@ -376,14 +361,14 @@ def test_box_plot_layout_with_by(self, by, column, layout, axes_num): ("At least one dimension of layout must be positive", "C", (-1, -1)), ], ) - def test_box_plot_invalid_layout_with_by_raises(self, msg, by, layout): + def test_box_plot_invalid_layout_with_by_raises(self, msg, by, layout, hist_df): # GH 15079, test if error is raised when invalid layout is given with pytest.raises(ValueError, match=msg): - self.box_df.plot.box(column=["A", "B"], by=by, layout=layout) + hist_df.plot.box(column=["A", "B"], by=by, layout=layout) @pytest.mark.parametrize("figsize", [(12, 8), (20, 10)]) - def test_figure_shape_hist_with_by(self, figsize): + def test_figure_shape_hist_with_by(self, figsize, hist_df): # GH 15079 - axes = self.box_df.plot.box(column="A", by="C", figsize=figsize) + axes = hist_df.plot.box(column="A", by="C", figsize=figsize) self._check_axes_shape(axes, axes_num=1, figsize=figsize) diff --git a/pandas/tests/plotting/test_boxplot_method.py b/pandas/tests/plotting/test_boxplot_method.py index 0094c4a502bad..207ebd7f2a193 100644 --- a/pandas/tests/plotting/test_boxplot_method.py +++ b/pandas/tests/plotting/test_boxplot_method.py @@ -108,9 +108,9 @@ def test_boxplot_legacy2(self): lines = list(itertools.chain.from_iterable(d.values())) assert len(ax.get_lines()) == len(lines) - def test_boxplot_return_type_none(self): + def test_boxplot_return_type_none(self, hist_df): # GH 12216; return_type=None & by=None -> axes - result = self.hist_df.boxplot() + result = hist_df.boxplot() assert isinstance(result, self.plt.Axes) def test_boxplot_return_type_legacy(self): @@ -140,13 +140,13 @@ def test_boxplot_return_type_legacy(self): result = df.boxplot(return_type="both") self._check_box_return_type(result, "both") - def test_boxplot_axis_limits(self): + def test_boxplot_axis_limits(self, hist_df): def _check_ax_limits(col, ax): y_min, y_max = ax.get_ylim() assert y_min <= col.min() assert y_max >= col.max() - df = self.hist_df.copy() + df = hist_df.copy() df["age"] = np.random.randint(1, 20, df.shape[0]) # One full row height_ax, weight_ax = df.boxplot(["height", "weight"], by="category") @@ -329,8 +329,8 @@ def test_boxplot_group_xlabel_ylabel(self, vert): @td.skip_if_no_mpl class TestDataFrameGroupByPlots(TestPlotBase): - def test_boxplot_legacy1(self): - grouped = self.hist_df.groupby(by="gender") + def test_boxplot_legacy1(self, hist_df): + grouped = hist_df.groupby(by="gender") with tm.assert_produces_warning(UserWarning): axes = _check_plot_works(grouped.boxplot, return_type="axes") self._check_axes_shape(list(axes.values), axes_num=2, layout=(1, 2)) @@ -381,8 +381,8 @@ def test_grouped_plot_fignums(self): res = df.groupby("gender").hist() tm.close() - def test_grouped_box_return_type(self): - df = self.hist_df + def test_grouped_box_return_type(self, hist_df): + df = hist_df # old style: return_type=None result = df.boxplot(by="gender") @@ -415,8 +415,8 @@ def test_grouped_box_return_type(self): returned = df2.boxplot(by="category", return_type=t) self._check_box_return_type(returned, t, expected_keys=columns2) - def test_grouped_box_layout(self): - df = self.hist_df + def test_grouped_box_layout(self, hist_df): + df = hist_df msg = "Layout of 1x1 must be larger than required size 2" with pytest.raises(ValueError, match=msg): @@ -508,9 +508,9 @@ def test_grouped_box_layout(self): ) self._check_axes_shape(self.plt.gcf().axes, axes_num=3, layout=(1, 3)) - def test_grouped_box_multiple_axes(self): + def test_grouped_box_multiple_axes(self, hist_df): # GH 6970, GH 7069 - df = self.hist_df + df = hist_df # check warning to ignore sharex / sharey # this check should be done in the first function which @@ -614,9 +614,9 @@ def test_groupby_boxplot_subplots_false(self, col, expected_xticklabel): result_xticklabel = [x.get_text() for x in axes.get_xticklabels()] assert expected_xticklabel == result_xticklabel - def test_groupby_boxplot_object(self): + def test_groupby_boxplot_object(self, hist_df): # GH 43480 - df = self.hist_df.astype("object") + df = hist_df.astype("object") grouped = df.groupby("gender") msg = "boxplot method requires numerical columns, nothing to plot" with pytest.raises(ValueError, match=msg): diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index 8fcd0283d6a98..cc10b6bcf1d02 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -531,8 +531,7 @@ def test_gaps(self): line = lines[0] data = line.get_xydata() - if self.mpl_ge_3_0_0 or not self.mpl_ge_2_2_3: - data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) + data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) assert isinstance(data, np.ma.core.MaskedArray) mask = data.mask @@ -550,8 +549,7 @@ def test_gaps(self): line = lines[0] data = line.get_xydata() - if self.mpl_ge_3_0_0 or not self.mpl_ge_2_2_3: - data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) + data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) assert isinstance(data, np.ma.core.MaskedArray) mask = data.mask @@ -568,8 +566,7 @@ def test_gaps(self): assert len(lines) == 1 line = lines[0] data = line.get_xydata() - if self.mpl_ge_3_0_0 or not self.mpl_ge_2_2_3: - data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) + data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) assert isinstance(data, np.ma.core.MaskedArray) mask = data.mask @@ -590,8 +587,7 @@ def test_gap_upsample(self): line = lines[0] data = line.get_xydata() - if self.mpl_ge_3_0_0 or not self.mpl_ge_2_2_3: - data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) + data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) assert isinstance(data, np.ma.core.MaskedArray) mask = data.mask @@ -614,7 +610,7 @@ def test_secondary_y(self): _, ax2 = self.plt.subplots() ser2.plot(ax=ax2) - assert ax2.get_yaxis().get_ticks_position() == self.default_tick_position + assert ax2.get_yaxis().get_ticks_position() == "left" self.plt.close(ax2.get_figure()) ax = ser2.plot() @@ -643,7 +639,7 @@ def test_secondary_y_ts(self): _, ax2 = self.plt.subplots() ser2.plot(ax=ax2) - assert ax2.get_yaxis().get_ticks_position() == self.default_tick_position + assert ax2.get_yaxis().get_ticks_position() == "left" self.plt.close(ax2.get_figure()) ax = ser2.plot() @@ -672,14 +668,14 @@ def test_secondary_frame(self): df = DataFrame(np.random.randn(5, 3), columns=["a", "b", "c"]) axes = df.plot(secondary_y=["a", "c"], subplots=True) assert axes[0].get_yaxis().get_ticks_position() == "right" - assert axes[1].get_yaxis().get_ticks_position() == self.default_tick_position + assert axes[1].get_yaxis().get_ticks_position() == "left" assert axes[2].get_yaxis().get_ticks_position() == "right" def test_secondary_bar_frame(self): df = DataFrame(np.random.randn(5, 3), columns=["a", "b", "c"]) axes = df.plot(kind="bar", secondary_y=["a", "c"], subplots=True) assert axes[0].get_yaxis().get_ticks_position() == "right" - assert axes[1].get_yaxis().get_ticks_position() == self.default_tick_position + assert axes[1].get_yaxis().get_ticks_position() == "left" assert axes[2].get_yaxis().get_ticks_position() == "right" def test_mixed_freq_regular_first(self): @@ -1453,12 +1449,7 @@ def test_matplotlib_scatter_datetime64(self): ax.scatter(x="time", y="y", data=df) self.plt.draw() label = ax.get_xticklabels()[0] - if self.mpl_ge_3_2_0: - expected = "2018-01-01" - elif self.mpl_ge_3_0_0: - expected = "2017-12-08" - else: - expected = "2017-12-12" + expected = "2018-01-01" assert label.get_text() == expected def test_check_xticks_rot(self): diff --git a/pandas/tests/plotting/test_hist_method.py b/pandas/tests/plotting/test_hist_method.py index 403f4a2c06df1..288fd9c466d73 100644 --- a/pandas/tests/plotting/test_hist_method.py +++ b/pandas/tests/plotting/test_hist_method.py @@ -64,8 +64,8 @@ def test_hist_bins_legacy(self): ax = df.hist(bins=2)[0][0] assert len(ax.patches) == 2 - def test_hist_layout(self): - df = self.hist_df + def test_hist_layout(self, hist_df): + df = hist_df msg = "The 'layout' keyword is not supported when 'by' is None" with pytest.raises(ValueError, match=msg): df.height.hist(layout=(1, 1)) @@ -73,8 +73,8 @@ def test_hist_layout(self): with pytest.raises(ValueError, match=msg): df.height.hist(layout=[1, 1]) - def test_hist_layout_with_by(self): - df = self.hist_df + def test_hist_layout_with_by(self, hist_df): + df = hist_df # _check_plot_works adds an `ax` kwarg to the method call # so we get a warning about an axis being cleared, even @@ -126,8 +126,8 @@ def test_hist_no_overlap(self): axes = fig.axes assert len(axes) == 2 - def test_hist_by_no_extra_plots(self): - df = self.hist_df + def test_hist_by_no_extra_plots(self, hist_df): + df = hist_df axes = df.height.hist(by=df.gender) # noqa assert len(self.plt.get_fignums()) == 1 @@ -236,18 +236,18 @@ def test_hist_kde_color(self): @td.skip_if_no_mpl class TestDataFramePlots(TestPlotBase): - def test_hist_df_legacy(self): + def test_hist_df_legacy(self, hist_df): from matplotlib.patches import Rectangle with tm.assert_produces_warning(UserWarning): - _check_plot_works(self.hist_df.hist) + _check_plot_works(hist_df.hist) # make sure layout is handled df = DataFrame(np.random.randn(100, 2)) df[2] = to_datetime( np.random.randint( - self.start_date_to_int64, - self.end_date_to_int64, + 812419200000000000, + 819331200000000000, size=100, dtype=np.int64, ) @@ -265,8 +265,8 @@ def test_hist_df_legacy(self): df = DataFrame(np.random.randn(100, 5)) df[5] = to_datetime( np.random.randint( - self.start_date_to_int64, - self.end_date_to_int64, + 812419200000000000, + 819331200000000000, size=100, dtype=np.int64, ) @@ -350,7 +350,7 @@ def test_hist_layout(self): df = DataFrame(np.random.randn(100, 2)) df[2] = to_datetime( np.random.randint( - self.start_date_to_int64, + 812419200000000000, self.end_date_to_int64, size=100, dtype=np.int64, @@ -392,7 +392,7 @@ def test_tight_layout(self): df = DataFrame(np.random.randn(100, 2)) df[2] = to_datetime( np.random.randint( - self.start_date_to_int64, + 812419200000000000, self.end_date_to_int64, size=100, dtype=np.int64, @@ -574,7 +574,7 @@ def test_grouped_hist_legacy(self): df = DataFrame(np.random.randn(500, 1), columns=["A"]) df["B"] = to_datetime( np.random.randint( - self.start_date_to_int64, + 812419200000000000, self.end_date_to_int64, size=500, dtype=np.int64, @@ -648,8 +648,8 @@ def test_grouped_hist_legacy2(self): assert len(self.plt.get_fignums()) == 2 tm.close() - def test_grouped_hist_layout(self): - df = self.hist_df + def test_grouped_hist_layout(self, hist_df): + df = hist_df msg = "Layout of 1x1 must be larger than required size 2" with pytest.raises(ValueError, match=msg): df.hist(column="weight", by=df.gender, layout=(1, 1)) @@ -702,9 +702,9 @@ def test_grouped_hist_layout(self): axes = df.hist(column=["height", "weight", "category"]) self._check_axes_shape(axes, axes_num=3, layout=(2, 2)) - def test_grouped_hist_multiple_axes(self): + def test_grouped_hist_multiple_axes(self, hist_df): # GH 6970, GH 7069 - df = self.hist_df + df = hist_df fig, axes = self.plt.subplots(2, 3) returned = df.hist(column=["height", "weight", "category"], ax=axes[0]) @@ -722,8 +722,8 @@ def test_grouped_hist_multiple_axes(self): with pytest.raises(ValueError, match=msg): axes = df.hist(column="height", ax=axes) - def test_axis_share_x(self): - df = self.hist_df + def test_axis_share_x(self, hist_df): + df = hist_df # GH4089 ax1, ax2 = df.hist(column="height", by=df.gender, sharex=True) @@ -735,8 +735,8 @@ def test_axis_share_x(self): assert not self.get_y_axis(ax1).joined(ax1, ax2) assert not self.get_y_axis(ax2).joined(ax1, ax2) - def test_axis_share_y(self): - df = self.hist_df + def test_axis_share_y(self, hist_df): + df = hist_df ax1, ax2 = df.hist(column="height", by=df.gender, sharey=True) # share y @@ -747,8 +747,8 @@ def test_axis_share_y(self): assert not self.get_x_axis(ax1).joined(ax1, ax2) assert not self.get_x_axis(ax2).joined(ax1, ax2) - def test_axis_share_xy(self): - df = self.hist_df + def test_axis_share_xy(self, hist_df): + df = hist_df ax1, ax2 = df.hist(column="height", by=df.gender, sharex=True, sharey=True) # share both x and y diff --git a/pandas/tests/plotting/test_misc.py b/pandas/tests/plotting/test_misc.py index adda95f4c5aa0..18b4b7f5e5ebb 100644 --- a/pandas/tests/plotting/test_misc.py +++ b/pandas/tests/plotting/test_misc.py @@ -102,8 +102,6 @@ class TestDataFramePlots(TestPlotBase): @td.skip_if_no_scipy @pytest.mark.parametrize("pass_axis", [False, True]) def test_scatter_matrix_axis(self, pass_axis): - from pandas.plotting._matplotlib.compat import mpl_ge_3_0_0 - scatter_matrix = plotting.scatter_matrix ax = None @@ -114,9 +112,7 @@ def test_scatter_matrix_axis(self, pass_axis): df = DataFrame(np.random.randn(100, 3)) # we are plotting multiples on a sub-plot - with tm.assert_produces_warning( - UserWarning, raise_on_extra_warnings=mpl_ge_3_0_0() - ): + with tm.assert_produces_warning(UserWarning, raise_on_extra_warnings=True): axes = _check_plot_works( scatter_matrix, filterwarnings="always", From d713c96e352aa3d65abaca0b4d266f8e203ec127 Mon Sep 17 00:00:00 2001 From: Matthew Roeschke Date: Mon, 14 Feb 2022 12:15:30 -0800 Subject: [PATCH 2/3] Remove all other setup methods --- pandas/tests/plotting/common.py | 13 +- pandas/tests/plotting/test_converter.py | 32 ++- pandas/tests/plotting/test_datetimelike.py | 112 +++++------ pandas/tests/plotting/test_hist_method.py | 64 +++--- pandas/tests/plotting/test_misc.py | 26 +-- pandas/tests/plotting/test_series.py | 221 +++++++++++---------- 6 files changed, 224 insertions(+), 244 deletions(-) diff --git a/pandas/tests/plotting/common.py b/pandas/tests/plotting/common.py index 521cd4a7244fd..1e91379921b88 100644 --- a/pandas/tests/plotting/common.py +++ b/pandas/tests/plotting/common.py @@ -7,7 +7,6 @@ from __future__ import annotations -import os from typing import ( TYPE_CHECKING, Sequence, @@ -40,7 +39,7 @@ def setup_method(self): mpl.rcdefaults() - def teardown_method(self, method): + def teardown_method(self): tm.close() @cache_readonly @@ -112,13 +111,12 @@ def _check_data(self, xp, rs): xp_lines = xp.get_lines() rs_lines = rs.get_lines() - def check_line(xpl, rsl): + assert len(xp_lines) == len(rs_lines) + for xpl, rsl in zip(xp_lines, rs_lines): xpdata = xpl.get_xydata() rsdata = rsl.get_xydata() tm.assert_almost_equal(xpdata, rsdata) - assert len(xp_lines) == len(rs_lines) - [check_line(xpl, rsl) for xpl, rsl in zip(xp_lines, rs_lines)] tm.close() def _check_visible(self, collections, visible=True): @@ -603,8 +601,3 @@ def _gen_two_subplots(f, fig, **kwargs): else: kwargs["ax"] = fig.add_subplot(212) yield f(**kwargs) - - -def curpath(): - pth, _ = os.path.split(os.path.abspath(__file__)) - return pth diff --git a/pandas/tests/plotting/test_converter.py b/pandas/tests/plotting/test_converter.py index bbf97987a6d0a..f3418415695b0 100644 --- a/pandas/tests/plotting/test_converter.py +++ b/pandas/tests/plotting/test_converter.py @@ -260,28 +260,24 @@ def test_time_formatter(self, time, format_expected): result = self.tc(time) assert result == format_expected - def test_dateindex_conversion(self): + @pytest.mark.parametrize("freq", ("B", "L", "S")) + def test_dateindex_conversion(self, freq): rtol = 10**-9 + dateindex = tm.makeDateIndex(k=10, freq=freq) + rs = self.dtc.convert(dateindex, None, None) + xp = converter.dates.date2num(dateindex._mpl_repr()) + tm.assert_almost_equal(rs, xp, rtol=rtol) - for freq in ("B", "L", "S"): - dateindex = tm.makeDateIndex(k=10, freq=freq) - rs = self.dtc.convert(dateindex, None, None) - xp = converter.dates.date2num(dateindex._mpl_repr()) - tm.assert_almost_equal(rs, xp, rtol=rtol) - - def test_resolution(self): - def _assert_less(ts1, ts2): - val1 = self.dtc.convert(ts1, None, None) - val2 = self.dtc.convert(ts2, None, None) - if not val1 < val2: - raise AssertionError(f"{val1} is not less than {val2}.") - + @pytest.mark.parametrize("offset", [Second(), Milli(), Micro(50)]) + def test_resolution(self, offset): # Matplotlib's time representation using floats cannot distinguish # intervals smaller than ~10 microsecond in the common range of years. - ts = Timestamp("2012-1-1") - _assert_less(ts, ts + Second()) - _assert_less(ts, ts + Milli()) - _assert_less(ts, ts + Micro(50)) + ts1 = Timestamp("2012-1-1") + ts2 = ts1 + offset + val1 = self.dtc.convert(ts1, None, None) + val2 = self.dtc.convert(ts2, None, None) + if not val1 < val2: + raise AssertionError(f"{val1} is not less than {val2}.") def test_convert_nested(self): inner = [Timestamp("2017-01-01"), Timestamp("2017-01-02")] diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index cc10b6bcf1d02..1b818f57d0572 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -46,28 +46,6 @@ @td.skip_if_no_mpl class TestTSPlot(TestPlotBase): - def setup_method(self, method): - TestPlotBase.setup_method(self, method) - - self.freq = ["S", "T", "H", "D", "W", "M", "Q", "A"] - idx = [period_range("12/31/1999", freq=x, periods=100) for x in self.freq] - self.period_ser = [Series(np.random.randn(len(x)), x) for x in idx] - self.period_df = [ - DataFrame(np.random.randn(len(x), 3), index=x, columns=["A", "B", "C"]) - for x in idx - ] - - freq = ["S", "T", "H", "D", "W", "M", "Q-DEC", "A", "1B30Min"] - idx = [date_range("12/31/1999", freq=x, periods=100) for x in freq] - self.datetime_ser = [Series(np.random.randn(len(x)), x) for x in idx] - self.datetime_df = [ - DataFrame(np.random.randn(len(x), 3), index=x, columns=["A", "B", "C"]) - for x in idx - ] - - def teardown_method(self, method): - tm.close() - def test_ts_plot_with_tz(self, tz_aware_fixture): # GH2877, GH17173, GH31205, GH31580 tz = tz_aware_fixture @@ -128,17 +106,24 @@ def test_nonnumeric_exclude(self): with pytest.raises(TypeError, match=msg): df["A"].plot() - def test_tsplot(self): - + @pytest.mark.parametrize("freq", ["S", "T", "H", "D", "W", "M", "Q", "A"]) + def test_tsplot_period(self, freq): + idx = period_range("12/31/1999", freq=freq, periods=100) + ser = Series(np.random.randn(len(idx)), idx) _, ax = self.plt.subplots() - ts = tm.makeTimeSeries() - - for s in self.period_ser: - _check_plot_works(s.plot, ax=ax) + _check_plot_works(ser.plot, ax=ax) - for s in self.datetime_ser: - _check_plot_works(s.plot, ax=ax) + @pytest.mark.parametrize( + "freq", ["S", "T", "H", "D", "W", "M", "Q-DEC", "A", "1B30Min"] + ) + def test_tsplot_datetime(self, freq): + idx = date_range("12/31/1999", freq=freq, periods=100) + ser = Series(np.random.randn(len(idx)), idx) + _, ax = self.plt.subplots() + _check_plot_works(ser.plot, ax=ax) + def test_tsplot(self): + ts = tm.makeTimeSeries() _, ax = self.plt.subplots() ts.plot(style="k", ax=ax) color = (0.0, 0.0, 0.0, 1) @@ -159,13 +144,12 @@ def test_both_style_and_color(self): with pytest.raises(ValueError, match=msg): s.plot(style="b-", color="#000099") - def test_high_freq(self): - freaks = ["ms", "us"] - for freq in freaks: - _, ax = self.plt.subplots() - rng = date_range("1/1/2012", periods=100, freq=freq) - ser = Series(np.random.randn(len(rng)), rng) - _check_plot_works(ser.plot, ax=ax) + @pytest.mark.parametrize("freq", ["ms", "us"]) + def test_high_freq(self, freq): + _, ax = self.plt.subplots() + rng = date_range("1/1/2012", periods=100, freq=freq) + ser = Series(np.random.randn(len(rng)), rng) + _check_plot_works(ser.plot, ax=ax) def test_get_datevalue(self): from pandas.plotting._matplotlib.converter import get_datevalue @@ -194,9 +178,11 @@ def check_format_of_first_point(ax, expected_string): check_format_of_first_point(ax, "t = 2014-01-01 y = 1.000000") tm.close() - def test_line_plot_period_series(self): - for s in self.period_ser: - _check_plot_works(s.plot, s.index.freq) + @pytest.mark.parametrize("freq", ["S", "T", "H", "D", "W", "M", "Q", "A"]) + def test_line_plot_period_series(self, freq): + idx = period_range("12/31/1999", freq=freq, periods=100) + ser = Series(np.random.randn(len(idx)), idx) + _check_plot_works(ser.plot, ser.index.freq) @pytest.mark.parametrize( "frqncy", ["1S", "3S", "5T", "7H", "4D", "8W", "11M", "3A"] @@ -208,13 +194,19 @@ def test_line_plot_period_mlt_series(self, frqncy): s = Series(np.random.randn(len(idx)), idx) _check_plot_works(s.plot, s.index.freq.rule_code) - def test_line_plot_datetime_series(self): - for s in self.datetime_ser: - _check_plot_works(s.plot, s.index.freq.rule_code) + @pytest.mark.parametrize( + "freq", ["S", "T", "H", "D", "W", "M", "Q-DEC", "A", "1B30Min"] + ) + def test_line_plot_datetime_series(self, freq): + idx = date_range("12/31/1999", freq=freq, periods=100) + ser = Series(np.random.randn(len(idx)), idx) + _check_plot_works(ser.plot, ser.index.freq.rule_code) - def test_line_plot_period_frame(self): - for df in self.period_df: - _check_plot_works(df.plot, df.index.freq) + @pytest.mark.parametrize("freq", ["S", "T", "H", "D", "W", "M", "Q", "A"]) + def test_line_plot_period_frame(self, freq): + idx = date_range("12/31/1999", freq=freq, periods=100) + df = DataFrame(np.random.randn(len(idx), 3), index=idx, columns=["A", "B", "C"]) + _check_plot_works(df.plot, df.index.freq) @pytest.mark.parametrize( "frqncy", ["1S", "3S", "5T", "7H", "4D", "8W", "11M", "3A"] @@ -228,18 +220,26 @@ def test_line_plot_period_mlt_frame(self, frqncy): freq = df.index.asfreq(df.index.freq.rule_code).freq _check_plot_works(df.plot, freq) - def test_line_plot_datetime_frame(self): - for df in self.datetime_df: - freq = df.index.to_period(df.index.freq.rule_code).freq - _check_plot_works(df.plot, freq) + @pytest.mark.parametrize( + "freq", ["S", "T", "H", "D", "W", "M", "Q-DEC", "A", "1B30Min"] + ) + def test_line_plot_datetime_frame(self, freq): + idx = date_range("12/31/1999", freq=freq, periods=100) + df = DataFrame(np.random.randn(len(idx), 3), index=idx, columns=["A", "B", "C"]) + freq = df.index.to_period(df.index.freq.rule_code).freq + _check_plot_works(df.plot, freq) - def test_line_plot_inferred_freq(self): - for ser in self.datetime_ser: - ser = Series(ser.values, Index(np.asarray(ser.index))) - _check_plot_works(ser.plot, ser.index.inferred_freq) + @pytest.mark.parametrize( + "freq", ["S", "T", "H", "D", "W", "M", "Q-DEC", "A", "1B30Min"] + ) + def test_line_plot_inferred_freq(self, freq): + idx = date_range("12/31/1999", freq=freq, periods=100) + ser = Series(np.random.randn(len(idx)), idx) + ser = Series(ser.values, Index(np.asarray(ser.index))) + _check_plot_works(ser.plot, ser.index.inferred_freq) - ser = ser[[0, 3, 5, 6]] - _check_plot_works(ser.plot) + ser = ser[[0, 3, 5, 6]] + _check_plot_works(ser.plot) def test_fake_inferred_business(self): _, ax = self.plt.subplots() diff --git a/pandas/tests/plotting/test_hist_method.py b/pandas/tests/plotting/test_hist_method.py index 288fd9c466d73..785734c7d1061 100644 --- a/pandas/tests/plotting/test_hist_method.py +++ b/pandas/tests/plotting/test_hist_method.py @@ -21,43 +21,39 @@ pytestmark = pytest.mark.slow -@td.skip_if_no_mpl -class TestSeriesPlots(TestPlotBase): - def setup_method(self, method): - TestPlotBase.setup_method(self, method) - import matplotlib as mpl - - mpl.rcdefaults() +@pytest.fixture +def ts(): + return tm.makeTimeSeries(name="ts") - self.ts = tm.makeTimeSeries() - self.ts.name = "ts" - def test_hist_legacy(self): - _check_plot_works(self.ts.hist) - _check_plot_works(self.ts.hist, grid=False) - _check_plot_works(self.ts.hist, figsize=(8, 10)) +@td.skip_if_no_mpl +class TestSeriesPlots(TestPlotBase): + def test_hist_legacy(self, ts): + _check_plot_works(ts.hist) + _check_plot_works(ts.hist, grid=False) + _check_plot_works(ts.hist, figsize=(8, 10)) # _check_plot_works adds an ax so catch warning. see GH #13188 with tm.assert_produces_warning(UserWarning): - _check_plot_works(self.ts.hist, by=self.ts.index.month) + _check_plot_works(ts.hist, by=ts.index.month) with tm.assert_produces_warning(UserWarning): - _check_plot_works(self.ts.hist, by=self.ts.index.month, bins=5) + _check_plot_works(ts.hist, by=ts.index.month, bins=5) fig, ax = self.plt.subplots(1, 1) - _check_plot_works(self.ts.hist, ax=ax, default_axes=True) - _check_plot_works(self.ts.hist, ax=ax, figure=fig, default_axes=True) - _check_plot_works(self.ts.hist, figure=fig, default_axes=True) + _check_plot_works(ts.hist, ax=ax, default_axes=True) + _check_plot_works(ts.hist, ax=ax, figure=fig, default_axes=True) + _check_plot_works(ts.hist, figure=fig, default_axes=True) tm.close() fig, (ax1, ax2) = self.plt.subplots(1, 2) - _check_plot_works(self.ts.hist, figure=fig, ax=ax1, default_axes=True) - _check_plot_works(self.ts.hist, figure=fig, ax=ax2, default_axes=True) + _check_plot_works(ts.hist, figure=fig, ax=ax1, default_axes=True) + _check_plot_works(ts.hist, figure=fig, ax=ax2, default_axes=True) msg = ( "Cannot pass 'figure' when using the 'by' argument, since a new 'Figure' " "instance will be created" ) with pytest.raises(ValueError, match=msg): - self.ts.hist(by=self.ts.index, figure=fig) + ts.hist(by=ts.index, figure=fig) def test_hist_bins_legacy(self): df = DataFrame(np.random.randn(10, 2)) @@ -131,7 +127,7 @@ def test_hist_by_no_extra_plots(self, hist_df): axes = df.height.hist(by=df.gender) # noqa assert len(self.plt.get_fignums()) == 1 - def test_plot_fails_when_ax_differs_from_figure(self): + def test_plot_fails_when_ax_differs_from_figure(self, ts): from pylab import figure fig1 = figure() @@ -139,7 +135,7 @@ def test_plot_fails_when_ax_differs_from_figure(self): ax1 = fig1.add_subplot(111) msg = "passed axis not bound to passed figure" with pytest.raises(AssertionError, match=msg): - self.ts.hist(ax=ax1, figure=fig2) + ts.hist(ax=ax1, figure=fig2) @pytest.mark.parametrize( "histtype, expected", @@ -180,27 +176,27 @@ def test_hist_with_legend_raises(self, by): with pytest.raises(ValueError, match="Cannot use both legend and label"): s.hist(legend=True, by=by, label="c") - def test_hist_kwargs(self): + def test_hist_kwargs(self, ts): _, ax = self.plt.subplots() - ax = self.ts.plot.hist(bins=5, ax=ax) + ax = ts.plot.hist(bins=5, ax=ax) assert len(ax.patches) == 5 self._check_text_labels(ax.yaxis.get_label(), "Frequency") tm.close() _, ax = self.plt.subplots() - ax = self.ts.plot.hist(orientation="horizontal", ax=ax) + ax = ts.plot.hist(orientation="horizontal", ax=ax) self._check_text_labels(ax.xaxis.get_label(), "Frequency") tm.close() _, ax = self.plt.subplots() - ax = self.ts.plot.hist(align="left", stacked=True, ax=ax) + ax = ts.plot.hist(align="left", stacked=True, ax=ax) tm.close() @td.skip_if_no_scipy - def test_hist_kde(self): + def test_hist_kde(self, ts): _, ax = self.plt.subplots() - ax = self.ts.plot.hist(logy=True, ax=ax) + ax = ts.plot.hist(logy=True, ax=ax) self._check_ax_scales(ax, yaxis="log") xlabels = ax.get_xticklabels() # ticks are values, thus ticklabels are blank @@ -208,10 +204,10 @@ def test_hist_kde(self): ylabels = ax.get_yticklabels() self._check_text_labels(ylabels, [""] * len(ylabels)) - _check_plot_works(self.ts.plot.kde) - _check_plot_works(self.ts.plot.density) + _check_plot_works(ts.plot.kde) + _check_plot_works(ts.plot.density) _, ax = self.plt.subplots() - ax = self.ts.plot.kde(logy=True, ax=ax) + ax = ts.plot.kde(logy=True, ax=ax) self._check_ax_scales(ax, yaxis="log") xlabels = ax.get_xticklabels() self._check_text_labels(xlabels, [""] * len(xlabels)) @@ -221,13 +217,13 @@ def test_hist_kde(self): @td.skip_if_no_scipy def test_hist_kde_color(self): _, ax = self.plt.subplots() - ax = self.ts.plot.hist(logy=True, bins=10, color="b", ax=ax) + ax = ts.plot.hist(logy=True, bins=10, color="b", ax=ax) self._check_ax_scales(ax, yaxis="log") assert len(ax.patches) == 10 self._check_colors(ax.patches, facecolors=["b"] * 10) _, ax = self.plt.subplots() - ax = self.ts.plot.kde(logy=True, color="r", ax=ax) + ax = ts.plot.kde(logy=True, color="r", ax=ax) self._check_ax_scales(ax, yaxis="log") lines = ax.get_lines() assert len(lines) == 1 diff --git a/pandas/tests/plotting/test_misc.py b/pandas/tests/plotting/test_misc.py index 18b4b7f5e5ebb..be5e5cbae2538 100644 --- a/pandas/tests/plotting/test_misc.py +++ b/pandas/tests/plotting/test_misc.py @@ -65,36 +65,30 @@ def test_get_accessor_args(): @td.skip_if_no_mpl class TestSeriesPlots(TestPlotBase): - def setup_method(self, method): - TestPlotBase.setup_method(self, method) - import matplotlib as mpl - - mpl.rcdefaults() - - self.ts = tm.makeTimeSeries() - self.ts.name = "ts" - def test_autocorrelation_plot(self): from pandas.plotting import autocorrelation_plot + ser = tm.makeTimeSeries(name="ts") # Ensure no UserWarning when making plot with tm.assert_produces_warning(None): - _check_plot_works(autocorrelation_plot, series=self.ts) - _check_plot_works(autocorrelation_plot, series=self.ts.values) + _check_plot_works(autocorrelation_plot, series=ser) + _check_plot_works(autocorrelation_plot, series=ser.values) - ax = autocorrelation_plot(self.ts, label="Test") + ax = autocorrelation_plot(ser, label="Test") self._check_legend_labels(ax, labels=["Test"]) - def test_lag_plot(self): + @pytest.mark.parametrize("kwargs", [{}, {"lag": 5}]) + def test_lag_plot(self, kwargs): from pandas.plotting import lag_plot - _check_plot_works(lag_plot, series=self.ts) - _check_plot_works(lag_plot, series=self.ts, lag=5) + ser = tm.makeTimeSeries(name="ts") + _check_plot_works(lag_plot, series=ser, **kwargs) def test_bootstrap_plot(self): from pandas.plotting import bootstrap_plot - _check_plot_works(bootstrap_plot, series=self.ts, size=10) + ser = tm.makeTimeSeries(name="ts") + _check_plot_works(bootstrap_plot, series=ser, size=10) @td.skip_if_no_mpl diff --git a/pandas/tests/plotting/test_series.py b/pandas/tests/plotting/test_series.py index 8f8f59cf291d0..5af111ba503be 100644 --- a/pandas/tests/plotting/test_series.py +++ b/pandas/tests/plotting/test_series.py @@ -26,62 +26,69 @@ pytestmark = pytest.mark.slow -@td.skip_if_no_mpl -class TestSeriesPlots(TestPlotBase): - def setup_method(self, method): - TestPlotBase.setup_method(self, method) - import matplotlib as mpl +@pytest.fixture +def ts(): + return tm.makeTimeSeries(name="ts") + - mpl.rcdefaults() +@pytest.fixture +def series(): + return tm.makeStringSeries(name="series") - self.ts = tm.makeTimeSeries() - self.ts.name = "ts" - self.series = tm.makeStringSeries() - self.series.name = "series" +@pytest.fixture +def iseries(): + return tm.makePeriodSeries(name="iseries") - self.iseries = tm.makePeriodSeries() - self.iseries.name = "iseries" - def test_plot(self): - _check_plot_works(self.ts.plot, label="foo") - _check_plot_works(self.ts.plot, use_index=False) - axes = _check_plot_works(self.ts.plot, rot=0) +@td.skip_if_no_mpl +class TestSeriesPlots(TestPlotBase): + def test_plot(self, ts): + _check_plot_works(ts.plot, label="foo") + _check_plot_works(ts.plot, use_index=False) + axes = _check_plot_works(ts.plot, rot=0) self._check_ticks_props(axes, xrot=0) - ax = _check_plot_works(self.ts.plot, style=".", logy=True) + ax = _check_plot_works(ts.plot, style=".", logy=True) self._check_ax_scales(ax, yaxis="log") - ax = _check_plot_works(self.ts.plot, style=".", logx=True) + ax = _check_plot_works(ts.plot, style=".", logx=True) self._check_ax_scales(ax, xaxis="log") - ax = _check_plot_works(self.ts.plot, style=".", loglog=True) + ax = _check_plot_works(ts.plot, style=".", loglog=True) self._check_ax_scales(ax, xaxis="log", yaxis="log") - _check_plot_works(self.ts[:10].plot.bar) - _check_plot_works(self.ts.plot.area, stacked=False) - _check_plot_works(self.iseries.plot) + _check_plot_works(ts[:10].plot.bar) + _check_plot_works(ts.plot.area, stacked=False) + + def test_plot_iseries(self, iseries): + _check_plot_works(iseries.plot) + + @pytest.mark.parametrize("kind", ["line", "bar", "barh", "kde", "hist", "box"]) + def test_plot_series_kinds(self, kind): + _check_plot_works(series[:5].plot, kind=kind) - for kind in ["line", "bar", "barh", "kde", "hist", "box"]: - _check_plot_works(self.series[:5].plot, kind=kind) + def test_plot_series_barh(self, series): + _check_plot_works(series[:10].plot.barh) - _check_plot_works(self.series[:10].plot.barh) + def test_plot_series_bar_ax(self): ax = _check_plot_works(Series(np.random.randn(10)).plot.bar, color="black") self._check_colors([ax.patches[0]], facecolors=["black"]) + def test_plot_6951(self, ts): # GH 6951 - ax = _check_plot_works(self.ts.plot, subplots=True) + ax = _check_plot_works(ts.plot, subplots=True) self._check_axes_shape(ax, axes_num=1, layout=(1, 1)) - ax = _check_plot_works(self.ts.plot, subplots=True, layout=(-1, 1)) + ax = _check_plot_works(ts.plot, subplots=True, layout=(-1, 1)) self._check_axes_shape(ax, axes_num=1, layout=(1, 1)) - ax = _check_plot_works(self.ts.plot, subplots=True, layout=(1, -1)) + ax = _check_plot_works(ts.plot, subplots=True, layout=(1, -1)) self._check_axes_shape(ax, axes_num=1, layout=(1, 1)) - def test_plot_figsize_and_title(self): + def test_plot_figsize_and_title(self, series): # figsize and title _, ax = self.plt.subplots() - ax = self.series.plot(title="Test", figsize=(16, 8), ax=ax) + ax = series.plot(title="Test", figsize=(16, 8), ax=ax) self._check_text_labels(ax.title, "Test") self._check_axes_shape(ax, axes_num=1, layout=(1, 1), figsize=(16, 8)) @@ -93,24 +100,24 @@ def test_dont_modify_rcParams(self): Series([1, 2, 3]).plot(ax=ax) assert colors == self.plt.rcParams[key] - def test_ts_line_lim(self): + def test_ts_line_lim(self, ts): fig, ax = self.plt.subplots() - ax = self.ts.plot(ax=ax) + ax = ts.plot(ax=ax) xmin, xmax = ax.get_xlim() lines = ax.get_lines() assert xmin <= lines[0].get_data(orig=False)[0][0] assert xmax >= lines[0].get_data(orig=False)[0][-1] tm.close() - ax = self.ts.plot(secondary_y=True, ax=ax) + ax = ts.plot(secondary_y=True, ax=ax) xmin, xmax = ax.get_xlim() lines = ax.get_lines() assert xmin <= lines[0].get_data(orig=False)[0][0] assert xmax >= lines[0].get_data(orig=False)[0][-1] - def test_ts_area_lim(self): + def test_ts_area_lim(self, ts): _, ax = self.plt.subplots() - ax = self.ts.plot.area(stacked=False, ax=ax) + ax = ts.plot.area(stacked=False, ax=ax) xmin, xmax = ax.get_xlim() line = ax.get_lines()[0].get_data(orig=False)[0] assert xmin <= line[0] @@ -120,7 +127,7 @@ def test_ts_area_lim(self): # GH 7471 _, ax = self.plt.subplots() - ax = self.ts.plot.area(stacked=False, x_compat=True, ax=ax) + ax = ts.plot.area(stacked=False, x_compat=True, ax=ax) xmin, xmax = ax.get_xlim() line = ax.get_lines()[0].get_data(orig=False)[0] assert xmin <= line[0] @@ -128,7 +135,7 @@ def test_ts_area_lim(self): self._check_ticks_props(ax, xrot=30) tm.close() - tz_ts = self.ts.copy() + tz_ts = ts.copy() tz_ts.index = tz_ts.tz_localize("GMT").tz_convert("CET") _, ax = self.plt.subplots() ax = tz_ts.plot.area(stacked=False, x_compat=True, ax=ax) @@ -147,12 +154,12 @@ def test_ts_area_lim(self): assert xmax >= line[-1] self._check_ticks_props(ax, xrot=0) - def test_area_sharey_dont_overwrite(self): + def test_area_sharey_dont_overwrite(self, ts): # GH37942 fig, (ax1, ax2) = self.plt.subplots(1, 2, sharey=True) - abs(self.ts).plot(ax=ax1, kind="area") - abs(self.ts).plot(ax=ax2, kind="area") + abs(ts).plot(ax=ax1, kind="area") + abs(ts).plot(ax=ax2, kind="area") assert self.get_y_axis(ax1).joined(ax1, ax2) assert self.get_y_axis(ax2).joined(ax1, ax2) @@ -194,28 +201,24 @@ def test_boolean(self): with pytest.raises(TypeError, match=msg): _check_plot_works(s.plot) - def test_line_area_nan_series(self): + @pytest.mark.parametrize("index", [None, tm.makeDateIndex(k=4)]) + def test_line_area_nan_series(self, index): values = [1, 2, np.nan, 3] - s = Series(values) - ts = Series(values, index=tm.makeDateIndex(k=4)) - - for d in [s, ts]: - ax = _check_plot_works(d.plot) - masked = ax.lines[0].get_ydata() - # remove nan for comparison purpose - exp = np.array([1, 2, 3], dtype=np.float64) - tm.assert_numpy_array_equal(np.delete(masked.data, 2), exp) - tm.assert_numpy_array_equal( - masked.mask, np.array([False, False, True, False]) - ) - - expected = np.array([1, 2, 0, 3], dtype=np.float64) - ax = _check_plot_works(d.plot, stacked=True) - tm.assert_numpy_array_equal(ax.lines[0].get_ydata(), expected) - ax = _check_plot_works(d.plot.area) - tm.assert_numpy_array_equal(ax.lines[0].get_ydata(), expected) - ax = _check_plot_works(d.plot.area, stacked=False) - tm.assert_numpy_array_equal(ax.lines[0].get_ydata(), expected) + d = Series(values, index=index) + ax = _check_plot_works(d.plot) + masked = ax.lines[0].get_ydata() + # remove nan for comparison purpose + exp = np.array([1, 2, 3], dtype=np.float64) + tm.assert_numpy_array_equal(np.delete(masked.data, 2), exp) + tm.assert_numpy_array_equal(masked.mask, np.array([False, False, True, False])) + + expected = np.array([1, 2, 0, 3], dtype=np.float64) + ax = _check_plot_works(d.plot, stacked=True) + tm.assert_numpy_array_equal(ax.lines[0].get_ydata(), expected) + ax = _check_plot_works(d.plot.area) + tm.assert_numpy_array_equal(ax.lines[0].get_ydata(), expected) + ax = _check_plot_works(d.plot.area, stacked=False) + tm.assert_numpy_array_equal(ax.lines[0].get_ydata(), expected) def test_line_use_index_false(self): s = Series([1, 2, 3], index=["a", "b", "c"]) @@ -462,15 +465,15 @@ def test_plot_fails_with_dupe_color_and_style(self): x.plot(style="k--", color="k", ax=ax) @td.skip_if_no_scipy - def test_kde_kwargs(self): + def test_kde_kwargs(self, ts): sample_points = np.linspace(-100, 100, 20) - _check_plot_works(self.ts.plot.kde, bw_method="scott", ind=20) - _check_plot_works(self.ts.plot.kde, bw_method=None, ind=20) - _check_plot_works(self.ts.plot.kde, bw_method=None, ind=np.int_(20)) - _check_plot_works(self.ts.plot.kde, bw_method=0.5, ind=sample_points) - _check_plot_works(self.ts.plot.density, bw_method=0.5, ind=sample_points) + _check_plot_works(ts.plot.kde, bw_method="scott", ind=20) + _check_plot_works(ts.plot.kde, bw_method=None, ind=20) + _check_plot_works(ts.plot.kde, bw_method=None, ind=np.int_(20)) + _check_plot_works(ts.plot.kde, bw_method=0.5, ind=sample_points) + _check_plot_works(ts.plot.density, bw_method=0.5, ind=sample_points) _, ax = self.plt.subplots() - ax = self.ts.plot.kde(logy=True, bw_method=0.5, ind=sample_points, ax=ax) + ax = ts.plot.kde(logy=True, bw_method=0.5, ind=sample_points, ax=ax) self._check_ax_scales(ax, yaxis="log") self._check_text_labels(ax.yaxis.get_label(), "Density") @@ -483,50 +486,48 @@ 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())) - def test_boxplot_series(self): + def test_boxplot_series(self, ts): _, ax = self.plt.subplots() - ax = self.ts.plot.box(logy=True, ax=ax) + ax = ts.plot.box(logy=True, ax=ax) self._check_ax_scales(ax, yaxis="log") xlabels = ax.get_xticklabels() - self._check_text_labels(xlabels, [self.ts.name]) + self._check_text_labels(xlabels, [ts.name]) ylabels = ax.get_yticklabels() self._check_text_labels(ylabels, [""] * len(ylabels)) - def test_kind_both_ways(self): + @pytest.mark.parametrize( + "kind", + plotting.PlotAccessor._common_kinds + plotting.PlotAccessor._series_kinds, + ) + def test_kind_both_ways(self, kind): s = Series(range(3)) - kinds = ( - plotting.PlotAccessor._common_kinds + plotting.PlotAccessor._series_kinds - ) - for kind in kinds: - _, ax = self.plt.subplots() - s.plot(kind=kind, ax=ax) - self.plt.close() - _, ax = self.plt.subplots() - getattr(s.plot, kind)() - self.plt.close() + _, ax = self.plt.subplots() + s.plot(kind=kind, ax=ax) + self.plt.close() + _, ax = self.plt.subplots() + getattr(s.plot, kind)() + self.plt.close() - def test_invalid_plot_data(self): + @pytest.mark.parametrize("kind", plotting.PlotAccessor._common_kinds) + def test_invalid_plot_data(self, kind): s = Series(list("abcd")) _, ax = self.plt.subplots() - for kind in plotting.PlotAccessor._common_kinds: - - msg = "no numeric data to plot" - with pytest.raises(TypeError, match=msg): - s.plot(kind=kind, ax=ax) + msg = "no numeric data to plot" + with pytest.raises(TypeError, match=msg): + s.plot(kind=kind, ax=ax) - def test_valid_object_plot(self): + @pytest.mark.parametrize("kind", plotting.PlotAccessor._common_kinds) + def test_valid_object_plot(self, kind): s = Series(range(10), dtype=object) - for kind in plotting.PlotAccessor._common_kinds: - _check_plot_works(s.plot, kind=kind) + _check_plot_works(s.plot, kind=kind) - def test_partially_invalid_plot_data(self): + @pytest.mark.parametrize("kind", plotting.PlotAccessor._common_kinds) + def test_partially_invalid_plot_data(self, kind): s = Series(["a", "b", 1.0, 2]) _, ax = self.plt.subplots() - for kind in plotting.PlotAccessor._common_kinds: - - msg = "no numeric data to plot" - with pytest.raises(TypeError, match=msg): - s.plot(kind=kind, ax=ax) + msg = "no numeric data to plot" + with pytest.raises(TypeError, match=msg): + s.plot(kind=kind, ax=ax) def test_invalid_kind(self): s = Series([1, 2]) @@ -602,9 +603,9 @@ def test_errorbar_plot(self): with tm.external_error_raised(TypeError): s.plot(yerr=s_err) - def test_table(self): - _check_plot_works(self.series.plot, table=True) - _check_plot_works(self.series.plot, table=self.series) + def test_table(self, series): + _check_plot_works(series.plot, table=True) + _check_plot_works(series.plot, table=series) def test_series_grid_settings(self): # Make sure plot defaults to rcParams['axes.grid'] setting, GH 9792 @@ -613,21 +614,21 @@ def test_series_grid_settings(self): plotting.PlotAccessor._series_kinds + plotting.PlotAccessor._common_kinds, ) - def test_standard_colors(self): + @pytest.mark.parametrize("c", ["r", "red", "green", "#FF0000"]) + def test_standard_colors(self, c): from pandas.plotting._matplotlib.style import get_standard_colors - for c in ["r", "red", "green", "#FF0000"]: - result = get_standard_colors(1, color=c) - assert result == [c] + result = get_standard_colors(1, color=c) + assert result == [c] - result = get_standard_colors(1, color=[c]) - assert result == [c] + result = get_standard_colors(1, color=[c]) + assert result == [c] - result = get_standard_colors(3, color=c) - assert result == [c] * 3 + result = get_standard_colors(3, color=c) + assert result == [c] * 3 - result = get_standard_colors(3, color=[c]) - assert result == [c] * 3 + result = get_standard_colors(3, color=[c]) + assert result == [c] * 3 def test_standard_colors_all(self): import matplotlib.colors as colors From d1beca81fb9ce4f004f66c7a21ad39829afc06c4 Mon Sep 17 00:00:00 2001 From: Matthew Roeschke Date: Mon, 14 Feb 2022 14:43:20 -0800 Subject: [PATCH 3/3] Fix some tests --- pandas/plotting/_matplotlib/compat.py | 5 +-- pandas/plotting/_matplotlib/core.py | 25 +---------- pandas/plotting/_matplotlib/tools.py | 8 +--- pandas/tests/plotting/conftest.py | 2 +- pandas/tests/plotting/frame/test_frame.py | 54 +++++++++++------------ pandas/tests/plotting/test_hist_method.py | 8 ++-- pandas/tests/plotting/test_series.py | 2 +- 7 files changed, 37 insertions(+), 67 deletions(-) diff --git a/pandas/plotting/_matplotlib/compat.py b/pandas/plotting/_matplotlib/compat.py index 9583010b58062..c731c40f10a05 100644 --- a/pandas/plotting/_matplotlib/compat.py +++ b/pandas/plotting/_matplotlib/compat.py @@ -10,10 +10,7 @@ def inner(): import matplotlib as mpl except ImportError: return False - return ( - op(Version(mpl.__version__), Version(version)) - and str(mpl.__version__)[0] != "0" - ) + return op(Version(mpl.__version__), Version(version)) return inner diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index e7c49d7bffb14..41bd1df81ef61 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -42,7 +42,6 @@ from pandas.core.frame import DataFrame from pandas.io.formats.printing import pprint_thing -from pandas.plotting._matplotlib.compat import mpl_ge_3_0_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.style import get_standard_colors @@ -1032,29 +1031,7 @@ def _plot_colorbar(self, ax: Axes, **kwds): # use the last one which contains the latest information # about the ax img = ax.collections[-1] - cbar = self.fig.colorbar(img, ax=ax, **kwds) - - if mpl_ge_3_0_0(): - # The workaround below is no longer necessary. - return cbar - - points = ax.get_position().get_points() - cbar_points = cbar.ax.get_position().get_points() - - cbar.ax.set_position( - [ - cbar_points[0, 0], - points[0, 1], - cbar_points[1, 0] - cbar_points[0, 0], - points[1, 1] - points[0, 1], - ] - ) - # To see the discrepancy in axis heights uncomment - # the following two lines: - # print(points[1, 1] - points[0, 1]) - # print(cbar_points[1, 1] - cbar_points[0, 1]) - - return cbar + return self.fig.colorbar(img, ax=ax, **kwds) class ScatterPlot(PlanePlot): diff --git a/pandas/plotting/_matplotlib/tools.py b/pandas/plotting/_matplotlib/tools.py index 7bd90a4e4d908..30af4f90d6869 100644 --- a/pandas/plotting/_matplotlib/tools.py +++ b/pandas/plotting/_matplotlib/tools.py @@ -388,12 +388,8 @@ def handle_shared_axes( sharey: bool, ): if nplots > 1: - if compat.mpl_ge_3_2_0(): - row_num = lambda x: x.get_subplotspec().rowspan.start - col_num = lambda x: x.get_subplotspec().colspan.start - else: - row_num = lambda x: x.rowNum - col_num = lambda x: x.colNum + row_num = lambda x: x.get_subplotspec().rowspan.start + col_num = lambda x: x.get_subplotspec().colspan.start if compat.mpl_ge_3_4_0(): is_first_col = lambda x: x.get_subplotspec().is_first_col() diff --git a/pandas/tests/plotting/conftest.py b/pandas/tests/plotting/conftest.py index 75d53e3efdb33..b88d9344da707 100644 --- a/pandas/tests/plotting/conftest.py +++ b/pandas/tests/plotting/conftest.py @@ -8,7 +8,7 @@ import pandas._testing as tm -@pytest.mark.parametrize +@pytest.fixture def hist_df(): n = 100 with tm.RNGContext(42): diff --git a/pandas/tests/plotting/frame/test_frame.py b/pandas/tests/plotting/frame/test_frame.py index 87056612266f0..9861c84b7cc03 100644 --- a/pandas/tests/plotting/frame/test_frame.py +++ b/pandas/tests/plotting/frame/test_frame.py @@ -363,7 +363,8 @@ def _compare_stacked_y_cood(self, normal_lines, stacked_lines): sy = sl.get_data()[1] tm.assert_numpy_array_equal(base, sy) - def test_line_area_stacked(self): + @pytest.mark.parametrize("kind", ["line", "area"]) + def test_line_area_stacked(self, kind): with tm.RNGContext(42): df = DataFrame(np.random.rand(6, 4), columns=["w", "x", "y", "z"]) neg_df = -df @@ -383,33 +384,32 @@ def test_line_area_stacked(self): columns=["w", "x", "y", "z"], ) - for kind in ["line", "area"]: - ax1 = _check_plot_works(df.plot, kind=kind, stacked=False) - ax2 = _check_plot_works(df.plot, kind=kind, stacked=True) - self._compare_stacked_y_cood(ax1.lines, ax2.lines) - - ax1 = _check_plot_works(neg_df.plot, kind=kind, stacked=False) - ax2 = _check_plot_works(neg_df.plot, kind=kind, stacked=True) - self._compare_stacked_y_cood(ax1.lines, ax2.lines) - - ax1 = _check_plot_works(sep_df.plot, kind=kind, stacked=False) - ax2 = _check_plot_works(sep_df.plot, kind=kind, stacked=True) - self._compare_stacked_y_cood(ax1.lines[:2], ax2.lines[:2]) - self._compare_stacked_y_cood(ax1.lines[2:], ax2.lines[2:]) - - _check_plot_works(mixed_df.plot, stacked=False) - msg = ( - "When stacked is True, each column must be either all positive or " - "all negative. Column 'w' contains both positive and negative " - "values" - ) - with pytest.raises(ValueError, match=msg): - mixed_df.plot(stacked=True) + ax1 = _check_plot_works(df.plot, kind=kind, stacked=False) + ax2 = _check_plot_works(df.plot, kind=kind, stacked=True) + self._compare_stacked_y_cood(ax1.lines, ax2.lines) + + ax1 = _check_plot_works(neg_df.plot, kind=kind, stacked=False) + ax2 = _check_plot_works(neg_df.plot, kind=kind, stacked=True) + self._compare_stacked_y_cood(ax1.lines, ax2.lines) + + ax1 = _check_plot_works(sep_df.plot, kind=kind, stacked=False) + ax2 = _check_plot_works(sep_df.plot, kind=kind, stacked=True) + self._compare_stacked_y_cood(ax1.lines[:2], ax2.lines[:2]) + self._compare_stacked_y_cood(ax1.lines[2:], ax2.lines[2:]) + + _check_plot_works(mixed_df.plot, stacked=False) + msg = ( + "When stacked is True, each column must be either all positive or " + "all negative. Column 'w' contains both positive and negative " + "values" + ) + with pytest.raises(ValueError, match=msg): + mixed_df.plot(stacked=True) - # Use an index with strictly positive values, preventing - # matplotlib from warning about ignoring xlim - df2 = df.set_index(df.index + 1) - _check_plot_works(df2.plot, kind=kind, logx=True, stacked=True) + # Use an index with strictly positive values, preventing + # matplotlib from warning about ignoring xlim + df2 = df.set_index(df.index + 1) + _check_plot_works(df2.plot, kind=kind, logx=True, stacked=True) def test_line_area_nan_df(self): values1 = [1, 2, np.nan, 3] diff --git a/pandas/tests/plotting/test_hist_method.py b/pandas/tests/plotting/test_hist_method.py index 785734c7d1061..c2926b4f22372 100644 --- a/pandas/tests/plotting/test_hist_method.py +++ b/pandas/tests/plotting/test_hist_method.py @@ -215,7 +215,7 @@ def test_hist_kde(self, ts): self._check_text_labels(ylabels, [""] * len(ylabels)) @td.skip_if_no_scipy - def test_hist_kde_color(self): + def test_hist_kde_color(self, ts): _, ax = self.plt.subplots() ax = ts.plot.hist(logy=True, bins=10, color="b", ax=ax) self._check_ax_scales(ax, yaxis="log") @@ -347,7 +347,7 @@ def test_hist_layout(self): df[2] = to_datetime( np.random.randint( 812419200000000000, - self.end_date_to_int64, + 819331200000000000, size=100, dtype=np.int64, ) @@ -389,7 +389,7 @@ def test_tight_layout(self): df[2] = to_datetime( np.random.randint( 812419200000000000, - self.end_date_to_int64, + 819331200000000000, size=100, dtype=np.int64, ) @@ -571,7 +571,7 @@ def test_grouped_hist_legacy(self): df["B"] = to_datetime( np.random.randint( 812419200000000000, - self.end_date_to_int64, + 819331200000000000, size=500, dtype=np.int64, ) diff --git a/pandas/tests/plotting/test_series.py b/pandas/tests/plotting/test_series.py index 5af111ba503be..457ccc2ffce51 100644 --- a/pandas/tests/plotting/test_series.py +++ b/pandas/tests/plotting/test_series.py @@ -65,7 +65,7 @@ def test_plot_iseries(self, iseries): _check_plot_works(iseries.plot) @pytest.mark.parametrize("kind", ["line", "bar", "barh", "kde", "hist", "box"]) - def test_plot_series_kinds(self, kind): + def test_plot_series_kinds(self, series, kind): _check_plot_works(series[:5].plot, kind=kind) def test_plot_series_barh(self, series):