Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork7.9k
Allow user to specify colors in violin plots with constructor method#27304
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Merged
Uh oh!
There was an error while loading.Please reload this page.
Merged
Changes fromall commits
Commits
Show all changes
13 commits Select commitHold shift + click to select a range
c1190e6
Add color specification and pyi docs
landoskape4c6def1
edgecolor to linecolor, no more alpha
landoskape9ce5d12
Arg documentation
landoskape33d186b
completeness, formatting
landoskape9e97d6f
Default logic, docstring, straightforward testing
landoskape2d4c7b7
Spelling error
landoskape35f5c62
single "next color" for default face/line
landoskape8474cf1
Merge branch 'violin-plot-color' of https://github.com/landoskape/mat…
landoskapea206de8
clarify color specification
landoskape3998c6f
axes bug -- set with facecolor
landoskapef219c3f
direct comparison to source colors, face!=line
landoskape60343f5
adjust behavior for classic mode
landoskapee66e33a
Apply suggestions from code review
timhoffmFile filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
8 changes: 8 additions & 0 deletionsdoc/users/next_whats_new/violinplot_colors.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
``violinplot`` now accepts color arguments | ||
------------------------------------------- | ||
`~.Axes.violinplot` and `~.Axes.violin` now accept ``facecolor`` and | ||
``linecolor`` as input arguments. This means that users can set the color of | ||
violinplots as they make them, rather than setting the color of individual | ||
objects afterwards. It is possible to pass a single color to be used for all | ||
violins, or pass a sequence of colors. |
30 changes: 20 additions & 10 deletionsgalleries/examples/statistics/customized_violin.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -36,20 +36,30 @@ def set_axis_style(ax, labels): | ||
np.random.seed(19680801) | ||
data = [sorted(np.random.normal(0, std, 100)) for std in range(1, 5)] | ||
fig, (ax1, ax2, ax3) = plt.subplots(nrows=1, ncols=3, figsize=(9,3), sharey=True) | ||
ax1.set_title('Default violin plot') | ||
ax1.set_ylabel('Observed values') | ||
ax1.violinplot(data) | ||
ax2.set_title('Set colors of violins') | ||
ax2.set_ylabel('Observed values') | ||
ax2.violinplot( | ||
data, | ||
facecolor=[('yellow', 0.3), ('blue', 0.3), ('red', 0.3), ('green', 0.3)], | ||
linecolor='black', | ||
) | ||
# Note that when passing a sequence of colors, the method will repeat the sequence if | ||
# less colors are provided than data distributions. | ||
ax3.set_title('Customized violin plot') | ||
parts = ax3.violinplot( | ||
data, showmeans=False, showmedians=False, showextrema=False, | ||
facecolor='#D43F3A', linecolor='black') | ||
for pc in parts['bodies']: | ||
pc.set_edgecolor('black') | ||
landoskape marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
pc.set_linewidth(1) | ||
pc.set_alpha(1) | ||
quartile1, medians, quartile3 = np.percentile(data, [25, 50, 75], axis=1) | ||
@@ -59,13 +69,13 @@ def set_axis_style(ax, labels): | ||
whiskers_min, whiskers_max = whiskers[:, 0], whiskers[:, 1] | ||
inds = np.arange(1, len(medians) + 1) | ||
ax3.scatter(inds, medians, marker='o', color='white', s=30, zorder=3) | ||
ax3.vlines(inds, quartile1, quartile3, color='k', linestyle='-', lw=5) | ||
ax3.vlines(inds, whiskers_min, whiskers_max, color='k', linestyle='-', lw=1) | ||
# set style for the axes | ||
labels = ['A', 'B', 'C', 'D'] | ||
for ax in [ax1, ax2, ax3]: | ||
set_axis_style(ax, labels) | ||
plt.subplots_adjust(bottom=0.15, wspace=0.05) | ||
77 changes: 68 additions & 9 deletionslib/matplotlib/axes/_axes.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -8439,7 +8439,8 @@ def matshow(self, Z, **kwargs): | ||
def violinplot(self, dataset, positions=None, vert=None, | ||
orientation='vertical', widths=0.5, showmeans=False, | ||
showextrema=True, showmedians=False, quantiles=None, | ||
points=100, bw_method=None, side='both', | ||
facecolor=None, linecolor=None): | ||
""" | ||
Make a violin plot. | ||
@@ -8506,6 +8507,17 @@ def violinplot(self, dataset, positions=None, vert=None, | ||
'both' plots standard violins. 'low'/'high' only | ||
plots the side below/above the positions value. | ||
facecolor : :mpltype:`color` or list of :mpltype:`color`, optional | ||
If provided, will set the face color(s) of the violins. | ||
oscargus marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
.. versionadded:: 3.11 | ||
linecolor : :mpltype:`color` or list of :mpltype:`color`, optional | ||
If provided, will set the line color(s) of the violins (the | ||
horizontal and vertical spines and body edges). | ||
.. versionadded:: 3.11 | ||
data : indexable object, optional | ||
DATA_PARAMETER_PLACEHOLDER | ||
@@ -8558,12 +8570,14 @@ def _kde_method(X, coords): | ||
return self.violin(vpstats, positions=positions, vert=vert, | ||
orientation=orientation, widths=widths, | ||
showmeans=showmeans, showextrema=showextrema, | ||
showmedians=showmedians, side=side, | ||
facecolor=facecolor, linecolor=linecolor) | ||
@_api.make_keyword_only("3.9", "vert") | ||
def violin(self, vpstats, positions=None, vert=None, | ||
orientation='vertical', widths=0.5, showmeans=False, | ||
showextrema=True, showmedians=False, side='both', | ||
facecolor=None, linecolor=None): | ||
""" | ||
Draw a violin plot from pre-computed statistics. | ||
@@ -8635,6 +8649,17 @@ def violin(self, vpstats, positions=None, vert=None, | ||
'both' plots standard violins. 'low'/'high' only | ||
plots the side below/above the positions value. | ||
facecolor : :mpltype:`color` or list of :mpltype:`color`, optional | ||
If provided, will set the face color(s) of the violins. | ||
.. versionadded:: 3.11 | ||
linecolor : :mpltype:`color` or list of :mpltype:`color`, optional | ||
If provided, will set the line color(s) of the violins (the | ||
horizontal and vertical spines and body edges). | ||
.. versionadded:: 3.11 | ||
Returns | ||
------- | ||
dict | ||
@@ -8717,12 +8742,45 @@ def violin(self, vpstats, positions=None, vert=None, | ||
[0.25 if side in ['both', 'high'] else 0]] \ | ||
* np.array(widths) + positions | ||
# Make a cycle of color to iterate through, using 'none' as fallback | ||
def cycle_color(color, alpha=None): | ||
rgba = mcolors.to_rgba_array(color, alpha=alpha) | ||
color_cycler = itertools.chain(itertools.cycle(rgba), | ||
itertools.repeat('none')) | ||
color_list = [] | ||
for _ in range(N): | ||
color_list.append(next(color_cycler)) | ||
return color_list | ||
# Convert colors to chain (number of colors can be different from len(vpstats)) | ||
if facecolor is None or linecolor is None: | ||
if not mpl.rcParams['_internal.classic_mode']: | ||
next_color = self._get_lines.get_next_color() | ||
if facecolor is not None: | ||
facecolor = cycle_color(facecolor) | ||
else: | ||
default_facealpha = 0.3 | ||
# Use default colors if user doesn't provide them | ||
if mpl.rcParams['_internal.classic_mode']: | ||
facecolor = cycle_color('y', alpha=default_facealpha) | ||
else: | ||
facecolor = cycle_color(next_color, alpha=default_facealpha) | ||
if mpl.rcParams['_internal.classic_mode']: | ||
# Classic mode uses patch.force_edgecolor=True, so we need to | ||
# set the edgecolor to make sure it has an alpha. | ||
body_edgecolor = ("k", 0.3) | ||
else: | ||
body_edgecolor = None | ||
if linecolor is not None: | ||
linecolor = cycle_color(linecolor) | ||
else: | ||
if mpl.rcParams['_internal.classic_mode']: | ||
linecolor = cycle_color('r') | ||
else: | ||
linecolor = cycle_color(next_color) | ||
# Check whether we are rendering vertically or horizontally | ||
if orientation == 'vertical': | ||
@@ -8748,14 +8806,15 @@ def violin(self, vpstats, positions=None, vert=None, | ||
# Render violins | ||
bodies = [] | ||
bodies_zip = zip(vpstats, positions, widths, facecolor) | ||
for stats, pos, width, facecolor in bodies_zip: | ||
# The 0.5 factor reflects the fact that we plot from v-p to v+p. | ||
vals = np.array(stats['vals']) | ||
vals = 0.5 * width * vals / vals.max() | ||
bodies += [fill(stats['coords'], | ||
-vals + pos if side in ['both', 'low'] else pos, | ||
vals + pos if side in ['both', 'high'] else pos, | ||
facecolor=facecolor, edgecolor=body_edgecolor)] | ||
means.append(stats['mean']) | ||
mins.append(stats['min']) | ||
maxes.append(stats['max']) | ||
4 changes: 4 additions & 0 deletionslib/matplotlib/axes/_axes.pyi
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
4 changes: 4 additions & 0 deletionslib/matplotlib/pyplot.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
73 changes: 73 additions & 0 deletionslib/matplotlib/tests/test_axes.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.