且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何绘制带有多个组注释的堆叠条形图

更新时间:2023-11-21 23:03:46

  • 这更容易实现为堆叠条形图,因此,使用pandas.crosstab重塑数据帧,并使用pandas.DataFrame.plotkind='bar'stacked=True绘制
    • 这不应该用plt.hist来实现,因为它比较复杂,直接使用 pandas 图方法更容易。
    • 此外,当x值是连续的数字范围,而不是离散的类别值时,直方图更合适。
  • ct.iloc[:, :-1]选择除最后一列'tot'以外的所有列以条形图绘制。
  • 使用matplotlib.pyplot.bar_label添加批注
    • ax.bar_label(ax.containers[2], padding=3)默认情况下使用label_type='edge',这会导致用累积和来注释边('center'用面片值注释),如answer所示。
      • ax.containers[2]中的[2]只选择顶部的容器来注释累计和。containers从底部开始索引为0。
    • 有关其他详细信息和示例,请参阅此answer
    • 这个answer展示了如何在没有.bar_label的情况下用旧方法做批注。我不推荐这样做。
    • answer显示如何自定义标签,以防止为给定大小以下的值添加批注。
  • 测试于python 3.10pandas 1.3.5matplotlib 3.5.1

加载和塑造DataFrame

import pandas as pd

# load from github repo link
url = 'https://raw.githubusercontent.com/jpiedehierroa/files/main/Libro1.csv'
df = pd.read_csv(url) 

# reshape the dataframe
ct = pd.crosstab(df.countries, df.type)

# total medals per country, which is necessary to sort the bars
ct['tot'] = ct.sum(axis=1)

# sort
ct = ct.sort_values(by='tot', ascending=False)

# display(ct)
type         bronze  gold  silver  tot
countries                             
USA              33    39      41  113
China            18    38      32   88
ROC              23    20      28   71
GB               22    22      21   65
Japan            17    27      14   58
Australia        22    17       7   46
Italy            20    10      10   40
Germany          16    10      11   37
Netherlands      14    10      12   36
France           11    10      12   33

绘图

colors = ("#CD7F32", "silver", "gold")
cd = dict(zip(ct.columns, colors))

# plot the medals columns
title = 'Country Medal Count for Tokyo 2020'
ax = ct.iloc[:, :-1].plot(kind='bar', stacked=True, color=cd, title=title,
                          figsize=(12, 5), rot=0, width=1, ec='k' )

# annotate each container with individual values
for c in ax.containers:
    ax.bar_label(c, label_type='center')
    
# annotate the top containers with the cumulative sum
ax.bar_label(ax.containers[2], padding=3)

# pad the spacing between the number and the edge of the figure
ax.margins(y=0.1)

  • 用总和批注顶部的另一种方法是对自定义标签使用'tot'列,但如图所示,这不是必需的。
labels = ct.tot.tolist()
ax.bar_label(ax.containers[2], labels=labels, padding=3)