Paramétrage du rapport d'aspect de la parcelle 3D

j'essaie de tracer une image 3D du fond marin à partir des données d'un sonar sur une portion de 500m par 40m du fond marin. J'utilise matplotlib / mplot3d avec Axes3D et je veux être capable de changer le rapport d'aspect des axes pour que l'axe x & y soit à l'échelle. Un exemple de script avec des données générées plutôt que les données réelles est:

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

et l'image de sortie de ce script:

matplotlib output image

maintenant, je voudrais le changer de sorte que 1 mètre dans l'axe le long de la piste (x) soit le même que 1 mètre dans l'axe de la gamme (y) (ou peut-être un rapport différent selon les tailles relatives impliquées). Je voudrais aussi régler le rapport de l'axe z, encore une fois pas nécessairement à 1:1 en raison des tailles relatives dans les données, mais donc l'axe est plus petit que le graphe actuel.

j'ai essayé de construire et d'utiliser cette branche de matplotlib , suite à la exemple de script dans ce message de la liste de diffusion , mais ajouter la ligne ax.pbaspect = [1.0, 1.0, 0.25] à mon script (après avoir désinstallé la version "standard" de matplotlib pour s'assurer que la version personnalisée était utilisée) n'a pas fait de différence dans l'image générée.

Edit: de Sorte que la sortie désirée serait quelque chose comme ce qui suit (grossièrement édité avec Inkscape) de l'image. Dans ce cas, je n'ai pas fixé de ratio 1:1 sur les axes x / y parce que ça a l'air ridiculement mince, mais je l'ai étalé pour qu'il ne soit pas carré comme sur la sortie originale.

Desired output

26
demandé sur Blair 2012-04-26 06:18:31

3 réponses

ajouter le code suivant avant savefig:

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

enter image description here

si vous ne voulez pas d'axe carré:

éditer la fonction get_proj à l'intérieur 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])

puis Ajouter une ligne pour définir pbaspect:

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

enter image description here

19
répondu HYRY 2018-07-13 17:24:27

la réponse à cette question fonctionne parfaitement pour moi. Et vous n'avez pas besoin de configurer de ratio, il fait tout automatiquement.

6
répondu ole 2017-05-23 11:46:42

comment j'ai résolu le gaspillage de l'espace de problème:

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
répondu Hexander 2017-02-01 10:14:45