diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst index f77a55b95d567..62c90e32fad2d 100644 --- a/doc/source/whatsnew/v1.2.0.rst +++ b/doc/source/whatsnew/v1.2.0.rst @@ -437,6 +437,7 @@ Plotting - Bug in :meth:`DataFrame.plot` was rotating xticklabels when ``subplots=True``, even if the x-axis wasn't an irregular time series (:issue:`29460`) - Bug in :meth:`DataFrame.plot` where a marker letter in the ``style`` keyword sometimes causes a ``ValueError`` (:issue:`21003`) - Twinned axes were losing their tick labels which should only happen to all but the last row or column of 'externally' shared axes (:issue:`33819`) +- Bug in :meth:`DataFrame.boxplot` was raising ``ValueError`` when plotting with ``vert=False`` on a subplot with shared axes (:issue:`36918`) Groupby/resample/rolling ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/pandas/plotting/_matplotlib/boxplot.py b/pandas/plotting/_matplotlib/boxplot.py index 8ceba22b1f7a4..906413bd6c764 100644 --- a/pandas/plotting/_matplotlib/boxplot.py +++ b/pandas/plotting/_matplotlib/boxplot.py @@ -246,6 +246,7 @@ def boxplot( ): import matplotlib.pyplot as plt + from matplotlib.ticker import FixedFormatter, FixedLocator # validate return_type: if return_type not in BoxPlot._valid_return_types: @@ -302,15 +303,15 @@ def plot_group(keys, values, ax: "Axes"): bp = ax.boxplot(values, **kwds) if fontsize is not None: ax.tick_params(axis="both", labelsize=fontsize) + if kwds.get("vert", 1): - ticks = ax.get_xticks() - if len(ticks) != len(keys): - i, remainder = divmod(len(ticks), len(keys)) - assert remainder == 0, remainder - keys *= i - ax.set_xticklabels(keys, rotation=rot) + axis = ax.xaxis else: - ax.set_yticklabels(keys, rotation=rot) + axis = ax.yaxis + positions = kwds.get("positions", list(range(1, 1 + len(values)))) + axis.set_major_locator(FixedLocator(positions)) + axis.set_major_formatter(FixedFormatter(keys)) + ax.tick_params(axis=axis.axis_name, which="major", rotation=rot) maybe_color_bp(bp, **kwds) # Return axes in multiplot case, maybe revisit later # 985 diff --git a/pandas/tests/plotting/test_boxplot_method.py b/pandas/tests/plotting/test_boxplot_method.py index 0a096acc9fa6d..85f52675769a1 100644 --- a/pandas/tests/plotting/test_boxplot_method.py +++ b/pandas/tests/plotting/test_boxplot_method.py @@ -218,6 +218,28 @@ def test_specified_props_kwd(self, props, expected): assert result[expected][0].get_color() == "C1" + @pytest.mark.parametrize("vert", [(True), (False)]) + def test_boxplot_multiple_times_same_axis(self, vert): + # GH 37107 + df = DataFrame(np.random.random((100, 5)), columns=["A", "B", "C", "D", "E"]) + + fig, ax = self.plt.subplots(nrows=1, ncols=1) + df.boxplot(ax=ax, vert=vert, fontsize=10, rot=10) + df.boxplot(ax=ax, vert=vert, fontsize=10, rot=10) + + # In order for the ticklabels to be placed, the plot has to be drawn + fig.canvas.draw() + + if vert: + self._check_ticks_props(ax, xlabelsize=10, xrot=10) + else: + self._check_ticks_props(ax, ylabelsize=10, yrot=10) + + axis = ax.xaxis if vert else ax.yaxis + self._check_text_labels( + axis.get_ticklabels(which="major"), ["A", "B", "C", "D", "E"] + ) + @td.skip_if_no_mpl class TestDataFrameGroupByPlots(TestPlotBase):