简体   繁体   English

设置3D图的纵横比

[英]Setting aspect ratio of 3D plot

I am trying to plot a 3D image of the seafloor from the data of a sonar run over a 500m by 40m portion of the seafloor. 我正在尝试从遍及海底500m x 40m的声纳数据绘制海底3D图像。 I am using matplotlib/mplot3d with Axes3D and I want to be able to change the aspect ratio of the axes so that the x & y axis are to scale. 我将Matplotlib / mplot3d与Axes3D结合使用,并且希望能够更改轴的纵横比,以使x和y轴缩放。 An example script with generated data rather than the real data is: 具有生成的数据而非实际数据的示例脚本为:

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')

And the output image from this script: 以及此脚本的输出图像:

matplotlib输出图像

Now I would like to change it so that 1 metre in the along-track (x) axis is the same as 1 metre in the range (y) axis (or maybe a different ratio depending on the relative sizes involved). 现在,我想对其进行更改,以使沿轨迹(x)轴的1米与范围(y)轴的1米相同(或取决于相关的相对大小,其比率可能不同)。 I would also like to set the ratio of the z-axis, again not neccessarily to 1:1 due to the relative sizes in the data, but so the axis is smaller than the current plot. 我还想设置z轴的比例,由于数据的相对大小,也不必将其设置为1:1,但是该轴小于当前图。

I have tried building and using this branch of matplotlib , following the example script in this message from the mailing list , but adding the ax.pbaspect = [1.0, 1.0, 0.25] line to my script (having uninstalled the 'standard' version of matplotlib to ensure the custom version was being used) didn't make any difference in the generated image. 我已尝试按照邮件列表此消息中的示例脚本来构建和使用matplotlib的此分支 ,但是在我的脚本中添加了ax.pbaspect = [1.0, 1.0, 0.25]行(已卸载了标准版的matplotlib以确保正在使用自定义版本)对生成的图像没有任何影响。

Edit: So the desired output would be something like the following (crudely edited with Inkscape) image. 编辑:因此所需的输出将类似于以下图像(使用Inkscape进行了详细编辑)。 In this case I haven't set a 1:1 ratio on the x/y axes because that looks ridiculously thin, but I have spread it out so it isn't square as on the original output. 在这种情况下,我没有在x / y轴上设置1:1的比例,因为它看起来太稀薄了,但是我将其散开了,因此与原始输出不一样。

所需的输出

Add following code before savefig: 在savefig之前添加以下代码:

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

在此处输入图片说明

If you want no square axis: 如果您不希望方轴:

edit the get_proj function inside site-packages\\mpl_toolkits\\mplot3d\\axes3d.py: 编辑get_proj站点包\\ 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])

then add one line to set pbaspect: 然后添加一行以设置pbaspect:

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

在此处输入图片说明

The answer to this question works perfectly for me. 这个问题的答案非常适合我。 And you do not need to set up any ratio, it does everything automatically. 而且您无需设置任何比率,它会自动执行所有操作。

That how i solved the wasted space problem: 那就是我如何解决空间浪费的问题:

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))

An issue has been opened over at github: https://github.com/matplotlib/matplotlib/issues/8593 在github上已经打开了一个问题: https : //github.com/matplotlib/matplotlib/issues/8593

The above solutions don't seem to work any more. 上面的解决方案似乎不再起作用。 One has to edit the get_proj function inside site-packages\\mpl_toolkits\\mplot3d\\axes3d.py in the following way now: 现在必须以以下方式在site-packages\\mpl_toolkits\\mplot3d\\axes3d.py中编辑get_proj函数:

        try:
            self.localPbAspect = self.pbaspect
        except AttributeError:
            self.localPbAspect = [1,1,1]

        xmin, xmax = ( lim / self.localPbAspect[0] for lim in self.get_xlim3d() )
        ymin, ymax = ( lim / self.localPbAspect[1] for lim in self.get_ylim3d() )
        zmin, zmax = ( lim / self.localPbAspect[2] for lim in self.get_zlim3d() )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM