105

3Dグラフに等しいアスペクト比を設定すると、z-axisは「等しい」に変わりません。したがって、この:

fig = pylab.figure()
mesFig = fig.gca(projection='3d', adjustable='box')
mesFig.axis('equal')
mesFig.plot(xC, yC, zC, 'r.')
mesFig.plot(xO, yO, zO, 'b.')
pyplot.show()

私に次のことを与えます:

img1

明らかに、z軸の単位長がxおよびy単位と等しくない場合。

3軸すべての単位長を等しくするにはどうすればよいですか?私が見つけたすべての解決策は機能しませんでした。

4

8 に答える 8

76

matplotlib はまだ 3D で正しく等しい軸を設定していないと思います...しかし、私はそれを使用して適応させたトリックを少し前に見つけました (場所は覚えていません)。コンセプトは、データの周りに偽の立方体境界ボックスを作成することです。次のコードでテストできます。

from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure()
ax = fig.add_subplot(projection='3d')
ax.set_aspect('equal')

X = np.random.rand(100)*10+5
Y = np.random.rand(100)*5+2.5
Z = np.random.rand(100)*50+25

scat = ax.scatter(X, Y, Z)

# Create cubic bounding box to simulate equal aspect ratio
max_range = np.array([X.max()-X.min(), Y.max()-Y.min(), Z.max()-Z.min()]).max()
Xb = 0.5*max_range*np.mgrid[-1:2:2,-1:2:2,-1:2:2][0].flatten() + 0.5*(X.max()+X.min())
Yb = 0.5*max_range*np.mgrid[-1:2:2,-1:2:2,-1:2:2][1].flatten() + 0.5*(Y.max()+Y.min())
Zb = 0.5*max_range*np.mgrid[-1:2:2,-1:2:2,-1:2:2][2].flatten() + 0.5*(Z.max()+Z.min())
# Comment or uncomment following both lines to test the fake bounding box:
for xb, yb, zb in zip(Xb, Yb, Zb):
   ax.plot([xb], [yb], [zb], 'w')

plt.grid()
plt.show()

z データは x および y よりも約 1 桁大きいですが、等軸オプションを使用しても、matplotlib は z 軸を自動スケーリングします。

悪い

しかし、バウンディング ボックスを追加すると、正しいスケーリングが得られます。

ここに画像の説明を入力

于 2012-12-04T11:21:58.443 に答える
7

編集: user2525140 のコードは完全に正常に動作するはずですが、この回答は存在しないエラーを修正しようとしたと思われます。以下の答えは、単なる複製 (代替) 実装です。

def set_aspect_equal_3d(ax):
    """Fix equal aspect bug for 3D plots."""

    xlim = ax.get_xlim3d()
    ylim = ax.get_ylim3d()
    zlim = ax.get_zlim3d()

    from numpy import mean
    xmean = mean(xlim)
    ymean = mean(ylim)
    zmean = mean(zlim)

    plot_radius = max([abs(lim - mean_)
                       for lims, mean_ in ((xlim, xmean),
                                           (ylim, ymean),
                                           (zlim, zmean))
                       for lim in lims])

    ax.set_xlim3d([xmean - plot_radius, xmean + plot_radius])
    ax.set_ylim3d([ymean - plot_radius, ymean + plot_radius])
    ax.set_zlim3d([zmean - plot_radius, zmean + plot_radius])
于 2016-02-01T09:14:10.360 に答える