Skip to content

Commit 508f843

Browse files
committed
Add configuration of Shadow and pie shadow
1 parent c8aaa90 commit 508f843

File tree

9 files changed

+87
-64
lines changed

9 files changed

+87
-64
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
The pie chart shadow can be controlled
2+
--------------------------------------
3+
4+
The *shadow* argument to `~.Axes.pie` can now be a dict, allowing more control
5+
of the `.Shadow`-patch used.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Shadow shade can be controlled
2+
------------------------------
3+
4+
The `.Shadow` patch now has a *shade* argument to control the shadow darkness.
5+
If 1, the shadow is black, if 0, the shadow has the same color as the patch that
6+
is shadowed. The default value, which earlier was fixed, is 0.7.

galleries/examples/pie_and_polar_charts/pie_demo2.py

-55
This file was deleted.

galleries/examples/pie_and_polar_charts/pie_features.py

+28-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
"""
2+
.. redirect-from:: gallery/pie_and_polar_charts/pie_demo2
3+
24
==========
35
Pie charts
46
==========
@@ -88,7 +90,7 @@
8890

8991
fig, ax = plt.subplots()
9092
ax.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%',
91-
shadow=True, startangle=90)
93+
shadow=True, startangle=90)
9294
plt.show()
9395

9496
# %%
@@ -97,6 +99,31 @@
9799
# slices are rotated counter-clockwise by 90 degrees, and the frog slice starts
98100
# on the positive y-axis.
99101
#
102+
# Controlling the size
103+
# --------------------
104+
#
105+
# By changing the *radius* parameter, and often the text size for better visual
106+
# appearance, the pie chart can be scaled.
107+
108+
fig, ax = plt.subplots()
109+
110+
ax.pie(sizes, labels=labels, autopct='%.0f%%',
111+
textprops={'size': 'smaller'}, radius=0.5)
112+
plt.show()
113+
114+
# %%
115+
# Modifying the shadow
116+
# --------------------
117+
#
118+
# The *shadow* parameter may optionally take a dictionary with arguments to
119+
# the `.Shadow` patch. This can be used to modify the default shadow.
120+
121+
fig, ax = plt.subplots()
122+
ax.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%',
123+
shadow={'ox': -0.04, 'edgecolor': 'none', 'shade': 0.9}, startangle=90)
124+
plt.show()
125+
126+
# %%
100127
# .. admonition:: References
101128
#
102129
# The use of the following functions, methods, classes and modules is shown

lib/matplotlib/axes/_axes.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -3102,8 +3102,12 @@ def pie(self, x, explode=None, labels=None, colors=None,
31023102
If set to ``None``, labels are not drawn but are still stored for
31033103
use in `.legend`.
31043104
3105-
shadow : bool, default: False
3106-
Draw a shadow beneath the pie.
3105+
shadow : bool or dict, default: False
3106+
If bool, whether to draw a shadow beneath the pie. If dict, draw a shadow
3107+
passing the properties in the dict to `.Shadow`.
3108+
3109+
.. versionadded:: 3.8
3110+
*shadow* can be a dict.
31073111
31083112
startangle : float, default: 0 degrees
31093113
The angle by which the start of the pie is rotated,
@@ -3231,8 +3235,10 @@ def get_next_color():
32313235
if shadow:
32323236
# Make sure to add a shadow after the call to add_patch so the
32333237
# figure and transform props will be set.
3234-
shad = mpatches.Shadow(w, -0.02, -0.02, label='_nolegend_')
3235-
self.add_patch(shad)
3238+
shadow_dict = {'ox': -0.02, 'oy': -0.02, 'label': '_nolegend_'}
3239+
if isinstance(shadow, dict):
3240+
shadow_dict.update(shadow)
3241+
self.add_patch(mpatches.Shadow(w, **shadow_dict))
32363242

32373243
if labeldistance is not None:
32383244
xt = x + labeldistance * radius * math.cos(thetam)

lib/matplotlib/patches.py

+11-3
Original file line numberDiff line numberDiff line change
@@ -613,12 +613,12 @@ def __str__(self):
613613
return f"Shadow({self.patch})"
614614

615615
@_docstring.dedent_interpd
616-
def __init__(self, patch, ox, oy, **kwargs):
616+
def __init__(self, patch, ox, oy, *, shade=0.7, **kwargs):
617617
"""
618618
Create a shadow of the given *patch*.
619619
620620
By default, the shadow will have the same face color as the *patch*,
621-
but darkened.
621+
but darkened. The darkness can be controlled by *shade*.
622622
623623
Parameters
624624
----------
@@ -627,6 +627,12 @@ def __init__(self, patch, ox, oy, **kwargs):
627627
ox, oy : float
628628
The shift of the shadow in data coordinates, scaled by a factor
629629
of dpi/72.
630+
shade : float, default: 0.7
631+
How the darkness of the shadow relates to the original color. If 1, the
632+
shadow is black, if 0, the shadow has the same color as the *patch*.
633+
634+
.. versionadded:: 3.8
635+
630636
**kwargs
631637
Properties of the shadow patch. Supported keys are:
632638
@@ -638,7 +644,9 @@ def __init__(self, patch, ox, oy, **kwargs):
638644
self._shadow_transform = transforms.Affine2D()
639645

