You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Matplotlib多子图热力图固定位置添加黑色方块标记及文本方法

问题根源

代码中补丁和文本无法正常显示,核心是以下几个问题:

  • 坐标体系不匹配:给imshow传入extent参数后,坐标轴范围被设置为百万级的真实地理坐标,但添加矩形、文本时用的是0~149的网格索引坐标,二者差了6个数量级,元素直接跑到可视范围外
  • 子图对象调用错误:循环里用plt.gca()获取子图,该方法只会返回最后一个激活的子图,不是当前遍历到的子图,就算坐标正确,元素也只会出现在最后一个子图上
  • 矩形参数错误:需要覆盖x、y方向60~64共4个网格单元,但传入的矩形宽高为3,且Rectangle第一个参数为左下角坐标,原参数计算出的覆盖范围不符合预期
  • 文本添加逻辑错误:写了两次文本添加代码,第一次错把网格的数值当坐标传入,第二次错误把text对象当成patch传给add_patch,根本不会生效;另外黑方块配黑字就算显示出来也无法识别
  • 语法问题:用Python关键字property当变量名,且layer、reservoir_property两个变量未定义,运行会直接报错
修复后完整代码
from matplotlib.patches import Rectangle
import numpy as np
import matplotlib.pyplot as plt
import os
import matplotlib.colors as mcolors

# 模拟数据
data = np.random.rand(10, 150, 150)
data = data.reshape(-1, 1)

# 修改变量名避免关键字冲突
reservoir_property = "Sale"
layer = 1

pmin = data.min()
pmax = data.max()

v = np.linspace(round(pmin,3), round(pmax,3),15, endpoint=True)
v = [round(x,3) for x in v] 

# 原figsize(160,80)过大,测试时可缩小,需要出大图可改回原值
fig, ax = plt.subplots(2, 5, figsize=(16, 8))
row_count = 0
col_count = 0

# 地理边界参数
xmin = 1258096.6
xmax = 1291155.0
ymin = 11251941.6
ymax = 11285000.0
grid_num = 150
# 计算单个网格对应的地理坐标长度
x_grid_step = (xmax - xmin) / grid_num
y_grid_step = (ymax - ymin) / grid_num
# 计算标记方块的地理坐标:左下角(60,60)网格对应位置,宽高对应4个网格
rect_x0 = xmin + 60 * x_grid_step
rect_y0 = ymin + 60 * y_grid_step
rect_w = 4 * x_grid_step
rect_h = 4 * y_grid_step
# 计算文本中心位置:(62,62)网格对应坐标
text_x = xmin + 62 * x_grid_step
text_y = ymin + 62 * y_grid_step

for i in range(10):
    sub_plot_data = data[(i)*(150*150):(i+1)*150*150]
    pmin_sub = sub_plot_data.min()
    pmax_sub = sub_plot_data.max() 

    # 定义离散色条
    bounds = np.linspace(-1, 1, 10)
    Discrete_colors = plt.get_cmap('jet')(np.linspace(0,1,len(bounds)+1))
    cmap = mcolors.ListedColormap(Discrete_colors[1:-1]) 

    actual_2d = np.reshape(sub_plot_data,(grid_num,grid_num)) 
    current_ax = ax[row_count, col_count]
    # 加origin='lower'让y轴方向和网格索引一致,若数据y轴从上到下递增可删除该参数,同时调整y坐标计算逻辑即可
    im1 = current_ax.imshow(actual_2d, interpolation=None, cmap=cmap, 
        extent=(xmin, xmax, ymin, ymax), vmin=pmin_sub, vmax=pmax_sub, origin='lower')
    
    # 直接给当前子图加黑色方块
    current_ax.add_patch(Rectangle((rect_x0, rect_y0), rect_w, rect_h, 
        edgecolor='black', facecolor='black', fill=True, lw=2))
    # 加白色文本,黑底白字保证可见,原fontsize=90对应超大figsize,小尺寸下对应调整即可
    current_ax.text(text_x, text_y, 'Sale 1', 
        horizontalalignment='center', verticalalignment='center', 
        color='white', fontsize=12)

    current_ax.set_title("Sale_Stores-%s - L: %s"%(i+1, layer), 
        fontsize=13, pad=4, x=0.5, y=0.999)
    current_ax.set_aspect('auto')
    current_ax.tick_params(left=False, labelleft=False, top=False, 
        labeltop=False, right=False, labelright=False, bottom=False, labelbottom=False)

    col_count +=1
    if col_count == 5:
        row_count +=1  
        col_count =0

fig.tight_layout(h_pad=1) 
plt.subplots_adjust(left=0.02,
                bottom=0.1, 
                right=0.91, 
                top=0.8, 
                wspace=0.1, 
                hspace=0.2)

cbaxes = fig.add_axes([0.94, 0.05, 0.02, 0.8]) 
cbar = fig.colorbar(im1, ax=ax.ravel().tolist(), ticks=v, extend='both', cax=cbaxes)
cbar.ax.tick_params(labelsize=7) 
cbar.ax.set_yticklabels([i for i in v], fontsize=12)

# 保存部分
output_dir = r"D/test"
plot_dir = os.path.join(output_dir, reservoir_property)
if not os.path.exists(plot_dir):
    os.makedirs(plot_dir)
fig.savefig(r"%s/per_allmodel.png"%(plot_dir))
关键修改说明
  • 所有绘图元素直接绑定当前循环拿到的子图对象current_ax,不再使用plt.gca(),确保10个子图都能正常添加标记
  • 提前将网格索引位置换算成和extent一致的地理坐标,彻底解决坐标不匹配问题;如果不需要显示地理坐标,直接删掉imshow里的extent参数,矩形和文本直接用网格索引坐标即可,无需换算
  • 修正矩形尺寸:4个网格长度对应宽高4,刚好覆盖60~64的范围
  • 去掉重复、错误的文本代码,文本颜色改为白色,保证黑块上文字可见
  • 清理重复导入的冗余库,补上未定义变量,重命名占用关键字的变量,修复运行报错问题

内容的提问来源于stack exchange,提问作者bluered_earth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 13:21:21