从Pandas DataFrame绘图时对数据点进行标注

52

我希望在绘图中的数据点旁边注释它们的值。我找到的例子只涉及x和y作为向量的情况。然而,我想对包含多个列的pandas DataFrame进行这样的注释。

ax = plt.figure().add_subplot(1, 1, 1)
df.plot(ax = ax)
plt.show()

如何为多列DataFrame注释所有点最好的方法是什么?

4个回答

60

这里是Dan Allan的答案的稍微优化版:

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

df = pd.DataFrame({'x':np.random.rand(10), 'y':np.random.rand(10)}, 
                  index=list(string.ascii_lowercase[:10]))

这将会给出:

          x         y
a  0.541974  0.042185
b  0.036188  0.775425
c  0.950099  0.888305
d  0.739367  0.638368
e  0.739910  0.596037
f  0.974529  0.111819
g  0.640637  0.161805
h  0.554600  0.172221
i  0.718941  0.192932
j  0.447242  0.172469

接着:

fig, ax = plt.subplots()
df.plot('x', 'y', kind='scatter', ax=ax)

for k, v in df.iterrows():
    ax.annotate(k, v)

最后,如果您处于交互模式,可能需要刷新图表:

fig.canvas.draw()

产生以下结果: 无聊的散点图

或者,由于那看起来非常丑陋,您可以轻松地使事情变得更好看:

from matplotlib import cm
cmap = cm.get_cmap('Spectral')
df.plot('x', 'y', kind='scatter', ax=ax, s=120, linewidth=0, 
        c=range(len(df)), colormap=cmap)

for k, v in df.iterrows():
    ax.annotate(k, v,
                xytext=(10,-5), textcoords='offset points',
                family='sans-serif', fontsize=18, color='darkslategrey')

这看起来更漂亮了:漂亮的散点图


太棒了!(正如你所说的第二个图表...) - Little Bobby Tables
@LondonRob,你能告诉我如何注释每隔n个标记器吗? - st19297
@st19297 创建一个新问题!并包含此答案的链接(请参见“分享”链接),以便人们知道您从哪里开始! - LondonRob
我使用这种方法遇到的问题是,如果标签超出了绘图区域,它们就会被截断。有什么办法可以解决这个问题吗? - Howard Lovatt
@HowardLovatt,您可以使用xlim=[0,1]重置轴限制,并使用ax.set(xlim=xlim, ylim=ylim)进行设置。如果您需要动态计算限制,则可以从df[x].max()开始,并通过乘以0.91.1进行调整。 - PatrickT
@PatrickT 非常感谢。 - Howard Lovatt

43

您是否想将其他列用作注释的文本?最近我做了这样的事情。

从一些示例数据开始

In [1]: df
Out[1]: 
           x         y val
 0 -1.015235  0.840049   a
 1 -0.427016  0.880745   b
 2  0.744470 -0.401485   c
 3  1.334952 -0.708141   d
 4  0.127634 -1.335107   e

绘制这些点。在此示例中,我将y绘制到x上。

ax = df.set_index('x')['y'].plot(style='o')
编写一个函数,循环遍历x、y和要在点旁注释的值。
def label_point(x, y, val, ax):
    a = pd.concat({'x': x, 'y': y, 'val': val}, axis=1)
    for i, point in a.iterrows():
        ax.text(point['x'], point['y'], str(point['val']))

label_point(df.x, df.y, df.val, ax)

draw()

标注点


34

假设你的 df 包含多列数据,其中三列分别为 xylbl。要在散点图上用 lbl 注释 (x,y),只需执行以下操作:

ax = df.plot(kind='scatter',x='x',y='y')
df[['x','y','lbl']].apply(lambda row: ax.text(*row),axis=1);

1
对于第一行,当前的pandas将使用df.plot('x', 'y', kind='scatter')。 - Nelson Auner

12

我发现之前的回答非常有帮助,尤其是LondonRob的示例,它改善了布局。

唯一让我不满意的是,我不喜欢从数据框中提取数据然后再循环处理,因为这会浪费数据框的资源。

下面是一个替代方案,它使用了.apply()避免了循环,并且包括了更好看的注释(我认为颜色缩放有点过度了,而且无法去除颜色栏):

ax = df.plot('x', 'y', kind='scatter', s=50 )

def annotate_df(row):  
    ax.annotate(row.name, row.values,
                xytext=(10,-5), 
                textcoords='offset points',
                size=18, 
                color='darkslategrey')
    
_ = df.apply(annotate_df, axis=1)

在此输入图片描述

编辑注释

我最近编辑了我的代码示例。最初它使用了相同的:

fig, ax = plt.subplots()

与其他帖子一样,揭露轴承是不必要的,这会使:

import matplotlib.pyplot as plt

行也是不必要的。

还请注意:

  • 如果您尝试重现此示例,并且您的图没有任何一个点与我们的相同,那么可能是因为数据框使用的是随机值。如果我们使用了固定的数据表或随机种子,可能会更少引起混乱。
  • 根据点的情况,您可能需要调整xytext值以获得更好的放置。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接