Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d57fa97

Browse filesBrowse files
authored
Merge pull request #27815 from anjabeck/side-option-violinplot
Add side option to violinplot
2 parents 76eaa96 + 0adab7b commit d57fa97
Copy full SHA for d57fa97

File tree

Expand file treeCollapse file tree

7 files changed

+88
-20
lines changed
Filter options
Expand file treeCollapse file tree

7 files changed

+88
-20
lines changed
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Add option to plot only one half of violin plot
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
Setting the parameter *side* to 'low' or 'high' allows to only plot one half of the violin plot.

‎galleries/examples/statistics/violinplot.py

Copy file name to clipboardExpand all lines: galleries/examples/statistics/violinplot.py
+29-11Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,55 +28,73 @@
2828
pos = [1, 2, 4, 5, 7, 8]
2929
data = [np.random.normal(0, std, size=100) for std in pos]
3030

31-
fig, axs = plt.subplots(nrows=2, ncols=5, figsize=(10, 6))
31+
fig, axs = plt.subplots(nrows=2, ncols=6, figsize=(10, 4))
3232

3333
axs[0, 0].violinplot(data, pos, points=20, widths=0.3,
3434
showmeans=True, showextrema=True, showmedians=True)
35-
axs[0, 0].set_title('Custom violinplot 1', fontsize=fs)
35+
axs[0, 0].set_title('Custom violin 1', fontsize=fs)
3636

3737
axs[0, 1].violinplot(data, pos, points=40, widths=0.5,
3838
showmeans=True, showextrema=True, showmedians=True,
3939
bw_method='silverman')
40-
axs[0, 1].set_title('Custom violinplot 2', fontsize=fs)
40+
axs[0, 1].set_title('Custom violin 2', fontsize=fs)
4141

4242
axs[0, 2].violinplot(data, pos, points=60, widths=0.7, showmeans=True,
4343
showextrema=True, showmedians=True, bw_method=0.5)
44-
axs[0, 2].set_title('Custom violinplot 3', fontsize=fs)
44+
axs[0, 2].set_title('Custom violin 3', fontsize=fs)
4545

4646
axs[0, 3].violinplot(data, pos, points=60, widths=0.7, showmeans=True,
4747
showextrema=True, showmedians=True, bw_method=0.5,
4848
quantiles=[[0.1], [], [], [0.175, 0.954], [0.75], [0.25]])
49-
axs[0, 3].set_title('Custom violinplot 4', fontsize=fs)
49+
axs[0, 3].set_title('Custom violin 4', fontsize=fs)
5050

5151
axs[0, 4].violinplot(data[-1:], pos[-1:], points=60, widths=0.7,
5252
showmeans=True, showextrema=True, showmedians=True,
5353
quantiles=[0.05, 0.1, 0.8, 0.9], bw_method=0.5)
54-
axs[0, 4].set_title('Custom violinplot 5', fontsize=fs)
54+
axs[0, 4].set_title('Custom violin 5', fontsize=fs)
55+
56+
axs[0, 5].violinplot(data[-1:], pos[-1:], points=60, widths=0.7,
57+
showmeans=True, showextrema=True, showmedians=True,
58+
quantiles=[0.05, 0.1, 0.8, 0.9], bw_method=0.5, side='low')
59+
60+
axs[0, 5].violinplot(data[-1:], pos[-1:], points=60, widths=0.7,
61+
showmeans=True, showextrema=True, showmedians=True,
62+
quantiles=[0.05, 0.1, 0.8, 0.9], bw_method=0.5, side='high')
63+
axs[0, 5].set_title('Custom violin 6', fontsize=fs)
5564

5665
axs[1, 0].violinplot(data, pos, points=80, vert=False, widths=0.7,
5766
showmeans=True, showextrema=True, showmedians=True)
58-
axs[1, 0].set_title('Custom violinplot 6', fontsize=fs)
67+
axs[1, 0].set_title('Custom violin 7', fontsize=fs)
5968

6069
axs[1, 1].violinplot(data, pos, points=100, vert=False, widths=0.9,
6170
showmeans=True, showextrema=True, showmedians=True,
6271
bw_method='silverman')
63-
axs[1, 1].set_title('Custom violinplot 7', fontsize=fs)
72+
axs[1, 1].set_title('Custom violin 8', fontsize=fs)
6473

6574
axs[1, 2].violinplot(data, pos, points=200, vert=False, widths=1.1,
6675
showmeans=True, showextrema=True, showmedians=True,
6776
bw_method=0.5)
68-
axs[1, 2].set_title('Custom violinplot 8', fontsize=fs)
77+
axs[1, 2].set_title('Custom violin 9', fontsize=fs)
6978

