J'ai vu ce merveilleux boxplot dans cet article (Fig.2).
Comme vous pouvez le voir, il s'agit d'un boxplot sur lequel se superpose une dispersion de points noirs: x indexe les points noirs (dans un ordre aléatoire), y est la variable d'intérêt. Je voudrais faire quelque chose de similaire en utilisant Matplotlib, mais je ne sais pas par où commencer. Jusqu'à présent, les boxplots que j'ai trouvés en ligne sont beaucoup moins cool et ressemblent à ceci:
Documentation de matplotlib: http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.boxplot
Façons de coloriser les boîtes à moustaches: https://github.com/jbmouret/matplotlib_for_papers#colored-boxes
Ce que vous recherchez est un moyen d'ajouter de la gigue à l'axe des x.
Quelque chose comme ça tiré de ici :
bp = titanic.boxplot(column='age', by='pclass', grid=False)
for i in [1,2,3]:
y = titanic.age[titanic.pclass==i].dropna()
# Add some random "jitter" to the x-axis
x = np.random.normal(i, 0.04, size=len(y))
plot(x, y, 'r.', alpha=0.2)
Citant le lien:
Une façon d'ajouter des informations supplémentaires à un boxplot est de superposer les données réelles; c'est généralement le plus approprié avec des séries de données de petite ou moyenne taille. Lorsque les données sont denses, quelques astuces utilisées ci-dessus aident à la visualisation:
- réduire le niveau alpha pour rendre les points partiellement transparents
- ajouter une "gigue" aléatoire le long de l'axe des x pour éviter les surcharges
Le code ressemble à ceci:
import pylab as P
import numpy as np
# Define data
# Define numBoxes
P.figure()
bp = P.boxplot(data)
for i in range(numBoxes):
y = data[i]
x = np.random.normal(1+i, 0.04, size=len(y))
P.plot(x, y, 'r.', alpha=0.2)
P.show()
Développer la solution de Kyrubas et utiliser uniquement matplotlib pour la partie de traçage (j'ai parfois du mal à formater pandas tracés avec matplotlib).
from matplotlib import cm
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
# initialize dataframe
n = 200
ngroup = 3
df = pd.DataFrame({'data': np.random.Rand(n), 'group': map(np.floor, np.random.Rand(n) * ngroup)})
group = 'group'
column = 'data'
grouped = df.groupby(group)
names, vals, xs = [], [] ,[]
for i, (name, subdf) in enumerate(grouped):
names.append(name)
vals.append(subdf[column].tolist())
xs.append(np.random.normal(i+1, 0.04, subdf.shape[0]))
plt.boxplot(vals, labels=names)
ngroup = len(vals)
clevels = np.linspace(0., 1., ngroup)
for x, val, clevel in Zip(xs, vals, clevels):
plt.scatter(x, val, c=cm.prism(clevel), alpha=0.4)
En tant qu'option plus simple, peut-être plus récente, vous pouvez utiliser l'option seaborn
de swarmplot
.
import seaborn as sns
import matplotlib.pyplot as plt
sns.set(style="whitegrid")
tips = sns.load_dataset("tips")
ax = sns.boxplot(x="day", y="total_bill", data=tips, showfliers = False)
ax = sns.swarmplot(x="day", y="total_bill", data=tips, color=".25")
plt.show()
En regardant à nouveau la question d'origine (et en ayant moi-même plus d'expérience), je pense qu'au lieu de sns.swarmplot
, sns.stripplot
serait plus précis.