Agregar una dispersión de puntos a una gráfica de caja usando matplotlib

He visto este maravilloso diagtwig de caja en este artículo (Fig.2).

Un maravilloso boxplot

Como puede ver, este es un diagtwig de caja en el que se superponen una dispersión de puntos negros: x indexa los puntos negros (en un orden aleatorio), y es la variable de interés. Me gustaría hacer algo similar usando Matplotlib, pero no tengo idea de por dónde empezar. Hasta ahora, los diagtwigs de caja que he encontrado en línea son mucho menos geniales y se ven así:

Diagramas de caja habituales

Documentación de matplotlib: http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.boxplot

Formas de colorear diagtwigs de caja: https://github.com/jbmouret/matplotlib_for_papers#colored-boxes

Lo que estás buscando es una forma de agregar jitter al eje x.

Algo como esto tomado desde aquí :

 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) 

introduzca la descripción de la imagen aquí

Citando el enlace:

Una forma de agregar información adicional a un diagtwig de caja es superponer los datos reales; Esto es generalmente más adecuado con series de datos de tamaño pequeño o moderado. Cuando los datos son densos, un par de trucos utilizados anteriormente ayudan a la visualización:

  1. Reduciendo el nivel alfa para hacer los puntos parcialmente transparentes.
  2. añadiendo “fluctuaciones” aleatorias a lo largo del eje x para evitar sobrescribir

El código se ve así:

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

Ampliando la solución de Kyrubas y utilizando solo matplotlib para la parte de trazado (a veces tengo dificultades para formatear los diagtwigs de pandas con 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) 

introduzca la descripción de la imagen aquí

Como una opción más simple, posiblemente más nueva, podría usar la opción 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() 

introduzca la descripción de la imagen aquí