当前位置: 首页 > news >正文

从数据到地图:用Python复现中国旱区土壤碳分布图(附代码与数据)

从数据到地图:用Python复现中国旱区土壤碳分布图(附代码与数据)

当我们在学术论文中看到一张精美的科学图表时,常常会好奇:这些数据从何而来?又是如何被转化为直观可视的图形?本文将以中国旱区土壤碳分布研究为例,带你用Python完整复现科研论文中的空间分布图,从原始数据获取到最终可视化,手把手教你掌握地理空间数据分析的核心技能。

1. 环境准备与数据获取

1.1 搭建Python分析环境

地理空间分析需要特定的工具链支持。推荐使用conda创建独立环境,避免包冲突:

conda create -n soil_carbon python=3.9 conda activate soil_carbon conda install -c conda-forge geopandas rasterio matplotlib numpy pandas

关键库说明:

  • geopandas:地理空间数据处理的核心库
  • rasterio:栅格数据读写与处理
  • matplotlib:科学可视化
  • numpy/pandas:数值计算与表格处理

提示:conda-forge通道能确保所有地理空间库的依赖关系正确解析

1.2 获取土壤碳数据

中国旱区土壤碳数据可从以下公开来源获取:

  1. HWSD(Harmonized World Soil Database)

    • 全球1km分辨率土壤数据库
    • 包含有机碳(SOC)和无机碳(SIC)含量数据
    • 下载地址:FAO官网土壤门户
  2. WorldClim气候数据

    • 提供降水、温度等气候指标
    • 可用于验证干旱梯度变化
    • 下载地址:WorldClim官网
  3. 中国行政区划数据

    • 从国家基础地理信息中心获取省界矢量数据
    • 用于裁剪和可视化
import geopandas as gpd from rasterio.warp import calculate_default_transform, reproject # 示例代码:读取HWSD数据 hwsd_path = "path/to/HWSD_China.tif" with rasterio.open(hwsd_path) as src: china_carbon = src.read(1) # 读取土壤碳含量波段

2. 数据处理与空间分析

2.1 定义中国旱区范围

根据联合国环境规划署定义,旱区包括:

  • 干旱指数(AI) < 0.65的区域
  • 涵盖中国北方大部分地区
# 计算干旱指数AI = P/PET def calculate_ai(precip, pet): return precip / pet # 从WorldClim数据计算AI precip = rasterio.open("wc2.1_30s_prec.tif") # 年降水量 pet = rasterio.open("global_et0.tif") # 潜在蒸散发 ai = calculate_ai(precip.read(1), pet.read(1)) # 创建旱区掩膜 dryland_mask = ai < 0.65

2.2 土壤碳数据预处理

原始数据通常需要以下处理步骤:

  1. 投影转换
    • 统一所有数据到相同坐标系(如WGS84)
  2. 重采样
    • 将不同分辨率数据统一到相同网格
  3. 异常值处理
    • 过滤明显错误的土壤碳值
# 投影转换示例 def reproject_raster(src_file, dst_crs): transform, width, height = calculate_default_transform( src.crs, dst_crs, src.width, src.height, *src.bounds) kwargs = src.meta.copy() kwargs.update({ 'crs': dst_crs, 'transform': transform, 'width': width, 'height': height }) with rasterio.open('reprojected.tif', 'w', **kwargs) as dst: reproject( source=rasterio.band(src, 1), destination=rasterio.band(dst, 1), src_transform=src.transform, src_crs=src.crs, dst_transform=transform, dst_crs=dst_crs, resampling=Resampling.nearest)

3. 空间可视化实现

3.1 创建分级色彩图

土壤碳分布通常采用分级设色法表示:

碳含量范围 (kg/m²)颜色代码等级
0-2#FFFFCC1
2-4#C7E9B42
4-6#7FCDBB3
6-8#41B6C44
8-10#2C7FB85
>10#2534946
import matplotlib.colors as colors # 自定义颜色映射 cmap = colors.ListedColormap([ '#FFFFCC', '#C7E9B4', '#7FCDBB', '#41B6C4', '#2C7FB8', '#253494']) bounds = [0, 2, 4, 6, 8, 10, 15] norm = colors.BoundaryNorm(bounds, cmap.N)

