Matplotlib:如何使imshow从其他numpy数组读取x、y坐标?

20

当您想要使用imshow绘制一个numpy数组时,这通常是您要做的:

import numpy as np
import matplotlib.pyplot as plt

A=np.array([[3,2,5],[8,1,2],[6,6,7],[3,5,1]]) #The array to plot

im=plt.imshow(A,origin="upper",interpolation="nearest",cmap=plt.cm.gray_r)
plt.colorbar(im)

这给我们呈现了这个简单的图像: 在此输入图片描述

在这张图片中,xy 坐标可以从数组中每个值的位置中简单提取出来。现在,假设 A 是一个包含指定坐标的值的数组:

real_x=np.array([[15,16,17],[15,16,17],[15,16,17],[15,16,17]])
real_y=np.array([[20,21,22,23],[20,21,22,23],[20,21,22,23]])

这些值是虚构的,只是为了举例说明。 是否有一种方法可以强制imshow将A中的每个值分配给相应的坐标对(real_x,real_y)?

PS:我不是要在基于数组的x和y上加减某些值使其与real_xreal_y匹配,而是希望能够从real_xreal_y数组中读取这些值。预期结果是一幅图像,其中x轴上的值为real_x,y轴上的值为real_y


http://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.scatter.html - 这是您要找的吗? - rammelmueller
不,我不是在寻找能够生成散点图的工具。我关注的是栅格图像(numpy 数组)。 - FaCoffee
你能分享一张图片来展示它应该是什么样子吗?或者基于你的两个数组解释一下它应该如何“生成”(不需要是代码,只需要一些解释)。 - MSeifert
2
如果我理解正确,您只有3个不同的x(15、16、17)和3个不同的y(20、21、22)坐标,但是却有一个3x4像素的图像。这应该如何工作? - MSeifert
是的,我的错。请检查我的编辑。 - FaCoffee
显示剩余2条评论
4个回答

21

设置范围

假设您已经

real_x=np.array([15,16,17])
real_y=np.array([20,21,22,23])

你需要将图像范围设置为

dx = (real_x[1]-real_x[0])/2.
dy = (real_y[1]-real_y[0])/2.
extent = [real_x[0]-dx, real_x[-1]+dx, real_y[0]-dy, real_y[-1]+dy]
plt.imshow(data, extent=extent)

更改刻度标签

另一种方法是只更改刻度标签

real_x=np.array([15,16,17])
real_y=np.array([20,21,22,23])
plt.imshow(data)
plt.gca().set_xticks(range(len(real_x)))
plt.gca().set_yticks(range(len(real_x)))
plt.gca().set_xticklabels(real_x)
plt.gca().set_yticklabels(real_y)

4
如果real_xreal_y是固定宽度的单调递增的话,那种“程度”方法就行得通。我猜这个问题是在询问一个更加普遍的方法。 - MSeifert
3
Imshow图形假设具有单调的1像素比例,否则比例尺将失去作用。因此,如果像素之间的差异在轴范围内不相同,则需要更改刻度标签。我还添加了一个解决方案,只需设置刻度标签即可。 - ImportanceOfBeingErnest

4

如果我理解正确,这与为imshow生成光栅图有关,也就是说,给定X-图像坐标和y值,生成imshow的输入矩阵。我不知道是否有标准函数可供使用,因此我实现了它。

import numpy as np

def to_raster(X, y):
"""
:param X: 2D image coordinates for values y
:param y: vector of scalar or vector values
:return: A, extent
"""
    def deduce_raster_params():
        """
        Computes raster dimensions based on min/max coordinates in X
        sample step computed from 2nd - smallest coordinate values
        """
        unique_sorted = np.vstack((np.unique(v) for v in X.T)).T
        d_min = unique_sorted[0] # x min, y min
        d_max = unique_sorted[-1] # x max, y max
        d_step = unique_sorted[1]-unique_sorted[0] # x, y step
        nsamples = (np.round((d_max - d_min) / d_step) + 1).astype(int)
        return d_min, d_max, d_step, nsamples

    d_min, d_max, d_step, nsamples = deduce_raster_params()
    # Allocate matrix / tensor for raster. Allow y to be vector (e.g. RGB triplets)
    A = np.full((*nsamples, 1 if y.ndim==1 else y.shape[-1]), np.NaN)
    # Compute index for each point in X
    ind = np.round((X - d_min) / d_step).T.astype(int)
    # Scalar/vector values assigned over outer dimension 
    A[list(ind)] = y  # cell id
    # Prepare extent in imshow format
    extent = np.vstack((d_min, d_max)).T.ravel()
    return A, extent

这可以与imshow一起使用,如下所示:
import matplotlib.pyplot as plt 
A, extent = to_raster(X, y)
plt.imshow(A, extent=extent) 

请注意,deduce_raster_params()的运行时间复杂度为O(n*log(n)),而不是O(n),这是因为np.unique()中的排序所导致的 - 这简化了代码,并且可能不会对发送到imshow的东西造成问题。

2

这里是一个简单的示例,说明如何将y轴重新缩放到另一个范围:

import matplotlib.pyplot as plt
import numpy as np

def yaxes_rerange(row_count, new_y_range):
    scale = (new_y_range[1] - new_y_range[0]) / row_count
    y_range = np.array([1, row_count - 1]) * scale

    dy = (y_range[1] - y_range[0]) / 2 - (new_y_range[1] - new_y_range[0])
    ext_y_range = y_range + new_y_range[0] + np.array([-dy, dy])
    extent = [-0.5, data.shape[1] - 0.5, ext_y_range[0], ext_y_range[1]]

    aspect = 1 / scale

    return extent, aspect


data = np.array([[1, 5, 3], [8, 2, 3], [1, 3, 5], [1, 2, 4]])

row_count = data.shape[0]
new_range = [8, 16]

extent, aspect = yaxes_rerange(row_count, new_range)

img = plt.imshow(data, extent=extent, aspect=aspect)
img.axes.set_xticks(range(data.shape[1]))
img.axes.set_xticklabels(["water", "wine", "stone"])

enter image description here


1

对于extent方法,为了使其起作用,imshow()的参数aspect需要为"auto"。


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