I use pyplot.arrow
do draw some straight arrows, e.g.,
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()
Now I want to also draw some arrows that have circular curvature instead of being straight. I see that I can achieve this with pyplot.annotate()
or patches.FancyArrowPatch
with connectionstyle="arc3,rad=.5"
or so.
But these arrows look completely different from the pyplot.arrow
s and do not fit with the rest of my figures. And I don't know how I could pass something like connectionstyle
to pyplot.arrow
. Is there a way to draw curved arrows that look exactly like those that I get from pyplot.arrow
?
You cannot plot curved arrows with pyplot.arrow
. However, patches.FancyArrowPatch
should offer all the options to get any arrow style you want, so the idea would be to use a FancyArrowPatch
for the straight arrows as well, such that you can use the same style for all arrows.
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()
Here's what I ended up using; it's a bit of a hack and just draws straight arrow
heads at the ends of an 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)
The function is called circarrow
, and as arguments you pass the diameter, the two coordinates of the center, the angle at which the arc starts and the total angle the arc should pass over, as well as any parameters that are passed to pyplot arrow
. To draw an arrowhead at the beginning of the arc you specify startarrow=True
, while endarrow=True
will enable an arrowhead at the end of the arc.
Here's an example image, where you can also see that the arrow style is consistent with the straight arrows:
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