使用Cartopy绘制动态降水散点图:从数据清洗到可视化实战

使用Cartopy绘制动态降水散点图:从数据清洗到可视化实战 1. 气象数据可视化入门指南第一次接触气象数据可视化时我被那些五彩斑斓的天气图深深吸引。作为地理信息可视化的重要工具Cartopy库在气象领域有着广泛应用。它就像是Python中的魔法画笔能将枯燥的气象站点数据变成直观的动态图表。动态降水散点图特别适合展示区域降水分布变化。想象一下你手上有全国气象站点的降水数据通过Cartopy可以在地图上用不同颜色和大小的圆点表示降水量就像给地图上色一样简单。这种可视化方式比单纯看数字表格直观多了降水多的地方点大色深少的地方点小色浅一眼就能看出降水分布格局。我刚开始学习时最头疼的就是数据清洗环节。气象数据常有缺测值比如用99999表示无效数据。如果不处理这些脏数据画出来的图表就会出现异常点。后来我摸索出一套完整的数据处理流程从读取原始文件到最终可视化每个环节都有需要注意的细节。2. 数据清洗实战技巧2.1 原始数据读取与解析气象数据通常以文本文件形式存储结构可能不太规整。我常用Python的pandas库来读取这类数据。比如下面这段代码可以批量读取某个文件夹下的所有气象数据文件import os import pandas as pd path 气象数据文件夹路径/ files [f for f in os.listdir(path) if f.endswith(.txt)] data_frames [] for file in files: # 跳过文件头部的三行说明文字 df pd.read_csv(pathfile, skiprows3, delimiter , headerNone) df.columns [站名,站号,纬度,经度,高度,温度露点差,气压,温度,相对湿度,大气可降水量] data_frames.append(df)这里有个小技巧气象数据文件前几行往往是说明文字用skiprows参数可以直接跳过。delimiter参数指定分隔符气象数据常用空格分隔但要注意连续多个空格的情况。2.2 缺测值处理与数据转换气象数据中常用特定值表示缺测比如99999。处理这类数据时我习惯先用NaN替换这些特殊值import numpy as np for df in data_frames: df[大气可降水量] df[大气可降水量].replace(99999, np.nan) # 将字符串类型的数字转为float df[经度] df[经度].astype(float) df[纬度] df[纬度].astype(float) df[大气可降水量] df[大气可降水量].astype(float)astype(float)是个很实用的方法它能将字符串数字转为浮点数。但要注意如果数据中包含非数字字符如NaN字符串直接转换会报错需要先处理这些特殊情况。2.3 地理范围筛选技巧实际项目中我们往往只需要特定区域的数据。Cartopy绘图前可以先对数据进行地理范围筛选# 筛选长江三角洲地区的数据 min_lon, max_lon 116.5, 121.5 min_lat, max_lat 31.0, 35.0 filtered_dfs [] for df in data_frames: mask (df[经度] min_lon) (df[经度] max_lon) \ (df[纬度] min_lat) (df[纬度] max_lat) filtered_dfs.append(df.loc[mask])这里有个容易踩的坑Python不支持形如116.5 df[经度] 121.5的链式比较必须拆分成两个条件用连接。而且别忘了加括号因为的优先级高于比较运算符。3. Cartopy绘图核心配置3.1 地图投影与底图设置Cartopy支持多种地图投影对于区域气象图我推荐使用墨卡托投影import cartopy.crs as ccrs import matplotlib.pyplot as plt proj ccrs.Mercator() fig plt.figure(figsize(12, 8)) ax fig.add_subplot(1, 1, 1, projectionproj) # 设置地图范围 ax.set_extent([116.5, 121.5, 31, 35], crsproj)添加地理边界可以增强地图的可读性。我从Natural Earth下载了中国行政区划数据import cartopy.io.shapereader as shpreader reader shpreader.Reader(china_boundary.shp) china reader.geometries() ax.add_geometries(china, proj, facecolornone, edgecolorblack, linewidth1)3.2 散点图参数详解动态降水散点图的关键在于合理配置散点参数。下面这段代码展示了如何用散点大小和颜色同时表示降水量scatter ax.scatter( xdf[经度], ydf[纬度], cdf[大气可降水量], # 颜色映射到降水量 sdf[大气可降水量]*0.5, # 点大小与降水量成正比 cmapviridis, # 颜色映射方案 vmin30, vmax80, # 颜色范围 transformccrs.PlateCarree() # 数据坐标系统 ) # 添加颜色条 cbar plt.colorbar(scatter, axax, orientationvertical, pad0.02) cbar.set_label(大气可降水量 (mm))这里有几个实用技巧s参数控制点的大小我习惯用降水量乘以一个系数避免点过大或过小vmin和vmax固定颜色范围便于不同时次图表的比较transform参数必须指定为PlateCarree因为原始数据是经纬度坐标3.3 动态效果实现要实现动态效果可以创建多个子图展示不同时次的数据fig plt.figure(figsize(18, 12)) proj ccrs.Mercator() for i, df in enumerate(filtered_dfs): ax fig.add_subplot(2, 2, i1, projectionproj) ax.set_extent([116.5, 121.5, 31, 35], crsproj) # 绘制底图 ax.add_geometries(china, proj, facecolornone, edgecolorblack) # 绘制散点 scatter ax.scatter( xdf[经度], ydf[纬度], cdf[大气可降水量], sdf[大气可降水量]*0.5, cmapviridis, vmin30, vmax80, transformccrs.PlateCarree() ) # 添加标题显示时间 ax.set_title(f时间: {times[i]}, fontsize12) plt.tight_layout()4. 高级技巧与常见问题4.1 颜色映射方案选择选择合适的颜色映射(cmap)对图表可读性至关重要。气象领域有一些专用颜色方案import cmaps # 气象专用颜色库 # 降水相关颜色方案 precip_cmaps [ GMT_drywet, # 干湿对比 precip2_17lev, # 降水等级 WhiteBlueGreenYellowRed # 温度降水通用 ] scatter ax.scatter(..., cmapcmaps.GMT_drywet)我常用的经验是连续变化的数据用渐变色分类数据用明显区分色避免使用红绿色组合考虑色盲用户4.2 性能优化技巧当站点数据量很大时绘图可能变慢。我总结了几个优化方法数据层面# 只绘制有效数据点 valid df.dropna(subset[大气可降水量])绘图层面# 使用rasterization栅格化 scatter ax.scatter(..., rasterizedTrue)输出设置# 保存为矢量图时优化 plt.savefig(output.pdf, dpi300, bbox_inchestight)4.3 常见报错解决在Cartopy使用过程中我遇到过几个典型问题投影不匹配错误ValueError: 无法转换坐标解决方法确保scatter的transform参数设置为ccrs.PlateCarree()内存不足错误MemoryError: 无法分配数组解决方法降低输出分辨率或使用栅格化选项字体显示问题中文显示为方框解决方法在绘图前设置中文字体plt.rcParams[font.sans-serif] [SimHei]5. 完整案例实战下面我将展示一个完整的动态降水散点图实现流程。假设我们有四个时次的气象站点数据需要展示降水时空变化。5.1 数据准备阶段import os import numpy as np import pandas as pd import matplotlib.pyplot as plt import cartopy.crs as ccrs import cartopy.io.shapereader as shpreader from datetime import datetime, timedelta # 1. 数据读取函数 def read_weather_data(path): 读取指定路径下的所有气象数据文件 files sorted([f for f in os.listdir(path) if f.endswith(.txt)]) data, times [], [] for file in files: # 从文件名解析时间 time_str file.split(_)[1][:10] dt datetime.strptime(time_str, %Y%m%d%H) times.append(dt timedelta(hours8)) # UTC转北京时间 # 读取数据文件 df pd.read_csv( os.path.join(path, file), skiprows3, delim_whitespaceTrue, headerNone, names[站名,站号,纬度,经度,高度,温度露点差,气压,温度,相对湿度,大气可降水量] ) # 数据清洗 df df.replace(99999, np.nan) for col in [经度,纬度,大气可降水量]: df[col] pd.to_numeric(df[col], errorscoerce) data.append(df) return data, times # 2. 地理范围筛选 def filter_by_region(df, lon_range, lat_range): 按经纬度范围筛选数据 mask (df[经度] lon_range[0]) (df[经度] lon_range[1]) \ (df[纬度] lat_range[0]) (df[纬度] lat_range[1]) return df[mask].copy()5.2 可视化实现阶段# 3. 绘图函数 def plot_precip_scatter(data_list, times, output_file): 绘制多时次降水散点图 # 初始化图形 fig plt.figure(figsize(18, 12)) proj ccrs.Mercator() # 设置地理边界 reader shpreader.Reader(china_boundary.shp) china reader.geometries() # 创建子图 for i, (df, time) in enumerate(zip(data_list, times)): ax fig.add_subplot(2, 2, i1, projectionproj) # 设置地图范围 ax.set_extent([116, 122, 30.5, 35.5], crsproj) ax.add_geometries(china, proj, facecolornone, edgecolorgray) # 绘制散点 scatter ax.scatter( xdf[经度], ydf[纬度], cdf[大气可降水量], sdf[大气可降水量]*0.8, cmapcmaps.GMT_drywet, vmin30, vmax80, alpha0.7, transformccrs.PlateCarree() ) # 添加图饰 ax.set_title(f{time.strftime(%Y-%m-%d %H时)}, fontsize12) gl ax.gridlines(draw_labelsTrue, linestyle--) gl.top_labels False gl.right_labels False # 添加公共颜色条 cbar_ax fig.add_axes([0.92, 0.15, 0.02, 0.7]) fig.colorbar(scatter, caxcbar_ax, label大气可降水量 (mm)) # 调整布局并保存 plt.subplots_adjust(right0.9, wspace0.1, hspace0.2) plt.savefig(output_file, dpi300, bbox_inchestight) plt.close() # 主程序 if __name__ __main__: # 参数设置 data_path 气象数据文件夹路径 output_image 降水时空分布.png lon_range (116.5, 121.5) lat_range (31.0, 35.0) # 数据处理流程 raw_data, times read_weather_data(data_path) filtered_data [filter_by_region(df, lon_range, lat_range) for df in raw_data] # 可视化 plot_precip_scatter(filtered_data, times, output_image)5.3 成果分析与解读运行上述代码后我们将得到一张包含四个子图的降水分布图。每个子图代表不同时间的降水状况通过对比可以直观看出降水高值区的移动路径降水强度的变化趋势降水空间分布特征在实际业务中这种可视化方式可以帮助气象分析师快速识别降水系统的演变过程为天气预报提供直观参考。我在一次强降水过程分析中就曾用类似方法成功捕捉到了一个中尺度对流系统的生消过程。