首页 文章

在matplotlib条形图上添加值标签

提问于
浏览
54

我陷入了一些感觉应该相对容易的事情 . 我在下面的代码是基于我正在研究的更大项目的示例 . 我没有理由发布所有细节,所以请接受我带来的数据结构 .

基本上,我正在创建一个条形图,我只是想弄清楚如何在条形图上添加值标签(在条形图的中心,或者在它上面) . 一直在寻找网络上的样本,但没有成功实现我自己的代码 . 我相信解决方案要么是'text',要么是'annotate',但我:a)不知道使用哪一个(一般来说,还没弄清楚何时使用哪个) . b)无法看到要么呈现 Value 标签 . 非常感谢您的帮助,我的代码如下 . 提前致谢!

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.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))
fig = freq_series.plot(kind='bar')
fig.set_title('Amount Frequency')
fig.set_xlabel('Amount ($)')
fig.set_ylabel('Frequency')
fig.set_xticklabels(x_labels)

3 回答

  • 18

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

    您可以从 ax.patches 成员获取绘图中生成的条形列表 . 然后,您可以使用this matplotlib gallery example中演示的技术使用ax.text方法添加标签 .

    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)
    
    rects = ax.patches
    
    # Make some labels.
    labels = ["label%d" % i for i in xrange(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')
    

    这会产生一个标记的图,看起来像:

    enter image description here

  • 83

    根据this answer to another question中提到的功能,我找到了一种非常普遍适用的解决方案,用于在条形图上放置标签 .

    遗憾的是,其他解决方案在许多情况下都不起作用,因为标签和条之间的间距要么是given in absolute units of the bars,要么是scaled 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)
    
    rects = ax.patches
    
    # For each bar: Place a label
    for rect in rects:
        # 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 = 5
        # 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
        plt.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.
    
    plt.savefig("image.png")
    

    这会产生以下输出:

    Bar chart with automatically placed labels on each bar

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

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

  • 7

    基于以上(伟大的!)答案,我们还可以通过一些调整来制作水平条形图:

    # 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

相关问题