Trazar un trazado de líneas con barras de error y puntos de datos de un dataframe de pandas

He estado atormentando mi cerebro para tratar de descubrir cómo trazar un DataFrame de pandas de la manera que quiero, pero fue en vano.

El DataFrame tiene un MultiIndex y se ve así:

+-----------+--------------+------------+--------------+-----------------+---------+---------+---------+---------+---------+ | | | | | | run_001 | run_002 | run_003 | run_004 | run_005 | +-----------+--------------+------------+--------------+-----------------+---------+---------+---------+---------+---------+ | file_type | server_count | file_count | thread_count | cacheclear_type | | | | | | +-----------+--------------+------------+--------------+-----------------+---------+---------+---------+---------+---------+ | gor | 01servers | 05files | 20threads | ccALWAYS | 15.918 | 16.275 | 15.807 | 17.781 | 16.233 | | gor | 01servers | 10files | 20threads | ccALWAYS | 17.322 | 17.636 | 16.096 | 16.484 | 16.715 | | gor | 01servers | 15files | 20threads | ccALWAYS | 19.265 | 17.128 | 17.630 | 18.739 | 16.833 | | gor | 01servers | 20files | 20threads | ccALWAYS | 23.744 | 20.539 | 21.416 | 22.921 | 22.794 | +-----------+--------------+------------+--------------+-----------------+---------+---------+---------+---------+---------+ 

Lo que quiero hacer es trazar un gráfico de líneas donde los valores de x son el valor ‘file_count’, y el valor de y para cada uno es el promedio de todos los valores de run_xxx para la línea correspondiente en el DataFrame.

Si es posible, me gustaría agregar barras de error e incluso los puntos de datos para poder ver la distribución de los datos detrás de ese promedio.

Aquí hay una maqueta de lo que estoy hablando:

maqueta de gráfico deseado

He podido crear un diagtwig de caja usando la función boxplot () integrada en el DataFrame de pandas haciendo:

 df.transpose().boxplot() 

Esto parece casi correcto pero un poco desordenado y no tiene los puntos de datos reales trazados.

El argumento de Beeswarm será muy bueno en esta situación, especialmente cuando tienes muchos puntos y qué mostrar las distribuciones de esos puntos. Sin embargo, debe proporcionar el parámetro de position a beeswarm ya que, por defecto, comenzará en 0. El método boxplot de pandas DataFrame , por otro lado, dibuja cuadros en x = 1, 2 …

Todo se reduce a esto:

 from beeswarm import * D1 = beeswarm(df.values, positions = np.arange(len(df.values))+1) D2 = df.transpose().boxplot(ax=D1[1]) 

introduzca la descripción de la imagen aquí

Para completar, incluiré la forma en que finalmente logré hacer esto aquí:

 import numpy as np import matplotlib.pyplot as plt import random dft = df.sortlevel(2).transpose() fig, ax = plt.subplots() x = [] y = [] y_err = [] scatterx = [] scattery = [] for n, col in enumerate(dft.columns): x.append(n) y.append(np.mean(dft[col])) y_err.append(np.std(dft[col])) for v in dft[col]: scattery.append(v) scatterx.append(n + ((random.random()-0.5)*0.05)) p = plt.plot(x, y, label=label) color=p[0].get_color() plt.errorbar(x, y, yerr=y_err, fmt=color) plt.scatter(scatterx, scattery, alpha=0.3, color=color) plt.legend(loc=2) ax.set_xticks(range(len(dft.columns))) ax.set_xticklabels([x[2] for x in dft.columns]) plt.show() 

Esto mostrará un gráfico de líneas con barras de error y puntos de datos. Puede haber algunos errores en el código anterior. Lo copié y simplifiqué un poco antes de pegar aquí.