Вы можете оценить кривую Безье, которая создается стрелкой вручную.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from scipy.special import binom
fig, ax = plt.subplots()
kw = dict(arrowstyle = '-', shrinkA = 0, shrinkB = 0, color = 'k',
connectionstyle = "arc3, rad = -0.9" )
arrow = mpatches.FancyArrowPatch((0, 0), (5, 3), **kw)
ax.add_patch(arrow)
bernstein = lambda n, k, t: binom(n,k)* t**k * (1.-t)**(n-k)
def bezier(points, t=[0,1], num=200):
N = len(points)
t = np.linspace(*t, num=num)
curve = np.zeros((num, 2))
for i in range(N):
curve += np.outer(bernstein(N - 1, i, t), points[i])
return curve
verts = arrow.get_path().vertices
curve1 = bezier(verts, t=[0.0, 0.5], num=100)
curve2 = bezier(verts, t=[0.5, 1.0], num=100)
ax.plot(curve1[:,0], curve1[:,1], lw=3, color="crimson")
ax.plot(curve2[:,0], curve2[:,1], lw=3, ls="--", color="crimson")
plt.show()
![enter image description here](https://i.stack.imgur.com/2egMv.png)
Как вы заметили две кривые, т.е. исходная стрелка и созданная вручную кривая Безье не накладываются друг на друга. Это связано с тем, что matplotlib оценивает кривую Безье в пространстве экрана, а ручная версия оценивает ее в пространстве данных.
Чтобы получить одинаковую кривую в обоих случаях, нам необходимо выполнить оценку в пространстве экрана, которая показана на следующий (где мы также строим три более точных узла, как в данных, так и в пиксельном пространстве).
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from scipy.special import binom
fig, ax = plt.subplots()
kw = dict(arrowstyle = '-', shrinkA = 0, shrinkB = 0, color = 'k',
connectionstyle = "arc3, rad = -0.4" )
arrow = mpatches.FancyArrowPatch((0, 0), (5, 3), **kw)
ax.add_patch(arrow)
ax.autoscale()
print(arrow.get_path().vertices)
bernstein = lambda n, k, t: binom(n,k)* t**k * (1.-t)**(n-k)
def bezier(points, t=[0,1], num=200):
N = len(points)
t = np.linspace(*t, num=num)
curve = np.zeros((num, 2))
for i in range(N):
curve += np.outer(bernstein(N - 1, i, t), points[i])
return curve
trans = ax.transData
trans_inv = trans.inverted()
verts = trans.transform(arrow.get_path().vertices)
curve1 = trans_inv.transform(bezier(verts, t=[0.0, 0.5], num=100))
curve2 = trans_inv.transform(bezier(verts, t=[0.5, 1.0], num=100))
ax.plot(curve1[:,0], curve1[:,1], lw=3, color="crimson", zorder=0)
ax.plot(curve2[:,0], curve2[:,1], lw=3, ls="--", color="crimson", zorder=0)
from matplotlib.transforms import IdentityTransform
ax.plot(*trans.transform(arrow.get_path().vertices).T, ls="", marker="o",
color="C1", ms=7, transform=IdentityTransform())
ax.plot(*arrow.get_path().vertices.T, ls="", marker="o", color="C0", ms=3)
plt.show()
![enter image description here](https://i.stack.imgur.com/iNDcr.png)