Python气象数据可视化:用Cartopy+frykit绘制中国AQI分布图(附完整代码)

Python气象数据可视化实战:从散点到专业地图的完整工作流

最近在分析全国空气质量数据时,我遇到了一个典型问题:如何将338个城市的AQI监测点数据,转化为一张既专业又美观的全国分布图?这不仅仅是简单的散点图绘制,而是涉及地理坐标转换、空间插值、地图投影、边界裁剪等一系列复杂操作。经过几周的摸索和实践,我总结出了一套基于Cartopy和frykit的高效解决方案,今天就来分享这个完整的工作流程。

如果你也经常需要处理气象、环境或地理空间数据,这篇文章将为你提供一个可以直接复用的代码框架。不同于简单的教程,我会深入讲解每个环节的技术细节和实际应用中可能遇到的坑,特别是如何处理中国地图的特殊需求。

1. 环境配置与工具选择:为什么是Cartopy+frykit组合?

在Python地理可视化领域,有几个主流选择:Basemap(已停止维护)、GeoPandas、Plotly,以及我们今天要重点介绍的Cartopy。Cartopy由英国气象局开发,专门为科学数据可视化设计,与Matplotlib无缝集成,支持多种地图投影和地理特征。

但Cartopy有个“小问题”——它自带的全球地图数据在某些区域边界上不够精确。这就是为什么我们需要frykit这个国产工具包。frykit专门针对中国地图优化,提供了准确的国界、省界数据,以及九段线等必要元素,还能大幅提升绘制速度。

1.1 环境搭建:一步到位的配置方案

我强烈推荐使用Conda进行环境管理,特别是处理地理空间数据时,依赖库的版本兼容性是个大问题。下面是我的标准配置流程:

# 创建专用环境
conda create -n geo_viz python=3.9 -y
conda activate geo_viz

# 核心地理可视化库
conda install -c conda-forge cartopy -y

# 数据处理与分析基础包
conda install numpy pandas xarray scipy -y

# 插值算法库(克里金插值)
conda install -c conda-forge pykrige -y

# 中国地图专用工具包
pip install frykit

# 可选但推荐的辅助工具
pip install openpyxl  # 处理Excel数据
pip install cnmaps    # 另一个中国地图工具,作为备选

注意:如果你之前尝试过从源码编译安装Cartopy,可能会遇到Proj、GEOS等C++库的依赖问题。Conda-forge渠道已经帮你解决了所有底层依赖,这是最省心的方式。

1.2 工具对比:为什么选择这个技术栈?

为了让你更清楚这个技术组合的优势,我整理了一个对比表格:

工具/库 主要用途 优势 局限性
Cartopy 地理投影与基础地图绘制 专业气象级精度,投影系统完善 中国边界数据不完整
frykit 中国地图优化 准确的国界省界,绘制速度快 功能相对专一
PyKrige 空间插值 多种克里金算法,适合气象数据 大数据集时计算较慢
GeoPandas 地理数据处理 与pandas完美结合,操作方便 地图绘制功能相对简单
Basemap 传统地图绘制 功能成熟,文档丰富 已停止维护

这个组合的核心思路是:用Cartopy处理地理投影和基础地图,用frykit补充中国特定的地理要素,用PyKrige进行空间插值,形成一个完整的工作流。

2. 数据准备与预处理:从原始数据到可插值格式

在实际项目中,数据往往来自不同的监测站、不同的格式。我最近处理的一个典型数据集包含338个城市的AQI(空气质量指数)小时数据,存储格式是Excel,结构如下:

城市 经度 纬度 AQI PM2.5 PM10 时间戳
北京 116.4074 39.9042 85 45 78 2024-05-02 10:00
上海 121.4737 31.2304 72 38 65 2024-05-02 10:00
... ... ... ... ... ... ...

2.1 数据读取与质量检查

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 读取数据
df = pd.read_excel('./data/aqi_20240502_1000.xlsx')

