Clasificación del orden de barras en los gráficos de barras pandas / matplotlib

¿Cuál es la forma Pythonic / pandas de clasificar los “niveles” dentro de una columna en pandas para dar un orden específico de barras en el gráfico de barras?

Por ejemplo, dado:

import pandas as pd df = pd.DataFrame({ 'group': ['a', 'a', 'a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'b', 'b', 'b'], 'day': ['Mon', 'Tues', 'Fri', 'Thurs', 'Sat', 'Sun', 'Weds', 'Fri', 'Sun', 'Thurs', 'Sat', 'Weds', 'Mon', 'Tues'], 'amount': [1, 2, 4, 2, 1, 1, 2, 4, 5, 3, 4, 2, 1, 3]}) dfx = df.groupby(['group']) dfx.plot(kind='bar', x='day') 

Puedo generar el siguiente par de plots:

Gráficos de barras desordenados

El orden de las barras sigue el orden de las filas.

¿Cuál es la mejor manera de reordenar los datos para que los gráficos de barras tengan barras ordenadas de lunes a domingo?

ACTUALIZACIÓN: esta solución de basura funciona, pero está lejos de ser elegante en la forma en que utiliza una columna de clasificación adicional:

 df2 = pd.DataFrame({ 'day': ['Mon', 'Tues', 'Weds', 'Thurs', 'Fri', 'Sat', 'Sun'], 'num': [0, 1, 2, 3, 4, 5, 6]}) df = pd.merge(df, df2, on='day') df = df.sort_values('num') dfx = df.groupby(['group']) dfx.plot(kind='bar', x='day') 

MAYOR GENERALIZACIÓN:

¿Existe alguna solución que también corrija el orden de las barras en un gráfico de barras “esquivado”:

 df.pivot('day', 'group', 'amount').plot(kind='bar') 

introduzca la descripción de la imagen aquí

Tendrá que proporcionar una asignación para especificar cómo ordenar los nombres de los días. (Si se almacenaran como fechas apropiadas, habría otras formas de hacerlo).

Actualizado:

Construye la llave. Podría escribir un diccionario explícitamente o usar algo inteligente como esta comprensión de dictado.

 weekdays = ['Mon', 'Tues', 'Weds', 'Thurs', 'Fri', 'Sat', 'Sun'] mapping = {day: i for i, day in enumerate(weekdays)} key = df['day'].map(mapping) 

Y la clasificación es simple:

 df.iloc[key.argsort()] 

Sé que esta respuesta es tardía, pero una solución simplista para los dos casos presentados, sin el uso de un diccionario / asignaciones sería algo como lo que he publicado a continuación.

Establecer “día” como un índice le permite usar .loc para seleccionar datos en un orden específico

Advertencia: usar un índice no único en pandas es más lento que usar uno único

1) Para las dos plots separadas.

 df=pd.DataFrame({'group':['a','a','a','a','a','a','a','b','b','b','b','b','b','b'], 'day':['Mon','Tues','Fri','Thurs','Sat','Sun','Weds','Fri','Sun','Thurs','Sat','Weds','Mon','Tues'], 'amount':[1,2,4,2,1,1,2,4,5,3,4,2,1,3]}) order = ['Mon', 'Tues', 'Weds','Thurs','Fri','Sat','Sun']` df.set_index('day').loc[order].groupby('group').plot(kind='bar') 

2) Para el ejemplo de pivote con el diagtwig esquivado:

 order = ['Mon', 'Tues', 'Weds','Thurs','Fri','Sat','Sun'] df.pivot('day','group','amount').loc[order].plot(kind='bar') 

tenga en cuenta que los resultados dynamics en el día ya están en el índice, por lo que puede usar .loc aquí nuevamente.

Edición: es una práctica recomendada utilizar .loc en lugar de .ix en estas soluciones, .ix quedará en desuso y puede tener resultados extraños cuando los nombres de las columnas y los índices son números.

Proporcionaré el código de abajo para extender la respuesta de Dan a la sección “GENERALIZACIÓN ADICIONAL” de la pregunta del OP. Primero, un ejemplo completo para el caso simple (solo una variable) basado en la solución de Dan:

 import pandas as pd # Create dataframe df=pd.DataFrame({ 'group':['a','a','a','a','a','a','a','b','b','b','b','b','b','b'], 'day':['Mon','Tues','Fri','Thurs','Sat','Sun','Weds','Fri','Sun','Thurs','Sat','Weds','Mon','Tues'], 'amount':[1,2,4,2,1,1,2,4,5,3,4,2,1,3] }) # Calculate the total amount for each day df_grouped = df.groupby(['day']).sum().amount.reset_index() # Use Dan's trick to order days names in the table created by groupby weekdays = ['Mon', 'Tues', 'Weds', 'Thurs', 'Fri', 'Sat', 'Sun'] mapping = {day: i for i, day in enumerate(weekdays)} key = df_grouped['day'].map(mapping) df_grouped = df_grouped.iloc[key.argsort()] # Draw the bar chart df_grouped.plot(kind='bar', x='day') 

Y ahora, usamos la misma técnica de ordenamiento para ordenar las filas de la tabla dinámica (en lugar de las filas creadas por groupby).

 import pandas as pd # Create dataframe df=pd.DataFrame({ 'group':['a','a','a','a','a','a','a','b','b','b','b','b','b','b'], 'day':['Mon','Tues','Fri','Thurs','Sat','Sun','Weds','Fri','Sun','Thurs','Sat','Weds','Mon','Tues'], 'amount':[1,2,4,2,1,1,2,4,5,3,4,2,1,3] }) # Get the amount for each day AND EACH GROUP df_grouped = df.groupby(['group', 'day']).sum().amount.reset_index() # Create pivot table to get the total amount for each day and each in the proper format to plot multiple series with pandas df_pivot = df_grouped.pivot('day','group','amount').reset_index() # Use Dan's trick to order days names in the table created by PIVOT (not the table created by groupby, in the previous example) weekdays = ['Mon', 'Tues', 'Weds', 'Thurs', 'Fri', 'Sat', 'Sun'] mapping = {day: i for i, day in enumerate(weekdays)} key = df_pivot['day'].map(mapping) df_pivot = df_pivot.iloc[key.argsort()] # Draw the bar chart df_pivot.plot(kind='bar', x='day') 

El resultado se muestra a continuación:

introduzca la descripción de la imagen aquí