2014-12-19 164 views
21

我只是試圖在3D中繪製曲面及其輪廓,與this示例中一樣。使用Matplotlib進行3D繪圖

這是我用做它的代碼:其中一個輪廓(zdir=y)正在表面上

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

不過,我得到一個怪異的行爲。此外,我得到的z_dir=z一個奇怪的輪廓(有部分缺失):

enter image description here

我不知道我錯過了什麼。標量字段可以找到here

+1

你試圖在繪圖時更改'zorder'嗎? – nicoguaro

+0

是的,那是我第一次嘗試@nicoguaro。 – pceccon

+4

我可以在matplotlib 1.4.0中重現這一點。其中一位開發人員可能會發表評論,但我認爲這與一般的3D繪圖問題有關 - 如果您將該圖形交互式顯示,則可以看到,更改視角會更改哪些元素在「前景」中繪製。至於xy平面輪廓中的「非數據」的有趣連勝,可能是某個輪廓的「關閉」發生了一些有趣的事情。我不認爲你的代碼有什麼問題。 – Ajean

回答

6

我同意Ajean。我相信問題的出現是因爲每個matplotlib的藝術家(即PolygonCollection)都是單獨渲染的。沒有辦法在場景中的另一個對象的不同面上渲染同一對象的不同面。

這裏是一個代碼有用片:

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) 

這樣做具有下述圖像:

enter image description here

前兩行由類似你一個代碼產生的。您可能會注意到,將高程值view_init設置爲更高的值可解決問題。但這並不令人滿意。我也確定了z值範圍的影響(此處未顯示),只有當此範圍較小時(您可以使用f參數進行測試),該錯誤似乎纔會出現,這解釋了爲什麼example不受影響從中。

我提出的解決辦法是更換:

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

由:

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

,並添加此附加行:

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

由於在過去的兩年中所示以前的圖像的行,這樣你將能夠避免matplotlib的突發奇想。

+0

不知道那@Baptiste!謝謝!! – pceccon