Matplotlib で3Dグラフを作成するとき、グラフの軸のサイズを設定しつつ軸の比率を統一したいが plt.axes().set_aspect('equal')
のような関数が 3D plot には存在しないので、その解決方法を。
(軌道のプロットなどで便利)
例えば、このプロットについて
# plot in 3D of candidate branches
fig = plt.figure(figsize=(12,10))
plt.rcParams["font.size"] = 20
ax = fig.gca(projection='3d')
# mass
ax.plot_wireframe(xperilune_m2, yperilune_m2, zperilune_m2, color="k", label='m2', alpha=0.1)
# LPO trajectory
ax.plot(dynmatLPO["x_arr"]*Lstar, dynmatLPO["y_arr"]*Lstar, dynmatLPO["z_arr"]*Lstar, c='m', linewidth='1.5', label='Halo')
軸のサイズを固めたいとする。$x$軸を$320000$から$470000$、$y$軸を$-60000$から$60000$、$z$軸を$-1000$から$1000$で止めたい場合、これらの中から最大のrangeをもつ範囲を max=range
として計算し、これをもとにボックスを作成している。
def set_equal_axis(ax, xlims, ylims, zlims):
"""Helper function to set equal axis
Args:
ax (Axes3DSubplot): matplotlib 3D axis, created by `ax = fig.add_subplot(projection='3d')`
xlims (np.array): array containing min and max value of x
ylims (np.array): array containing min and max value of y
zlims (np.array): array containing min and max value of z
"""
# compute max required range
max_range = np.array([xlims.max()-xlims.min(), ylims.max()-ylims.min(), zlims.max()-zlims.min()]).max() / 2.0
# compute mid-point along each axis
mid_x = (xlims.max() + xlims.min()) * 0.5
mid_y = (ylims.max() + ylims.min()) * 0.5
mid_z = (zlims.max() + zlims.min()) * 0.5
# set limits to axis
ax.set_xlim(mid_x - max_range, mid_x + max_range)
ax.set_ylim(mid_y - max_range, mid_y + max_range)
ax.set_zlim(mid_z - max_range, mid_z + max_range)
return
# create plot
fig = plt.figure(figsize=(12,10))
plt.rcParams["font.size"] = 20
ax = fig.gca(projection='3d')
# mass
ax.plot_wireframe(xperilune_m2, yperilune_m2, zperilune_m2, color="k", label='m2', alpha=0.1)
# LPO trajectory
ax.plot(dynmatLPO["x_arr"]*Lstar, dynmatLPO["y_arr"]*Lstar, dynmatLPO["z_arr"]*Lstar, c='m', linewidth='1.5', label='Halo')
# set array for max/min boxing
xlims = np.array([320000, 470000])
ylims = np.array( [-60000, 60000])
zlims = np.array([-1000, 1000])
set_equal_axis(ax, xlims, ylims, zlims)
ax.grid()
plt.title(f'Targeting from {num_branch} manifolds')
ax.legend(loc='best')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.show()
参考:
https://matplotlib.org/3.2.1/api/_as_gen/mpl_toolkits.mplot3d.axes3d.Axes3D.html
https://stackoverflow.com/questions/30196503/2d-plots-are-not-sitting-flush-against-3d-axis-walls-in-python-mplot3d/41779162#41779162