2014-12-19 32 views
21

Tôi chỉ đang cố vẽ một bề mặt và đường bao của nó ở dạng 3D, chính xác như trong ví dụ this.Cốt truyện 3D với Matplotlib

Đây là mã tôi đang sử dụng để làm điều đó:

import matplotlib.pyplot as plt 
from mpl_toolkits.mplot3d import axes3d 
from matplotlib import cm 
import numpy 

def plot_3d_contour(x_dim, y_dim, x_steps, y_steps, scalar_field, file_path): 
    fig = plt.figure() 

    x, y = numpy.mgrid[-x_dim/2:x_dim/2:x_steps*1j, -y_dim/2:y_dim/2:y_steps*1j] 
    v_min = numpy.min(scalar_field) 
    v_max = nupmy.max(scalar_field) 

    ax = fig.gca(projection='3d') 

    cset = ax.contourf(x, y, scalar_field, zdir='z', offset=v_min, cmap=cm.coolwarm) 
    cset = ax.contourf(x, y, scalar_field, zdir='x', offset=-x_dim/2-1, cmap=cm.coolwarm) 
    cset = ax.contourf(x, y, scalar_field, zdir='y', offset=y_dim/2+1, cmap=cm.coolwarm) 

    ax.plot_surface(x, y, scalar_field, rstride=10, cstride=10, alpha=0.3) 

    ax.set_xlabel('X') 
    ax.set_xlim(-x_dim/2-1, x_dim/2+1) 
    ax.set_ylabel('Y') 
    ax.set_ylim(-y_dim/2-1, y_dim/2+1) 
    ax.set_zlabel('Z') 
    ax.set_zlim(v_min, v_max) 

    plt.savefig(file_path + '.jpg') 
    plt.close() 

scalar_field = numpy.loadtxt('../scalar_field', delimiter=",") 
plot_3d_contour(12, 12, 100, 100, scalar_field, 'scalar_field3D') 

Tuy nhiên, tôi nhận được một hành vi kỳ lạ trong đó một đường viền (zdir=y) đang được trên bề mặt. Bên cạnh đó, tôi nhận được một đường viền lạ trong z_dir=z (với một phần còn thiếu):

enter image description here

Tôi đang tự hỏi những gì tôi đang mất tích. Trường vô hướng có thể được tìm thấy here.

+1

Bạn đã thử thay đổi 'zorder' khi vẽ đồ thị? – nicoguaro

+0

Vâng, đó là nỗ lực đầu tiên của tôi, @nicoguaro. – pceccon

+4

Tôi có thể tạo lại điều này trong matplotlib 1.4.0. Một trong những nhà phát triển có thể nhận xét, nhưng tôi nghĩ điều này có liên quan đến vấn đề vẽ đồ họa 3D chung - nếu bạn làm cho con số đó tương tác, bạn có thể thấy rằng thay đổi góc nhìn thay đổi mà các yếu tố được vẽ "trong nền trước". Đối với các vệt hài hước của "phi dữ liệu" trong đường viền xy-plane, nó có thể là một cái gì đó buồn cười xảy ra với "đóng cửa" của một trong những đường nét. Tôi không nghĩ có gì sai với mã của bạn. – Ajean

Trả lời

6

Tôi đồng ý với Ajean. Tôi tin rằng vấn đề phát sinh bởi vì mỗi nghệ sĩ của matplotlib (tức là PolygonCollection) được hiển thị riêng biệt. Không có cách nào các khuôn mặt khác nhau từ cùng một đối tượng được hiển thị trên các cạnh khác nhau của một đối tượng khác trong cảnh.

Đây là một mảnh hữu ích của mã:

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

file_path = "./3D_surface_and_contour.jpg" 
p = 0.05 
f = -0.01 

def get_data(p): 
    x, y, z = axes3d.get_test_data(p) 
    z = f * z 
    return x, y, z 

def plot_3d_contour(p, f): 
    nrows = 4 
    ncols = 5 

    x, y, z = get_data(p) 

    x_min, x_max = np.min(x), np.max(x) 
    y_min, y_max = np.min(y), np.max(y) 
    z_min, z_max = np.min(z), np.max(z) 

    fig = plt.figure(figsize=(15, 10)) 
    for n in range(nrows * ncols): 
     i = n % ncols 
     j = n/ncols 
     k = n + 1 
     if j == 0: 
      azim = -60 + (i - 2) * 15 
      elev = 30 
     elif j == 1: 
      azim = -60 
      elev = 30 + (i - 2) * 5 
     elif j == 2: 
      azim = 60 + (i - 2) * 10 
      elev = 30 
     elif j == 3: 
      azim = 60 
      elev = 30 + (i - 2) * 5 
     ax = fig.add_subplot(nrows, ncols, k, projection='3d') 
     ax.set_title("azim=" + str(azim) + " elev=" + str(elev)) 
     ax.tick_params(labelsize=8) 
     ax.view_init(azim=azim, elev=elev) 
     ax.plot_surface(x, y, z, rstride=10, cstride=10, alpha=0.3) 
     ax.contourf(x, y, z, zdir='z', offset=z_min, cmap=cm.coolwarm) 
     ax.contourf(x, y, z, zdir='x', offset=x_min, cmap=cm.coolwarm) 
     if j == 0 or j == 1: 
      ax.contourf(x, y, z, zdir='y', offset=y_max, cmap=cm.coolwarm) 
     elif j == 2 or j == 3: 
      ax.contourf(x, y, z, zdir='y', offset=y_min, cmap=cm.coolwarm) 

     ax.set_xlabel('X') 
     ax.set_xlim(x_min, x_max) 
     ax.set_ylabel('Y') 
     ax.set_ylim(y_min, y_max) 
     ax.set_zlabel('Z') 
     ax.set_zlim(z_min, z_max) 

    plt.savefig(file_path, dpi=80) 
    plt.close() 

plot_3d_contour(p, f) 

mang đến cho hình ảnh sau:

enter image description here

Hai hàng đầu tiên được sản xuất bởi một mã số tương tự như của bạn. Bạn có thể nhận thấy rằng việc đặt độ cao bằng view_init thành giá trị cao hơn sẽ giải quyết được sự cố. Nhưng nó không phải là thỏa đáng. Tôi cũng đã xác định ảnh hưởng của phạm vi giá trị z (không được hiển thị ở đây), lỗi dường như chỉ xuất hiện khi phạm vi này nhỏ (bạn có thể sử dụng tham số f để kiểm tra nó), giải thích tại sao example không bị ảnh hưởng từ nó.

Giải pháp tôi đề xuất là thay thế:

ax.contourf(x, y, scalar_field, zdir='y', offset=y_dim/2+1, cmap=cm.coolwarm) 

bởi:

ax.contourf(x, y, scalar_field, zdir='y', offset=-y_dim/2-1, cmap=cm.coolwarm) 

trong mã của bạn và thêm dòng bổ sung này:

ax.view_init(azim=60, elev=30) 

Như đã trình bày ở vòng hai các hàng của hình ảnh trước đó, theo cách này, bạn sẽ có thể tránh được những whims của matplotlib.

+0

Không biết về @Baptiste! Cảm ơn bạn!! – pceccon

Các vấn đề liên quan