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

Matplotlib imshow绘制子图导出UV时像素尺寸不统一、缩放不一致问题

统一像素尺度对齐的Matplotlib实现方案

核心问题成因

之前使用均等分1行6列的plt.subplot()布局时,会给每个子图分配完全相等的轴占位区域,完全不匹配每个图像的原始分辨率宽高比,自然会出现拉伸变形、非正方形像素、视觉尺寸不匹配的问题;手动调整aspect、extent、figsize的方式只是凑比例,无法做到跨子图的单个像素物理尺度1:1对齐。

实现步骤

  • 全局定义统一的单像素物理尺度,保证所有子图的单个像素对应相同的物理长度,从根源上避免像素拉伸
  • 放弃均等分的自动subplot布局,使用fig.add_axes()手动定义每个子图的轴位置、宽高参数,严格匹配每个图像的原始分辨率对应的物理尺寸,垂直方向对短高度的图像做居中对齐
  • 所有imshow调用统一设置aspect='equal',强制轴范围匹配图像真实宽高比,关闭所有坐标轴

可直接复用的代码

import matplotlib.pyplot as plt

# 定义全局参数:单像素对应物理尺寸(英寸)
s = 0.1
# 各图像原始分辨率对应的物理宽高(英寸)
w1, h1 = 160 * s, 100 * s  # front、back 160x100
w2, h2 = 100 * s, 45 * s   # left、right 100x45
w3, h3 = 160 * s, 45 * s   # top、bottom 160x45
gap = 0.2  # 子图水平间距(英寸)

# 计算总画布尺寸
total_w = w1*2 + w2*2 + w3*2 + gap*5
total_h = h1
fig = plt.figure(figsize=(total_w, total_h), dpi=100)

# 手动定义每个子图的归一化位置 [left, bottom, width, height]
ax1 = fig.add_axes([0, 0, w1/total_w, h1/total_h])  # front
ax2 = fig.add_axes([(w1 + gap)/total_w, 0, w1/total_w, h1/total_h])  # back
ax3 = fig.add_axes([(w1*2 + gap*2)/total_w, (total_h - h2)/(2*total_h), w2/total_w, h2/total_h])  # left
ax4 = fig.add_axes([(w1*2 + w2 + gap*3)/total_w, (total_h - h2)/(2*total_h), w2/total_w, h2/total_h])  # right
ax5 = fig.add_axes([(w1*2 + w2*2 + gap*4)/total_w, (total_h - h2)/(2*total_h), w3/total_w, h2/total_h])  # top
ax6 = fig.add_axes([(w1*2 + w2*2 + w3 + gap*5)/total_w, (total_h - h2)/(2*total_h), w3/total_w, h2/total_h])  # bottom

# 绘制图像,统一设置等比例无拉伸
for ax, img in zip([ax1, ax2, ax3, ax4, ax5, ax6], [front, back, left, right, top, bottom]):
    ax.imshow(img, aspect='equal')
    ax.axis('off')

plt.savefig(f"{directory}{num}.png", dpi=100, bbox_inches=None, pad_inches=0)
plt.close()

PIL兼容NaN值的处理方案

PIL本身不直接识别浮点NaN值,但可以通过RGBA通道映射的方式,全程不将NaN转换为0值完成图像处理:

  • 先计算数据中非NaN区域的数值上下限,作为彩色映射的归一化范围
  • 单独创建Alpha通道,将原始数据中NaN对应的位置标记为透明(Alpha值0),非NaN位置标记为不透明(Alpha值255)
  • 将彩色映射后的RGB数组与Alpha通道拼接为RGBA格式的uint8数组,即可直接传入PIL保存,透明区域会在PNG导出时正确保留,不会强制将NaN位置填充为0值

对应代码片段

import numpy as np
from PIL import Image

# 假设data是含NaN的气象数组
valid_mask = ~np.isnan(data)
dmin, dmax = data[valid_mask].min(), data[valid_mask].max()
# 归一化到0-255范围
norm_data = 255 * (data - dmin) / (dmax - dmin)
# 生成Alpha通道:NaN位置透明,其余不透明
alpha = np.where(valid_mask, 255, 0).astype(np.uint8)
# 拼接为RGBA图像(可根据需求替换为自定义colormap生成的RGB三通道)
rgba = np.stack([norm_data.astype(np.uint8)]*3 + [alpha], axis=-1)
img = Image.fromarray(rgba, mode='RGBA')
img.save("output.png")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.27 04:15:02