Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Customize violin plot demo, see #6723 #6814

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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 11, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions examples/statistics/customized_violin_demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Customizing violin plots
#
#

import matplotlib.pyplot as plt
import numpy as np


# functions to calculate percentiles and adjacent values
def percentile(vals, p):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use np.percentile?

N = len(vals)
n = p*(N+1)
k = int(n)
d = n-k
if k <= 0:
return vals[0]
if k >= N:
return vals[N-1]
return vals[k-1] + d*(vals[k] - vals[k-1])


def adjacent_values(vals):
q1 = percentile(vals, 0.25)
q3 = percentile(vals, 0.75)
uav = q3 + (q3-q1)*1.5
if uav > vals[-1]:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can use np.clip here

uav = vals[-1]
if uav < q3:
uav = q3
lav = q1 - (q3-q1)*1.5
if lav < vals[0]:
lav = vals[0]
if lav > q1:
lav = q1
return [lav, uav]

# create test data
dat = [np.random.normal(0, std, 100) for std in range(6, 10)]
lab = ['a', 'b', 'c', 'd'] # labels
med = [] # medians
iqr = [] # inter-quantile ranges
avs = [] # upper and lower adjacent values
for arr in dat:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much of this could be wrapped up in a function with a siganture like def vln(ax, data, style)

sarr = sorted(arr)
med.append(percentile(sarr, 0.5))
iqr.append([percentile(sarr, 0.25), percentile(sarr, 0.75)])
avs.append(adjacent_values(sarr))

# plot the violins
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(7, 5))
parts = ax.violinplot(dat, showmeans=False, showmedians=False,
showextrema=False)

# plot medians and averages
for i in range(len(med)):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can do the lines with a single call to ax.vlines and all of the markes with a single call to ax.plot. On the other hand, if it is the idea to be able to make a single violin invisible at a time this way might be better.

Can you collect the returned artists into a data structure of some sort (probably a dictionary per violin?)?

ax.plot([i+1, i+1], avs[i], '-', c='black', lw=1)
ax.plot([i+1, i+1], iqr[i], '-', c='black', lw=5)
ax.plot(i+1, med[i], 'o', mec='none', c='white', ms=6)

# customize colors
for pc in parts['bodies']:
pc.set_facecolor('#D43F3A')
pc.set_edgecolor('black')
pc.set_alpha(1)

ax.get_xaxis().set_tick_params(direction='out')
ax.xaxis.set_ticks_position('bottom')
ax.set_xticks([x+1 for x in range(len(lab))])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

np.arange(1, len(lab) + 1)

ax.set_xticklabels(lab)
ax.set_xlim(0.25, len(lab)+0.75)
ax.set_ylabel('ylabel')
ax.set_xlabel('xlabel')
ax.set_title('customized violin plot')

plt.subplots_adjust(bottom=0.15)

plt.show()