640646
self.update_from(self.patch)
641-
color = .3 * np.asarray(colors.to_rgb(self.patch.get_facecolor()))
647+
if not 0 <= shade <= 1:
648+
raise ValueError("shade must be between 0 and 1.")
649+
color = (1 - shade) * np.asarray(colors.to_rgb(self.patch.get_facecolor()))
642650
self.update({'facecolor': color, 'edgecolor': color, 'alpha': 0.5,
643651
# Place shadow patch directly behind the inherited patch.
644652
'zorder': np.nextafter(self.patch.zorder, -np.inf),

lib/matplotlib/tests/test_axes.py

+24
Original file line numberDiff line numberDiff line change
@@ -5697,6 +5697,30 @@ def test_pie_nolabel_but_legend():
56975697
plt.legend()
56985698

56995699

5700+
@image_comparison(['pie_shadow.png'], style='mpl20')
5701+
def test_pie_shadow():
5702+
# Also acts as a test for the shade argument of Shadow
5703+
sizes = [15, 30, 45, 10]
5704+
colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral']
5705+
explode = (0, 0.1, 0, 0) # only "explode" the 2nd slice
5706+
_, axes = plt.subplots(2, 2)
5707+
axes[0][0].pie(sizes, explode=explode, colors=colors,
5708+
shadow=True, startangle=90,
5709+
wedgeprops={'linewidth': 0})
5710+
5711+
axes[0][1].pie(sizes, explode=explode, colors=colors,
5712+
shadow=False, startangle=90,
5713+
wedgeprops={'linewidth': 0})
5714+
5715+
axes[1][0].pie(sizes, explode=explode, colors=colors,
5716+
shadow={'ox': -0.05, 'oy': -0.05, 'shade': 0.9, 'edgecolor': 'none'},
5717+
startangle=90, wedgeprops={'linewidth': 0})
5718+
5719+
axes[1][1].pie(sizes, explode=explode, colors=colors,
5720+
shadow={'ox': 0.05, 'linewidth': 2, 'shade': 0.2},
5721+
startangle=90, wedgeprops={'linewidth': 0})
5722+
5723+
57005724
def test_pie_textprops():
57015725
data = [23, 34, 45]
57025726
labels = ["Long name 1", "Long name 2", "Long name 3"]

lib/matplotlib/tests/test_legend.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,10 @@ def test_alpha_rcparam():
196196
leg.legendPatch.set_facecolor([1, 0, 0, 0.5])
197197

198198

199-
@image_comparison(['fancy'], remove_text=True)
199+
@image_comparison(['fancy'], remove_text=True, tol=0.05)
200200
def test_fancy():
201+
# Tolerance caused by changing shadow "shade" from 0.3 to 1 - 0.7 =
202+
# 0.30000000000000004
201203
# using subplot triggers some offsetbox functionality untested elsewhere
202204
plt.subplot(121)
203205
plt.plot([5] * 10, 'o--', label='XX')

0 commit comments

Comments
 (0)