Wireframe在numpy matplotlib mplot3d中加入错误方式

Wireframe joins the wrong way in numpy matplotlib mplot3d

我正在尝试使用 matplotlib 在 Python 中创建 3D 线框。

然而,当我进行实际绘图时,线框连接方式错误,如下图所示。

如何强制 matplotlib 沿某个轴连接线框?

我的代码如下:

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

我得到这个作为输出:

换个角度同样的输出:

而我希望线框沿着波峰连接。抱歉,我不能给你我想看的图片,这是我的问题,但我想它更像是教程图片。

我不太确定你到底想达到什么目的,但我认为它不会奏效。

这是逐层绘制(无填充和有填充)时数据的样子:

您正在尝试将其绘制为线框图。这是线框图的样子 the manual:

注意巨大的差异:线框图本质上是一个适当的曲面图,唯一的区别是曲面的各个面是完全透明的。这也意味着你只能 plot

  1. 形式为 z(x,y) 的单值函数,此外
  2. 在矩形网格上指定(至少在拓扑上)

你的数据两者都不是:你的点是沿着 线 给出的,并且它们相互堆叠,所以这不可能是一个单一的表面绘制。

如果你只是想将你的函数可视化,我是这样绘制上面的图的:

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

还有另一种选择:切换坐标轴,使 (x,t) 对对应于垂直平面而不是水平平面。在这种情况下,您的各种 c 值的函数绘制在平行平面上。这允许正确使用线框图,但由于您的函数在不同的时间步长中具有极值,因此结果与您的原始图一样令人困惑。您 可以 尝试沿 t 轴使用很少的绘图,并希望极值接近。这种方法需要大量的猜测,所以我自己并没有尝试这样做。不过,您可以将每个函数绘制为填充曲面:

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

结果如下:

不过,有几点需要注意。

  1. 由于缺乏深度信息,3d 散点图和线图很难理解。您可能以根本错误的方式处理可视化问题:也许还有其他选项可以让您可视化数据。
  2. 即使你做了像我展示的那样的事情,你也应该知道 matplotlib 一直未能正确地绘制复杂的 3d 对象。现在 "properly" 我的意思是 "with physically reasonable apparent depth",另见 the mplot3d FAQ note describing exactly this. The core of the problem is that matplotlib projects every 3d object to 2d, and draws these pancakes on the sreen one after the other. Sometimes the asserted drawing order of the pancakes doesn't correspond to their actual relative depth, which leads to artifacts that are both very obvious to humans and uncanny to look at. If you take a closer look at the first filled plot in this post, you'll see that the gold flat plot is behind the magenta one, even though it should be on top of it. Similar things often happen with and
  3. 当你说“抱歉,我不能给你我想看的图像,那是我的问题”,你就大错特错了。这不仅仅是你的问题。您可能 crystal 清楚自己想要实现的目标,但除非您 非常 清楚地描述您在脑海中看到的内容,否则外界将不得不求助于猜测。您可以尝试提供尽可能多的信息,从而使他人和您自己的工作更轻松。

如果我理解的话,你想要 link 6 条带多边形的轨迹。您可以通过对迹线进行 2 乘 2 三角测量,然后绘制没有边缘或抗锯齿的表面来做到这一点。也许选择一个好的颜色图也会有所帮助。

请记住,这将是一个非常沉重的情节。导出的 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()

这是生成的图像: