diff --git a/doc/api/next_api_changes/deprecations/28074-TS.rst b/doc/api/next_api_changes/deprecations/28074-TS.rst
new file mode 100644
index 000000000000..6a8b5d4b21b8
--- /dev/null
+++ b/doc/api/next_api_changes/deprecations/28074-TS.rst
@@ -0,0 +1,9 @@
+``boxplot`` and ``bxp`` *vert* parameter, and ``rcParams["boxplot.vertical"]``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The parameter *vert: bool* has been deprecated on `~.Axes.boxplot` and
+`~.Axes.bxp`. It is replaced by *orientation: {"vertical", "horizontal"}*
+for API consistency.
+
+``rcParams["boxplot.vertical"]``, which controlled the orientation of ``boxplot``,
+is deprecated without replacement.
diff --git a/doc/users/next_whats_new/boxplot_orientation.rst b/doc/users/next_whats_new/boxplot_orientation.rst
new file mode 100644
index 000000000000..19193b530a9e
--- /dev/null
+++ b/doc/users/next_whats_new/boxplot_orientation.rst
@@ -0,0 +1,21 @@
+``boxplot`` and ``bxp`` orientation parameter
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Boxplots have a new parameter *orientation: {"vertical", "horizontal"}*
+to change the orientation of the plot. This replaces the deprecated
+*vert: bool* parameter.
+
+
+.. plot::
+ :include-source: true
+ :alt: Example of creating 4 horizontal boxplots.
+
+ import matplotlib.pyplot as plt
+ import numpy as np
+
+ fig, ax = plt.subplots()
+ np.random.seed(19680801)
+ all_data = [np.random.normal(0, std, 100) for std in range(6, 10)]
+
+ ax.boxplot(all_data, orientation='horizontal')
+ plt.show()
diff --git a/galleries/examples/statistics/boxplot_demo.py b/galleries/examples/statistics/boxplot_demo.py
index f7f1078b2d27..46d6c7609807 100644
--- a/galleries/examples/statistics/boxplot_demo.py
+++ b/galleries/examples/statistics/boxplot_demo.py
@@ -46,11 +46,11 @@
axs[1, 0].set_title("don't show\noutlier points")
# horizontal boxes
-axs[1, 1].boxplot(data, sym='rs', vert=False)
+axs[1, 1].boxplot(data, sym='rs', orientation='horizontal')
axs[1, 1].set_title('horizontal boxes')
# change whisker length
-axs[1, 2].boxplot(data, sym='rs', vert=False, whis=0.75)
+axs[1, 2].boxplot(data, sym='rs', orientation='horizontal', whis=0.75)
axs[1, 2].set_title('change whisker length')
fig.subplots_adjust(left=0.08, right=0.98, bottom=0.05, top=0.9,
@@ -107,7 +107,7 @@
fig.canvas.manager.set_window_title('A Boxplot Example')
fig.subplots_adjust(left=0.075, right=0.95, top=0.9, bottom=0.25)
-bp = ax1.boxplot(data, notch=False, sym='+', vert=True, whis=1.5)
+bp = ax1.boxplot(data, notch=False, sym='+', orientation='vertical', whis=1.5)
plt.setp(bp['boxes'], color='black')
plt.setp(bp['whiskers'], color='black')
plt.setp(bp['fliers'], color='red', marker='+')
diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py
index 50540d862b5f..e7b484bc99a9 100644
--- a/lib/matplotlib/axes/_axes.py
+++ b/lib/matplotlib/axes/_axes.py
@@ -3819,9 +3819,10 @@ def apply_mask(arrays, mask):
@_api.make_keyword_only("3.9", "notch")
@_preprocess_data()
@_api.rename_parameter("3.9", "labels", "tick_labels")
- def boxplot(self, x, notch=None, sym=None, vert=None, whis=None,
- positions=None, widths=None, patch_artist=None,
- bootstrap=None, usermedians=None, conf_intervals=None,
+ def boxplot(self, x, notch=None, sym=None, vert=None,
+ orientation='vertical', whis=None, positions=None,
+ widths=None, patch_artist=None, bootstrap=None,
+ usermedians=None, conf_intervals=None,
meanline=None, showmeans=None, showcaps=None,
showbox=None, showfliers=None, boxprops=None,
tick_labels=None, flierprops=None, medianprops=None,
@@ -3877,9 +3878,21 @@ def boxplot(self, x, notch=None, sym=None, vert=None, whis=None,
the fliers. If `None`, then the fliers default to 'b+'. More
control is provided by the *flierprops* parameter.
- vert : bool, default: :rc:`boxplot.vertical`
- If `True`, draws vertical boxes.
- If `False`, draw horizontal boxes.
+ vert : bool, optional
+ .. deprecated:: 3.10
+ Use *orientation* instead.
+
+ If this is given during the deprecation period, it overrides
+ the *orientation* parameter.
+
+ If True, plots the boxes vertically.
+ If False, plots the boxes horizontally.
+
+ orientation : {'vertical', 'horizontal'}, default: 'vertical'
+ If 'horizontal', plots the boxes horizontally.
+ Otherwise, plots the boxes vertically.
+
+ .. versionadded:: 3.10
whis : float or (float, float), default: 1.5
The position of the whiskers.
@@ -4047,8 +4060,6 @@ def boxplot(self, x, notch=None, sym=None, vert=None, whis=None,
labels=tick_labels, autorange=autorange)
if notch is None:
notch = mpl.rcParams['boxplot.notch']
- if vert is None:
- vert = mpl.rcParams['boxplot.vertical']
if patch_artist is None:
patch_artist = mpl.rcParams['boxplot.patchartist']
if meanline is None:
@@ -4148,13 +4159,14 @@ def boxplot(self, x, notch=None, sym=None, vert=None, whis=None,
meanline=meanline, showfliers=showfliers,
capprops=capprops, whiskerprops=whiskerprops,
manage_ticks=manage_ticks, zorder=zorder,
- capwidths=capwidths, label=label)
+ capwidths=capwidths, label=label,
+ orientation=orientation)
return artists
@_api.make_keyword_only("3.9", "widths")
- def bxp(self, bxpstats, positions=None, widths=None, vert=True,
- patch_artist=False, shownotches=False, showmeans=False,
- showcaps=True, showbox=True, showfliers=True,
+ def bxp(self, bxpstats, positions=None, widths=None, vert=None,
+ orientation='vertical', patch_artist=False, shownotches=False,
+ showmeans=False, showcaps=True, showbox=True, showfliers=True,
boxprops=None, whiskerprops=None, flierprops=None,
medianprops=None, capprops=None, meanprops=None,
meanline=False, manage_ticks=True, zorder=None,
@@ -4213,9 +4225,21 @@ def bxp(self, bxpstats, positions=None, widths=None, vert=True,
Either a scalar or a vector and sets the width of each cap.
The default is ``0.5*(width of the box)``, see *widths*.
- vert : bool, default: True
- If `True` (default), makes the boxes vertical.
- If `False`, makes horizontal boxes.
+ vert : bool, optional
+ .. deprecated:: 3.10
+ Use *orientation* instead.
+
+ If this is given during the deprecation period, it overrides
+ the *orientation* parameter.
+
+ If True, plots the boxes vertically.
+ If False, plots the boxes horizontally.
+
+ orientation : {'vertical', 'horizontal'}, default: 'vertical'
+ If 'horizontal', plots the boxes horizontally.
+ Otherwise, plots the boxes vertically.
+
+ .. versionadded:: 3.10
patch_artist : bool, default: False
If `False` produces boxes with the `.Line2D` artist.
@@ -4334,8 +4358,29 @@ def merge_kw_rc(subkey, explicit, zdelta=0, usemarker=True):
if meanprops is None or removed_prop not in meanprops:
mean_kw[removed_prop] = ''
+ # vert and orientation parameters are linked until vert's
+ # deprecation period expires. vert only takes precedence
+ # if set to False.
+ if vert is None:
+ vert = mpl.rcParams['boxplot.vertical']
+ else:
+ _api.warn_deprecated(
+ "3.10",
+ name="vert: bool",
+ alternative="orientation: {'vertical', 'horizontal'}"
+ )
+ if vert is False:
+ orientation = 'horizontal'
+ _api.check_in_list(['horizontal', 'vertical'], orientation=orientation)
+
+ if not mpl.rcParams['boxplot.vertical']:
+ _api.warn_deprecated(
+ "3.10",
+ name='boxplot.vertical', obj_type="rcparam"
+ )
+
# vertical or horizontal plot?
- maybe_swap = slice(None) if vert else slice(None, None, -1)
+ maybe_swap = slice(None) if orientation == 'vertical' else slice(None, None, -1)
def do_plot(xs, ys, **kwargs):
return self.plot(*[xs, ys][maybe_swap], **kwargs)[0]
@@ -4460,7 +4505,7 @@ def do_patch(xs, ys, **kwargs):
artist.set_label(lbl)
if manage_ticks:
- axis_name = "x" if vert else "y"
+ axis_name = "x" if orientation == 'vertical' else "y"
interval = getattr(self.dataLim, f"interval{axis_name}")
axis = self._axis_map[axis_name]
positions = axis.convert_units(positions)
diff --git a/lib/matplotlib/axes/_axes.pyi b/lib/matplotlib/axes/_axes.pyi
index 2f5f6b4f3fde..b728d24d9fe9 100644
--- a/lib/matplotlib/axes/_axes.pyi
+++ b/lib/matplotlib/axes/_axes.pyi
@@ -350,6 +350,7 @@ class Axes(_AxesBase):
notch: bool | None = ...,
sym: str | None = ...,
vert: bool | None = ...,
+ orientation: Literal["vertical", "horizontal"] = ...,
whis: float | tuple[float, float] | None = ...,
positions: ArrayLike | None = ...,
widths: float | ArrayLike | None = ...,
@@ -382,7 +383,8 @@ class Axes(_AxesBase):
positions: ArrayLike | None = ...,
*,
widths: float | ArrayLike | None = ...,
- vert: bool = ...,
+ vert: bool | None = ...,
+ orientation: Literal["vertical", "horizontal"] = ...,
patch_artist: bool = ...,
shownotches: bool = ...,
showmeans: bool = ...,
diff --git a/lib/matplotlib/mpl-data/stylelib/classic.mplstyle b/lib/matplotlib/mpl-data/stylelib/classic.mplstyle
index 976ab291907b..50516d831ae4 100644
--- a/lib/matplotlib/mpl-data/stylelib/classic.mplstyle
+++ b/lib/matplotlib/mpl-data/stylelib/classic.mplstyle
@@ -380,7 +380,6 @@ boxplot.showbox: True
boxplot.showcaps: True
boxplot.showfliers: True
boxplot.showmeans: False
-boxplot.vertical: True
boxplot.whiskerprops.color: b
boxplot.whiskerprops.linestyle: --
boxplot.whiskerprops.linewidth: 1.0
diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py
index 5d9d2f42f6ac..00e623dd649e 100644
--- a/lib/matplotlib/pyplot.py
+++ b/lib/matplotlib/pyplot.py
@@ -2935,6 +2935,7 @@ def boxplot(
notch: bool | None = None,
sym: str | None = None,
vert: bool | None = None,
+ orientation: Literal["vertical", "horizontal"] = "vertical",
whis: float | tuple[float, float] | None = None,
positions: ArrayLike | None = None,
widths: float | ArrayLike | None = None,
@@ -2967,6 +2968,7 @@ def boxplot(
notch=notch,
sym=sym,
vert=vert,
+ orientation=orientation,
whis=whis,
positions=positions,
widths=widths,
diff --git a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_rc_parameters.pdf b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_rc_parameters.pdf
index cc9433bebd31..c424bc5e982f 100644
Binary files a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_rc_parameters.pdf and b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_rc_parameters.pdf differ
diff --git a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_rc_parameters.png b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_rc_parameters.png
index 07b8a5da7247..944f9451285c 100644
Binary files a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_rc_parameters.png and b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_rc_parameters.png differ
diff --git a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_rc_parameters.svg b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_rc_parameters.svg
index 054af5b4f2f3..c3a3cda7a9a0 100644
--- a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_rc_parameters.svg
+++ b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_rc_parameters.svg
@@ -1,538 +1,535 @@
-
-
-
-
+
+
+
diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py
index c48519377290..ef0b7c7db29e 100644
--- a/lib/matplotlib/tests/test_axes.py
+++ b/lib/matplotlib/tests/test_axes.py
@@ -3186,7 +3186,7 @@ def _bxp_test_helper(
logstats = mpl.cbook.boxplot_stats(
np.random.lognormal(mean=1.25, sigma=1., size=(37, 4)), **stats_kwargs)
fig, ax = plt.subplots()
- if bxp_kwargs.get('vert', True):
+ if bxp_kwargs.get('orientation', 'vertical') == 'vertical':
ax.set_yscale('log')
else:
ax.set_xscale('log')
@@ -3237,7 +3237,7 @@ def transform(stats):
style='default',
tol=0.1)
def test_bxp_horizontal():
- _bxp_test_helper(bxp_kwargs=dict(vert=False))
+ _bxp_test_helper(bxp_kwargs=dict(orientation='horizontal'))
@image_comparison(['bxp_with_ylabels.png'],
@@ -3250,7 +3250,8 @@ def transform(stats):
s['label'] = label
return stats
- _bxp_test_helper(transform_stats=transform, bxp_kwargs=dict(vert=False))
+ _bxp_test_helper(transform_stats=transform,
+ bxp_kwargs=dict(orientation='horizontal'))
@image_comparison(['bxp_patchartist.png'],
@@ -3579,7 +3580,6 @@ def test_boxplot_rc_parameters():
}
rc_axis1 = {
- 'boxplot.vertical': False,
'boxplot.whiskers': [0, 100],
'boxplot.patchartist': True,
}
@@ -9102,3 +9102,42 @@ def test_violinplot_orientation(fig_test, fig_ref):
ax_test = fig_test.subplots()
ax_test.violinplot(all_data, orientation='horizontal')
+
+
+@check_figures_equal(extensions=['png'])
+def test_boxplot_orientation(fig_test, fig_ref):
+ # Test the `orientation : {'vertical', 'horizontal'}`
+ # parameter and deprecation of `vert: bool`.
+ fig, axs = plt.subplots(nrows=1, ncols=2)
+ np.random.seed(19680801)
+ all_data = [np.random.normal(0, std, 100) for std in range(6, 10)]
+
+ axs[0].boxplot(all_data) # Default vertical plot.
+ # xticks and yticks should be at their default position.
+ assert all(axs[0].get_xticks() == np.array(
+ [1, 2, 3, 4]))
+ assert all(axs[0].get_yticks() == np.array(
+ [-30., -20., -10., 0., 10., 20., 30.]))
+
+ # Horizontal plot using new `orientation` keyword.
+ axs[1].boxplot(all_data, orientation='horizontal')
+ # xticks and yticks should be swapped.
+ assert all(axs[1].get_xticks() == np.array(
+ [-30., -20., -10., 0., 10., 20., 30.]))
+ assert all(axs[1].get_yticks() == np.array(
+ [1, 2, 3, 4]))
+
+ plt.close()
+
+ # Deprecation of `vert: bool` keyword and
+ # 'boxplot.vertical' rcparam.
+ with pytest.warns(mpl.MatplotlibDeprecationWarning,
+ match='was deprecated in Matplotlib 3.10'):
+ # Compare images between a figure that
+ # uses vert and one that uses orientation.
+ with mpl.rc_context({'boxplot.vertical': False}):
+ ax_ref = fig_ref.subplots()
+ ax_ref.boxplot(all_data)
+
+ ax_test = fig_test.subplots()
+ ax_test.boxplot(all_data, orientation='horizontal')
diff --git a/lib/matplotlib/tests/test_datetime.py b/lib/matplotlib/tests/test_datetime.py
index 4b693eb7d1ca..276056d044ae 100644
--- a/lib/matplotlib/tests/test_datetime.py
+++ b/lib/matplotlib/tests/test_datetime.py
@@ -255,7 +255,7 @@ def test_bxp(self):
datetime.datetime(2020, 1, 27)
]
}]
- ax.bxp(data, vert=False)
+ ax.bxp(data, orientation='horizontal')
ax.xaxis.set_major_formatter(mpl.dates.DateFormatter("%Y-%m-%d"))
ax.set_title('Box plot with datetime data')