Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ssis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Matlab 是否在matplotlib中显示最大曲面?_Matlab_Matplotlib_Plot_Surface - Fatal编程技术网

Matlab 是否在matplotlib中显示最大曲面?

Matlab 是否在matplotlib中显示最大曲面?,matlab,matplotlib,plot,surface,Matlab,Matplotlib,Plot,Surface,我正在使用matplotlib在同一个图形上绘制多个曲面,我只希望看到最上面的曲面,如matlab所示 Matlab 3D视图: Matlab俯视图: Matplotlib三维视图: Matplotlib俯视图: 如何让Matplotlib显示类似于Matlab的结果,其中最顶层的类显示在顶部,而不是一个类优先于另一个类?答案 正如对问题的评论中所指出的,matplotlib并不能真正进行三维打印,它所做的近似可以提供有限的结果。您遇到的问题实际上已在中得到承认 如果要进行认真的三维打印

我正在使用matplotlib在同一个图形上绘制多个曲面,我只希望看到最上面的曲面,如matlab所示

Matlab 3D视图:

Matlab俯视图:

Matplotlib三维视图:

Matplotlib俯视图:

如何让Matplotlib显示类似于Matlab的结果,其中最顶层的类显示在顶部,而不是一个类优先于另一个类?

答案 正如对问题的评论中所指出的,matplotlib并不能真正进行三维打印,它所做的近似可以提供有限的结果。您遇到的问题实际上已在中得到承认

如果要进行认真的三维打印,它们也会指导您。如果你真的不需要3D绘图,只关心俯视图,那么我会按照Bensciens在评论中的建议直接进行2D绘图

肮脏的变通办法 当然,如果你愿意用程序员的灵魂来支付,几乎总会有一个解决方案涉及到一些黑暗魔法…:P

选择1 如果您确实只需要两个视图作为示例,并且曲面与这些视图相似,则可以先绘制曲面A后面的部分,然后绘制所有曲面B,然后绘制曲面A顶部的部分。。。让我解释一下:

如前所述,
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)