diff --git a/pandas/plotting/_matplotlib/boxplot.py b/pandas/plotting/_matplotlib/boxplot.py index 32b1fbe73a310..b768a4f623203 100644 --- a/pandas/plotting/_matplotlib/boxplot.py +++ b/pandas/plotting/_matplotlib/boxplot.py @@ -212,9 +212,10 @@ def _make_plot(self, fig: Figure) -> None: # When `by` is assigned, the ticklabels will become unique grouped # values, instead of label which is used as subtitle in this case. - # error: "Index" has no attribute "levels"; maybe "nlevels"? - levels = self.data.columns.levels # type: ignore[attr-defined] - ticklabels = [pprint_thing(col) for col in levels[0]] + ticklabels = [ + pprint_thing(col) + for col in self.data.columns.get_level_values(0) + ] else: ticklabels = [pprint_thing(label)] diff --git a/pandas/tests/plotting/test_boxplot_method.py b/pandas/tests/plotting/test_boxplot_method.py index 2267b6197cd80..85c509ac1f965 100644 --- a/pandas/tests/plotting/test_boxplot_method.py +++ b/pandas/tests/plotting/test_boxplot_method.py @@ -9,6 +9,7 @@ import pytest from pandas import ( + Categorical, DataFrame, MultiIndex, Series, @@ -408,6 +409,19 @@ def test_boxplot_group_no_xlabel_ylabel(self, vert, request): ) assert target_label == pprint_thing(["group"]) + @pytest.mark.filterwarnings("ignore:set_ticklabels:UserWarning") + def test_boxplot_group_ordered_ticklabel(self, vert): + df = DataFrame( + { + "value": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + "label": ["c", "c", "c", "c", "b", "b", "b", "b", "a", "a"], + } + ) + df.label = Categorical(df.label, categories=["c", "b", "a"], ordered=True) + ax = df.boxplot(by="label") + xticklabels = ax.get_xticklabels() + assert [x.get_text() for x in xticklabels] == ["c", "b", "a"] + class TestDataFrameGroupByPlots: def test_boxplot_legacy1(self, hist_df):