简介:这份中亚五国矢量图数据集面向GIS从业者、地理科研人员及区域研究学习者,提供哈萨克斯坦、乌兹别克斯坦、吉尔吉斯斯坦、塔吉克斯坦和土库曼斯坦五国的精确地理边界与属性信息,可用于地图制作、土地利用规划、区域发展分析及政治边界研究等场景。资源包共8个文件,约545KB,以Shapefile标准组件为主:shp主文件承载几何形状,shx索引加速数据访问,dbf存储国家名称等属性字段,prj定义坐标系统,另有cpg字符编码、sbn与sbx地理索引及xml元数据文件,各组件协同保证数据在ArcGIS、QGIS等主流软件中正确投影与显示。目前已有189人学习下载。借助这份数据,读者可快速搭建中亚地区空间分析底图,结合属性表开展资源分布、交通网络等专题制图,也可作为区域经济与地缘研究的基础数据源,省去自行采集与配准的繁琐流程。
1. 中亚五国矢量图 shp 格式:一份能直接进 GIS 的边界底图
做区域研究或者跨境项目的人多半遇到过这种场景:手头有一份中亚五国的业务数据,想落到地图上看看空间分布,结果卡在第一步——找不到一套干净、完整、坐标系明确的行政边界矢量。网上搜到的要么是网页截图描出来的,要么缺了某个国家的二级行政区,要么属性表里全是乱码。这份中亚五国矢量图 shp 格式数据集,解决的就是这个「底图从哪来」的问题。它把哈萨克斯坦、吉尔吉斯斯坦、塔吉克斯坦、土库曼斯坦、乌兹别克斯坦五个国家的行政边界整理成标准 Shapefile,能直接拖进 QGIS、ArcGIS 或者用 GeoPandas 读进 Python 做空间分析。适合做区域经济、物流路径、资源分布、环境监测这类需要中亚底图的人,也适合教学演示里当基础数据用。下面按「它是什么、怎么用、坑在哪」的顺序拆开讲。
2. Shapefile 到底装了什么:从坐标系到属性表逐层拆
2.1 为什么是 shp 而不是 GeoJSON
Shapefile 是 Esri 在上世纪九十年代定的一套格式,严格说它不是一个文件,而是一组同名文件的集合。很多人第一次拿到 shp 会懵:怎么解压出来一堆.shp、.shx、.dbf、.prj、.cpg。这不是打包失误,是格式本身的设计。.shp存几何形状,.shx存索引,.dbf存属性表,.prj存坐标系定义,.cpg存字符编码。少任何一个,软件都可能读不出来或者读出来是错的。
那为什么不用 GeoJSON?GeoJSON 单文件、可读性好、网页端友好,但它在处理大量多边形时体积膨胀明显,而且属性字段类型支持不如 dbf 稳定。做区域边界这种「几何不算特别复杂、但要求跨软件兼容」的场景,shp 依然是很多行业软件和政务系统的默认交换格式。常见做法是:分析阶段用 GeoJSON 或 GeoPackage,交付和归档时转成 shp。这份数据集直接给 shp,省掉了转换环节。
2.2 坐标系:WGS84 与 Web 墨卡托的取舍
拿到矢量第一件事是看.prj文件。如果里面写的是GCS_WGS_1984,说明是地理坐标系,单位是度;如果写的是WGS_1984_Web_Mercator_Auxiliary_Sphere,那是投影坐标系,单位是米。两者不能混用。
做面积统计、距离量算,必须用投影坐标系,否则算出来的「度」没有物理意义。做网页地图叠加,通常用 Web 墨卡托(EPSG:3857)。做全球尺度的空间关系判断,WGS84(EPSG:4326)够用。这份数据如果给的是 WGS84,你在 QGIS 里量面积之前,得先重投影到适合中亚的投影带,比如 UTM Zone 42N 到 45N 之间,具体看经度范围。
import geopandas as gpd # 读取 shp,先看坐标系 gdf = gpd.read_file("central_asia.shp") print("原始坐标系:", gdf.crs) print("要素数量:", len(gdf)) print("字段列表:", gdf.columns.tolist()) # 如果要做面积统计,重投影到 UTM # 中亚大致在 46°E 到 88°E,选 UTM Zone 42N-45N gdf_proj = gdf.to_crs(epsg=32642) # Zone 42N gdf_proj["area_km2"] = gdf_proj.geometry.area / 1e6 print(gdf_proj[["name", "area_km2"]].head())这段代码先确认原始坐标系,再转成 UTM Zone 42N 算面积。to_crs的参数epsg=32642是 Zone 42N 的编码,如果你研究区域偏东,换成 32643 或 32644。area返回的是投影单位下的面积,除以 1e6 得到平方公里。注意:重投影后几何会变,但属性表跟着走,不会丢字段。
2.3 属性表里该有什么字段
一份能用的行政边界数据,属性表至少要有国家名、行政区名称、行政区代码、层级。如果只有几何没有属性,那它只是一张「画」,没法做筛选和统计。常见字段命名有NAME_0(国家)、NAME_1(一级行政区)、NAME_2(二级行政区),这是 GADM 的风格;也有ADM0_NAME、ADM1_NAME这种。字段名本身不重要,重要的是你得知道哪个字段对应哪一级。
拿到数据后先跑一遍字段探查:
# 查看属性表结构和前几行 print(gdf.dtypes) print(gdf.head(10)) # 按国家分组统计要素数 if "NAME_0" in gdf.columns: print(gdf.groupby("NAME_0").size())如果groupby出来的国家数量不是 5,说明数据可能只覆盖了部分区域,或者国家名字段有拼写不一致。这时候别急着用,先跟数据提供方确认覆盖范围。
3. 把 shp 用起来:QGIS 可视化与 Python 空间分析两条路
3.1 QGIS 里五分钟出图
QGIS 是免费开源的,对 shp 支持最稳。操作路径:打开 QGIS → 图层 → 添加图层 → 添加矢量图层 → 选.shp文件 → 打开。如果坐标系正确,图层会落在正确位置。如果落到了几内亚湾(0,0 附近),说明.prj缺失或者坐标系定义错了。
出图之后,右键图层 → 属性 → 符号化,可以按国家填色。想按行政区层级显示,用「分类」模式,字段选NAME_1或对应的一级行政区字段。标注用「单一标注」,字段选名称字段,调整字号和避让。
提示:QGIS 里如果中文属性显示乱码,检查
.cpg文件内容是不是UTF-8。如果是GBK或空,用文本编辑器改成UTF-8再重新加载。
3.2 GeoPandas 做空间筛选与叠加
Python 这边用 GeoPandas 最顺手。除了读文件,还能做缓冲区、相交、裁剪这些操作。比如你想找出某个城市 200 公里范围内的所有行政区:
from shapely.geometry import Point # 假设有个城市坐标 city = Point(76.9, 43.2) # 阿拉木图附近 # 转成投影坐标系再做缓冲区,单位才是米 gdf_proj = gdf.to_crs(epsg=32643) city_proj = gpd.GeoSeries([city], crs="EPSG:4326").to_crs(epsg=32643) # 200 公里缓冲区 buffer = city_proj.buffer(200 * 1000) # 找出与缓冲区相交的行政区 intersect = gdf_proj[gdf_proj.intersects(buffer.iloc[0])] print(intersect[["NAME_0", "NAME_1"]])这里的关键是「先投影再缓冲」。如果直接在 WGS84 下buffer(200000),单位是度,结果完全不对。intersects返回布尔索引,筛选出相交的要素。如果你要的是「完全包含在缓冲区内」的行政区,把intersects换成within。
3.3 导出成其他格式给不同工具用
shp 虽然通用,但有些场景需要别的格式。给网页地图用,转 GeoJSON;给空间数据库用,转 PostGIS 的 SQL;给 Excel 做报表,导出属性表 CSV。
# 用 ogr2ogr 转 GeoJSON(GDAL 自带工具) ogr2ogr -f GeoJSON central_asia.geojson central_asia.shp # 转成 GeoPackage,单文件、支持多图层 ogr2ogr -f GPKG central_asia.gpkg central_asia.shp # 只导出属性表为 CSV ogr2ogr -f CSV attributes.csv central_asia.shp -select NAME_0,NAME_1ogr2ogr是 GDAL 的命令行工具,参数-f指定输出格式,-select选字段。转 GeoJSON 时注意编码,加-lco ENCODING=UTF-8更稳。转 CSV 会丢掉几何,只留属性,适合做表格分析。
4. 避坑与排查:shp 用错姿势的五个血泪现场
4.1 现象:图层加载后位置偏移几百米
原因:坐标系定义不匹配。数据本身是 WGS84,但.prj写成了别的坐标系,或者你在 QGIS 里手动指定了错误的 CRS。
解决:先用gdalsrsinfo看.prj内容,跟数据实际来源核对。如果确认是 WGS84,在 QGIS 里右键图层 → 属性 → 源 → 重新指定坐标系为 EPSG:4326,再导出一次。
4.2 现象:属性表中文全是问号
原因:.dbf文件的字符编码跟.cpg声明的不一致。老数据常见 GBK 编码但.cpg写 UTF-8。
解决:用 Python 读的时候指定编码gpd.read_file("file.shp", encoding="gbk"),或者用 QGIS 的「重新保存」功能,在保存时选 UTF-8。
4.3 现象:面积算出来是负数或者零
原因:几何有自相交或者环方向反了。shp 对多边形环方向有要求,外环逆时针、内环顺时针,反了会导致面积计算异常。
解决:用gdf.geometry.is_valid检查,无效的用gdf.geometry.buffer(0)修复。buffer(0) 是常用技巧,能修掉大部分自相交问题。
# 检查并修复无效几何 invalid = gdf[~gdf.geometry.is_valid] print(f"无效几何数量: {len(invalid)}") gdf["geometry"] = gdf.geometry.buffer(0)4.4 现象:五个国家只显示四个
原因:某个国家的几何是空值,或者被错误地合并到了邻国。也可能是属性表里国家名字段有拼写差异,比如「Kyrgyzstan」和「Kyrgyz Republic」被当成两个。
解决:先gdf["NAME_0"].unique()看实际值,再做名称标准化映射。几何为空的行直接删掉或者单独处理。
4.5 现象:文件复制到另一台电脑打不开
原因:只复制了.shp,没复制.shx和.dbf。shp 是一组文件,缺一不可。
解决:打包时把同名文件全部带上,或者转成 GeoPackage 单文件格式再传。我一般习惯在交付前用zip把一组文件压成一个包,避免漏文件。
5. 进阶:用这份底图做区域统计与批量出图
5.1 按国家聚合统计并出图
假设你有一份带经纬度的业务点数据,想统计每个国家的点数量并出图。思路是空间连接(spatial join):把点落到国家多边形里,再按国家分组计数。
import pandas as pd # 读业务点数据 points = pd.read_csv("business_points.csv") points_gdf = gpd.GeoDataFrame( points, geometry=gpd.points_from_xy(points["lon"], points["lat"]), crs="EPSG:4326" ) # 空间连接:每个点匹配到所在国家 joined = gpd.sjoin(points_gdf, gdf[["NAME_0", "geometry"]], how="left", predicate="within") # 按国家计数 count_by_country = joined.groupby("NAME_0").size().reset_index(name="point_count") print(count_by_country) # 合并回国家多边形用于出图 gdf_with_count = gdf.merge(count_by_country, on="NAME_0", how="left") gdf_with_count["point_count"] = gdf_with_count["point_count"].fillna(0) # 出图 import matplotlib.pyplot as plt fig, ax = plt.subplots(1, 1, figsize=(12, 8)) gdf_with_count.plot(column="point_count", ax=ax, legend=True, cmap="OrRd") ax.set_title("中亚五国业务点分布统计") plt.savefig("central_asia_points.png", dpi=150, bbox_inches="tight")sjoin的predicate="within"表示点完全落在多边形内。如果点落在边界上,可能匹配不到,可以换成intersects。how="left"保证没匹配到的点也保留,方便排查。出图时column指定用哪个字段着色,cmap是色带。
5.2 批量裁剪与分国家导出
如果你只需要某个国家的数据,或者要把每个国家单独存一份 shp,用groupby加循环导出:
import os output_dir = "by_country" os.makedirs(output_dir, exist_ok=True) for country, group in gdf.groupby("NAME_0"): # 文件名去掉空格和特殊字符 safe_name = country.replace(" ", "_") group.to_file(f"{output_dir}/{safe_name}.shp", encoding="UTF-8") print(f"已导出: {safe_name}, 要素数: {len(group)}")这段代码按NAME_0分组,每组存一个 shp。encoding="UTF-8"保证属性表中文不乱码。导出后每个文件依然是一组.shp/.shx/.dbf/.prj,别只拿.shp。
5.3 验证数据完整性的三个检查点
拿到任何矢量数据,我习惯先跑三个检查:几何有效性、坐标系一致性、属性表完整性。这三个过了,基本不会出大问题。
| 检查项 | 方法 | 通过标准 |
|---|---|---|
| 几何有效性 | gdf.geometry.is_valid.all() | 返回 True |
| 坐标系 | gdf.crs | 非空且与预期一致 |
| 属性完整性 | gdf[["NAME_0","NAME_1"]].isnull().sum() | 关键字段无空值 |
| 覆盖范围 | gdf.total_bounds | 经度约 46-88,纬度约 35-56 |
total_bounds返回[minx, miny, maxx, maxy],中亚五国的经度范围大致在 46°E 到 88°E,纬度在 35°N 到 56°N。如果边界差太多,说明数据有问题。
从那以后我每次拿到新的 shp,都强制走一遍「看 prj、查字段、验几何、跑 bounds」这四步,宁可多花五分钟,也不想到出图的时候才发现坐标系是错的。希望这份中亚五国矢量图能帮你省掉找底图的时间,把精力留给真正的分析。
本文还有配套的精品资源,点击获取