简介全国火车站站点位置GIS数据集面向GIS开发、地图制图与铁路数据分析人员解决全国范围内火车站地理信息快速获取与空间分析的需求。压缩包共包含8个文件整体大小仅为405KB采用标准且完整的Shapefile格式组织shp存储车站经纬度坐标shx负责形状索引与快速定位sbn/sbx进一步加速大型数据集的空间检索prj定义坐标系与投影方式dbf保存站名、铁路线、服务类型、所在城市等属性信息cpg指定字符编码以保证中文正常显示xml提供创建者、日期等元数据。用户获得数据后可在ArcGIS、QGIS等主流GIS软件中直接打开快速绘制全国铁路站点分布图进行区域站点覆盖统计、最短路径分析以及铁路线路规划也可作为教学实验或业务系统的底图数据。目前已有393人浏览/学习对于需要标准、轻量、完整国铁站点位置数据的开发者和地理信息学习者是一份可直接落地的实用资源。1. 全国火车站的站点位置 GIS一份比想象中难搞、但做完能省三年的底图数据做交通规划、物流选址或地图可视化的人早晚都会遇到同一件事想把全国火车站的站点位置 gis做成一份能直接落地的图层结果站名好找、坐标难定坐标定了坐标系又对不上。这和普通 POI 完全不同它要过三关坐标准不准、坐标系认不认、属性表能不能跟路局和车次数据关联。这篇笔记就按这三关往下讲怎么把散落的站名整理成 shp怎么选投影参数以及加载天地图、出图、做分析时那些不报错但结果错位的坑。适合 GIS 开发、交通运输分析和规划院从业者也适合刚拿到第一份车站坐标表的新手。2. 把全国火车站坐标整理成 GIS 数据坐标校核、shp 生成与投影转换拿到一份车站名录只是开始。我习惯把落地拆成三步先校核坐标来源再生成标准图层最后统一投影。顺序不能反坐标没校核就去做投影转换错位会被投影计算放大后面排查成本很高。这章给的代码都按最小可跑通来写环境是 Python 3.9、GeoPandas 0.14ArcGIS Pro 用户也能照步骤在界面上完成同样的事。2.1 站点坐标的三类来源怎么选、怎么互相校核全国火车站没有一份官方发布的、带坐标的 shp 在那里等你下载常见做法是把三类公开来源交叉着用。第一类是 12306 的客运车站列表站名和拼音最全但坐标通常要靠地理编码补第二类是 OpenStreetMap 里标注为 railwaystation 的点坐标是 GPS 实测得来覆盖度中等小站经常缺失第三类是天地图或高德的地名搜索接口按站名查坐标速度快但同名站点会解析到错误位置而且高德返回的是 GCJ-02 坐标直接落进 WGS84 底图会偏几百米。来源坐标基准覆盖度主要问题12306 客运车站列表多为 WGS84残缺全坐标常缺失需地理编码补齐OpenStreetMap railwaystationWGS84中上小站遗漏多站名与官方不一致天地图地名搜索CGCS2000高同名站会解析错位高德版需纠偏天地图的 CGCS2000 和 WGS84 在站点定位这个尺度上差异可以忽略所以我把12306 站名 天地图坐标当主来源OSM 当第三方抽检。校核这一步用一个小脚本只做三件事经纬度范围粗筛、按站名聚合去重、把匹配不上官方代码的站单独导出给人查。import pandas as pd df pd.read_csv(stations_raw.csv) # 粗筛中国陆域经纬度范围超出必是脏数据 ok df[lat].between(18, 54) df[lon].between(73, 135) df df[ok].copy() # 按站名拼音聚合坐标取中位数抗离群点 df ( df.groupby([name, pinyin], as_indexFalse) .agg({lon: median, lat: median, num_obs: sum}) ) # 和官方车站代码表比对对不上的单独导出 df[~df[code].isin(station_codes)].to_csv(need_review.csv, indexFalse)这里的 between 边界按我国经纬度范围写的18~54 度北纬、73~135 度东经站名表里出现 0 或 180 这种值说明某一行地理编码失败。groupby 里用 median 而不是 mean是因为同一个车站名可能被第三方数据源记了三五个点中位数能把个别飘点拉回正常位置。最后导出的 need_review.csv 是给人工复核留的清单别嫌多此一举后面所有错位问题都能在这份文件里找到根因。2.2 用 GeoPandas 把站名表转成 shp新建 shp 的最小代码校核完就是新建 shp。两种路径ArcGIS Pro 里可以直接手动新建目录窗格右键 → 新建要素类 → 选点类型、坐标系选 4326再按字段添加 station_code、province 等然后用追加把坐标粘贴进去批量或者要做成可复用脚本时用 GeoPandas 更省事。import geopandas as gpd gdf gpd.GeoDataFrame( df, geometrygpd.points_from_xy(df[lon], df[lat]), crsEPSG:4326, # 来源是 GPS/WGS84 就写 4326 ) gdf.to_file( stations.shp, driverESRI Shapefile, encodingutf-8, )两份代码里最容易被忽略的是 crsEPSG:4326 这一行。不写它GeoDataFrame 没有坐标基准后面一旦调用 to_crs 会直接报错或者按默认 4326 处理看着没报错实际已经错位。points_from_xy 的参数顺序是经度在前、纬度在后写反了整张图会沿对角线飞走这个错位在画布上非常难一眼看出来。生成 stations.shp 后要注意Shapefile 不是一个文件而是 .shp、.shx、.dbf、.prj 至少四个文件一起才算完整。给别人发的时候只发 .shp 是必翻车的操作建议发 zip 压缩包或者干脆导出成 GeoPackage.gpkg一个文件就是一份数据省去漏发 .prj这类低级事故。提示Shapefile 的 .prj 文件记录坐标系信息拷数据时缺失 .prj 会让对方软件按未知坐标系打开站点位置直接不可信。2.3 投影转换WGS84、CGCS2000 与 GCJ-02 三套坐标别乱转全国火车站跨了多个投影带投影转换是绕不开的一步。先记住分工存储和交换用 WGS84EPSG:4326叠加在线底图显示用 Web MercatorEPSG:3857局部距离、面积分析用车站所在区域的高斯投影带或 CGCS2000 的 3 度带。三者混用是大多数看着对、量着错的根因。from pyproj import Transformer # 4326 - Web Mercator叠加天地图/在线底图用 t_wm Transformer.from_crs(EPSG:4326, EPSG:3857, always_xyTrue) x, y t_wm.transform(116.42, 40.08) # 4326 - CGCS2000 3 度带例如中央经线 117 的 39 带 t_gk Transformer.from_crs(EPSG:4326, EPSG:4548, always_xyTrue) gk_x, gk_y t_gk.transform(116.42, 40.08)always_xyTrue 表示输入输出都是经度、纬度的顺序不写它时 pyproj 会按纬度、经度解释两个数一换位站点就跑到海里。EPSG:4548 是 CGCS2000 3 度高斯投影 39 带中央经线 117 度覆盖华北大部分车站做北京市或京津冀的缓冲区分析够用往西到山西就得换 38 带中央经线 114。全国尺度的面积统计则选 Albers 等积投影各 GIS 软件预设里都有别用一个固定高斯带去量全国面积。还有一类常见错误是把改坐标当转坐标。GeoPandas 里直接给 gdf.crs 赋新值只是给数据贴标签没有重算坐标只有 gdf.to_crs() 才真正做了投影转换。ArcGIS Pro 里对应的是投影工具而不是定义投影用错一次全国站点就会整体平移几十米到几百米而且越往高纬度越明显。至于高德那类 GCJ-02 坐标我的建议是站点数据不要碰火星坐标纠偏算法网上到处都是但让非测绘同事在数据链路里自己纠偏十个有九个会在下一轮更新时忘了纠直接拿 GCJ-02 的经纬度写进 WGS84 的 shp。3. 站点图层加载与出图天地图底图、地图切片包与图例换行数据就绪后第一步是把它叠到真实地理底图上不然全国站点图就是一堆悬浮的点。这章讲我在 ArcGIS Pro 里三个高频操作接天地图底图、出切片包、调图例。前两个跟缓存和保存位置有关第三个是出图前必碰的细节。3.1 ArcGIS Pro 加载天地图底图失败按四步排查加载天地图在线底图的常规路径是插入 → 连接 → 服务器 → WMTS 服务器把天地图申请的密钥拼进服务地址然后选择影像、矢量或注记图层。很多人卡在这一步现象是gis pro 在线地图加载不了具体有四类表现连接后空白、图层黑色、报服务不可用、叠加站点时偏移。我一般按顺序排查先在服务地址里确认密钥 tk 已拼上且申请时勾选了对应服务再确认选择的图层类型影像服务用影像的地址矢量服务用矢量的地址混着用会出现黑块第三步看坐标系弹出对话框里输出坐标系选 Web Mercator3857不要选 4326天地图的 WMTS 在 4326 下经常不渲染最后清缓存之前加载失败留下的坏缓存会一直让新图层保持空白在工程选项里把缓存目录清掉再重连。现象优先排查项处理连接成功但空白缓存损坏 / 坐标系 4326清缓存改用 3857图层全黑影像与矢量服务地址混用按服务类型换地址报服务不可用密钥没生效或没勾服务回天地图控制台核对密钥叠加站点整体偏移底图是 3857站点还是 4326站点图层用投影或让底图转 3857最后一种偏移不是加载失败是投影没对齐但表现很像底图坏了。把工程地图框坐标系直接设为 3857让站点图层按实时投影显示通常立刻就好。3.2 创建地图切片包改掉默认 C 盘输出位置出图交给同事或交付给领导时直接发工程文件依赖数据路径容易断链。常见做法是创建地图切片包把站点图层和天地图底图一起打包成离线切片。操作路径是共享 → 网图 → 创建地图切片包按向导选 Level 范围和切片格式在包存储文件夹这一步能看到默认路径总是 C 盘用户目录。这就是拷贝的 gis 地图包自动保存在 c 盘的真相ArcGIS 的默认包存储和临时工作空间都在系统盘用户目录。解决方式有两个一个是工程 → 选项 → 共享里把包的默认存储文件夹改到数据盘的项目目录另一个更稳妥向导最后一步手动指定 D 盘输出不点默认。切片包生成后是单个文件拷贝给别人双击就能叠加显示不用再担心相对路径断链。还有一类强制改 C 盘的位置是分析环境里的临时工作空间。栅格转面、缓冲分析默认把中间结果写到 C 盘 Temp跑全国站点这类几千个要素的操作经常把 C 盘塞满。在 ArcGIS Pro 的分析环境里统一把临时工作空间和 Scratch 工作空间指到项目文件夹能少清好几次磁盘。3.3 图例标签换行标注表达式与转图形两个办法站点图例里北京南站BJP这类长标签默认一行放不下图例项会自动压扁或者截断这时候要手动换行。我在 ArcGIS Pro 里常用两个办法。第一个是改标注表达式在站点图层的标注表达式里把站名和代码拼成两行换行符用 Python 表达式定义图例会跟着标注走而且是动态的数据更新后不用重画def FindLabel([station], [code]): return [station] \n [code]这段表达式里 station 和 code 是属性表字段名\n 在标注引擎里就是强制换行。需要注意标注表达式用的是 ArcGIS Pro 的 Python 解析器字段名用英文不要用中文列名否则中文环境下解析器会把中文字段识别成变量名导致整段表达式报错。第二个办法是只出一次图、不再更新的情况右键图例 → 转换为图形然后双击文本块在光标处回车换行。这个办法最直接但转完图形后图例和图层就失去关联了数据一变图例不会跟着变属于一次性出图的救急手段不适合要反复出周报的场景。4. 站点 GIS 数据的落地应用缓冲区、面积核算与地图下钻数据整理干净了接下来是拿它干活。我挑三个最常见、也最容易因为参数选错而白跑的场景讲缓冲区覆盖分析、栅格转面加面积平差、地图下钻。4.1 用缓冲区做站点覆盖分析先看坐标系再定半径给站点做覆盖分析需求通常是火车站周边三公里覆盖了多少人。这个需求一句话坑却很深直接在 WGS84 的经纬度点图层上做缓冲区buffer(0.05) 是 0.05 度不是 50 米而且在全国不同纬度同样 0.05 度对应的实际距离差得离谱。# 先把站点投影到以米为单位的坐标系再做 3000 米缓冲 gdf_m gdf.to_crs(EPSG:3857) buf gdf_m.buffer(3000) # 半径 3000 米 cov gpd.GeoDataFrame(geometrybuf, crsEPSG:3857) # 多个站点缓冲面压在一起要去重合并再算覆盖 whole cov.dissolve() print(whole.area.sum() / 1e6, 平方千米)这里用 3857 是图省事画面上叠加天地图没问题但 3857 在高纬度有面积变形华北测还算能接受放到东北或新疆做面积统计就不够用了。严谨做法是分区域用 CGCS2000 高斯投影带华北用 39 带、东北用 45 带左右每个站选自己所在 3 度带重新缓冲最后再把结果统一转回 4326 展示。dissolve() 这一步容易被忽略两个站半径内的覆盖区重叠不合并直接求和会重复计算重叠面积覆盖人口会虚高。4.2 栅格转面与面积平差找回丢失的两位数面积站点周边的用地分类图经常是栅格比如从遥感影像分类出来的建设用地、农田范围落进 GIS 要算面积就得先把它转成矢量面。ArcGIS Pro 里栅格转面的位置是地理处理 → 转换工具 → 从栅格转出 → 栅格转面。前提是栅格必须是整型浮点栅格要先重分类成 0、1、2 这类整数否则每个像元都会变成独立的面碎面数量能把图层卡死。转面后的面积计算有个经典坑栅格本身没投影、或投影坐标系和输出坐标系不一致时面积是按度算的和上报口径完全对不上。处理顺序应该是转面前先把栅格投影到高斯或等积投影转面后按分类字段 dissolve最后用计算几何算面积。涉及用地面积上报比如永久基本农田这类两位数面积口径还要做平差拿计算总面积和实测或上报总面积求一个比例系数把每个面的面积乘上这个系数保证总和与口径一致再四舍五入到两位小数。# 面积平差比例系数 已知总面积 / 计算总面积 k known_total / calc_total # 每个要素平差后面积 area_adjusted area_gdf[area] * k平差不是调每个面的大小而是给所有面乘同一个系数保留原来的空间比例。操作顺序很重要先合并碎面再平差否则碎面数量会影响面积总和四舍五入必须放在平差之后先四舍五入再乘系数尾差会累计到不可控。注意先平差再四舍五入反过来会让每个面的尾差积累最终合计和上报口径永远对不上。4.3 地图下钻省—市—站点三级联动怎么做地图下钻是站点数据展示里最常见的交互全国一张图点击某个省只看这个省的站点再点市再缩到区县。这个功能在 ArcGIS 里可以用书签和可见性组合硬做但可维护性太差我一般导出 GeoJSON用 Leaflet 做前端联动代码量小且刷新快。站点点数据先按下钻字段做过滤前端逻辑很简单省级面图层绑一个点击事件根据点击省份的名称从站点 GeoJSON 里筛出对应点再刷新点图层。// stations 是已加载的全国站点 GeoJSON provinceLayer.on(click, function (e) { const name e.layer.feature.properties.name; const filtered stations.features.filter(f f.properties.province name ); stationLayer.clearLayers(); stationLayer.addData(filtered); // 只显示当前省的站点 });这里的先决条件是 shp 属性表里预填好 province 字段且取值和省级面图层 name 字段完全一致。我踩过最尴尬的一次是省名带省字、站点表不带全图点下去一片空白排查半天发现是两个字段口径不一致。做下钻的图层先用 GeoJSON 导出而不是 shp 也能省点事绕开编码问题。如果项目里用的是 Anylogic 这类仿真平台导入 GIS 底图的思路也一样先把这个 shp 导出成它认的格式字段名全部用英文数据源头统一后面对接才不会反复改。5. 全国火车站站点数据的避坑记录坐标偏移、C 盘乱存与文件损坏这章是血泪汇总。每一条都是真实环境里出现过的按现象 → 原因 → 解决写照着排查能少走弯路。5.1 转 CAD 后坐标整体偏移几百米现象站点图层在 GIS 里叠得严丝合缝导出成 DXF 发给设计院后整个路网平移了几百米。原因源图层是经纬度 4326导出 CAD 时经纬度被当成米直接写进去了坐标值只有 116 这种量级CAD 里看起来就是一条线贴在原点附近放大后和底图完全错位。解决导出前先把图层投影到 CGCS2000 的高斯投影带或者在 ArcGIS 导出到 CAD 的对话框里把输出坐标系明确指定为投影坐标系不要留当前地图框坐标系默认值。CAD 端打开后先确认单位是米再按坐标插入基本就不会再漂。5.2 拷出去的地图包自动存 C 盘现象别人发来的地图包双击打开数据全出现在 C 盘个人目录自己创建的包默认也往 C 盘写。原因ArcGIS 的包存储文件夹和临时工作空间默认都在系统盘用户目录工程设置没改的话包会先解压或保存到那里。解决在工程 → 选项 → 共享里改包存储文件夹在分析环境里把临时工作空间和 Scratch 工作空间指到项目目录。修改后再创建切片包输出路径就不会再自动跳回 C 盘。已经存到 C 盘的旧包直接剪切到数据盘后重新打开一次让工程把新路径记下来即可。5.3 shp 发给别人后属性表乱码现象用 GeoPandas 按 utf-8 写的 shp自己打开正常对方用 QGIS 或其他 GIS 打开中文站名全乱。原因Shapefile 的 dbf 属性表编码没有统一标准软件只能按系统语言猜测ArcGIS 和 QGIS 的默认猜测逻辑不一样utf-8 写出去遇到默认按 GBK 读的软件就乱码。解决给国内同事发数据写 shp 时用 gbk 编码更省事或者干脆发 GeoPackage 或 File Geodatabase这两种格式编码内建没有这个玄学问题。已经乱了的文件在 QGIS 图层属性里手动改编码为 utf-8 可以救回来。5.4 栅格转面后面积对不上现象栅格转面后各分类面积合计和栅格属性表里统计的值差一大截有时差出数倍。原因栅格没有正确投影面积按度计算或者栅格是浮点型没有重分类每个像元一个面dissolve 之前碎面把统计搞乱了。解决转面前确认栅格已投影到高斯投影或等积投影坐标系浮点栅格先重分类成整型转面后按分类字段 dissolve 一次再算面积。面积平差的逻辑按 4.2 的公式来先平差后四舍五入。5.5 天地图在线底图加载后一片空白现象WMTS 服务添加成功图例和数据目录里都有这个图层地图窗口里就是一片空白。原因加载失败留下的坏缓存会持续干扰后续加载或者输出的坐标系选了 4326而该服务只能用 3857 正常渲染还有一种是密钥申请时没开通这个具体服务类型。解决先删除图层在工程选项里清缓存再用 3.1 的四步重连坐标系固定选 3857。密钥服务类型的问题回天地图控制台把要用的影像、矢量、注记服务都勾上重新生成一个 key 再拼地址。6. 进阶给站点数据加一个增量更新管道坐标自动校验站点不是静态数据铁路每年都新增站、改名站。全量重新整理一遍成本太高我给自己留了一个增量更新管道上一版干净数据存一份新拉到的名单只对增量做地理编码更新完自动跑一遍坐标范围校验把今天新增了哪些站、改了哪个站写进 changelog。这样每次出图前跑一次心里有底。6.1 增量更新脚本schema 固定与 changelog 必留import pandas as pd from datetime import date old pd.read_feather(stations.ftr) # 上次处理完的干净数据 new fetch_stations_from_source() # 本次拉到的站名表 new geocode_missing(new, old) # 只对新增站做地理编码 merged ( pd.concat([old, new]) .drop_duplicates(code, keeplast) # 同一车站代码保留新数据 ) merged validate_coords(merged) # 经纬度范围 18-54 / 73-135 merged.to_feather(stations.ftr) # changelog 是给下游的后悔药 merged[merged[update_date] date.today()].to_csv(changelog.csv, indexFalse)这个脚本有三个参数值得盯住update_date 字段必须每条记录都带否则 changelog 无法区分今天新增和上季度就存在的站drop_duplicates 的 keeplast 保证同一车站代码下老坐标被新坐标覆盖但前提是 old 排在前面、new 排在后面concat 顺序不能倒geocode_missing 只对新增站调地理编码接口全量重编码既费配额又会把已经人工校核过的坐标冲洗掉。我现在每周跑一次跑完会盯着 changelog 看两分钟凡是出现同名站换坐标的记录都会回到天地图和 OSM 交叉确认一遍。这条习惯救过我一次——某次更新后华东某站平移了十来公里如果没有 changelog我就直接拿着错位数据出图了。给全国火车站这类长期维护的 GIS 数据建立管道核心不是自动化而是每次改动都留痕、每个坐标都有来源。希望帮到你你也可以在自己的项目里把流程改造成适合自己的数据源。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?