Уменьшение длины оси при сохранении равного соотношения сторон на трехмерном графике

Я пытаюсь создать 3-D и 2-D сюжет в Python. Мне нужны равные пропорции для обоих графиков, которые мне удалось с помощью кода, предоставленного этим ответом: /questions/28364078/matplotlib-ravnaya-edinichnaya-dlina-pri-ravnom-sootnoshenii-storon-os-z-ne-ravna-x-i-y/28364081#28364081. Теперь у меня проблема в том, как эффективно "обрезать" трехмерный сюжет, чтобы он не занимал так много пустого пространства. То есть я хочу уменьшить длину осей X и Y, сохраняя при этом равный масштаб (более длинной) оси Z. Вот пример кода и сюжет:

from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np

def set_axes_equal(ax):
    '''Make axes of 3D plot have equal scale so that spheres appear as spheres,
    cubes as cubes, etc..  This is one possible solution to Matplotlib's
    ax.set_aspect('equal') and ax.axis('equal') not working for 3D.

    Input
      ax: a matplotlib axis, e.g., as output from plt.gca().
    '''

    x_limits = ax.get_xlim3d()
    y_limits = ax.get_ylim3d()
    z_limits = ax.get_zlim3d()

    x_range = abs(x_limits[1] - x_limits[0])
    x_middle = np.mean(x_limits)
    y_range = abs(y_limits[1] - y_limits[0])
    y_middle = np.mean(y_limits)
    z_range = abs(z_limits[1] - z_limits[0])
    z_middle = np.mean(z_limits)

    # The plot bounding box is a sphere in the sense of the infinity
    # norm, hence I call half the max range the plot radius.
    plot_radius = 0.5*max([x_range, y_range, z_range])

    ax.set_xlim3d([x_middle - plot_radius, x_middle + plot_radius])
    ax.set_ylim3d([y_middle - plot_radius, y_middle + plot_radius])
    ax.set_zlim3d([z_middle - plot_radius, z_middle + plot_radius])

ax  = [None]*2
fig = plt.figure()
ax[0] = fig.add_subplot(121, projection='3d', aspect='equal')
ax[1] = fig.add_subplot(122, aspect='equal')



nn   = 30
phis = np.linspace(0,np.pi,  nn).reshape(1,nn)
psis = np.linspace(0,np.pi*2,nn).reshape(nn,1)
ones = np.ones((nn,1))
el_h = np.linspace(-5, 5, nn).reshape(1,nn)

x_sph = np.sin(phis)*np.cos(psis)
y_sph = np.sin(phis)*np.sin(psis)
z_sph = np.cos(phis)*ones

x_elp = np.sin(phis)*np.cos(psis)*.25
y_elp = np.sin(phis)*np.sin(psis)*.25
z_elp = el_h*ones

ax[0].scatter(x_sph, y_sph, z_sph)
ax[0].scatter(x_elp, y_elp, z_elp)
ax[1].scatter(y_sph, z_sph)
ax[1].scatter(y_elp, z_elp)

for ii in range(2):
    ax[ii].set_xlabel('X')
    ax[ii].set_ylabel('Y')
ax[0].set_zlabel('Z')

set_axes_equal(ax[0])
plt.savefig('SphereElipse.png', dpi=300)

И вот его вывод изображения: 3-D и 2-D сфера и эллипс бок о бок

Ясно, что двухмерный график автоматически изменяет длину осей при сохранении масштаба, но трехмерный график этого не делает, что приводит к крошечному представлению, которое не очень хорошо использует пространство, выделенное для его подзаговора. Есть какой-либо способ сделать это? Этот вопрос похож на ранее оставшийся без ответа вопрос Как обрезать график Axes3D с квадратным соотношением сторон?, за исключением того, что добавляется условие о нескольких участках, что означает, что ответы, представленные там, не работают.

0 ответов

Другие вопросы по тегам