7079
axs[1, 3].violinplot(data, pos, points=200, vert=False, widths=1.1,
7180
showmeans=True, showextrema=True, showmedians=True,
7281
quantiles=[[0.1], [], [], [0.175, 0.954], [0.75], [0.25]],
7382
bw_method=0.5)
74-
axs[1, 3].set_title('Custom violinplot 9', fontsize=fs)
83+
axs[1, 3].set_title('Custom violin 10', fontsize=fs)
7584

7685
axs[1, 4].violinplot(data[-1:], pos[-1:], points=200, vert=False, widths=1.1,
7786
showmeans=True, showextrema=True, showmedians=True,
7887
quantiles=[0.05, 0.1, 0.8, 0.9], bw_method=0.5)
79-
axs[1, 4].set_title('Custom violinplot 10', fontsize=fs)
88+
axs[1, 4].set_title('Custom violin 11', fontsize=fs)
89+
90+
axs[1, 5].violinplot(data[-1:], pos[-1:], points=200, vert=False, widths=1.1,
91+
showmeans=True, showextrema=True, showmedians=True,
92+
quantiles=[0.05, 0.1, 0.8, 0.9], bw_method=0.5, side='low')
93+
94+
axs[1, 5].violinplot(data[-1:], pos[-1:], points=200, vert=False, widths=1.1,
95+
showmeans=True, showextrema=True, showmedians=True,
96+
quantiles=[0.05, 0.1, 0.8, 0.9], bw_method=0.5, side='high')
97+
axs[1, 5].set_title('Custom violin 12', fontsize=fs)
8098

8199

82100
for ax in axs.flat:

‎lib/matplotlib/axes/_axes.py

