#python #pandas #dataframe #matplotlib
Вопрос:
Я создаю график панд с необработанными подсчетами, представленными на графике, однако я хотел бы аннотировать бары с помощью pct этих подсчетов в целом. Я видел много людей, использующих ax.patches
методы для аннотирования, но мои значения не связаны с get_height
реальными столбцами.
Вот некоторые данные об игрушках. Произведенный сюжет будет представлять собой отдельные отсчеты определенного типа. Тем не менее, я хочу добавить аннотации над этой конкретной строкой, которые представляют общую сумму pct для этого конкретного типа для всех типов имени этого человека.
Дайте мне знать, если вам понадобятся дополнительные разъяснения.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
d = {'ID': [1,1,1,2,2,3,3,3,4],
'name': ['bob','bob','bob','shelby','shelby','jordan','jordan','jordan','jeff'],
'type': ['type1','type2','type4','type1','type6','type5','type8','type2',None]}
df: pd.DataFrame = pd.DataFrame(data=d)
df_pivot: pd.DataFrame = df.pivot_table(index='type', columns=['name'], values='ID', aggfunc={'ID': np.sum}).fillna(0)
# create percent totals of the specific type's row of the total
df_pivot['bob_pct_total']: pd.Series = (df_pivot['bob']/df_pivot['bob'].sum()).mul(100).round(1)
df_pivot['shelby_pct_total']: pd.Series = (df_pivot['shelby']/df_pivot['shelby'].sum()).mul(100).round(1)
df_pivot['jordan_pct_total']: pd.Series = (df_pivot['jordan']/df_pivot['jordan'].sum()).mul(100).round(1)
df_pivot.head(10)
name bob jordan shelby bob_pct_total shelby_pct_total jordan_pct_total
type
type1 1.0 0.0 2.0 33.3 50.0 0.0
type2 1.0 3.0 0.0 33.3 0.0 33.3
type4 1.0 0.0 0.0 33.3 0.0 0.0
type5 0.0 3.0 0.0 0.0 0.0 33.3
type6 0.0 0.0 2.0 0.0 50.0 0.0
type8 0.0 3.0 0.0 0.0 0.0 33.3
fig, ax = plt.subplots(figsize=(15,15))
df_pivot.plot(kind='bar', y=['bob','jordan','shelby'], ax=ax)
Комментарии:
1. Вы можете использовать
get_height()
для вычисления позиции, а затем написать другую любую другую строку.
Ответ №1:
Вы можете использовать старый подход, проходя по столбцам, используя высоту для размещения любого текста, который вы хотите. Начиная с matplotlib 3.4.0, также появилась новая функция bar_label
, которая удаляет большую часть шаблона:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
d = {'ID': [1, 1, 1, 2, 2, 3, 3, 3, 4],
'name': ['bob', 'bob', 'bob', 'shelby', 'shelby', 'jordan', 'jordan', 'jordan', 'jeff'],
'type': ['type1', 'type2', 'type4', 'type1', 'type6', 'type5', 'type8', 'type2', None]}
df: pd.DataFrame = pd.DataFrame(data=d)
df_pivot: pd.DataFrame = df.pivot_table(index='type', columns=['name'], values='ID', aggfunc={'ID': np.sum}).fillna(0)
# create percent totals of the specific type's row of the total
df_pivot['bob_pct_total']: pd.Series = (df_pivot['bob'] / df_pivot['bob'].sum()).mul(100).round(1)
df_pivot['shelby_pct_total']: pd.Series = (df_pivot['shelby'] / df_pivot['shelby'].sum()).mul(100).round(1)
df_pivot['jordan_pct_total']: pd.Series = (df_pivot['jordan'] / df_pivot['jordan'].sum()).mul(100).round(1)
fig, ax = plt.subplots(figsize=(12, 5))
columns = ['bob', 'jordan', 'shelby']
df_pivot.plot(kind='bar', y=['bob', 'jordan', 'shelby'], rot=0, ax=ax)
for bars, col in zip(ax.containers, ['bob_pct_total', 'jordan_pct_total', 'shelby_pct_total']):
ax.bar_label(bars, labels=['' if val == 0 else f'{val}' for val in df_pivot[col]])
plt.tight_layout()
plt.show()
PS: Чтобы пропустить маркировку первых полос, вы можете поэкспериментировать с:
for bars, col in zip(ax.containers, ['bob_pct_total', 'jordan_pct_total', 'shelby_pct_total']):
labels=['' if val == 0 else f'{val}' for val in df_pivot[col]]
labels[0] = ''
ax.bar_label(bars, labels=labels)
Комментарии:
1. Это действительно хорошо. Я использовал более старую версию Matplotlib. Только что обновлено, и это действительно помогает. Я всегда находил аннотации в Matplotlib действительно громоздкими и неприятными, но это идеально!
2. Это может быть немного нишевым, но если бы я хотел опустить одну из аннотаций группы баров, как бы я мог это сделать? Поскольку контейнеры содержат 6 художников, мне нужно было бы опустить первого художника для каждого контейнера. Итак, в принципе, если бы я хотел, чтобы аннотации «type1» были скрыты, как я мог бы продолжить? Я полагаю, что я мог бы просто вручную установить эти значения в 0, чтобы при построении графика они просто оставались пустыми.
3. Да, вероятно, проще всего просто установить это значение равным нулю.