# 基础数据检查
print(f"数据形状: {df.shape}")
print(f"城市数量: {df['城市'].nunique()}")
print(f"数据时间范围: {df['时间戳'].min()} 到 {df['时间戳'].max()}")

# 检查缺失值
missing_values = df.isnull().sum()
print("缺失值统计:")
print(missing_values[missing_values > 0])

# 数据分布概览
print("\nAQI统计描述:")
print(df['AQI'].describe())

# 异常值检测(基于3σ原则)
mean_aqi = df['AQI'].mean()
std_aqi = df['AQI'].std()
outliers = df[(df['AQI'] < mean_aqi - 3*std_aqi) | (df['AQI'] > mean_aqi + 3*std_aqi)]
print(f"\n异常值数量: {len(outliers)}")

数据质量是可视化准确性的基础。我通常会进行以下几个检查:

  • 完整性检查:确保所有必要字段都有值
  • 范围验证:经度应在73°E-135°E,纬度应在3°N-54°N之间
  • 一致性检查:同一城市不同时间的坐标是否一致

2.2 空间分布初步探索

在投入复杂的地图绘制前,先用简单的散点图了解数据分布特征:

def plot_aqi_scatter(df, save_path='./output/aqi_scatter.png'):
    """
    绘制AQI空间分布散点图
    """
    plt.figure(figsize=(12, 8))
    
    # 创建颜色映射
    norm = plt.Normalize(df['AQI'].min(), df['AQI'].max())
    cmap = plt.cm.viridis
    
    # 绘制散点
    scatter = plt.scatter(
        df['经度'], 
        df['纬度'], 
        c=df['AQI'], 
        cmap=cmap,
        norm=norm,
        s=50,           # 点大小
        alpha=0.7,      # 透明度
        edgecolors='w',  # 边缘颜色
        linewidths=0.5   # 边缘线宽
    )
    
    # 添加颜色条
    cbar = plt.colorbar(scatter, shrink=0.8)
    cbar.set_label('AQI指数', fontsize=12)
    
    # 设置图形属性
    plt.xlabel('经度 (°E)', fontsize=12)
    plt.ylabel('纬度 (°N)', fontsize=12)
    plt.title('全国338城市AQI分布散点图', fontsize=14, fontweight='bold')
    plt.grid(True, alpha=0.3, linestyle='--')
    
    # 添加中国大致范围框
    plt.axvline(x=73, color='gray', linestyle='--', alpha=0.5)
    plt.axvline(x=135, color='gray', linestyle='--', alpha=0.5)
    plt.axhline(y=3, color='gray', linestyle='--', alpha=0.5)
    plt.axhline(y=54, color='gray', linestyle='--', alpha=0.5)
    
    plt.tight_layout()
    plt.savefig(save_path, dpi=300, bbox_inches='tight')
    plt.show()
    
    return scatter

# 执行绘制
scatter_plot = plot_aqi_scatter(df)

这个散点图虽然简单,但能快速揭示几个关键信息:

  1. 数据密度:东部地区监测点明显更密集
  2. 异常值:是否有明显偏离主要分布区的点
  3. 空间趋势:是否呈现东高西低或南高北低的趋势

3. 克里金插值:从离散点到连续场

散点图只能显示监测点的位置和数值,但我们需要的是全国范围的连续分布图。这就是空间插值的用武之地。在气象和环境领域,克里金(Kriging)插值是最常用的方法之一,因为它能考虑空间自相关性。

3.1 克里金插值原理与参数选择

克里金插值基于地统计学,基本假设是空间上接近的点比远离的点更相似。它不仅要估计未知点的值,还要给出估计的方差(不确定性)。

from pykrige.ok import OrdinaryKriging
import numpy as np

