[英]Wireframe joins the wrong way in numpy matplotlib mplot3d
I'm trying to create a 3D wireframe in Python using matplotlib.我正在尝试使用 matplotlib 在 Python 中创建一个 3D 线框。
When I get to the actual graph plotting, however, the wireframe joins the wrong way, as shown in the images below.然而,当我开始绘制实际的图形时,线框以错误的方式加入,如下图所示。
How can I force matplotlib to join the wireframe along a certain axis?如何强制 matplotlib 沿某个轴加入线框?
My code is below:我的代码如下:
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()
I am getting this as an output:我得到这个作为输出:
The same output from another angle:另一个角度的相同输出:
Whereas I'd like the wireframe to join along the wave-peaks.而我希望线框沿着波峰连接。 Sorry, I can't give you an image I'd like to see, that's my problem, but I guess it'd be more like the tutorial image.对不起,我不能给你我想看的图片,这是我的问题,但我想它更像是教程图片。
I'm quite unsure about what you're exactly trying to achieve, but I don't think it will work.我不确定你到底想达到什么目的,但我认为它不会奏效。
Here's what your data looks like when plotted layer by layer (without and with filling):这是您的数据逐层绘制时的样子(无填充和有填充):
You're trying to plot this as a wireframe plot.您正在尝试将其绘制为线框图。 Here's how a wireframe plot looks like as per the manual : 根据手册,线框图如下所示:
Note the huge differene: a wireframe plot is essentially a proper surface plot, the only difference is that the faces of the surface are fully transparent.注意巨大的差异:线框图本质上是一个适当的表面图,唯一的区别是表面的面是完全透明的。 This also implies that you can only plot这也意味着您只能绘制
Your data is neither: your points are given along lines , and they are stacked on top of each other, so there's no chance that this is a single surface that can be plotted.您的数据既不是:你点沿着线给出,它们堆叠在彼此的顶部,所以没有机会,这是一个单一的表面,可以被绘制。
If you just want to visualize your functions above each other, here's how I plotted the above figures:如果您只是想将您的功能彼此可视化,以下是我绘制上述数字的方式:
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()
There is one other option: switching your coordinate axes, such that the (x,t) pair corresponds to a vertical plane rather than a horizontal one.还有另一种选择:切换坐标轴,使 (x,t) 对对应于垂直平面而不是水平平面。 In this case your functions for various c
values are drawn on parallel planes.在这种情况下,不同c
值的函数绘制在平行平面上。 This allows a wireframe plot to be used properly, but since your functions have extrema in different time steps, the result is as confusing as your original plot.这允许正确使用线框图,但由于您的函数在不同的时间步长中具有极值,因此结果与您的原始图一样令人困惑。 You can try using very few plots along the t
axis, and hoping that the extrema are close.您可以尝试沿t
轴使用很少的图,并希望极值接近。 This approach needs so much guesswork that I didn't try to do this myself.这种方法需要很多猜测,我没有尝试自己做。 You can plot each function as a filled surface instead, though:不过,您可以将每个函数绘制为填充曲面:
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()
This results in something like this:这会导致如下结果:
There are a few things to note, however.但是,有几点需要注意。
If I understood, you want to link the 6 traces with polygons.如果我理解,您想将 6 条轨迹与多边形联系起来。 You can do that by triangulating the traces 2 by 2, then plotting the surface with no edges or antialising.您可以通过对轨迹进行 2 x 2 三角测量,然后绘制没有边缘或抗锯齿的表面来实现。 Maybe choosing a good colormap will also help.也许选择一个好的颜色图也会有所帮助。
Just keep in mind that this will be a very heavy plot.请记住,这将是一个非常沉重的情节。 The exported SVG weight 10mb :)导出的 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.