簡體   English   中英

線框在 numpy matplotlib mplot3d 中以錯誤的方式加入

[英]Wireframe joins the wrong way in numpy matplotlib mplot3d

我正在嘗試使用 matplotlib 在 Python 中創建一個 3D 線框。

然而,當我開始繪制實際的圖形時,線框以錯誤的方式加入,如下圖所示。

如何強制 matplotlib 沿某個軸加入線框?

我的代碼如下:

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

def rossler(x_n, y_n, z_n, h, a, b, c):
#defining the rossler function
x_n1=x_n+h*(-y_n-z_n)
y_n1=y_n+h*(x_n+a*y_n)
z_n1=z_n+h*(b+z_n*(x_n-c))   
return x_n1,y_n1,z_n1

#defining a, b, and c
a = 1.0/5.0
b = 1.0/5.0
c = 5

#defining time limits and steps
t_0 = 0
t_f = 32*np.pi
h = 0.01
steps = int((t_f-t_0)/h)

#3dify
c_list = np.linspace(5,10,6)
c_size = len(c_list)
c_array = np.zeros((c_size,steps))

for i in range (0, c_size):
    for j in range (0, steps):
        c_array[i][j] = c_list[i]

#create plotting values
t = np.zeros((c_size,steps))
for i in range (0, c_size):
    t[i] = np.linspace(t_0,t_f,steps)
x = np.zeros((c_size,steps))
y = np.zeros((c_size,steps))
z = np.zeros((c_size,steps))
binvar, array_size = x.shape

#initial conditions
x[0] = 0
y[0] = 0
z[0] = 0

for j in range(0, c_size-1):
    for i in range(array_size-1):
        c = c_list[j]
        #re-evaluate the values of the x-arrays depending on the initial conditions
        [x[j][i+1],y[j][i+1],z[j][i+1]]=rossler(x[j][i],y[j][i],z[j][i],t[j][i+1]-t[j][i],a,b,c)

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_wireframe(t,x,c_array, rstride=10, cstride=10)
plt.show()

我得到這個作為輸出:

在此處輸入圖片說明

另一個角度的相同輸出:

在此處輸入圖片說明

而我希望線框沿着波峰連接。 對不起,我不能給你我想看的圖片,這是我的問題,但我想它更像是教程圖片。

我不確定你到底想達到什么目的,但我認為它不會奏效。

這是您的數據逐層繪制時的樣子(無填充和有填充):

無填充 填充

您正在嘗試將其繪制為線框圖。 根據手冊,線框圖如下所示:

示例線框

注意巨大的差異:線框圖本質上是一個適當的表面圖,唯一的區別是表面的面是完全透明的。 這也意味着您只能繪制

  1. z(x,y) 形式的單值函數,此外
  2. 在矩形網格上指定(至少在拓撲上)

您的數據既不是:你點沿着給出,它們堆疊在彼此的頂部,所以沒有機會,這是一個單一的表面,可以被繪制。

如果您只是想將您的功能彼此可視化,以下是我繪制上述數字的方式:

from mpl_toolkits.mplot3d.art3d import Poly3DCollection

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
for zind in range(t.shape[0]):
    tnow,xnow,cnow = t[zind,:],x[zind,:],c_array[zind,:]
    hplot = ax.plot(tnow,xnow,cnow)

    # alternatively fill:
    stride = 10
    tnow,xnow,cnow = tnow[::stride],xnow[::stride],cnow[::stride]
    slice_from = slice(None,-1)
    slice_to = slice(1,None)
    xpoly = np.array([tnow[slice_from],
                      tnow[slice_to],
                      tnow[slice_to],
                      tnow[slice_from]]
                      ).T
    ypoly = np.array([xnow[slice_from],
                      xnow[slice_to],
                      np.zeros_like(xnow[slice_to]),
                      np.zeros_like(xnow[slice_from])]
                      ).T
    zpoly = np.array([cnow[slice_from],
                      cnow[slice_to],
                      cnow[slice_to],
                      cnow[slice_from]]
                      ).T

    tmppoly = [tuple(zip(xrow,yrow,zrow)) for xrow,yrow,zrow in zip(xpoly,ypoly,zpoly)]
    poly3dcoll = Poly3DCollection(tmppoly,linewidth=0.0)
    poly3dcoll.set_edgecolor(hplot[0].get_color())
    poly3dcoll.set_facecolor(hplot[0].get_color())
    ax.add_collection3d(poly3dcoll)

plt.xlabel('t')
plt.ylabel('x')
plt.show()

