武汉路网Shp数据在ArcGIS中的处理:坐标、清洗与密度分析 简介本资源是武汉市路网矢量数据包面向GIS开发、城市规划及交通分析等需要武汉市陆路交通与行政边界的ArcGIS用户。数据提供武汉市道路矢量图层、各行政区和武汉市边界图层不含地铁、铁路、水路、航空专注陆路路网便于直接进行路网可视化、缓冲区分析或与人口、土地利用等数据叠加。包体共21个文件以shp、dbf、prj、sbn、sbx、shx、xml等类型为主shp为矢量主体dbf存储属性信息prj定义坐标系sbn与sbx为空间索引shx为几何索引xml保存元数据压缩包整体3.45MB结构清晰便于按图层调用。目前已有2926人学习下载适合需要快速获取武汉市基础路网底图的研究者或项目开发者省去从零整理数据的繁琐过程直接加载到ArcGIS中即可开展后续分析。1. 一份能直接落地的武漢路網 shp先回答三個使用前提做城市道路分析最耗時間的往往不是分析本身而是找一張能直接信任的底圖。這份武漢市路網矢量數據 shp就是把「找數據、下載、校準、清洗」這四步壓縮成「導入 ArcGIS 就能用」的資源——它表面上看只是一組線圖層實際上決定了你後續做長度統計、緩衝區分析、路網密度計算時結果到底能不能拿出去說明問題。我在拆這類路網數據時會先確認三個前提第一shapefile 附屬文件是否完整缺了 .prj 後續座標系全亂第二數據用的什麼座標基準這直接影響跟影像底圖疊加時是否整體漂移第三屬性表裡有沒有可用的道路等級字段沒有字段就只能畫圖做不了統計。如果你是 GIS 課設、規劃前期選址、數據可視化 demo 的參與者這份數據的性價比在於它把「能不能用」的不確定性降到最低剩下的是你自己要會的 ArcGIS 操作。2. 導入與出圖讓 shp 在 ArcGIS 里真正「能看」2.1 從壓縮包到圖層導入四步走先明確一件事shapefile 不是單個文件而是至少三個文件組成的集合。.shp 存幾何、.dbf 存屬性、.shx 存索引缺了任何一個ArcGIS 要麼打不開要麼屬性表一片空白。如果壓縮包裡還有 .prj 和 .cpg那是最好的情況——前者記錄座標系後者記錄屬性編碼。我拿到數據的第一步永遠先列目錄確認這幾兄弟是否齊全import os from pathlib import Path data_dir Path(rD:\gis_data\wuhan_road) base_name road_network exts [.shp, .shx, .dbf, .prj, .cpg] for ext in exts: f data_dir / (base_name ext) print(f.name, -, OK if f.exists() else MISSING)這段用於「驗屍」。base_name 必須和主文件實際名稱一致比如實際叫 wuhan_road.shp就寫 base_name wuhan_roadexts 列表裡 .cpg 缺失不一定致命但往往伴隨屬性亂碼。打印結果若是 MISSING先別往 ArcGIS 裡拖補齊來源再繼續。確認文件齊全後導入本身沒有技術含量打開 ArcCatalog用「資料夾連接」指向解壓目錄右鍵圖層預覽幾何和屬性然後直接拖進 ArcMap。這裡有一個我反覆踩過的細節——目錄路徑不要帶中文也不要放在桌面這種帶空格的位置。某些環境下 dbf 的編碼識別會被中文路徑干擾表現為屬性表裡中文變亂碼而文件本身其實是好的。把數據放到 D:\gis_data 這種純英文路徑下是最廉價的排錯手段。2.2 座標系統一CGCS2000、WGS84 與 Web Mercator 的選擇武漢市經度在 114°E 附近國產地理數據最常見的座標基準是 CGCS2000投影方式多為 3 度分帶高斯-克呂格投影武漢落在第 38 帶也就是中央經線為 114°E 的那一帶。但也有部分資源直接用 WGS84 經緯度存儲加載時被 ArcGIS 當成未知座標系或者被默認成 Web Mercator於是疊底圖時整張路網平移幾百米甚至上千米。判斷當前座標系最穩的辦法是讓 ArcGIS 自己讀 .prj 文件並告訴你結果import arcpy arcpy.env.workspace rD:\gis_data\wuhan_road sr arcpy.Describe(road_network.shp).spatialReference print(sr.name) print(factoryCode:, sr.factoryCode) print(linearUnits:, sr.linearUnits)這一段的關鍵參數是 linearUnits——如果返回 Meter說明是投影座標系長度可以直接算如果返回 Degree說明是地理座標系直接算長度是錯誤的。factoryCode 對應 EPSG 編號但在國產數據裡有時返回 -1 或 0表示 .prj 缺失或內容不標準這種情況下需要手動定義投影。定義投影和投影變換是兩件事。數據有幾何但缺座標系用「Define Projection」補數據有座標系但需要換到另一種用「Project」工具。如果你的底圖是 Online 地圖Web Mercator路網是 CGCS2000 3 度帶直接疊加會因橢球和投影差異產生偏移常見做法是先把路網通過 Project 轉到 Web Mercatorimport arcpy arcpy.Project_management( in_datasetrD:\gis_data\wuhan_road\road_network.shp, out_datasetrD:\gis_data\wuhan_road\road_network_wm.shp, out_coor_systemPROJCS[WGS_1984_Web_Mercator_Auxiliary_Sphere, GEOGCS[GCS_WGS_1984,DATUM[D_WGS_1984, SPHEROID[WGS_1984,6378137.0,298.257223563]], PRIMEM[Greenwich,0.0],UNIT[Degree,0.0174532925199433]], UNIT[Meter,1.0]], transform_method)注意 out_coor_system 我直接寫了完整 WKT避免依賴 ArcGIS 的座標系庫能否正確識別國產名稱。transform_method 在跨基準轉換時要填CGCS2000 與 WGS84 差異很小很多場景為了省事留空但如果你手上的數據疊加後仍在影像上偏十幾米就要補上七參數轉換而不是靠手動平移硬湊。2.3 出圖前必做的符號化按道路等級渲染導入和座標都正常後第一個讓數據「像樣」的操作是符號化。路網數據最忌諱不分等級全畫成同一條細黑線——那既看不出城市骨架也讓後續溝通過程變得非常糟糕。ArcGIS 裡的操作是雙擊圖層打開 Layer Properties在 Symbology 分類中選擇 Categories Unique valuesValue Field 選擇道路等級字段比如 CLASS 或 ROAD_LEVEL再手動調整每類的線寬和顏色。我通常用一套固定的配色思路高速公路用橙色粗線寬度 2.5 左右主幹道用紅色寬度 1.8次幹道用黃色寬度 1.2支路用淺灰寬度 0.8。這套規則不是什麼標準但它貼合導航地圖的視覺習慣開會投影時別人掃一眼就知道城市骨架在哪。符號化前還要做一件事查看等級字段到底有哪些值。有時候字段裡的類別是數字編碼比如 1、2、3需要對照圖層說明才能映射成主幹道、次幹道、支路。可以用屬性表的 Summarize 統計也可以跑一句快速代碼import arcpy fc rD:\gis_data\wuhan_road\road_network.shp with arcpy.da.SearchCursor(fc, [CLASS]) as cursor: values set(row[0] for row in cursor) print(sorted(values))這裡使用 SearchCursor 遍歷全部要素的 CLASS 字段集合去重後直接得到所有類別值。看到數字編碼時別急著當成無效數據——先對照資源附帶的說明文件找不到說明的把數字類別和 NAME 字段結合起來看比如 1 類路的名字大多是「某某大道」「某某高速」基本能反推含義。3. 屬性表拆解與清洗字段決定了你能算什麼3.1 一張路網 shp 的屬性表裡通常有哪些字段路網矢量數據的屬性表一半的價值在字段。不同來源的 shp 字段命名差異很大但核心信息就那幾類。拿到表後先別急著統計先看字段再動手。常見字段如下字段名類型常見含義使用注意FID / OBJECTID長整型要素唯一編號不參與分析但可作為關聯鍵NAME / RN_NAME字符串道路名稱可能為空也可能多條道路同名CLASS / ROAD_LEVEL字符串或整型道路等級先確認是文本還是數字編碼ROAD_ID整型道路邏輯編號同一條路多段要素常共用一個 IDSPEED整型設計速度或限速城市內有值郊區可能大量為空WIDTH浮點型道路紅線寬度單位需確認是米還是公里SHAPE_LEN雙精度幾何長度依賴座標系地理座標系下不可直接使用這張表對應的是一個「能直接分析的理想情況」。實際拿到的數據可能有字段更少、命名不一致、或者把等級和名稱混在一個字段裡的情況這很正常。我的經驗是先確認 NAME 和 CLASS 兩個字段可用其他字段是可選的加分項。NAME 用於抽樣驗證時對照真實地圖CLASS 用於分級統計缺了這兩個數據的可用性要打對折。3.2 空值、重複與斷頭線清洗的三個重點路網數據不是下載完就能直接算。第一類問題是空值NAME 字段空著的要素在分析時往往被忽略但它們是真實存在的道路忽略會讓長度偏小。第二類是重複同一條道路被多次複製或者不同要素共用同一個 ROAD_ID統計時會重複計入。第三類是幾何層面的「斷頭」線段端點沒有與其他線段連接在後續網絡分析裡就是斷路。先用 Python 對屬性和重複做一次體檢import geopandas as gpd gdf gpd.read_file(rD:\gis_data\wuhan_road\road_network.shp) print(要素總數:, len(gdf)) print(gdf[[NAME, CLASS]].isnull().sum()) dup gdf[gdf.duplicated(subset[ROAD_ID], keepFalse)] print(有重複 ROAD_ID 的要素數:, len(dup)) invalid gdf[~gdf.geometry.is_valid] print(幾何無效要素數:, len(invalid))這裡使用 geopandas 讀取 shpisnull 統計字段空值duplicated 按 ROAD_ID 查找重複is_valid 檢查幾何是否自相交或退化。注意 duplicated 的 subset 參數要用你確認存在的字段如果屬性表裡沒有 ROAD_ID改用 NAME。幾何無效的要素一定要處理它們在緩衝區和相交分析裡可能產生極端結果。空值的處理我一般按場景區分做總長度統計空值要素保留但標記做逐路統計空值 NAME 的可以合併到「未命名道路」組。重複要素的處理是另一回事不能直接刪——先看重複的 ROAD_ID 對應的幾何是否完全一致如果幾何一致是複製導致的重複直接刪如果幾何不一致說明同一邏輯道路被拆成了多條保留幾何。刪除重複要素時保留幾何完全一致的 FID 較小者用 drop_duplicates 即可gdf2 gdf.drop_duplicates(subset[geometry]) print(去重後要素數:, len(gdf2))在 geopandas 中對幾何列做去重可行但要注意float 精度可能讓「本該一致」的線段被判為不同。更穩的替代方案是先把幾何轉成 WKT 字符串再比對但需要引入 shapely 的轉換這裡用不上就不過度設計了。實際操作時我更多是確定重複模式後回到 ArcGIS 用屬性表選中重複項逐個看幾何位置來決定刪除與否。3.3 統計道路總長度與分等級里程有了乾淨的屬性和可信的座標系統計才有意義。長度統計的前提是投影座標系武漢數據用 CGCS2000 3 度帶或 UTM 50N 都可以但不要用地理座標系也不建議用 Web Mercator——後者在高緯度變形嚴重統計出來的路網長度比真實值小不少。先轉到合適的投影再算長度import geopandas as gpd gdf gpd.read_file(rD:\gis_data\wuhan_road\road_network_wm.shp) gdf gdf.to_crs(EPSG:3857) # 僅作演示正式統計不建議 gdf[length_km] gdf.geometry.length / 1000 summary gdf.groupby(CLASS)[length_km].agg([sum, mean, count]) print(summary.round(1))注意我在代碼裡標註了「正式統計不建議」——這行是演示如何把長度算出來不是推薦做法。實際項目裡如果原始數據就是 CGCS2000 3 度帶投影直接在此座標系下算長度即可不需要再轉。分組統計的關鍵是 groupby 的字段要和實際等級字段對上CLASS 是字符串還是數字會影響分組結果的顯示順序。輸出三列sum 是該等級總里程mean 是平均每段長度count 是路段數——這三個數字能幫你判斷數據是否合理比如主幹道 count 只有幾十條對一個大城市來說可能代表數據被過度合併了。4. 避坑與排查路網數據四個「一踩一個準」的雷4.1 疊底圖時整張路網平移了幾百米現象是路網線條能顯示位置看起來也對但和影像底圖疊加時整體往某個方向偏離有時偏兩百米有時偏一公里以上。原因幾乎都是座標系不統一路網本身是 CGCS2000 或 WGS84 地理座標ArcGIS 沒讀到 .prj默認按 Web Mercator 顯示或者路網是 CGCS2000 3 度帶而你直接疊到了未設置投影的空白地圖上。解決辦法是先 Describe 確認座標系缺失就用 Define Projection 補上正確的座標系然後用 Project 轉到與底圖一致。不要手動移動圖層硬湊那不是解決問題只是把錯誤藏起來後續分析全會被污染。4.2 屬性表里的中文全是亂碼現象是打開屬性表NAME 字段顯示為「????」或一組無意義的字符。原因是 dbf 文件內部編碼與 ArcGIS 讀取時使用的編碼不一致常見情況是數據用 UTF-8 存儲而 ArcGIS 按 GBK 讀取或者反過來。解決辦法分兩步先看壓縮包裡有沒有 .cpg 文件有就打開看裏面寫的是 UTF-8 還是 GBK沒有就自己新建一個同名 .cpg 文件內容寫UTF-8放在 shp 同目錄下重新加載。如果無效用 QGIS 打開試試它能自動識別更多編碼在 QGIS 中導出時把編碼明確指定為 UTF-8再回到 ArcGIS 加載這是我在跨軟體協作時最常用的辦法。4.3 道路在交叉口不交匯緩衝區和密度分析質量很差現象是做緩衝區時相交道路各自出各的圈互相不連通做路網密度時網格內道路長度明顯偏小。原因往往不是數據不準而是路網是「雙線表達」或「未在節點處打斷」——兩條路在空間上相交但幾何上沒有共享節點。解決辦法是在分析前先對路網執行「在交點處打斷線路」操作。ArcGIS Pro 中用 Geoprocessing 面板搜索「Planarize Lines」ArcMap 中也可以用「Intersect」工具把同一份路網自己和自己相交輸出線要素再把原數據的屬性連接回去。這一步是路網分析的地基跳過它後面所有基於連通性的分析都不可信。4.4 全圖縮放卡成幻燈片現象是加載後縮放到全圖範圍軟體每動一下就轉圈放大到局部反而流暢。原因是要素數量過多且圖層沒有空間索引或者索引過期。解決辦法是先做一次「重建空間索引」在 ArcCatalog 裡選中圖層在屬性裡找到 Index 標籤重建空間索引。另一個容易被忽略的原因是符號化時給每個要素做了複雜的緩衝陰影效果把符號化簡化成單一線條後再試。如果仍然卡說明要素數到了幾十萬級別此時要麼按行政區切割成多個圖層分區顯示要麼轉成 File Geodatabase 的要素類來讀取後者的讀取效率通常高於直接挂接 shp。5. 從 shp 到分析結果密度、緩衝區與中心線5.1 路網密度計算漁網與相交的組合拳路網密度是城市分析裡出鏡率極高的指標定義很簡單單位面積內的道路總長度單位是 km/km²。計算思路是先把研究區劃成規則網格再統計每個網格內的道路長度。手動畫網格不可取用 ArcGIS 的 Create Fishnet 工具生成 1km×1km 的漁網import arcpy arcpy.env.workspace rD:\gis_data\wuhan_road arcpy.env.overwriteOutput True arcpy.CreateFishnet_management( out_feature_classgrid_1km, origin_coord438000 3331000, y_axis_coord438000 3332000, cell_width1000, cell_height1000, number_rows, number_columns, labelsNO_LABELS, templateroad_network.shp, geometry_typePOLYLINE )CreateFishnet 的關鍵參數是 origin_coord 和 y_axis_coord這兩個點決定了網格的起始位置和旋轉方向必須和路網在同一座標系下否則錯位。template 參數直接指定路網它會讓網格範圍自動貼合路網的範圍省去手動調整的麻煩。geometry_type 這裡用 POLYLINE輸出網格邊界線也可以改成 POLYGON 輸出網格面看你下一步怎麼用。網格建立後把路網和網格做相交讓每一段道路都被打上它所在網格的編號arcpy.analysis.Intersect( in_features[[road_network.shp, ], [grid_1km, ]], out_feature_classroad_grid_intersect, join_attributesALL, output_typeLINE )Intersect 輸出的線段會帶上兩邊的全部屬性其中網格面的 FID 就是網格編號。接著用 Summary Statistics 按網格編號統計道路長度的總和再跟網格面積換算成密度。這一步最隱蔽的問題是網格邊界上的道路被切分後長度精度取決於 Intersect 是否在切割點處光滑處理一般不用過度擔心因為 1km 網格切分導致的誤差遠小於數據本身的採集誤差。5.2 道路緩衝區與城市覆蓋率緩衝區是路網數據應用的第二個常見場景。它回答的問題是城市道路兩側多少範圍內是「可達區域」。不同等級道路對出行的重要性不同緩衝距離也要不同——這是我特別強調屬性字段價值的地方。沒有 CLASS 字段你只能全路網統一做 500m 緩衝結果粗糙得多。import arcpy arcpy.env.workspace rD:\gis_data\wuhan_road buffers [] for cls, dist in [(1, 800), (2, 500), (3, 300), (4, 150)]: out_fc fbuf_{cls} arcpy.analysis.Buffer( in_featuresroad_network.shp, out_feature_classout_fc, buffer_distance_or_fielddist, dissolve_optionALL ) buffers.append(out_fc) arcpy.management.Merge(buffers, buffer_all)這里的核心是把按等級的緩衝結果合併成一個圖層。dissolve_option「ALL」讓同一等級內的重疊緩衝區融成一體避免面積重複計算。距離參數 800/500/300/150 是經驗值不是標準——如果你做的是 15 分鐘生活圈距離要縮小做的是全市道路影響評估就放大。合併後用幾何面積減去水域等不可達區域就能算出道路緩衝區覆蓋率。這個指標常用於評價城市服務均衡性但它對路網的連通性極度敏感如果沒做第 4.3 節的節點打斷結果會略偏小。5.3 中心線提取與線路簡化很多路網數據為了表現道路寬度用雙線或面狀表達這在可視化上好看但做網絡分析時必須得到單線中心線。ArcGIS 提供 Collapse Dual Lines To Centerline 工具專門處理雙線道路的塌縮問題輸入雙線要素輸出中間的軸線。參數裡有一個 Maximum Width 的選項表示雙線之間最大距離超過這個距離的雙線不會被塌縮——這個值要根據數據實際情況調整城市主幹道的雙線間距往往大於支路設太小會漏掉主幹道。中心線提取完成後下一步是簡化。原始路網的節點往往過密用來做緩衝區沒問題但用來出小比例尺圖件或發布 Web 服務會讓文件體積和渲染時間膨脹。Simplify Line 工具基於 Douglas-Peucker 算法容差設置 5 米到 20 米比較常見。武漢市中心城區道路轉彎密集容差 5 米幾乎不丟形狀遠城區快速路線形平緩容差可以放到 10 米以上。容差太小的簡化沒有意義容差太大則會把匝道、環島的形狀抹平出圖後被熟悉城市的人一眼看出問題。我一般在簡化前後各算一次總長度簡化後的長度偏差控制在 2% 以內才認為可接受。6. 用一個笨辦法驗證路網質量抽樣對比6.1 隨機抽二十條路逐條和地圖底圖對幾何和屬性都處理完了最後一步是驗證。驗證不需要高深算法最可靠的辦法是抽樣對比。用 Python 從路網中隨機抽 20 條要素導出為單獨圖層加載到地圖裡疊在影像底圖上逐條核對起終點、走向、位置偏差import geopandas as gpd import random gdf gpd.read_file(rD:\gis_data\wuhan_road\road_network.shp) sample gdf.sample(n20, random_state42) sample[name] sample[NAME].fillna(未命名) sample[[name, geometry]].to_file(rD:\gis_data\wuhan_road\check_sample.shp)random_state 固定隨機種子保證每一次驗證抽到的樣本一致方便復盤和別人復現。檢查重點有三項道路是否存在於影像底圖上、走向是否一致、偏移是否在合理範圍。有一條對不上先別急著下結論說數據有問題——可能是數據時效性導致新建道路和拆除道路的差異這種差異在城市擴張區域非常常見。6.2 用交叉口數量做一次快速交叉檢查逐條對比的成本較高想更快可以統計路網節點數和交叉口數做合理性判斷。路網相交節點數量級與道路總長度之間存在經驗比例關係一般城市的路網節點數大致是道路要素數的 1.2 到 1.8 倍。如果相交後發現節點數比要素數量還少說明大量道路相互斷開連通性有問題如果節點數是要素數的幾倍說明道路被切得過碎源數據質量堪憂。這個比例不是嚴格標準但它能快速暴露數據結構的異常。那次我拿到一份路網沒做任何驗證就投入到項目分析裡匯報時被問到「這條路為什麼穿過了水體」我才發現數據和水系沒有做任何空間一致性檢查。從那以後我每次拿到路網 shp都強制走一遍「隨機抽樣 底圖對比 節點比例檢查」三道工序成本不高但能擋住九成以上的低級錯誤。希望這些路徑對你有用。本文还有配套的精品资源点击获取