如何绘制带注释的水平堆积条
How to plot a horizontal stacked bar with annotations
我在 matplotlib Discrete distribution as horizontal bar chart 上使用离散分布示例作为水平条形图示例来创建图表,显示 2017 年什罗普郡选举中的投票份额。
但是,因为我不知道如何操作数据,所以我不得不在程序中手动输入我的数据,这显然是我自己的无知。
我在 CSV 文件中有相关数据,因此可以将其作为数据框加载。
- CSV 的每个选区都有一行,其中每个政党(保守党、LD、工党、绿色、独立党)的投票百分比有 63 列,所以有 5 个实质性列。
我需要有关如何更改数据形式以使其类似于此图表的输入的建议。
我不确定它是什么,但似乎可能是具有键和值的字典类型:
我的数据部分读取:
import pandas as pd
import matplotlib.pyplot as plt
category_names = ['Labour', 'LD', 'Indep', 'Green', 'Tory']
results = {'Abbey': [16, 56, 4,0, 24],
'Albrighton': [0, 0, 32, 0, 68],
'Alveley & Claverley': [0, 25, 0, 0, 75],
'Bagley': [30, 30, 0, 0, 40],
'Battlefield': [34, 0, 0, 9, 57],
'Bayston Hill, Column & Sutton': [53, 4, 3, 7, 33],
'Belle Vue': [43,28,0,5,24]}
# setup dataframe using the dict provided in the OP
df = pd.DataFrame(results, index=category_names)
# display(df)
Abbey Albrighton Alveley & Claverley Bagley Battlefield Bayston Hill, Column & Sutton Belle Vue
Labour 16 0 0 30 34 53 43
LD 56 0 25 30 0 4 28
Indep 4 32 0 0 0 3 0
Green 0 0 0 0 9 7 5
Tory 24 68 75 40 57 33 24
当作为 pandas 数据帧输入时,我试图直接从 csv 文件中获取要格式化的数据。
尝试了值方法和 to_dict
方法,虽然他们得到的数据看起来相似,但并不完全正确。
- 我认为有必要将数据分成键和值,但这是我的知识达到极限的地方。
- 两个选项都使用来自 OP 的 DataFrame
df
。
- 使用
pandas.DataFrame.plot
和参数 stacked=True
选项 1:'Party'
作为 y 轴
使用版本 3.4.2 中的 matplotlib
- 使用
matplotlib.pyplot.bar_label
- 有关其他格式选项,请参阅 matplotlib: Bar Label Demo 页面。
- 在
pandas 1.3.2
、python 3.8
1. 和 matplotlib 3.4.2
1.[ 中测试=85=]
- 1.要求的最低版本
labels = [f'{v.get_width():.0f}' if v.get_width() > 0 else '' for v in c ]
不使用赋值表达式 (:=
)
- 对竖线使用
.get_height()
。
ax = df.plot.barh(stacked=True, cmap='tab10', figsize=(16, 10))
for c in ax.containers:
# format the number of decimal places and replace 0 with an empty string
labels = [f'{w:.0f}' if (w := v.get_width()) > 0 else '' for v in c ]
ax.bar_label(c, labels=labels, label_type='center')
使用matplotlib
3.4.2 之前的版本
- 在循环中提取
.patch
个组件,然后仅绘制大于 0 的值的注释。
# plot
ax = df.plot.barh(stacked=True, cmap='tab10', figsize=(16, 10))
# annotations:
for p in ax.patches:
left, bottom, width, height = p.get_bbox().bounds
if width > 0:
ax.annotate(f'{width:0.0f}', xy=(left+width/2, bottom+height/2), ha='center', va='center')
选项 2:'Ward'
作为 y 轴
- 使用
pandas.DataFrame.T
交换Index
和Columns
'Ward'
现在将成为索引,'Party'
将成为列
# transpose df from the OP so Party is the in the columns and Ward is the index
dft = df.T
# display(dft)
Labour LD Indep Green Tory
Abbey 16 56 4 0 24
Albrighton 0 0 32 0 68
Alveley & Claverley 0 25 0 0 75
Bagley 30 30 0 0 40
Battlefield 34 0 0 9 57
Bayston Hill, Column & Sutton 53 4 3 7 33
Belle Vue 43 28 0 5 24
使用版本 3.4.2 中的 matplotlib
# plot
ax = df.T.plot.barh(stacked=True, figsize=(16, 10))
plt.legend(loc='center left', bbox_to_anchor=(1.0, 0.5))
# annotations:
for c in ax.containers:
# format the number of decimal places and replace 0 with an empty string
labels = [f'{w:.0f}' if (w := v.get_width()) > 0 else '' for v in c ]
ax.bar_label(c, labels=labels, label_type='center')
使用matplotlib
3.4.2 之前的版本
# plot
ax = dft.plot.barh(stacked=True, figsize=(16, 10))
plt.legend(loc='center left', bbox_to_anchor=(1.0, 0.5))
# annotations:
for p in ax.patches:
left, bottom, width, height = p.get_bbox().bounds
if width > 0:
ax.annotate(f'{width:0.0f}', xy=(left+width/2, bottom+height/2), ha='center', va='center')
我在 matplotlib Discrete distribution as horizontal bar chart 上使用离散分布示例作为水平条形图示例来创建图表,显示 2017 年什罗普郡选举中的投票份额。
但是,因为我不知道如何操作数据,所以我不得不在程序中手动输入我的数据,这显然是我自己的无知。
我在 CSV 文件中有相关数据,因此可以将其作为数据框加载。
- CSV 的每个选区都有一行,其中每个政党(保守党、LD、工党、绿色、独立党)的投票百分比有 63 列,所以有 5 个实质性列。
我需要有关如何更改数据形式以使其类似于此图表的输入的建议。
我不确定它是什么,但似乎可能是具有键和值的字典类型:
我的数据部分读取:
import pandas as pd
import matplotlib.pyplot as plt
category_names = ['Labour', 'LD', 'Indep', 'Green', 'Tory']
results = {'Abbey': [16, 56, 4,0, 24],
'Albrighton': [0, 0, 32, 0, 68],
'Alveley & Claverley': [0, 25, 0, 0, 75],
'Bagley': [30, 30, 0, 0, 40],
'Battlefield': [34, 0, 0, 9, 57],
'Bayston Hill, Column & Sutton': [53, 4, 3, 7, 33],
'Belle Vue': [43,28,0,5,24]}
# setup dataframe using the dict provided in the OP
df = pd.DataFrame(results, index=category_names)
# display(df)
Abbey Albrighton Alveley & Claverley Bagley Battlefield Bayston Hill, Column & Sutton Belle Vue
Labour 16 0 0 30 34 53 43
LD 56 0 25 30 0 4 28
Indep 4 32 0 0 0 3 0
Green 0 0 0 0 9 7 5
Tory 24 68 75 40 57 33 24
当作为 pandas 数据帧输入时,我试图直接从 csv 文件中获取要格式化的数据。
尝试了值方法和
to_dict
方法,虽然他们得到的数据看起来相似,但并不完全正确。- 我认为有必要将数据分成键和值,但这是我的知识达到极限的地方。
- 两个选项都使用来自 OP 的 DataFrame
df
。 - 使用
pandas.DataFrame.plot
和参数stacked=True
选项 1:'Party'
作为 y 轴
使用版本 3.4.2 中的 matplotlib
- 使用
matplotlib.pyplot.bar_label
- 有关其他格式选项,请参阅 matplotlib: Bar Label Demo 页面。
- 在
pandas 1.3.2
、python 3.8
1. 和matplotlib 3.4.2
1.[ 中测试=85=]- 1.要求的最低版本
labels = [f'{v.get_width():.0f}' if v.get_width() > 0 else '' for v in c ]
不使用赋值表达式 (:=
)
- 对竖线使用
.get_height()
。
ax = df.plot.barh(stacked=True, cmap='tab10', figsize=(16, 10))
for c in ax.containers:
# format the number of decimal places and replace 0 with an empty string
labels = [f'{w:.0f}' if (w := v.get_width()) > 0 else '' for v in c ]
ax.bar_label(c, labels=labels, label_type='center')
使用matplotlib
3.4.2 之前的版本
- 在循环中提取
.patch
个组件,然后仅绘制大于 0 的值的注释。
# plot
ax = df.plot.barh(stacked=True, cmap='tab10', figsize=(16, 10))
# annotations:
for p in ax.patches:
left, bottom, width, height = p.get_bbox().bounds
if width > 0:
ax.annotate(f'{width:0.0f}', xy=(left+width/2, bottom+height/2), ha='center', va='center')
选项 2:'Ward'
作为 y 轴
- 使用
pandas.DataFrame.T
交换Index
和Columns
'Ward'
现在将成为索引,'Party'
将成为列
# transpose df from the OP so Party is the in the columns and Ward is the index
dft = df.T
# display(dft)
Labour LD Indep Green Tory
Abbey 16 56 4 0 24
Albrighton 0 0 32 0 68
Alveley & Claverley 0 25 0 0 75
Bagley 30 30 0 0 40
Battlefield 34 0 0 9 57
Bayston Hill, Column & Sutton 53 4 3 7 33
Belle Vue 43 28 0 5 24
使用版本 3.4.2 中的 matplotlib
# plot
ax = df.T.plot.barh(stacked=True, figsize=(16, 10))
plt.legend(loc='center left', bbox_to_anchor=(1.0, 0.5))
# annotations:
for c in ax.containers:
# format the number of decimal places and replace 0 with an empty string
labels = [f'{w:.0f}' if (w := v.get_width()) > 0 else '' for v in c ]
ax.bar_label(c, labels=labels, label_type='center')
使用matplotlib
3.4.2 之前的版本
# plot
ax = dft.plot.barh(stacked=True, figsize=(16, 10))
plt.legend(loc='center left', bbox_to_anchor=(1.0, 0.5))
# annotations:
for p in ax.patches:
left, bottom, width, height = p.get_bbox().bounds
if width > 0:
ax.annotate(f'{width:0.0f}', xy=(left+width/2, bottom+height/2), ha='center', va='center')