如何在条形图上添加价值标签

我被困在了一个感觉应该相对容易的东西上。下面我带来的代码是基于我正在进行的一个更大的项目的一个示例。我认为没有理由张贴所有的细节,所以请接受我带来的数据结构原样。

基本上,我正在创建一个条形图,我只是可以弄清楚如何添加价值标签的酒吧(在酒吧的中心,或只是上面)。我一直在网上寻找样本,但是在我自己的代码上没有成功的实现。我认为解决方案是使用“文本”或“注释”,但我: A)不知道使用哪一个(一般来说,还没有想好什么时候使用哪一个)。 B)无法看到获得任何一个来显示值标签。 感谢您的帮助,我的代码如下。 先谢谢你!

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
pd.set_option('display.mpl_style', 'default')
%matplotlib inline


# Bring some raw data.
frequencies = [6, 16, 75, 160, 244, 260, 145, 73, 16, 4, 1]


# In my original code I create a series and run on that,
# so for consistency I create a series from the list.
freq_series = pd.Series(frequencies)


x_labels = [108300.0, 110540.0, 112780.0, 115020.0, 117260.0, 119500.0,
121740.0, 123980.0, 126220.0, 128460.0, 130700.0]


# Plot the figure.
plt.figure(figsize=(12, 8))
fig = freq_series.plot(kind='bar')
fig.set_title('Amount Frequency')
fig.set_xlabel('Amount ($)')
fig.set_ylabel('Frequency')
fig.set_xticklabels(x_labels)

enter image description here

404435 次浏览

首先,freq_series.plot返回一个轴 没有一个数字,所以让我的答案更清楚一点,我已经改变了你的给定代码称为 ax,而不是 fig,以更一致的其他代码示例。

您可以从 ax.patches成员那里获得在情节中生成的条形图的列表。然后,您可以使用 这个 matplotlib画廊的例子中演示的技术,使用 ax.text方法添加标签。

import pandas as pd
import matplotlib.pyplot as plt


# Bring some raw data.
frequencies = [6, 16, 75, 160, 244, 260, 145, 73, 16, 4, 1]
# In my original code I create a series and run on that,
# so for consistency I create a series from the list.
freq_series = pd.Series(frequencies)


x_labels = [
108300.0,
110540.0,
112780.0,
115020.0,
117260.0,
119500.0,
121740.0,
123980.0,
126220.0,
128460.0,
130700.0,
]


# Plot the figure.
plt.figure(figsize=(12, 8))
ax = freq_series.plot(kind="bar")
ax.set_title("Amount Frequency")
ax.set_xlabel("Amount ($)")
ax.set_ylabel("Frequency")
ax.set_xticklabels(x_labels)


rects = ax.patches


# Make some labels.
labels = [f"label{i}" for i in range(len(rects))]


for rect, label in zip(rects, labels):
height = rect.get_height()
ax.text(
rect.get_x() + rect.get_width() / 2, height + 5, label, ha="center", va="bottom"
)


plt.show()

这样就产生了一个带标签的情节,看起来像:

enter image description here

基于 另一个问题的答案中提到的一个特性,我发现了一个非常普遍适用的解决方案,用于在条形图上放置标签。

遗憾的是,其他解决方案在许多情况下不起作用,因为标签和条之间的间距是 以棒的绝对单位给出按条形图的高度缩放。前者只适用于一个很窄的值范围,而后者在一个情节中给出了不一致的间距。两者都不能很好地处理对数轴。

我提出的解决方案独立于比例(即对于小数和大数) ,甚至正确地使用负值和对数比例放置标签,因为它使用可视化单元 points作为偏移量。

我已经添加了一个负数,以显示在这种情况下标签的正确位置。

每个条的高度值用作它的标签。其他标签可以很容易地与 西蒙的 for rect, label in zip(rects, labels)片段一起使用。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt


# Bring some raw data.
frequencies = [6, -16, 75, 160, 244, 260, 145, 73, 16, 4, 1]


# In my original code I create a series and run on that,
# so for consistency I create a series from the list.
freq_series = pd.Series.from_array(frequencies)


x_labels = [108300.0, 110540.0, 112780.0, 115020.0, 117260.0, 119500.0,
121740.0, 123980.0, 126220.0, 128460.0, 130700.0]


# Plot the figure.
plt.figure(figsize=(12, 8))
ax = freq_series.plot(kind='bar')
ax.set_title('Amount Frequency')
ax.set_xlabel('Amount ($)')
ax.set_ylabel('Frequency')
ax.set_xticklabels(x_labels)




def add_value_labels(ax, spacing=5):
"""Add labels to the end of each bar in a bar chart.


Arguments:
ax (matplotlib.axes.Axes): The matplotlib object containing the axes
of the plot to annotate.
spacing (int): The distance between the labels and the bars.
"""