3.2 绘制专题地图

完整地图应包含以下要素:

  • 主图:土壤碳空间分布
  • 图例:颜色与数值对应关系
  • 比例尺和指北针
  • 数据来源说明
import matplotlib.pyplot as plt from mpl_toolkits.axes_grid1 import make_axes_locatable fig, ax = plt.subplots(figsize=(12, 8)) # 绘制底图 china = gpd.read_file('china_province.shp') china.boundary.plot(ax=ax, linewidth=0.5, color='gray') # 绘制土壤碳数据 im = ax.imshow(total_carbon, cmap=cmap, norm=norm, extent=[xmin, xmax, ymin, ymax]) # 添加颜色条 divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.1) cbar = fig.colorbar(im, cax=cax) cbar.set_label('Soil Carbon Stock (kg/m²)') # 设置标题和注释 ax.set_title('Soil Carbon Distribution in Chinese Drylands', fontsize=14) ax.text(0.01, 0.01, 'Data: HWSD v1.2 | Created with Python', transform=ax.transAxes, fontsize=8) plt.tight_layout() plt.savefig('soil_carbon_distribution.png', dpi=300)

4. 进阶分析与验证

4.1 沿干旱梯度的碳变化分析

为验证论文中"有机碳下降、无机碳增加"的结论,我们可以提取沿干旱梯度的变化曲线:

# 创建采样点沿干旱梯度 transect_points = [ (85.0, 44.5), # 新疆北部 (100.3, 40.2), # 河西走廊 (112.5, 41.5), # 内蒙古中部 (116.4, 39.9) # 华北平原北部 ] # 提取各点碳含量 soc_values = [extract_value(soc_data, point) for point in transect_points] sic_values = [extract_value(sic_data, point) for point in transect_points] ai_values = [extract_value(ai_data, point) for point in transect_points] # 绘制变化曲线 plt.figure(figsize=(10, 5)) plt.plot(ai_values, soc_values, 'b-o', label='SOC') plt.plot(ai_values, sic_values, 'r-s', label='SIC') plt.xlabel('Aridity Index') plt.ylabel('Carbon Content (kg/m²)') plt.legend() plt.grid(True)

4.2 空间自相关分析

使用Moran's I指数检验土壤碳的空间聚集性:

from esda.moran import Moran import libpysal as lps # 计算空间权重矩阵 w = lps.weights.Queen.from_dataframe(china_gdf) # 计算Moran's I moran = Moran(china_gdf['total_carbon'], w) print(f"Moran's I: {moran.I:.3f}") print(f"P-value: {moran.p_norm:.4f}")

典型结果解读:

  • Moran's I > 0:空间正相关(聚集分布)
  • Moran's I < 0:空间负相关(分散分布)
  • P-value < 0.05:统计显著

5. 完整代码架构

推荐的项目目录结构:

soil_carbon_map/ ├── data/ # 原始数据 │ ├── HWSD_China.tif │ ├── china_province.shp │ └── worldclim/ ├── notebooks/ # Jupyter笔记本 │ └── analysis.ipynb ├── scripts/ # Python脚本 │ ├── data_processing.py │ └── visualization.py ├── output/ # 结果输出 │ ├── figures/ │ └── processed_data/ └── requirements.txt # 依赖列表

核心处理流程:

  1. 数据预处理脚本(data_processing.py):

    • 数据下载与格式转换
    • 坐标系统一
    • 掩膜裁剪
  2. 分析脚本(analysis.py):

    • 空间统计计算
    • 干旱梯度分析
    • 相关性检验
  3. 可视化脚本(visualization.py):

    • 专题地图生成
    • 变化曲线绘制
    • 交互式地图输出

提示:使用Jupyter Notebook进行探索性分析,成熟后迁移到.py脚本实现自动化

6. 常见问题与优化技巧

6.1 性能优化策略

处理全国范围高分辨率数据时,可能遇到内存问题:

  • 分块处理:使用rasterio的窗口读取功能
with rasterio.open('large.tif') as src: for window in src.block_windows(): data = src.read(window=window) # 处理每个分块
  • Dask并行:适用于大规模计算
