在 matplotlib 中显示最大表面?
Display the maximum surface in matplotlib?
我正在使用 matplotlib 在同一个图形上绘制多个曲面,我只想看到最上面的曲面,如 matlab 所示。
Matlab 3D视图:
Matlab顶视图:
Matplotlib 3D 视图:
Matplotlib 俯视图:
如何让 Matplotlib 显示类似于 Matlab 的结果,其中最顶部的 class 显示在顶部,而不是一个 class 优先于另一个?
回答
正如问题的评论中所指出的,matplotlib 并没有真正进行 3d 绘图,它所做的近似可以给你有限的结果。您遇到的问题实际上已在 mplot3d
module's FAQ.
中得到确认
如果您想进行严肃的 3D 绘图,他们还会将您引导至 MayaVi。如果您真的不需要 3D 绘图并且只关心顶视图,那么我会按照 Bensciens 在评论中的建议直接进行 2D 绘图...
肮脏的解决方法
当然,如果您愿意用程序员的灵魂付出代价,几乎总有一个涉及一些黑魔法的解决方案...:P
选项 1
如果你真的只需要你作为例子的两个视图,并且表面与那些相似,你可以先绘制表面 A 后面的部分,然后是所有表面 B,然后是表面的部分在表面 A 之上...让我解释一下:
正如所指出的,here and here 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()
选项 2
(里面有解释,想知道答案的直接跳到最后一段!)
这个解决方案稍微复杂一些,但对于更复杂的表面也更稳健......问题是 matplotlib
中的 3d 图不能很好地处理 different[= 的深度80=] 对象...对吗?但它适用于 单个 对象...
那么如何将两个表面绘制为 单个 表面呢??
为此,您需要将所有点合并到一个曲面中(对于重复的 X-Y 组合,您可以有多个 Z 值)。为了区分我们新表面的两个部分(我们以前的两个表面),我们可以使用 facecolors
kwarg。 (我添加了一些 alpha
值以更清楚地看到发生了什么)
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)
Z1 = np.sin(np.sqrt(X**2+Y**2))
Z2 = np.ones_like(Z1)*0.6
C1 = np.empty_like(X, dtype=str)
C1.fill('b')
C2 = C1.copy()
C2.fill('r')
X3 = np.vstack([X,X])
Y3 = np.vstack([Y,Y])
Z3 = np.vstack([Z1,Z2])
C3 = np.vstack([C1,C2])
surf3 = ax.plot_surface(X3, Y3, Z3, rstride=1, cstride=1,
facecolors=C3, linewidth=0,
antialiased=False, alpha=0.5)
ax.set_zlim3d(-1, 2)
plt.show()
如您所见,结果非常好,但有一些奇怪的效果,因为一个表面的一个极端连接到另一个表面的另一个极端。如何摆脱它?
透明胶片不是一种选择,因为据我所知,plot_surface()
只允许影响整个表面的 alpha
值。我还尝试使用 X、Y 和 Z 中的一行 NaN
值来 mask 转换,其方式与 中的解决方法 1[=81= 类似],但随后渲染被破坏。你可以试试,也许这取决于我的安装。
编辑: 我找到了一个不太优雅且问题更多的解决方案,但正如@will 指出的那样,您 can 仅在通过使用 rgba
语法指定颜色来桥接区域。我将把我的版本留作评论历史,因为答案已经足够长了...:P
(增加点数可以获得更柔和的边缘)
from mpl_toolkits.mplot3d 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)
# Complex shape from examples in matplotlib gallery
Z1 = np.sin(np.sqrt(X**2+Y**2))
Z2 = np.ones_like(Z1)*0.6
# Define the color for each one of our surfaces
# (it doesn't need to be a gradient)
color1 = np.empty_like(X, dtype=str)
color1.fill('b')
color2 = np.empty_like(X, dtype=str)
color2.fill('r')
# Create a white bridge region
X_bridge = np.vstack([X[-1,:],X[0,:]])
Y_bridge = np.vstack([Y[-1,:],Y[0,:]])
Z_bridge = np.vstack([Z1[-1,:],Z2[0,:]])
color_bridge = np.empty_like(Z_bridge, dtype=object)
color_bridge.fill((1,1,1,0))
# Join the two surfaces (using also the bridge)
X_full = np.vstack([X, X_bridge, X])
Y_full = np.vstack([Y, Y_bridge, Y])
Z_full = np.vstack([Z1, Z_bridge, Z2])
color_full = np.vstack([color1, color_bridge, color2])
surf_full = ax.plot_surface(X_full, Y_full, Z_full, rstride=1, cstride=1,
facecolors=color_full, linewidth=0,
antialiased=False)
ax.set_zlim3d(-1, 2)
ax.set_ylim(-5,5)
ax.set_xlim(-5,5)
plt.show()
我本来想考虑一些 肮脏的 hacks,比如 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 的答案中大量窃取,使用他的 "bridge" 解决方案,然后还对表面使用颜色贴图,并使用 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 解决问题。我用你的技术为我正在制定的商业计划增添了趣味(见图表)。我只是打听“alpha”问题。
是的,您可以在表面上使用不同的不透明度,方法是使用 RGBA 语法中的第四个属性。您还可以使用顺序颜色图,方法是向其传递一个 min-max 缩放 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.S。那个收入面不是平面。它会重新计算两个参数的每个组合的损益。
据我了解,ax.plplot_surface 方法只能为一个表面绘制好的图形,因此如果您需要绘制多个表面,则需要将它们组合成一个公共的 np.array。
我准备了一些代码,希望对您有所帮助:
# 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)
some tests
我正在使用 matplotlib 在同一个图形上绘制多个曲面,我只想看到最上面的曲面,如 matlab 所示。
Matlab 3D视图:
Matlab顶视图:
Matplotlib 3D 视图:
Matplotlib 俯视图:
如何让 Matplotlib 显示类似于 Matlab 的结果,其中最顶部的 class 显示在顶部,而不是一个 class 优先于另一个?
回答
正如问题的评论中所指出的,matplotlib 并没有真正进行 3d 绘图,它所做的近似可以给你有限的结果。您遇到的问题实际上已在 mplot3d
module's FAQ.
如果您想进行严肃的 3D 绘图,他们还会将您引导至 MayaVi。如果您真的不需要 3D 绘图并且只关心顶视图,那么我会按照 Bensciens 在评论中的建议直接进行 2D 绘图...
肮脏的解决方法
当然,如果您愿意用程序员的灵魂付出代价,几乎总有一个涉及一些黑魔法的解决方案...:P
选项 1
如果你真的只需要你作为例子的两个视图,并且表面与那些相似,你可以先绘制表面 A 后面的部分,然后是所有表面 B,然后是表面的部分在表面 A 之上...让我解释一下:
正如所指出的,here and here 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()
选项 2
(里面有解释,想知道答案的直接跳到最后一段!)
这个解决方案稍微复杂一些,但对于更复杂的表面也更稳健......问题是 matplotlib
中的 3d 图不能很好地处理 different[= 的深度80=] 对象...对吗?但它适用于 单个 对象...
那么如何将两个表面绘制为 单个 表面呢??
为此,您需要将所有点合并到一个曲面中(对于重复的 X-Y 组合,您可以有多个 Z 值)。为了区分我们新表面的两个部分(我们以前的两个表面),我们可以使用 facecolors
kwarg。 (我添加了一些 alpha
值以更清楚地看到发生了什么)
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)
Z1 = np.sin(np.sqrt(X**2+Y**2))
Z2 = np.ones_like(Z1)*0.6
C1 = np.empty_like(X, dtype=str)
C1.fill('b')
C2 = C1.copy()
C2.fill('r')
X3 = np.vstack([X,X])
Y3 = np.vstack([Y,Y])
Z3 = np.vstack([Z1,Z2])
C3 = np.vstack([C1,C2])
surf3 = ax.plot_surface(X3, Y3, Z3, rstride=1, cstride=1,
facecolors=C3, linewidth=0,
antialiased=False, alpha=0.5)
ax.set_zlim3d(-1, 2)
plt.show()
如您所见,结果非常好,但有一些奇怪的效果,因为一个表面的一个极端连接到另一个表面的另一个极端。如何摆脱它?
透明胶片不是一种选择,因为据我所知,plot_surface()
只允许影响整个表面的 alpha
值。我还尝试使用 X、Y 和 Z 中的一行 NaN
值来 mask 转换,其方式与 中的解决方法 1[=81= 类似],但随后渲染被破坏。你可以试试,也许这取决于我的安装。
编辑: 我找到了一个不太优雅且问题更多的解决方案,但正如@will 指出的那样,您 can 仅在通过使用 rgba
语法指定颜色来桥接区域。我将把我的版本留作评论历史,因为答案已经足够长了...:P
(增加点数可以获得更柔和的边缘)
from mpl_toolkits.mplot3d 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)
# Complex shape from examples in matplotlib gallery
Z1 = np.sin(np.sqrt(X**2+Y**2))
Z2 = np.ones_like(Z1)*0.6
# Define the color for each one of our surfaces
# (it doesn't need to be a gradient)
color1 = np.empty_like(X, dtype=str)
color1.fill('b')
color2 = np.empty_like(X, dtype=str)
color2.fill('r')
# Create a white bridge region
X_bridge = np.vstack([X[-1,:],X[0,:]])
Y_bridge = np.vstack([Y[-1,:],Y[0,:]])
Z_bridge = np.vstack([Z1[-1,:],Z2[0,:]])
color_bridge = np.empty_like(Z_bridge, dtype=object)
color_bridge.fill((1,1,1,0))
# Join the two surfaces (using also the bridge)
X_full = np.vstack([X, X_bridge, X])
Y_full = np.vstack([Y, Y_bridge, Y])
Z_full = np.vstack([Z1, Z_bridge, Z2])
color_full = np.vstack([color1, color_bridge, color2])
surf_full = ax.plot_surface(X_full, Y_full, Z_full, rstride=1, cstride=1,
facecolors=color_full, linewidth=0,
antialiased=False)
ax.set_zlim3d(-1, 2)
ax.set_ylim(-5,5)
ax.set_xlim(-5,5)
plt.show()
我本来想考虑一些 肮脏的 hacks,比如 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 的答案中大量窃取,使用他的 "bridge" 解决方案,然后还对表面使用颜色贴图,并使用 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 解决问题。我用你的技术为我正在制定的商业计划增添了趣味(见图表)。我只是打听“alpha”问题。
是的,您可以在表面上使用不同的不透明度,方法是使用 RGBA 语法中的第四个属性。您还可以使用顺序颜色图,方法是向其传递一个 min-max 缩放 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.S。那个收入面不是平面。它会重新计算两个参数的每个组合的损益。
据我了解,ax.plplot_surface 方法只能为一个表面绘制好的图形,因此如果您需要绘制多个表面,则需要将它们组合成一个公共的 np.array。
我准备了一些代码,希望对您有所帮助:
# 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)
some tests