Создайте гистограмму с накоплением процентов и аннотируйте ее количеством

Создайте гистограмму с накоплением процентов и аннотируйте ее количеством

У меня есть эти данные (df), я получаю их проценты (data=rel) и строю гистограмму с накоплением.

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

Мой код на данный момент:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from csv import reader
import seaborn as sns

df = pd.DataFrame({'IL':['Balıkesir', 'Bursa', 'Çanakkale', 'Edirne', 'İstanbul', 'Kırklareli', 'Kocaeli', 'Sakarya','Tekirdağ','Yalova'],'ENGELLIUYGUN':[7,13,3,1,142,1,14,1,2,2],'ENGELLIUYGUNDEGIL':[1,5,0,0,55,0,3,0,1,0]})
iller=df.iloc[:,[0]]

df_total = df["ENGELLIUYGUN"] + df["ENGELLIUYGUNDEGIL"]
df_rel = df[df.columns[1:]].div(df_total, 0)*100

rel=[]
rel=pd.DataFrame(df_rel)
rel['İller'] = iller

d=df.iloc[:,[1]] #I want to add these values to the center of blue bars.
f=df.iloc[:,[2]] #I want to add these values to the center of green bars.

sns.set_theme (style='whitegrid')

ax=rel.plot(x='İller',kind='bar', stacked=True, color=["#3a88e2","#5c9e1e"], label=("Uygun","Uygun Değil"))

plt.legend(["Evet","Hayır"],fontsize=8, bbox_to_anchor=(1, 0.5))

plt.xlabel('...........',fontsize=12)
plt.ylabel('..........',fontsize=12)
plt.title('.............',loc='center',fontsize=14)
plt.ylim(0,100)
ax.yaxis.grid(color='gray', linestyle='dashed')

plt.show()

У меня есть это на данный момент:

Создайте гистограмму с накоплением процентов и аннотируйте ее количеством

Я хочу точно такой же стиль этой фотографии:

Создайте гистограмму с накоплением процентов и аннотируйте ее количеством

Я использую ноутбук Anaconda-Jupyter.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
129
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

for i in range(len(d)):
    ax.text(i, df_rel.iloc[i,0]/2, d.iloc[i,0], ha='center', fontweight='bold', color='#ffff00', fontsize='small')
    ax.text(i, 50+df_rel.iloc[i,0]/2, f.iloc[i,0], ha='center', fontweight='bold', color='#400040', fontsize='small')

вы получаете этот результат

Вы, конечно, можете изменить цвет, размер, положение и т. д. (я хорошо известен полным отсутствием хорошего настроения в этом отношении). Но также примите какое-нибудь произвольное правило, например, не печатайте «0» (преимущество делать что-то явно: ваш код, ваше правило; вам не нужно бороться с существующим API, чтобы убедить его сделать это по-вашему).

Спасибо за ваш ответ!! Но поскольку я новичок, я не могу легко понять. Какой смысл в df_rel.iloc[i,0]/2 и 50+df_rel.iloc[i,0]/2 ? Также f.iloc[i,0] ноль в этом? Может глупый вопрос, не знаю...

Melisa 09.12.2022 07:44
Ответ принят как подходящий
  • Ответ: я хочу добавить значения (непроцентные значения) в центры каждого столбца, но из моего первого фрейма данных.
  • Правильный способ аннотировать бары — использовать .bar_label , как объясняется в этом ответе.
    • Значения из df можно отправлять в параметр label= вместо процентов.
  • Этот ответ показывает, как кратко рассчитать проценты, но отображает количество и аннотирует с процентами и значениями, тогда как этот OP хочет отображать проценты по оси Y и аннотировать с количеством.
  • Этот ответ показывает, как разместить легенду внизу графика.
  • Этот ответ показывает, как отформатировать метки осей в процентах.
  • См. pandas.DataFrame.plot для объяснения доступных параметров.
  • Я использую ноутбук Anaconda-Jupyter. Все из комментария, # процент графика; ..., должны находиться в той же ячейке блокнота.
  • Протестировано в python 3.11, pandas 1.5.2, matplotlib 3.6.2
import pandas as pd
import matplotlib.ticker as tkr

# sample data
df = pd.DataFrame({'IL': ['Balıkesir', 'Bursa', 'Çanakkale', 'Edirne', 'İstanbul', 'Kırklareli', 'Kocaeli', 'Sakarya','Tekirdağ','Yalova'],
                   'ENGELLIUYGUN': [7, 13, 3, 1, 142, 1, 14, 1, 2, 2],
                   'ENGELLIUYGUNDEGIL': [1, 5, 0, 0, 55, 0, 3, 0, 1, 0]})

# set IL as the index
df = df.set_index('IL')

# calculate the percent
per = df.div(df.sum(axis=1), axis=0).mul(100)

# plot percent; adjust rot= for the rotation of the xtick labels
ax = per.plot(kind='bar', stacked=True, figsize=(10, 8), rot=0,
              color=['#3a88e2', '#5c9e1e'], yticks=range(0, 101, 10),
              title='my title', ylabel='', xlabel='')

# move the legend
ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.05), ncol=2, frameon=False)

# format the y-axis tick labels
ax.yaxis.set_major_formatter(tkr.PercentFormatter())

# iterate through the containers
for c in ax.containers:
    
    # get the current segment label (a string); corresponds to column / legend
    col = c.get_label()
    
    # use label to get the appropriate count values from df
    # customize the label to account for cases when there might not be a bar section
    labels = [v if v > 0 else '' for v in df[col]]
    # the following will also work
    # labels = df[col].replace(0, '')
    
    # add the annotation
    ax.bar_label(c, labels=labels, label_type='center', fontweight='bold')

Альтернативная реализация аннотации

  • Поскольку имена столбцов в df и per одинаковы, их можно извлечь непосредственно из per.
# iterate through the containers and per column names
for c, col in zip(ax.containers, per):
    
    # add the annotations with custom labels from df
    ax.bar_label(c, labels=df[col].replace(0, ''), label_type='center', fontweight='bold')

Другие вопросы по теме