matplotlib 线上箭头图

wvt8vs2t  于 2023-10-24  发布在  其他
关注(0)|答案(5)|浏览(138)

我想用matplotlib在一个线图上添加一个箭头,就像下面的图(用pgfplots绘制)。

我该怎么做(箭头的位置和方向应该是理想的参数)?
这里有一些代码来做实验。

  1. from matplotlib import pyplot
  2. import numpy as np
  3. t = np.linspace(-2, 2, 100)
  4. plt.plot(t, np.sin(t))
  5. plt.show()

谢谢.

c6ubokkw

c6ubokkw1#

根据我的经验,使用annotate效果最好,从而避免了使用ax.arrow时出现的奇怪的扭曲,这在某种程度上很难控制。

**编辑:**我已经把它 Package 成一个小函数。

  1. from matplotlib import pyplot as plt
  2. import numpy as np
  3. def add_arrow(line, position=None, direction='right', size=15, color=None):
  4. """
  5. add an arrow to a line.
  6. line: Line2D object
  7. position: x-position of the arrow. If None, mean of xdata is taken
  8. direction: 'left' or 'right'
  9. size: size of the arrow in fontsize points
  10. color: if None, line color is taken.
  11. """
  12. if color is None:
  13. color = line.get_color()
  14. xdata = line.get_xdata()
  15. ydata = line.get_ydata()
  16. if position is None:
  17. position = xdata.mean()
  18. # find closest index
  19. start_ind = np.argmin(np.absolute(xdata - position))
  20. if direction == 'right':
  21. end_ind = start_ind + 1
  22. else:
  23. end_ind = start_ind - 1
  24. line.axes.annotate('',
  25. xytext=(xdata[start_ind], ydata[start_ind]),
  26. xy=(xdata[end_ind], ydata[end_ind]),
  27. arrowprops=dict(arrowstyle="->", color=color),
  28. size=size
  29. )
  30. t = np.linspace(-2, 2, 100)
  31. y = np.sin(t)
  32. # return the handle of the line
  33. line = plt.plot(t, y)[0]
  34. add_arrow(line)
  35. plt.show()

这不是很直观,但它工作,然后你可以摆弄arrowprops字典,直到它看起来正确。

展开查看全部
9fkzdhlc

9fkzdhlc2#

只需添加plt.arrow()

  1. from matplotlib import pyplot as plt
  2. import numpy as np
  3. # your function
  4. def f(t): return np.sin(t)
  5. t = np.linspace(-2, 2, 100)
  6. plt.plot(t, f(t))
  7. plt.arrow(0, f(0), 0.01, f(0.01)-f(0), shape='full', lw=0, length_includes_head=True, head_width=.05)
  8. plt.show()

EDIT:更改箭头参数,以包含要绘制的函数的位置和方向。

wsewodh2

wsewodh23#

不是最好的解决方案,但应该工作:

  1. import matplotlib.pyplot as plt
  2. import numpy as np
  3. def makeArrow(ax,pos,function,direction):
  4. delta = 0.0001 if direction >= 0 else -0.0001
  5. ax.arrow(pos,function(pos),pos+delta,function(pos+delta),head_width=0.05,head_length=0.1)
  6. fun = np.sin
  7. t = np.linspace(-2, 2, 100)
  8. ax = plt.axes()
  9. ax.plot(t, fun(t))
  10. makeArrow(ax,0,fun,+1)
  11. plt.show()
hwazgwia

hwazgwia4#

我知道这并没有完全回答问题,但我认为这可能对其他人在这里登陆有用。我想在我的情节图例中包括箭头,但这里的解决方案没有提到如何。可能有一个更简单的方法来做到这一点,但这里是我的解决方案:
要在图例中包含箭头,您需要创建一个自定义补丁处理程序并使用matplotlib.patches.FancyArrow对象。这里是一个最小的工作解决方案。此解决方案依赖于此线程中的现有解决方案。
首先,进口…

  1. import matplotlib.pyplot as plt
  2. from matplotlib.legend_handler import HandlerPatch
  3. import matplotlib.patches as patches
  4. from matplotlib.lines import Line2D
  5. import numpy as np

