【问题标题】:Python: Creating a 2D histogram from a numpy matrixPython:从 numpy 矩阵创建二维直方图
【发布时间】:2015-01-25 04:59:11
【问题描述】:

我是 python 新手。

我有一个 numpy 矩阵,尺寸为 42x42,值范围为 0-996。我想使用这些数据创建一个 2D 直方图。我一直在看教程,但它们似乎都展示了如何从随机数据而不是 numpy 矩阵创建二维直方图。

到目前为止,我已经导入了:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colors

我不确定这些是否是正确的导入,我只是想从我看到的教程中获取我能找到的东西。

我有一个包含所有值的 numpy 矩阵 M(如上所述)。最后,我希望它看起来像这样:

显然,我的数据会有所不同,所以我的情节应该看起来不同。谁能帮帮我?

编辑:出于我的目的,Hooked 的下面使用 matshow 的示例正是我正在寻找的。​​p>

【问题讨论】:

  • numpy 矩阵中的 x 和 y 是什么,它基本上是 42 行和 42 列。你的 x、y 值是多少?
  • 是的,我的矩阵是 42 行 42 列。在每个索引中,都有一个从 0 到 996 的整数,它是在程序的早期计算并放置在那里的。

标签: python numpy matrix matplotlib histogram


【解决方案1】:

如果您有来自计数的原始数据,您可以使用 plt.hexbin 为您创建图(恕我直言,这比方格好):改编自 hexbin 的示例:

import numpy as np
import matplotlib.pyplot as plt

n = 100000
x = np.random.standard_normal(n)
y = 2.0 + 3.0 * x + 4.0 * np.random.standard_normal(n)
plt.hexbin(x,y)

plt.show()

如果您提到的矩阵中已有 Z 值,只需使用 plt.imshowplt.matshow

XB = np.linspace(-1,1,20)
YB = np.linspace(-1,1,20)
X,Y = np.meshgrid(XB,YB)
Z = np.exp(-(X**2+Y**2))
plt.imshow(Z,interpolation='none')

【讨论】:

  • matshow 正是我想要的。非常感谢!
  • 要正确标记轴,您可以使用 bin 边缘的最小值和最大值将 extent 传递给 imshow。
  • 使用 matplotlib 函数 imshowpcolormeshNonUniformImage 也检查 official examples
【解决方案2】:

如果您不仅有 2D 直方图矩阵而且还有基础 (x, y) 数据,那么您可以制作 (x, y) 点的散点图,并根据 2D 直方图矩阵中的分箱计数值对每个点进行着色:

import numpy as np
import matplotlib.pyplot as plt

n = 10000
x = np.random.standard_normal(n)
y = 2.0 + 3.0 * x + 4.0 * np.random.standard_normal(n)
xedges, yedges = np.linspace(-4, 4, 42), np.linspace(-25, 25, 42)
hist, xedges, yedges = np.histogram2d(x, y, (xedges, yedges))
xidx = np.clip(np.digitize(x, xedges), 0, hist.shape[0]-1)
yidx = np.clip(np.digitize(y, yedges), 0, hist.shape[1]-1)
c = hist[xidx, yidx]
plt.scatter(x, y, c=c)

plt.show()

