石家庄GIS数据怎么转GeoJSON?Shapely与Fiona实战技巧(附:代码示例)
如果你正在处理“石家庄GIS数据怎么转GeoJSON?Shapely与Fiona实战技巧(附:代码示例)”这个问题,通常不是简单把后缀改成 .geojson 就结束了。真正容易出错的地方在于坐标系、中文字段编码、几何有效性、属性类型以及最终是否适合 WebGIS 加载。
本文以石家庄常见的 GIS 矢量数据为例,演示如何用 Python 中的 Fiona 读取 Shapefile,用 Shapely 处理几何对象,并输出标准 GeoJSON。适合 GIS 学生、初级 GIS 工程师、空间数据分析人员和 WebGIS 开发者参考。

引言:为什么石家庄GIS数据转GeoJSON经常出问题
很多石家庄本地项目会拿到行政区、道路、兴趣点、管网或用地边界等 Shapefile 数据。把这些数据转成 GeoJSON 后,常用于 Leaflet、OpenLayers、Mapbox GL JS 或 Cesium 等 WebGIS 前端展示。
但在实际工作中,经常会遇到这些问题:
- GeoJSON 加载后位置偏到海上或其他城市。
- 中文字段变成乱码。
- Polygon 面数据显示缺口、重叠或无法渲染。
- 属性字段里的日期、数值、空值导致导出失败。
- GeoJSON 文件过大,前端打开卡顿。
这些问题背后往往不是 GeoJSON 本身的问题,而是数据坐标系、编码、几何质量和转换流程没有处理好。下面我们用 Fiona 与 Shapely 建立一个相对稳妥的转换流程。
背景:Shapefile、Fiona、Shapely和GeoJSON分别负责什么
在开始写代码之前,需要先把几个概念分清楚。
- Shapefile:传统 GIS 矢量数据格式,通常由
.shp、.shx、.dbf、.prj等多个文件组成。 - GeoJSON:基于 JSON 的矢量地理数据格式,常用于 WebGIS 前端加载。
- Fiona:Python 中常用的 GIS 矢量数据读写库,适合读取 Shapefile、GeoPackage、GeoJSON 等格式。
- Shapely:Python 中处理几何对象的库,可用于判断几何是否有效、修复几何、计算范围、简化线面等。
- 坐标系:决定数据坐标如何落到地球上的规则。WebGIS 中的 GeoJSON 通常建议使用 WGS84 经纬度坐标,即 EPSG:4326。
一个稳妥的转换思路是:用 Fiona 读取原始数据,用 PyProj 进行坐标转换,用 Shapely 检查和修复几何,再用 Fiona 或标准 JSON 写出 GeoJSON。
原理:石家庄GIS数据转GeoJSON前必须先检查坐标系
石家庄位于河北省中南部,WGS84 经纬度大致在东经 113 到 115 度、北纬 37 到 39 度附近。如果你导出的 GeoJSON 坐标不是类似 [114.5, 38.0] 这样的经纬度,而是 [500000, 4200000] 或 [38400000, 4200000] 这类大数值,就说明它很可能仍然是投影坐标。
常见情况包括:
- 数据本身是 CGCS2000 高斯克吕格投影。
- 数据是西安80或北京54坐标系。
- 数据缺少
.prj文件,无法自动识别坐标系。 - 数据已经是 WGS84,但被错误地再次转换。
GeoJSON 规范本身并不强制所有坐标都必须是 EPSG:4326,但大多数 WebGIS 工具默认按经纬度坐标理解 GeoJSON。因此,石家庄 GIS 数据转 GeoJSON 时,建议明确输出为 EPSG:4326,除非你的前端地图专门处理了其他坐标系。
判断是否需要转换坐标系的简单方法:打开几条坐标看数值范围。如果是 110 到 120、35 到 45 这样的经纬度范围,通常接近 WGS84;如果是几十万、几百万或带分带号的大数值,则通常是投影坐标。
步骤:使用Fiona和Shapely把石家庄Shapefile转GeoJSON
步骤1:准备Python环境
建议使用独立虚拟环境,避免与系统 Python 或 ArcGIS Pro 自带 Python 混用。可以使用 conda 安装,GIS 相关依赖会更省心。
conda create -n gis_geojson python=3.11
conda activate gis_geojson
conda install -c conda-forge fiona shapely pyproj
如果使用 pip,也可以安装:
pip install fiona shapely pyproj
如果在 Windows 上安装 Fiona 报错,优先建议使用 conda-forge,因为 Fiona 依赖 GDAL,直接 pip 安装有时会遇到本地编译或动态库问题。
步骤2:检查Shapefile文件是否完整
假设你的石家庄行政区数据路径为:
D:/gisdata/shijiazhuang/admin_boundary.shp
同目录下至少应有以下文件:
admin_boundary.shp:几何数据。admin_boundary.shx:几何索引。admin_boundary.dbf:属性表。admin_boundary.prj:坐标系信息,强烈建议保留。
如果缺少 .prj 文件,程序可能无法知道原始坐标系。此时不要盲目转换,应先向数据提供方确认坐标系,或在 QGIS、ArcGIS Pro 中根据已知底图位置进行判断。
步骤3:读取Shapefile并查看坐标系
import fiona
input_shp = r"D:/gisdata/shijiazhuang/admin_boundary.shp"
with fiona.open(input_shp, "r", encoding="utf-8") as src:
print("驱动:", src.driver)
print("坐标系:", src.crs)
print("要素数量:", len(src))
print("字段结构:", src.schema)
如果中文字段乱码,可以把 encoding="utf-8" 改为 encoding="gbk" 试一下。很多历史 Shapefile 的 .dbf 属性表使用 GBK 或 CP936 编码。
with fiona.open(input_shp, "r", encoding="gbk") as src:
print(src.schema)
步骤4:将坐标转换为EPSG:4326
下面的代码会读取原始 Shapefile,自动获取源坐标系,并转换到 WGS84 经纬度坐标。这里使用 pyproj.Transformer 做坐标转换,用 shapely.ops.transform 应用到几何对象。
import fiona
from fiona.crs import CRS
from shapely.geometry import shape, mapping
from shapely.ops import transform
from pyproj import Transformer
input_shp = r"D:/gisdata/shijiazhuang/admin_boundary.shp"
output_geojson = r"D:/gisdata/shijiazhuang/admin_boundary_wgs84.geojson"
target_crs = CRS.from_epsg(4326)
with fiona.open(input_shp, "r", encoding="gbk") as src:
source_crs = src.crs
if not source_crs:
raise ValueError("原始数据缺少坐标系信息,请先确认 .prj 或手动指定源坐标系。")
transformer = Transformer.from_crs(source_crs, target_crs, always_xy=True)
output_schema = src.schema.copy()
with fiona.open(
output_geojson,
"w",
driver="GeoJSON",
crs=target_crs,
schema=output_schema,
encoding="utf-8"
) as dst:
for feature in src:
geom = shape(feature["geometry"])
geom_wgs84 = transform(transformer.transform, geom)
new_feature = {
"type": "Feature",
"geometry": mapping(geom_wgs84),
"properties": dict(feature["properties"])
}
dst.write(new_feature)
print("转换完成:", output_geojson)
这段代码适合大多数“有正确 .prj 文件”的石家庄 GIS 数据转 GeoJSON 场景。如果输出后能在 QGIS 或 WebGIS 中落到石家庄附近,说明坐标转换基本正确。
步骤5:用Shapely检查和修复无效几何
有些面数据在 Shapefile 中看起来正常,但转换为 GeoJSON 后前端渲染失败,原因可能是 Polygon 自相交、环方向异常或几何为空。可以在转换时增加几何检查。
import fiona
from fiona.crs import CRS
from shapely.geometry import shape, mapping
from shapely.ops import transform
from pyproj import Transformer
input_shp = r"D:/gisdata/shijiazhuang/admin_boundary.shp"
output_geojson = r"D:/gisdata/shijiazhuang/admin_boundary_fixed.geojson"
target_crs = CRS.from_epsg(4326)
with fiona.open(input_shp, "r", encoding="gbk") as src:
source_crs = src.crs
if not source_crs:
raise ValueError("原始数据缺少坐标系信息,请先确认源坐标系。")
transformer = Transformer.from_crs(source_crs, target_crs, always_xy=True)
output_schema = src.schema.copy()
invalid_count = 0
empty_count = 0
with fiona.open(
output_geojson,
"w",
driver="GeoJSON",
crs=target_crs,
schema=output_schema,
encoding="utf-8"
) as dst:
for feature in src:
geom = shape(feature["geometry"])
if geom.is_empty:
empty_count += 1
continue
if not geom.is_valid:
invalid_count += 1
geom = geom.buffer(0)
if geom.is_empty:
empty_count += 1
continue
geom_wgs84 = transform(transformer.transform, geom)
new_feature = {
"type": "Feature",
"geometry": mapping(geom_wgs84),
"properties": dict(feature["properties"])
}
dst.write(new_feature)
print("转换完成:", output_geojson)
print("修复的无效几何数量:", invalid_count)
print("跳过的空几何数量:", empty_count)
buffer(0) 是 Shapely 中常见的简单几何修复方法,对部分自相交面有效。但它不是万能工具,复杂拓扑错误仍建议在 QGIS 的“修复几何”工具或 ArcGIS Pro 的 Repair Geometry 工具中进一步处理。
步骤6:处理GeoJSON属性中的特殊类型
GeoJSON 属性最终会变成 JSON。JSON 对字段类型比较敏感,日期、Decimal、小数精度、空值和特殊对象都可能造成问题。Fiona 通常会帮你处理大部分常见类型,但为了更稳妥,可以对属性做一次清洗。
from datetime import date, datetime
from decimal import Decimal
def clean_properties(properties):
result = {}
for key, value in dict(properties).items():
if isinstance(value, (datetime, date)):
result[key] = value.isoformat()
elif isinstance(value, Decimal):
result[key] = float(value)
elif value is None:
result[key] = None
else:
result[key] = value
return result
在写出 Feature 时使用:
new_feature = {
"type": "Feature",
"geometry": mapping(geom_wgs84),
"properties": clean_properties(feature["properties"])
}
如果你的属性字段包含很长的说明文本、图片路径、附件字段或内部管理字段,可以在导出前删除不需要的字段,减小 GeoJSON 文件体积。
步骤7:在QGIS中验证GeoJSON结果
代码运行完成后,不建议直接交给前端使用。至少做一次 GIS 软件验证:
- 打开 QGIS。
- 加载一个在线底图,例如 OpenStreetMap。
- 把输出的
admin_boundary_wgs84.geojson拖入 QGIS。 - 检查是否落在石家庄市范围附近。
- 随机点选几个要素,检查中文属性是否正常。
- 放大到边界细节,检查面是否破碎、线是否断裂。
如果位置正确、属性正常、几何显示完整,说明这次石家庄 GIS 数据转 GeoJSON 的结果基本可用。
常见坑:石家庄GIS数据转GeoJSON时最容易忽略的问题
1. 把投影坐标直接当成经纬度
这是最常见的问题。比如原始数据是 CGCS2000 高斯克吕格投影,坐标值可能是几十万和几百万。如果不转成 EPSG:4326,WebGIS 前端会把这些大数当作经纬度,结果自然无法显示到正确位置。
2. 不确认.prj文件是否正确
有些数据虽然带 .prj,但并不一定正确。历史数据经过多次复制、裁剪和导出后,可能出现几何坐标和 .prj 描述不一致的情况。遇到位置偏移明显的数据,应回到数据源确认坐标系。
3. 中文字段乱码
石家庄本地项目数据常见字段如“区县名”“道路名”“地块编号”“用地性质”等。如果 .dbf 编码是 GBK,而读取时按 UTF-8 处理,就会出现乱码。Fiona 读取 Shapefile 时可以尝试 encoding="gbk"。
4. 面数据无效导致前端不显示
WebGIS 前端渲染 GeoJSON 时,对几何质量比较敏感。自相交 Polygon、空几何、重复节点、极小碎面都可能导致显示异常。Shapely 可以做初步检查,但复杂数据最好配合 QGIS 或 ArcGIS Pro 做拓扑清理。
5. GeoJSON文件太大
GeoJSON 是文本格式,体积通常比 Shapefile 或 GeoPackage 更大。如果石家庄道路、建筑物或地块数据特别细,前端一次性加载会很慢。可以考虑简化几何、裁剪范围、删除冗余字段,或改用矢量瓦片。
方法比较:Fiona和Shapely转换GeoJSON与其他工具怎么选
| 方法 | 适合场景 | 优点 | 注意事项 |
|---|---|---|---|
| Fiona + Shapely + PyProj | 需要批处理、自动化、几何检查和属性清洗 | 流程可控,适合写脚本和项目集成 | 需要理解坐标系和 Python 环境 |
| QGIS另存为GeoJSON | 少量数据、人工转换、需要可视化检查 | 操作直观,适合初学者 | 批量处理和规则化清洗不如代码灵活 |
| ogr2ogr命令行 | 格式转换、坐标转换、批处理 | 速度快,适合自动化脚本 | 命令参数需要准确,错误时不易排查 |
| GeoPandas | 需要同时做表格分析和空间处理 | 语法接近 Pandas,适合数据分析 | 大文件内存占用较高 |
| ArcGIS Pro导出 | 已有 ArcGIS 工作流和地理数据库数据 | 界面成熟,适合企业数据管理 | 自动化通常需要 ArcPy 环境和许可 |
如果只是偶尔把一个 Shapefile 转成 GeoJSON,用 QGIS 最快。如果你要定期处理石家庄多个区县、多个专题图层,推荐使用 Fiona 与 Shapely 写成脚本,这样更容易复用和检查。
检查清单:交付GeoJSON前建议逐项确认
- 原始 Shapefile 是否包含
.shp、.shx、.dbf、.prj文件。 - 是否确认源坐标系,不要只凭文件名猜测。
- 输出 GeoJSON 是否转换为 EPSG:4326。
- 坐标数值是否落在石家庄合理经纬度范围附近。
- 中文字段是否正常显示。
- 是否检查并处理空几何、无效几何。
- 属性字段是否包含不能 JSON 序列化的类型。
- 是否删除了前端不需要的冗余字段。
- GeoJSON 文件大小是否适合浏览器直接加载。
- 是否在 QGIS 或 WebGIS 页面中做过最终验证。
FAQ:石家庄GIS数据转GeoJSON常见问题
石家庄GIS数据转GeoJSON一定要转成WGS84吗?
如果用于 Leaflet、OpenLayers 等常见 WebGIS 前端,建议输出 EPSG:4326 的 GeoJSON。虽然某些前端框架可以处理其他投影,但需要额外配置坐标转换。为了通用性和交付便利,WGS84 是最稳妥的选择。
Shapely可以直接读写Shapefile和GeoJSON吗?
Shapely 主要负责几何计算和几何处理,不负责完整的 GIS 文件读写。读取 Shapefile、写出 GeoJSON 通常交给 Fiona,Shapely 负责检查、修复、简化和转换几何对象。
Fiona读取中文字段乱码怎么办?
优先尝试在 fiona.open 中指定编码,例如 encoding="gbk" 或 encoding="utf-8"。如果仍然乱码,说明原始 .dbf 编码可能不标准,建议先用 QGIS 或其他工具确认属性表编码。
为什么GeoJSON在QGIS里正常,但网页上加载很慢?
QGIS 是桌面 GIS 软件,对大文件处理能力更强;浏览器加载 GeoJSON 时,需要下载、解析 JSON、创建图形对象并渲染。若 GeoJSON 过大,网页就会卡顿。可以通过简化几何、裁剪范围、删除字段或使用矢量瓦片解决。
buffer(0)修复几何安全吗?
buffer(0) 可以修复一部分自相交面,但可能改变几何形状或拆分为多部件。对于规划红线、权属边界、管线等高精度数据,不建议只依赖它自动修复,最好人工抽查或使用专业拓扑检查流程。
没有.prj文件还能转换GeoJSON吗?
可以,但前提是你必须知道原始数据的真实坐标系。如果不知道源坐标系,任何转换都可能是错的。建议先联系数据提供方,或用已知控制点、底图叠加和坐标数值范围进行判断。
结论:用代码转换GeoJSON的关键不是写出文件,而是保证位置和质量正确
石家庄 GIS 数据转 GeoJSON 的核心流程可以概括为:确认原始坐标系,读取 Shapefile,修复或过滤问题几何,转换到 EPSG:4326,清洗属性字段,最后用 QGIS 或 WebGIS 验证结果。
Fiona 与 Shapely 的组合适合需要批量处理和可重复交付的场景。Fiona 负责稳定读写 GIS 文件,Shapely 负责几何质量控制,PyProj 负责坐标转换。只要把坐标系、编码和几何有效性这三件事处理好,大多数石家庄 GIS 数据转 GeoJSON 的问题都能被定位并解决。