在表面图上绘制线条

时间:2018-03-31 09:43:53

标签: python matplotlib plot 3d

我希望能够看到表面顶部(第二张图像)上的3D表面上的线条(和点),而不是后面(第一张图像)。 这是我的3D功能:

def f(x, y): 
    return np.sin(2*x) * np.cos(2*y)

3D表面的X,Y,Z:

x = np.linspace(-2, 2, 100)
y = np.linspace(-2, 2, 100)
X, Y = np.meshgrid(x, y)
Z = f(X, Y)

我生成了x点(xx)和y点(yy)的向量,其中zz = f(xx,yy)

fig = plt.figure(figsize=(8,6))
ax = plt.axes(projection='3d')
ax.scatter(xx, yy, zz, c='r', marker='o')
#ax.plot(xx,yy,zz, c= 'r')

ax.plot_surface(X, Y, Z, rstride=1, cstride=1,
                cmap='viridis', edgecolor='none')

enter image description here

正如你所看到的,这些点是在情节的后面,这个数字涵盖了各点。我想看看情节上的分数。我该怎么办?

我希望能够看到像这样的点和线:

enter image description here

编辑: 这就是我生成积分的方式:

for i in range(1,2000):
    [a, b] =  np.random.rand(2,1)*np.sign(np.random.randn(2,1))*2
    xx = np.append(xx, a)
    yy = np.append(yy, b)

我注意到如果我写zz = f(xx,yy) + epsilon,我可以看到这些点。如果是epsilon = 0,那么这些点在数学上就在表面上,我无法清楚地看到它们,就像在第一张图像中一样。如果epsilon > 0.05,我可以看到这些点,但这意味着将点数移到上方。我真的不喜欢这个解决方案。如果一个点在表面上,表面具有优先权,则表面看起来超过该点。我希望我的图形能够反过来。

2 个答案:

答案 0 :(得分:1)

首先让我说你想要的东西有些不明确。您希望以一种始终在图中显示的方式在底层曲面上绘制完全的点,即正好在曲面上方,而不是明确地将它们向上移动。这已经成为一个问题,因为

  1. 浮点运算意味着您的点和曲面的精确坐标可以根据机器精度的顺序而变化,因此尝试依赖精确的等式不会起作用。
  2. 即使数字精确到无限精度,也会使用近似平面的集合绘制曲面。这意味着您的完全数据点将函数凸起的近似表面下。
  3. 然而,最大的问题是,当涉及绘制图中的多个或复杂对象时,matplotlib中的3d绘图是known to be unreliable。特别是,渲染器本质上是2d,并且在试图找出对象的相对明显位置时经常遇到问题。要克服此问题,可以尝试使用hacking around the problem,或使用合适的3D渲染器切换到mayavi之类的内容。

    不幸的是,zorder可选关键字参数通常被3d轴对象忽略。所以我在pyplot中唯一可以提出的就是你几乎拥有的东西,注释掉:使用ax.plot而不是ax.scatter。虽然后者产生了第一个图中显示的图(由于某种原因隐藏了每个散点,无论视角如何),前者会导致第二个图中显示的图(点可见的位置)。通过从绘图样式中删除线条,我们几乎得到你想要的东西:

    import numpy as np
    import matplotlib.pyplot as plt
    from mpl_toolkits.mplot3d import Axes3D
    
    def f(x, y):                        
        return np.sin(2*x) * np.cos(2*y)
    
    # data for the surface
    x = np.linspace(-2, 2, 100)
    X, Y = np.meshgrid(x, x)
    Z = f(X, Y)
    
    # data for the scatter
    xx = 4*np.random.rand(1000) - 2
    yy = 4*np.random.rand(1000) - 2
    zz = f(xx,yy)
    
    fig = plt.figure(figsize=(8,6))
    ax = plt.axes(projection='3d')
    #ax.scatter(xx, yy, zz, c='r', marker='o')
    ax.plot(xx, yy, zz, 'ro', alpha=0.5) # note the 'ro' (no '-') and the alpha
    
    ax.plot_surface(X, Y, Z, rstride=1, cstride=1,
                    cmap='viridis', edgecolor='none')
    

    matplotlib surf vs plot

    但并不完全:很明显,在这种情况下,点总是可见,即使它们应隐藏在表面的一部分后面:

    # note the change in points: generate only in the "back" quadrant
    xx = 2*np.random.rand(1000) - 2
    yy = 2*np.random.rand(1000)
    zz = f(xx,yy)
    
    fig = plt.figure(figsize=(8,6))
    ax = plt.axes(projection='3d')
    ax.plot(xx,yy,zz, 'ro', alpha=0.5)
    
    ax.plot_surface(X, Y, Z, rstride=1, cstride=1,
                    cmap='viridis', edgecolor='none')
    

    matplotlib surf vs scatter with points only in the back, showing spurious visible points that should be hidden

    很容易看出前面的凹凸应该隐藏背景中的大块点,但这些点是可见的。这正是pyplot在复杂的三维可视化中遇到的问题。因此,我的底线是你无法使用matplotlib可靠地做你想做的事。对于它的价值,我不确定无论如何这样的情节是多么容易理解。

    最后以更积极的方式结束,这里是如何使用mayavi(您需要安装vtk来实现此目的的,最好通过您的包管理器完成):

    import numpy as np
    from mayavi import mlab
    from matplotlib.cm import get_cmap # for viridis
    
    def f(x, y):
        return np.sin(2*x) * np.cos(2*y)
    
    # data for the surface
    x = np.linspace(-2, 2, 100)
    X, Y = np.meshgrid(x, x)
    Z = f(X, Y)
    
    # data for the scatter
    xx = 4*np.random.rand(1000) - 2
    yy = 4*np.random.rand(1000) - 2
    zz = f(xx,yy)
    
    fig = mlab.figure(bgcolor=(1,1,1))
    # note the transpose in surf due to different conventions compared to meshgrid
    su = mlab.surf(X.T, Y.T, Z.T)
    sc = mlab.points3d(xx, yy, zz, scale_factor=0.1, scale_mode='none',
                       opacity=1.0, resolution=20, color=(1,0,0))
    
    # manually set viridis for the surface
    cmap_name = 'viridis'
    cdat = np.array(get_cmap(cmap_name,256).colors)
    cdat = (cdat*255).astype(int)
    su.module_manager.scalar_lut_manager.lut.table = cdat
    
    mlab.show()
    

    mayavi example: surface with small spheres as points

    如您所见,结果是交互式三维图,其中表面上的数据点是适当的球体。可以使用不透明度和球体比例设置来获得令人满意的可视化效果。由于正确的3D渲染,无论视角如何,您都可以看到适当数量的每个点。

答案 1 :(得分:0)

从图中看来,您似乎愿意展示非线性优化器局部解决方案的路径,因此我认为您应该考虑在等高线图上绘制线框:

...

ax.scatter(xx,yy,zz,c ='r',marker ='o')###这将仅绘制点,而不绘制线

ax.plot_surface(X,Y,Z,rstride = 1,cstride = 1,cmap ='viridis',edgecolor ='none')

ax.plot_wireframe(xx,yy,zz)###这将绘制线以及可能的点。

...

(xx,yy,zz)包含到局部最大值的路径,这是我想从非线性后悔方法获得的。