From 36298f1a518d587729fb0cd95ec7a8b6f7495615 Mon Sep 17 00:00:00 2001 From: Brock Date: Thu, 9 Nov 2023 18:05:17 -0800 Subject: [PATCH 1/2] REF: avoid altering self.data in get_xticks --- pandas/plotting/_matplotlib/core.py | 28 +++++++++-------------- pandas/tests/plotting/frame/test_frame.py | 18 +++++++++++---- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index d59220a1f97f8..d455612487b11 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -45,15 +45,13 @@ ) from pandas.core.dtypes.generic import ( ABCDataFrame, + ABCDatetimeIndex, ABCIndex, ABCMultiIndex, ABCPeriodIndex, ABCSeries, ) -from pandas.core.dtypes.missing import ( - isna, - notna, -) +from pandas.core.dtypes.missing import isna import pandas.core.common as com from pandas.core.frame import DataFrame @@ -94,10 +92,7 @@ npt, ) - from pandas import ( - PeriodIndex, - Series, - ) + from pandas import Series def _color_in_style(style: str) -> bool: @@ -887,26 +882,25 @@ def plt(self): _need_to_set_index = False @final - def _get_xticks(self, convert_period: bool = False): + def _get_xticks(self): index = self.data.index is_datetype = index.inferred_type in ("datetime", "date", "datetime64", "time") x: list[int] | np.ndarray if self.use_index: - if convert_period and isinstance(index, ABCPeriodIndex): - self.data = self.data.reindex(index=index.sort_values()) - index = cast("PeriodIndex", self.data.index) + if isinstance(index, ABCPeriodIndex): + # test_mixed_freq_irreg_period x = index.to_timestamp()._mpl_repr() + # TODO: why do we need to do to_timestamp() here but not other + # places where we call mpl_repr? elif is_any_real_numeric_dtype(index.dtype): # Matplotlib supports numeric values or datetime objects as # xaxis values. Taking LBYL approach here, by the time # matplotlib raises exception when using non numeric/datetime # values for xaxis, several actions are already taken by plt. x = index._mpl_repr() - elif is_datetype: - self.data = self.data[notna(self.data.index)] - self.data = self.data.sort_index() - x = self.data.index._mpl_repr() + elif isinstance(index, ABCDatetimeIndex) or is_datetype: + x = index._mpl_repr() else: self._need_to_set_index = True x = list(range(len(index))) @@ -1434,7 +1428,7 @@ def _make_plot(self, fig: Figure) -> None: plotf = self._ts_plot it = data.items() else: - x = self._get_xticks(convert_period=True) + x = self._get_xticks() # error: Incompatible types in assignment (expression has type # "Callable[[Any, Any, Any, Any, Any, Any, KwArg(Any)], Any]", variable has # type "Callable[[Any, Any, Any, Any, KwArg(Any)], Any]") diff --git a/pandas/tests/plotting/frame/test_frame.py b/pandas/tests/plotting/frame/test_frame.py index 2ef1f065f603d..07846361e3bdd 100644 --- a/pandas/tests/plotting/frame/test_frame.py +++ b/pandas/tests/plotting/frame/test_frame.py @@ -1362,16 +1362,26 @@ def test_specified_props_kwd_plot_box(self, props, expected): assert result[expected][0].get_color() == "C1" def test_unordered_ts(self): + index = [date(2012, 10, 1), date(2012, 9, 1), date(2012, 8, 1)] + values = [3.0, 2.0, 1.0] df = DataFrame( - np.array([3.0, 2.0, 1.0]), - index=[date(2012, 10, 1), date(2012, 9, 1), date(2012, 8, 1)], + np.array(values), + index=index, columns=["test"], ) ax = df.plot() xticks = ax.lines[0].get_xdata() - assert xticks[0] < xticks[1] + tm.assert_numpy_array_equal(xticks, np.array(index, dtype=object)) ydata = ax.lines[0].get_ydata() - tm.assert_numpy_array_equal(ydata, np.array([1.0, 2.0, 3.0])) + tm.assert_numpy_array_equal(ydata, np.array(values)) + + # even though we don't sort the data before passing it to matplotlib, + # the ticks are sorted + xticks = ax.xaxis.get_ticklabels() + xlocs = [x.get_position()[0] for x in xticks] + assert pd.Index(xlocs).is_monotonic_increasing + xlabels = [x.get_text() for x in xticks] + assert pd.to_datetime(xlabels, format="%Y-%m-%d").is_monotonic_increasing @pytest.mark.parametrize("kind", plotting.PlotAccessor._common_kinds) def test_kind_both_ways(self, kind): From fdf145eae0b702856333711c871ff908c5f985f6 Mon Sep 17 00:00:00 2001 From: Brock Date: Thu, 9 Nov 2023 18:07:45 -0800 Subject: [PATCH 2/2] GH ref --- pandas/tests/plotting/frame/test_frame.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/tests/plotting/frame/test_frame.py b/pandas/tests/plotting/frame/test_frame.py index 07846361e3bdd..f002d7a6e66ab 100644 --- a/pandas/tests/plotting/frame/test_frame.py +++ b/pandas/tests/plotting/frame/test_frame.py @@ -1362,6 +1362,7 @@ def test_specified_props_kwd_plot_box(self, props, expected): assert result[expected][0].get_color() == "C1" def test_unordered_ts(self): + # GH#2609, GH#55906 index = [date(2012, 10, 1), date(2012, 9, 1), date(2012, 8, 1)] values = [3.0, 2.0, 1.0] df = DataFrame(