# For each bar: Place a label
for rect in ax.patches:
# Get X and Y placement of label from rect.
y_value = rect.get_height()
x_value = rect.get_x() + rect.get_width() / 2


# Number of points between bar and label. Change to your liking.
space = spacing
# Vertical alignment for positive values
va = 'bottom'


# If value of bar is negative: Place label below bar
if y_value < 0:
# Invert space to place label below
space *= -1
# Vertically align label at top
va = 'top'


# Use Y value as label and format number with one decimal place
label = "{:.1f}".format(y_value)


# Create annotation
ax.annotate(
label,                      # Use `label` as label
(x_value, y_value),         # Place label at end of the bar
xytext=(0, space),          # Vertically shift label by `space`
textcoords="offset points", # Interpret `xytext` as offset in points
ha='center',                # Horizontally center label
va=va)                      # Vertically align label differently for
# positive and negative values.




# Call the function above. All the magic happens there.
add_value_labels(ax)


plt.savefig("image.png")

编辑: 按照 Barnhillec的建议,我已经提取了函数中的相关功能。

这产生了以下结果:

Bar chart with automatically placed labels on each bar

加上对数尺度(以及对输入数据的一些调整,以展示对数缩放) ,结果是这样的:

Bar chart with logarithmic scale with automatically placed labels on each bar

基于上面的答案(太棒了!) ,我们也可以做一个水平条图,只需要做一些调整:

# Bring some raw data.
frequencies = [6, -16, 75, 160, 244, 260, 145, 73, 16, 4, 1]


freq_series = pd.Series(frequencies)


y_labels = [108300.0, 110540.0, 112780.0, 115020.0, 117260.0, 119500.0,
121740.0, 123980.0, 126220.0, 128460.0, 130700.0]


# Plot the figure.
plt.figure(figsize=(12, 8))
ax = freq_series.plot(kind='barh')
ax.set_title('Amount Frequency')
ax.set_xlabel('Frequency')
ax.set_ylabel('Amount ($)')
ax.set_yticklabels(y_labels)
ax.set_xlim(-40, 300) # expand xlim to make labels easier to read


rects = ax.patches


# For each bar: Place a label
for rect in rects:
# Get X and Y placement of label from rect.
x_value = rect.get_width()
y_value = rect.get_y() + rect.get_height() / 2


# Number of points between bar and label. Change to your liking.
space = 5
# Vertical alignment for positive values
ha = 'left'


# If value of bar is negative: Place label left of bar
if x_value < 0:
# Invert space to place label to the left
space *= -1
# Horizontally align label at right
ha = 'right'


# Use X value as label and format number with one decimal place
label = "{:.1f}".format(x_value)


# Create annotation
plt.annotate(
label,                      # Use `label` as label
(x_value, y_value),         # Place label at end of the bar
xytext=(space, 0),          # Horizontally shift label by `space`
textcoords="offset points", # Interpret `xytext` as offset in points
va='center',                # Vertically center label
ha=ha)                      # Horizontally align label differently for
# positive and negative values.


plt.savefig("image.png")

horizontal bar plot with annotations

我需要的酒吧标签太,注意我的 y 轴是有一个放大的视图使用限制的 y 轴。将标签放在条形图顶部的默认计算仍然使用 height (在示例中使用 _ global _ 盘坐标 = False)。但是我想说明的是,标签也可以放在图的底部,在缩放视图中使用 Matplotlib 3.0.2中的全局坐标。希望能帮到别人。

def autolabel(rects,data):
"""
Attach a text label above each bar displaying its height
"""
c = 0
initial = 0.091
offset = 0.205
use_global_coordinate = True


if use_global_coordinate:
for i in data:
ax.text(initial+offset*c, 0.05, str(i), horizontalalignment='center',
verticalalignment='center', transform=ax.transAxes,fontsize=8)
c=c+1
else:
for rect,i in zip(rects,data):
height = rect.get_height()
ax.text(rect.get_x() + rect.get_width()/2., height,str(i),ha='center', va='bottom')

Example output

如果你只想在条形图上添加数据点,你可以很容易地使用:

 for i in range(len(frequencies)): # your number of bars
plt.text(x = x_values[i]-0.25, #takes your x values as horizontal positioning argument
y = y_values[i]+1, #takes your y values as vertical positioning argument
s = data_labels[i], # the labels you want to add to the data
size = 9) # font size of datalabels

如果只想在条形图上方标记数据点,可以使用 plt.annotate ()

我的代码:

import numpy as np
import matplotlib.pyplot as plt


n = [1,2,3,4,5,]
s = [i**2 for i in n]
line = plt.bar(n,s)
plt.xlabel('Number')
plt.ylabel("Square")


for i in range(len(s)):
plt.annotate(str(s[i]), xy=(n[i],s[i]), ha='center', va='bottom')


