只使用matplotlib绘制3d图的一部分

时间:2016-01-30 07:56:58

标签: python matplotlib plot

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

figure1

此处XY是网格网格,ZZ_XY的功能。 C代表表面颜色。

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绘制的是:

figure 2

我尝试了ax.set_zlim3dax.set_zlim,但他们都没有给我想要的数字。有人知道如何使用python做到这一点吗?

1 个答案:

答案 0 :(得分:5)

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

您应该通过将要忽略的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()

结果如下:

graphene full band structure graphene Dirac cones

不幸的是,第二种情况的渲染存在问题:在后一种情况下,数据的明显深度顺序混乱:背景中的圆锥体在前面的圆锥体前面呈现(这在一个更清晰的情况下)互动情节)。问题是存在比实际数据更多的漏洞,并且数据未连接,这会使plot_surface的渲染器混乱。 Matplotlib有一个2D渲染器,所以三维可视化有点像黑客。这意味着对于复杂的重叠曲面,您经常会得到渲染瑕疵(特别是两个简单连接的曲面要么完全在后面,要么完全在彼此的前面)。

我们可以通过做更多工作来解决渲染错误:使用nan而不是的数据保存在单个表面中,而是将表面着色为不可见它对我们不感兴趣。由于我们正在绘制的曲面现在包括整个原始曲面,因此我们必须手动设置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()

这是输出: updated version, no rendering artifact

请注意,它看起来与之前的数字略有不同,因为3年之间已经过去了,而matplotlib(3.0.2)的当前版本具有非常不同(且更漂亮)的默认样式。特别是,边缘现在在表面图中是透明的。但重点是渲染错误已经消失,如果你在交互式情节中开始旋转表面,这很明显。