【发布时间】:2016-05-12 16:29:10
【问题描述】:
我一直在尝试突破 matplotlib 补丁的边界,并指示它在其中点绘制一个带有方向箭头的圆形 FancyArrowPatch。这在我试图创建的网络表示中证明是非常有用的。
我使用 python 的编码时间还没有达到两位数,所以我不能说我对 matplotlib 的 patch.py 有清楚的了解,但我已经将解决方案缩小到两种可能的策略:
- 聪明的,可能是pythonic的方式:创建一个自定义
arrowstyle类,进一步需要修改_get_arrow_wedge()函数以包含一个中点坐标。这可能超出了我现在的可能,或者 - 懒惰的方式:从引出的 FancyArrowPatch 中提取中点坐标,并在这些坐标上绘制所需的
arrowstyle。
当然,到目前为止我都选择了偷懒的方式。我做了一些早期实验,使用get_path() 和get_path_in_displaycoord() 提取弯曲FancyArrowPatch 的中点坐标,但我似乎无法预测精确的中点坐标。一些帮助将不胜感激。
到目前为止我的摆弄:
import matplotlib.pyplot as plt
from matplotlib.patches import FancyArrowPatch
n1 = (2,3)
n2 = (4,6)
# Try with multiple arc radius sizes, draw a separate plot each time
for rad in range(20):
#setup figure
figure = plt.figure()
ax = plt.subplot(111)
plt.annotate('rad:' + str(rad/25.),xy=(2,5))
# create rounded fancyarrowpatch
t = FancyArrowPatch(posA=n1,posB=n2,
connectionstyle='arc3,rad=%s'%float(rad/25.),
arrowstyle='->',
shrinkA=0,
shrinkB=0,
mutation_scale=0.5)
# extract vertices from get_path: points P#
path = t.get_path().vertices.tolist()
lab, px, py = ['P{0}'.format(i) for i in range(len(path))], [u[0] for u in path],[u[1] for u in path]
for i in range(len(path)):
plt.annotate(lab[i],xy=(px[i],py[i]))
# extract vertices from get_path_in_displaycoord (but they are useless) : points G#
newpath = t.get_path_in_displaycoord()
a,b = newpath[0][0].vertices.tolist(), newpath[0][1].vertices.tolist()
a.extend(b)
glab, gx, gy = ['G{0}'.format(i) for i in range(len(a))], [u[0] for u in a],[u[1] for u in a]
for i in range(len(a)):
plt.annotate(glab[i],xy=(gx[i],gy[i]))
#point A: start
x1, y1 = n1
plt.annotate('A',xy=(x1,y1))
#point B:end
x2, y2 = n2
plt.annotate('B',xy=(x2,y2))
#point M: the 'midpoint' as defined by class Arc3, specifically its connect() function
x12, y12 = (x1 + x2) / 2., (y1 + y2) / 2.
dx, dy = x2 - x1, y2 - y1
cx, cy = x12 + (rad/100.) * dy, y12 - (rad/100.) * dx
plt.annotate('M',xy=(cx,cy))
#point O : midpoint between M and P1, the second vertex from get_path
mx,my = (cx + px[1])/2., (cy + py[1])/2.
plt.annotate('O',xy=(mx,my))
ax.add_patch(t)
plt.scatter([x1,cx,x2,mx,gx].extend(px),[y1,cy,y2,my,gy].extend(py))
plt.show()
编辑:采纳@cphlewis 建议:我尝试重建贝塞尔曲线:
def bezcurv(start,control,end,tau):
ans = []
for t in tau:
B = [(1-t)**2 * start[i] + 2*(1-t)*t*end[i] + (t**2)*control[i] for i in range(len(start))]
ans.append(tuple(B))
return ans
因此,我将生成的线添加到原始图中:
tau = [time/100. for time in range(101)]
bezsim = bezcurv(n1,n2,(cx,cy),tau)
simx,simy = [b[0] for b in bezsim], [b[1] for b in bezsim]
【问题讨论】:
-
嗯,绿线不是 FancyArrowPatch 使用的 same 贝塞尔曲线,但我发现它在情节中是可以理解的。你能在中间放一个箭头吗?
标签: python matplotlib patch