plt.show()

通过分别指定 'center''bottom'的水平和垂直对齐方式,可以得到居中的注释。

a labelled bar chart

matplotlib v3.4.0开始

  • 使用 < a href = “ https://matplotlib.org/stat/api/_ as _ gen/matplotlib.pyplot.bar _ label.html”rel = “ noReferrer”> matplotlib.pyplot.bar_label
    • 使用参数 label_type设置的默认标签位置为 'edge'。使用 'center'将标签放在条形图中间的中心位置
    • 额外的 kwargs被传递给 Axes.annotate,它接受 Text kwargs
  • 有关其他格式设置选项,请参见 Matplotlib: Bar Label Demo页。
  • 测试 python 3.10pandas 1.4.2matplotlib 3.5.1seaborn 0.11.2
  • ax.containersBarContainer artistslist
    • 对于单个级别的条形图,它是一个 len 1列表,因此使用 [0]
    • 对于分组和堆叠的条形图将有更多的对象在 list
import pandas as pd


# dataframe using frequencies and x_labels from the OP
df = pd.DataFrame({'Frequency': frequencies}, index=x_labels)


# display(df)
Frequency
108300.0          6
110540.0         16
112780.0         75
115020.0        160
117260.0        244


# plot
ax = df.plot(kind='bar', figsize=(12, 8), title='Amount Frequency',
xlabel='Amount ($)', ylabel='Frequency', legend=False)


# annotate
ax.bar_label(ax.containers[0], label_type='edge')


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

enter image description here

ax.bar_label(ax.containers[0], label_type='edge', color='red', rotation=90, fontsize=7, padding=3)

enter image description here

海运轴线平面图

  • 可以看到,这与 ax.bar(...)plt.bar(...)df.plot(kind='bar',...)完全相同
import seaborn as sns


# plot data
fig, ax = plt.subplots(figsize=(12, 8))
sns.barplot(x=x_labels, y=frequencies, ax=ax)


# annotate
ax.bar_label(ax.containers[0], label_type='edge')


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

enter image description here

海运数字水平图

  • seaborn.catplot 接受 data的数据帧。
  • 由于 .catplot是一个 FacetGrid (子图) ,所以唯一的区别是迭代图的每个轴以使用 .bar_labels
import pandas as pd
import seaborn as sns


# load the data into a dataframe
df = pd.DataFrame({'Frequency': frequencies, 'amount': x_labels})


# plot
g = sns.catplot(kind='bar', data=df, x='amount', y='Frequency', height=6, aspect=1.5)


# iterate through the axes
for ax in g.axes.flat:


# annotate
ax.bar_label(ax.containers[0], label_type='edge')


# pad the spacing between the number and the edge of the figure; should be in the loop, otherwise only the last subplot would be adjusted
ax.margins(y=0.1)

enter image description here

matplotlib.axes.Axes.bar

import matplotlib.pyplot as plt


# create the xticks beginning a index 0
xticks = range(len(frequencies))


# plot
fig, ax = plt.subplots(figsize=(12, 8))
ax.bar(x=xticks, height=frequencies)


# label the xticks
ax.set_xticks(xticks, x_labels)


# annotate
ax.bar_label(ax.containers[0], label_type='edge')


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

enter image description here

使用 bar_label的其他示例

相关答案 相关答案
如何创建和注释一个堆叠的比例条形图 如何包装在一个海运数字水平的情节长蜱标签
如何按行计算百分比并对100% 堆叠的条形图进行注释 如何用色相/图例组的百分比来注释条形图
堆叠的条形图意外地标注了条形图高度之和 如何增加百分比顶部的酒吧在海运
如何绘制和注释分组的条形图 如何绘制百分比与海运远景/历史远景/远景
如何用不同于 get _ height ()的值对条形图进行注释 如何以正确的顺序绘制成组的条形图
熊猫栏如何标记所需的价值 使用 matplotlib 绘制两个不同大小的列表时遇到的问题
如何显示分组条形图上面的百分比 如何注释只有一个类别的堆叠酒吧情节
如何设置标签旋转和添加酒吧注释 如何增加子图文本大小和添加自定义条形图注释
如何聚合群体指标和绘制数据与熊猫 如何得到分类数据的分组条形图
如何为多个组绘制带有注释的堆叠条形图 如何从一个广泛的数据框架在一个图形分组条形图
如何注释堆积图或面积图 如何确定所有列中的最后一个值是否大于 n
如何绘制成组酒吧 如何绘制元素计数和添加注释
如何在 matplotlib 的条形图中添加多个数据标签 Seborn Catplot 在条形图上设置值
Python matplotlib 多条 Matplotlib 饼图标签与值不匹配
在 matplotlib 中不能使用 plt 网格 ALPHA 参数 如何水平居中的酒吧情节注释