Setting aspect ratio of 3D plot

匿名 (未验证) 提交于 2019-12-03 02:14:01

问题:

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. 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. 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:

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

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.

Edit: So the desired output would be something like the following (crudely edited with Inkscape) image. 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.

回答1:

Add following code before 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:

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

then add one line to set pbaspect:

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



回答2:

The answer to this question works perfectly for me. And you do not need to set up any ratio, it does everything automatically.



回答3:

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


转载请标明出处:Setting aspect ratio of 3D plot
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!