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

2024-11-20 08:44:00
admin
原创
10
摘要:问题描述:我正在创建条形图,但我不知道如何在条形上(在条形的中心或正上方)添加值标签。我相信解决方案是使用“文本”或“注释”,但我:a)不知道使用哪一个(并且一般来说,还没有弄清楚何时使用哪一个)。b)看不到任何一种方法来呈现值标签。这是我的代码:import numpy as np import panda...

问题描述:

我正在创建条形图,但我不知道如何在条形上(在条形的中心或正上方)添加值标签。

我相信解决方案是使用“文本”或“注释”,但我: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)

在此处输入图片描述

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


解决方案 1:

首先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()

这将生成一个如下所示的标记图:

在此处输入图片描述

解决方案 2:

根据另一个问题的答案中提到的功能,我找到了一种在条形图上放置标签的非常普遍适用的解决方案。

不幸的是,其他解决方案在许多情况下不起作用,因为标签和条形之间的间距要么以条形的绝对单位给出,要么按条形的高度缩放。前者仅适用于较窄范围的值,后者在一个图中给出不一致的间距。这两种方法都不适用于对数轴。

我提出的解决方案与尺度无关(即对于小数和大数),甚至可以正确地放置负值和对数尺度的标签,因为它使用视觉单位points进行偏移。

我添加了一个负数来展示这种情况下标签的正确位置。

每个条形的高度值用作其标签。其他标签可轻松与Simon 的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的建议,在函数中提取了相关功能。

这将产生以下输出:

条形图,每个条形上自动放置标签

使用对数刻度(以及对输入数据进行一些调整以展示对数缩放)后,得到以下结果:

带对数刻度的条形图,每个条形上自动放置标签

解决方案 3:

增强条形图注释matplotlib.pyplot.bar_label

介绍

matplotlib.pyplot.bar_label功能于 中引入matplotlib v3.4.0,简化了向条形图添加标签的过程。本指南探讨如何使用此功能使您的数据可视化更具信息量且更易于理解。

主要特点和用途

  • 标签定位:标签默认定位在栏的“边缘”,也可以选择通过 将其放置在“中心” label_type

  • 定制:可以通过传递 kwargs 来实现额外的定制Axes.annotate,从而允许调整、和text等属性。color`rotation`fontsize

  • 格式字符串:该fmt参数现在支持在中引入的 {} 样式格式字符串,matplotlib 3.7 Update用于动态标签格式化。

  • 条件格式:可以使用参数对标签进行条件格式化,fmt以实现更大的数据呈现灵活性。

理解ax.containers

ax.containers包含BarContainer艺术家,这对于条形图中的标签放置至关重要。对于单层图来说,它很简单,但对于分组或堆叠图来说,它包含多个对象,反映了它们的结构。

实例

  1. 基本注释:从 DataFrame 创建并标记简单的条形图。

# Creating a DataFrame and plotting a bar chart
import pandas as pd
df = pd.DataFrame({'Frequency': frequencies}, index=x_labels)
ax = df.plot(kind='bar', figsize=(12, 8), title='Amount Frequency', xlabel='Amount ($)', ylabel='Frequency', legend=False)
# Adding labels to the chart
ax.bar_label(ax.containers[0], label_type='edge')
# Adjusting margins for clarity
ax.margins(y=0.1)

在此处输入图片描述

seaborn 和Axes.bar示例所得到的图表与上面演示的图表非常相似。

  1. 自定义外观:使用来自的参数自定义条形图标签的外观matplotlib.axes.Axes.text

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

在此处输入图片描述

  1. Seaborn轴级图:注释 seaborn 条形图。

# Plotting and annotating using seaborn
import seaborn as sns
fig, ax = plt.subplots(figsize=(12, 8))
sns.barplot(x=x_labels, y=frequencies, ax=ax)
ax.bar_label(ax.containers[0], label_type='edge')
ax.margins(y=0.1)
  1. Seaborn图形级别图表:注释 seaborn 的图形级别条形图。

df = pd.DataFrame({'Frequency': frequencies, 'amount': x_labels})
# Annotating seaborn's figure-level plots
g = sns.catplot(kind='bar', data=df, x='amount', y='Frequency', height=6, aspect=1.5)
for ax in g.axes.flat:
    ax.bar_label(ax.containers[0], label_type='edge')
    ax.margins(y=0.1)
  1. 使用matplotlib.axes.Axes.bar:可以采用类似的方法matplotlib.pyplot.bar进行直接绘图。

