2026/10/21 2:56:33

中亚五国shp格式矢量边界数据全解析:从获取、验证到应用

中亚五国shp格式矢量边界数据全解析:从获取、验证到应用 简介这份中亚五国矢量图数据集面向GIS从业者、地理科研人员及区域研究学习者提供哈萨克斯坦、乌兹别克斯坦、吉尔吉斯斯坦、塔吉克斯坦和土库曼斯坦五国的精确地理边界与属性信息可用于地图制作、土地利用规划、区域发展分析及政治边界研究等场景。资源包共8个文件约545KB以Shapefile标准组件为主shp主文件承载几何形状shx索引加速数据访问dbf存储国家名称等属性字段prj定义坐标系统另有cpg字符编码说明及sbx、sbn地理索引文件xml则记录元数据各文件协同保证数据在ArcGIS、QGIS等主流软件中正确投影与显示。目前已有189人学习下载。借助该数据集读者可快速搭建中亚地区空间分析底图结合属性数据开展自然资源分布、交通网络等专题制图为政策研究、投资分析与学术探索提供可靠的地理信息支撑。1. 中亚五国矢量图 shp 格式一份边界数据到底能撑起多少种用法做区域分析的人迟早会撞上同一个需求手头要一份中亚五国的矢量边界格式还得是 shp。中亚五国指的是哈萨克斯坦、吉尔吉斯斯坦、塔吉克斯坦、土库曼斯坦、乌兹别克斯坦这五个国家的国界、州级行政区划、水系、交通线是跨境物流测算、能源管线选线、气候分区统计、人口密度制图这类活儿的基础底图。很多人第一反应是去搜一份现成的 shp 压缩包下载解压拖进软件然后发现坐标系对不上、属性表是乱码、国界线缺了一段。问题不在数据本身而在于 shp 从来不是一个文件它是一组文件的集合少一个都跑不起来。这篇笔记就按我实际做项目的顺序把中亚五国 shp 从哪来、怎么验、怎么用、坑在哪讲清楚适合刚接手区域数据的新手也适合想核对边界精度的熟手。2. 先搞懂 shp 到底是什么一组文件而不是一个文件2.1 shp 文件族的成员与各自职责很多人把 shp 当成一张图片来理解这是后面所有翻车的根源。Esri Shapefile 是一种开放的矢量数据格式但它物理上是一组同名、不同后缀的文件必须放在同一个目录里缺任何一个都会导致读取失败或属性丢失。核心成员是这几个后缀是否必需作用.shp必需存储几何形状点线面的坐标.shx必需几何索引记录每个要素在 shp 中的偏移.dbf必需属性表存国家名、行政区代码等字段.prj强烈建议坐标系定义缺失会导致坐标被当成无意义数字.cpg建议属性表字符编码缺了中文或西里尔字母会乱码.sbn/.sbx可选空间索引加速查询我一般拿到一份中亚五国 shp 后第一件事不是打开软件而是进目录数文件。只有 .shp 一个文件的基本可以判定是残缺包属性表大概率丢了。.prj 缺失的情况更隐蔽软件能打开图形也画得出来但坐标是错的你拿它去和别的图层叠加就会整体偏移几百米甚至几公里。2.2 坐标系地理坐标和投影坐标别混用中亚五国横跨东经约 46 度到 88 度北纬约 35 度到 56 度范围很大。这个纬度带常见的投影是 UTM 分区从 38N 到 45N 都有覆盖跨区严重。所以做全国级或五国级的分析我一般用地理坐标系 WGS84EPSG:4326存底图做面积和距离计算时再临时投影到等积或等距投影。判断一份 shp 用的是哪种坐标看 .prj 文件内容或者用工具读。地理坐标的单位是度数值范围经度 -180 到 180、纬度 -90 到 90投影坐标的单位是米数值通常是几十万到几百万。如果你看到坐标值是 70、45 这种那是经纬度看到 500000、4500000 这种那是投影坐标。两者混用是叠加分析里最常见的错误来源。提示面积计算一定要用投影坐标或等积投影直接用经纬度算面积在高纬度地区误差能到百分之几十中亚正好属于中高纬度。2.3 用 Python 读一份 shp 并打印基本信息下面这段代码是我每次拿到新数据的固定动作读进来、看坐标系、看字段、看要素数量、看几何类型。import geopandas as gpd # 读取中亚五国 shp注意传的是 .shp 路径同目录其他文件会被自动关联 gdf gpd.read_file(./central_asia/countries.shp) # 坐标系看 EPSG 编码4326 是 WGS84 地理坐标 print(CRS:, gdf.crs) # 属性表字段和类型 print(Columns:, gdf.columns.tolist()) print(gdf.dtypes) # 要素数量和几何类型 print(Feature count:, len(gdf)) print(Geom types:, gdf.geom_type.unique()) # 看前几行的关键属性 print(gdf.head()) # 边界范围判断坐标是经纬度还是投影坐标 print(Bounds:, gdf.total_bounds)逻辑说明read_file会自动去找同名的 .shx、.dbf、.prj所以路径只写 .shp 就行但前提是这些文件都在。gdf.crs返回坐标系对象如果是 None说明 .prj 缺失需要手动指定。total_bounds返回的是 minx、miny、maxx、maxy如果这四个值落在经纬度范围内就是地理坐标如果数值很大就是投影坐标。这一步能帮你快速判断数据是否可用避免后面白忙。参数说明read_file的路径建议用相对路径或绝对路径都行但目录里不要有中文和空格某些底层库对路径编码敏感。如果数据量大可以加rows5只读前几行做快速检查。3. 数据从哪来三条可靠路径和各自的取舍3.1 公开边界数据集Natural Earth 与 GADM 的差别做中亚五国底图最常被提到的两个公开来源是 Natural Earth 和 GADM。它们不是同一个东西用途也不同。Natural Earth 提供的是制图级边界比例尺有 1:10m、1:50m、1:110m 三档。它的国界线经过制图综合视觉上平滑好看适合做展示图、汇报图。但它的行政级别只到国家级和部分省级且边界是概化过的不适合做精确的面积统计和跨境缓冲分析。GADM 提供的是行政边界数据库层级更深能到国家级、省级、县级。它的边界更贴近实际行政划分适合做统计单元。但 GADM 的边界在不同版本间会有调整且部分争议地区的处理方式需要你自己判断用于正式分析前要核对。我一般的做法是展示图用 Natural Earth统计和空间分析用 GADM 或各国官方测绘部门发布的边界。两者不要混着用因为同一段国界在两套数据里可能差几百米叠加后会出现细长的缝隙或重叠。3.2 从公开源下载并裁剪出中亚五国以 Natural Earth 的 1:10m 国家级数据为例下载后是全球数据需要按国家筛选出中亚五国。下面这段代码演示筛选和导出。import geopandas as gpd # 读取全球国家级边界 world gpd.read_file(./ne_10m_admin_0_countries.shp) # 中亚五国的英文名注意不同数据集命名可能不同先看字段再筛选 target [Kazakhstan, Kyrgyzstan, Tajikistan, Turkmenistan, Uzbekistan] # 按属性字段筛选ADMIN 是 Natural Earth 的国家名字段 ca world[world[ADMIN].isin(target)].copy() # 检查筛出来是不是五个 print(Selected:, len(ca), ca[ADMIN].tolist()) # 统一到 WGS84 后导出 ca ca.to_crs(epsg4326) ca.to_file(./central_asia/ca_countries.shp, encodingutf-8)逻辑说明isin做的是精确匹配所以字段值必须和数据集里的写法完全一致。Natural Earth 里国家名字段是ADMINGADM 里可能是NAME_0动手前先print(world.columns)看一眼。to_crs把坐标系统一到 WGS84避免后续叠加时坐标不一致。导出时指定encodingutf-8能减少属性表乱码。参数说明to_file的格式由后缀决定写 .shp 就导出 shapefile。如果字段里有中文建议同时生成 .cpg 文件或者在导出后用文本编辑器确认编码。数据量大时导出会慢可以先用ca.plot()看一眼图形对不对再导。3.3 属性表字段的取舍别把整张表都带出来下载的原始数据往往带几十个字段人口、GDP、ISO 代码、各种别名。导出时我一般只保留分析真正用到的字段比如国家名、ISO 三字码、行政区代码。字段越少文件越小后续处理越快也越不容易在编码上出问题。# 只保留需要的字段重命名成自己顺手的名字 ca_slim ca[[ADMIN, ISO_A3, geometry]].rename( columns{ADMIN: country, ISO_A3: iso3} ) # 确认没有空几何 print(Empty geoms:, ca_slim.geometry.is_empty.sum()) # 导出精简版 ca_slim.to_file(./central_asia/ca_slim.shp, encodingutf-8)逻辑说明geometry列必须保留否则导出后没有图形。is_empty检查有没有空几何空几何在后续空间连接时会报错或产生意外结果。重命名字段是为了后续代码里引用方便避免每次都要回忆原始字段名。参数说明如果原始数据里 ISO 字段有缺失筛选后要检查缺失的可以手动补或者换用其他唯一标识。字段名建议用英文小写加下划线跨平台兼容性最好。4. 把 shp 用起来叠加、裁剪、统计的完整链路4.1 用中亚五国边界裁剪全球栅格数据拿到五国边界后最常见的下游操作是裁剪。比如你有一份全球的夜间灯光栅格、气候栅格或人口栅格想只保留中亚部分。下面演示用边界裁剪栅格。import rioxarray import geopandas as gpd from shapely.geometry import box # 读边界 ca gpd.read_file(./central_asia/ca_slim.shp) # 读全球栅格 raster rioxarray.open_rasterio(./global/nightlight.tif) # 坐标系必须一致不一致先转 if raster.rio.crs ! ca.crs: ca ca.to_crs(raster.rio.crs) # 用边界的总范围做矩形裁剪速度快 minx, miny, maxx, maxy ca.total_bounds clipped raster.rio.clip_box(minx, miny, maxx, maxy) # 如果要精确按国界裁剪用几何掩膜 clipped_exact raster.rio.clip(ca.geometry, ca.crs, dropTrue) clipped_exact.rio.to_raster(./central_asia/nightlight_ca.tif)逻辑说明clip_box按矩形范围裁速度快适合先粗裁再精裁。clip按实际几何掩膜边界外的像元会被设为 nodata适合出图。两者坐标系必须一致否则裁剪结果会错位。dropTrue表示裁完后把无数据的边缘去掉减小文件。参数说明open_rasterio对大栅格会占用较多内存可以先看栅格分辨率和尺寸必要时用chunks分块读。clip的几何可以是 GeoSeries也可以是单个几何传入前确认几何有效有自相交的先用buffer(0)修复。4.2 按国家做分区统计裁剪完栅格下一步往往是按国家统计均值、总和。这需要把栅格值和国界做空间关联。import rasterstats # 按国界统计栅格均值stats 可以换成 sum、max、count stats rasterstats.zonal_stats( ca.geometry, ./central_asia/nightlight_ca.tif, stats[mean, sum, count], nodata-9999 ) # 把结果挂回属性表 ca[mean_light] [s[mean] for s in stats] ca[sum_light] [s[sum] for s in stats] print(ca[[country, mean_light, sum_light]])逻辑说明zonal_stats接收几何列表和栅格路径返回每个几何对应的统计值。nodata要和栅格实际的 nodata 值一致否则会把无效值算进去结果偏小或偏大。统计结果按几何顺序返回所以挂回属性表时顺序是对应的。参数说明stats支持 mean、sum、min、max、count、std 等。做灯光或人口这类总量指标用 sum做强度指标用 mean。如果几何跨多个栅格块zonal_stats会自动处理但大区域会慢可以先用all_touchedFalse只统计中心落在几何内的像元速度快但边缘会略少。4.3 导出成 GeoJSON 给前端或其他工具用shp 在 Web 端和很多轻量工具里不好直接用转成 GeoJSON 是常见做法。# 转 GeoJSON注意坐标系用 WGS84前端地图库默认吃这个 ca_wgs ca.to_crs(epsg4326) ca_wgs.to_file(./central_asia/ca.geojson, driverGeoJSON) # 如果文件太大可以简化几何容差按度给0.01 约等于 1 公里 ca_simplified ca_wgs.copy() ca_simplified[geometry] ca_simplified.geometry.simplify(0.01) ca_simplified.to_file(./central_asia/ca_simplified.geojson, driverGeoJSON)逻辑说明GeoJSON 规范要求坐标是 WGS84 经纬度所以导出前必须转坐标系。simplify用 Douglas-Peucker 算法减少节点容差越大越简化文件越小但边界越粗糙。做展示图可以简化做精确分析不要简化。参数说明simplify的容差单位跟随坐标系经纬度下 0.01 度约 1 公里0.001 度约 100 米。简化后要检查国界是否还闭合有没有产生自相交。GeoJSON 用 UTF-8 编码中文属性不会乱码。5. 避坑与排查中亚五国 shp 最常见的五个翻车点5.1 打开后图形跑到非洲西边海面上现象加载 shp 后图形不在中亚位置而是跑到几内亚湾附近或者干脆看不见。原因坐标系定义错误或缺失。软件把经纬度数值当成了投影坐标的米或者把投影坐标当成了经纬度。比如经度 70 被当成 70 米自然跑到原点附近。解决先看 .prj 是否存在内容是否合理。用gdf.crs读如果是 None根据数据来源手动指定。如果指定后位置还是不对检查是不是把投影坐标误标成了 4326。可以用gdf.to_crs(epsg4326)试转看位置是否回到中亚。判断依据是中亚的经纬度范围经度 46 到 88纬度 35 到 56。5.2 属性表里国家名变成问号或方块现象打开属性表国家名字段显示为?????或乱码方块。原因.dbf 文件的字符编码和读取时用的编码不一致。shp 的 dbf 默认可能是 Latin-1 或系统本地编码而数据里存了西里尔字母或中文。解决先确认有没有 .cpg 文件里面写的就是编码比如 UTF-8。没有的话读取时手动指定编码gpd.read_file(path, encodingutf-8)或encodinggbk逐个试。导出时统一用 UTF-8 并生成 .cpg。如果原始数据编码已经丢失只能对照要素顺序重新挂属性。5.3 五个国家只显示出来三个现象筛选后要素数量不对或者地图上只画出部分国家。原因国家名字段的值和筛选列表不完全匹配。比如数据里写的是 Kyrgyz Republic 而不是 Kyrgyzstan或者有前后空格、大小写差异。解决先print(gdf[字段名].unique())看实际值再调整筛选列表。用str.strip()去空格用str.lower()统一大小写后再匹配。也可以改用 ISO 三字码筛选比国家名稳定。5.4 面积算出来大得离谱现象用经纬度直接算面积结果和实际面积差很多或者单位是平方度不是平方公里。原因在 EPSG:4326 下算面积单位是平方度且随纬度变化没有物理意义。解决先投影到合适的等积投影再算。中亚可以用 Albers 等积投影自定义中央经线和标准纬线。或者用gdf.to_crs(epsg3857)做粗略估算但 3857 在高纬度变形大精确统计还是用 Albers 或 UTM 对应分区。# 自定义 Albers 等积投影适合中亚 albers projaea lat_140 lat_255 lat_045 lon_067 datumWGS84 unitsm ca_albers ca.to_crs(albers) ca_albers[area_km2] ca_albers.geometry.area / 1e6 print(ca_albers[[country, area_km2]])逻辑说明lat_1和lat_2是标准纬线选在中亚主要纬度范围内能减小变形。lon_0是中央经线取五国中间偏东的位置。unitsm保证面积单位是平方米除以 1e6 得平方公里。参数说明标准纬线不是随便取的一般取区域南北边界的纬度。中央经线取区域中心经度。改这两个参数会改变面积结果做正式统计前用已知面积的国家核对一下。5.5 叠加分析时出现细长缝隙或重叠现象把中亚五国边界和另一份行政边界叠加国界处出现发丝一样的缝隙或者两个图层重叠。原因两份数据的边界精度和版本不同同一段国界的节点不一致。这是数据源差异不是操作错误。解决如果只是出图可以忽略或把缝隙填色。如果要做精确统计先统一到同一数据源或者用snap把节点对齐。也可以用overlay时设置容差但容差过大会改变几何形状。最稳妥的做法是分析前就选定一套边界数据全程不换。6. 进阶把五国边界做成可复用的底图资产做到这里你手里应该有一份干净的中亚五国 shp 了。但项目一多每次重新下载、筛选、转坐标很烦。我的习惯是把它做成一套可复用的底图资产按用途分几个版本存好下次直接取。第一个版本是原始版保留完整字段和最高精度WGS84 地理坐标用于需要精确几何的场景。第二个版本是精简版只留国家名、ISO 码和几何用于快速加载和展示。第三个版本是投影版按常用分析需求预先投影好比如 Albers 等积用于面积统计UTM 分区用于局部高精度测量。第四个版本是简化版 GeoJSON用于 Web 端和轻量工具。维护这套资产的关键是记录来源和版本。我一般会在目录里放一个说明文件写清楚数据来自哪个公开数据集、下载时间、坐标系、字段含义、做过哪些处理。这样过半年再回来不用重新猜。验证一套边界数据是否可靠我常用三个检查。一是看总面积哈萨克斯坦约 272 万平方公里其他四国各在 14 万到 49 万之间算出来偏差超过百分之几就要查。二是看国界是否闭合用geometry.is_valid检查无效的用buffer(0)修复。三是看和已知地标的吻合度比如取几个城市坐标看是否落在对应国家内。# 有效性检查与修复 invalid ca[~ca.geometry.is_valid] print(Invalid geoms:, len(invalid)) # 修复无效几何 ca[geometry] ca.geometry.buffer(0) # 用城市点验证点是否在对应国家内 from shapely.geometry import Point city Point(71.43, 51.13) # 某城市坐标 country ca[ca.contains(city)] print(country[country].tolist())逻辑说明is_valid检查几何是否有自相交、重复节点等问题。buffer(0)是常用的修复手段能把自相交的几何整理成有效几何但会轻微改变形状修复后要重新核对面积。contains做点面判断用来验证边界和实际地理位置是否吻合。参数说明buffer(0)对大多数无效几何有效但对严重错误的几何可能产生空结果修复后要检查要素数量有没有变。城市坐标从公开地理资料取取的时候注意坐标系要和边界一致。最后说个我踩过的坑。早期做中亚项目图省事直接拿了一份网上下的 shp没看坐标系就叠加结果所有统计都偏了排查了一整天才发现是投影问题。从那以后我拿到任何矢量数据第一件事就是读坐标系、看范围、验有效性这三步花不了五分钟但能省掉后面几天的后悔药。希望帮到你。本文还有配套的精品资源点击获取