【问题标题】:Adding an arbitrary line to a matplotlib plot in ipython notebook在 ipython 笔记本中向 matplotlib 图中添加任意线
【发布时间】:2012-10-12 17:32:40
【问题描述】:

我对 python/matplotlib 和通过 ipython notebook 使用它都很陌生。我正在尝试向现有图形添加一些注释线,但我不知道如何在图形上呈现这些线。因此,例如,如果我绘制以下内容:

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 中是否有等价物?

【问题讨论】:

    标签: matplotlib ipython


    【解决方案1】:

    您可以通过向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()
    

    【讨论】:

    • 小修正,上面的代码应该是x = np.arange(1, 101)
    • 这不会画一条线,而只会画一段。如何画线抛出两个给定点的问题仍未得到解答。
    • 问题我看到这些段会被算作情节,破坏传说......
    • @Rmano 您可以通过添加以“_”开头的标签参数来避免在图例中考虑分段。例如:plt.plot([70, 70], [100, 250], 'k-', lw=2, label="_not in legend")
    • 90 同时用作x2y1 的事实导致了很多歧义。对于查看此内容的任何人,请注意[70, 90] 不是指位置x1,y1 的单个点。供参考,这里是值的含义:[x1: 70, x2: 90], [y1: 90, y2: 200]
    【解决方案2】:

    newcomers 还为时不晚。

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

    它也采用y 的范围,使用yminymax

    【讨论】:

    • axhline 和 axvline 的最小/最大参数是 0 到 1 之间的标量值,用于绘制参考绘图边缘的线。虽然是个不错的工具,但可能不是解决作者画注解线问题的最佳解决方案。
    • 这非常适合想要在背景中添加跨越整个图形的注释线。如果我使用上面选择的解决方案在 x=1 处绘制一条垂直线,我必须指定最小和最大 y,然后绘图会使用缓冲区自动调整大小,因此该线不会延伸到整个绘图,并且这很麻烦。这更优雅,并且不会调整绘图的大小。
    【解决方案3】:

    使用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)
    

    【讨论】:

    • 那太好了。我没有看到vline()hline() 函数。对角线呢?既然您已经向我展示了 h 和 v 线,我编辑了问题以添加对角线位。
    • 尝试制作一个包含 x,y 坐标的DataFrame 并用style='k-' 绘制它们
    【解决方案4】:

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

    the documentation 中,它说您只能绘制一个以空字符串作为第一个参数的箭头。

    来自 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回答中的方法一样,您可以选择颜色、线宽、线型等。

    这里是对部分代码的修改,它会使两个示例行之一变成红色、更宽,并且不是 100% 不透明。

    # 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 为连接线添加曲线。

    【讨论】:

      【解决方案5】:

      与其滥用plotannotate这样对很多线路效率低下,你可以使用matplotlib.collections.LineCollection

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

      它需要一个行列表[l1, l2, ...],其中每一行是一个N个坐标序列(N可以多于两个)。

      标准格式关键字可用,接受单个值,在这种情况下该值适用于每一行,或 M values 的序列,在这种情况下 第i行是values[i % M]

      【讨论】:

        猜你喜欢
        • 2014-07-16
        • 1970-01-01
        • 2015-08-09
        • 2013-05-27
        • 1970-01-01
        • 2017-01-25
        • 2013-10-24
        相关资源
        最近更新 更多