首页 > 解决方案 > 在每个单元格中创建具有相同点数的 2D Hist

问题描述

我正在寻找一种可能性来创建具有不规则bin 大小的 2D 直方图,并可以将热量绘制为 z 变量。

数据:我有十亿个对象。每个对象都有特征 x、y 和 z 的异常分数。

绘图:绘制的是所有带有 y 对 x 的对象。直方图应该具有不规则(自适应)的 bin 大小,以便在创建的每个 bin 中都有相同数量的对象。这应该最初创建一个没有任何可见特征的直方图,只有一种颜色(颜色代表对象的数量)。

为了创建 bin 边缘,我首先使用 np.percentiles 并将基于 x 特征的对象分成百分位数。其次,我使用第一个 x binedge,找到其中的所有点并根据百分位数在 y 方向上对它们进行 binedge。这看起来像这样(伪代码):

for i, key_x in enumerate(np.percentile(x, np.arange(0,101, 10))):
    xedges[i] = key_x
    objects = find_all_objects_within_binedge(key_x)

    for j, key_y in enumerate(np.percentile(objects["y"], np.arange(0,101, 10))):
        yedges[i, j] = key_y

所以 xedges 是一个在 x 方向上有边的数组,而 yedges 是一个矩阵,为我提供了每个 x 边的 y 边。如果这不能理解,请告诉我。

因此,如果我们想象会产生的直方图,我们将在 x 中有直线分箱线。但在 y 方向上,这些线将被分割。请参阅此处以了解我的意思是 y bin 是不规则拆分。

这就是我被卡住了。我不知道如何使用这些不规则的 bin 从我的 x-binedges 和 y-binedges 创建直方图或绘图。

目标(为了更好地理解):一旦完成,我希望能够使用 z 值将每个 bin 用该单元格内所有点的平均值或标准着色(准备好代码)。理想情况下,这看起来也很顺利,除了一些小的例外,这将是异常的,也是我正在寻找的。但这对于 plt.pcolormesh 应该是可行的。

英语不是我的母语,我尽力描述这个问题。如果有不清楚的地方,请告诉我,我会尽力澄清。提前谢谢你们:)

标签: pythonmatplotlib

解决方案


似乎这个问题要求一种在网格上绘制值的方法,该网格在一个维度上是规则的,但在另一个维度上是不规则的。
据我了解,这样的网格将由例如 x 方向的一维数组和 y 方向的二维数组定义。两个数组都将表示相应维度中网格单元的边缘。

对于 M x N 网格,x_edges因此将具有N+1元素,并且y_edges形状为(M+1, N)。下面是一个 4 x 3 的网格。

x_edges = np.array([0,1,2,3])
y_edges = np.array([[0.,0.,0.],
                    [.3,.2,.2],
                    [.5,.6,.4],
                    [.8,.9,.7],
                    [1.,1.,1.]])

通常的 matplotlib 工具喜欢imshowpcolor做 - 据我所知 - 不允许绘制这样的网格。因此,另一种方法是使用 aPolyCollection并用它绘制相应的矩形。

可以将应映射到颜色的值数组设置为该集合。这个数组应该每个维度少一个值并且是平坦的,即有 M*N 个元素。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import PolyCollection

# Starting data: A grid, regular in x-direction and irregular in y direction.
x_edges = np.array([0,1,2,3])
y_edges = np.array([[0.,0.,0.],
                    [.3,.2,.2],
                    [.5,.6,.4],
                    [.8,.9,.7],
                    [1.,1.,1.]])

######## Grid creation ################
#y_edges = np.concatenate((y_edges, np.zeros(len(y_edges))))
s = np.array(y_edges.shape)
# make x_edges 2D as well.
x_edges = np.tile(x_edges, s[0]-1).reshape((s[0]-1, s[1]+1))

# you may also have an array of values. 
# This should be of shape one less than the edges and flattened.
values = np.arange(np.prod(s+np.array((-1,0))))

# Produce a vertices array of the edges of rectangles that form each pixel.
x = np.c_[x_edges[:,:-1].flatten(), x_edges[:,:-1].flatten(),
          x_edges[:,1: ].flatten(), x_edges[:,1: ].flatten()]
y = np.c_[y_edges[:-1,:].flatten(), y_edges[1: ,:].flatten(),
          y_edges[1: ,:].flatten(), y_edges[:-1,:].flatten()]
xy = np.stack((x,y), axis=2)

# Create collection of rectangles.
pc = PolyCollection(xy, closed=True, edgecolors="k", linewidth=0.72, cmap="inferno")
pc.set_array(values)

######## Plotting ################
fig, ax = plt.subplots()
ax.add_collection(pc)
fig.colorbar(pc, ax=ax)

ax.margins(0)
ax.autoscale()
plt.show()

在此处输入图像描述

此网格使用少量单元格来显示原理。如果您想要更多单元格,请确保不要通过删除edgecolorslinewidth参数来绘制矩形的边缘。


推荐阅读