matplotlib子图标记连通域最大值异常问题求助
问题:Matplotlib 4×4子图散点全部集中在最后一张图
原代码与问题现象
plt.show()

完整原代码:
CC = [] fig, ax = plt.subplots(4,4,figsize=(8,8)) tau = 130 for n,img in enumerate(ls2): sel = img <= tau img[sel] = 0 visited = img==0.0 i_1 = n % 4 j_1 = n//4 if i_1<4 and j_1<4: img = ls2[i_1+ax.shape[0]*j_1] ax[i_1,j_1].imshow(img,cmap='gray') for i in range(img.shape[0]): for j in range(img.shape[1]): if visited[i,j]: continue # 跳过已访问像素 ## 对于灰度图像,此处应为 img[i,j,0] todo = set() todo.add((i,j)) visited[i,j]=True # 在(i,j)处添加新的连通分量,初始最大值为0 CC.append( (i,j,img[i,j]) ) # 内层循环:遍历邻域 while len(todo)>0: r,c = todo.pop() # 从集合中取出一个元素 # 计算邻域的有效范围(图像边界) rl, rr = max(0,r-1), min(img.shape[0],r+2) cl, cr = max(0,c-1), min(img.shape[1],c+2) for this_row in range(rl,rr): for this_col in range(cl,cr): if visited[this_row,this_col]: continue todo.add((this_row,this_col)) visited[this_row,this_col]=True if img[this_row,this_col]>CC[-1][2]: # 找到新的最大值 CC[-1] = (this_row,this_col,img[this_row,this_col]) x = [r for r,c,val in CC] y = [c for r,c,val in CC] vals = [val for r,c,val in CC] plt.scatter(y,x) plt.show()
用户求助描述
我使用matplotlib创建4×4子图,意图在每张子图的图像中识别连通域的最大值(白色斑点)并标记散点,但所有标记点均集中显示在最后一张子图上。尝试将以下散点绘制代码缩进至循环内部仍未解决问题,恳请帮忙排查:
x = [r for r,c,val in CC] y = [c for r,c,val in CC] vals = [val for r,c,val in CC] plt.scatter(y,x)
问题原因
- 未指定子图绘制对象:
plt.scatter()默认在当前活动子图绘制,循环中未切换子图上下文,所有点最终都会画到最后一个活动子图。 - 全局列表未重置:
CC是全局变量,每次循环会累积所有子图的标记点,即使缩进散点代码,也会把之前所有点重复画到当前子图。 - 子图索引逻辑混乱:原代码中
i_1 = n%4、j_1 = n//4,后续又通过i_1+ax.shape[0]*j_1重新获取图像,导致图像遍历顺序混乱,可能重复处理同一图像。
修正后的代码
fig, ax = plt.subplots(4,4,figsize=(8,8)) tau = 130 for n, img in enumerate(ls2): # 每次处理新图像时重置连通分量列表 CC = [] # 阈值化处理图像 sel = img <= tau img[sel] = 0 visited = img == 0.0 # 计算当前子图的行列索引(行优先排列) row = n // 4 col = n % 4 # 超出4x4范围则跳过 if row >=4 or col >=4: continue # 获取当前子图对象并显示图像 current_ax = ax[row, col] current_ax.imshow(img, cmap='gray') # 遍历像素查找连通域最大值 for i in range(img.shape[0]): for j in range(img.shape[1]): if visited[i,j]: continue todo = set() todo.add((i,j)) visited[i,j] = True # 初始化当前连通域的最大值点 max_point = (i,j,img[i,j]) while len(todo) >0: r,c = todo.pop() # 计算邻域有效范围 rl, rr = max(0,r-1), min(img.shape[0], r+2) cl, cr = max(0,c-1), min(img.shape[1], c+2) for this_row in range(rl, rr): for this_col in range(cl, cr): if visited[this_row, this_col]: continue todo.add((this_row, this_col)) visited[this_row, this_col] = True # 更新连通域最大值点 if img[this_row, this_col] > max_point[2]: max_point = (this_row, this_col, img[this_row, this_col]) # 将当前连通域最大值点加入列表 CC.append(max_point) # 在当前子图绘制散点,指定颜色方便区分 x = [r for r,c,val in CC] y = [c for r,c,val in CC] current_ax.scatter(y, x, color='red', s=20) # 调整子图间距避免重叠 plt.tight_layout() plt.show()
修正说明
- 将
CC移至循环内部,每次处理新图像时清空,避免累积历史点。 - 使用
current_ax = ax[row, col]明确指定子图对象,通过current_ax.scatter()将点绘制到对应子图。 - 修正子图索引逻辑,采用行优先的
row = n//4、col = n%4,确保图像与子图一一对应。 - 优化连通域最大值的存储逻辑,用
max_point变量单独记录当前连通域的最大值点,代码更简洁。 - 添加
plt.tight_layout()自动调整子图间距,避免图像重叠。
内容的提问来源于stack exchange,提问作者fogwoodandfig
相关产品推荐
相关产品推荐

