【问题标题】:Only plot part of a 3d figure using matplotlib仅使用 matplotlib 绘制 3d 图形的一部分
【发布时间】:2019-01-26 01:19:09
【问题描述】:

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

这里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之间的部分。

我想要的是用 gnuplot 绘制的,是这样的:

我尝试过ax.set_zlim3dax.set_zlim,但它们都没有给我想要的数字。有人知道怎么用python吗?

【问题讨论】:

  • 我不希望这与你相关,但只是为了安全起见:我通过答案更新以显示如何解决渲染错误更多的工作。

标签: python matplotlib plot


【解决方案1】:

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

应该通过将要忽略的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) 具有非常不同(并且更漂亮)的默认样式。特别是,边缘现在在曲面图中是透明的。但重点是渲染错误消失了,如果您开始在交互式绘图中旋转表面,这一点很明显。

【讨论】:

  • 我的第二个最佳猜测,plot_trisurf 也会产生这个工件(如果我将不必要的值设置为 NaN),或者在阈值水平上绘制丑陋的水平线(如果我只是提取 需要值到新向量中,没有任何NaNs)。
  • @jjjjjj 是的,很简单。如果你只是想改变颜色,没有什么能阻止你通过vmin=F.min(), vmax=F.max() 或其他东西。如果您想隐藏这些值之外的表面,您需要将E[E&gt;Elim] = np.nan 更改为E[(E&lt;F.min()) | (F.max() &lt; E)] = np.nan 以隐藏这些值。这能回答你的问题吗?
  • 啊,是的,np.nans 做到了,谢谢!会再次+1,但已经这样做了:)
  • @jjjjjj 并不是我希望这仍然与您相关,但我添加了一个更新的解决方案来避免呈现错误。
  • @jjjjjj 不,这只是必需品。诀窍不是将 z 值设置为nan,而是手动创建一个颜色图,然后将位于我们感兴趣区域之外的颜色设置为 0 alpha(即 100% 透明),否则不会触及它们的颜色。 (渲染错误的原因是使用nans 会给您显式不相交的表面,并且单独的表面相对于彼此渲染错误。使用不可见的补丁欺骗渲染器,将这些部分作为一个大表面处理,渲染它对。)
猜你喜欢
  • 2016-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-24
  • 1970-01-01
相关资源
最近更新 更多