在发布在问题How can I draw a multiple 3d-curves picture by Python?中的代码中,plot方法被调用了两次,由于要绘制的点没有重置,所以这些行被淹没在另一个上面。但是如果我们尝试使用分散法,我们可以看到在不同位置绘制的点,而不是{
代码复制如下
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
import math as mt
from mpl_toolkits.mplot3d import Axes3D
t=2 #t can be changed
fig = plt.figure()
ax=Axes3D(fig)
#data
def unitilize(x,y,z):
r=mt.sqrt(x**2+y**2+z**2)
return x/r, y/r, z/r
def g_1(x,y,z):
x=t*x
z=z/t
x,y,z=unitilize(x,y,z)
return x,y,z
stepCnt=10000 ######step
#########data#################
xs = np.empty((stepCnt + 1,))
ys = np.empty((stepCnt + 1,))
zs = np.empty((stepCnt + 1,))
#Setting initial values
def huatu(x,y,z):
xs[0], ys[0], zs[0] =unitilize(x,y,z)
for i in range(stepCnt):
xs[i+1],ys[i+1],zs[i+1]=g_1(xs[i], ys[i], zs[i])
return xs,ys,zs
xs3,ys3,zs3=huatu(1,10,40)
ax.plot(xs3, ys3, zs3, color='b', marker='x')
xs2,ys2,zs2=huatu(1,0,40)
ax.plot(xs2, ys2, zs2, color='r', marker='o')
plt.show()
所以,你发现了一些很奇怪的东西,我还没能找到它的确切来源。底线是
Axes3D.plot
(和Axes.plot
绘制的线实际上是如何创建的)不会复制它们的输入数据,而是与视图一起工作。这意味着,当数据随后发生突变时,曲线图可能会发生变化。由于某些原因,同样使用视图的Axes.plot
没有重现这种可变性。这可能与Axes3D
对象如何更新有关,我不太清楚。在无论如何,
Axes3D.scatter
另一方面创建PathCollection
对象(转换为PathCollection3D
),这些对象具有更复杂的内部工作。据我所知,这些对象(已经在2d中)使用一个._offsets
属性,它是从输入坐标构建的ndarray
。通过构造,这些数组独立于输入数据。在让我们比较一下
plot
的情况,看看我的意思。对于通常的二维图:结果包含原始平面零线:
请注意,中间的几个
print
调用验证了附加到plot
创建的line对象的数据确实是输入数据的视图(而不是副本),因此这里的效果不佳是因为修改数据的方式反映在绘图上。在案例比较3d:
^{pr2}$我们只对3d轴对象(以及一个多维度)执行完全相同的操作,结果如下:
如您所见,原始源数组的变异很好地更新了绘图,与2d情况完全相反。在
我不太确定这是怎么发生的;^{} 外包most of the problem to ^{} (好吧,2d部分),然后pulls out all the data along the third dimension。由于在这两种情况下,行都是由
Axes.plot
创建的,所以这两种方法都不会复制它们的输入数据。在^{} 非常类似地让^{} 执行2d任务。虽然我不明白2d和3d的
plot
大小写之间的区别,但我发现这一部分更容易理解:PathCollection(3D)
对象要复杂得多,如果不与原始数据数组分离,就无法进行组装。在因此,在您的问题代码中,生成要绘制的数据的函数实际上改变(并返回)相同的数组
xs,ys,zs
。因为基本上每个绘图都使用相同的数组,所以您看到的结果取决于绘图调用是否对其数据源的变异敏感。对于Axes3D.plot
这是这种情况,因此对数据生成函数的第二次调用修改了第一个绘图;而对于Axes3D.scatter
,数据源的突变不会影响绘图,因此两个图都如预期可见。在如果您想看到真的奇怪,请尝试使用列表输入而不是ndarray的3d示例:
在这种情况下,我希望输入列表被转换成ndarray,因此变异不会起任何作用,我们得到一条平坦的零线。事实并非如此:
显然y坐标没有改变,但是z坐标发生了变化。这太奇怪了!关键是绘图的基础数据数组:
当^{} hacks the z coordinates 通过调用^{} 进入绘图时,函数grabs the existing x and y arrays from the 2d plot and just slaps the z coordinates next to them。在
将{26}中的一个{26>转换为z输入是单独处理的,并且在完成所有操作后它不会受到损害。这就是为什么}的突变最终只改变了{}。在
y
和{作为结束语,我查看了matplotlib问题页面,找到了2d案例的this relevant discussion。解决的办法似乎是,二维绘图不复制数据,因为这通常会增加不必要的开销。我还可以看到3d案件是如何处理不同的,这将导致令人惊讶的行为。在
不管怎样,我不这么认为nk改变传递给绘图方法的数据是合理的。如果您是故意这样做的,请使用专用方法,如
pl.set_xdata()
。同样,这对于3d绘图来说是不可能的(其中x/ydata属性被重新解释为引用不同种类的坐标)。所以我的建议是不要对源数组进行变异,或者手动传递一个副本,以防以后需要对这些数组进行变异。变异不能被禁止,但我也能理解为什么matplotlib开发人员不想在每种情况下都复制每一个输入。所以最有可能的解决方案是用户不应该改变他们的原始数据。有些东西告诉我,写问题中代码的人没有意识到他们一开始就在改变输入,这意味着我们仍将看到一个有效的用例,其中输入数组被有意地改变。在相关问题 更多 >
编程相关推荐