Copy file name to clipboardExpand all lines: lib/matplotlib/axes/_axes.py
+36-9Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8205,7 +8205,7 @@ def matshow(self, Z, **kwargs):
82058205
@_preprocess_data(replace_names=["dataset"])
82068206
def violinplot(self, dataset, positions=None, vert=True, widths=0.5,
82078207
showmeans=False, showextrema=True, showmedians=False,
8208-
quantiles=None, points=100, bw_method=None):
8208+
quantiles=None, points=100, bw_method=None, side='both'):
82098209
"""
82108210
Make a violin plot.
82118211
@@ -8256,6 +8256,10 @@ def violinplot(self, dataset, positions=None, vert=True, widths=0.5,
82568256
callable, it should take a `matplotlib.mlab.GaussianKDE` instance as
82578257
its only parameter and return a float.
82588258
8259+
side : {'both', 'low', 'high'}, default: 'both'
8260+
'both' plots standard violins. 'low'/'high' only
8261+
plots the side below/above the positions value.
8262+
82598263
data : indexable object, optional
82608264
DATA_PARAMETER_PLACEHOLDER
82618265
@@ -8307,10 +8311,10 @@ def _kde_method(X, coords):
83078311
quantiles=quantiles)
83088312
return self.violin(vpstats, positions=positions, vert=vert,
83098313
widths=widths, showmeans=showmeans,
8310-
showextrema=showextrema, showmedians=showmedians)
8314+
showextrema=showextrema, showmedians=showmedians, side=side)
83118315

83128316
def violin(self, vpstats, positions=None, vert=True, widths=0.5,
8313-
showmeans=False, showextrema=True, showmedians=False):
8317+
showmeans=False, showextrema=True, showmedians=False, side='both'):
83148318
"""
83158319
Draw a violin plot from pre-computed statistics.
83168320
@@ -8366,6 +8370,10 @@ def violin(self, vpstats, positions=None, vert=True, widths=0.5,
83668370
showmedians : bool, default: False
83678371
Whether to show the median with a line.
83688372
8373+
side : {'both', 'low', 'high'}, default: 'both'
8374+
'both' plots standard violins. 'low'/'high' only
8375+
plots the side below/above the positions value.
8376+
83698377
Returns
83708378
-------
83718379
dict
@@ -8428,8 +8436,13 @@ def violin(self, vpstats, positions=None, vert=True, widths=0.5,
84288436
elif len(widths) != N:
84298437
raise ValueError(datashape_message.format("widths"))
84308438

8439+
# Validate side
8440+
_api.check_in_list(["both", "low", "high"], side=side)
8441+
84318442
# Calculate ranges for statistics lines (shape (2, N)).
8432-
line_ends = [[-0.25], [0.25]] * np.array(widths) + positions
8443+
line_ends = [[-0.25 if side in ['both', 'low'] else 0],
8444+
[0.25 if side in ['both', 'high'] else 0]] \
8445+
* np.array(widths) + positions
84338446

84348447
# Colors.
84358448
if mpl.rcParams['_internal.classic_mode']:
@@ -8441,20 +8454,34 @@ def violin(self, vpstats, positions=None, vert=True, widths=0.5,
84418454
# Check whether we are rendering vertically or horizontally
84428455
if vert:
84438456
fill = self.fill_betweenx
8444-
perp_lines = functools.partial(self.hlines, colors=linecolor)
8445-
par_lines = functools.partial(self.vlines, colors=linecolor)
8457+
if side in ['low', 'high']:
8458+
perp_lines = functools.partial(self.hlines, colors=linecolor,
8459+
capstyle='projecting')
8460+
par_lines = functools.partial(self.vlines, colors=linecolor,
8461+
capstyle='projecting')
8462+
else:
8463+
perp_lines = functools.partial(self.hlines, colors=linecolor)
8464+
par_lines = functools.partial(self.vlines, colors=linecolor)
84468465
else:
84478466
fill = self.fill_between
8448-
perp_lines = functools.partial(self.vlines, colors=linecolor)
8449-
par_lines = functools.partial(self.hlines, colors=linecolor)
8467+
if side in ['low', 'high']:
8468+
perp_lines = functools.partial(self.vlines, colors=linecolor,
8469+
capstyle='projecting')
8470+
par_lines = functools.partial(self.hlines, colors=linecolor,
8471+
capstyle='projecting')
8472+
else:
8473+
perp_lines = functools.partial(self.vlines, colors=linecolor)
8474+
par_lines = functools.partial(self.hlines, colors=linecolor)
84508475

84518476
# Render violins
84528477
bodies = []
84538478
for stats, pos, width in zip(vpstats, positions, widths):
84548479
# The 0.5 factor reflects the fact that we plot from v-p to v+p.
84558480
vals = np.array(stats['vals'])
84568481
vals = 0.5 * width * vals / vals.max()
8457-
bodies += [fill(stats['coords'], -vals + pos, vals + pos,
8482+
bodies += [fill(stats['coords'],
8483+
-vals + pos if side in ['both', 'low'] else pos,
8484+
vals + pos if side in ['both', 'high'] else pos,
84588485
facecolor=fillcolor, alpha=0.3)]
84598486
means.append(stats['mean'])
84608487
mins.append(stats['min'])

‎lib/matplotlib/axes/_axes.pyi

Copy file name to clipboardExpand all lines: lib/matplotlib/axes/_axes.pyi
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,7 @@ class Axes(_AxesBase):
743743
| float
744744
| Callable[[GaussianKDE], float]
745745
| None = ...,
746+
side: Literal["both", "low", "high"] = ...,
746747
*,
747748
data=...,
748749
) -> dict[str, Collection]: ...
@@ -755,6 +756,7 @@ class Axes(_AxesBase):
755756
showmeans: bool = ...,
756757
showextrema: bool = ...,
757758
showmedians: bool = ...,
759+
side: Literal["both", "low", "high"] = ...,
758760
) -> dict[str, Collection]: ...
759761

760762
table = mtable.table

‎lib/matplotlib/pyplot.py

Copy file name to clipboardExpand all lines: lib/matplotlib/pyplot.py
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4075,6 +4075,7 @@ def violinplot(
40754075
| float
40764076
| Callable[[GaussianKDE], float]
40774077
| None = None,
4078+
side: Literal["both", "low", "high"] = "both",
40784079
*,
40794080
data=None,
40804081
) -> dict[str, Collection]:
@@ -4089,6 +4090,7 @@ def violinplot(
40894090
quantiles=quantiles,
40904091
points=points,
40914092
bw_method=bw_method,
4093+
side=side,
40924094
**({"data": data} if data is not None else {}),
40934095
)
40944096

Loading

‎lib/matplotlib/tests/test_axes.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_axes.py
+15Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3794,6 +3794,21 @@ def test_horiz_violinplot_custompoints_200():
37943794
showextrema=False, showmedians=False, points=200)
37953795

37963796

3797+
@image_comparison(['violinplot_sides.png'], remove_text=True, style='mpl20')
3798+
def test_violinplot_sides():
3799+
ax = plt.axes()
3800+
np.random.seed(19680801)
3801+
data = [np.random.normal(size=100)]
3802+
# Check horizontal violinplot
3803+
for pos, side in zip([0, -0.5, 0.5], ['both', 'low', 'high']):
3804+
ax.violinplot(data, positions=[pos], vert=False, showmeans=False,
3805+
showextrema=True, showmedians=True, side=side)
3806+
# Check vertical violinplot
3807+
for pos, side in zip([4, 3.5, 4.5], ['both', 'low', 'high']):
3808+
ax.violinplot(data, positions=[pos], vert=True, showmeans=False,
3809+
showextrema=True, showmedians=True, side=side)
3810+
3811+
37973812
def test_violinplot_bad_positions():
37983813
ax = plt.axes()
37993814
# First 9 digits of frac(sqrt(47))

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.