我通过使用for循环将每条线添加到轴上,在Python中使用matplotlib在同一张图上绘制多条线。

当以2D绘制时,每条线都在另一条线的上方,则效果很好。

但是,当以3D绘图时,即使我的数据有显着差异,每次运行for循环时,python也会显示相同的图形化数据。

编辑:我不相信这个问题是“ How can I tell if NumPy creates a view or a copy?”的重复,因为它突出了意外行为的一个特定实例。

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


如您所见,这些图形看起来应该非常不同。

这是同一轴上图形的2D图像,并对代码做了一些改动(如下所示):



这是3D图生成的图形:



通过对代码进行这些小的更改来创建2D图。第一行上方的内容均未更改:

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

最佳答案

x = np.zeros(steps)循环内移动for row in init_condition_array可以解决/避免该问题。 x存储在Line3D返回的plt.plot对象内部,并且对x进行更改会影响另一个Line3Ds中存储的值。

python - 3D时,Python for循环总是绘制同一条线(使用matplotlib)-LMLPHP



如果您通过source code for 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中的this line在源代码中解决此问题

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




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

关于python - 3D时,Python for循环总是绘制同一条线(使用matplotlib),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36356952/

10-12 22:09
查看更多