等压线是怎么画出来的:barometer.today 的绘制算法
barometer.today 展示任意城市的气压:当前读数、24 小时变化、未来一周;还有全球等压线地图,从一天前到四天后逐小时动画。这篇讲等压线是什么、以及作者用的绘制算法——Python + numpy + scipy + contourpy + shapely,任何从网格数据画等值线的人都会遇到同样的问题。
什么是等压线
气压各处不同,天气图用等压线(连接相等气压点的线)表示。线挤在一起 = 气压短距离内变化快 = 风通常强;线散开 = 空气平静。环闭合在高压中心(H)与低压中心(L)周围:紧环深低压是风暴,松环宽高压是稳定天气。
地图上的是海平面气压:丹佛的气压计读 835 hPa 因为它海拔 1600 米,与天气无关——所以读数被换算成海平面值,地图到处可比。
数据与平滑
地图来自 ECMWF 全球预报:每 0.25 度(约 28 km)一个海平面气压网格,全地球。模型时间步长 3 小时,Open-Meteo 插值成小时值。模型每天更新 4 次,每次更新产出一个作业、每帧一小时、共约 120 帧。
平滑:原始网格逐格毛糙,直接从它描线会抖。作者用 sigma=1 格(28 km)的高斯模糊。更宽的模糊线更平滑但会抹平极值:110 km 模糊下,936 hPa 核心的飓风会变成 993 hPa 的温和低压——看起来没错、实际上是错的。
关键技巧:归一化卷积
模糊必须知道山。高原上空的海平面气压是"对不存在空气的计算",通常偏高几 hPa——普通高斯会把虚高值扩散进真实场。喜马拉雅山前缘,这会让低地值移动超过一个等压线间隔。
修法是归一化卷积:把高原格清零后模糊场,用同样方式模糊 0/1 掩码,两者相除——每个输出格只取邻近有效格的加权平均。scipy 两行:
num = gaussian_filter(np.where(valid, z, 0.0), sigma)
den = gaussian_filter(valid.astype(float), sigma)
smoothed = np.where(valid, num / den, z)
同一技巧处理缺失值:单个 null 不再糊成 9×9 的洞,而是不贡献任何东西、保持一格间隙。掩码是海拔 2500 米以上地面,来自数字高程模型、平滑到 55 km(单个山峰不算数)。
实践建议
- 画等值线先做"会伤极值的模糊"测试:大 sigma 平滑后核对极值有没有被吞(飓风变低压就是失败);
- 带无效区/地形边界的场,用归一化卷积而不是裸 Gaussian——否则虚高值会渗进真实场;
- 掩码分辨率要匹配物理尺度:单峰不算数,先平滑到区域尺度再判定。