FancyArrowPatch не отображается правильно на точечной диаграмме - PullRequest
0 голосов
/ 26 апреля 2020

У меня есть точечная диаграмма, на которой я пытаюсь нарисовать стрелку.

Когда я пытаюсь добавить патч с помощью ax.add_patch (arrow1), ничего не происходит.

Если я использую plt.gca (). Add_patch (arrow1), стрелка появляется не в том месте.

Вот график, который я получаю, используя gca ():

График, показывающий стрелку в неправильном месте

import numpy as np
import matplotlib.patches as pat
import matplotlib.pyplot as plt
from matplotlib.ticker import FormatStrFormatter
import matplotlib.animation as animation
import matplotlib.colors as mcolors

# initialise arrays
n = 2 # number of particles
its = 10 # number of iternations
m = np.zeros(n)
x = np.zeros((n,its+1))
v = np.zeros((n,its+1))
dt = 1000

G = 6.67408*10**(-11)

# set initial conditions
m[0], m[1] = 10**20, 10**12
x[0,0], x[1,0] = 0, 10**6
x[0,1], x[1,1] = 6.67408*10**(-5), 993325.92
v[0,1], v[1,1] = 6.67408*10**(-8), -6.67408

def leap_x(xnow, vnow):
   xleap = xnow + dt*vnow
   return xleap

def leap_v(i, xnow2, xnow1, vnow):
    a = G*m[i]*(xnow2 - xnow1)/np.abs((xnow2 - xnow1)**3)
    vleap = vnow + dt*a
    return vleap

for j in range(2, its+1):
    v[0,j] = leap_v(1, x[1,j-1], x[0,j-1], v[0,j-1])
    v[1,j] = leap_v(0, x[0,j-1], x[1,j-1], v[1,j-1])
    x[0,j] = leap_x(x[0,j-1], v[0,j])
    x[1,j] = leap_x(x[1,j-1], v[1,j])

# plotting

def sci_not(x):
    return "{:.1e}".format(x)

def make_color(num):
    alphas = np.linspace(0.8, 0.1, len(num))
    rgba_colors = np.zeros((2,len(num),4))
    rgba_colors[0,:,0] = m1Color[0] # m1 r
    rgba_colors[0,:,1] = m1Color[1] # m2 g
    rgba_colors[0,:,2] = m1Color[2] # m3 b
    rgba_colors[1,:,0] = m2Color[0] # m2 r
    rgba_colors[1,:,1] = m2Color[1] # m2 g
    rgba_colors[1,:,2] = m2Color[2] # m2 b
    rgba_colors[:,:,3] = alphas
    return rgba_colors

def reset_axes():
    plt.clf()
    ax = plt.axes(xlim=(-x[1,0]*.3,x[1,0]*1.1))
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.spines['left'].set_visible(False)
    ax.set_xticks([x[0,0], x[1,0]/2, x[1,0]])
    ax.xaxis.set_major_formatter(FormatStrFormatter('%.0E'))
    ax.set_title(Title)
    ax.set_xlabel('Distance / m')
    plt.yticks([])

def res_legend(mass1,mass2):
    lgnd = plt.legend(handles=[mass1, mass2], frameon=False)
    lgnd.legendHandles[0]._sizes = [30]
    lgnd.legendHandles[1]._sizes = [30]

def animate(i):
    reset_axes()
    numPlots = [k for k in range(i, i-4, -1) if k >= 0]
    rgba_colors = make_color(numPlots)
    newx = x[:,numPlots]
    newy = np.zeros(newx.shape)
    mass1 = plt.scatter(newx[0], newy[0], marker='o', s=scale[0], c=rgba_colors[0], label=labels[0])
    mass2 = plt.scatter(newx[1], newy[1], marker='o', s=scale[1], c=rgba_colors[1], label=labels[1])
    res_legend(mass1,mass2)
    return (mass1,mass2)

fig = plt.figure(num=1, figsize=(10,5))
Title = '2 - body sim using Leap Frog'
ax = plt.axes(xlim=(-x[1,0]*.3,x[1,0]*1.1))
scale = np.array([max(m)/min(m)*0.00005,50])
radii = np.sqrt(scale)/2
m1Color = mcolors.to_rgba('deepskyblue')
m2Color = mcolors.to_rgba('darkorchid')
labels = [str(sci_not(m[0]))+' Kg', str(sci_not(m[1]))+' Kg']
rgba_color = make_color([1])
reset_axes()
mass1 = plt.scatter(x[0,0], 0, marker='o', s=scale[0], c=rgba_color[0], label=labels[0])
mass2 = plt.scatter(x[1,0], 0, marker='o', s=scale[1], c=rgba_color[1], label=labels[1])
arrow1 = pat.FancyArrowPatch(posA=(x[0,0],0),posB=(5**5,0),arrowstyle='-|>', mutation_scale=20, 
                                    shrinkA=radii[0], shrinkB=0)
# plt.gca().add_patch(arrow1)
ax.add_patch(arrow1)
res_legend(mass1,mass2)

# anim = animation.FuncAnimation(fig, animate, frames=its+1, interval=1000, repeat=False)
plt.show()

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

1 Ответ

0 голосов
/ 26 апреля 2020

Вызов ax.add_patch() не работает, потому что вы очищаете фигуру (plt.clf()) и создаете новый объект ax внутри функции reset_axes(). Но этот объект ax является локальным для функции и не перезаписывает объект ax, который существует в глобальной области видимости. Однако исходный объект ax теперь недопустим, поскольку исходные оси были уничтожены при вызове plt.clf()

. В общем случае следует избегать очистки фигуры (или даже осей), если в этом нет необходимости. особенно в контексте анимации.

Быстрое решение состоит в том, чтобы изменить reset_axes() следующим образом:

def reset_axes(ax=None):
    ax = ax or plt.gca()
    ax.cla()
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.spines['left'].set_visible(False)
    ax.set_xticks([x[0,0], x[1,0]/2, x[1,0]])
    ax.xaxis.set_major_formatter(FormatStrFormatter('%.0E'))
    ax.set_title(Title)
    ax.set_xlabel('Distance / m')
    ax.set_yticks([])

Таким образом, вы никогда не уничтожите исходные оси, вы просто очищаете содержимое .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...