Сортировка порядка штрихов в пунктах pandas/matplotlib bar

Как Pythonic/pandas способ сортировки "уровней" в столбце в pandas, чтобы дать конкретное упорядочение баров в гистограмме.

Например, учитывая:

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

Я могу сгенерировать следующую пару графиков:

Disordered bar charts

Порядок баров соответствует порядку строк.

Каков наилучший способ переупорядочения данных, чтобы на столбчатых диаграммах были столбцы, упорядоченные Mon-Sun?

ОБНОВЛЕНИЕ: это мусорное решение работает, но оно далеко не элегантно, поскольку использует дополнительную сортировочную колонку:

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

ДАЛЬНЕЙШАЯ ОБОБЩЕНИЕ:

Есть ли решение, которое также исправляет порядок баров на "уклоненном" баровом графике:

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

enter image description here

Ответ 1

Вам нужно будет предоставить сопоставление, чтобы указать, как упорядочить имена дней. (Если бы они были сохранены как правильные даты, были бы другие способы сделать это.)

Обновлено:

Создайте ключ. Вы можете явно выписать словарь или использовать что-то умное, как это объяснение dict.

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

И сортировка проста:

df.iloc[key.argsort()]

Ответ 2

Я знаю, что этот ответ запоздал, но упрощенное решение для двух представленных случаев без использования словаря/отображений было бы чем-то вроде того, что я опубликовал ниже.

Установка "дня" в качестве индекса позволяет использовать .loc для выбора данных в определенном порядке.

1) Для двух отдельных участков

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) Для сводного примера с уклоненным графиком:

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

обратите внимание, что сводная таблица приводит к тому, что день уже находится в индексе, поэтому вы можете снова использовать .loc здесь.

Редактировать: в этих решениях рекомендуется использовать .loc вместо .ix..Ix будет устаревшим и может иметь странные результаты, когда имена столбцов и индексы являются числами.

Ответ 3

Я представлю следующий код, чтобы продлить ответ Дэна, чтобы обратиться к разделу "ДАЛЬНЕЙШЕЕ ОБЩИЕ ПОЛОЖЕНИЯ" в вопросе ОП. Во-первых, полный пример простого случая (всего одна переменная), основанная на решении Дэна:

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

И теперь мы используем тот же метод упорядочения для упорядочения строк сводной таблицы (вместо строк, созданных 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 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')

Результат показан ниже:

введите описание изображения здесь