在ipython notebook中向matplotlib图表添加任意线条

150

我对Python/matplotlib和通过IPython笔记本使用它都比较新。我想在现有的图表中添加一些注释线,但我无法弄清如何在图表上呈现这些线。因此,例如,如果我绘制以下内容:

import numpy as np
np.random.seed(5)
x = arange(1, 101)
y = 20 + 3 * x + np.random.normal(0, 60, 100)
p =  plot(x, y, "o")

我得到了以下图形:

漂亮的散点图

那么如何从(70,100)添加一条垂直线到(70,250)?从(70,100)到(90,200)又该怎么办呢?

我尝试过使用Line2D(),但只导致了我的困惑。在R中,我只需使用segments()函数即可添加线段。在matplotlib中有类似的功能吗?

5个回答

226

您可以通过将相应的数据(线段的边界)传递给plot命令来直接绘制所需的线条:

plot([x1, x2], [y1, y2], color='k', linestyle='-', linewidth=2)

(当然,您可以选择颜色、线宽、线型等。)

根据您的示例:

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(5)
x = np.arange(1, 101)
y = 20 + 3 * x + np.random.normal(0, 60, 100)
plt.plot(x, y, "o")


# draw vertical line from (70,100) to (70, 250)
plt.plot([70, 70], [100, 250], 'k-', lw=2)

# draw diagonal line from (70, 90) to (90, 200)
plt.plot([70, 90], [90, 200], 'k-')

plt.show()

新图表


2
小修正,上面的代码应该写成 x = np.arange(1, 101) - W.P. McNeill
这不会画一条线,只会画一个线段。如何通过给定的两个点绘制一条直线的问题仍然没有得到解答。 - Alexey
6
@Rmano,您可以通过添加以“_”开头的标签参数来避免在图例中考虑要素。例如:plt.plot([70, 70], [100, 250], 'k-', lw=2, label="_不在图例中") - gcalmettes
当xvalue是日期时,如何处理? - suku
8
“90”同时被用作“x2”和“y1”的事实导致了很多歧义。 对于任何查看此内容的人,请注意,“[70, 90]”不是指位于“x1,y1”位置的单个点。参考一下,以下是各个数值的含义:[x1: 70, x2: 90], [y1: 90, y2: 200] - pookie
显示剩余3条评论

86

对于新手来说,现在开始使用这个工具并不为时过晚。

plt.axvline(x, color='r') # vertical
plt.axhline(x, color='r') # horizontal

它也考虑了 y 的范围,使用 yminymax

1
axhline和axvline的min/max参数是0到1之间的标量值,用于参考绘图边缘绘制线条。虽然这是一个不错的工具,但它可能并不是作者在绘制注释线时最好的解决方案。 - binarysubstrate
3
这对于想要在整个图表中添加一个注释线的需求非常完美。如果我使用上面选择的解决方案在x = 1处绘制一条垂直线,我必须指定最小和最大y值,然后绘图会自动调整大小并留有缓冲区,这样该线就不会横跨整个图表,这很麻烦。这种方法更加优雅且不会改变图表的大小。 - Bonnie
太棒了,谢谢你。 - Clef.

42

使用vlines函数:

import numpy as np
np.random.seed(5)
x = arange(1, 101)
y = 20 + 3 * x + np.random.normal(0, 60, 100)
p =  plot(x, y, "o")
vlines(70,100,250)

基本的调用签名是:

vlines(x, ymin, ymax)
hlines(y, xmin, xmax)

3
太好了。我之前没有见过 vline()hline() 函数。那么斜线呢?现在你已经向我展示了横向和纵向线条,我编辑了问题以添加对斜线的说明。 - JD Long
尝试创建一个包含x、y坐标的DataFrame,并使用style='k-'绘制它们。 - Austin Richardson

11

可以使用matplotlib.collections.LineCollection,而不是滥用plotannotate,因为对于许多线条来说这样做效率低下。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection

np.random.seed(5)
x = np.arange(1, 101)
y = 20 + 3 * x + np.random.normal(0, 60, 100)
plt.plot(x, y, "o")

# Takes list of lines, where each line is a sequence of coordinates
l1 = [(70, 100), (70, 250)]
l2 = [(70, 90), (90, 200)]
lc = LineCollection([l1, l2], color=["k","blue"], lw=2)

plt.gca().add_collection(lc)

plt.show()

通过LineCollection绘制的两条线的图

它接受一个由线段 [l1, l2, ...] 组成的列表,其中每个线段都是一个包含N个坐标的序列(N可以大于2)。

标准格式化关键字可用,接受单个值,此时该值适用于所有线段,或者接受M个值的序列,此时第i个线段的值为values[i % M]


10

Matplolib现在支持“注释线”,正如OP所寻求的。 annotate()函数允许连接路径的几种形式,其中一种是无箭头和无尾部的箭头,即简单的线。

ax.annotate("",
            xy=(0.2, 0.2), xycoords='data',
            xytext=(0.8, 0.8), textcoords='data',
            arrowprops=dict(arrowstyle="-",
                      connectionstyle="arc3, rad=0"),
            )

文档中提到,您可以使用空字符串作为第一个参数仅绘制箭头。
从OP的示例中:
%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(5)
x = np.arange(1, 101)
y = 20 + 3 * x + np.random.normal(0, 60, 100)
plt.plot(x, y, "o")


# draw vertical line from (70,100) to (70, 250)
plt.annotate("",
              xy=(70, 100), xycoords='data',
              xytext=(70, 250), textcoords='data',
              arrowprops=dict(arrowstyle="-",
                              connectionstyle="arc3,rad=0."), 
              )

# draw diagonal line from (70, 90) to (90, 200)
plt.annotate("",
              xy=(70, 90), xycoords='data',
              xytext=(90, 200), textcoords='data',
              arrowprops=dict(arrowstyle="-",
                              connectionstyle="arc3,rad=0."), 
              )

plt.show()

示例内联图片

和gcalmettes的回答中的方法一样,您可以选择颜色、线宽、线型等。

这是对代码的一部分进行修改,使两个示例行中的一个变为红色、更宽、不完全不透明。

# draw vertical line from (70,100) to (70, 250)
plt.annotate("",
              xy=(70, 100), xycoords='data',
              xytext=(70, 250), textcoords='data',
              arrowprops=dict(arrowstyle="-",
                              edgecolor = "red",
                              linewidth=5,
                              alpha=0.65,
                              connectionstyle="arc3,rad=0."), 
              )

您可以通过调整connectionstyle来为连接线添加曲线。

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