现在,我们创建一个自定义的图例处理程序。这个处理程序可以为任何线条-面片组合创建图例艺术家,假设线条没有标记。

  1. class HandlerLinePatch(HandlerPatch):
  2. def __init__(self, linehandle=None, **kw):
  3. HandlerPatch.__init__(self, **kw)
  4. self.linehandle=linehandle
  5. def create_artists(self, legend, orig_handle,
  6. xdescent, ydescent, width,
  7. height, fontsize, trans):
  8. p = super().create_artists(legend, orig_handle,
  9. xdescent, descent,
  10. width, height, fontsize,
  11. trans)
  12. line = Line2D([0,width],[height/2.,height/2.])
  13. if self.linehandle is None:
  14. line.set_linestyle('-')
  15. line._color = orig_handle._edgecolor
  16. else:
  17. self.update_prop(line, self.linehandle, legend)
  18. line.set_drawstyle('default')
  19. line.set_marker('')
  20. line.set_transform(trans)
  21. return [p[0],line]

接下来,我们编写一个函数来指定我们想要在图例中包含的补丁类型-在我们的例子中是一个箭头。

  1. def make_legend_arrow(legend, orig_handle,
  2. xdescent, ydescent,
  3. width, height, fontsize):
  4. p = patches.FancyArrow(width/2., height/2., width/5., 0,
  5. length_includes_head=True, width=0,
  6. head_width=height, head_length=height,
  7. overhang=0.2)
  8. return p

接下来,一个来自托马斯的答案的add_arrow函数的修改版本,它使用了FancyArrow补丁而不是注解。这个解决方案可能会导致像托马斯警告的那样奇怪的 Package ,但是我不知道如何在箭头是注解的情况下将箭头放在图例中。

  1. def add_arrow(line, ax, position=None, direction='right', color=None, label=''):
  2. """
  3. add an arrow to a line.
  4. line: Line2D object
  5. position: x-position of the arrow. If None, mean of xdata is taken
  6. direction: 'left' or 'right'
  7. color: if None, line color is taken.
  8. label: label for arrow
  9. """
  10. if color is None:
  11. color = line.get_color()
  12. xdata = line.get_xdata()
  13. ydata = line.get_ydata()
  14. if position is None:
  15. position = xdata.mean()
  16. # find closest index
  17. start_ind = np.argmin(np.absolute(xdata - position))
  18. if direction == 'right':
  19. end_ind = start_ind + 1
  20. else:
  21. end_ind = start_ind - 1
  22. dx = xdata[end_ind] - xdata[start_ind]
  23. dy = ydata[end_ind] - ydata[start_ind]
  24. size = abs(dx) * 5.
  25. x = xdata[start_ind] + (np.sign(dx) * size/2.)
  26. y = ydata[start_ind] + (np.sign(dy) * size/2.)
  27. arrow = patches.FancyArrow(x, y, dx, dy, color=color, width=0,
  28. head_width=size, head_length=size,
  29. label=label,length_includes_head=True,
  30. overhang=0.3, zorder=10)
  31. ax.add_patch(arrow)

现在,一个辅助函数来绘制箭头和直线。它返回一个Line 2D对象,这是我们在第一个代码块中编写的图例处理程序所需要的。

  1. def plot_line_with_arrow(x,y,ax=None,label='',**kw):
  2. if ax is None:
  3. ax = plt.gca()
  4. line = ax.plot(x,y,**kw)[0]
  5. add_arrow(line, ax, label=label)
  6. return line

最后,我们绘制图并使用自定义处理程序更新图例的handler_map

  1. t = np.linspace(-2, 2, 100)
  2. y = np.sin(t)
  3. line = plot_line_with_arrow(t,y,label='Path', linestyle=':')
  4. plt.gca().set_aspect('equal')
  5. plt.legend(handler_map={patches.FancyArrow :
  6. HandlerLinePatch(patch_func=make_legend_arrow,
  7. linehandle=line)})
  8. plt.show()

下面是输出:

展开查看全部
os8fio9y

os8fio9y5#

我发现,当x轴和y轴的比例非常不同时,quiver()arrow()annotate()更好地工作。下面是我的帮助函数,用于绘制带箭头的直线:

  1. def plot_with_arrows(ax, x, y, color="g", label="", n_arrows=2):
  2. ax.plot(x, y, rasterized=True, color=color, label=label)
  3. x_range = x.max() - x.min()
  4. y_range = y.max() - y.min()
  5. for i in np.linspace(x.keys().min(), x.keys().max(), n_arrows * 2 + 1).astype(np.int32)[1::2]:
  6. direction = np.array([(x[i+5] - x[i]), (y[i+5] - y[i])])
  7. direction = direction / (np.sqrt(np.sum(np.power(direction, 2)))) * 0.05
  8. direction[0] /= x_range
  9. direction[1] /= y_range
  10. ax.quiver(x[i], y[i], direction[0], direction[1], color=color)

相关问题