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

时间:2012-12-18 11:40:04

标签: python matplotlib

我试图用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。

5 个答案:

答案 0 :(得分:10)

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

您可能希望使用 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)

<强>更新

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

enter image description here

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

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

答案 1 :(得分:6)

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

答案 2 :(得分:0)

对此可以进行手动修复。显然,这不是最干净的解决方案,但是它可以为您提供所需的东西。假设您想绘制X1和Y2的Z1和Z2。

  1. 创建一个数组Z1_gte,是Z1的副本,其中Z1> = Z2且 否则为np.nan。
  2. 创建一个数组Z1_lte,它是Z1的副本,其中 Z1 <= Z2,否则为np.nan。
  3. 在下面绘制三个曲面 顺序: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轴的一个特定查看方向。

答案 3 :(得分:0)

另一个可能对这里的某些应用程序有用的技巧是将您的表面更改为一种颜色,并将 alpha 值更改为两个表面的 0.5,然后您至少可以得到一个提示旋转表面。如果您正在调试交叉表面,或者在我的情况下,如果您想检查尖峰的平滑情况,这会很快。蓝色是下面平滑的表面,红色是原始表面。

Profile of two surfaces

答案 4 :(得分:0)

您可以通过同时绘制两者来规避该问题。只需附加两个矩阵并为它们指定单独的颜色。

def plotTwo(ax, X, Y, Z1, Z2):
    col1 = np.full(Z1.shape, 'b', dtype='U50')
    col2 = np.full(Z2.shape, 'r', dtype='U50')
    ax[2].plot_surface(np.append(X, X, axis=0),
                      np.append(Y, Y, axis=0),
                      np.append(Z1, Z2, axis=0),
                      facecolors= np.append(col1, col2, axis=0),
                      edgecolor='none', alpha=1)