Вопрос по matplotlib, mplot3d, python – Настройка формата изображения 3D-графика

27

Я пытаюсь построить трехмерное изображение морского дна по данным гидролокатора, пролегающего над участком морского дна размером 500 на 40 метров. Я использую matplotlib / mplot3d с Axes3D, и я хочу иметь возможность изменить соотношение сторон осей, чтобы x & amp; Ось Y в масштабе. Пример сценария с сгенерированными данными, а не с реальными данными:

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

# Create figure.
fig = plt.figure()
ax = fig.gca(projection = '3d')

# Generate example data.
R, Y = np.meshgrid(np.arange(0, 500, 0.5), np.arange(0, 40, 0.5))
z = 0.1 * np.abs(np.sin(R/40) * np.sin(Y/6))

# Plot the data.
surf = ax.plot_surface(R, Y, z, cmap=cm.jet, linewidth=0)
fig.colorbar(surf)

# Set viewpoint.
ax.azim = -160
ax.elev = 30

# Label axes.
ax.set_xlabel('Along track (m)')
ax.set_ylabel('Range (m)')
ax.set_zlabel('Height (m)')

# Save image.
fig.savefig('data.png')
</code>

И выводим изображение из этого скрипта:

matplotlib output image

Теперь я хотел бы изменить его так, чтобы 1 метр по оси вдоль траектории (x) был таким же, как 1 метр по оси диапазона (y) (или, возможно, другое соотношение в зависимости от используемых относительных размеров). Я также хотел бы установить отношение оси z, опять же не обязательно к 1: 1 из-за относительных размеров данных, но так, чтобы ось была меньше текущего графика.

Я пытался строить и использоватьэта ветка матплотлиб, следуя примеру сценария вэто сообщение из списка рассылки, но добавивax.pbaspect = [1.0, 1.0, 0.25] строка в мой сценарий (удаление «стандартной» версии matplotlib, чтобы убедиться, что используется пользовательская версия) не имеет никакого значения для сгенерированного изображения.

Edit: Таким образом, желаемым результатом будет что-то вроде следующего (грубо отредактированного с помощью Inkscape) изображения. В этом случае я не установил соотношение 1: 1 для осей x / y, потому что оно выглядит смехотворно тонким, но я разложил его так, чтобы оно не было квадратным, как на исходном выходе.

Desired output

Увидетьthis question and answers для решения. ImportanceOfBeingErnest

Ваш Ответ

3   ответа
6

этот вопрос отлично работает для меня И вам не нужно устанавливать какое-либо соотношение, оно все делает автоматически.

20

ax.auto_scale_xyz([0, 500], [0, 500], [0, 0.15])

enter image description here

Если вы не хотите иметь квадратную ось:

редактироватьget_proj функция внутри site-packages \ mpl_toolkits \ mplot3d \ axes3d.py:

xmin, xmax = np.divide(self.get_xlim3d(), self.pbaspect[0])
ymin, ymax = np.divide(self.get_ylim3d(), self.pbaspect[1])
zmin, zmax = np.divide(self.get_zlim3d(), self.pbaspect[2])

затем добавьте одну строку для установки pbaspect:

ax = fig.gca(projection = '3d')
ax.pbaspect = [2.0, 0.6, 0.25]

enter image description here

Эти оси не выглядят мне 1: 1 ...
Вы можете использовать модификацию pbaspect, чтобы получить квадратные оси. Я отредактировал ответ.
Круто, спасибо! Blair
Я думаю, что это очень полезный хак. Обратите внимание, что это в пределахget_proj функция, где нужно изменить это значение. Также обратите внимание, что после изменения, как показано здесь, вы должны датьpbaspect значение. Можно избежать этого, добавив что-то вродеtry: self.localPbAspect=self.pbaspect except AttributeError: self.localPbAspect=[1,1,1] и разделить наself.localPbAspect[...]или что-то вроде этого ... так как вы не всегда можете установитьpbaspect вручную.
Хммм. Это дает правильное масштабирование осей, но приводит к большому потерянному пространству. В то время как яcould сохранить это как SVG и отредактировать его вручную (как то, что я сделал с нужным изображением, с которым я только что обновил вопрос), это будет очень утомительно, когда у меня есть большое количество изображений для создания, и я не уверен, что это можно было автоматизировать ... Blair
0

try: 
    self.localPbAspect=self.pbaspect
    zoom_out = (self.localPbAspect[0]+self.localPbAspect[1]+self.localPbAspect[2]) 
except AttributeError: 
    self.localPbAspect=[1,1,1]
    zoom_out = 0 
xmin, xmax = self.get_xlim3d() /  self.localPbAspect[0]
ymin, ymax = self.get_ylim3d() /  self.localPbAspect[1]
zmin, zmax = self.get_zlim3d() /  self.localPbAspect[2]

# transform to uniform world coordinates 0-1.0,0-1.0,0-1.0
worldM = proj3d.world_transformation(xmin, xmax,
                                         ymin, ymax,
                                         zmin, zmax)

# look into the middle of the new coordinates
R = np.array([0.5*self.localPbAspect[0], 0.5*self.localPbAspect[1], 0.5*self.localPbAspect[2]])
xp = R[0] + np.cos(razim) * np.cos(relev) * (self.dist+zoom_out)
yp = R[1] + np.sin(razim) * np.cos(relev) * (self.dist+zoom_out)
zp = R[2] + np.sin(relev) * (self.dist+zoom_out)
E = np.array((xp, yp, zp))

Похожие вопросы