Python for-loop 在 3D 时总是绘制同一条线(使用 matplotlib)
Python for-loop always plots the same line when 3D (using matplotlib)
我在 Python 中使用 matplotlib 在同一图表上绘制多条线,方法是使用 for 循环将每条线添加到轴上。
当在 2D 中绘制时,每条线都在另一条线之上,这很好。
然而,当在 3D 中绘图时,python 每次我 运行 通过 for 循环显示相同的图形数据,即使数据明显不同。
编辑:我不认为这个问题是“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()
如您所见,图表看起来应该非常不同;
这是同一轴上图形的二维图像,对代码进行了一些改动(如下所示):
虽然这是 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
循环中移动 x = np.zeros(steps)
fixes/avoids 问题。 x
存储在 plt.plot
返回的 Line3D
对象中,改变 x
会影响存储在其他 Line3Ds
.
中的值
如果你追踪 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()
制作二维线图时不会发生这种令人惊讶的陷阱,因为保存用于渲染的数据的 Line2D._xy
属性存储了原始数据的副本。
通过将 art3d.Line3D.set_3d_properties
中的 this line 从
更改为 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 中使用 matplotlib 在同一图表上绘制多条线,方法是使用 for 循环将每条线添加到轴上。
当在 2D 中绘制时,每条线都在另一条线之上,这很好。
然而,当在 3D 中绘图时,python 每次我 运行 通过 for 循环显示相同的图形数据,即使数据明显不同。
编辑:我不认为这个问题是“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()
如您所见,图表看起来应该非常不同;
这是同一轴上图形的二维图像,对代码进行了一些改动(如下所示):
虽然这是 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
循环中移动 x = np.zeros(steps)
fixes/avoids 问题。 x
存储在 plt.plot
返回的 Line3D
对象中,改变 x
会影响存储在其他 Line3Ds
.
如果你追踪 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()
制作二维线图时不会发生这种令人惊讶的陷阱,因为保存用于渲染的数据的 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))