«Объект Tuple не вызывается» при попытке обновить трехмерный график рассеяния с помощью _offsets3d - PullRequest
0 голосов
/ 20 октября 2018

Я пытаюсь создать (очень) простое N-body моделирование и анимировать его в 3D.Вот мой код:

from mpl_toolkits.mplot3d import Axes3D

import numpy as np
from matplotlib.animation import FuncAnimation
import matplotlib.pyplot as plt

G=6.67408e-11
msol=1.989e40
mter=5.972e24
au=1.496e11
dt=.0007
N=30
positions=np.random.rand(N,3)
velocities=np.random.randn(N,3)
acc=np.zeros_like(positions)
masses=np.random.rand(N)

def gravforce(m0,m1,pos0,pos1):
    global G
    dx=pos1[0]-pos0[0]
    dy=pos1[1]-pos0[1]
    dz=pos1[2]-pos0[2]
    r=np.sqrt(dx**2+dy**2+dz**2)
    f=-G*m0*m1/r**2
    ratio=f/r
    fx=dx*ratio
    fy=dy*ratio
    fz=dz*ratio
    return fx, fy, fz

fig,ax=plt.subplots(subplot_kw=dict(projection='3d'))
planets=ax.scatter(positions[:,0],positions[:,1],positions[:,2],c='b',marker='o')

def animate(i):
    acc[:,0]=[sum([gravforce(masses[i],masses[j],positions[i],positions[j])[0]/masses[j] for j in range(1,N) if j != i]) for i in range(len(acc))]
    acc[:,1]=[sum([gravforce(masses[i],masses[j],positions[i],positions[j])[1]/masses[j] for j in range(1,N) if j != i]) for i in range(len(acc))]
    acc[:,2]=[sum([gravforce(masses[i],masses[j],positions[i],positions[j])[2]/masses[j] for j in range(1,N) if j != i]) for i in range(len(acc))]

    velocities[:,0]=velocities[:,0]+acc[:,0]*dt
    velocities[:,1]=velocities[:,1]+acc[:,1]*dt
    velocities[:,2]=velocities[:,2]+acc[:,2]*dt        

    positions[:,0]=positions[:,0]+velocities[:,0]*dt
    positions[:,1]=positions[:,1]+velocities[:,1]*dt
    positions[:,2]=positions[:,2]+velocities[:,2]*dt

    planets.set_sizes(masses[:]*20)
    planets._offsets3d(positions[:,0],positions[:,1],positions[:2])

ani=FuncAnimation(fig,animate,frames=1000,interval=1,blit=False)

Когда я запускаю его, я получаю следующее сообщение об ошибке:

Traceback (most recent call last):

File "<ipython-input-30-b2a4f400dbe9>", line 1, in <module>
runfile('C:/Program Files (x86)/WinPython-64bit-3.3.5.9/python-3.3.5.amd64/Scripts/orbit/3dnbody_2dprojection.py', wdir='C:/Program Files (x86)/WinPython-64bit-3.3.5.9/python-3.3.5.amd64/Scripts/orbit')

File "C:\Program Files (x86)\WinPython-64bit-3.3.5.9\python-3.3.5.amd64\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 685, in runfile
execfile(filename, namespace)

File "C:\Program Files (x86)\WinPython-64bit-3.3.5.9\python-3.3.5.amd64\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 85, in execfile
exec(compile(open(filename, 'rb').read(), filename, 'exec'), namespace)

File "C:/Program Files (x86)/WinPython-64bit-3.3.5.9/python-3.3.5.amd64/Scripts/orbit/3dnbody_2dprojection.py", line 56, in <module>
ani=FuncAnimation(fig,animate,frames=1000,interval=1,blit=False)

File "C:\Program Files (x86)\WinPython-64bit-3.3.5.9\python-3.3.5.amd64\lib\site-packages\matplotlib\animation.py", line 1067, in __init__
TimedAnimation.__init__(self, fig, **kwargs)

File "C:\Program Files (x86)\WinPython-64bit-3.3.5.9\python-3.3.5.amd64\lib\site-packages\matplotlib\animation.py", line 913, in __init__
*args, **kwargs)

File "C:\Program Files (x86)\WinPython-64bit-3.3.5.9\python-3.3.5.amd64\lib\site-packages\matplotlib\animation.py", line 591, in __init__
self._init_draw()

File "C:\Program Files (x86)\WinPython-64bit-3.3.5.9\python-3.3.5.amd64\lib\site-packages\matplotlib\animation.py", line 1092, in _init_draw
self._draw_frame(next(self.new_frame_seq()))

File "C:\Program Files (x86)\WinPython-64bit-3.3.5.9\python-3.3.5.amd64\lib\site-packages\matplotlib\animation.py", line 1106, in _draw_frame
self._drawn_artists = self._func(framedata, *self._args)  

File "C:/Program Files (x86)/WinPython-64bit-3.3.5.9/python-3.3.5.amd64/Scripts/orbit/3dnbody_2dprojection.py", line 54, in animate
planets._offsets3d(positions[:,0],positions[:,1],positions[:2])

TypeError: 'tuple' object is not callable

Насколько я могу судить, я не вызываю кортеж (изВ моем понимании это было бы попыткой сделать, например, F(2) вместо F[2], где F - это кортеж), поэтому это сбивает меня с толку и расстраивает.

Я также приветствую любые горячиесоветы, как сделать этот код более элегантным / эффективным.

1 Ответ

0 голосов
/ 20 октября 2018

Кажется, ошибка из этой строки

planets._offsets3d(positions[:,0],positions[:,1],positions[:2])

Согласно этот ответ и этот ответ , _offsets3d является частным недокументированным атрибутом, которыйкортеж, содержащий координаты, то есть он не может быть вызван.

Почему вы пытаетесь вызвать _offsets3d подобную функцию?

Если вы пытаетесь установить значения, возможно, используйте это:

planets._offsets3d = (positions[:,0], positions[:,1], positions[:2])
...