Matplotlib:如何让 imshow 从其他 numpy 数组读取 x、y 坐标?
Matplotlib: how to make imshow read x,y coordinates from other numpy arrays?
当你想用 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)
这给了我们这个简单的图像:
在这张图片中,x 和 y 坐标只是从数组中每个值的位置中提取出来的。现在,假设 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_x 和 real_y,但是对于 读取 这些值来自 real_x 和 real_y 数组。预期的结果是 x 轴上具有 real_x 值且 real_y 值在 x 轴上的图像y 轴。
设置范围
假设你有
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)
如果我没理解错的话,这是关于为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
的东西应该不是问题
对于 extent 方法,要使其工作,imshow() 的参数方面需要 "auto"。
这里是一个如何将 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"])
当你想用 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)
这给了我们这个简单的图像:
在这张图片中,x 和 y 坐标只是从数组中每个值的位置中提取出来的。现在,假设 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_x 和 real_y,但是对于 读取 这些值来自 real_x 和 real_y 数组。预期的结果是 x 轴上具有 real_x 值且 real_y 值在 x 轴上的图像y 轴。
设置范围
假设你有
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)
如果我没理解错的话,这是关于为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
的东西应该不是问题对于 extent 方法,要使其工作,imshow() 的参数方面需要 "auto"。
这里是一个如何将 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"])