Matplotlib:`pcolormesh.get_array()`返回了扁平化的数组 - 如何获取2D数据?

3
我正在尝试获取沿着一条线的数据值(就像这个提示中所示)。该示例使用imshow(),但我目前正在使用pcolormesh()进行绘图。
我发现从pcolormesh()抓取绘制数据的get_array()函数返回的是我的数据的1-D平坦数组,而不是原始(或截断)2-D数据。
例如:
D = np.genfromtxt(DataFilePath, skip_header=4, delimiter=',', unpack=True)
print( D.shape )
: (500, 500)

...more code...

img = ax[0].pcolormesh( np.arange( len(D[0,:]) ), np.arange(len(D[:,0])), D)

>>> D
: array([[ 42.38,  41.93,  41.92, ...,  41.73,  41.74,  41.51],
       [ 41.88,  42.24,  42.21, ...,  41.88,  41.67,  41.64],
       [ 42.4 ,  41.47,  41.49, ...,  41.92,  42.07,  41.49],
       ..., 
       [ 44.24,  44.14,  44.17, ...,  40.2 ,  40.68,  40.67],
       [ 44.59,  44.24,  44.3 , ...,  40.91,  40.92,  40.95],
       [ 44.2 ,  44.27,  44.27, ...,  40.82,  40.91,  40.94]])
>>> img.get_array()
: array([ 42.38,  41.93,  41.92, ...,  40.85,  40.91,  40.92])

自从我试图在绘图上获取用户点击并使用所点击的数据值重新绘制(就像这个提示中的示例),我想使用一个不会全局访问原始数据,但确实可以访问img对象的函数/类。
有什么办法可以仅使用img(QuadMesh)对象获取pcolormesh()中的二维数据?对于我来说,它甚至似乎没有x/y长度/形状值,以便我可以从1-D的get_array()重构数据。
谢谢!

就像 pcolormesh 对数据运行了 np.ravel() 并将其存储在 get_array() 中一样 - 有没有什么方法可以进行“解开”操作? - Demis
你预计会看到哪些用户更改? - hpaulj
只想获取用户点击并释放的点之间的线上绘制数据值,然后让它发生在事件处理程序类内部,该类仅能访问img(QuadMesh)对象,但无法访问原始数据数组。 - Demis
那么@unutbu提到的img属性就是正确的方法。 - hpaulj
我在这里发布了整个函数:https://dev59.com/O2sz5IYBdhLWcg3weHqU#34848130 - Demis
2个回答

4
数组的形状存储在私有属性 _meshWidth_meshHeight 中。然而,由于这些属性不是公共API的一部分,如果可能的话最好保存原始数据的形状,而不是依赖这些属性。
import matplotlib.pyplot as plt
import numpy as np

D = np.random.uniform(0, 100, size=(5, 5))
fig, ax = plt.subplots()
h, w = D.shape
img = ax.pcolormesh( np.arange(h+1), np.arange(w+1), D)

D2 = img.get_array().reshape(img._meshWidth, img._meshHeight)
assert  np.array_equal(D, D2)

请注意,如果您希望恢复原始数组D,则坐标数组np.arange(h+1)np.arange(w+1)的长度必须比D的形状大1。否则,当D的形状为(500, 500)时,img.get_array()返回一个形状为(499, 499)的数组。

_pcolorargs来看,pcolor将会根据需要匹配xy截断C中的点。 - hpaulj
啊,_meshWidth_meshHeight的值是我需要复制原始数组的东西。不幸的是,编写这些属性使得我的函数现在只能适用于pcolormesh - 如果有一个通用的API调用(比如get_width()/get_height()),我的函数将适用于pcolorpcolormesh,甚至可能也适用于contourf等其他函数。也许应该提交一个功能请求... - Demis
我在pcolor生成的内容上添加了一些注释 - 它将网格分成许多简单的四边形,因此它的img没有任何网格高度或宽度的概念。 - hpaulj

3
是的,它确实会解开输入:

https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/axes/_axes.py

    # convert to one dimensional arrays
    C = C.ravel()
    X = X.ravel()
    Y = Y.ravel()

如果您知道所需的2D形状,只需使用简单的reshape调用即可展开。

如果结果应与D具有相同的形状,请使用:

img.get_array().reshape(D.shape)

如果被卷曲的 C 的大小可以改变,那么这个方法就不适用了。
如果我创建一个 D 数组,大小为 (10,20) 并将其绘制出来。
img = pyplot.pcolormesh(D)

img._A 是一个形状为 (200,) 的数组,它是 img.get_array() 返回的结果。

img._meshHeight, img._meshWidth
# 10, 20

所以可以使用以下方式重新调整数组:

img._A.reshape(img._meshHeight, img._meshWidth)
img._coordinates是一个(11,21,2)的数组,包含了沿着x和y方向的坐标,再加上一个点。从_coordinates中可以获取到C重塑信息。我没有看到任何公共API方法用于检索这些属性,但这并不能阻止“严肃”的Python程序员。在这个测试用例中,它从D的形状生成了coordinates
这个Quadmesh是通过以下方式创建的:
    coords = np.zeros(((Nx * Ny), 2), dtype=float)
    coords[:, 0] = X
    coords[:, 1] = Y

    collection = QuadMesh(
        Nx - 1, Ny - 1, coords, ...)
    ....
    collection.set_array(C)

matplotlib 的 GitHub 存储库中搜索 get_array 并没有得到很多结果。
我深入研究了一下 pcolor 代码。它返回一个 PolyCollections img,而不是 Quadmesh。 它包含绘制四边形集合的信息。
例如,在我的测试案例中,输入为 10x20,img._paths 是由 200 个 Path 对象组成的列表。
In [486]: img1._paths[0]
Out[486]: 
Path(array([[ 0.,  0.],
       [ 0.,  1.],
       [ 1.,  1.],
       [ 1.,  0.],
       [ 0.,  0.],
       [ 0.,  0.]]), array([ 1,  2,  2,  2,  2, 79], dtype=uint8))

它有五对坐标点,即绘制四边形边界所需的xy点,其颜色值对应于以展开形式表示的C[0]。因此,所有的XY网格信息现在都编码在这些Path对象中。它不再绘制网格,而是绘制了200个着色的正方形(四边形)。PolyCollections代码并不假设这些正方形是按任何顺序甚至相互接触的。大图已被一堆独立的小图替代。您可以尝试重新组合这些四边形成为网格,寻找匹配的顶点等,但这将是很多工作。

很遗憾,我的函数将无法访问原始数据 D - Demis
谢谢,这真的很有趣。在您的研究中,您是否遇到过适用于各种类型的表面/二维绘图的方法?我还没有尝试过,但我想知道“_coordinates”方法是否不仅适用于“Pcolormesh”,还适用于“Pcolor”或“ContorF”。 - Demis
pcolorimg没有_coordinates属性。我能找到xy值的唯一位置是在_paths中。我查看了代码和样本img对象(通过ipython)。 - hpaulj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接