2012-04-26 31 views
26

Tôi đang cố vẽ một hình ảnh 3D của đáy biển từ dữ liệu của sóng siêu âm chạy trên một đoạn từ 500m đến 40m của đáy biển. Tôi đang sử dụng matplotlib/mplot3d với Axes3D và tôi muốn có thể thay đổi tỷ lệ khung hình của trục sao cho trục x & y là tỷ lệ. Một kịch bản ví dụ với dữ liệu được tạo chứ không phải là dữ liệu thực tế là:Cài đặt tỷ lệ co của ô 3D

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

Và hình ảnh đầu ra từ kịch bản này:

matplotlib output image

Bây giờ tôi muốn thay đổi nó để 1 mét trong trục dọc (x) giống với 1 mét trong trục (y) (hoặc có thể là một tỷ số khác nhau tùy thuộc vào kích thước tương đối có liên quan). Tôi cũng muốn thiết lập tỷ lệ của trục z, một lần nữa không cần thiết đến 1: 1 do kích thước tương đối trong dữ liệu, nhưng do đó trục nhỏ hơn âm mưu hiện tại.

Tôi đã cố gắng xây dựng và sử dụng this branch of matplotlib, sau kịch bản ví dụ trong this message from the mailing list, nhưng thêm dòng ax.pbaspect = [1.0, 1.0, 0.25] để kịch bản của tôi (sau khi gỡ bỏ cài đặt các phiên bản 'tiêu chuẩn' của matplotlib để đảm bảo phiên bản tùy chỉnh đã được sử dụng) đã không làm bất kỳ sự khác biệt nào trong hình ảnh được tạo.

Chỉnh sửa: Vì vậy, đầu ra mong muốn sẽ giống như hình ảnh sau (được chỉnh sửa thô lỗ với Inkscape). Trong trường hợp này, tôi đã không đặt tỷ lệ 1: 1 trên trục x/y vì nó trông rất mỏng, nhưng tôi đã trải nó ra sao cho nó không vuông như trên đầu ra ban đầu.

Desired output

Trả lời

18

Thêm mã sau đây trước savefig:

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

enter image description here

Nếu bạn không muốn một trục vuông:

chỉnh sửa các get_proj chức năng bên trong trang web gói \ mpl_toolkits \ mplot3d \ axes3d.py:

xmin, xmax = self.get_xlim3d()/self.pbaspect[0] 
ymin, ymax = self.get_ylim3d()/self.pbaspect[1] 
zmin, zmax = self.get_zlim3d()/self.pbaspect[2] 

sau đó thêm một dòng vào thiết pbaspect:

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

enter image description here

+0

Hmmm. Điều đó có được sự mở rộng của trục chính xác, nhưng kết quả trong rất nhiều không gian lãng phí. Trong khi tôi * có thể * lưu nó thành SVG và chỉnh sửa nó theo cách thủ công (giống như những gì tôi đã làm với hình ảnh mong muốn, tôi chỉ cập nhật câu hỏi với) điều này sẽ rất tẻ nhạt khi tôi có nhiều hình ảnh để tạo và tôi không chắc chắn nó có thể được tự động ... – Blair

+1

Bạn có thể sử dụng sửa đổi pbaspect để không có trục vuông. Tôi đã chỉnh sửa câu trả lời. – HYRY

+0

Tuyệt vời, cảm ơn! – Blair

5

Câu trả lời cho this question công trình hoàn hảo cho tôi. Và bạn không cần thiết lập bất kỳ tỷ lệ nào, nó sẽ tự động làm mọi thứ.

0

Đó làm thế nào tôi giải quyết vấn đề không gian lãng phí:

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)) 
Các vấn đề liên quan