简介:一份聚焦中亚五国的矢量地理数据集,含哈萨克斯坦、乌兹别克斯坦、吉尔吉斯斯坦、塔吉克斯坦和土库曼斯坦完整国界与属性信息,面向需要在ArcGIS、QGIS等主流平台开展制图、空间规划与区域分析的GIS从业者和研究者。压缩包共8个文件,以shp主文件为核心,配套shx索引、dbf属性库、prj坐标系统文件及cpg编码、sbn/sbx空间索引和xml元数据,完整覆盖空间数据读取、检索与属性关联所需的辅助文件,整体仅约545KB。目前已有186人浏览学习,数据可直接加载并进行可视化展示、空间查询与叠加分析,也可结合人口、经济等外部数据进一步探索区域自然资源、交通网络和政治边界等议题,对中亚研究与国际合作分析具有实用价值。
1. 中亚五国矢量图:为什么一份 shp 格式的国界数据能帮你省掉三天工作量
接到中亚相关项目时,第一件事往往不是跑模型、写报告,而是找一份靠谱的国界底图。哈萨克斯坦、吉尔吉斯斯坦、塔吉克斯坦、土库曼斯坦、乌兹别克斯坦这五个国家的边界数据,看起来只是几根线,实际用起来却处处是坑——国界走向、湖泊归属、飞地处理、坐标系混乱,任何一个环节出错,后面所有空间分析、地图出图、业务落位全部白做。所谓“中亚五国矢量图,shp格式”,本质就是一份可直接加载进 GIS 工具的多边形边界文件,把五国国界、行政区、主要水系这些矢量要素按统一标准组织好。这篇笔记就是把我自己反复用过、也帮别人踩过坑的经验拆开讲:这份数据是什么结构、去哪拿、怎么在 QGIS 和 Python 里跑通最小流程,以及坐标系、属性表、WKT 导出这些环节到底有哪些坑。适合刚接触 GIS 数据的分析人员,也适合要被这份数据折磨的规划、物流、能源领域从业者。
2. 拆开 shp 格式:一个看似“单文件”的矢量包,其实是多个文件的合谋
2.1 一个 .shp 背后至少跟着 4 个兄弟文件,少一个就报错
很多人第一次拿到“中亚五国矢量图”压缩包,解压后发现里面有 .shp、.shx、.dbf、.prj,甚至还有 .cpg、.sbn,第一反应是“怎么这么多文件”。这不是打包的人偷懒,而是 ESRI Shapefile 格式本身的硬性要求。.shp 文件只存几何坐标,.shx 是几何索引,.dbf 存属性字段,.prj 记录坐标系信息。四者缺一不可:少了 .shx,QGIS 会提示“无法打开文件”;少了 .dbf,属性表就彻底空了;少了 .prj,软件只能靠猜,投影大概率错位。
我自己处理数据时有个习惯:拿到压缩包先全量解压到同一个文件夹,再用 QGIS 的图层管理器拖入 .shp 文件。第一次加载如果弹出“Invalid Data Source”或者“No features found”,八成不是数据本身的问题,而是文件组件缺失或者路径中有中文/空格导致的读取失败。这个排查顺序能帮你少走很多弯路。
# 在 Linux 终端里快速检查一个 shp 包的完整性 ls -la central_asia_latest/ # 期望看到 at least: central_asia_latest.shp/.shx/.dbf/.prj # 如果只有 .shp 和 .prj,基本可以判定这个包是残的这段命令做的是一次最基本的“体检”。完整 shapefile 至少要有 .shp(几何体)、.shx(几何索引)、.dbf(属性表)、.prj(坐标系);如果做空间查询还需要 .sbn/.sbx,做字段编码标注还需要 .cpg。参数上没有任何调优空间,缺文件就是缺文件,唯一稳妥的出路是回到数据源重新下载完整包。与其在缺文件之后手动补后缀,不如一开始就确认来源是否提供了全套组件。
2.2 prj 文件里的坐标系玄学:WGS84 和 Web 墨卡托能差出几十公里
.shapefile 本身不强制坐标系,真正决定数据落在哪里的是 .prj 文件。中亚五国常见的 .prj 有两种:WGS84 地理坐标系(EPSG:4326,单位是度)和 Web 墨卡托投影(EPSG:3857,单位是米)。前者用于真实地理计算很稳,后者用于 Web 地图底图很常见。麻烦的是,有些二手数据把 .prj 文件丢了,或者拷文件时漏掉,QGIS 会默认按 EPSG:4326 加载,结果一张原本是 3857 的图被硬套上经纬度显示,五国边界直接缩成一小团。
判断方法是加载后看图层的“范围”:如果是 EPSG:4326,哈萨克斯坦的纬度范围大致是北纬 40 到 55 度;如果是 EPSG:3857,数值会是几十万到几百万的大数。一旦发现数值不对,右键图层 -> 设置 CRS -> 手动选择 EPSG:3857 即可纠正显示,但注意这只改了视图,没改数据本身。
# 用 ogrinfo 读取 shp 的坐标系信息(GDAL 自带) ogrinfo -so central_asia.shp central_asia # 输出中查看 Layer SRS WKT 字段 # 常见结果1: GEOGCRS["WGS 84", ...] -> EPSG:4326 # 常见结果2: PROJCRS["WGS 84 / Pseudo-Mercator", ...] -> EPSG:3857ogrinfo 是 GDAL 工具集的成员,这条命令不加载图形界面,直接读文件的元数据。Layer SRS WKT 字段会以 WKT 字符串打印坐标系定义,看到 GEOGCRS 就是地理坐标,看到 PROJCRS 就是投影坐标。如果输出是 PROJCRS 且单位为 metre,但你的下游任务要求经纬度,就必须做坐标转换,不能直接拿数值用。
3. 获取一份能直接用的中亚五国 shp:三个来源与筛选标准
3.1 三个可靠来源
中亚五国的行政边界数据,主流来源无非三类:全球行政区划库、众包地图数据、专业地理数据商。全球行政区划库以 GADM 为代表,覆盖到国界和一级行政区,产出的就是 .shp 压缩包,非常标准;众包地图数据(如 OpenStreetMap 的 relation 关系导出)几何精度不错,但属性表里没有行政区划代码,后续关联统计数据要自己拼;专业数据商优点是精度和售后,缺点是贵,一份五国边界可能报价上千。
我个人的筛选标准排序是:先问“坐标系是否明确”,再问“边界是否含争议区域,比如里海沿岸的划分”,最后才问“属性表里有没有 ISO 3166-1 的 alpha-3 代码”。前两项决定数据能不能用,最后一项决定好不好用。没有 alpha-3 代码(如 KAZ、KGZ、TJK、TKM、UZB),做地图配色和外部数据关联时都得手工映射,非常痛苦。
# 用 geopandas 读出 shp 并检查核心字段 import geopandas as gpd gdf = gpd.read_file("central_asia.shp") print(gdf.columns.tolist()) # 理想字段:['NAME', 'ISO_CC', 'geometry'] # 只有 geometry 没有 NAME 的数据要慎重,后续出图做标注会非常麻烦 print(gdf['ISO_CC'].value_counts())这段代码是拿到任何 shp 后我必跑的第一步。read_file自动读取 .dbf 里的属性表,columns.tolist()让你立刻知道有什么字段;value_counts()则确认五个国家的代码是否齐全。注意如果ISO_CC字段缺失,可以退一步用NAME字段人工映射,但如果NAME也没有,这份数据基本就是“裸几何体”,地图上画出来是一条线,落到业务上连“哪个多边形是哪个国家”都分不清。
3.2 不要迷信“最新版”:五国边界的变化没那么快,但属性表的差异大
“最新版”三个字对数据采购决策的影响,经常被高估。中亚五国的国界是稳定的国际边界,短期内不会有大变动,2020 版和 2024 版在几何图形上几乎看不出区别。真正迭代频繁的是属性表里的行政区划代码、城市人口字段、道路等级,这些与边界线无关。如果要的是“五国国界 + 一级行政区边界”,任何近五年内的版本都能用,没必要追新。
反之,如果拿到的数据声称是最新版,但 .prj 文件缺失、属性表里只有 FID 和 geometry,那这个“新”很可疑,不如选老牌 GADM 的稳定版本。还有一类要警惕的是“五国合一”还是“五国分开”的组织方式:一个文件包含五个国家的所有多边形,还是每个国家一个独立的 shp?前者适合整体出图,后者适合分国别做分析,没有哪个更好,取决于你的工作流。
4. 跑通最小落地:QGIS 加载与 Python 导出全流程
4.1 用 QGIS 做第一次可视化和行政区合并
拿到一份齐整的中亚五国 shp 后,第一步永远是可视化确认——看几何是否闭合、边界是否跨界、五国是否齐全。QGIS 加载方式很简单:菜单 -> 图层 -> 添加图层 -> 添加矢量图层,选中 .shp 文件即可。加载后如果多边形填充色是统一的,右键图层 -> 属性 -> 符号化,按NAME字段做“分类”渲染,五种颜色就出来了,这时候五国边界是否完整一眼便知。
一个常见需求是把五国合并成一个整体轮廓,用来做区域 mask。这时用 QGIS 的“矢量 -> 地理处理 -> 融合”工具,融合字段选NAME或留空,输出的就是五国合并后的单多边形。如果只是想提取哈萨克斯坦一个国家的边界,则用“矢量 -> 地理处理 -> 提取”写表达式"NAME" = 'Kazakhstan'即可。
# 如果数据在 PostGIS 里,SQL 也能做同样的融合 SELECT ST_Union(geom) AS geom FROM central_asia WHERE iso_cc IN ('KAZ','KGZ','TJK','TKM','UZB');上面这段 SQL 展示了 QGIS 图形界面背后的逻辑:ST_Union把所有小多边形焊接成一个整体。WHERE条件里的五国 alpha-3 代码决定了融合范围;如果你只想融合哈萨克斯坦,把条件改成iso_cc = 'KAZ'即可。参数上唯一要留意的是ST_Union在数据量极大时非常吃内存,但五国国界这种量级毫秒级完成,不需要优化。
4.2 用 Python 做属性筛选和 WKT 导出
更多时候,shp 只是项目的中间产物,最终要交给下游程序的是 WKT 文本。比如把中亚五国的国界导入关系型数据库,或者交付给不读 GIS 文件的算法同学,WKT 就是最通用的交换格式。用 geopandas 做这个转换非常直接:
import geopandas as gpd gdf = gpd.read_file("central_asia.shp") # 确保坐标系是 WGS84 再导出 WKT,否则经纬度数值是错的 if gdf.crs.to_epsg() != 4326: gdf = gdf.to_crs(epsg=4326) # 逐行导出 WKT,带上国家名称字段 with open("central_asia.wkt", "w", encoding="utf-8") as f: for name, geom in zip(gdf["NAME"], gdf.geometry): f.write(f"{name}\t{geom.wkt}\n")这段代码关键有三处。第一,to_crs(epsg=4326)的时机必须在导出 WKT 之前,否则坐标系不对输出的是投影坐标而非经纬度;第二,geom.wkt输出的是该行要素的完整几何文本,多边形内部如果有洞或者多部件,WKT 里会用POLYGON或MULTIPOLYGON类型标注;第三,tab 分隔的写文件方式让结果能被 pandas、R 或者文本编辑器直接读取,后续要转 GeoJSON 也能用gdf.to_file("central_asia.geojson", driver="GeoJSON")一条命令搞定。
geometry列是 geopandas 的特殊列,承载的是矢量几何对象,任何几何运算(比如求面积、算质心、做 buffer)都要走这一列。对新手最友好的一点是:它自带.wkt属性,不用调 GDAL 命令行就能导出文本,省去不少学习成本。如果你拿到的数据是 MultiPolygon(比如哈萨克斯坦存在飞地),WKT 导出不会报错,但下游 SQL 解析时要注意用ST_GeomFromText并指定正确 SRID。
4.3 转 WKB 的另一个选择
WKT 是人可读的文本,优点是透明、可调试;缺点是文件体量大,一个五国国界转成 WKT 可能几 MB,在数据库里做空间索引也相对慢。如果一定要最佳性能,常见做法是转 WKB(Well-Known Binary),用 geopandas 的geom.wkb就能拿到二进制,但对于“五国国界”这种几十 KB 到几 MB 的数据量,WKT 和 WKB 的差异可以忽略。只有当数据量到百万多边形级别,才值得认真考虑二进制格式,一般从业者不需要在这个层面纠结。
5. 避坑手册:中亚五国 shp 使用中的 5 条血泪经验
5.1 里海沿岸边界形态不一致
现象:两份不同来源的中亚数据,土库曼斯坦和哈萨克斯坦的里海沿岸线形状明显不同,一个平滑,一个锯齿状。
原因:里海是湖泊,不是公海,各国对沿岸线的主张存在差异,不同数据源采用的海岸线基准不同。这不是数据错误,而是制图规范不同。
解决:下游任务如果是出图,任选一份,只要全图统一用同一来源即可;如果是做面积统计,面积差异可能达到几个百分点,这时必须在报告中注明数据来源和日期,否则面积数字无法复现。
5.2 费尔干纳盆地边界与飞地问题
现象:乌兹别克斯坦和吉尔吉斯斯坦在费尔干纳盆地存在互相嵌入的飞地,比如乌兹别克斯坦的索赫飞地完全被吉尔吉斯斯坦包围,加载后这些飞地有时显示异常,名称标注重叠。
原因:飞地在大多数数据集中被处理为独立多边形,但属性表里的“所属国家”字段可能标注不一致,有的标飞地所在国,有的标实际所属国,导致查询时国家面积统计错乱。
解决:做区域分析前优先检查NAME_2或NAME_1字段,把所有飞地的ISO_CC统一为实际所属国代码。如果数据源没有飞地区分字段,宁可保留原始状态,也不要手动改,因为你手动改错的风险远大于数据源自身的偏差。
5.3 哈萨克斯坦的西部边界延伸到欧洲
现象:哈萨克斯坦最西部的多边形跨越了乌拉尔河,部分区域位于传统地理分界线的欧洲一侧,导致“亚洲”数据集里出现欧洲坐标。
原因:这是地理事实,不是数据错误。哈萨克斯坦是跨洲国家,国土自然延伸到欧洲部分。
解决:如果项目严格要求“亚洲范围”裁剪,用 PostGIS 的ST_Intersects或 QGIS 的裁剪工具按欧洲边界做切割即可。但多数业务场景不需要做这个裁剪,别为了“概念上干净”而主动引入边界争议。
5.4 属性表字段编码乱码
现象:用 Python 读取 shp,NAME字段里的国家名显示为乱码,比如 “Қазақстан” 变成一串看不懂的符号。
原因:dbf 属性表的文本编码不是 UTF-8,通常是 CP1251 或 CP1252。GeoPandas 默认按 UTF-8 解析,西里尔字母就被打散了。
解决:读取时显式指定编码,代码改为gpd.read_file("central_asia.shp", encoding="utf-8");如果仍乱码,依次尝试encoding="cp1251"和encoding="latin1",总有一个能对上。这是为数不多的能靠参数调整解决的 shp 问题。
5.5 五国数据合并到一起后,几何出现细小缝隙
现象:单独加载每个国家的 shp 时一切正常,但把五个 shp merge 成一个大文件后,相邻国界之间出现白色细线或缝隙,缩放时尤其明显。
原因:相邻国家共享的边界在数字化时各画各的,没有经过拓扑一致性处理,微小的坐标差异导致多边形无法完全贴合。
解决:如果只是出图,用 QGIS 的 “矢量 -> 几何工具 -> 修复几何” 批量处理即可;如果是做面积计算,先融合后统计,融合能消除共享边界上的微小间隙误差。这个现象不是中亚特有的,全球所有国界数据都有,只是看数据源的精度有多高。
6. 收尾的压箱底技巧:在 Python 里快速校验一份未知 shp 的质量
拿到一份来源不明的中亚五国 shp 时,不要直接丢进地图引擎,也不要在 QGIS 里一个个点,用几行代码做自动化体检。
import geopandas as gpd gdf = gpd.read_file("unknown_central_asia.shp", encoding="utf-8") # 1. 几何类型分布 print(gdf.geom_type.value_counts()) # 期望结果是 Polygon 和 MultiPolygon 的混合;如果出现 GeometryCollection,大概率有问题 # 2. 面积合理性 gdf["area_km2"] = gdf.geometry.area / 1e6 print(gdf[["NAME", "area_km2"]].sort_values("area_km2", ascending=False)) # 哈萨克斯坦面积应接近 272 万平方公里,远超其他四国;如果结果里它最小,坐标系必然错了 # 3. 几何有效性 print(gdf.is_valid.sum(), "valid out of", len(gdf))这段代码三个检查点全是经验值。第一个检查geom_type,GeometryCollection通常是数据源把点、线、面混在一个要素里,对下游统计是灾难;第二个检查是对面积排序,“哈萨克斯坦最大”是铁律,如果排序结果异常就是坐标系或属性表映射问题;第三个检查is_valid,shapefile 里自相交多边形不算罕见,QGIS 显示没问题,但数据库空间查询时会被拒掉。三次体检都过了,这份数据才配进入正式流程。
我用这个流程处理过不少类似的区域数据,最大的体会是:shp 格式本身不难,难的是数据来源的完整性和坐标系的一致性。每一次“为什么这个国家不在图上”的翻车,根因几乎都落在 prj 缺失或者解码错误上,而不是数据本身不存在。按我上面说的顺序做完整性检查和坐标系确认,至少能挡掉一半的后续事故。希望帮到你。
最后再补一个实战习惯:在项目交付前,导出 WKT 并抽查前 3 行的长度单位。如果一行的 WKT 里坐标值是 42.x、43.x 这样的两位数,说明坐标系是对的;如果是 7000000 以上的七位数,说明投影坐标被当作经纬度输出了。这一条在跨团队交接时尤其重要,因为对方很可能不问坐标系就直接入库。希望你从这个细节开始,建立起对矢量数据的敏感度——坐标系对不对,永远比图层颜色好不好看看更重要。
本文还有配套的精品资源,点击获取