Аннотирование Барплота Панд дополнительным значением, не связанным с осями x и y графика

#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()
 

bar_label на барплоте панд

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. Да, вероятно, проще всего просто установить это значение равным нулю.