has distplot catplot categorical barplot attribute python pandas matplotlib data-visualization seaborn

python - distplot - seaborn histogram



Seaborn: countplot() con frecuencias (3)

Tengo un Pandas DataFrame con una columna llamada "AXLES", que puede tomar un valor entero entre 3-12. Estoy tratando de usar la opción countplot () de Seaborn para lograr el siguiente diagrama:

  1. El eje y izquierdo muestra las frecuencias de estos valores que ocurren en los datos. Los ejes extendidos son [0% -100%], marcas de verificación en cada 10%.
  2. el eje y derecho muestra los recuentos reales, los valores corresponden a las marcas de verificación determinadas por el eje y izquierdo (marcado cada 10%).
  3. El eje x muestra las categorías para los gráficos de barras [3, 4, 5, 6, 7, 8, 9, 10, 11, 12].
  4. La anotación en la parte superior de las barras muestra el porcentaje real de esa categoría.

El siguiente código me da la siguiente gráfica, con conteos reales, pero no pude encontrar una forma de convertirlos en frecuencias. Puedo obtener las frecuencias usando df.AXLES.value_counts()/len(df.index) pero no estoy seguro de cómo conectar esta información en el countplot() de countplot() de Seaborn countplot() .

También encontré una solución para las anotaciones, pero no estoy seguro de si esa es la mejor implementación.

¡Cualquier ayuda sería apreciada!

Gracias

plt.figure(figsize=(12,8)) ax = sns.countplot(x="AXLES", data=dfWIM, order=[3,4,5,6,7,8,9,10,11,12]) plt.title(''Distribution of Truck Configurations'') plt.xlabel(''Number of Axles'') plt.ylabel(''Frequency [%]'') for p in ax.patches: ax.annotate(''%{:.1f}''.format(p.get_height()), (p.get_x()+0.1, p.get_height()+50))

EDITAR:

Me acerqué a lo que necesito con el siguiente código, usando el diagrama de barras de Pandas, abandonando Seaborn. Siento que estoy usando tantas soluciones alternativas, y tiene que haber una manera más fácil de hacerlo. Los problemas con este enfoque:

  • No existe una palabra clave de order en la función de diagrama de barras de Pandas como la cuenta de diagrama de Seaborn (), por lo que no puedo trazar todas las categorías de 3-12 como lo hice en la tabla de cálculo de conteo (). Necesito que se muestren incluso si no hay datos en esa categoría.
  • El eje y secundario ensucia las barras y la anotación por alguna razón (vea las líneas de cuadrícula blancas dibujadas sobre el texto y las barras).

    plt.figure(figsize=(12,8)) plt.title(''Distribution of Truck Configurations'') plt.xlabel(''Number of Axles'') plt.ylabel(''Frequency [%]'') ax = (dfWIM.AXLES.value_counts()/len(df)*100).sort_index().plot(kind="bar", rot=0) ax.set_yticks(np.arange(0, 110, 10)) ax2 = ax.twinx() ax2.set_yticks(np.arange(0, 110, 10)*len(df)/100) for p in ax.patches: ax.annotate(''{:.2f}%''.format(p.get_height()), (p.get_x()+0.15, p.get_height()+1))


Creo que primero puedes configurar los ticks principales y manualmente y luego modificar cada etiqueta

dfWIM = pd.DataFrame({''AXLES'': np.random.randint(3, 10, 1000)}) total = len(dfWIM)*1. plt.figure(figsize=(12,8)) ax = sns.countplot(x="AXLES", data=dfWIM, order=[3,4,5,6,7,8,9,10,11,12]) plt.title(''Distribution of Truck Configurations'') plt.xlabel(''Number of Axles'') plt.ylabel(''Frequency [%]'') for p in ax.patches: ax.annotate(''{:.1f}%''.format(100*p.get_height()/total), (p.get_x()+0.1, p.get_height()+5)) #put 11 ticks (therefore 10 steps), from 0 to the total number of rows in the dataframe ax.yaxis.set_ticks(np.linspace(0, total, 11)) #adjust the ticklabel to the desired format, without changing the position of the ticks. _ = ax.set_yticklabels(map(''{:.1f}%''.format, 100*ax.yaxis.get_majorticklocs()/total))


Lo hice funcionar usando el matplotlib de barras del núcleo matplotlib . Obviamente no tenía sus datos, pero adaptarlos a los suyos debería ser sencillo.

Acercarse a, aproximarse

