仅使用matplotlib绘制3D图形的一部分

发布于 2021-01-29 15:05:42

使用python的matplotlib绘制3d图形时出现问题。使用以下python函数,我得到了这个图:

图1

在这里XY有孔栅格和ZZ_的功能XYC代表表面颜色。

import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt

def plot(X, Y, Z, Z_, C):
   fig = plt.figure()
   ax = fig.gca(projection='3d')
   surf = ax.plot_surface(
           X, Y, Z, rstride=1, cstride=1,
           facecolors=cm.jet(C),
           linewidth=0, antialiased=False, shade=False)
   surf_ = ax.plot_surface(
           X, Y, Z_, rstride=1, cstride=1,
           facecolors=cm.jet(C),
          linewidth=0, antialiased=False, shade=False)                    
   ax.view_init(elev=7,azim=45)
   plt.show()

但是现在我想水平切割该图,仅保留z在-1和2之间的部分。

我想要的,用gnu​​plot绘制的是这样的:

图2

我尝试了ax.set_zlim3dax.set_zlim,但是它们都没有给我想要的数字。有人知道如何使用python吗?

关注者
0
被浏览
111
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    你在那里有漂亮的圆锥形交叉点:)

    您要尝试执行的操作应通过将Z要忽略的数据设置为来实现NaN。以石墨烯的紧密结合带结构为例:

    import numpy as np
    import matplotlib.pyplot as plt
    from mpl_toolkits.mplot3d import Axes3D
    
    # generate dummy data (graphene tight binding band structure)
    kvec = np.linspace(-np.pi,np.pi,101)
    kx,ky = np.meshgrid(kvec,kvec)
    E = np.sqrt(1+4*np.cos(3*kx/2)*np.cos(np.sqrt(3)/2*ky) + 4*np.cos(np.sqrt(3)/2*ky)**2)
    
    # plot full dataset
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    ax.plot_surface(kx,ky,E,cmap='viridis',vmin=-E.max(),vmax=E.max(),rstride=1,cstride=1)
    ax.plot_surface(kx,ky,-E,cmap='viridis',vmin=-E.max(),vmax=E.max(),rstride=1,cstride=1)
    
    
    
    # focus on Dirac cones
    Elim = 1  #threshold
    E[E>Elim] = np.nan
    
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    #ax.plot_surface(kx2,ky2,E2,cmap='viridis',vmin=-Elim,vmax=Elim)
    #ax.plot_surface(kx2,ky2,-E2,cmap='viridis',vmin=-Elim,vmax=Elim)
    ax.plot_surface(kx,ky,E,cmap='viridis',rstride=1,cstride=1,vmin=-Elim,vmax=Elim)
    ax.plot_surface(kx,ky,-E,cmap='viridis',rstride=1,cstride=1,vmin=-Elim,vmax=Elim)
    
    plt.show()
    

    结果如下:

    石墨烯全能带结构石墨烯狄拉克锥

    不幸的是,第二种情况的渲染存在问题:在后一种情况下,数据的表观深度顺序被弄乱了:背景中的圆锥体在前面的圆锥体之前渲染(这在交互式绘图中更为清晰)
    。问题在于,空洞比实际数据多,并且数据未连接,这使的渲染器感到困惑plot_surface。Matplotlib具有2d渲染器,因此3d可视化有点麻烦。这意味着对于复杂的重叠曲面,您经常会遇到渲染伪影(特别是两个简单连接的曲面彼此之间完全在后或完全在前面)。

    我们可以通过做更多的工作来解决渲染错误:通过
    使用nans来将数据保留在单个表面中,而是将表面着色为在我们不感兴趣的地方不可见。由于我们现在要绘制的曲面包括整个原始曲面,因此我们必须zlim手动设置才能专注于我们感兴趣的区域。对于以上示例:

    from matplotlib.cm import get_cmap
    
    # create a color mapping manually
    Elim = 1  #threshold
    cmap = get_cmap('viridis')
    colors_top = cmap((E + Elim)/2/Elim) # listed colormap that maps E from [-Elim, Elim] to [0.0, 1.0] for color mapping
    colors_bott = cmap((-E + Elim)/2/Elim) # same for -E branch
    colors_top[E > Elim, -1] = 0 # set outlying faces to be invisible (100% transparent)
    colors_bott[-E < -Elim, -1] = 0
    
    # in nature you would instead have something like this:
    #zmin,zmax = -1,1 # where to cut the _single_ input surface (x,y,z)
    #cmap = get_cmap('viridis')
    #colors = cmap((z - zmin)/(zmax - zmin))
    #colors[(z < zmin) | (z > zmax), -1] = 0
    # then plot_surface(x, y, z, facecolors=colors, ...)
    
    # or for your specific case where you have X, Y, Z and C:
    #colors = get_cmap('viridis')(C)
    #colors[(z < zmin) | (z > zmax), -1] = 0
    # then plot_surface(x, y, z, facecolors=colors, ...)
    
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    # pass the mapped colours as the facecolors keyword arg
    s1 = ax.plot_surface(kx, ky, E, facecolors=colors_top, rstride=1, cstride=1)
    s2 = ax.plot_surface(kx, ky, -E, facecolors=colors_bott, rstride=1, cstride=1)
    # but now we need to manually hide the invisible part of the surface:
    ax.set_zlim(-Elim, Elim)
    
    plt.show()
    

    这是输出:
    更新版本,没有渲染神器

    请注意,它看起来与早期的数字有些不同,因为之间相隔了3年,并且当前版本的matplotlib(3.0.2)具有非常不同(且更漂亮)的默认样式。尤其是,现在曲面图中的边缘是透明的。但是要点是渲染错误已消失,如果您开始在交互式绘图中旋转曲面,这是显而易见的。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看