【问题标题】:Matplotlib: how to make imshow read x,y coordinates from other numpy arrays?Matplotlib:如何让 imshow 从其他 numpy 数组中读取 x,y 坐标?
【发布时间】:2017-10-30 19:48:32
【问题描述】:

当你想用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 值的图像。

【问题讨论】:

  • 什么意思?在这种情况下,强度是虚构的 - 它们可以是任何东西。
  • 不,我不是在寻找产生散点图的东西。我专注于光栅图像(numpy 数组)。
  • 你能分享一张图片应该是什么样子吗?或者根据你的两个数组解释它应该如何“产生”(不一定是代码,只是一些解释)。
  • 如果我理解正确,您只有 3 个不同的 x (15, 16, 17) 和 3 个不同的 y (20, 21, 22) 坐标,但图像为 3x4 像素。这究竟应该如何运作?

标签: python numpy matplotlib imshow


【解决方案1】:

设置范围

假设你有

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)

【讨论】:

  • 如果real_xreal_y 是固定宽度单调递增,那么extent 方法才有效。我假设这个问题是关于更通用的方法。
  • Imshow 图假设单调 1 像素比例,是的。其他一切都会使秤过时。因此,如果像素之间的差异在轴范围内不同,则需要更改刻度标签。我还添加了一个仅设置刻度标签的解决方案。
【解决方案2】:

如果我理解正确,这是关于为 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) 

请注意,由于 np.unique() 中的排序,因此 deduce_raster_params() 在 O(n*log(n)) 而不是 O(n) 中工作 - 这简化了代码并且可能不应该成为问题发送到imshow

【讨论】:

    【解决方案3】:

    对于 extent 方法,要使其工作,imshow() 的参数方面需要是“auto”。

    【讨论】:

      【解决方案4】:

      这是一个如何将 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"])
      

      【讨论】:

        猜你喜欢
        • 2019-05-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-13
        • 1970-01-01
        相关资源
        最近更新 更多