I know the question is not very informative.. but as I do not know the name of his type of plot, I can not be more informative..
[EDIT] I changed the title, and now it is more informative...
I know the question is not very informative.. but as I do not know the name of his type of plot, I can not be more informative..
[EDIT] I changed the title, and now it is more informative...
You can do something similar with seaborn.swarmplot
. I also use seaborn.boxplot
(with the whiskers and caps turned off) to plot the mean and range:
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style("whitegrid")
tips = sns.load_dataset("tips")
ax = sns.swarmplot(x="day", y="total_bill", data=tips)
ax = sns.boxplot(x="day", y="total_bill", data=tips,
showcaps=False,boxprops={'facecolor':'None'},
showfliers=False,whiskerprops={'linewidth':0})
plt.show()
If (for whatever reason) you don't want to use seaborn, you can have a go at making them yourself (see e.g. this explanation: https://www.flerlagetwins.com/2020/11/beeswarm.html ).
A simple version is:
#!/usr/bin/env python3
import matplotlib.pyplot as plt
import numpy as np
def simple_beeswarm(y, nbins=None):
"""
Returns x coordinates for the points in ``y``, so that plotting ``x`` and
``y`` results in a bee swarm plot.
"""
y = np.asarray(y)
if nbins is None:
nbins = len(y) // 6
# Get upper bounds of bins
x = np.zeros(len(y))
ylo = np.min(y)
yhi = np.max(y)
dy = (yhi - ylo) / nbins
ybins = np.linspace(ylo + dy, yhi - dy, nbins - 1)
# Divide indices into bins
i = np.arange(len(y))
ibs = [0] * nbins
ybs = [0] * nbins
nmax = 0
for j, ybin in enumerate(ybins):
f = y <= ybin
ibs[j], ybs[j] = i[f], y[f]
nmax = max(nmax, len(ibs[j]))
f = ~f
i, y = i[f], y[f]
ibs[-1], ybs[-1] = i, y
nmax = max(nmax, len(ibs[-1]))
# Assign x indices
dx = 1 / (nmax // 2)
for i, y in zip(ibs, ybs):
if len(i) > 1:
j = len(i) % 2
i = i[np.argsort(y)]
a = i[j::2]
b = i[j+1::2]
x[a] = (0.5 + j / 3 + np.arange(len(b))) * dx
x[b] = (0.5 + j / 3 + np.arange(len(b))) * -dx
return x
fig = plt.figure(figsize=(2, 4))
fig.subplots_adjust(0.2, 0.1, 0.98, 0.99)
ax = fig.add_subplot(1, 1, 1)
y = np.random.gamma(20, 10, 100)
x = simple_beeswarm(y)
ax.plot(x, y, 'o')
fig.savefig('bee.png')
A variation on the answer by @MichaelClerx, using numpy binning function and adding width parameter, to combine with boxplots:
#!/usr/bin/python3.6
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
def simple_beeswarm2(y, nbins=None, width=1.):
"""
Returns x coordinates for the points in ``y``, so that plotting ``x`` and
``y`` results in a bee swarm plot.
"""
y = np.asarray(y)
if nbins is None:
# nbins = len(y) // 6
nbins = np.ceil(len(y) / 6).astype(int)
# Get upper bounds of bins
x = np.zeros(len(y))
nn, ybins = np.histogram(y, bins=nbins)
nmax = nn.max()
#Divide indices into bins
ibs = []#np.nonzero((y>=ybins[0])*(y<=ybins[1]))[0]]
for ymin, ymax in zip(ybins[:-1], ybins[1:]):
i = np.nonzero((y>ymin)*(y<=ymax))[0]
ibs.append(i)
# Assign x indices
dx = width / (nmax // 2)
for i in ibs:
yy = y[i]
if len(i) > 1:
j = len(i) % 2
i = i[np.argsort(yy)]
a = i[j::2]
b = i[j+1::2]
x[a] = (0.5 + j / 3 + np.arange(len(b))) * dx
x[b] = (0.5 + j / 3 + np.arange(len(b))) * -dx
return x
y1 = np.random.gamma(20, 10, 100)
y2 = np.random.gamma(20, 10, 100)
fig, ax = plt.subplots(1, 1, figsize=(4, 8))
ax.boxplot([y1, y2], widths=0.5, showfliers=False, showcaps=False)
x1 = simple_beeswarm2(y1, width=0.25)
ax.plot(x1+1., y1, 'o')
x2 = simple_beeswarm2(y2, width=0.25)
ax.plot(x2+2., y2, 'o')
# ax.plot(x2, y, 'o')
plt.savefig('./swarm_final.png')
plt.close(fig)
© 2022 - 2024 — McMap. All rights reserved.
seaborn.swarmplot
orseaborn.stripplot
– Ollie