【问题标题】:Python scatter plot of 4D data4D数据的Python散点图
【发布时间】:2014-07-08 09:01:20
【问题描述】:

我有想要散点图的 4D 数据数组。可以将数据视为两个附加参数的每对值的 x 和 y 坐标。

我想将绘图“展平”为 2D 散点图,其中两个额外参数由不同颜色表示,例如两个参数中每对的颜色。或者,我希望仅为少数参数对绘制的点看起来很亮,而为许多参数对绘制的点看起来更重/更暗。也许这可以通过“堆叠”一些半透明的点来实现?

是否有一些标准方法可以在 Python 中执行此操作,例如使用 matplotlib

【问题讨论】:

  • 也许散点图矩阵是更好的解决方案。以here 为例。
  • 这看起来确实很有趣。不幸的是,我没有使用pandas 的经验,但也许我应该检查一下。
  • this question中有相关的纯matplotlib例子。 @tisimst's answer,这是对@Joe Kington's的重构,似乎是最完整的。
  • @lbn-plus-1 n-plus-1 这个问题很接近,但并不完全重复。简短的回答是肯定的。您能向我们展示您对 scatter 的尝试吗?这将是比“请为我编写代码”更好的起点。
  • 我昨天尝试了几种解决方案。如果我有时间的话,我会在今天晚些时候添加它们。

标签: python matplotlib


【解决方案1】:

作为the "stacked" scatter plot 的替代方案,我首先尝试在二维“出现地图”中累积data1 < data2 的出现。然后我使用pcolormesh 绘制了这张地图(从prettyplotlib 导入以使其看起来更好):

import prettyplotlib as ppl
import numpy as np

occurrence_map = np.sum(data1 < data2, axis=(2,3), dtype=float) / np.prod(data1.shape[2:])
ppl.pcolormesh(occurrence_map2, vmin=0, vmax=1)

归一化是为了产生一个相对的发生率度量,即参数对(data1data2 的最后两个维度)中有多大比例是data1 &lt; data2?然后将该图配置为从 0 到 1 范围内的颜色值。这将产生以下我更满意的图:

【讨论】:

    【解决方案2】:

    我尝试了我建议的“堆叠”半透明散点图的方法:

    import numpy as np
    import matplotlib.pyplot as plt
    
    for ii in xrange(len(param1)):
        for jj in xrange(len(param2)):
            delta_idx, rho_idx = np.where(data1[:,:,ii,jj] < data2[:,:,ii,jj])
            plt.scatter(delta_idx, rho_idx, marker = 'o', c = 'k', alpha = 0.01)
    plt.xlabel('$\delta$')
    plt.ylabel('$\rho$')
    plt.show()
    

    我在问题中描述的二维点实际上是对data1 中的值小于data2 中相应值的位置的标识。这产生了以下情节:

    可以做更多的事情来美化情节,但我对它的外观并不满意,所以我尝试了另一个approach。无论如何我都会在这里发布,以防有​​人发现它有用。

    【讨论】:

      【解决方案3】:

      关于散点图矩阵的 cmets 也启发了我尝试类似的方法。散点图矩阵并不是我想要的,但我从@lbn-plus-1 建议的@tisimst's answer 中获取了代码并对其进行了一些调整,如下所示:

      import itertools
      import numpy as np
      import matplotlib.pyplot as plt
      
      def scatterplot_matrix(data, names=[], **kwargs):
          """Plots a pcolormesh matrix of subplots.  The two first dimensions of
          data are plotted as a mesh of values, one for each of the two last
          dimensions of data. Data must thus be four-dimensional and results
          in a matrix of pcolormesh plots with the number of rows equal to
          the size of the third dimension of data and number of columns
          equal to the size of the fourth dimension of data. Additional
          keyword arguments are passed on to matplotlib\'s \"pcolormesh\"
          command. Returns the matplotlib figure object containg the subplot
          grid.
          """
          assert data.ndim == 4, 'data must be 4-dimensional.'
          datashape = data.shape
          fig, axes = plt.subplots(nrows=datashape[2], ncols=datashape[3], figsize=(8,8))
          fig.subplots_adjust(hspace=0.0, wspace=0.0)
      
          for ax in axes.flat:
              # Hide all ticks and labels
              ax.xaxis.set_visible(False)
              ax.yaxis.set_visible(False)
      
              # Set up ticks only on one side for the "edge" subplots...
              if ax.is_first_col():
                  ax.yaxis.set_ticks_position('left')
              if ax.is_last_col():
                  ax.yaxis.set_ticks_position('right')
              if ax.is_first_row():
                  ax.xaxis.set_ticks_position('top')
              if ax.is_last_row():
                  ax.xaxis.set_ticks_position('bottom')
      
          # Plot the data.
          for ii in xrange(datashape[2]):
              for jj in xrange(datashape[3]):
                  axes[ii,jj].pcolormesh(data[:,:,ii,jj], **kwargs)
      
          # Label the diagonal subplots...
          #if not names:
          #    names = ['x'+str(i) for i in range(numvars)]
          # 
          #for i, label in enumerate(names):
          #    axes[i,i].annotate(label, (0.5, 0.5), xycoords='axes fraction',
          #            ha='center', va='center')
      
          # Turn on the proper x or y axes ticks.
          #for i, j in zip(range(numvars), itertools.cycle((-1, 0))):
          #    axes[j,i].xaxis.set_visible(True)
          #    axes[i,j].yaxis.set_visible(True)
      
          # FIX #2: if numvars is odd, the bottom right corner plot doesn't have the
          # correct axes limits, so we pull them from other axes
          #if numvars%2:
          #    xlimits = axes[0,-1].get_xlim()
          #    ylimits = axes[-1,0].get_ylim()
          #    axes[-1,-1].set_xlim(xlimits)
          #    axes[-1,-1].set_ylim(ylimits)
      
          return fig
      
      if __name__=='__main__':
          np.random.seed(1977)
          data = np.random.random([10] * 4)
          fig = scatterplot_matrix(data,
                  linestyle='none', marker='o', color='black', mfc='none')
          fig.suptitle('Simple Scatterplot Matrix')
          plt.show()
      

      我把上面的模块保存为datamatrix.py,使用如下:

      import datamatrix
      import brewer2mpl
      
      colors = brewer2mpl.get_map('RdBu', 'Diverging', 11).mpl_colormap
      indicator = np.ma.masked_invalid(-np.sign(data1 - data2)) # Negated because the 'RdBu' colormap is the wrong way around
      fig = datamatrix.scatterplot_matrix(indicator, cmap = colors)
      plt.show()
      

      brewer2mpl 和颜色映射的东西可以省略 - 这只是我正在玩弄的一些颜色。结果如下图:

      矩阵的“外部”维度是两个参数(data1data2 的最后两个维度)。矩阵内的每个pmeshcolor 图都是一个“出现图”,有点类似于this answer 中的图,但是对于每对参数来说都是一个二进制图。一些图底部的白线是相等的区域。每个右上角的白点是数据中的nan 值。

      【讨论】: