I am using the code written here to make a plot like this one below.
The problem is, that I want to adjust an aspect ratio, namely, to stretch it along the z-axis, so that all the stacked images are more or less visible. Is there an easy way of doing that?
Looks like there is no “proper” way to do it, but we can try monkey-patching our way around the problem. Here’s the best kludge I could do:
from mpl_toolkits.mplot3d import proj3d
def make_get_proj(self, rx, ry, rz):
'''
Return a variation on :func:`~mpl_toolkit.mplot2d.axes3d.Axes3D.getproj` that
makes the box aspect ratio equal to *rx:ry:rz*, using an axes object *self*.
'''
rm = max(rx, ry, rz)
kx = rm / rx; ky = rm / ry; kz = rm / rz;
# Copied directly from mpl_toolkit/mplot3d/axes3d.py. New or modified lines are
# marked by ##
def get_proj():
relev, razim = np.pi * self.elev/180, np.pi * self.azim/180
xmin, xmax = self.get_xlim3d()
ymin, ymax = self.get_ylim3d()
zmin, zmax = self.get_zlim3d()
# transform to uniform world coordinates 0-1.0,0-1.0,0-1.0
worldM = proj3d.world_transformation(xmin, xmax,
ymin, ymax,
zmin, zmax)
# adjust the aspect ratio ##
aspectM = proj3d.world_transformation(-kx + 1, kx, ##
-ky + 1, ky, ##
-kz + 1, kz) ##
# look into the middle of the new coordinates
R = np.array([0.5, 0.5, 0.5])
xp = R[0] + np.cos(razim) * np.cos(relev) * self.dist
yp = R[1] + np.sin(razim) * np.cos(relev) * self.dist
zp = R[2] + np.sin(relev) * self.dist
E = np.array((xp, yp, zp))
self.eye = E
self.vvec = R - E
self.vvec = self.vvec / proj3d.mod(self.vvec)
if abs(relev) > np.pi/2:
# upside down
V = np.array((0, 0, -1))
else:
V = np.array((0, 0, 1))
zfront, zback = -self.dist, self.dist
viewM = proj3d.view_transformation(E, R, V)
perspM = proj3d.persp_transformation(zfront, zback)
M0 = np.dot(viewM, np.dot(aspectM, worldM)) ##
M = np.dot(perspM, M0)
return M
return get_proj
# and later in the code:
ax.get_proj = make_get_proj(ax, 1, 1, 2)
ax.set_aspect(1.0)
As of matplotlib 3.3.0, Axes3D.set_box_aspect seems to be the recommended approach.
import matplotlib.pyplot as plt
ax = plt.axes(projection='3d')
N = 10 # some number > 1 that stretches z axis as you desire
ax.set_box_aspect((1, 1, N)) # xy aspect ratio is 1:1, but stretches z axis
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With