Прежде всего полный отказ от ответственности, я новичок в python, и мой вопрос может быть глупым, но, насколько мне показали мои исследования, кажется, что в matplotlib
нет поддерживаемого способа делать то, что я хочу.
Мне нужно построить траектории задачи трех тел, и я пытаюсь сделать это с помощью Python, чтобы меньше зависеть от Matlab
(это то, чему учат в моем университете). В этих сюжетах фигурируют и Земля, и Луна, и мне важно, чтобы они выглядели сферическими. Следующий код дает базовый пример того, что мне нужно построить:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D, proj3d # Needed to 3Dplots
plt.close('all') # Close plots of previous scripts
#Data
Er = 0.0166 # Earth radius
Mr = 0.0045 # Moon radius
mu = 0.01215 # Mass parameter
#
def plotCC(ax,rad,pos): # Plot celestial bodies
u = np.linspace(0, 2 * np.pi, 53)
v = np.linspace(0, np.pi, 53)
x = pos + rad * np.outer(np.cos(u), np.sin(v))
y = rad * np.outer(np.sin(u), np.sin(v))
z = rad * np.outer(np.ones(np.size(u)), np.cos(v))
ax.plot_surface(x, y, z)
# Dummy Halo orbit
u = np.linspace(0, 2 * np.pi, 30)
xh = (1-mu)*np.ones(len(u))
yh = 20*Mr*np.sin(u)
zh = 0.12 + 30*Mr*np.cos(u)
# Dummy trajectory
xt = np.linspace(1-mu,-mu,20)
yt = (xt-(1-mu))*(xt+mu)*-1.2
zt = (xt-(1-mu))*(xt+mu)*-0.8
Используя это, я могу построить все, что мне нужно, с помощью:
# Plots
fig = plt.figure(figsize=(8,8))
ax = fig.gca(projection='3d',proj_type = 'ortho')
ax.plot(xh,yh,zh, lw=1.2) # Plot Halo orbit
ax.plot(xt,yt,zt, lw=1.2) # Plot trajectory
plotCC(ax,Mr,1-mu) # Plot Moon
plotCC(ax,Er,-mu) # Plot Earth
Что дает в результате это:
Это далеко не то, что мне нужно, поскольку ни одно из небесных тел не представлено в виде сфер. Я думал, что соотношение сторон можно настроить так, чтобы оно соответствовало представленным данным, но ни один из найденных мной поддерживаемых методов, похоже, не делает именно этого. Это методы: ax.axis('equal')
, ax.set_aspect('equal')
, ax.axis('scaled')
, ax.set_aspect('equal', adjustable='box')
, ax.set_aspect('equal', adjustable='datalim')
. Ни один из них не выполняет эту работу.
Первое, что я нашел, это ответ, который в основном создает поле, чтобы все оси измерялись одинаково. Это работает, но в моем случае одно из измерений намного больше, чем другие, и это приводит к большому количеству потраченного впустую пространства:
Сюжет с решением, создающим поле
Наконец, лучшее, что я смог найти, — это решение здесь, которое требует изменить файл axes.py
так, чтобы get_proj()
принимал соотношение сторон, которое вы даете ему с помощью:
ay = (ax.get_ylim3d()[1]-ax.get_ylim3d()[0])/(ax.get_xlim3d()[1]-ax.get_xlim3d()[0])
az = (ax.get_zlim3d()[1]-ax.get_zlim3d()[0])/(ax.get_xlim3d()[1]-ax.get_xlim3d()[0])
ax.pbaspect = list(1.8*np.array([1,ay,az]))
Результатом будет это. Если вы внимательно посмотрите, график не центрирован, и в зависимости от ориентации не все данные находятся внутри области рисования. Пока я буду использовать этот последний метод, но после всех исследований, которые я провел, я все еще не могу поверить, что что-то подобное не поддерживается должным образом инструментом построения графиков (который во всем остальном просто фантастический, насколько я понимаю). знаю), и поэтому мой вопрос: я упускаю что-то очевидное?
Заранее спасибо :)
pbaspect
не был принят в matplotlib, потому что это может вызвать некоторые проблемы (я думаю, одну из них вы нашли здесь). Вы пробовали этот ответ? - person ImportanceOfBeingErnest   schedule 21.02.2019bpaspect
(по крайней мере, я так думал). Я только что попробовал это, и это дает хороший результат, с той разницей, что вы не можете изменить размер графика (как я сделал вax.pbaspect = list(1.8*np.array([1,ay,az]))
, так что ничего многообещающего... - person Jose Manuel   schedule 21.02.2019