2. 处理GeoJSON数据格式

任务说明

本案例将完成一个完整的GeoJSON处理闭环:读取GeoJSON文件 → 转换为GeoDataFrame → 执行属性查询 → 执行空间过滤。使用Python的GeoPandas库实现,输入数据为内嵌的示例GeoJSON(包含北京市三个城区的面要素及人口属性),最终输出各步骤的结果行数与过滤后的要素。

实现代码

import geopandas as gpd
from shapely.geometry import Polygon
import json

# 1. 准备示例GeoJSON数据(内嵌,保证独立可复现)
geojson_data = {
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "properties": {"name": "东城区", "population": 65.2, "area_km2": 41.8},
            "geometry": {
                "type": "Polygon",
                "coordinates": [[[116.40, 39.90], [116.43, 39.90], [116.43, 39.94], [116.40, 39.94], [116.40, 39.90]]]
            }
        },
        {
            "type": "Feature",
            "properties": {"name": "西城区", "population": 113.7, "area_km2": 50.7},
            "geometry": {
                "type": "Polygon",
                "coordinates": [[[116.35, 39.90], [116.38, 39.90], [116.38, 39.94], [116.35, 39.94], [116.35, 39.90]]]
            }
        },
        {
            "type": "Feature",
            "properties": {"name": "朝阳区", "population": 354.5, "area_km2": 470.8},
            "geometry": {
                "type": "Polygon",
                "coordinates": [[[116.43, 39.90], [116.50, 39.90], [116.50, 39.97], [116.43, 39.97], [116.43, 39.90]]]
            }
        }
    ]
}

# 将字典写入临时文件(模拟真实读取场景)
with open("beijing_districts.geojson", "w", encoding="utf-8") as f:
    json.dump(geojson_data, f, ensure_ascii=False)

# 2. 读取GeoJSON文件并转换为GeoDataFrame
gdf = gpd.read_file("beijing_districts.geojson")
print("=== 读取GeoJSON并转换 ===")
print(f"类型: {type(gdf).__name__}")
print(f"要素数量: {len(gdf)}")
print(f"列名: {list(gdf.columns)}")
print(gdf[["name", "population", "area_km2"]].to_string(index=False))

# 3. 属性查询:筛选人口大于100万的区
attr_result = gdf[gdf["population"] > 100]
print("\n=== 属性查询(人口 > 100万)===")
print(f"命中数量: {len(attr_result)}")
print(attr_result["name"].tolist())

# 4. 空间过滤:筛选与给定点(天安门附近)相交的区
from shapely.geometry import Point
tiananmen_point = Point(116.397, 39.908)  # 天安门坐标
spatial_result = gdf[gdf.intersects(tiananmen_point)]
print("\n=== 空间过滤(与天安门点相交)===")
print(f"命中数量: {len(spatial_result)}")
print(spatial_result["name"].tolist())

# 5. 验证:检查空间过滤结果的几何有效性
assert len(spatial_result) > 0, "空间过滤结果为空,请检查坐标范围"
print("\n验证通过:空间过滤返回了有效要素")

代码说明

代码首先在内存中构建一个包含三个北京市区县面要素的GeoJSON字典,并写入临时文件以模拟真实文件读取。使用gpd.read_file()读取后自动转换为GeoDataFrame。属性查询通过布尔索引实现,筛选population大于100万的区县;空间过滤则利用intersects()方法,判断每个面要素是否与天安门坐标点相交。最后通过断言验证空间过滤结果非空。

运行与验证

依赖安装:

pip install geopandas shapely

运行方式:将上述代码保存为geojson_processing.py,在Python环境中执行:

python geojson_processing.py

预期输出与判定标准:

  • 读取阶段输出3个要素,列名包含name、population、area_km2和geometry;
  • 属性查询输出['西城区', '朝阳区'](人口均大于100万);
  • 空间过滤输出['东城区', '西城区'](天安门位于东城区与西城区交界附近,两个面均与之相交);
  • 程序无异常退出且断言通过,即表示处理流程正确。
GeoJSON处理流程与数据变换 ① 读取GeoJSON gpd.read_file() ② 转换为GeoDataFrame 自动解析几何列 ③ 属性查询 population > 100 ④ 空间过滤 intersects() 输入数据(3个要素) 东城区 | 人口65.2万 | 面积41.8km² 西城区 | 人口113.7万 | 面积50.7km² 朝阳区 | 人口354.5万 | 面积470.8km² 中间结果 属性查询 → 西城区、朝阳区 空间过滤 → 东城区、西城区 验证观测点 ✓ 读取后要素数 = 3 ✓ 属性查询结果 = 2个区 ✓ 空间过滤结果 = 2个区 天安门坐标点 (116.397, 39.908) 用于空间相交测试