Skip to content

Commit f70a4a2

Browse files
committed
FIX: Keep legacy alpha behavior for violinplot without facecolor
Closes matplotlib#30613.
1 parent e7e5865 commit f70a4a2

File tree

2 files changed

+45
-4
lines changed

2 files changed

+45
-4
lines changed

lib/matplotlib/axes/_axes.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8967,6 +8967,14 @@ def violin(self, vpstats, positions=None, vert=None,
89678967
89688968
.. versionadded:: 3.11
89698969
8970+
For backward compatibility, if *facecolor* is not given, the body
8971+
will get an Artist-level transparency `alpha <.Artist.set_alpha>`
8972+
of 0.3, which will persist if you afterwards change the facecolor,
8973+
e.g. via ``result['bodies'][0].set_facecolor('red')``.
8974+
If *facecolor* is given, there is no Artist-level transparency.
8975+
To set transparency for *facecolor* or *edgecolor* use
8976+
``(color, alpha)`` tuples.
8977+
89708978
linecolor : :mpltype:`color` or list of :mpltype:`color`, optional
89718979
If provided, will set the line color(s) of the violins (the
89728980
horizontal and vertical spines and body edges).
@@ -9074,13 +9082,14 @@ def cycle_color(color, alpha=None):
90749082

90759083
if facecolor is not None:
90769084
facecolor = cycle_color(facecolor)
9085+
body_artist_alpha = None
90779086
else:
9078-
default_facealpha = 0.3
9087+
body_artist_alpha = 0.3
90799088
# Use default colors if user doesn't provide them
90809089
if mpl.rcParams['_internal.classic_mode']:
9081-
facecolor = cycle_color('y', alpha=default_facealpha)
9090+
facecolor = cycle_color('y')
90829091
else:
9083-
facecolor = cycle_color(next_color, alpha=default_facealpha)
9092+
facecolor = cycle_color(next_color)
90849093

90859094
if mpl.rcParams['_internal.classic_mode']:
90869095
# Classic mode uses patch.force_edgecolor=True, so we need to
@@ -9129,7 +9138,8 @@ def cycle_color(color, alpha=None):
91299138
bodies += [fill(stats['coords'],
91309139
-vals + pos if side in ['both', 'low'] else pos,
91319140
vals + pos if side in ['both', 'high'] else pos,
9132-
facecolor=facecolor, edgecolor=body_edgecolor)]
9141+
facecolor=facecolor, edgecolor=body_edgecolor,
9142+
alpha=body_artist_alpha)]
91339143
means.append(stats['mean'])
91349144
mins.append(stats['min'])
91359145
maxes.append(stats['max'])

lib/matplotlib/tests/test_axes.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4171,6 +4171,10 @@ def color_violins(parts, facecolor=None, linecolor=None):
41714171
if facecolor is not None:
41724172
for pc in parts['bodies']:
41734173
pc.set_facecolor(facecolor)
4174+
# disable alpha Artist property to counter the legacy behavior
4175+
# that applies an alpha of 0.3 to the bodies if no facecolor
4176+
# was set
4177+
pc.set_alpha(None)
41744178
if linecolor is not None:
41754179
for partname in ('cbars', 'cmins', 'cmaxes', 'cmeans', 'cmedians'):
41764180
if partname in parts:
@@ -4228,6 +4232,33 @@ def assert_colors_equal(colors1, colors2):
42284232
assert_colors_equal(colors_test, mcolors.to_rgba_array(linecolors))
42294233

42304234

4235+
def test_violinplot_alpha():
4236+
matplotlib.style.use('default')
4237+
data = [(np.random.normal(0, 1, 100))]
4238+
4239+
fig, ax = plt.subplots()
4240+
parts = ax.violinplot(data, positions=[1])
4241+
4242+
# Case 1: If facecolor is unspecified, it's the first color from the color cycle
4243+
# with Artist-level alpha=0.3
4244+
facecolor = ('y' if mpl.rcParams['_internal.classic_mode']
4245+
else plt.rcParams['axes.prop_cycle'].by_key()['color'][0])
4246+
assert mcolors.same_color(parts['bodies'][0].get_facecolor(), (facecolor, 0.3))
4247+
assert parts['bodies'][0].get_alpha() == 0.3
4248+
# setting a new facecolor maintains the alpha
4249+
parts['bodies'][0].set_facecolor('red')
4250+
assert mcolors.same_color(parts['bodies'][0].get_facecolor(), ('red', 0.3))
4251+
4252+
# Case 2: If facecolor is explicitly given, it's alpha does not become an
4253+
# Artist property
4254+
parts = ax.violinplot(data, positions=[1], facecolor=('blue', 0.3))
4255+
assert mcolors.same_color(parts['bodies'][0].get_facecolor(), ('blue', 0.3))
4256+
assert parts['bodies'][0].get_alpha() is None
4257+
# so setting a new color does not maintain the alpha
4258+
parts['bodies'][0].set_facecolor('red')
4259+
assert mcolors.same_color(parts['bodies'][0].get_facecolor(), 'red')
4260+
4261+
42314262
@check_figures_equal()
42324263
def test_violinplot_single_list_quantiles(fig_test, fig_ref):
42334264
# Ensures quantile list for 1D can be passed in as single list

0 commit comments

Comments
 (0)