Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions doc/api/next_api_changes/deprecations/29152_REC.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
``pie`` *labels* and *labeldistance* parameters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Currently the *labels* parameter of `~.Axes.pie` is used both for annotating the
pie wedges directly, and for automatic legend entries. For consistency
with other plotting methods, in future *labels* will only be used for the legend.

The *labeldistance* parameter will therefore default to ``None`` from Matplotlib
3.14, when it will also be deprecated and then removed in Matplotlib 3.16. To
preserve the existing behavior for now, set ``labeldistance=1.1``. For the longer
term, use the new *wedge_labels* parameter of `~.Axes.pie` or the `~.Axes.pie_label`
method instead of *labels*.
26 changes: 26 additions & 0 deletions doc/release/next_whats_new/pie_wedge_labels.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
New *wedge_labels* parameter for pie
------------------------------------

`~.Axes.pie` now accepts a *wedge_labels* parameter as a shortcut to the
`~.Axes.pie_label` method. This may be used for simple annotation of the wedges
of the pie chart. It can take

* a list of strings, similar to the existing *labels* parameter
* a format string similar to the existing *autopct* parameter except that it
uses the `str.format` method, and it can handle absolute values as well as
fractions/percentages

*wedge_labels* has an accompanying *wedge_label_distance* parameter, to control
the distance of the labels from the center of the pie.


.. plot::
:include-source: true
:alt: Two pie charts. The chart on the left has labels 'foo' and 'bar' outside the wedges. The chart on the right has labels '1' and '2' inside the wedges.

import matplotlib.pyplot as plt

fig, (ax1, ax2) = plt.subplots(ncols=2, layout='constrained')

ax1.pie([1, 2], wedge_labels=['foo', 'bar'], wedge_label_distance=1.1)
ax2.pie([1, 2], wedge_labels='{absval:d}', wedge_label_distance=0.6)
6 changes: 3 additions & 3 deletions galleries/examples/misc/svg_filter_pie.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@

# We want to draw the shadow for each pie, but we will not use "shadow"
# option as it doesn't save the references to the shadow patches.
pie = ax.pie(fracs, explode=explode, labels=labels, autopct='%1.1f%%')
pie = ax.pie(fracs, explode=explode, wedge_labels=labels, wedge_label_distance=1.1)

for w in pie.wedges:
for w, label in zip(pie.wedges, labels):
# set the id with the label.
w.set_gid(w.get_label())
w.set_gid(label)

# we don't want to draw the edge of the pie
w.set_edgecolor("none")
Expand Down
7 changes: 5 additions & 2 deletions galleries/examples/pie_and_polar_charts/bar_of_pie.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@
explode = [0.1, 0, 0]
# rotate so that first wedge is split by the x-axis
angle = -180 * overall_ratios[0]
pie = ax1.pie(overall_ratios, autopct='%1.1f%%', startangle=angle,
labels=labels, explode=explode)
pie = ax1.pie(overall_ratios, startangle=angle, explode=explode)

# label the wedges with our label strings and the ratios as percentages
ax1.pie_label(pie, labels, distance=1.1)
ax1.pie_label(pie, '{frac:.1%}', distance=0.6)

# bar chart parameters
age_ratios = [.33, .54, .07, .06]
Expand Down
70 changes: 41 additions & 29 deletions galleries/examples/pie_and_polar_charts/pie_features.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,41 +15,68 @@
# ------------
#
# Plot a pie chart of animals and label the slices. To add
# labels, pass a list of labels to the *labels* parameter
# labels, pass a list of labels to the *wedge_labels* parameter.

import matplotlib.pyplot as plt

labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
sizes = [15, 30, 45, 10]
sizes = [12, 24, 36, 8]

fig, ax = plt.subplots()
ax.pie(sizes, labels=labels)
ax.pie(sizes, wedge_labels=labels)

# %%
# Each slice of the pie chart is a `.patches.Wedge` object; therefore in
# addition to the customizations shown here, each wedge can be customized using
# the *wedgeprops* argument, as demonstrated in
# :doc:`/gallery/pie_and_polar_charts/nested_pie`.
#
# Controlling label positions
# ---------------------------
# If you want the labels outside the pie, set a *wedge_label_distance* greater than 1.
# This is the distance from the center of the pie as a fraction of its radius.

fig, ax = plt.subplots()
ax.pie(sizes, wedge_labels=labels, wedge_label_distance=1.1)

# %%
#
# Auto-label slices
# -----------------
#
# Pass a function or format string to *autopct* to label slices.
# Pass a format string to *wedge_labels* to label slices with their values...

fig, ax = plt.subplots()
ax.pie(sizes, wedge_labels='{absval:.1f}')

# %%
#
# ...or with their percentages...

fig, ax = plt.subplots()
ax.pie(sizes, wedge_labels='{frac:.1%}')

# %%
#
# ...or both.

fig, ax = plt.subplots()
ax.pie(sizes, labels=labels, autopct='%1.1f%%')
ax.pie(sizes, wedge_labels='{absval:d}\n{frac:.1%}')

# %%
#
# For more control over labels, or to add multiple sets, see
# :doc:`/gallery/pie_and_polar_charts/pie_label`.

