【问题标题】:Waterfall plot python?瀑布图python?
【发布时间】:2012-06-27 21:46:42
【问题描述】:

是否有一个 python 模块可以像 MATLAB 那样绘制瀑布图?我用谷歌搜索了“numpy 瀑布”、“scipy 瀑布”和“matplotlib 瀑布”,但没有找到任何东西。

【问题讨论】:

    标签: python matlab numpy matplotlib scipy


    【解决方案1】:

    您可以使用 PolyCollection 类在 matplotlib 中制作瀑布图。请参阅这个特定的example 以了解有关如何使用此类制作瀑布的更多详细信息。

    此外,您可能会发现此blog post 很有用,因为作者表明您可能会在某些特定情况下获得一些“视觉错误”(取决于选择的视角)。

    以下是使用 matplotlib 制作的瀑布示例(图片来自博客文章):
    (来源:austringer.net

    【讨论】:

      【解决方案2】:

      我已经生成了一个函数,可以在 matplotlib 中复制 matlab 瀑布行为。那就是:

      1. 它生成的 3D 形状与许多独立且平行的 2D 曲线一样
      2. 它的颜色来自 z 值中的颜色图

      我从 matplotlib 文档中的两个示例开始:multicolor linesmultiple lines in 3d plot。从这些示例中,我只看到可以根据示例后面的 z 值绘制颜色在给定颜色图之后变化的线条,这正在重塑输入数组以通过 2 个点的线段绘制线并将线段的颜色设置为这两个点之间的 z 平均值。

      因此,给定输入矩阵 n,m 矩阵 XYZ,函数在 n,m 之间的最小维度上循环,以将每个瀑布图独立线绘制为如上所述的 2 个点段。

      def waterfall_plot(fig,ax,X,Y,Z,**kwargs):
          '''
          Make a waterfall plot
          Input:
              fig,ax : matplotlib figure and axes to populate
              Z : n,m numpy array. Must be a 2d array even if only one line should be plotted
              X,Y : n,m array
              kwargs : kwargs are directly passed to the LineCollection object
          '''
          # Set normalization to the same values for all plots
          norm = plt.Normalize(Z.min().min(), Z.max().max())
          # Check sizes to loop always over the smallest dimension
          n,m = Z.shape
          if n>m:
              X=X.T; Y=Y.T; Z=Z.T
              m,n = n,m
      
          for j in range(n):
              # reshape the X,Z into pairs 
              points = np.array([X[j,:], Z[j,:]]).T.reshape(-1, 1, 2)
              segments = np.concatenate([points[:-1], points[1:]], axis=1)  
              # The values used by the colormap are the input to the array parameter
              lc = LineCollection(segments, cmap='plasma', norm=norm, array=(Z[j,1:]+Z[j,:-1])/2, **kwargs)
              line = ax.add_collection3d(lc,zs=(Y[j,1:]+Y[j,:-1])/2, zdir='y') # add line to axes
      
          fig.colorbar(lc) # add colorbar, as the normalization is the same for all
          # it doesent matter which of the lc objects we use
          ax.auto_scale_xyz(X,Y,Z) # set axis limits
      

      因此,可以使用与 matplotlib 曲面图相同的输入矩阵轻松生成看起来像 matlab 瀑布的图:

      import numpy as np; import matplotlib.pyplot as plt
      from matplotlib.collections import LineCollection
      from mpl_toolkits.mplot3d import Axes3D
      
      # Generate data
      x = np.linspace(-2,2, 500)
      y = np.linspace(-2,2, 60)
      X,Y = np.meshgrid(x,y)
      Z = np.sin(X**2+Y**2)-.2*X
      # Generate waterfall plot
      fig = plt.figure()
      ax = fig.add_subplot(111, projection='3d')
      waterfall_plot(fig,ax,X,Y,Z,linewidth=1.5,alpha=0.5) 
      ax.set_xlabel('X'); ax.set_ylabel('Y'); ax.set_zlabel('Z') 
      fig.tight_layout()
      

      该函数假设在生成网格时,x 数组是最长的,并且默认情况下,线条的 y 是固定的,而 x 坐标是变化的。但是,如果y 数组的大小较长,则矩阵会被转置,从而生成具有固定 x 的行。因此,生成大小反转的网格(len(x)=60len(y)=500)会产生:

      要查看**kwargs 参数的可能性,请参阅LineCollection class documantation 及其set_ methods

      【讨论】:

        【解决方案3】:

        Waterfall chart的Wikipedia类型也可以这样获取:

        import numpy as np
        import pandas as pd
        
        def waterfall(series):
            df = pd.DataFrame({'pos':np.maximum(series,0),'neg':np.minimum(series,0)})
            blank = series.cumsum().shift(1).fillna(0)
            df.plot(kind='bar', stacked=True, bottom=blank, color=['r','b'])
            step = blank.reset_index(drop=True).repeat(3).shift(-1)
            step[1::3] = np.nan
            plt.plot(step.index, step.values,'k')
        
        test = pd.Series(-1 + 2 * np.random.rand(10), index=list('abcdefghij'))
        waterfall(test)
        

        【讨论】:

        【解决方案4】:

        看看mplot3d:

        # copied from 
        # http://matplotlib.sourceforge.net/mpl_examples/mplot3d/wire3d_demo.py
        
        from mpl_toolkits.mplot3d import axes3d
        import matplotlib.pyplot as plt
        import numpy as np
        
        fig = plt.figure()
        ax = fig.add_subplot(111, projection='3d')
        X, Y, Z = axes3d.get_test_data(0.05)
        ax.plot_wireframe(X, Y, Z, rstride=10, cstride=10)
        
        plt.show()
        

        我不知道如何得到像 Matlab 那样好的结果。


        如果你想要更多,你也可以看看MayaVihttp://mayavi.sourceforge.net/

        【讨论】:

          猜你喜欢
          • 2020-01-14
          • 2018-11-14
          • 2021-12-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多