首页 文章

Matplotlib - 在同一轴上绘制两个3D曲面时错误重叠

提问于
浏览
15

我试图用plot_surface命令在matplotlib中的相同轴上绘制两个3D表面 .

fig = plt.figure()
fig.figsize = fig_size
ax = fig.gca(projection='3d')

surf = ax.plot_surface(X, Y, Exp_Fric_map, alpha = 1, rstride=1, cstride=1, cmap=cm.winter, linewidth=0.5, antialiased=True)
surf = ax.plot_surface(X, Y, Fric_map, alpha = 1, rstride=1, cstride=1, cmap=cm.autumn,linewidth=0.5, antialiased=True)

我遇到的问题是,在查看绘图时,并不总是正确的表面是“在顶部”,例如在图中:

Example plot

在后角(200N,轴上为2.5Hz),当实际上黄色 - 红色更靠近观察者时,蓝绿色表面位于“顶部” . 如果我旋转图:

Second example plot

那么事情看起来还不错,蓝绿色表面位于200N和2.5Hz(现在在左侧)的黄红色表面下方 . 我尝试过搜索stackoverflow和Google,但找不到解决方案的任何类似问题 .

我在Linux上使用Python 2.7.3,Numpy 1.6.1和Matplotlib 1.1.1rc .

3 回答

  • 2

    这就像绘画一样 . 哪一个'在顶部'取决于你最后绘制的那个 .

    您可能希望使用 zorder 属性来告诉matplotlib表面的绘制顺序 .

    例如:

    ax.plot_surface(X, Y, Exp_Fric_map, alpha = 1, rstride=1, cstride=1, cmap=cm.winter, linewidth=0.5, antialiased=True, zorder = 0.5)
    ax.plot_surface(X, Y, Fric_map, alpha = 1, rstride=1, cstride=1, cmap=cm.autumn,linewidth=0.5, antialiased=True, zorder = 0.3)
    

    Update

    我已经运行了几个测试,我相信它是matplotlib的 bug ,同时在一个图中绘制多个表面 . 例如,它使我们的3D世界中不应存在的一些表面如:

    enter image description here

    ,尝试后我看不到有效的解决方案 . 正如我所说,因果关系是绘画的顺序: matplotlib always paints things one by one . 如果表面的一部分应位于顶部,而另一部分应位于底部,则matplotlib将出错 .

    因此我的建议是停止解决这个问题,除非你想为matplotlib做贡献,否则浪费时间 . 如果你有必要解决这个问题,我建议你去找另一个绘图工具来完成你的工作 .

  • 0

    matplotlib FAQ here中记录了此行为 . 同一页建议安装Mayavi,它可以正常使用3D绘图 .

    • 它的界面与matplotlib非常相似 .

    • 它的主要问题是在python 3上安装它仍然很棘手 . (现在变得更容易了)


    这是一个演示“matplotlib vs mayavi”比较:

    # generate data
    import numpy as np
    
    x = np.arange(-2, 2, 0.1)
    y = np.arange(-2, 2, 0.1)
    mx, my = np.meshgrid(x, y, indexing='ij')
    mz1 = np.abs(mx) + np.abs(my)
    mz2 = mx ** 2 + my ** 2
    
    # A fix for "API 'QString' has already been set to version 1"
    # see https://github.com/enthought/pyface/issues/286#issuecomment-335436808
    from sys import version_info
    if version_info[0] < 3:
        import pyface.qt
    
    
    def v1_matplotlib():
        from matplotlib import pyplot as plt
        from mpl_toolkits.mplot3d import Axes3D
    
        fig = plt.figure()
        ax = fig.gca(projection='3d')
        surf1 = ax.plot_surface(mx, my, mz1, cmap='winter')
        surf2 = ax.plot_surface(mx, my, mz2, cmap='autumn')
        ax.view_init(azim=60, elev=16)
        fig.show()
    
    
    def v2_mayavi(transparency):
        from mayavi import mlab
        fig = mlab.figure()
    
        ax_ranges = [-2, 2, -2, 2, 0, 8]
        ax_scale = [1.0, 1.0, 0.4]
        ax_extent = ax_ranges * np.repeat(ax_scale, 2)
    
        surf3 = mlab.surf(mx, my, mz1, colormap='Blues')
        surf4 = mlab.surf(mx, my, mz2, colormap='Oranges')
    
        surf3.actor.actor.scale = ax_scale
        surf4.actor.actor.scale = ax_scale
        mlab.view(60, 74, 17, [-2.5, -4.6, -0.3])
        mlab.outline(surf3, color=(.7, .7, .7), extent=ax_extent)
        mlab.axes(surf3, color=(.7, .7, .7), extent=ax_extent,
                  ranges=ax_ranges,
                  xlabel='x', ylabel='y', zlabel='z')
    
        if transparency:
            surf3.actor.property.opacity = 0.5
            surf4.actor.property.opacity = 0.5
            fig.scene.renderer.use_depth_peeling = 1
    
    
    v1_matplotlib()
    v2_mayavi(False)
    v2_mayavi(True)
    
    # To install mayavi, the following currently works for me (Windows 10):
    #
    #   conda create --name mayavi_test_py2 python=2.7 matplotlib mayavi=4.4.0
    #    (installs pyqt=4.10.4 mayavi=4.4.0 vtk=5.10.1)
    #    * the `use_depth_peeling=1` got no effect. Transparency is not correct.
    #    * requires `import pyface.qt` or similar workaround
    #
    # or
    #
    #   conda create --name mayavi_test_py3 python=3.6 matplotlib
    #   conda activate mayavi_test_py3
    #   pip install mayavi
    

    matplotlib vs mayavi_no_transparency vs mayavi_with_transparency

  • 10

    可以手动修复此问题 . 它显然不是最干净的解决方案,但它可以满足您的需求 . 假设你想为常见的X和Y绘制Z1和Z2 .

    • 创建一个数组Z1_gte,它是Z1的副本,其中Z1> = Z2,否则为np.nan .

    • 创建一个数组Z1_lte,它是Z1的副本,其中Z1 <= Z2,否则为np.nan .

    • 按以下顺序绘制三个曲面:Z1_lte,Z2,Z1_gte . 沿z轴从高到低查看时,表面看起来是正确的 . 如果您希望沿z轴从低到高查看表面看起来正确,请反转顺序 .

    或直接:

    ax.plot_surface(X,Y,np.where(Z1<Z2,Z1,np.nan))
    ax.plot_surface(X,Y,Z2)
    ax.plot_surface(X,Y,np.where(Z1>=Z2,Z1,np.nan))
    

    该方法的明显缺点是它仅适用于沿z轴的一个特定观察方向 .

相关问题