def perform_kriging(df, grid_resolution=0.5):
    """
    执行普通克里金插值
    
    参数:
    df: 包含经度、纬度、AQI的DataFrame
    grid_resolution: 网格分辨率(度)
    
    返回:
    grid_lon: 网格经度
    grid_lat: 网格纬度  
    grid_aqi: 插值后的AQI网格
    """
    
    # 提取数据
    lon = df['经度'].values
    lat = df['纬度'].values
    aqi = df['AQI'].values
    
    # 定义插值网格范围(覆盖中国全境)
    lon_min, lon_max = 73, 135
    lat_min, lat_max = 3, 54
    
    # 创建网格
    grid_lon = np.arange(lon_min, lon_max + grid_resolution, grid_resolution)
    grid_lat = np.arange(lat_min, lat_max + grid_resolution, grid_resolution)
    
    print(f"网格尺寸: {len(grid_lon)} × {len(grid_lat)} = {len(grid_lon)*len(grid_lat)}个格点")
    print(f"经度范围: {grid_lon[0]:.2f}°E 到 {grid_lon[-1]:.2f}°E")
    print(f"纬度范围: {grid_lat[0]:.2f}°N 到 {grid_lat[-1]:.2f}°N")
    
    # 选择变差函数模型
    # linear: 线性模型,适合趋势明显的数据
    # gaussian: 高斯模型,适合平滑变化的数据
    # exponential: 指数模型,通用性较好
    # spherical: 球状模型,地质学常用
    
    variogram_model = 'exponential'  # 根据数据特性选择
    
    # 执行克里金插值
    print("开始克里金插值计算...")
    OK = OrdinaryKriging(
        lon, lat, aqi,
        variogram_model=variogram_model,
        verbose=True,      # 显示计算过程
        enable_plotting=False,  # 不显示变差函数图
        coordinates_type='geographic'  # 指定为地理坐标
    )
    
    # 生成网格数据
    grid_aqi, ss = OK.execute('grid', grid_lon, grid_lat)
    
    print(f"插值完成,AQI范围: {grid_aqi.min():.1f} - {grid_aqi.max():.1f}")
    
    # 创建网格坐标矩阵
    grid_lon_mesh, grid_lat_mesh = np.meshgrid(grid_lon, grid_lat)
    
    return grid_lon_mesh, grid_lat_mesh, grid_aqi

# 执行插值
grid_lon, grid_lat, grid_aqi = perform_kriging(df, grid_resolution=0.5)

3.2 插值结果的质量评估

插值完成后,我们需要评估结果的质量。一个简单的方法是交叉验证:

def cross_validate_kriging(df, test_ratio=0.2):
    """
    交叉验证克里金插值精度
    """
    from sklearn.model_selection import train_test_split
    from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
    
    # 划分训练集和测试集
    train_df, test_df = train_test_split(
        df, test_size=test_ratio, random_state=42
    )
    
    print(f"训练集: {len(train_df)}个点,测试集: {len(test_df)}个点")
    
    # 用训练集训练克里金模型
    OK = OrdinaryKriging(
        train_df['经度'].values,
        train_df['纬度'].values,
        train_df['AQI'].values,
        variogram_model='exponential',
        verbose=False
    )
    
    # 在测试集位置进行预测
    pred_aqi, pred_var = OK.execute(
        'points',
        test_df['经度'].values,
        test_df['纬度'].values
    )
    
    # 计算评估指标
    mse = mean_squared_error(test_df['AQI'].values, pred_aqi)
    mae = mean_absolute_error(test_df['AQI'].values, pred_aqi)
    r2 = r2_score(test_df['AQI'].values, pred_aqi)
    
    print("\n交叉验证结果:")
    print(f"均方误差 (MSE): {mse:.2f}")
    print(f"平均绝对误差 (MAE): {mae:.2f}")
    print(f"决定系数 (R²): {r2:.3f}")
    
    # 可视化预测 vs 实际
    plt.figure(figsize=(8, 6))
    plt.scatter(test_df['AQI'].values, pred_aqi, alpha=0.6)
    plt.plot([0, 300], [0, 300], 'r--', label='理想线')
    plt.xlabel('实际AQI')
    plt.ylabel('预测AQI')
    plt.title('克里金插值交叉验证')
    plt.legend()
    plt.grid(True, alpha=0.3)
    plt.tight_layout()
    plt.savefig('./output/kriging_cv.png', dpi=300)
    plt.show()
    
    return mse, mae, r2

