简介面向地理信息系统使用者与交通规划研究者这份陕西各级公路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 位数字比如 X36500000Y3800000那基本可以确定是投影坐标系而且很可能是 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如果中文乱码尝试 encodinggbk roads gpd.read_file(shanxi_roads.shp, encodingutf-8) print(roads.columns.tolist()) print(roads.crs) # 筛出高速和国道用于干线分析 trunk roads[ roads[level].astype(str).str.contains(高速|国道|G) ].copy() # 按等级字段溶解合并减少碎线数量 trunk_dissolved trunk.dissolve(bylevel, as_indexFalse) # 导出为新的shp文件 trunk_dissolved.to_file(shanxi_trunk_roads.shp, encodingutf-8)这段代码建议细致说明一下。读取时encodingutf-8是告诉 geopandas 用 UTF-8 解码 dbf 属性表如果打开后中文路名都是乱码就改成encodinggbk重读因为很多 shp 里的中文字段实际是 GBK 编码。astype(str)是把字段统一转成字符串再做筛选这样既避开整型和字符型不匹配的问题也能用包含匹配来处理“高速”、“G65”这类混合值。dissolve(bylevel)会把相邻的同等级线段合并成一条连续要素适合做路网概况图但要注意它也可能把相距很远的同等级线段合并如果你需要的是逐条路线的拓扑关系这一步要谨慎使用。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, encodingutf-8) keep_cols [name, level, code, geometry] gdf gdf[keep_cols] gdf.to_file(roads_for_kml.shp, encodingutf-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, encodingutf-8) gdfs.append(g.to_crs(EPSG:4547)) combined gpd.GeoDataFrame(pd.concat(gdfs, ignore_indexTrue), crsEPSG:4547) combined.to_file(province_roads_merged.shp, encodingutf-8)这段代码把每组读取出来的数据都先转成 EPSG:4547CGCS2000 三度带中央经线 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, encodingutf-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都会强制走一遍“字段统计 影像抽查 拓扑检查”这三个步骤再进入下一环节。这一步看着耗时实际上一份全省路网数据也就二十分钟但能拦住表格统计和制图环节的半数返工。希望帮到你少走一段弯路。本文还有配套的精品资源点击获取