在matplotlib条形图上添加值标签

Opt*_*esh 74 python data-visualization matplotlib python-2.7 pandas

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

基本上,我正在创建一个条形图,我只是想弄清楚如何在条形图上添加值标签(在条形图的中心,或者在它上面).一直在寻找网络上的样本,但没有成功实现我自己的代码.我相信解决方案要么是'text',要么是'annotate',但是我: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.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)
Run Code Online (Sandbox Code Playgroud)

Sim*_*ons 101

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

您可以从ax.patches成员中获取绘图中生成的条形列表.然后,您可以使用matplotlib库示例中演示的技术使用该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')
Run Code Online (Sandbox Code Playgroud)

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

在此输入图像描述

  • 好的解决方案 我写了一篇基于解决方案的博客文章,并提供了一个稍微强大的版本,可根据轴的高度进行缩放,因此相同的代码适用于具有不同轴高度的不同图:http://composition.al/博客/ 2015/11 /第29/A-更好的方式对添加的标签到酒吧,图表与 - matplotlib / (10认同)
  • 两者都可用于在绘图上添加文本.``text``只是在绘图上打印一些文字,而``annotate``是一个帮助,您可以使用它来轻松地从文本中添加一个箭头指向图中特定的点.文本. (2认同)

jus*_*rec 38

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

遗憾的是,其他解决方案在许多情况下都不起作用,因为标签和条之间的间距或者以条的绝对单位给出,或者通过条的高度缩放.前者仅适用于较窄范围的值,后者在一个图中给出不一致的间距.两者都不适用于对数轴.

我建议的解决方案独立于规模(即小数字和大数字)工作,甚至正确地为负值和对数标度放置标签,因为它使用视觉单位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")
Run Code Online (Sandbox Code Playgroud)

编辑:我已经在一个函数中提取了相关的功能,正如barnhillec所建议的那样.

这会产生以下输出:

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

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

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


Aja*_*jay 38

如果只想标记条形上方的数据点,可以使用 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()
Run Code Online (Sandbox Code Playgroud)

通过指定的水平和垂直对齐'center''bottom'相应的一个可以得到居中注释。

带标签的条形图


小智 22

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

# 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")
Run Code Online (Sandbox Code Playgroud)

带注释的水平条形图


Tre*_*ney 12

作为 matplotlib v3.4.2

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)
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明


归档时间:

查看次数:

133567 次

最近记录:

6 年,4 月 前