仅使用matplotlib绘制3D图形的一部分 [英] Only plot part of a 3d figure using matplotlib

查看:130
本文介绍了仅使用matplotlib绘制3D图形的一部分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I got a problem when I was plotting a 3d figure using matplotlib of python. Using the following python function, I got this figure:

此处XY是网格,而ZZ_XY的函数. C代表表面颜色.

Here X, Y are meshed grids and Z and Z_ are functions of X and Y. C stands for surface color.

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之间的部分.

But now I want to cut this figure horizontally and only the part whose z is between -1 and 2 remain.

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

What I want, plotted with gnuplot, is this:

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

I have tried ax.set_zlim3d and ax.set_zlim, but neither of them give me the desired figure. Does anybody know how to do it using python?

推荐答案

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

Nice conical intersections you have there:)

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

What you're trying to do should be achieved by setting the Z data you want to ignore to NaN. Using graphene's tight binding band structure as an example:

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可视化有点麻烦.这意味着对于复杂的重叠曲面,您经常会得到渲染伪影(特别是两个简单连接的曲面彼此之间完全在后或完全在前面).

Unfortunately, there are problems with the rendering of the second case: the apparent depth order of the data is messed up in the latter case: cones in the background are rendered in front of the front ones (this is much clearer in an interactive plot). The problem is that there are more holes than actual data, and the data is not connected, which confuses the renderer of plot_surface. Matplotlib has a 2d renderer, so 3d visualization is a bit of a hack. This means that for complex overlapping surfaces you'll more often than not get rendering artifacts (in particular, two simply connected surfaces are either fully behind or fully in front of one another).

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

We can get around the rendering bug by doing a bit more work: keeping the data in a single surface by not using nans, but instead colouring the the surface to be invisible where it doesn't interest us. Since the surface we're plotting now includes the entire original surface, we have to set the zlim manually in order to focus on our region of interest. For the above example:

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)具有非常不同(且更漂亮)的默认样式.特别是,现在曲面图中的边缘是透明的.但是要点是渲染错误已经消失了,如果您开始在交互式绘图中旋转曲面,这是显而易见的.

Note that it looks a bit different from the earlier figures because 3 years have passed in between and the current version of matplotlib (3.0.2) has very different (and much prettier) default styles. In particular, edges are now transparent in surface plots. But the main point is that the rendering bug is gone, which is evident if you start rotating the surface around in an interactive plot.

这篇关于仅使用matplotlib绘制3D图形的一部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