恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
国家基础地理信息系统SHP数据实战:坐标系、编码与空间分析全流程
首页
资讯中心
/
国家基础地理信息系统SHP数据实战:坐标系、编码与空间分析全流程
国家基础地理信息系统SHP数据实战:坐标系、编码与空间分析全流程
发布时间:2026/9/26 8:27:06
简介这份国家基础地理信息系统数据集面向GIS初学者、地理信息分析人员及城市规划、交通管理、环境研究等领域的从业者提供一套可直接加载使用的中国基础地理矢量数据帮助解决空间分析中底图要素缺失、行政边界与交通水系数据难以获取的问题。压缩包共93个文件约10.63MB以shp、shx、dbf、prj、sbn、sbx等Shapefile配套格式为主涵盖主要公路、铁路、河流、湖泊、国界与省县界线、省会及地级城市驻地、经纬网等要素并附全国县级统计数据便于开展空间统计与可视化。资源已有1943人学习下载说明其在实际项目中具备较高参考价值。读者可借助这些数据完成交通网络分析、行政区划制图、生态与森林覆盖研究等任务快速搭建GIS实验或规划分析的基础数据框架。1. 拿到一套国家基础地理信息系统 SHP 数据先别急着往 ArcGIS 里拖做 GIS 项目的人大概都有过这种经历甲方甩过来一个压缩包说“这是全国的基础地理数据你拿去做个分析”。解压一看几十个文件全是 .shp、.dbf、.shx、.prj、.sbn、.sbx 混在一起文件名还都是中文。这时候如果直接把 .shp 拖进 ArcGIS 或者 QGIS大概率会遇到属性表乱码、坐标系对不上、图层缺字段这些问题。这套国家基础地理信息系统数据核心价值在于它是一套完整的全国尺度矢量底图。覆盖了国界线、省级行政区、地州界、县界、主要公路、主要铁路、主要河流、湖泊、省会城市驻地、地级城市驻地、县城驻地、经纬网以及全国县级统计数据。所有矢量文件以 SHP 格式存储配套完整的 .dbf 属性表、.shx 索引、.prj 投影定义。对于做城市规划、交通分析、水文研究、行政区划统计的人来说这是一套可以直接用的基础框架数据。适合谁适合需要全国尺度底图做空间分析、专题制图、数据可视化的从业者和学生。不适合谁不适合需要高精度局部大比例尺数据的场景这套数据的定位是国家级基础框架不是测绘级详图。2. SHP 文件族的构成与坐标系确认别让 .prj 成为摆设2.1 每个图层到底由哪些文件组成SHP 不是单个文件而是一个文件族。很多人只知道 .shp结果拷贝数据时只复制了 .shp到另一台机器上打开发现属性表空了、投影丢了。这套数据里每个图层都配了完整的文件组先搞清楚每个后缀是干什么的。后缀作用是否必须.shp存储几何形状点/线/面必须.shx几何索引加速空间查询必须.dbf属性表存储字段数据必须.prj投影坐标系定义WKT 格式强烈建议保留.sbn空间索引文件Esri 格式可选.sbx空间索引文件Esri 格式可选.shp.xml元数据描述数据来源与精度可选这套数据里主要公路、主要铁路、主要河流、经纬网、国界线、省级行政区、中国地州界、中国县界、线状省界、线状县界、中国湖泊、省会城市、地级城市驻地、县城驻地、全国县级统计数据每个图层都带了 .shp/.shx/.dbf/.prj部分带了 .sbn/.sbx全国县级统计数据、国界线、中国湖泊还额外带了 .shp.xml 元数据。注意拷贝或分发数据时至少要把 .shp、.shx、.dbf、.prj 四个文件一起带上。少一个都可能出问题。2.2 坐标系确认第一步永远是看 .prj这套数据的 .prj 文件里存的是 WKT 格式的投影定义。在动手做任何分析之前先确认坐标系。常见做法是在 QGIS 里右键图层 → 属性 → 信息看 Coordinate Reference System或者在 ArcGIS 里看图层属性的“源”选项卡。如果 .prj 文件丢失或者内容为空可以用 Python 的pyproj库来检查和重新定义import shapefile # 需要 pyshp 库 from pyproj import CRS # 读取 shp 文件检查是否有 prj 信息 sf shapefile.Reader(省级行政区.shp) # pyshp 不直接读 prj用 osgeo 或手动读 with open(省级行政区.prj, r) as f: wkt f.read() crs CRS.from_wkt(wkt) print(crs.name) # 输出坐标系名称 print(crs.to_epsg()) # 尝试输出 EPSG 代码 print(crs.axis_info) # 输出坐标轴信息这段代码的逻辑是先用 pyshp 打开 SHP 确认几何可读再单独读取 .prj 文件内容用 pyproj 解析 WKT 字符串。crs.to_epsg()会尝试匹配对应的 EPSG 代码如果返回 None 说明这是一个自定义投影需要手动确认。crs.axis_info告诉你坐标轴的方向和单位对后续做距离计算很关键。参数说明CRS.from_wkt()接受标准 WKT 字符串如果 .prj 文件是 Esri 自定义格式可能需要用CRS.from_user_input()来兼容。国内常见的投影有 CGCS2000、WGS84、西安80、北京54这套国家基础地理信息系统数据常见做法是使用 CGCS2000 或 WGS84 地理坐标系具体以 .prj 文件为准。2.3 用 QGIS 批量检查所有图层的坐标系如果图层多一个个看太慢。QGIS 的 Python 控制台可以批量检查# QGIS Python 控制台运行 from qgis.core import QgsProject layers QgsProject.instance().mapLayers().values() for layer in layers: crs layer.crs() print(f{layer.name()} - {crs.authid()} | {crs.description()})逻辑说明遍历当前工程中所有已加载图层输出每个图层的坐标系 authid如 EPSG:4326和描述。如果某个图层显示为空或 authid 为 “USER:100000” 之类说明 .prj 缺失或未定义需要手动指定。参数方面crs.authid()返回的是 QGIS 内部标识crs.description()返回可读名称。这一步看起来简单但血泪经验是很多人跳过坐标系确认直接做缓冲区分析结果算出来的距离单位是度而不是米差了十万八千里。3. 属性表编码与字段结构中文乱码的根因和修复3.1 DBF 编码问题为什么打开属性表全是问号SHP 的 .dbf 文件默认使用 UTF-8 或 GBK 编码存储中文字段。ArcGIS 对编码比较敏感如果 .dbf 是 GBK 编码而 ArcGIS 按 UTF-8 解析中文就会变成乱码。QGIS 相对宽容但也不是万能的。常见做法是先用 Python 检测 .dbf 的编码import chardet with open(省级行政区.dbf, rb) as f: raw f.read(10000) # 读前 10000 字节做检测 result chardet.detect(raw) print(result) # {encoding: GB2312, confidence: 0.99, ...}逻辑说明chardet.detect()对二进制数据进行编码推断返回编码名称和置信度。读前 10000 字节就够了因为 DBF 头部包含字段名中文字段名会暴露编码特征。参数方面raw的大小可以根据文件调整一般 10000 字节足够。如果检测出是 GBK/GB2312而你的 GIS 软件默认按 UTF-8 读取有两个解决方案一是在 QGIS 里图层属性 → 源 → 数据编码手动选 GBK二是用 Python 转码后重新写出。3.2 用 Python 修复 DBF 编码并导出import shapefile # 读取原始 shp reader shapefile.Reader(省级行政区.shp, encodinggbk) # 写出为新文件指定 utf-8 编码 writer shapefile.Writer(省级行政区_utf8.shp, encodingutf-8) writer.fields reader.fields[1:] # 跳过 DeletionFlag writer.shapeType reader.shapeType for record in reader.iterShapeRecords(): writer.record(*record.record) writer.shape(record.shape) writer.close() reader.close()逻辑说明pyshp 的Reader和Writer都支持encoding参数。读取时指定gbk写出时指定utf-8这样属性表就转码了。reader.fields[1:]是为了跳过 DBF 文件头部的 DeletionFlag 字段这个字段不是真实属性。iterShapeRecords()同时遍历几何和属性保证一一对应。参数说明encoding参数在 pyshp 2.0 版本支持如果用的是旧版需要手动处理字节流。writer.shapeType必须和原始一致否则几何类型会出错。3.3 字段结构速查这套数据里每个图层有什么这套数据的属性表字段设计比较规范常见字段包括行政区划类图层省级行政区、地州界、县界通常有NAME、CODE、ADCODE等字段记录名称和行政区划代码。交通类图层主要公路、主要铁路通常有NAME、TYPE、LEVEL等字段记录道路名称、类型、等级。水系类图层主要河流、湖泊通常有NAME、TYPE、LENGTH或AREA等字段。驻地类图层省会城市、地级城市驻地、县城驻地通常有NAME、LEVEL、X、Y等字段。全国县级统计数据这个图层的 .dbf 可能包含人口、经济等统计字段具体字段名需要打开属性表确认。注意不同版本的国家基础地理信息系统数据字段名可能有差异不要硬编码字段名先读字段列表再写代码。4. 从加载到出图一套可复现的 QGIS Python 操作流程4.1 在 QGIS 中批量加载并统一坐标系拿到数据后第一步是把所有需要的图层加载进来并统一到同一个坐标系。如果原始数据是地理坐标系度做面积和距离分析前需要投影到投影坐标系米。# QGIS Python 控制台批量加载 shp 并重投影 import os from qgis.core import QgsVectorLayer, QgsProject, QgsCoordinateReferenceSystem, QgsCoordinateTransform # 目标坐标系CGCS2000 高斯克吕格投影以 105E 中央经线为例 target_crs QgsCoordinateReferenceSystem(EPSG:4547) data_dir /path/to/your/data shp_files [f for f in os.listdir(data_dir) if f.endswith(.shp)] for shp in shp_files: layer QgsVectorLayer(os.path.join(data_dir, shp), shp[:-4], ogr) if not layer.isValid(): print(f加载失败: {shp}) continue # 重投影 transform QgsCoordinateTransform(layer.crs(), target_crs, QgsProject.instance()) layer.setCrs(target_crs) QgsProject.instance().addMapLayer(layer) print(f已加载: {shp} - {target_crs.authid()})逻辑说明遍历目录下所有 .shp 文件用 QgsVectorLayer 加载检查有效性后统一设置目标坐标系。QgsCoordinateTransform用于定义转换关系layer.setCrs()设置图层坐标系。参数方面EPSG:4547是 CGCS2000 / 3-degree Gauss-Kruger CM 105E适合中国中部地区如果研究区域偏东或偏西需要换对应的中央经线。4.2 用 GeoPandas 做空间叠加分析QGIS 适合交互式操作但批量分析用 GeoPandas 更高效。下面是一个典型场景统计每个省内的主要公路总长度。import geopandas as gpd # 读取数据 provinces gpd.read_file(省级行政区.shp, encodinggbk) roads gpd.read_file(主要公路.shp, encodinggbk) # 统一坐标系到投影坐标系以米为单位 provinces provinces.to_crs(epsg4547) roads roads.to_crs(epsg4547) # 空间叠加用省份边界裁剪公路 roads_in_province gpd.overlay(roads, provinces, howintersection) # 计算每个省内的公路总长度 roads_in_province[length_km] roads_in_province.geometry.length / 1000 result roads_in_province.groupby(NAME)[length_km].sum().reset_index() result result.sort_values(length_km, ascendingFalse) print(result.head(10))逻辑说明gpd.read_file()读取 SHPencodinggbk处理中文属性。to_crs(epsg4547)把地理坐标系转成投影坐标系这样geometry.length的单位才是米。gpd.overlay()做交集运算把公路按省界切开。groupby(NAME)按省名分组求和。参数方面howintersection表示保留两个图层的交集部分如果公路跨越省界会被切分成多段分别归入各省。4.3 导出为 GeoJSON 或 KML 供其他工具使用有时候需要把 SHP 转成其他格式比如给前端地图用 GeoJSON或者给 Google Earth 用 KML。import geopandas as gpd # SHP 转 GeoJSON gdf gpd.read_file(主要公路.shp, encodinggbk) gdf.to_file(主要公路.geojson, driverGeoJSON, encodingutf-8) # SHP 转 KML需要 fiona 支持 gdf.to_file(主要公路.kml, driverKML)逻辑说明GeoPandas 的to_file()方法根据文件扩展名自动选择驱动。driverGeoJSON输出标准 GeoJSONencodingutf-8保证中文正常。KML 驱动依赖底层 GDAL 的 LIBKML 支持如果报错可以先转 GeoJSON 再用其他工具转 KML。参数方面GeoJSON 默认使用 WGS84 坐标系如果原始数据是投影坐标系建议先to_crs(epsg4326)再导出。注意转 KML 时如果数据量很大文件会非常臃肿建议先按区域筛选再导出。5. 避坑与排查那些让我加班到凌晨的常见问题5.1 现象属性表打开全是乱码字段名和值都读不了原因.dbf 文件编码与 GIS 软件默认编码不一致。国内数据常见 GBK 编码而 QGIS 默认 UTF-8ArcGIS 则取决于系统区域设置。解决在 QGIS 中右键图层 → 属性 → 源 → 数据编码手动选择 GBK 或 GB2312。如果 ArcGIS 中乱码可以用 Python 转码后重新导出参考 3.2 节的代码。5.2 现象两个图层叠加分析结果为空明明范围有重叠原因两个图层的坐标系不一致一个可能是 WGS84 地理坐标系另一个可能是 CGCS2000 投影坐标系。虽然在地图上看起来重叠但数值范围完全不同。解决叠加前先用gdf.crs检查两个图层的坐标系用to_crs()统一到同一坐标系。不要依赖视觉判断一定要看数值。5.3 现象计算出来的面积或距离数值离谱差了几个数量级原因在地理坐标系度上直接计算几何长度或面积得到的是“度”而不是“米”或“平方米”。解决先投影到合适的投影坐标系再做计算。中国地区常用 CGCS2000 高斯克吕格投影或 Albers 等面积投影。具体选哪个取决于分析目标距离分析用高斯克吕格面积分析用 Albers。5.4 现象拷贝数据到另一台机器后图层打不开或属性丢失原因只复制了 .shp 文件没有带上 .shx、.dbf、.prj。解决打包时确保每个图层的 .shp、.shx、.dbf、.prj 四个文件都在。如果用了 .sbn/.sbx 空间索引也一并带上。建议直接打包整个文件夹不要单独挑文件。5.5 现象全国县级统计数据图层打开后字段全是数字代码看不懂原因统计数据的字段名可能是英文缩写或代码没有对应的数据字典。解决先查看 .shp.xml 元数据文件里面可能有字段说明。如果没有用gdf.columns列出所有字段名结合数据来源文档推断含义。常见做法是找同系列数据的说明文档对照。6. 进阶技巧用这套数据做一张全国公路密度专题图前面把数据加载、坐标系处理、属性表修复、空间叠加都走了一遍。最后落到一个具体产出用主要公路和省级行政区数据做一张全国公路密度专题图。这个技巧的核心是把线状数据按面状单元聚合再归一化。先算每个省的面积和公路总长度import geopandas as gpd provinces gpd.read_file(省级行政区.shp, encodinggbk).to_crs(epsg4547) roads gpd.read_file(主要公路.shp, encodinggbk).to_crs(epsg4547) # 计算省份面积平方公里 provinces[area_km2] provinces.geometry.area / 1e6 # 叠加计算各省公路长度 roads_clip gpd.overlay(roads, provinces, howintersection) roads_clip[length_km] roads_clip.geometry.length / 1000 road_length roads_clip.groupby(NAME)[length_km].sum().reset_index() # 合并回省份图层 provinces provinces.merge(road_length, onNAME, howleft) provinces[length_km] provinces[length_km].fillna(0) # 计算公路密度公里/万平方公里 provinces[density] provinces[length_km] / (provinces[area_km2] / 10000) # 导出结果 provinces[[NAME, area_km2, length_km, density, geometry]].to_file( 公路密度.shp, encodingutf-8 ) print(provinces[[NAME, density]].sort_values(density, ascendingFalse).head())逻辑说明geometry.area在投影坐标系下返回平方米除以 1e6 得到平方公里。gpd.overlay()把公路按省界切开后geometry.length返回米除以 1000 得到公里。groupby(NAME)按省名汇总。merge()把汇总结果合并回省份图层fillna(0)处理没有公路数据的省份。density的单位是公里/万平方公里方便制图时分级设色。参数方面epsg4547是 CGCS2000 3-degree Gauss-Kruger CM 105E适合中国中部如果做全国图建议用 Albers 等面积投影如 EPSG:9822 或自定义避免高纬度地区面积变形。howleft保证所有省份都保留没有公路的省份密度为 0。导出后在 QGIS 里加载公路密度.shp按density字段做分级设色用自然断点法分 5 级再加个图例和指北针一张专题图就出来了。如果要做成 Web 地图可以转成 GeoJSON 后用 ECharts 或 Leaflet 加载。提示做全国尺度专题图时建议把南海诸岛单独处理避免主图比例尺过大导致小岛屿看不清。这套数据我前后用过几次最深的教训是每次拿到新数据先花十分钟检查坐标系和编码比后面花两小时排查分析结果为什么不对要划算得多。从那以后我每次加载 SHP 文件都强制走一遍坐标系确认和编码检测再开始做任何分析。希望帮到你。本文还有配套的精品资源点击获取