стиль соединения arc3 (FancyArrowPatch) и путь CURVE3 - две квадратичные кривые Безье, разные результаты?

1

Я начал с аналогичной проблемы, как упоминалось здесь: нарисуйте закругленный fancyarrowpatch с стрелкой средней точки в matplotlib

Просто я хотел бы добавить метку к стрелке, идеально в разных местах. Я попытался восстановить координаты с вершинами пути, но метки все еще были повсюду. Затем я попытался следовать описанию стиля соединения arc3

(https://matplotlib.org/api/_as_gen/matplotlib.patches.ConnectionStyle.html?highlight=connectionstyle)

класс Arc3 (rad = 0.0)

Создает простую квадратичную кривую безье между двумя точками. Кривая создается так, что средняя контрольная точка (C1) расположена на том же расстоянии от начала (C0) и конечных точек (C2), а расстояние C1 до линии, соединяющей C0-C2, равно rad, умноженное на расстояние С0-С2.

Я восстановил это и заметил, что кривая, нарисованная FancyArrowPatch, не совпадает с квадратичной кривой Безье с указанными точками.

Минимальный пример:

import numpy
import matplotlib
from matplotlib import pyplot as plt
import matplotlib.path as mpath
import matplotlib.patches as mpatches
from matplotlib.patches import FancyArrowPatch, Circle

fig = plt.figure(frameon=False)
ax = fig.add_subplot(111, frame_on=False)

rad=0.3
shrink=0.3

# Setting up circles as start and end points
size = 0.1
n1 = Circle([0,0], radius=size, alpha=0., fill=False, linewidth=0.1)
n2 = Circle([1,1], radius=size, alpha=0., fill=False, linewidth=0.1)
ax.add_patch(n1)
ax.add_patch(n2)

# Create a fancy arrow between start and end point
e = FancyArrowPatch(n1.center, n2.center,
    connectionstyle='arc3,rad=%s' % rad,
    arrowstyle='simple',
    clip_on=False,
    linewidth=2.,
    shrinkA=shrink,shrinkB=shrink
    )

ax.add_patch(e)

# Start point
vs=numpy.asarray(n1.center)
# End point
ve=numpy.asarray(n2.center)
# Connection vector start->end
vD=ve-vs
# Perpendicular vector to vD
vp=numpy.asarray([vD[1],-vD[0]]) 
# Control point: same distance from start and end point, and rad*|vD| from the connection line between start and end
vc=vs+0.5*vD+rad*vp 

Path=mpath.Path
pp1 = mpatches.PathPatch(
    Path([vs, vc, ve],
     [Path.MOVETO, Path.CURVE3, Path.CURVE3]), color="red", transform=ax.transData,fc='None')

ax.add_patch(pp1)

# Putting labels on quadratic Bezier curve at various points
# Uses start point, control point and end point from above
for tt in numpy.arange(0,1.1,0.1):
    vl=((1-tt)**2)*vs+(2*(1-tt)*tt)*vc+(tt**2)*ve
    string = str(tt)
    ax.text(vl[0], vl[1], string,
        fontsize=10,bbox={'alpha':0.5, 'pad':2},
        verticalalignment='center',
        horizontalalignment='center')

plt.show()

Который дает

Изображение 174551

Черная линия: FancyArrowPatch (не знаю, почему нет стрелки)

Красная линия: PathPatch

Синие метки: точки на квадратичной кривой Безье между (0,0) и (1,1) с контрольной точкой на одном и том же расстоянии от начала и конца и rad * (расстояние от начальной точки до конечной точки) от линии соединения между началом и концом. (как описано в соединении arc3).

(К сожалению, я не могу просто дать FancyArrowPatch построенный путь, потому что мне нужны его параметры сжатия/патча.)

Поэтому вопрос заключается в том, как я надежно помещаю метку на стрелку и как FancyArrowPatch фактически создает свой путь.

(Я знаю, что вернутые вершины вернутся, но я использую идентичный код для разных длин стрелок (только для начала и конца точки), и эти пути могут сильно отличаться друг от друга).

Теги:
matplotlib
bezier

1 ответ

0

Кривая, которую вы создаете как Path живет в пространстве данных. Кривая FancyArrowPatch которая автоматически генерируется, живет в пространстве дисплея. Это означает, что они будут равны, только если расстояние между точками в пространстве данных будет пропорциональным расстоянию между точками в пространстве отображения. Это, в общем, только тот случай, когда соотношение сторон оси равно.

Это как-то похоже на более интуитивный (обратный) случай круга, определенного в координатах данных. В таком случае документация будет говорить что-то вроде "рисует круг, т.е. Линию, которая везде имеет такое же расстояние до заданной центральной точки". Тем не менее, если вы построите круг, он скорее будет выглядеть как эллипс, если вы не установите соотношение сторон осей равным 1.

Действительно, при установке ax.set_aspect("equal"), в приведенном выше случае вы получите

Изображение 174551

Поскольку сам Arc3 ничего не знает о системе координат, в которой он будет использоваться, документация Arc3 полностью верна.

  • 0
    Спасибо за ваш ответ, особенно объяснение различных мест обитания различных объектов. Является ли соотношение сторон единственным способом обойти это или каким-то образом возможно преобразование между системами координат? (Я, вероятно, должен сказать, что мой результат не соответствует тому, что я ожидаю от документации.)
  • 0
    Я не думаю, что есть какое-либо несоответствие, но вы, конечно, можете попытаться объяснить это лучше. Я полагаю, вы можете обойти нежелательное поведение, используя Path в координатах данных вместо FancyArrowPatch, как вы это делаете в примере?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню