Matlab 是否在matplotlib中显示最大曲面?
我正在使用matplotlib在同一个图形上绘制多个曲面,我只希望看到最上面的曲面,如matlab所示 Matlab 3D视图: Matlab俯视图: Matplotlib三维视图: Matplotlib俯视图: 如何让Matplotlib显示类似于Matlab的结果,其中最顶层的类显示在顶部,而不是一个类优先于另一个类?答案 正如对问题的评论中所指出的,matplotlib并不能真正进行三维打印,它所做的近似可以提供有限的结果。您遇到的问题实际上已在中得到承认 如果要进行认真的三维打印,它们也会指导您。如果你真的不需要3D绘图,只关心俯视图,那么我会按照Bensciens在评论中的建议直接进行2D绘图 肮脏的变通办法 当然,如果你愿意用程序员的灵魂来支付,几乎总会有一个解决方案涉及到一些黑暗魔法…:P 选择1 如果您确实只需要两个视图作为示例,并且曲面与这些视图相似,则可以先绘制曲面A后面的部分,然后绘制所有曲面B,然后绘制曲面A顶部的部分。。。让我解释一下: 如前所述,Matlab 是否在matplotlib中显示最大曲面?,matlab,matplotlib,plot,surface,Matlab,Matplotlib,Plot,Surface,我正在使用matplotlib在同一个图形上绘制多个曲面,我只希望看到最上面的曲面,如matlab所示 Matlab 3D视图: Matlab俯视图: Matplotlib三维视图: Matplotlib俯视图: 如何让Matplotlib显示类似于Matlab的结果,其中最顶层的类显示在顶部,而不是一个类优先于另一个类?答案 正如对问题的评论中所指出的,matplotlib并不能真正进行三维打印,它所做的近似可以提供有限的结果。您遇到的问题实际上已在中得到承认 如果要进行认真的三维打印
plot_surfaces()
不关心遮罩,但可以使用NaN
值获得类似效果。您可以使用此功能首先仅绘制低于另一个曲面的值,然后仅绘制高于另一个曲面的值
from mpl_toolkits.mplot4d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = (X+Y)
Z1 = R/R.max()
Z2 = -R/R.max()
surfA_bottom = ax.plot_surface(X, Y, np.where(Z1<=Z2,Z1, np.nan),
rstride=1, cstride=1, color='r', linewidth=0)
surfB = ax.plot_surface(X, Y, Z2,
rstride=1, cstride=1, color='b', linewidth=0)
surfA_top = ax.plot_surface(X, Y, np.where(Z1>=Z2,Z1, np.nan),
rstride=1, cstride=1, color='r', linewidth=0)
ax.set_zlim3d(-1, 1)
ax.set_ylim(-5,5)
ax.set_xlim(-5,5)
plt.show()
正如你所看到的,结果非常好,但有一些奇怪的效果,因为一个曲面的一个极端连接到另一个曲面的另一个极端。如何摆脱它?
透明度不是一个选项,因为据我所知,plot\u surface()
只允许影响整个曲面的alpha
值。我还尝试使用X、Y和Z中的一行NaN
值来遮罩变换,方式与解决方案1中的类似,但随后渲染被破坏。你可以试试,也许这取决于我的安装
EDIT:我发现了一个不那么优雅、问题更大的解决方案,但正如@will指出的那样,您只能通过使用rgba
synthax指定颜色来设置桥接区域的透明度。我将把我的版本留给回顾历史,因为答案已经足够长了…:P
(增加点的数量可以得到更软的边)
我本来打算考虑一些肮脏的黑客,比如mgab在他们的回答中提到的,但后来决定走一条简单得多的路线: 纯粹使用透明度可以获得类似的效果,只需确保透明度足够低,否则仍会出现明显的重叠情况:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt
import numpy as np
from scipy.special import erf
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(0, 6, 0.25)
Y = np.arange(0, 6, 0.25)
X, Y = np.meshgrid(X, Y)
Z1 = np.zeros_like(X)
Z2 = np.ones_like(X)
for i in range(len(X)):
for j in range(len(X[0])):
Z1[i,j] = 0.5*(erf((X[i,j]+Y[i,j]-4.5)*0.5)+1)
Z2[i,j] = 0.5*(erf((-X[i,j]-Y[i,j]+4.5)*0.5)+1)
alpha = 0.25
surf1 = ax.plot_surface(X, Y, Z1, cstride=2, rstride=1, cmap=cm.Oranges, linewidth=0, antialiased=False, alpha=alpha)
surf2 = ax.plot_surface(X, Y, Z2, cstride=2, rstride=1, cmap=cm.Blues, linewidth=0, antialiased=False, alpha=alpha)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
fig.colorbar(surf1, shrink=0.5, aspect=5)
fig.colorbar(surf2, shrink=0.5, aspect=5)
plt.show()
添加一条相交线将是一个很好的添加,但目前我没有简单的方法来添加它
编辑:大量借鉴mgab的答案,使用他的“桥接”解决方案,但也使用表面的颜色贴图,并使用RGBA
元组将桥接面设置为透明,您几乎可以得到您想要的:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from scipy.special import erf
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(0, 6, 0.25)
Y = np.arange(0, 6, 0.25)
X, Y = np.meshgrid(X, Y)
Z1 = np.empty_like(X)
Z2 = np.empty_like(X)
C1 = np.empty_like(X, dtype=object)
C2 = np.empty_like(X, dtype=object)
for i in range(len(X)):
for j in range(len(X[0])):
z1 = 0.5*(erf((X[i,j]+Y[i,j]-4.5)*0.5)+1)
z2 = 0.5*(erf((-X[i,j]-Y[i,j]+4.5)*0.5)+1)
Z1[i,j] = z1
Z2[i,j] = z2
# If you want to grab a colour from a matplotlib cmap function,
# you need to give it a number between 0 and 1. z1 and z2 are
# already in this range, so it just works.
C1[i,j] = plt.get_cmap("Oranges")(z1)
C2[i,j] = plt.get_cmap("Blues")(z2)
# Create a transparent bridge region
X_bridge = np.vstack([X[-1,:],X[-1,:]])
Y_bridge = np.vstack([Y[-1,:],Y[-1,:]])
Z_bridge = np.vstack([Z1[-1,:],Z2[-1,:]])
color_bridge = np.empty_like(Z_bridge, dtype=object)
color_bridge.fill((1,1,1,0)) # RGBA colour, onlt the last component matters.
# Join the two surfaces flipping one of them (using also the bridge)
X_full = np.vstack([X, X_bridge, np.flipud(X)])
Y_full = np.vstack([Y, Y_bridge, np.flipud(Y)])
Z_full = np.vstack([Z1, Z_bridge, np.flipud(Z2)])
color_full = np.vstack([C1, color_bridge, np.flipud(C2)])
surf_full = ax.plot_surface(X_full, Y_full, Z_full, rstride=1, cstride=1,
facecolors=color_full, linewidth=0,
antialiased=False)
plt.show()
对相交曲面进行颜色映射
首先,感谢@will和@mgab解决了这个问题。我用你们的技巧为我正在制定的商业计划增添了趣味(见图表)。我只是想问一下“阿尔法”问题
是的,通过在RGBA语法中使用第四个属性,可以在曲面上具有不同的不透明度。也可以通过传递最小-最大缩放Z值来使用顺序颜色贴图
for i in range(len(X)):
for j in range(len(X[0])):
C1[i,j] = plt.get_cmap('RdYlGn')((Z1[i,j]-Z_min)/Z_range)
C2[i,j] = (0,0,1,0.5)
另外,收入面不是平面。它会重新计算两个参数的每个组合的P&L。
据我所知,ax.plplot\U曲面方法只能为一个曲面绘制良好的图形,因此如果需要绘制多个曲面,则需要将它们组合在一个公共np数组中
我编写了一些代码,希望能对此有所帮助: # normalize values to range [0;1] for getting color from cmap
def norm_v(v) :
v_min = v.min()
v_max = v.max()
if v_min-v_max == 0 :
v.fill(0.5)
return v
return (v-v_min)/(v_max-v_min)
# combine several surfaces in one for plotting at once
def combine_in_one_graph(X,Y,*Z) :
cmaps_name = ['viridis', 'plasma', 'inferno', 'magma', 'cividis']
# transparent connection between grahps
transparen_link = np.empty_like(X[0], dtype=object)
transparen_link.fill((1,1,0,0))
# include first graph
combined_X = X
combined_Y = Y
combined_Z = Z[0]
# prepare collor matrix for first graph (Z[0])
combined_Color = np.empty_like(X, dtype=object)
normed_Z = norm_v(Z[0])
for i in range(len(combined_Color)) :
for j in range(len(X[0])) :
combined_Color[i,j] = plt.get_cmap(cmaps_name[0])(normed_Z[i,j])
# first row of collor matrix is not used in ploting, and will displace transparent links
# so we need to remove first row
combined_Color = combined_Color[1:]
# second aray combined with first in backward direction, so connection would on one side of graphs, not intersect them
direction = -1
cmap_index = 1
for next_Z in Z[1:] :
combined_X = np.vstack([combined_X, X[::direction][0], X[::direction]])
combined_Y = np.vstack([combined_Y, Y[::direction][0], Y[::direction]])
combined_Z = np.vstack([combined_Z, next_Z[::direction][0], next_Z[::direction]])
# prepare collors for next Z_
next_C = np.empty_like(X, dtype=object)
normed_Z = norm_v(next_Z)
for i in range(len(X)) :
for j in range(len(X[0])) :
next_C[i,j] = plt.get_cmap(cmaps_name[cmap_index])(normed_Z[i,j])
combined_Color = np.vstack([combined_Color ,transparen_link ,next_C[::direction]])
direction *= -1
cmap_index += 1
fig = plt.figure(figsize=(15,15))
ax = fig.gca(projection='3d') # get current axis
surf = ax.plot_surface(combined_X, combined_Y, combined_Z, facecolors=combined_Color, rstride=1, cstride=1,
linewidth=0,
antialiased=False )
# rotate graph on angle in degrees
ax.view_init(azim=-60)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()
X = np.arange(0.2, 1.06, 0.01)
Y = np.arange(0.2, 1.06, 0.01)
X, Y = np.meshgrid(X, Y)
Z1 = 2*np.sin(np.sqrt(20*X**2+20*Y**2))
Z2 = 2*np.cos(np.sqrt(20*X**2+20*Y**2))
Z3 = X*0+1
Z4 = Y*0+1.5
combine_in_one_graph(X,Y,Z1,Z2,Z3,Z4)
使用Matlab:p。不,真的,Matplotlib很神奇,但它有一些小东西,比如这个,让我很紧张。我猜,使用Matlab对我来说并不是一个选择。不幸的是,matplotlib有时会做这种视觉上的事情,但它们并不好。希望有人知道如何修复它。否则我建议您手动裁剪数据,使其不存在。Matplotlib实际上不进行三维打印。这是一个很好的例子,说明了我的意思。它没有3D渲染引擎,而是通过单个元素的z顺序进行近似。对于多个曲面或复杂的单个曲面,您将遇到如下问题。对于需要遮挡的情况,请考虑Mayavi,正如AjeAn所建议的。两个视图必须在同一个图上吗?你可以用3d绘图来显示表面,用2d绘图来显示俯视图。你差一点就得到了。差不多了。Matplotlib允许使用
rgba
颜色,因此您可以使用color\u bridge=np.empty\u like(Z\u bridge,dtype=object)
然后使用color\u bridge.fill((1,1,0))
来用透明颜色填充这些面。好了,对不起。我偷了你的答案,加了一个透明的桥,并用彩色地图给脸涂上颜色。我认为把它变成一个标准函数应该是相当容易的,它可能被添加到MPL中。@will-Argh,当然!说得好!在答案中编辑。。。(虽然这是一次相当大的盗窃,不是吗?:-S)你让我在黑暗魔法学院学习。我认为称之为“肮脏的黑客”是不公平的,因为这正是matlab内部正在做的,只是Matplotlib没有内部z缓冲区来支持它。确实是一次相当大的盗窃…:-沙哈,别担心盗窃案,我想你们两个都能得到赏金。我还没有在我的代码中实现它,但这看起来很棒!(仅供参考,我只能在24小时内颁发第二次赏金
for i in range(len(X)):
for j in range(len(X[0])):
C1[i,j] = plt.get_cmap('RdYlGn')((Z1[i,j]-Z_min)/Z_range)
C2[i,j] = (0,0,1,0.5)
# normalize values to range [0;1] for getting color from cmap
def norm_v(v) :
v_min = v.min()
v_max = v.max()
if v_min-v_max == 0 :
v.fill(0.5)
return v
return (v-v_min)/(v_max-v_min)
# combine several surfaces in one for plotting at once
def combine_in_one_graph(X,Y,*Z) :
cmaps_name = ['viridis', 'plasma', 'inferno', 'magma', 'cividis']
# transparent connection between grahps
transparen_link = np.empty_like(X[0], dtype=object)
transparen_link.fill((1,1,0,0))
# include first graph
combined_X = X
combined_Y = Y
combined_Z = Z[0]
# prepare collor matrix for first graph (Z[0])
combined_Color = np.empty_like(X, dtype=object)
normed_Z = norm_v(Z[0])
for i in range(len(combined_Color)) :
for j in range(len(X[0])) :
combined_Color[i,j] = plt.get_cmap(cmaps_name[0])(normed_Z[i,j])
# first row of collor matrix is not used in ploting, and will displace transparent links
# so we need to remove first row
combined_Color = combined_Color[1:]
# second aray combined with first in backward direction, so connection would on one side of graphs, not intersect them
direction = -1
cmap_index = 1
for next_Z in Z[1:] :
combined_X = np.vstack([combined_X, X[::direction][0], X[::direction]])
combined_Y = np.vstack([combined_Y, Y[::direction][0], Y[::direction]])
combined_Z = np.vstack([combined_Z, next_Z[::direction][0], next_Z[::direction]])
# prepare collors for next Z_
next_C = np.empty_like(X, dtype=object)
normed_Z = norm_v(next_Z)
for i in range(len(X)) :
for j in range(len(X[0])) :
next_C[i,j] = plt.get_cmap(cmaps_name[cmap_index])(normed_Z[i,j])
combined_Color = np.vstack([combined_Color ,transparen_link ,next_C[::direction]])
direction *= -1
cmap_index += 1
fig = plt.figure(figsize=(15,15))
ax = fig.gca(projection='3d') # get current axis
surf = ax.plot_surface(combined_X, combined_Y, combined_Z, facecolors=combined_Color, rstride=1, cstride=1,
linewidth=0,
antialiased=False )
# rotate graph on angle in degrees
ax.view_init(azim=-60)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()
X = np.arange(0.2, 1.06, 0.01)
Y = np.arange(0.2, 1.06, 0.01)
X, Y = np.meshgrid(X, Y)
Z1 = 2*np.sin(np.sqrt(20*X**2+20*Y**2))
Z2 = 2*np.cos(np.sqrt(20*X**2+20*Y**2))
Z3 = X*0+1
Z4 = Y*0+1.5
combine_in_one_graph(X,Y,Z1,Z2,Z3,Z4)