matplotlib:绘制看起来像pyplot.arrow的弯曲箭头?

时间:2017-06-13 15:45:10

标签: python matplotlib

我使用pyplot.arrow做一些直箭,例如,

import matplotlib.pyplot as plt
import numpy as np

v={}
for i in range (1,4):
    v[i]=np.array([np.cos(-2*np.pi/3*i),np.sin(-2*np.pi/3*i)])

plt.arrow(.85*(.05*v[2]+.95*v[1])[0],.85*(.05*v[2]+.95*v[1])[1],.85*.9*(v[2]-v[1])[0],.85*.9*(v[2]-v[1])[1],width=0,head_width=.03,head_length=.045,length_includes_head=True,color="black")
plt.arrow(.85*(.05*v[3]+.95*v[2])[0],.85*(.05*v[3]+.95*v[2])[1],.85*.9*(v[3]-v[2])[0],.85*.9*(v[3]-v[2])[1],width=0,head_width=.03,head_length=.045,length_includes_head=True,color="black")
plt.arrow(.85*(.05*v[1]+.95*v[3])[0],.85*(.05*v[1]+.95*v[3])[1],.85*.9*(v[1]-v[3])[0],.85*.9*(v[1]-v[3])[1],width=0,head_width=.03,head_length=.045,length_includes_head=True,color="black")

plt.axes().set_xlim(-.5,1)
plt.axes().set_ylim(-np.sqrt(3)/2,np.sqrt(3)/2)
plt.axes().set_aspect(1)
plt.show()

现在我想绘制一些圆弧曲线而不是直线的箭头。我发现我可以使用pyplot.annotate()patches.FancyArrowPatchconnectionstyle="arc3,rad=.5"左右来实现此目的。

但是这些箭头看起来与pyplot.arrow完全不同,并且不适合我的其他数字。而且我不知道如何将connectionstyle传递给pyplot.arrow。有没有办法绘制看起来与pyplot.arrow完全相同的弯曲箭头?

2 个答案:

答案 0 :(得分:11)

您无法使用pyplot.arrow绘制弯曲箭头。但是,patches.FancyArrowPatch应提供所有选项以获得您想要的任何箭头样式,因此我们的想法是使用FancyArrowPatch作为直箭头,这样您就可以使用相同的样式箭头

import matplotlib.pyplot as plt
import matplotlib.patches as patches

plt.axes().set_xlim(-.5,0.5)
plt.axes().set_ylim(-0.9,0.7)
plt.axes().set_aspect(1)

style="Simple,tail_width=0.5,head_width=4,head_length=8"
kw = dict(arrowstyle=style, color="k")

a1 = patches.FancyArrowPatch((-0.4,-0.6), (0,0.6),**kw )
a2 = patches.FancyArrowPatch((0,0.6), (0.4,-0.6),**kw)
a3 = patches.FancyArrowPatch((-0.4,-0.6), (0.4,-0.6),connectionstyle="arc3,rad=.5", **kw)

for a in [a1,a2,a3]:
    plt.gca().add_patch(a)
plt.show()

enter image description here

答案 1 :(得分:3)

这是我最终使用的内容;它有点像黑客,只是在arrow的末尾画出Arc个直头:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Arc
def circarrow(self,diameter,centX,centY,startangle,angle,**kwargs):
    startarrow=kwargs.pop("startarrow",False)
    endarrow=kwargs.pop("endarrow",False)

    arc = Arc([centX,centY],diameter,diameter,angle=startangle,
          theta1=np.rad2deg(kwargs.get("head_length",1.5*3*.001)) if startarrow else 0,theta2=angle-(np.rad2deg(kwargs.get("head_length",1.5*3*.001)) if endarrow else 0),linestyle="-",color=kwargs.get("color","black"))
    self.axes().add_patch(arc)

    if startarrow:
        startX=diameter/2*np.cos(np.radians(startangle))
        startY=diameter/2*np.sin(np.radians(startangle))
        startDX=+.000001*diameter/2*np.sin(np.radians(startangle)+kwargs.get("head_length",1.5*3*.001))
        startDY=-.000001*diameter/2*np.cos(np.radians(startangle)+kwargs.get("head_length",1.5*3*.001))
        self.arrow(startX-startDX,startY-startDY,startDX,startDY,**kwargs)

    if endarrow:
        endX=diameter/2*np.cos(np.radians(startangle+angle))
        endY=diameter/2*np.sin(np.radians(startangle+angle))
        endDX=-.000001*diameter/2*np.sin(np.radians(startangle+angle)-kwargs.get("head_length",1.5*3*.001))
        endDY=+.000001*diameter/2*np.cos(np.radians(startangle+angle)-kwargs.get("head_length",1.5*3*.001))
        self.arrow(endX-endDX,endY-endDY,endDX,endDY,**kwargs)

import types
plt.circarrow = types.MethodType(circarrow,plt)

该函数被称为circarrow,作为参数传递直径,中心的两个坐标,弧开始的角度和弧应该通过的总角度,以及任何参数传递给pyplot arrow的。要在弧的开头绘制箭头,请指定startarrow=True,而endarrow=True将在弧的末尾启用箭头。

这是一个示例图像,您还可以看到箭头样式与直箭头一致:

plt.plot(0,0,"o",markersize=10,color="black",mfc="none")

plt.circarrow(.85,0,0,0.05*120,.9*120,startarrow=True,width=0,head_width=.03,head_length=.045,length_includes_head=True,color="black")
plt.circarrow(.85,0,0,1.05*120,.9*120,startarrow=True,endarrow=True,width=0,head_width=.03,head_length=.045,length_includes_head=True,color="black")
plt.arrow(-.2,-.33,.6,+.33,width=0,head_width=.03,head_length=.045,length_includes_head=True,color="black")

plt.axes().set_xlim(-.5,.5)
plt.axes().set_ylim(-.5,.5)
plt.axes().set_aspect(1)
plt.show()

example image