[英]Changing aspect ratio for 3D plots on Matplotlib
我正在嘗試使用 Matplotlib 設置 3D 圖的縱橫比。 按照這個問題的答案: 設置 3D 繪圖的縱橫比
我將解決方案應用為:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d import proj3d
def get_proj(self):
"""
Create the projection matrix from the current viewing position.
elev stores the elevation angle in the z plane
azim stores the azimuth angle in the (x, y) plane
dist is the distance of the eye viewing point from the object point.
"""
# chosen for similarity with the initial view before gh-8896
relev, razim = np.pi * self.elev/180, np.pi * self.azim/180
#EDITED TO HAVE SCALED AXIS
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])
# transform to uniform world coordinates 0-1, 0-1, 0-1
worldM = proj3d.world_transformation(xmin, xmax,
ymin, ymax,
zmin, zmax)
# look into the middle of the new coordinates
R = self.pbaspect / 2
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 / np.linalg.norm(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)
projM = self._projection(zfront, zback)
M0 = np.dot(viewM, worldM)
M = np.dot(projM, M0)
return M
Axes3D.get_proj = get_proj
然后我創建一個示例數據並繪制為:
y,z,x = np.meshgrid(range(10),-np.arange(5)[::-1],range(20))
d = np.sin(x)+np.sin(y)+np.sin(z)
iy,ix = 0,-1
iz = -1
fig,ax = plt.subplots(figsize=(5,5),subplot_kw={'projection':'3d'})
ax.pbaspect = np.array([1, 1, 1])#np.array([2.0, 1.0, 0.5])
ax.contourf(x[iz], y[iz], d[iz],zdir='z',offset=0)
ax.contourf(x[:,iy,:],d[:,iy,:],z[:,iy,:],zdir='y',offset=y.min())
ax.contourf(d[:,:,ix],y[:,:,ix],z[:,:,ix],zdir='x',offset=x.max())
color = '0.3'
ax.plot(x[0,iy,:],y[0,iy,:],y[0,iy,:]*0,color,linewidth=1,zorder=1e4)
ax.plot(x[:,iy,0]*0+x.max(),y[:,iy,0],z[:,iy,0],color,linewidth=1,zorder=1e4)
ax.plot(x[0,:,ix],y[0,:,ix],y[0,:,ix]*0,color,linewidth=1,zorder=1e4)
ax.plot(x[:,0,ix],y[:,0,ix]*0+y.min(),z[:,0,ix],color,linewidth=1,zorder=1e4)
ax.set(xlim=[x.min(),x.max()],ylim=[y.min(),y.max()],zlim=[z.min(),z.max()])
fig.tight_layout()
如果我將 pbaspect 參數設置為 (1,1,1) 我得到:
但是如果我將它設置為 (2,1,0.5) 軸似乎是正確的,但它以某種方式裁剪數據:
即使我讓 xlim、ylim 和 zlim 自動。 這個方面也有一些奇怪的地方。 有些東西告訴我軸不正交。
有人知道如何為此更正縱橫比嗎? 我還想知道如何避免軸被圖形限制裁剪。
我在網上搜索了這么久,但我找不到更好的解決方案。
更新:
我嘗試按照建議對 pbaspect 使用小於 1 的值,結果變得更好,但仍會裁剪數據:
您可以嘗試更改figsize
並調整子圖邊距,如下所示:
fig = plt.figure(figsize=(10,6))
fig.subplots_adjust(left=0.2, right=0.8, top=0.8, bottom=0.2)
ax = fig.gca(projection='3d')
ax.pbaspect = np.array([2, 1, 0.5])
ax.contourf(x[iz], y[iz], d[iz],zdir='z',offset=0)
ax.contourf(x[:,iy,:],d[:,iy,:],z[:,iy,:],zdir='y',offset=y.min())
ax.contourf(d[:,:,ix],y[:,:,ix],z[:,:,ix],zdir='x',offset=x.max())
ax.plot(x[0,iy,:],y[0,iy,:],y[0,iy,:]*0,color,linewidth=1,zorder=1e4)
ax.plot(x[:,iy,0]*0+x.max(),y[:,iy,0],z[:,iy,0],color,linewidth=1,zorder=1e4)
ax.plot(x[0,:,ix],y[0,:,ix],y[0,:,ix]*0,color,linewidth=1,zorder=1e4)
ax.plot(x[:,0,ix],y[:,0,ix]*0+y.min(),z[:,0,ix],color,linewidth=1,zorder=1e4)
plt.show()
(2,1,0.5) 的輸出:
關於消失的圖形有Matplotlib 問題:
問題的發生是由於 3D 數據減少到 2D + z 階標量。 單個值表示集合中 3D 對象所有部分的第 3 維。 因此,當兩個集合的邊界框相交時,就有可能出現這種偽影。 此外,在 matplotlib 的 2D 渲染引擎中無法正確渲染兩個 3D 對象(例如多邊形或補丁)的交集。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.