Как обрезать график Axes3D с квадратным соотношением сторон?

Вот простой пример:

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure()
f = fig.add_subplot(2, 1, 1, projection='3d')
t = fig.add_subplot(2, 1, 2, projection='3d')

# axes
for d in {f, t}:
    d.plot([-1, 1], [0, 0], [0, 0], color='k', alpha=0.8, lw=2)
    d.plot([0, 0], [-1, 1], [0, 0], color='k', alpha=0.8, lw=2)
    d.plot([0, 0], [0, 0], [-1, 1], color='k', alpha=0.8, lw=2)

f.dist = t.dist = 5.2   # 10 is default

plt.tight_layout()
f.set_aspect('equal')
t.set_aspect('equal')

r = 6
f.set_xlim3d([-r, r])
f.set_ylim3d([-r, r])
f.set_zlim3d([-r, r])

t.set_xlim3d([-r, r])
t.set_ylim3d([-r, r])
t.set_zlim3d([-r, r])

f.set_axis_off()
t.set_axis_off()

plt.draw()
plt.show()

Вот что я получаю:

квадратные окна

Это то, что я хочу:

прямоугольные видовые окна

Другими словами, я хочу, чтобы сами графики имели квадратное соотношение сторон, а не все растягивались так:

вытянутый

и я получил эту часть работы благодаря /questions/28364078/matplotlib-ravnaya-edinichnaya-dlina-pri-ravnom-sootnoshenii-storon-os-z-ne-ravna-x-i-y/28364081#28364081

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

По сути, я делаю эту анимацию и хочу то же самое, но без пробелов:

анимация

3 ответа

Для того, чтобы следить за моими комментариями и показывать примеры, устанавливая меньшие r и удаление полей подзаговора с помощью subplots_adjust:

 
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure()
f = fig.add_subplot(2, 1, 1, projection='3d')
t = fig.add_subplot(2, 1, 2, projection='3d')

# axes
for d in {f, t}:
    d.plot([-1, 1], [0, 0], [0, 0], color='k', alpha=0.8, lw=2)
    d.plot([0, 0], [-1, 1], [0, 0], color='k', alpha=0.8, lw=2)
    d.plot([0, 0], [0, 0], [-1, 1], color='k', alpha=0.8, lw=2)

f.dist = t.dist = 5.2   # 10 is default

plt.tight_layout()
f.set_aspect('equal')
t.set_aspect('equal')

r = 1
f.set_xlim3d([-r, r])
f.set_ylim3d([-r, r])
f.set_zlim3d([-r, r])

t.set_xlim3d([-r, r])
t.set_ylim3d([-r, r])
t.set_zlim3d([-r, r])

f.set_axis_off()
t.set_axis_off()

fig.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0, 
            hspace = 0, wspace = 0)

plt.draw()
plt.show()

Это даст более плотные субплоты, так как значения по умолчанию для SubplotParams следующие:

осталось: 0,125

справа: 0,9

дно: 0,1

верх: 0,9

Wspace: 0,2

hspace: 0,2

не уверен, что именно это ищет ОП, хотя...

Связанная проблема с Matplotlib:

Один из разработчиков говорит :

Да, оригинальный Axes3D не работал в рамках subplot(). А подграфики оставляют дополнительное место для меток статических осей, в то время как Axes3D необходимо учитывать дополнительное пространство для меток осей в области построения осей. Первоначально это было нормально, потому что вы не создавали объекты Axes3D с использованием подграфиков, поэтому вам не выделялись дополнительные поля для меток осей. Когда появилась возможность указатьprojection='3d'к вызову подсюжета это привело к непреднамеренному эффекту получения дополнительного поля, которое на самом деле не было необходимо.

Я так и не нашел хорошего решения для этой проблемы, которое не действовало бы вразрез с интуицией. Возможно, Axes3D необходимо переработать, чтобы он мог сам интерпретировать и выражать параметры полей, а не позволять им обрабатываться на основе 2D-допущений?

Так как вы хотите прямоугольный участок, вы не можете использовать set_aspect('equal')вместо этого вы должны настроить пределы ваших графиков, чтобы учесть разницу в пропорциях.

В приведенной ниже попытке я использовал bbox оси, чтобы получить height а также width осей и использовал соотношение сторон для масштабирования X а также Y Оси. (Я предполагал, что оба графика имеют одинаковое измерение, но у вас также могут быть графики с разными размерами, вам просто нужно настроить пределы осей независимо для каждого из них).

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure()
f = fig.add_subplot(2, 1, 1, projection='3d')
t = fig.add_subplot(2, 1, 2, projection='3d')

# axes
for d in {f, t}:
    d.plot([-1, 1], [0, 0], [0, 0], color='k', alpha=0.8, lw=2)
    d.plot([0, 0], [-1, 1], [0, 0], color='k', alpha=0.8, lw=2)
    d.plot([0, 0], [0, 0], [-1, 1], color='k', alpha=0.8, lw=2)

f.dist = t.dist = 5.2   # 10 is default

plt.tight_layout()
# Cannot use 'equal' aspect for a rectangular plot
# f.set_aspect('equal')
# t.set_aspect('equal')

# get the dimensions of the axes from its bbox
f_bbox = f.get_position()
f_height = f_bbox.height
f_width = f_bbox.width


r = 6
f.set_xlim3d([-1 * f_width/f_height * r, f_width/f_height * r])
f.set_ylim3d([-1 * f_width/f_height * r, f_width/f_height * r])
f.set_zlim3d([-r, r])

t.set_xlim3d([-1 * f_width/f_height * r, f_width/f_height * r])
t.set_ylim3d([-1 * f_width/f_height * r, f_width/f_height * r])
t.set_zlim3d([-r, r])

f.set_axis_off()
t.set_axis_off()

plt.draw()
plt.show()

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

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