Упорядочение элементов в гистограмме с накоплением панд - PullRequest
0 голосов
/ 25 февраля 2019

Я пытаюсь отобразить информацию о части дохода домохозяйства, полученного в конкретной отрасли в 5 округах региона.

Я использовал groupby, чтобы отсортировать информацию в моем фрейме данных по районам:

df = df_orig.groupby('District')['Portion of income'].value_counts(dropna=False)
df = df.groupby('District').transform(lambda x: 100*x/sum(x))
df = df.drop(labels=math.nan, level=1)
ax = df.unstack().plot.bar(stacked=True, rot=0)
ax.set_ylim(ymax=100)

display(df.head())

    District  Portion of income
    A         <25%                 12.121212
              25 - 50%              9.090909
              50 - 75%              7.070707
              75 - 100%             2.020202

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

  • 25 - 50%
  • 50 - 75%
  • 75 - 100%
  • <25% </li>
  • Не уверен

Я понимаю, что они отсортированы в алфавитном порядке, и было бы любопытно, если бы был способ установить пользовательский порядок.Чтобы быть интуитивно понятным, я бы хотел, чтобы порядок был (опять же, начиная с нижней части бара):

  • Не уверен
  • <25% </li>
  • 25 -50%
  • 50 - 75%
  • 75 - 100%

Тогда я быхотел бы перевернуть легенду, чтобы отобразить реверс этого порядка (то есть, я хотел бы, чтобы легенда имела 75 - 100 сверху, так как это будет наверху столбцов).

1 Ответ

0 голосов
/ 26 февраля 2019

Чтобы наложить пользовательский порядок сортировки на категории дохода, один из способов - преобразовать их в CategoricalIndex.

Чтобы изменить порядок записей легенды matplotlib, используйте метод get_legend_handles_labels из этого SOвопрос: обратный порядок легенды сюжет панды

import pandas as pd
import numpy as np
import math

np.random.seed(2019)

# Hard-code the custom ordering of categories
categories = ['unsure', '<25%', '25 - 50%', '50 - 75%', '75 - 100%']

# Generate some example data
# I'm not sure if this matches your input exactly
df_orig = pd.DataFrame({'District': pd.np.random.choice(list('ABCDE'), size=100), 
                        'Portion of income': np.random.choice(categories + [np.nan], size=100)})

# Unchanged from your code. Note that value_counts() returns a 
# Series, but you name it df
df = df_orig.groupby('District')['Portion of income'].value_counts(dropna=False)
df = df.groupby('District').transform(lambda x: 100*x/sum(x))

# In my example data, np.nan was cast to the string 'nan', so 
# I have to drop it like this
df = df.drop(labels='nan', level=1)

# Instead of plotting right away, unstack the MultiIndex
# into columns, then convert those columns to a CategoricalIndex 
# with custom sort order
df = df.unstack()

df.columns = pd.CategoricalIndex(df.columns.values, 
                                 ordered=True, 
                                 categories=categories)

# Sort the columns (axis=1) by the new categorical ordering
df = df.sort_index(axis=1)

# Plot
ax = df.plot.bar(stacked=True, rot=0)
ax.set_ylim(ymax=100)

# Matplotlib idiom to reverse legend entries 
handles, labels = ax.get_legend_handles_labels()
ax.legend(reversed(handles), reversed(labels))

Output

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...