24

我正在尝试使用 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)

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

示例图

在后角(轴上为 200N,2.5Hz),蓝绿色表面“在顶部”,而实际上黄红色更靠近观察者。如果我旋转情节:

第二个示例图

现在看起来一切正常,蓝绿色表面在 200N 和 2.5Hz 的黄红色表面下方(现在在左侧)。我曾尝试搜索 stackoverflow 和 Google,但找不到任何类似的解决方案问题。

我在 Linux 上使用 Python 2.7.3、Numpy 1.6.1 和 Matplotlib 1.1.1rc。

4

5 回答 5

17

此行为记录在 matplotlib FAQ here中。同一页面建议安装适用于 3D 绘图的Mayavi 。

  • 它的界面与 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

于 2017-03-24T16:07:07.270 回答
11

这就像绘画一样。哪个“在上面”取决于您最后绘制的哪个。

您可能想使用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 在一个图形中绘制多个表面时的错误。例如,它制作了一些在我们的 3D 世界中不应该存在的表面,例如:

在此处输入图像描述

, 尝试后看不出有效的解决方案。因果关系是绘画的顺序,正如我所说:matplotlib 总是一件一件地绘画。如果表面的一部分应该在顶部,而另一部分应该在底部,matplotlib 就会出错。

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

于 2012-12-18T12:23:03.780 回答
1

可以为此进行手动修复。这显然不是最干净的解决方案,但它给了你你想要的。假设您想为公共 X 和 Y 绘制 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 轴从低到高查看时表面看起来正确,请反转 te 顺序。

或直接:

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 轴的一个特定观察方向。

于 2018-08-01T16:23:20.087 回答
0

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

两个表面的轮廓

于 2021-01-20T16:56:32.400 回答
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)
于 2021-06-08T15:43:25.537 回答