
简介上海市县区乡镇村各级点位图层资源面向GIS开发、城市规划、数据分析及学术研究人员解决上海行政区划与基层点位空间信息获取难、不完整的问题。压缩包共24个文件核心为4个点要素SHP及其配套DBF属性表、PRJ坐标系、SHX空间索引等覆盖上海市、区县、乡镇、村四级点位矢量结构可直接加载至ArcGIS、QGIS等平台也可通过GeoPandas读取后用于点位分布、辖区分析、热点展示等场景。包体约460KB体量轻但层级全便于快速接入项目。已有173人学习下载。相比手工抠点或第三方接口这套数据统一处理了坐标系与字段结构节省空间数据预处理时间村点与乡镇点可作为基层治理、网格化分析等精细尺度研究的基础底图区县与市级点位则适合宏观对比与汇报展示值得GIS入门与进阶者收藏使用。1. 为什么要把上海市区县乡镇村做成点位 shp一个上游交付的点位表上千条村居坐标直接拖进 ArcMap 反而炸成一团乱点——不是数据错了是没有按行政层级组织成 shp。上海市从 16 个区、两百多个街镇到数千个村居天然是一棵四级树。把每一级提成一个点带上编码和上下级关系写进属性表就是一个能用于检索、落格统计和前端发布的“上海市区县乡镇村各级点位 shp”。点位 shp 比面状边界轻得多全上海的村居面图层动辄十几 MB点图层只有几百 KB而“某坐标落在哪个村居”这类空间查询点在空间索引上的效率也远高于多边形相交。它适合两类人做城市数据运营的工程师拿它做订单落位、网格派单、热力聚合做地图前端的开发拿它转 GeoJSON、KML 做下钻展示。要做对这份数据绕不开三件事字段与编码规则、坐标系选型、批量导入导出的管线。下面按这条线展开。2. 点位 shp 的数据结构、层级编码与坐标系选型2.1 一个 shp 不是一个文件很多从网上拿到的“上海市乡镇点位 shp”解压后只有三五个文件有些人只收到一个 .dbf 就追问为什么打不开。先确认文件集一份规范的 shp 至少由 .shp几何坐标、.shx几何索引、.dbf属性表三个同名前缀文件组成正式发布还应带 .prj坐标系定义和 .cpg属性字符集声明。缺 .shx 时多数软件还能自动重建索引缺 .dbf 就只有位置没有属性缺 .prj 则坐标基准未知后面的叠加、量算全都不可信缺 .cpg 则中文属性大概率乱码。点位图层与面状图层在几何组织上完全不同。面状 shp 存储的是弧段和顶点序列一个村的多边形可能由几十上百个顶点构成加载时要构建多边形拓扑所以体积大点位 shp 的每条记录只是一个 Point两个 double 就放下经纬度。对“区县—乡镇—村”这种严格逐级归属的数据点图层表达“属于”的语义更直接每个村点坐标落在唯一一个乡镇面的范围内一次空间连接就能把四级关系全部串起来不需要对多边形反复做裁剪叠置。2.2 属性表字段设计与行政区划代码规律拿到原始数据时常常只有一个 name 字段只能画点做不了下钻和挂接。我会先把属性表规整成下面这张结构字段类型示例作用codeText310115118本级行政区划代码区县 6 位、乡镇街道 9 位、村居 12 位nameText张江镇本级名称与 code 一一对应levelInteger2 / 3 / 41 上海市、2 区县、3 乡镇街道、4 村居pcodeText310115上级代码回挂上级不用做空间计算lon / latDouble121.593 / 31.216冗余存十进制度坐标导出 txt、CSV 时直接可用三个细节容易被忽略。第一code 必须是文本型。310101 这类六位码没有前导零问题但村居的 12 位代码末尾出现 0 时Excel 会把后导零自动吃掉导致下一级挂不上去。第二level 用整数而不是文本筛选下钻、写分级符号时直接按数值比较。第三lon/lat 冗余字段不是为了好看而是下游同事时常要一份“带坐标的 Excel”直接从 dbf 导出即可不必再对几何做一次坐标提取。行政区划代码本身有规律可循310000 是上海市区县码是六位例如 310101 黄浦区、310104 徐汇区、310115 浦东新区乡镇街道码是区县码后补三位共九位村居委会码再补三位共十二位。这个规律意味着 pcode 可以靠字符串截断推导不依赖任何外部码表。交付前我通常会抽查几个末端节点确认 code 前缀与上级 name 对得上这是校验点位层级关系最快的一招。2.3 坐标系三选一先看 .prj 再动手点位数据 90% 的“对不上”都出在坐标系。上海市区县乡镇村点位最常见的三个基准是WGS84EPSG:4326是全球通用基准GPS 芯片、CSV 经纬度交换、Google Earth 都默认它。CGCS2000EPSG:4490 是它的地理坐标表达是国标与政务数据的主流与 WGS84 的差异在厘米级叠加底图肉眼几乎看不出。需要算距离、算面积时再把点位从地理坐标投影到 CGCS2000 的 3 度 Gauss-Kruger中央经线取 120°E单位从度变成米如果点位集中在浦东东部且要做高精度测距按 123°E 带号重新投影更合适。第三个是 GCJ-02互联网地图行业俗称“火星坐标”没有官方 EPSG 编码。高德、腾讯这类 app 的底图和 POI 抓取接口给出的就是 GCJ-02而 GPS 设备和 OSM 底图是 WGS84两者相差 300 米到 500 米。判断一份 shp 是否 GCJ-02最省钱的办法是拿地标对坐标人民广场的 WGS84 约在 121.4707°E、31.2304°N如果点位明显偏向东北方向几百米基本就是 GCJ-02。点位 shp 如果本就要叠加高德底图GCJ-02 反而不用转要和 GPS 轨迹、OSM 底图叠加必须换回 WGS84。2.4 没有 .prj 的文件怎么抢救先做粗判看 x 值。x 在 120 或 121 附近、y 在 30 或 31 附近是经纬度x 是六到七位数、y 是五到六位数是投影米制坐标大概率是 CGCS2000 或北京 54 的 3 度带。然后打开 QGIS在图层属性里把 CRS 先指定为 WGS84叠加 OSM XYZ 底图看点位是否落在上海市域。偏几百米是加密坐标系偏几公里则是投影被当成了经纬度。定位之后用“导出 另存要素为”把目标坐标系选成 EPSG:4490 或 EPSG:4326一次到位重投影并顺带生成新的 .prj。提示千万别在不知道原始基准时直接“另存为 4326”。另存只改变坐标写法不改变点位实际位置原始基准错了转出来的仍然是错点只是数值变了。3. 生成上海市点位 shp面边界提点与 Excel 经纬度导入3.1 从面状边界提取代表点如果手上已有区县或乡镇的面状 shp最快的方式不是重新采点而是从面里提取点。QGIS 的“矢量 几何工具 质心”和 ArcGIS 的 Data Management Features Feature To Point 是常用手段。但这两个工具输出的是几何质心上海沿江沿湾的乡镇不少是狭长或弯月形凹多边形的质心可能落在水面甚至邻区而行政区划点位期望落在本辖区范围内。所以我会优先用“多边形上的点”这类工具或 PostGIS 的 ST_PointOnSurface它们保证生成的点落在面内代价是计算量比质心大。用 geopandas 批量处理四级数据可以写成这样import geopandas as gpd # 读取乡镇面状边界字段含 code/name/pcode/level town gpd.read_file(shanghai_town.shp, encodingutf-8) # representative_point() 返回面内点比 centroid 更稳 town[geometry] town.geometry.representative_point() # 按固定字段顺序写出点位图层 out town[[code, name, pcode, level, geometry]] out out.set_crs(EPSG:4490, allow_overrideTrue) out.to_file(shanghai_town_point.shp, encodingutf-8)逻辑说明先读入面图层再用 representative_point() 把每个多边形的几何替换成面内代表点最后按统一字段结构写出。两个参数需要留意set_crs 只在源文件缺 .prj、坐标为裸数值时用来声明坐标系如果源文件已经带 .prj 且基准正确这里应改成 to_crs(EPSG:4490) 做重投影两者语义完全不同。representative_point() 比 centroid 慢处理全上海几千个乡镇多边形通常几秒如果面图层是全国级几十万个要素建议先按上海市域裁剪再执行。3.2 把 Excel 经纬度表变成点位 shp现实中更常见的是手里只有一张表字段大概是“区县、乡镇、村居、经度、纬度”。这种表转成 shp 不需要手动画点三种工具任选。3.2.1 ArcMap 的 XY 数据导入路径在 ArcMap 里点“文件 添加数据 添加 XY 数据”X 字段选经度列、Y 字段选纬度列坐标系按表头来源选 WGS84 或 GCJ-02确定后生成一个临时“事件图层”。事件图层没有落盘必须在内容列表中右键该图层选“数据 导出数据”坐标系选源数据坐标系保存成新的 shp。这步最常见的失败原因是 Excel 里经纬度没有转成纯数字——带“121°15′30″”的度分秒文本XY 数据窗口会把整行识别成空值导出的 shp 全是空点。3.2.2 QGIS 的分隔文本导入更省事QGIS 里“图层 添加图层 添加分隔文本图层”文件格式选 CSVX 字段设为经度Y 字段设为纬度几何类型选“点”坐标系指定 EPSG:4326WGS84或 EPSG:4490CGCS2000。导入后右键图层“导出 另存要素为”格式选 ESRI Shapefile即可生成点位 shp。QGIS 的 CSV 导入支持预览点有没有散到海外当场就能看出来比 ArcMap 的黑盒导入更可控。3.2.3 用 Python 直接生成 shp几百行的表用 GUI 没问题碰到多个区县多批表格脚本更省import pandas as pd import geopandas as gpd from shapely.geometry import Point # dtype 保证 12 位行政区划代码不被读成数字 df pd.read_excel(上海村居点位表.xlsx, dtype{code: str}) # 度分秒转十进制度兼容 121°1530 这类文本 def dms2dec(s): if isinstance(s, str) and ° in s: d, m, sec s.replace(, ).split(°) m, sec m.split() if in m else (m, 0) return float(d) float(m) / 60 float(sec) / 3600 return float(s) df[lng] df[lng].map(dms2dec) df[lat] df[lat].map(dms2dec) geom [Point(x, y) for x, y in zip(df[lng], df[lat])] gdf gpd.GeoDataFrame(df, geometrygeom, crsEPSG:4326) gdf.to_file(shanghai_village_points.shp, encodingutf-8)这段代码做了三件事强制 code 为文本、把度分秒文本统一成十进制度、按经纬度列构造几何并写出 shp。特别说明 Point(x, y) 的顺序是经度在前、纬度在后写反之后点的 x 会落在 31 附近而 y 落在 121 附近用 total_bounds 一眼就能发现。GCJ-02 的 Excel 表不要在这里直接指定 EPSG:4326需要先做坐标类型转换否则后续叠加全部偏移。3.3 层级回挂把区县、乡镇、村居串成父子链四级点位如果分别来自不同批次最后要合成一个带 pcode 的完整 shp。常见做法是按国标代码截断回挂而不是做空间计算def parent_code(code, level): if level 3: # 乡镇街道上级是区县 return code[:6] if level 4: # 村居上级是乡镇街道 return code[:9] return df[pcode] [parent_code(c, l) for c, l in zip(df[code], df[level])]回挂完成后做一个孤儿检查把所有 pcode 拿去和上级 code 集合比对找不到的记录基本是区划调整后的废弃代码或录入笔误。上海近年街镇撤并频繁老静安与闸北合并后旧代码对应的村居点需要重挂到新区划下这一步不能省。4. 上海市点位 shp 的转换与批量处理转 txt、批量 kml、瘦身4.1 shp 转 txt / CSV 与 GeoJSON“shp 转 txt”是点图层数据被搜得最多的操作下游经常只要一个带坐标的文本清单。不要手写脚本去解析二进制 .dbfGDAL 的 ogr2ogr 可以直接把点图层输出成带坐标的 CSVogr2ogr -f CSV shanghai_points.csv shanghai_points.shp -lco GEOMETRYAS_XY参数说明-lco GEOMETRYAS_XY 让输出的 CSV 直接包含 X、Y 两列十进制度坐标不加这个参数输出的 CSV 只有属性没有坐标。默认的表头就叫 X、Y想要 lng/lat 命名需要先重命名字段。另外 CSV 没有坐标系概念交付时要注明“WGS84 十进制度”否则对方拿去按投影处理就偏了。QGIS 里同样的操作是右键图层“导出 另存要素为”格式选 CSV几何部分选“Point (X,Y)”编码选 UTF-8。前端地图更喜欢 GeoJSON转换同样一条命令ogr2ogr -f GeoJSON shanghai_points.geojson shanghai_points.shpGeoJSON 是 Web 地图最常用的交换格式Leaflet、Mapbox、OpenLayers 直接加载。如果目标是 Cesium 这类三维场景常见做法是先把点位转成 GeoJSON再通过 3D Tiles 工具链比如 py3dtiles烘焙成瓦片对纯二维点位而言直接加载 GeoJSON 往往比生成 3D Tiles 更省事只有叠加建筑高度、需要 LOD 切换时才值得转瓦片。4.2 shp 批量转 kml 的 shell 循环给外场人员看的点位KML 是兼容性最好的格式Google Earth、奥维、两步路都能直接打开。如果一个点位 shp 拆成了十几个区县文件逐个在 QGIS 里转太原始shell 循环一次搞定for f in *.shp; do ogr2ogr -f KML ${f%.shp}.kml $f done这段循环的逻辑是遍历当前目录所有 shp用 ${f%.shp} 去掉后缀再拼接成同名 .kml。注意两点KML 规范强制 WGS84源 shp 带 .prj 时 ogr2ogr 会自动重投影源 shp 缺 .prj 时坐标会被原样写进 KML结果整体偏到海里。GCJ-02 的点位必须先转 WGS84 再做 KMLKML 不会替你纠偏。4.3 点位 shp 的三种瘦身方式点图层没有“简化几何”可做体积基本全来自 dbf 属性。常用瘦身手段对比如下手段操作方法适用场景删字段导出时只保留 code/name/pcode/level属性里挂着几十列统计数据的交付去重按 pcodename 分组保留首次出现的记录多次入库合并产生的重复点换容器导出为 GeoPackage.gpkg单文件交付、字段名超 10 字符、接近 2GB用 geopandas 一条链完成import geopandas as gpd # 读取、去重、裁字段、换容器一次完成 gdf gpd.read_file(shanghai_village_points.shp, encodingutf-8) gdf gdf.drop_duplicates(subset[pcode, name]) gdf[[code, name, pcode, level, geometry]].to_file( shanghai_village_points.gpkg, layervillage, driverGPKG)drop_duplicates 以 pcodename 为键能去掉同村重复的采集点GPKG 驱动写出时字段名不会被截断到 10 个字符中文属性也无需外挂 .cpg。下游只认 shp 的话最后再用同样方式导出回 .shp 即可注意导出时带 encodingutf-8。4.4 转换链路里的两个翻车点第一个翻车点是度分秒。Excel 里常见的 121°1530 直接进 CSV 会变成字符串GIS 读不到坐标前面 3.2.3 的 dms2dec 函数就是为这个场景准备的先统一成十进制度再进模板。第二个翻车点是 dbf 字段截断。shapefile 的 dbf 字段名限制 10 个字符中文名还可能乱码导出 KML、CSV 时字段名会被改写属性对不上的情况多半从这里来。遇到这种问题先把中文列名改成 code、name、pcode、level 这类短英文再做任何导出。5. 点位 shp 的坐标校验、空间挂接与中文编码收尾5.1 拿到点位先算 total_bounds上海市域的经纬度范围大致是 lng 120.85–122.15、lat 30.65–31.95。任何自称“上海市点位”的 shp第一步都该拿总范围做冒烟测试import geopandas as gpd gdf gpd.read_file(shanghai_points.shp, encodingutf-8) print(crs:, gdf.crs) print(bounds:, gdf.total_bounds)total_bounds 返回 (minx, miny, maxx, maxy)。minx 在 30 附近、miny 在 121 附近说明经纬度两列写反转置即可坐标是七位数米制但 crs 显示 EPSG:4326说明 .prj 内容与数据不符用 set_crs 声明真实基准后再 to_crs(EPSG:4326)大量点重叠在同一坐标通常是公式异常或“无坐标”默认值 0,0 被带进来按 lon/lat 双零过滤。5.2 空间挂接让村居点自动带上乡镇属性做街镇维度统计时一种常用路径是 QGIS 的“矢量 数据处理工具 按位置连接属性”目标图层选村居点位连接图层选乡镇面几何谓词选“相交”汇总方式选“取第一个匹配项”。输出后每个村居点都会多出所属乡镇的 code 和 name。不开 GUI 的话geopandas 里对应操作是villages gpd.read_file(village_points.shp) towns gpd.read_file(town_bounds.shp) joined gpd.sjoin(villages, towns[[code, name, geometry]], howleft, predicatewithin) miss joined[name_right].isna().sum() print(未匹配点数量:, miss)predicate 用 within 而不是 intersects是为了避免点恰好在乡镇边界上时被重复匹配。未匹配数量若超过总量 1%先检查乡镇面是否缺飞地——崇明、长兴、横沙等岛屿的点位尤其容易因为面数据版本旧而挂不上。5.3 结合渔网分割统计点位密度“渔网分割 shp”这个需求本质是用规则格网做密度聚合。在 QGIS 里选“矢量 研究工具 创建网格”范围取点位图层总边界间距设 0.02 度上海约 2 公里类型选矩形生成网格面再对网格执行“按位置连接属性”汇总选“统计计数”每个网格的属性里就有落点个数按计数做分级着色就是一张可发布的点位密度图。网格间距按业务调整0.01 度偏密适合看城区内部0.05 度偏疏适合看全区分布。5.4 交付前最后一步用 .cpg 根治中文乱码shp 的中文乱码在 QGIS 里最常见ArcMap 打开正常换 QGIS 就满屏乱码。原因不在数据而在 dbf 编码声明缺失或冲突。有一个比重新导出更快的收尾技巧在 shp 同目录新建一个与主文件同名的空文本文件把扩展名改成 .cpg例如 shanghai_points.cpg内容写 UTF-8源码是 GBK 就写 GBK保存后刷新图层即可。.cpg 只有几个字节但它是 GIS 软件决定用哪种代码页解析 dbf 的依据打包交付时把 .cpg 一并给出去能直接省掉对方大量“字段乱码”的返工沟通。本文还有配套的精品资源点击获取