matplotlib el eje gemelo de matplotlib y matplotlib los datos como barras en el segundo objeto Axes . El resto no es más que jugar un poco para acertar y hacer anotaciones.

Espero que esto ayude.

Código

import pandas as pd import numpy as np import matplotlib.pyplot as plt import matplotlib from mpl_toolkits.mplot3d import Axes3D import seaborn as sns tot = np.random.rand( 1 ) * 100 data = np.random.rand( 1, 12 ) data = data / sum(data,1) * tot df = pd.DataFrame( data ) palette = sns.husl_palette(9, s=0.7 ) ### Left Axis # Plot nothing here, autmatically scales to second axis. fig, ax1 = plt.subplots() ax1.set_ylim( [0,100] ) # Remove grid lines. ax1.grid( False ) # Set ticks and add percentage sign. ax1.yaxis.set_ticks( np.arange(0,101,10) ) fmt = ''%.0f%%'' yticks = matplotlib.ticker.FormatStrFormatter( fmt ) ax1.yaxis.set_major_formatter( yticks ) ### Right Axis # Plot data as bars. x = np.arange(0,9,1) ax2 = ax1.twinx() rects = ax2.bar( x-0.4, np.asarray(df.loc[0,3:]), width=0.8 ) # Set ticks on x-axis and remove grid lines. ax2.set_xlim( [-0.5,8.5] ) ax2.xaxis.set_ticks( x ) ax2.xaxis.grid( False ) # Set ticks on y-axis in 10% steps. ax2.set_ylim( [0,tot] ) ax2.yaxis.set_ticks( np.linspace( 0, tot, 11 ) ) # Add labels and change colors. for i,r in enumerate(rects): h = r.get_height() r.set_color( palette[ i % len(palette) ] ) ax2.text( r.get_x() + r.get_width()/2.0, / h + 0.01*tot, / r''%d%%''%int(100*h/tot), ha = ''center'' )


Puede hacer esto haciendo un eje twinx para las frecuencias. Puede cambiar los dos ejes y para que las frecuencias permanezcan a la izquierda y los recuentos a la derecha, pero sin tener que volver a calcular el eje de recuento (aquí usamos tick_left() y tick_left() para mover los ticks y set_label_position para mover el etiquetas de eje

Luego puede configurar los ticks utilizando el módulo matplotlib.ticker , específicamente ticker.MultipleLocator y ticker.LinearLocator .

En cuanto a sus anotaciones, puede obtener las ubicaciones x e y para las 4 esquinas de la barra con patch.get_bbox().get_points() . Esto, junto con la configuración correcta de la alineación horizontal y vertical, significa que no necesita agregar ningún desplazamiento arbitrario a la ubicación de la anotación.

Finalmente, debe desactivar la cuadrícula para el eje gemelo, para evitar que aparezcan líneas de cuadrícula en la parte superior de las barras ( ax2.grid(None) )

Aquí hay un script de trabajo:

import pandas as pd import matplotlib.pyplot as plt import numpy as np import seaborn as sns import matplotlib.ticker as ticker # Some random data dfWIM = pd.DataFrame({''AXLES'': np.random.normal(8, 2, 5000).astype(int)}) ncount = len(dfWIM) plt.figure(figsize=(12,8)) ax = sns.countplot(x="AXLES", data=dfWIM, order=[3,4,5,6,7,8,9,10,11,12]) plt.title(''Distribution of Truck Configurations'') plt.xlabel(''Number of Axles'') # Make twin axis ax2=ax.twinx() # Switch so count axis is on right, frequency on left ax2.yaxis.tick_left() ax.yaxis.tick_right() # Also switch the labels over ax.yaxis.set_label_position(''right'') ax2.yaxis.set_label_position(''left'') ax2.set_ylabel(''Frequency [%]'') for p in ax.patches: x=p.get_bbox().get_points()[:,0] y=p.get_bbox().get_points()[1,1] ax.annotate(''{:.1f}%''.format(100.*y/ncount), (x.mean(), y), ha=''center'', va=''bottom'') # set the alignment of the text # Use a LinearLocator to ensure the correct number of ticks ax.yaxis.set_major_locator(ticker.LinearLocator(11)) # Fix the frequency range to 0-100 ax2.set_ylim(0,100) ax.set_ylim(0,ncount) # And use a MultipleLocator to ensure a tick spacing of 10 ax2.yaxis.set_major_locator(ticker.MultipleLocator(10)) # Need to turn the grid on ax2 off, otherwise the gridlines end up on top of the bars ax2.grid(None) plt.savefig(''snscounter.pdf'')