# %%
# By default, the label values are obtained from the percent size of the slice.
#
# Color slices
# ------------
#
# Pass a list of colors to *colors* to set the color of each slice.

fig, ax = plt.subplots()
ax.pie(sizes, labels=labels,
colors=['olivedrab', 'rosybrown', 'gray', 'saddlebrown'])
ax.pie(sizes, colors=['olivedrab', 'rosybrown', 'gray', 'saddlebrown'])

# %%
# Hatch slices
Expand All @@ -58,22 +85,9 @@
# Pass a list of hatch patterns to *hatch* to set the pattern of each slice.

fig, ax = plt.subplots()
ax.pie(sizes, labels=labels, hatch=['**O', 'oO', 'O.O', '.||.'])

# %%
# Swap label and autopct text positions
# -------------------------------------
# Use the *labeldistance* and *pctdistance* parameters to position the *labels*
# and *autopct* text respectively.

fig, ax = plt.subplots()
ax.pie(sizes, labels=labels, autopct='%1.1f%%',
pctdistance=1.25, labeldistance=.6)
ax.pie(sizes, hatch=['**O', 'oO', 'O.O', '.||.'])

# %%
# *labeldistance* and *pctdistance* are ratios of the radius; therefore they
# vary between ``0`` for the center of the pie and ``1`` for the edge of the
# pie, and can be set to greater than ``1`` to place text outside the pie.
#
# Explode, shade, and rotate slices
# ---------------------------------
Expand All @@ -86,11 +100,10 @@
#
# This example orders the slices, separates (explodes) them, and rotates them.

explode = (0, 0.1, 0, 0) # only "explode" the 2nd slice (i.e. 'Hogs')
explode = (0, 0.2, 0, 0) # only "explode" the 2nd slice (i.e. 'Hogs')

fig, ax = plt.subplots()
ax.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%',
shadow=True, startangle=90)
ax.pie(sizes, explode=explode, wedge_labels='{frac:.1%}', shadow=True, startangle=90)
plt.show()

# %%
Expand All @@ -107,8 +120,7 @@

fig, ax = plt.subplots()

ax.pie(sizes, labels=labels, autopct='%.0f%%',
textprops={'size': 'small'}, radius=0.5)
ax.pie(sizes, wedge_labels='{frac:.1%}', textprops={'size': 'small'}, radius=0.5)
plt.show()

# %%
Expand All @@ -119,8 +131,8 @@
# the `.Shadow` patch. This can be used to modify the default shadow.

fig, ax = plt.subplots()
ax.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%',
shadow={'ox': -0.04, 'edgecolor': 'none', 'shade': 0.9}, startangle=90)
ax.pie(sizes, explode=explode, shadow={'ox': -0.04, 'edgecolor': 'none', 'shade': 0.9},
startangle=90)
plt.show()