# 执行交叉验证
metrics = cross_validate_kriging(df)

4. 地图绘制核心:Cartopy与frykit的深度集成

有了插值数据,现在进入最核心的部分——地图绘制。这里我会详细介绍如何将Cartopy的基础功能与frykit的中国地图优化结合起来。

4.1 基础地图框架搭建

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import frykit.plot as fplt
import frykit.shp as fshp
import numpy as np

def create_china_map_base(figsize=(12, 10), dpi=150):
    """
    创建中国地图基础框架
    
    返回:
    fig: 图形对象
    ax_main: 主地图坐标轴
    ax_south_china_sea: 南海小图坐标轴
    """
    
    # 设置中文字体(根据系统调整)
    plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans']
    plt.rcParams['axes.unicode_minus'] = False
    
    # 创建图形和主地图
    fig = plt.figure(figsize=figsize, dpi=dpi)
    
    # 选择投影 - 兰勃特等角圆锥投影,适合中国区域
    map_crs = ccrs.LambertConformal(
        central_longitude=105,      # 中央经线
        standard_parallels=(25, 47) # 标准纬线
    )
    
    # 数据坐标系统(经纬度)
    data_crs = ccrs.PlateCarree()
    
    # 主地图范围(中国主要区域)
    main_extent = [73, 136, 3, 54]  # 东经73-136°,北纬3-54°
    
    # 创建主地图
    ax_main = fig.add_subplot(1, 1, 1, projection=map_crs)
    ax_main.set_extent(
内容概要:本文提出了一种基于改进扩散模型的高海拔地区新能源高波动出力场景生成方法,并提供了完整Python代码实现。该方法针对高海拔地区风能、光伏等新能源出力波动剧烈、不确定性高的特点,通过优化扩散模型的结构与训练策略,有效捕捉历史数据的概率分布特征与时序相关性,从而生成高质量、多样化的出力场景。文中详细阐述了模型的数学推导、网络架构设计、损失函数优化及采样算法改进,并通过实验证明其在拟合精度、场景多样性与稳定性方面优于传统生成模型,为电力系统在高比例新能源接入下的规划、调度与风险评估提供了可靠的场景输入支持。; 适合人群:具备一定Python编程能力和机器学习基础,从事新能源发电预测、电力系统分析、智能优化、场景生成等方向研究的科研人员、高校研究生及工程技术人员。; 使用场景及目标:①用于高海拔地区风电、光伏出力的不确定性建模与多场景生成;②支撑含高渗透率新能源的电力系统随机优化调度、鲁棒决策与风险评估;③为相关学术研究、论文复现与算法改进提供可运行的技术方案与代码基础; 阅读建议:建议读者结合所提供的完整资源(代码、数据集、说明文档)进行实践操作,重点关注扩散模型的前向加噪与反向去噪过程的设计细节,以及如何将其适配于新能源时序数据的生成任务,通过参数调优与对比实验深入理解模型的生成机制与性能边界。
内容概要:本文围绕基于静态约束法的配电网电动汽车接入容量评估展开研究,提出了一种在新型电力系统背景下评估主动配电网对电动汽车承载能力的方法。研究通过构建数学模型,结合潮流计算与关键约束条件(如电压越限、线路过载等),量化分析配电网可承受的最大电动汽车充电负荷容量,旨在识别规模化电动汽车接入带来的潜在运行风险,并为电网规划与运行提供科学依据。文中配套提供了完整的Matlab代码实现,便于仿真验证与结果复现。此外,该研究与分布式光伏承载力评估、电动汽车可调能力分析等方向形成技术联动,展现了多主题协同的研究体系。; 适合人群:具备电力系统分析基础理论知识及Matlab编程能力的高校研究生、科研机构研究人员,以及从事新能源并网、智能配电网规划与运行等相关领域的工程技术人员。; 使用场景及目标:①用于学术研究中的模型复现与论文撰写支撑;②评估实际配电网中电动汽车大规模接入的可行性与安全边界,指导充电基础设施布局;③作为高校教学案例,帮助学生深入理解电网承载力评估的核心原理、建模方法与仿真技术; 阅读建议:建议结合文中提及的相关研究方向(如二阶锥规划、多面体聚合方法等)进行对比学习,充分利用所提供的Matlab代码与网盘资料开展仿真实验,重点关注约束条件的设定逻辑与潮流计算模块的实现细节,以深化对评估模型机理与工程应用价值的理解。
内容概要:本文围绕“考虑隐私保护的分布式联邦学习电力负荷预测研究”展开,提出了一种基于Python实现的联邦学习框架,旨在解决居民或行业电力负荷预测中用户电表数据隐私泄露的风险。该研究通过构建分布式机器学习模型,使各参与方在不共享原始数据的前提下协同训练全局模型,有效实现了数据“可用不可见”。文中详细阐述了联邦学习的整体架构设计、本地模型训练流程、参数加密传输与安全聚合机制,并结合差分隐私等技术进一步增强系统的隐私保护能力。同时,研究利用真实电力负荷数据集进行了实验验证,展示了方法在预测精度与隐私保障之间的良好平衡,并提供了完整代码实例与复现指南,便于后续研究与应用拓展。; 适合人群:具备一定机器学习基础和电力系统背景知识,从事智慧能源、隐私计算或人工智能相关方向研究的研究生、科研人员及工程技术人员。; 使用场景及目标:① 实现跨区域、跨主体的电力负荷协同预测,打破数据孤岛;② 在确保用户用电数据隐私安全的前提下提升负荷预测准确性;③ 推动联邦学习在智能电网、需求响应、虚拟电厂等场景中的实际部署与应用。; 阅读建议:建议结合文中提供的Python代码与网盘资料进行动手实践,重点关注联邦学习的通信轮次设计、模型聚合算法(如FedAvg)的实现细节以及差分隐私噪声添加策略,深入理解其对模型性能与隐私强度的影响,为进一步优化与创新奠定基础。
VDA_Band_19.1_3rd edition_2026 English Inspection of Technical Cleanliness 内容概要:本文档为德国汽车工业协会(VDA)发布的第三版《技术清洁度检验:功能相关汽车部件的颗粒污染检测》(VDA 19.1),系统规范了汽车行业中零部件技术清洁度的检测方法与流程。文件涵盖从取样、提取、过滤到分析的全流程标准化操作,重点更新了干法提取(如 Stamp Test 和刷吸法)、小于50µm颗粒的检测、光学子系统和SEM/EDX标准分析方法,并引入统一材料分类体系以提升结果可比性。同时明确了“标准分析”与“自由检验”的区别,前者用于高兼容性检测,后者允许客户与供应商协商定制参数。文档还强化了对非可测组件的技术清洁保障、测量不确定度评估及方法验证的要求,并提供了多个实际案例支持应用落地。; 适合人群:适用于汽车制造业中从事质量控制、工艺开发、供应商管理及相关检测实验室的技术人员和管理人员,尤其适合具备一定质量管理或洁净度检测基础的专业人员。; 使用场景及目标:①用于制定和执行零部件清洁度检测标准;②指导 incoming/outgoing 检验及生产过程监控;③支持失效分析与质量改进项目;④作为企业内部审核和技术交流的依据; 阅读建议:建议结合VDA 19.2及其他相关标准配套使用,重点关注各章节中的起始参数设定、方法选择逻辑及录中的检查表示例,在实际操作中同步开展方法验证与人员培训,确保检测结果的有效性和可追溯性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值