Skip to content

Commit 3c87254

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

File tree

2 files changed

+41
-4
lines changed

2 files changed

+41
-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+
You can use the ``(color, alpha)`` tuple notation to pass
8976+
semi-transparent colors.
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: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4228,6 +4228,33 @@ def assert_colors_equal(colors1, colors2):
42284228
assert_colors_equal(colors_test, mcolors.to_rgba_array(linecolors))
42294229

42304230

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

0 commit comments

Comments
 (0)