如何用Matplotlib imshow绘制x范围逐行变化的棋盘格图?
用imshow绘制每行X范围不同的棋盘格图?
当然可以实现,但直接在循环里修改imshow的extent参数确实行不通——因为imshow的extent是作用于整个图像的全局参数,不是用来单独控制每一行的。你最后一次设置的extent会覆盖之前所有的配置,所以所有行都会被偏移到最后那个extent对应的位置。
那该怎么解决呢?这里有两种靠谱的方法:
方法1:用pcolormesh(推荐)
pcolormesh天生支持非均匀的坐标网格,它可以接受每行不同的X坐标,完美适配你的场景。下面是一个完整的示例:
首先模拟你的数据结构(你可以替换成自己的真实数据):
import matplotlib.pyplot as plt import numpy as np # 模拟你的Y值和对应的X范围 y_values = [0, 1, 2] # 每个Y对应的40个X值(这里用linspace模拟,你可以换成自己的真实数据) x_arrays = [ np.linspace(20, 55, 40), # Y=0的X值 np.linspace(24, 49, 40), # Y=1的X值 np.linspace(23, 59, 40) # Y=2的X值 ] # 模拟每个(X,Y)对应的数值(这里用随机数,你替换成自己的数据) data = np.random.rand(len(y_values), 40)
然后用pcolormesh绘制每行的棋盘格:
fig, ax = plt.subplots(figsize=(10, 6)) for y_idx, y in enumerate(y_values): x = x_arrays[y_idx] # 计算X方向的单元格边缘(每个X点是单元格的中心,边缘取相邻中心的中点) x_edges = np.concatenate([ [x[0] - (x[1]-x[0])/2], # 第一个单元格的左边缘 (x[1:] + x[:-1])/2, # 中间单元格的边缘 [x[-1] + (x[-1]-x[-2])/2] # 最后一个单元格的右边缘 ]) # Y方向的边缘:当前Y行的上下边界(比如Y=0对应-0.5到0.5) y_edges = [y - 0.5, y + 0.5] # 生成网格坐标 X_grid, Y_grid = np.meshgrid(x_edges, y_edges) # 将当前行的数据转为2D格式(pcolormesh需要二维输入) row_data = data[y_idx][np.newaxis, :] # 绘制这一行的棋盘格,加上白色边框区分单元格 ax.pcolormesh(X_grid, Y_grid, row_data, edgecolor='white', linewidth=0.5, cmap='viridis') # 设置坐标轴范围和标签 ax.set_ylim(-0.5, max(y_values)+0.5) ax.set_xlabel('X Coordinate') ax.set_ylabel('Y Coordinate') ax.set_title('Non-uniform X Rows Grid') plt.colorbar(ax.collections[0], ax=ax, label='Value') plt.show()
方法2:手动绘制矩形(更灵活)
如果你的X间隔完全没有规律(甚至不是均匀间隔),可以用matplotlib.patches.Rectangle逐个绘制每个单元格,这种方式自由度最高:
fig, ax = plt.subplots(figsize=(10, 6)) cmap = plt.cm.viridis for y_idx, y in enumerate(y_values): x = x_arrays[y_idx] row_vals = data[y_idx] # 计算每个单元格的宽度和左边界 if len(x) > 1: widths = np.diff(x) # 第一个单元格的左边界 = 第一个X值 - 第一个宽度的一半 lefts = np.concatenate([[x[0] - widths[0]/2], x[:-1] + widths/2]) else: # 处理只有一个X值的特殊情况 widths = [1] lefts = [x[0] - 0.5] # Y方向的底部坐标和单元格高度 y_bottom = y - 0.5 cell_height = 1 # 逐个绘制单元格 for left, width, val in zip(lefts, widths, row_vals): # 根据数值获取颜色 color = cmap(val / data.max()) # 创建矩形并添加到坐标轴 rect = plt.Rectangle((left, y_bottom), width, cell_height, facecolor=color, edgecolor='white') ax.add_patch(rect) # 设置坐标轴范围 min_x = min([min(x) - (x[1]-x[0])/2 for x in x_arrays]) max_x = max([max(x) + (x[-1]-x[-2])/2 for x in x_arrays]) ax.set_xlim(min_x, max_x) ax.set_ylim(-0.5, max(y_values)+0.5) # 添加颜色条和标签 sm = plt.cm.ScalarMappable(cmap=cmap, norm=plt.Normalize(vmin=data.min(), vmax=data.max())) sm.set_array([]) plt.colorbar(sm, ax=ax, label='Value') ax.set_xlabel('X Coordinate') ax.set_ylabel('Y Coordinate') ax.set_title('Manual Rectangle Grid for Non-uniform X') plt.show()
为什么imshow不行?
再补充解释一下:imshow是为规则网格数据设计的,它默认假设每行的X范围是完全一致的,只是通过extent把整个数据块映射到坐标轴上。它没有单独控制每行X范围的能力,所以你循环修改extent只会不断覆盖全局设置,导致所有行都对齐到最后一次的extent。
所以针对你的非均匀X行场景,pcolormesh或者手动绘制矩形才是正确的选择~
内容的提问来源于stack exchange,提问作者Anonymous
相关产品推荐
相关产品推荐

