matplotlib 如何在条形图上添加数值标签?

k4emjkb1  于 2022-12-19  发布在  其他
关注(0)|答案(7)|浏览(631)

我正在创建一个条形图,但我不知道如何在条形图上添加值标签(在条形图的中心或其上方)。
我认为解决方案是使用“文本”或“注解”,但我: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)

如何在条形图上添加值标签(在条形图的中心或其上方)?

7bsow1i6

7bsow1i61#

首先,freq_series.plot返回一个轴,而不是一个图形,所以为了让我的答案更清楚一点,我已经修改了你给出的代码,将其称为ax,而不是fig,以与其他代码示例更一致。
您可以从ax.patches成员获取图中生成的条形列表。然后,您可以使用this matplotlib gallery example中演示的技术,通过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()

这将生成一个带标签的图,如下所示:

9w11ddsr

9w11ddsr2#

基于this answer to another question中提到的一个特性,我发现了一个非常普遍适用的在条形图上放置标签的解决方案。
遗憾的是,其他解决方案在许多情况下不起作用,因为标签和条形图之间的间距为given in absolute units of the barsscaled by the height of the bar。前者仅适用于较窄范围的值,而后者在一个图中给出了不一致的间距。这两种方法都不适用于对数轴。
我提出的解决方案不依赖于比例(即对于小数字和大数字),甚至可以正确地放置负值和对数比例的标签,因为它使用视觉单位points表示偏移量。
我添加了一个负数来展示在这种情况下标签的正确放置。
每个条形的高度值用作其标签。其他标签可以轻松地与Simon's for rect, label in zip(rects, labels) snippet一起使用。

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")
  • Edit:我已经提取了函数中的相关功能,如barnhillec所建议的。*

这将生成以下输出:

使用对数标度(并对输入数据进行一些调整以显示对数标度),结果如下:

htrmnn0y

htrmnn0y3#

根据上面的答案(太棒了!),我们还可以做一个水平条形图,只需做一些调整:

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

5cg8jx4n

5cg8jx4n4#

如果只想标记条形图上方的数据点,可以使用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'的水平和垂直对齐,可以获得居中的注解。

pjngdqdw

pjngdqdw5#

截至matplotlib v3.4.0

  • 使用matplotlib.pyplot.bar_label
  • 使用参数label_type设置的默认标签位置为'edge'。要将标签居中放置在条形的中间,请使用'center'
  • 其他kwargs被传递到Axes.annotateAxes.annotate接受Textkwargs
  • 可以使用colorrotationfontsize等属性。
  • 请参阅matplotlib: Bar Label Demo页面了解其他格式选项。
      • python 3.10pandas 1.4.2matplotlib 3.5.1seaborn 0.11.2中测试**
  • ax.containersBarContainer artistslist
  • 对于单水平条形图,它是len 1的列表,因此使用[0]
  • 对于分组和堆叠条形图,list中将有更多对象

| * * 堆叠**| * * 分组**|
| - ------| - ------|
| How to annotate each segment of a stacked bar chart| How to plot and annotate grouped bars in seaborn|
| Stacked Bar Chart with Centered Labels| How to plot and annotate a grouped bar chart|

| * * label=示例**| * * label=示例**|
| - ------| - ------|
| stack bar plot in matplotlib and add label to each section| How to annotate a stacked bar plot and add legend labels|
| How to add multiple annotations to a barplot| How to customize bar annotations to not show selected values|
| How to plot a horizontal stacked bar with annotations| How to annotate bar plots when adding error bars|
| How to align annotations at the end of a horizontal bar plot||

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)

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

海运轴级图

  • 可以看出,与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)

Seaborn图形级图

  • seaborn.catplot接受data的 Dataframe 。
  • 由于.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)

∮ ∮ ∮ ∮

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)

使用bar_label的其他示例

| 关联销售订单答案|关联销售订单答案|
| - ------| - ------|
| How to create and annotate a stacked proportional bar chart| How to wrap long tick labels in a seaborn figure-level plot|
| How to calculate percent by row and annotate 100 percent stacked bars| How to annotate barplot with percent by hue/legend group|
| Stacked bars are unexpectedly annotated with the sum of bar heights| How to add percentages on top of bars in seaborn|
| How to plot and annotate grouped bars| How to plot percentage with seaborn distplot / histplot / displot|
| How to annotate bar chart with values different to those from get_height()| How to plot grouped bars in the correct order|
| Pandas bar how to label desired values| Problem with plotting two lists with different sizes using matplotlib|
| How to display percentage above grouped bar chart| How to annotate only one category of a stacked bar plot|
| How to set ticklabel rotation and add bar annotations| How to Increase subplot text size and add custom bar plot annotations|
| How to aggregate group metrics and plot data with pandas| How to get a grouped bar plot of categorical data|
| How to plot a stacked bar with annotations for multiple groups| How to create grouped bar plots in a single figure from a wide dataframe|
| How to annotate a stackplot or area plot| How to determine if the last value in all columns is greater than n|
| How to plot grouped bars| How to plot element count and add annotations|
| How to add multiple data labels in a bar chart in matplotlib| Seaborn Catplot set values over the bars|
| Python matplotlib multiple bars| Matplotlib pie chart label does not match value|
| plt grid ALPHA parameter not working in matplotlib| How to horizontally center a bar plot annotation|

aiqt4smr

aiqt4smr6#

我也需要条形图标签,注意我的y轴有一个缩放视图,使用y轴上的限制。将标签放在条形图顶部的默认计算仍然使用高度(在本例中use_global_coordinate=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')

brqmpdu1

brqmpdu17#

如果您只想在条形图上方添加数据点,您可以使用以下命令轻松完成:

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

相关问题