# Plotting with matplotlib.axes.Axes.bar
import matplotlib.pyplot as plt
xticks = range(len(frequencies))  # Setting up xticks
fig, ax = plt.subplots(figsize=(12, 8))
ax.bar(x=xticks, height=frequencies)  # Creating the bar chart
ax.set_xticks(xticks, x_labels)  # Labeling xticks
ax.bar_label(ax.containers[0], label_type='edge')  # Annotating bars
ax.margins(y=0.1)  # Padding for clarity

使用条件格式fmt

  • 排除零或负值,仅显示正值的标签。

# Excluding zero or negative values from labels
ax.bar_label(ax.containers[0], fmt=lambda x: x if x > 0 else '', label_type='edge')
ax.bar_label(ax.containers[0], fmt=lambda x: f'{x:0.0f}' if x > 0 else '', label_type='edge')
  • 用于np.where更复杂的条件格式。

# Using np.where for conditional label formatting
import numpy as np
ax.bar_label(ax.containers[0], fmt=lambda x: np.where(x > 0, x, ''), label_type='center')

多条容器

使用多个条形容器处理复杂图表,如分组条形图或堆叠条形图。

# Iterating through multiple containers for annotation in complex charts
for c in ax.containers:
    ax.bar_label(c, fmt=lambda x: np.where(x > 0, x, ''), label_type='center')

广泛的标签定制

对于需要超出默认功能的更复杂的标签定制的场景,使用参数指定手动标签可以提供详细的控制,如本示例和以下代码片段labels所示:

# Generating custom labels for each bar, omitting labels for values less than 0
labels = [f'{h:.1f}%' if (h := v.get_height()) > 0 else '' for v in ax.containers[0]]
ax.bar_label(ax.containers[0], labels=labels, label_type='center')

兼容性

该代码已使用 Python 3.12.0、pandas 2.2.1、matplotlib 3.8.1 和 seaborn 0.13.2 进行了测试。


其他资源

如需深入了解格式选项和其他示例,请参阅“条形标签演示”页面和以下答案,它们可作为宝贵资源,为增强条形图提供更多指导。

label=带参数的答案

标签答案标签答案
水平堆积条形图并为每个部分添加标签如何注释堆叠条形图并添加图例标签
如何向条形图添加多个注释如何自定义条形注释以不显示选定的值
如何绘制带注释的水平堆叠条形图添加误差线时如何注释条形图
如何在水平条形图末尾对齐注释如何在 matplotlib 中的条形图中添加多个数据标签
如何使用不同于 get_height() 的值来注释条形图Pandas bar 如何标记所需值

堆积条形图

堆叠条形图答案堆叠条形图答案
如何注释堆积条形图的每个部分带居中标签的堆叠条形图
如何创建和注释堆叠比例条形图如何按行计算百分比并注释 100% 堆积条形图
堆叠条形图意外地标注了条形高度之和如何绘制带有多个组注释的堆叠条形图
如何仅注释堆积条形图的一个类别

分组条形图

分组栏答案分组栏答案
如何在 seaborn 中绘制和注释分组条形图如何绘制和注释分组条形图
如何绘制和注释分组条形图如何在分组条形图上方显示百分比
如何按正确顺序绘制分组条形图如何获取分类数据的分组条形图
如何从宽数据框中在单个图形中创建分组条形图如何绘制分组的多个条形图
如何绘制分组条形图

其他答案bar_label

其他答案其他答案
如何在 Seaborn 图形级图中包装长刻度标签如何按色调/图例组用百分比注释条形图
如何在 seaborn 的条形图顶部添加百分比如何使用 seaborn distplot/histplot/displot 绘制百分比
使用 matplotlib 绘制两个不同大小的列表的问题如何增加子图文本大小并添加自定义条形图注释
如何确定所有列中的最后一个值是否大于 n如何绘制元素数量并添加注释
Seaborn Catplot 在条形图上设置值Matplotlib 饼图标签与值不匹配
如何水平居中条形图注释如何解决 pyplot.grid 中的 'alpha' 参数显示问题
如何设置刻度标签旋转和添加条形注释如何用 Pandas 聚合组指标并绘制数据
如何注释堆栈图或面积图

解决方案 4:

基于上述(很棒!)的答案,我们只需进行一些调整就可以制作水平条形图:

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

带注释的水平条形图

解决方案 5:

如果您只想标记条形图上方的数据点,则可以使用 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'可以获得居中的注释。

带标签的条形图

解决方案 6:

我也需要条形标签,请注意,我的 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')

示例输出

解决方案 7:

如果您只想在条形图上方添加数据点,则可以轻松地执行以下操作:

 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
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用