# %%
Expand Down
79 changes: 69 additions & 10 deletions lib/matplotlib/axes/_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3514,13 +3514,13 @@ def stem(self, *args, linefmt=None, markerfmt=None, basefmt=None, bottom=0,
self.add_container(stem_container)
return stem_container

@_api.make_keyword_only("3.10", "explode")
@_preprocess_data(replace_names=["x", "explode", "labels", "colors"])
def pie(self, x, explode=None, labels=None, colors=None,
autopct=None, pctdistance=0.6, shadow=False, labeldistance=1.1,
startangle=0, radius=1, counterclock=True,
wedgeprops=None, textprops=None, center=(0, 0),
frame=False, rotatelabels=False, *, normalize=True, hatch=None):
@_preprocess_data(replace_names=["x", "explode", "labels", "colors",
"wedge_labels"])
def pie(self, x, *, explode=None, labels=None, colors=None, wedge_labels=None,
wedge_label_distance=0.6, autopct=None, pctdistance=0.6, shadow=False,
labeldistance=False, startangle=0, radius=1, counterclock=True,
wedgeprops=None, textprops=None, center=(0, 0), frame=False,
rotatelabels=False, normalize=True, hatch=None):
"""
Plot a pie chart.

Expand All @@ -3540,7 +3540,13 @@ def pie(self, x, explode=None, labels=None, colors=None,
of the radius with which to offset each wedge.

labels : list, default: None
A sequence of strings providing the labels for each wedge
A sequence of strings providing the legend labels for each wedge.

.. deprecated:: 3.12
In future these labels will not appear on the wedges but only
be made available for the legend (see *labeldistance* below).
To place labels on the wedges, use *wedge_labels* or the
`pie_label` method.

colors : :mpltype:`color` or list of :mpltype:`color`, default: None
A sequence of colors through which the pie chart will cycle. If
Expand All @@ -3553,12 +3559,35 @@ def pie(self, x, explode=None, labels=None, colors=None,

.. versionadded:: 3.7

wedge_labels : str or list of str, optional
A sequence of strings providing the labels for each wedge, or a format
string with ``absval`` and/or ``frac`` placeholders. For example, to label
each wedge with its value and the percentage in brackets::

wedge_labels="{absval:d} ({frac:.0%})"

For more control or to add multiple sets of labels, use `pie_label`
instead.

.. versionadded:: 3.12

wedge_label_distance : float, default: 0.6
The radial position of the wedge labels, relative to the pie radius.
Values > 1 are outside the wedge and values < 1 are inside the wedge.

.. versionadded:: 3.12

autopct : None or str or callable, default: None
If not *None*, *autopct* is a string or function used to label the
wedges with their numeric value. The label will be placed inside
the wedge. If *autopct* is a format string, the label will be
``fmt % pct``. If *autopct* is a function, then it will be called.

.. admonition:: Discouraged

Consider using the *wedge_labels* parameter or `pie_label`
method instead.

pctdistance : float, default: 0.6
The relative distance along the radius at which the text
generated by *autopct* is drawn. To draw the text outside the pie,
Expand All @@ -3571,6 +3600,11 @@ def pie(self, x, explode=None, labels=None, colors=None,
If set to ``None``, labels are not drawn but are still stored for
use in `.legend`.

.. deprecated:: 3.12
From v3.14 *labeldistance* will default to ``None`` and will
later be removed altogether. Use *wedge_labels* and
*wedge_label_distance* or the `pie_label` method instead.

shadow : bool or dict, default: False
If bool, whether to draw a shadow beneath the pie. If dict, draw a shadow
passing the properties in the dict to `.Shadow`.
Expand Down Expand Up @@ -3654,6 +3688,26 @@ def pie(self, x, explode=None, labels=None, colors=None,
fracs = x
if labels is None:
labels = [''] * len(x)
else:
if wedge_labels is not None and labeldistance is not None:
raise ValueError(
'wedge_labels is a replacement for labels when annotating the '
'wedges, so the two should not be used together. To add multiple'
'sets of labels, use the pie_label method.'
)
if labeldistance is False:
# NB: when the labeldistance default changes, both labeldistance and
# rotatelabels should be deprecated for removal.
msg = (
"From %(removal)s labeldistance will default to None, so that the "
"strings provided in the labels parameter are only available for "
"the legend. Later labeldistance will be removed completely. To "
"preserve existing behavior for now, pass labeldistance=1.1. "
"Consider using the wedge_labels parameter or the pie_label method "
"instead of the labels parameter."
)
_api.warn_deprecated("3.12", message=msg)
labeldistance = 1.1
if explode is None:
explode = [0] * len(x)
if len(x) != len(labels):
Expand Down Expand Up @@ -3711,11 +3765,16 @@ def get_next_color():

pc = PieContainer(slices, x, normalize)

if labeldistance is None:
if wedge_labels is not None:
self.pie_label(pc, wedge_labels, distance=wedge_label_distance,
textprops=textprops)

elif labeldistance is None:
# Insert an empty list of texts for backwards compatibility of the
# return value.
pc.add_texts([])
else:

if labeldistance is not None:
Comment on lines +3768 to +3777
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to prohibit wedge_labels is not None and labels is not None and labeldistance is not None. This would add two sets of labels. Currently, and after deprecation, we'll only add one set of labels.

Since wedge_labels is new, anybody who sets that could also adapt to labeldistance=None; and if needed use pie_label to add the second set of labels.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, good point.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

# Add labels to the wedges.
labels_textprops = {
'fontsize': mpl.rcParams['xtick.labelsize'],
Expand Down
2 changes: 2 additions & 0 deletions lib/matplotlib/axes/_axes.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,8 @@ class Axes(_AxesBase):
explode: ArrayLike | None = ...,
labels: Sequence[str] | None = ...,
colors: ColorType | Sequence[ColorType] | None = ...,
wedge_labels: str | Sequence | None = ...,
wedge_label_distance: float | Sequence = ...,
autopct: str | Callable[[float], str] | None = ...,
pctdistance: float = ...,
shadow: bool = ...,
Expand Down
8 changes: 6 additions & 2 deletions lib/matplotlib/pyplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -3939,13 +3939,16 @@ def phase_spectrum(
@_copy_docstring_and_deprecators(Axes.pie)
def pie(
x: ArrayLike,
*,
explode: ArrayLike | None = None,
labels: Sequence[str] | None = None,
colors: ColorType | Sequence[ColorType] | None = None,
wedge_labels: str | Sequence | None = None,
wedge_label_distance: float | Sequence = 0.6,
autopct: str | Callable[[float], str] | None = None,
pctdistance: float = 0.6,
shadow: bool = False,
labeldistance: float | None = 1.1,
labeldistance: float | None = False,
startangle: float = 0,
radius: float = 1,
counterclock: bool = True,
Expand All @@ -3954,7 +3957,6 @@ def pie(
center: tuple[float, float] = (0, 0),
frame: bool = False,
rotatelabels: bool = False,
*,
normalize: bool = True,
hatch: str | Sequence[str] | None = None,
data=None,
Expand All @@ -3964,6 +3966,8 @@ def pie(
explode=explode,
labels=labels,
colors=colors,
wedge_labels=wedge_labels,
wedge_label_distance=wedge_label_distance,
autopct=autopct,
pctdistance=pctdistance,
shadow=shadow,
Expand Down
Loading
Loading