【讨论】:

    【解决方案3】:

    我是“散点直方图”的忠实拥护者,但我认为其他解决方案并不能完全做到公正。 Here is a function 实现它们。与其他解决方案相比,此函数的主要优点是它按历史数据对点进行排序(请参阅mode 参数)。这意味着结果看起来更像传统的直方图(即,您不会在不同的 bin 中看到标记的混乱重叠)。

    此图的 MCVE(使用 my function):

    import numpy as np
    import matplotlib.pyplot as plt
    from hist_scatter import scatter_hist2d
    
    fig = plt.figure(figsize=[5, 4])
    ax = plt.gca()
    
    x = randgen.randn(npoint)
    y = 2 + 3 * x + 4 * randgen.randn(npoint)
    
    scat = scatter_hist2d(x, y,
                          bins=[np.linspace(-4, 4, 42),
                                np.linspace(-25, 25, 42)],
                          s=5,
                          cmap=plt.get_cmap('viridis'))
    ax.axhline(0, color='k', linestyle='--', zorder=3, linewidth=0.5)
    ax.axvline(0, color='k', linestyle='--', zorder=3, linewidth=0.5)
    plt.colorbar(scat)
    

    还有改进的余地?

    这种方法的主要缺点是最密集区域中的点与低密度区域中的点重叠,导致每个 bin 的区域存在一定程度的错误表示。我花了很多时间探索解决这个问题的两种方法:

    1) 对更高密度的 bin 使用更小的标记

    2) 对每个 bin 应用“剪辑”蒙版

    第一个gives results 太疯狂了。第二个看起来不错 - 特别是如果您只剪辑具有 >~20 点的垃圾箱 - 但它非常慢this figure 花了大约一分钟)。

    所以,我最终决定,通过仔细选择标记大小和 bin 大小(sbins),您可以获得视觉上令人愉悦且不会太差的结果歪曲数据的条款。毕竟,这些 2D 直方图通常旨在作为基础数据的视觉辅助工具,而不是对其进行严格的定量表示。因此,我认为这种方法远远优于“传统的 2D 直方图”(例如,plt.hist2dplt.hexbin),而且我认为如果您找到此页面,您也不是传统(单色) 散点图。

    如果我是科学之王,我会确保所有 2D 直方图在剩下的时间里永远做这样的事情。

    【讨论】:

      【解决方案4】:

      @unutbu's answer 包含错误:xidxyidx 的计算方式错误(至少在我的数据样本中)。正确的做法应该是:

      xidx = np.clip(np.digitize(x, xedges) - 1, 0, hist.shape[0] - 1)
      yidx = np.clip(np.digitize(y, yedges) - 1, 0, hist.shape[1] - 1)
      

      因为我们感兴趣的np.digitize的返回维度在1len(xedges) - 1之间,但是c = hist[xidx, yidx]需要0hist.shape - 1之间的索引。


      以下是结果对比。如您所见,您得到了相似但不同的结果。

      import numpy as np
      import matplotlib.pyplot as plt
      
      fig = plt.figure()
      ax1 = fig.add_subplot(211)
      ax2 = fig.add_subplot(212)
      
      n = 10000
      x = np.random.standard_normal(n)
      y = 2.0 + 3.0 * x + 4.0 * np.random.standard_normal(n)
      xedges, yedges = np.linspace(-4, 4, 42), np.linspace(-25, 25, 42)
      hist, xedges, yedges = np.histogram2d(x, y, (xedges, yedges))
      
      xidx = np.clip(np.digitize(x, xedges), 0, hist.shape[0] - 1)
      yidx = np.clip(np.digitize(y, yedges), 0, hist.shape[1] - 1)
      c = hist[xidx, yidx]
      old = ax1.scatter(x, y, c=c, cmap='jet')
      
      xidx = np.clip(np.digitize(x, xedges) - 1, 0, hist.shape[0] - 1)
      yidx = np.clip(np.digitize(y, yedges) - 1, 0, hist.shape[1] - 1)
      
      c = hist[xidx, yidx]
      new = ax2.scatter(x, y, c=c, cmap='jet')
      
      
      plt.show()
      

      【讨论】:

      • 发布答案时,请确保您的答案不依赖于其他答案中提供的信息。您在另一个答案中正确地描述了问题(这是一件好事),但随后只提供了部分解决方案,如果不查看其他答案就无法使用。请编辑您的答案并包含完整的sn-p,否则您的帖子可能会被删除。
      猜你喜欢
      • 2021-05-12
      • 1970-01-01
      • 2022-09-30
      • 2021-10-04
      • 2019-08-30
      • 1970-01-01
      • 2011-02-11
      • 2017-09-08
      • 1970-01-01
      相关资源
      最近更新 更多