web-dev-qa-db-fra.com

Ajout d'une dispersion de points à un boxplot à l'aide de matplotlib

J'ai vu ce merveilleux boxplot dans cet article (Fig.2).

A wonderful boxplot

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:

Usual boxplots

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

14
Wok

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)

enter image description here

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:

  1. réduire le niveau alpha pour rendre les points partiellement transparents
  2. 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()
21
Kyrubas

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)

enter image description here

14
hwang

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()

enter image description here


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.

3
HS-nebula