我试图从海底500米乘40米部分的声纳数据绘制海底的3D图像。我正在使用带有Axes3D的matplotlib / mplot3d,我希望能够改变轴的纵横比,以便x& y轴是按比例的。生成数据而非实际数据的示例脚本是:
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')
来自此脚本的输出图像:
现在我想改变它,使得沿着轨道(x)轴的1米与范围(y)轴中的1米相同(或者根据所涉及的相对尺寸可以是不同的比率)。由于数据中的相对大小,我还想设置z轴的比率,再次不是必须达到1:1,但是因此轴小于当前的图。
我已尝试按照this branch of matplotlib中的示例脚本构建和使用this message from the mailing list,但在我的脚本中添加ax.pbaspect = [1.0, 1.0, 0.25]
行(已卸载matplotlib的'标准'版本以确保正在使用自定义版本)在生成的图像中没有任何区别。
编辑:因此,所需的输出将类似于以下内容(使用Inkscape粗略编辑)图像。在这种情况下,我没有在x / y轴上设置1:1的比例,因为它看起来非常薄,但是我把它展开,所以它不像原始输出那样是正方形。
答案 0 :(得分:21)
在savefig之前添加以下代码:
ax.auto_scale_xyz([0, 500], [0, 500], [0, 0.15])
如果您不想要方轴:
编辑site-packages \ mpl_toolkits \ mplot3d \ axes3d.py中的get_proj
函数:
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]
答案 1 :(得分:6)
this question的答案对我来说非常合适。而且您不需要设置任何比例,它会自动完成所有操作。
答案 2 :(得分: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))
答案 3 :(得分:0)
问题已在github上公开:https://github.com/matplotlib/matplotlib/issues/8593
上述解决方案似乎不再起作用。现在必须按照以下方式在get_proj
内部编辑site-packages\mpl_toolkits\mplot3d\axes3d.py
函数:
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() )