簡體   English   中英

Python for 循環在 3D 時總是繪制同一條線(使用 matplotlib)

[英]Python for-loop always plots the same line when 3D (using matplotlib)

我在 Python 中使用 matplotlib 在同一個圖形上繪制多條線,方法是使用 for 循環將每條線添加到軸上。

當以 2D 方式繪制時,每條線都在另一條線上,這很好用。

但是,在 3D 中繪圖時,每次我運行 for 循環時,python 都會顯示相同的圖形數據,即使數據明顯不同。

編輯:我不認為這個問題是“ 我如何判斷 NumPy 創建視圖還是副本? ”的重復,因為它突出了意外行為的一個特定實例。

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

###### Unimportant maths not relevant to the question ######

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 = 50*np.pi
h = 0.01
steps = int((t_f-t_0)/h)

#create plotting values
t = np.linspace(t_0,t_f,steps)
x = np.zeros(steps)
y = np.zeros(steps)
z = np.zeros(steps)

##### Relevant to the question again #####

init_condition_array = [[0,0,0],[0.1,0,0],[0.2,0,0],[0.3,0,0]]
color_array = ["red","orange","green","blue"]
color_counter = 0
zs_array = [0, 0.1, 0.2, 0.3]

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

for row in init_condition_array:
    x[0] = row[0]
    y[0] = row[1]
    z[0] = row[2]

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

    plt.plot(t,x,zs=zs_array[color_counter],zdir="z",color=color_array[color_counter])
    color_counter += 1

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

如您所見,圖表看起來應該大不相同;

這是同一軸上圖形的二維圖像,對代碼進行了一些改動(如下所示):

雖然這是 3D 繪圖生成的圖形:

.

二維圖是通過對代碼進行這些小改動而創建的; 第一行以上沒有任何改變:

init_condition_array = [[0,0,0],[0.1,0,0],[0.2,0,0],[0.3,0,0]]
color_array = ["red","orange","green","blue"]
color_counter = 0

fig = plt.figure()
ax = fig.add_subplot(111)

for row in init_condition_array:
    x[0] = row[0]
    y[0] = row[1]
    z[0] = row[2]

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

    plt.plot(t,x,color=color_array[color_counter],lw=1)
    color_counter += 1

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

for row in init_condition_array循環中的for row in init_condition_array內移動x = np.zeros(steps)修復/避免了該問題。 x被存儲在內部Line3D對象通過返回plt.plot ,和變異x影響存儲在其它值Line3Ds

在此處輸入圖片說明


如果您跟蹤通過源代碼Line3D你會發現,你傳遞給數據plt.plot在結束了Line3D_verts3d屬性。 數據不被復制; _verts3d元組包含對完全相同數組的引用。

而這個_verts3d屬性是在后面渲染的時候直接訪問的:

def draw(self, renderer):
    xs3d, ys3d, zs3d = self._verts3d

因此改變數據——即使在調用plt.plot之后——也會改變self._verts3d 這個簡單的例子演示了這個問題:

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

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
t = np.linspace(0, 1, 5)
x = np.sin(t)
line, = plt.plot(t, x, 0)

這里我們有x的原始值:

print(line._verts3d[1])
# [ 0.          0.24740396  0.47942554  0.68163876  0.84147098]

這表明變異x修改line._verts3d

x[:] = 1
print(line._verts3d[1])
# [ 1.  1.  1.  1.  1.]

# The result is a straight line, not a sine wave.
plt.show()

制作 2D 線圖時不會發生這種令人驚訝的陷阱,因為保存用於渲染的數據的Line2D._xy屬性存儲了原始數據的副本。


這個問題可以在源代碼中通過改變art3d.Line3D.set_3d_properties 這一行art3d.Line3D.set_3d_properties

self._verts3d = art3d.juggle_axes(xs, ys, zs, zdir)

import copy
self._verts3d = copy.deepcopy(art3d.juggle_axes(xs, ys, zs, zdir))

暫無
暫無

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

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