還有另一種選擇:切換坐標軸,使 (x,t) 對對應於垂直平面而不是水平平面。 在這種情況下,不同c值的函數繪制在平行平面上。 這允許正確使用線框圖,但由於您的函數在不同的時間步長中具有極值,因此結果與您的原始圖一樣令人困惑。 可以嘗試沿t軸使用很少的圖,並希望極值接近。 這種方法需要很多猜測,我沒有嘗試自己做。 不過,您可以將每個函數繪制為填充曲面:

from matplotlib.collections import PolyCollection

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
for zind in range(t.shape[0]):
    tnow,xnow,cnow = t[zind,:],x[zind,:],c_array[zind,:]
    hplot = ax.plot(tnow,cnow,xnow)
    # alternative to fill:
    stride = 10
    tnow,xnow,cnow = tnow[::stride],xnow[::stride],cnow[::stride]
    slice_from = slice(None,-1)
    slice_to = slice(1,None)
    xpoly = np.array([tnow[slice_from],
                      tnow[slice_to],
                      tnow[slice_to],
                      tnow[slice_from]]
                      ).T
    ypoly = np.array([xnow[slice_from],
                      xnow[slice_to],
                      np.zeros_like(xnow[slice_to]),
                      np.zeros_like(xnow[slice_from])]
                      ).T
    tmppoly = [tuple(zip(xrow,yrow)) for xrow,yrow in zip(xpoly,ypoly)]
    polycoll = PolyCollection(tmppoly,linewidth=0.5)
    polycoll.set_edgecolor(hplot[0].get_color())
    polycoll.set_facecolor(hplot[0].get_color())
    ax.add_collection3d(polycoll,zdir='y',zs=cnow[0])
    hplot[0].set_color('none')

ax.set_xlabel('t')
ax.set_zlabel('x')
plt.show()

這會導致如下結果: 旋轉填充圖

但是,有幾點需要注意。

  1. 由於缺乏深度信息,3d 散點圖和線圖很難理解。 您可能正在以一種根本錯誤的方式處理您的可視化問題:也許還有其他選項可以使您的數據可視化。
  2. 即使你做了類似我展示的圖的事情,你也應該意識到 matplotlib 在歷史上一直未能正確繪制復雜的 3d 對象。 現在,“正確”是指“具有物理上合理的表觀深度”,另請參閱mplot3d 常見問題解答說明,准確描述了這一點。 問題的核心是matplotlib將每個3d對象投影到2d,然后將這些煎餅一個接一個地繪制在屏幕上。 有時,煎餅斷言的繪制順序與它們的實際相對深度不對應,這會導致人工制品對人類來說非常明顯,而且看起來也很不可思議。 如果您仔細查看這篇文章中的第一個填充圖,您會發現金色平坦圖位於洋紅色圖后面,即使它應該在其頂部。 類似的事情經常發生在3d 條形圖復雜曲面上
  3. 當你說“對不起,我不能給你一張我想看的圖片,那是我的問題”,你就大錯特錯了。 這不僅僅是你的問題。 您可能在腦海中清楚地知道您想要實現什么,但除非您非常清楚地描述您在腦海中看到的內容,否則外界將不得不依靠猜測。 通過盡可能提供信息,您可以使他人和您自己的工作更輕松。

如果我理解,您想將 6 條軌跡與多邊形聯系起來。 您可以通過對軌跡進行 2 x 2 三角測量,然后繪制沒有邊緣或抗鋸齒的表面來實現。 也許選擇一個好的顏色圖也會有所幫助。

請記住,這將是一個非常沉重的情節。 導出的 SVG 重量為 10mb :)

import matplotlib.tri as mtri

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

for LineIndex in range(c_size-1):
    # If plotting all at once, you get a MemoryError. I'll plot each 6 points
    for Sample in range(0, array_size-1, 3):
        # I switched x and c_array, because the surface  and the triangles 
        # will look better by default
        X = np.concatenate([t[LineIndex,Sample:Sample+3], t[LineIndex+1,Sample:Sample+3]])
        Y = np.concatenate([c_array[LineIndex,Sample:Sample+3], c_array[LineIndex+1,Sample:Sample+3]])
        Z = np.concatenate([x[LineIndex,Sample:Sample+3], x[LineIndex+1,Sample:Sample+3]])
        T = mtri.Triangulation(X, Y)

        ax.plot_trisurf(X, Y, Z, triangles=T.triangles, edgecolor='none', antialiased=False)

ax.set_xlabel('t')
ax.set_zlabel('x')
plt.savefig('Test.png', format='png', dpi=600)
plt.show()

這是生成的圖像: 在此處輸入圖片說明

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM