简介:面向地理信息系统使用者与交通规划研究者,这份陕西各级公路SHP文件提供全省高速公路、一、二、三级公路的矢量线数据,以及各地级市行政区划面数据,可按道路等级分层加载,用于路网分析、区域规划与空间统计。包体采用Esri的Shapefile格式,涵盖5套完整数据图层,共35个文件:shp存储几何、dbf记录道路名称/等级/长度等属性、prj定义坐标系、sbn/sbx建立空间索引、xml保存元数据,整套压缩包仅2.14MB,轻量易用,可直接导入ArcGIS、QGIS等桌面软件打开和编辑。已有631人学习下载。基于不同等级公路的区分,可快速开展交通网络连通性、道路密度、缓冲区影响等专题分析,结合行政边界还能支撑灾害应急路径选择、商业选址评估等应用,对地理信息教学与省级尺度课题研究均有参考价值。处理时可利用道路属性字段筛选特定等级线路,或结合底图制作专题地图,从而将原始地理数据转化为可读的决策信息。
1. 陕西各级公路SHP:先别急着拖进地图,弄清“能做什么”再动手
有没有这种经历:同事传来一份陕西各级公路SHP,解压后顺手往 QGIS 画布上一拖,满屏线要素确实壮观。但叠加天地图影像后,道路和影像对不上,属性表里全是数字代码,想按公路等级筛个“高速+国道”都要靠猜字段名。这份数据真正要解决的,是把省域公路从“一堆线”变成能做分析、出图、交付的工程路网底图,前提是你愿意花半小时拆文件、认坐标系、理字段。适合陕西交通规划、路网普查、选址分析以及做综合 GIS 数据整理的从业者;如果你只是要一张示意图,这套复杂度反而会拖慢进度。下面按我实际处理顺序走:先拆结构,再做清洗,然后讲格式转换,最后单列避坑和验收习惯。
2. 把结构吃透:陕西各级公路SHP的文件组成、分级字段与坐标系判定
拿到一份路网数据,先别急着做分析和出图,花十分钟搞清楚三件事:shp 是不是完整交付、道路等级存在哪个字段、坐标系到底是什么。这三件事不解决,后面每步都可能返工。
2.1 SHP 不是单文件:四件套与隐藏的编码文件
陕西省级公路数据的交付形态,在一线项目里几乎都是 shapefile 格式,但很多人只把.shp拷走,导致换一台电脑就打不开。这里要明确一点:shapefile 是一组文件约定,不是一个文件。常见的配套文件至少有下面这些:
| 后缀 | 作用 | 丢了会怎样 |
|---|---|---|
| .shp | 要素几何主文件 | 无法显示 |
| .shx | 几何索引 | 部分软件直接打不开 |
| .dbf | 属性表,路名、等级、编号都在这里 | 图层还在,属性全空 |
| .prj | 坐标系定义 | 坐标警告,叠加错位 |
| .cpg | 字符集定义 | 中文乱码 |
| .sbn /.sbx | 空间索引 | ArcGIS 效率下降,QGIS 基本无感 |
我一般会把这几个文件连同放它们的文件夹一起复制走,并且强制要求路径里不出现中文。比如D:\gisdata\shanxi_road\没问题,D:\工作\陕西道路\在部分旧版 ArcGIS 里就会翻车。在 QGIS 里加载时,直接把.shp拖进画布就能看到图层;ArcGIS 则用“添加数据”选中.shp,不要手动去勾.dbf,否则只能看到属性表看不到几何。
加载后第一件事是打开属性表,检查道路名称字段有没有大量 NULL,再确认坐标系是否被正确识别。很多时候图层显示“未知 CRS”,是因为.prj文件缺失或被改名了。这时可以在图层属性里手动指定,但指定之前必须判断它到底是经纬度还是投影坐标,这一步判断错了,后面整条线都偏到不知道哪里去。
2.2 道路分级字段怎么识别:等级字段、类型字段与编码字典
“各级公路”这四个字,落实到 shp 上就是一个或多个属性字段。常见命名有level、class、grade、type、Road_Type、等级,也可能是code这种纯数字编码。不同数据源字段名差异很大,但取值逻辑通常能归成两大类:
| 分类方式 | 典型取值 | 实际含义 |
|---|---|---|
| 按行政等级 | 国道 / 省道 / 县道 / 乡道 | 管理主体和路网地位 |
| 按技术等级 | 高速 / 一级 / 二级 / 三级 / 四级 | 设计标准和通行能力 |
| 按线路编号 | G108、S210、X105 | 具体路线标识 |
实际操作中,最忌讳的就是“看到 name 字段就以为能筛选等级”。很多 shp 里路线名称只写“G108”或“国道 108”,但等级字段里存的却是1、2、3这种编码。这时不要靠猜,先把字段值统计一遍,用 QGIS 的“按字段值分组统计”或者直接看属性表排序,确定编码字典后再做映射。
如果你在 QGIS 里想把数字编码转成文字等级,可以这样写:
CASE WHEN "level" = 1 OR "level" = '1' THEN '高速公路' WHEN "level" = 2 THEN '国道' WHEN "level" = 3 THEN '省道' WHEN "level" = 4 THEN '县道' ELSE '乡道/其他' END这个表达式的关键点是先确认字段类型。如果字段是整型,条件里就不要加引号;如果字段是字符型,就必须写'1'。我遇到过不少次“明明值是 1 但条件判断不生效”的情况,十有八九是类型没对上。建议先写typeof("level")看返回结果,再决定表达式写法。
2.3 坐标系判定:CGCS2000 与 WGS84 的区分方法
陕西地区的矢量数据,目前主流工程标准已经是 CGCS2000,投影带常用三度带中央经线 108E 或 110E。但也会碰到老数据用的是 WGS84 经纬度,甚至更旧的西安 80 坐标系。判断方法其实很简单:打开.prj文件看文本,或者在图层面板看 CRS 信息。
一个快速区分技巧是看坐标数值量级。陕西范围经度大约在 105.5 到 111 度之间,纬度在 31 到 39.5 度之间。如果图层的坐标范围是这种两位数和一位数的小数点组合,说明它是经纬度坐标系。如果 X 坐标是 6 到 7 位数字,Y 坐标是 4 到 5 位数字,比如 X=36500000,Y=3800000,那基本可以确定是投影坐标系,而且很可能是 CGCS2000 三度带投影。
用 Python 判断更直接:
import geopandas as gpd gdf = gpd.read_file('陕西省道路.shp') print(gdf.crs) print(gdf.total_bounds) # 输出 (minx, miny, maxx, maxy)这里如果gdf.crs显示EPSG:4547或EPSG:4548,对应的是 CGCS2000 三度带投影;如果显示EPSG:4490,则是 CGCS2000 经纬度。.total_bounds的作用是让你肉眼确认坐标范围是否符合陕西地理位置预期。如果显示出来是一串十七八位的大数字,说明坐标系定义和实际坐标不匹配,后面叠加一定会出问题,建议先回退到原始数据查找.prj,不要盲目投影。
3. 数据清洗与整理:筛选、合并、拓扑修复,把路网变成能分析的工作层
原始 shp 里的要素,往往比工程需要的多得多。有重复线段、有跨省边界线、有非常短的毛刺线,还有等级字段值不一致的情况。直接拿原始数据做分析,结果很难让人信服。这一章我用 QGIS 和 Python 各走一遍流程。
3.1 用 QGIS 按等级筛选道路并导出工作副本
QGIS 里最常用的筛选方式不是手动框选,而是属性筛选。右键图层,打开“筛选”对话框,写表达式:
"type" IN ('高速', '国道') OR "level" IN (1, 2)这个表达式的逻辑是:只要type字段是高速或国道,或者level字段是 1 或 2,就保留。注意两件事:第一,字段名和字段值要以你实际打开的属性表为准,不要照抄我的例子;第二,OR会叠加多个条件,如果筛选结果比预期多很多,检查是不是因为字段里既有“国道”又有“G210”这类重复表达。
筛选完成后,右键图层选择“导出”->“保存要素为”,格式选 ESRI Shapefile,编码勾选 UTF-8,坐标系按原图层保持即可。这样导出的文件是物理存在的独立图层,后续分析都基于它,原始数据不被动过。这是我很坚持的一个习惯:所有加工都做副本,源文件永远留一份原样备份,防止清洗过程中把不可逆的错误写进去。
如果是 ArcGIS 用户,对应操作是“按属性选择”后右键图层导出数据。逻辑相同,只是界面不同。
3.2 geopandas 批量处理:读取、筛选、合并与按等级重组
当陕西路网被拆成十几个 shp 时,比如按市或按县交付,手工在 QGIS 里一个个处理会非常痛苦。这时用 geopandas 批量处理更合适:
import geopandas as gpd import pandas as pd # 读取陕西各级公路SHP,如果中文乱码,尝试 encoding='gbk' roads = gpd.read_file('shanxi_roads.shp', encoding='utf-8') print(roads.columns.tolist()) print(roads.crs) # 筛出高速和国道,用于干线分析 trunk = roads[ roads['level'].astype(str).str.contains('高速|国道|G') ].copy() # 按等级字段溶解合并,减少碎线数量 trunk_dissolved = trunk.dissolve(by='level', as_index=False) # 导出为新的shp文件 trunk_dissolved.to_file('shanxi_trunk_roads.shp', encoding='utf-8')这段代码建议细致说明一下。读取时encoding='utf-8'是告诉 geopandas 用 UTF-8 解码 dbf 属性表;如果打开后中文路名都是乱码,就改成encoding='gbk'重读,因为很多 shp 里的中文字段实际是 GBK 编码。astype(str)是把字段统一转成字符串再做筛选,这样既避开整型和字符型不匹配的问题,也能用包含匹配来处理“高速”、“G65”这类混合值。dissolve(by='level')会把相邻的同等级线段合并成一条连续要素,适合做路网概况图,但要注意它也可能把相距很远的同等级线段合并,如果你需要的是逐条路线的拓扑关系,这一步要谨慎使用。
3.3 空间范围裁切与碎线清理:去掉不需要的矢量
陕西省路网数据经常会包含与甘肃、山西、四川、河南等邻省接边路段,原因是道路本身跨省贯通,制图时把边界外的部分也画进去了。如果项目只做陕西省内分析,就需要按省界裁切。
from shapely.geometry import shape import geopandas as gpd # 读取陕西省级边界shp boundary = gpd.read_file('shanxi_boundary.shp') # 用边界裁切路网 roads_clipped = gpd.clip(roads, boundary)gpd.clip的第二个参数可以是 GeoDataFrame,也可以是单个几何对象。裁切后要检查要素数量和总长度,如果总长度比原始数据少很多,可能是边界 shp 的坐标系与路网不一致,先把两者统一到同一 CRS 再裁。
碎线清理是针对那些长度很短的线要素,它们通常是分幅数据接边时产生的半截线段,对路网分析没有价值,还会让统计结果失真。按长度过滤是最直观的办法。需要注意一点:高速和国道的匝道、连接线也可能很短,不能一刀切全删,可以按等级分开处理。
4. 格式转换与互操作:shp转KML、DWG转shp、MapGIS线文件与shp合并
实际项目中,数据不会只在 GIS 软件里流转。给汇报组的可能是 Google Earth 的 KML,给测绘院的可能是 MapGIS 线文件,给设计院的可能是 DWG,还有大量场景要求把点坐标转成 shp。这一章解决的就是格式之间的桥接问题。
4.1 SHP 转 KML:控制输出大小,别把整个属性表都带过去
QGIS 里最顺手的操作是右键图层,选择“导出”->“保存要素为”,格式选 KML。但直接导出经常出现几十上百 MB 的 KML,打开慢、上传慢,放在 Web 前端甚至直接把浏览器卡死。原因很简单:属性表里所有字段都被带进了 KML,每条道路还有一堆历史字段。
我的做法是先复制图层,把不需要的字段删干净,再导出。字段只保留三个:道路名称、等级、线路编号。如果字段多到手动删不过来,可以用如下方式:
import geopandas as gpd gdf = gpd.read_file('shanxi_roads.shp', encoding='utf-8') keep_cols = ['name', 'level', 'code', 'geometry'] gdf = gdf[keep_cols] gdf.to_file('roads_for_kml.shp', encoding='utf-8')然后回到 QGIS 加载这个瘦身后的图层,再做导出。这里建议在导出前用“简化几何”工具,把冗余节点去掉。默认容差可以设 10 米,意思是两点间距小于 10 米的中间点会被移除。高速和国道用 20 米容差基本不影响形态,县道建议 10 米,复杂山区道路不要超过 5 米,否则转弯处会切出直线,看起来像走捷径。
KML 本身要求 WGS84 经纬度坐标系,QGIS 导出时会自动把投影坐标转换成经纬度,不需要你手动做投影变换。导出后的 KML 可以直接拖进 Google Earth 验证,如果后续要转 3D Tiles,可以先把 KML 再转成 GeoJSON,作为中间格式继续处理。
4.2 DWG 转 SHP 与 SHP 转 MapGIS 线文件:两套相反的注意事项
先说 DWG 转 SHP。从设计院拿到的公路 DWG,通常是一堆 CAD 多段线,属性只有图层名和颜色,没有“等级”这种 GIS 字段。在 ArcGIS 里用“快速导入”或 QGIS 里用 DXF 导入,先把线要素拉进来,再导出为 shp。这里最大的坑是 CAD 多段线转过来后带有 M 值,几何类型会显示为PolylineM。如果你后续要用空间分析工具,很多工具不认PolylineM,需要先转成普通Polyline。处理方式是用“修复几何”或者 QGIS 的“多部分转单部分”工具,转完后用gdf.geometry.geom_type.unique()检查类型是否全部变为LineString。
SHP 转 MapGIS 线文件的场景主要在需要提交给地质、矿政类项目时。MapGIS 的老格式是.wl线文件,转换路径通常是:在 MapGIS 的“文件转换”模块里选择“shp 转线文件”,或者反过来在 shp 端用 MapGIS 提供的转换工具。常见问题是字段中文名在转换后丢失,只剩 ID。我的处理顺序是:先把 shp 另存一份,字段名全部改成英文,再将字段值导出为 XLS 表格,转换完成后人工接回属性。多维数组这种转换是数据交换里的无奈选择,保几何不保属性是常态,不要指望它一次到位。
另外,如果同时拿到了“省1”和“省2”两个省界 shp 文件,注意区别通常在于:一个表示省级行政边界线本身,另一个表示省界界桩点或边界标注注记。合并前先单独打开两个文件查看几何类型,一个是线或面,另一个可能是点,不能直接合并。这属于数据源命名差异,不是标准约定,实际操作必须验明正身。
4.3 Excel 坐标点转 shp 与渔网分割
从导航设备或调查表里拿到的道路点位,经常是以 Excel 表格存储的,两列经纬度配上名称。QGIS 里处理最快的方式是用“添加文本数据图层”。加载时注意三件事:第一,X 字段选经度列,Y 字段选纬度列;第二,坐标系下拉框选 WGS84 EPSG:4326;第三,在“几何类型”里选 Point。加载成功后右键导出为 shp,坐标系保持 EPSG:4326,后续需要用投影坐标系再通过“导出要素另存为”做一次坐标变换。
如果拿到的是投影坐标点,比如 X 是 508000 左右、Y 是 3772000 左右的数值,那这些点大概率已经在 CGCS2000 投影坐标系里了,这时添加图层时就不应该选 WGS84 经纬度,而要指定对应的投影 CRS。经验法则:先看数据窗体里坐标值的量级,再决定坐标系,不要盲目默认。
渔网分割 shp 是路网密度分析里很常用的步骤。QGIS 菜单里有“创建渔网”,或者用 ArcGIS 工具箱里的“创建渔网”工具。两个关键参数:渔网宽度和高度,决定了每个网格的大小。做路网密度时,常用的网格大小有 500 米、1000 米、2000 米三档。500 米适合小范围城区项目,1000 米适合县域尺度,2000 米适合全省宏观分析。参数设置完成后运行,生成的是面要素网格,再通过“空间连接”把路网线段的长度或者条数汇总到网格里,就能做密度图了。
4.4 多份 shp 合并:ArcGIS Pro 与 QGIS 的注意点
当你需要把按县交付的多份道路 shp 合成一份省级路网时,合并操作本身不难,难的是合并之前的一致化处理。ArcGIS Pro 里有两个常见入口:一个是“合并”工具,一个是“追加”工具。我推荐用“追加”,因为它按字段匹配,不会因为多出几个字段就报错。但前提是各份数据的坐标系必须统一。如果一部分是 CGCS2000 三度带投影,另一部分是 WGS84 经纬度,合并后坐标就会乱掉,而且很难排查,因为图形还能显示,只是全挤到一片区域或飞得极其远。
合并前建议用 Python 统一检查:
import geopandas as gpd import glob files = glob.glob('city_roads/*.shp') gdfs = [] for f in files: g = gpd.read_file(f, encoding='utf-8') gdfs.append(g.to_crs('EPSG:4547')) combined = gpd.GeoDataFrame(pd.concat(gdfs, ignore_index=True), crs='EPSG:4547') combined.to_file('province_roads_merged.shp', encoding='utf-8')这段代码把每组读取出来的数据都先转成 EPSG:4547(CGCS2000 三度带中央经线 108E),再拼接导出一个统一的 shp。to_crs的目的是消除坐标系差异。如果数据源有的用投影、有的用经纬度,经过这一步后再合并,最终数据就在同一个坐标系下。拼接时也可以顺便检查字段结构:用print(g.columns.tolist())看一眼,如果不同文件字段名不一致,先统一字段名再合并,否则 dbf 属性表会出现大段空值。
5. 避坑:陕西各级公路SHP 实操中的常见问题清单
这一章是我的真实踩坑记录,每条都按“现象—原因—解决”来写。你在处理自己手上的数据时,遇到类似问题可以直接对照排查。
5.1 线与影像有几十米平移,坐标系被默认猜错
现象:加载陕西道路 shp 后叠加天地图影像,道路整体偏离真实位置,偏移量大概二三十米到近百米。放大后能看到观点,比如桥不在河上、路从山体侧面穿过。原因:陕西路网数据多采用 CGCS2000 三度带投影,而部分软件加载无.prj或.prj缺失的 shp 时,默认按 WGS84 经纬度解析,坐标被强行塞进经纬度坐标系表达,自然出现偏移。解决:打开图层属性确认当前 CRS,如果显示 WGS84 且坐标范围不是经纬度量级,手动改成 CGCS2000 三度带中央经线 108E 或 110E。改完后叠加影像验证两次,确认不再偏位再继续工作。
5.2 属性表中文路名显示为乱码或问号
现象:字段名正常,但“西宝高速”“包茂高速”这些中文值全变成??或乱码。原因:dbf 文件用 GBK 编码存储,而 QGIS 默认按 UTF-8 读取;部分 shp 的.cpg文件缺失或写成了1252西文编码,软件无法正确判断字符集。解决:关闭图层,在 QGIS 的数据源管理器中找到这个文件,重新加载时把编码改成GBK或CP936,再打开属性表。确认显示正常后再决定是否另存为 UTF-8 编码的新 shp。这里不要直接在乱码状态下做筛选,因为字符串匹配会失败,筛选结果为空,容易被误判为没有数据。
5.3 高速路网断成几千段,做网络分析对不上
现象:用路网做最短路径或服务区分析时,路径绕远路、掉头,甚至横穿多个不相邻节点。原因:shp 里的高速公路线没有进行拓扑化处理,同一路段被拆成多个没有公共端点的小段,断点处实际存在但属性上看不出来。解决:用 QGIS 的 GRASS 插件里的v.clean工具,先执行snap步骤,把断点吸附到最近的端点,容差可以按道路宽度设,比如 50 米;再执行break步骤,把相交线在交点处打断;最后执行rmdupl清理重复线段。处理完后重新加载跑一遍网络分析,路径结果会正常很多。
5.4 属性只有数字编码,没有可直接读的等级名称
现象:属性表里等级字段显示为1、2、3,或者A、B、C,项目组其他人根本看不懂。原因:交付数据为了压缩属性表体积,采用编码方式存值,完整的编码字典通常在说明文档或单独的表里,没有随 shp 一起交付。解决:先导出属性表查看所有可能的编码值,对照说明文档建一张映射字典表,用“连接属性表”的方式把等级名称接回。字典表可以是 Excel 也可以是 csv,用 QGIS 的“连接图层属性”功能按编码字段关联。关联后一定要检查关联条数和原要素数量是否一致,多对多关联会导致属性重复。
5.5 导出给 ArcGIS 后图层打开是空的或要素数量减少
现象:在 QGIS 里正常的 shp,用 ArcGIS 打开后要素数量变少,甚至整个图层是空的。原因:shp 里可能存在几何错误线,比如自相交线也兼容某些工具却不兼容导出格式;或者某些要素是空的几何对象,属性表里有记录但图形没有坐标。解决:用 QGIS 的“矢量几何检查器”或“修复几何”工具,先跑一遍检查,把空几何删掉,然后对所有线要素执行“修复几何”,修复后另存为新 shp。导出前用gdf.is_valid.sum()判断有效几何数量,如果有效数量和总要素数量不一致,就一定需要先修再导。
6. 验收习惯:把路网数据和影像叠起来,用统计和抽查判定能不能交付
分享一个我现在每次做完陕西路网清洗后都会走的固定流程。第一步是统计各等级道路的条数、总长度和平均长度,取一个能落地的验收基线。第二步是叠加影像抽查,重点看高速和国道是否落在真实道路上,桥梁段是否跨过河流,隧道段是否穿过山体。第三步是跑一次拓扑检查,确认没有重复线段和断头线。这三步走完,这份 shp 才敢说真正能进入分析环节。
统计的代码可以顺便写在下面:
import geopandas as gpd roads = gpd.read_file('province_roads_merged.shp', encoding='utf-8') roads['length_km'] = roads.geometry.length / 1000 summary = roads.groupby('level')['length_km'].agg(['count', 'sum', 'mean']) print(summary)这样输出就是一张按等级汇总的路网信息表。count是条数,sum是总长度公里数,mean是每条线的平均长度。如果某县道平均长度只有一两百米,明显就是碎线过多,需要回到上一步做 dissolve 合并;如果高等级高速的条数非常多,说明数据还是分段存储状态,不能直接用于网络分析。参数上,县道平均长度至少应达到一公里以上才说得过去;国道省道如果分幅交付,平均长度在五到十公里属于正常,再低就要查问题了。
叠加影像这一步没有固定参数,但有个习惯值得养成:不要选固定节点,而是按比例随机抽几条路。例如全省抽 20 条县道、10 条省道、5 条高速,逐条沿路线看一遍。抽查时要留意两个细节:一是有没有和影像完全对不上的路段,二是道路等级和实际形态是否匹配。比如线要素标着高速但走向沿着旧路拐弯,就需要回去查看原始数据是不是混入了低等级路。
从那以后,我每次拿到路网 shp,都会强制走一遍“字段统计 + 影像抽查 + 拓扑检查”这三个步骤,再进入下一环节。这一步看着耗时,实际上一份全省路网数据也就二十分钟,但能拦住表格统计和制图环节的半数返工。希望帮到你,少走一段弯路。
本文还有配套的精品资源,点击获取