import dask.array as da carbon_dask = da.from_array(carbon_data, chunks=(1000, 1000)) result = (carbon_dask * factor).compute()

6.2 可视化增强技巧

  1. 添加地形阴影
    • 使用SRTM高程数据增强立体感
  2. 动态可视化
    • 用folium创建交互式地图
import folium m = folium.Map(location=[35, 105], zoom_start=4) folium.raster_layers.ImageOverlay( image=carbon_data, bounds=[[15, 70], [55, 140]], colormap=lambda x: (1, 0, 0, x) ).add_to(m)
  1. 多图组合
    • 使用subplots同时显示SOC和SIC分布
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6)) im1 = ax1.imshow(soc_data, cmap='YlOrBr', vmax=10) im2 = ax2.imshow(sic_data, cmap='Blues', vmax=15) # 添加颜色条和标题等
http://www.zskr.cn/news/1451784.html

相关文章:

  • Arduino Mega驱动64x32 RGB LED矩阵:硬件连接、软件配置与图像显示全攻略
  • 蓝桥杯CT117E开发板实战:用STM32G431 HAL库驱动MCP4017数字电位器(附完整代码)
  • MakeCode for Minecraft:图形化编程与沙盒游戏的创新教育实践
  • novel-downloader:200+小说网站一站式下载解决方案,打造你的个人数字图书馆
  • 达梦DM8数据库安全加固实操:手把手教你管理sysdba密码与OS认证开关
  • Vision Mamba实战:手把手教你理解双向SSM Encoder的代码实现(PyTorch版)
  • 2026出圈!5款AI写作辅助软件实测,打破思路枯竭,初稿半天搞定
  • 从“走过场”到“走心”:如何策划一场成功的“终身服务”员工认可活动
  • 从图像分割到GAN:转置卷积(Transposed Convolution)在PyTorch实战中的三种高级用法
  • STK实战:如何用Walker Delta星座模型规划低轨卫星的跨星切换通信?
  • PyQt5实战:手把手教你用样式表打造一个圆形进度按钮(附完整代码和资源文件)
  • 告别命令行!用Docker快速部署sqlite-web,在浏览器里像玩Excel一样管理SQLite数据库
  • 色多项式导数与高阶导数:从着色计数到图结构分析
  • 给计算机/工科生的数学课指南:选《高等数学》还是《数学分析》?附主流教材对比(2024版)
  • 从HashMap到ConcurrentHashMap:聊聊Map.compute方法在并发编程里的那些“坑”与最佳实践
  • 2026年天津房产纠纷避坑指南:5位靠谱专业律师推荐 - 本地品牌推荐
  • 手把手教你用STM32高级定时器TIM8生成20kHz SPWM波(从正弦表计算到代码实现)
  • 从Boss直聘zp_stoken看前端安全:那些年我们绕过的反爬与检测
  • 别再傻傻分不清!CTP API里持仓和持仓明细到底啥区别?一个例子讲透
  • SPSS/R/SAS三平台直接可用的PROCESS v4.3全套分析文件(含安装指南与模型模板)
  • 告别假货与仿真坑:用LMV358M设计工频信号采集前端,从选型、计算到Proteus验证的完整流程
  • 终极AMD处理器调优神器:免费开源硬件调试工具完全指南
  • 微软研究院新英格兰实验室:跨学科融合如何重塑安全、隐私与密码学研究
  • Pyperclip实战:用Python打造你的专属剪贴板管理器(支持Windows/Mac)
  • OpenClaw 私有部署 AI 助手:从零基础到飞书/钉钉智能聊天,4步搞定!
  • AI生成代码的7大安全风险:漏洞模式、检测方法与修复方案
  • 从零训练 LLM:解析 GitHub 开源项目 train-llm-from-scratch
  • 政府与公共服务:从“群众跑腿”到“数据跑路”,电子签让政务更有温度
  • VAE不止能生成图片?深入Multi-VAE:看它如何用Gumbel Softmax和互信息‘拆解’多视图数据的底层逻辑
  • PHP版数字人短视频生成工具:上传3秒视频就能克隆真人形象,文字转口播视频