web-dev-qa-db-ja.com

3Dプロットのアスペクト比の設定

海底の500m x 40mの部分を走るソナーのデータから海底の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')

そして、このスクリプトからの出力画像:

matplotlib output image

ここで、トラックに沿った(x)軸の1メートルが範囲(y)軸の1メートルと同じになるように(または、関連する相対的なサイズに応じて比率が異なるように)変更します。また、データの相対的なサイズにより、Z軸の比率を1:1に設定する必要はありませんが、軸は現在のプロットよりも小さくなります。

matplotlibのこのブランチ を作成して使用してみましたが、- このメーリングリストからのメッセージ のスクリプト例に従っていますが、ax.pbaspect = [1.0, 1.0, 0.25]スクリプトへの行(「カスタム」バージョンが使用されていることを確認するためにmatplotlibの「標準」バージョンをアンインストールしました)は、生成されたイメージに違いを生じませんでした。

Edit:したがって、必要な出力は次のような画像になります(Inkscapeで完全に編集したもの)。この場合、x/y軸に1:1の比率を設定していません。これは、途方もなく薄いように見えるためですが、元の出力のように正方形にならないように広げています。

Desired output

30
Blair

Savefigの前に次のコードを追加します。

ax.auto_scale_xyz([0, 500], [0, 500], [0, 0.15])

enter image description here

正方形の軸が必要ない場合:

get_proj site-packages\mpl_toolkits\mplot3d\axes3d.py内の関数:

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

次に、1行を追加してpbaspectを設定します。

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

enter image description here

21
HYRY

この質問 への答えは、私にとって完璧に機能します。また、比率を設定する必要はありません。すべてが自動的に行われます。

6
user1329187

Githubで問題が解決されました: https://github.com/matplotlib/matplotlib/issues/859

上記のソリューションはもう機能しないようです。 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() )
0
Bastian

無駄なスペースの問題をどのように解決したか:

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