
简介面向地理信息科学学习者和区域研究人员的这份中亚五国矢量图数据集覆盖哈萨克斯坦、乌兹别克斯坦、吉尔吉斯斯坦、塔吉克斯坦与土库曼斯坦的国界及空间轮廓可用于地图制作、土地利用规划、区域发展分析等场景帮助读者快速补齐中亚地区的基础地理底图。压缩包共8个文件约545KB以shp主文件配合shx索引、dbf属性表、prj坐标系统以及xml元数据、cpg编码等文件组成兼顾几何数据、属性字段与投影信息的完整读取。已有190人学习下载。数据将空间要素与属性信息相对应便于在ArcGIS、QGIS等主流GIS软件中查看、编辑和叠加分析也能为自然资源分布、交通网络与政治边界研究提供可复用的底图素材适合课程练习、专题制图和前期方案论证使用。1. 中亚五国矢量图不是一张图shp格式到底交付什么中亚五国矢量图shp格式这两个词放在一起时很多人第一反应是找一个能直接打开的压缩包真正做过区域底图交付的人更清楚难点从来不是“有没有图”而是这套shp能不能被别人稳定打开、字段能不能对上、坐标系会不会在下一环节把面积算翻。五国区域矢量图常见的交付物是一组面要素但shp格式不是单个文件它背后有几何、索引、属性、投影和编码五个部件。它适合需要做区域底图、空间统计、制图排版和边界质检的从业者。你要拿它做统计单元就得关心面要素是否闭合、编码是否唯一、面积字段能不能复算你要拿它做制图底图就得关心线要素和面要素是否分开、投影是否适合出图你只是想要一张截图没必要折腾shp。接下来按数据口径、字段设计、脚本落地、质检和避坑的顺序拆开讲。中间会给可直接抄的Python和ogr2ogr命令也会说清哪些参数不能拍脑袋改。2. 把五国边界拆成可落地的shp图层边界口径与字段设计2.1 先定边界口径国界、行政边界和海岸线不要混在一个图层shp格式最容易被误用的地方是把它当成“一个文件装下所有边界”。实际上一个shp文件只能承载一种几何类型面就是面线就是线点就是点同一个shp里混入面和线写入阶段就会报错或者被静默丢弃。五国区域矢量图如果既要给统计用又要给制图用常见做法是拆成两个图层面图层用于区域汇总和面积量算线图层用于边界表达和出图描边。边界口径要在动手前写清楚。面要素是按行政单元合并后的区域面还是保留内部行政层级的细分面线要素是只画外边界还是把内部行政线也保留这些不是格式问题是数据语义问题。我的习惯是先在work/raw里放一份原始面数据再用脚本派生出“区域面”和“边界线”两个成果而不是在原始文件上反复改。这样后面发现口径不对还能回到原始文件重跑。选shp而不是GeoJSON或GPKG通常不是因为它更先进而是因为接收方的老GIS工具链只认shp。shp的兼容性强但限制也很硬字段名最长10个字符一个图层只能一种几何类型属性表对空值和编码的处理不如现代格式干净。知道这些限制后字段设计就要提前收窄不要等写入后再回头改名。常见做法是面图层只保留名称、编码、层级、版本和备注线图层只保留边界类型和版本别把统计指标一股脑塞进去。2.2 shp字段最小集与属性表设计名称、编码、层级、版本字段设计的目标不是“信息越多越好”而是让接收方在不看说明书的情况下也能判断一行记录是谁、属于哪一级、来自哪个版本。DBF字段名超过10个字符会被截断所以字段名要用短名含义放在交付说明里。下面这张表是我一般会用的最小集面图层和线图层可以共用前四个字段。字段名类型长度用途注意点name字符80区域或边界名称不要放长描述长描述放说明文档code字符32稳定编码必须唯一不要用名称临时拼level字符16层级或边界类型面图层写层级线图层写边界类型ver字符16数据版本和文件名版本保持一致note字符120备注可空但不要塞换行符name不要用来做关联键名称会变编码不要变。code建议用固定规则生成不要用“名称拼音加序号”这种临时方案后面一改名称就全乱。level在面图层里可以表示汇总层级在线图层里可以表示边界类型但不要在同一字段里混两种语义。ver不是软件版本号是这批数据的版本标记写进属性表是为了让接收方能追溯。提示DBF字段名只认前10个字符admin_name和administrative_name在不少工具里会被截成同一个短名写入前先改成name这类短名。属性表里不要放面积字段作为唯一依据。面积可以算但要在投影坐标系里算而且要在交付说明里写清用的投影。把面积写进shp不是不行问题是接收方如果不知道投影就会拿地理坐标直接复算最后对不上。我的做法是shp里保留area_km2可选字段同时在质检报告里记录“面积由哪个投影算出”两者对不上时以报告为准。2.3 用ogr2ogr建立最小可复现目录和转换命令目录先定好后面所有命令都往固定位置写排错时不会在一堆临时文件里找。下面这组命令只做三件事建目录、把原始GeoJSON转成面shp、把面转成边界线。命令里的路径是相对路径换成自己的工程目录即可。# 建立最小工作目录raw放原始数据out放成果qa放质检报告 mkdir -p work/raw work/out work/qa # 将原始GeoJSON转为面shp统一几何类型为MULTIPOLYGON写入UTF-8编码 ogr2ogr -f ESRI Shapefile work/out/region.shp work/raw/region.geojson \ -nlt MULTIPOLYGON \ -lco ENCODINGUTF-8 \ -a_srs EPSG:4326 # 从面shp派生边界线shp只保留边界几何不保留面属性中的统计字段 ogr2ogr -f ESRI Shapefile work/out/region_boundary.shp work/out/region.shp \ -nlt MULTILINESTRING \ -lco ENCODINGUTF-8 \ -dialect SQLite \ -sql SELECT name, code, level, ver, ST_Boundary(geometry) AS geometry FROM region第一段mkdir是固定工作区raw和out分开是为了保留可回滚的原始数据。-nlt MULTIPOLYGON把几何类型钉死避免源数据里混入POLYGON和MULTIPOLYGON导致写入不稳定-lco ENCODINGUTF-8让DBF按UTF-8写并配套生成.cpg这一步不做后面打开就是乱码。-a_srs EPSG:4326是给源数据补一个地理坐标系声明前提是原始数据确实是经纬度如果原始数据已经是投影坐标不要硬套这个参数。第二段用SQLite方言执行ST_Boundary把面转成线。-sql里的字段列表要和目标shp字段对得上name、code、level、ver都在面shp里存在如果面shp字段被截断这里就会报找不到字段。-nlt MULTILINESTRING保证线图层只有一种几何类型。-dialect SQLite不是必须每次都写但涉及几何函数时写上更稳。执行完先别急着打包用ogrinfo -so看图层摘要确认几何类型、字段数、坐标系和要素数。命令如下# 查看面shp的图层摘要重点看Geometry、Feature Count、Extent和Layer SRS ogrinfo -so work/out/region.shp region # 查看线shp的图层摘要确认几何类型是MultiLineString ogrinfo -so work/out/region_boundary.shp region_boundaryogrinfo -so只读摘要不改数据。Geometry看几何类型是否和预期一致Feature Count看要素数有没有在转换中丢失Extent看范围是不是落在合理区间Layer SRS看坐标系有没有丢。如果Layer SRS为空说明.prj没写出来后面面积和叠加都会出问题。这个检查只要几秒钟但能挡掉很多返工。3. 用Python把五国矢量图落成shp从GeoJSON到投影、编码和索引3.1 环境与依赖geopandas、fiona、pyproj怎么锁Python侧我一般用GeoPandas读数据、Shapely做几何检查、PyProj处理投影写shp时由Fiona/GDAL落到磁盘。依赖不要追最新锁定到团队验证过的一组版本把requirements.txt和成果一起归档。下面只列安装命令不写具体版本号版本号按你们内部基线填。# 建议在独立虚拟环境中安装避免和系统GIS库互相污染 python -m venv .venv source .venv/bin/activate # 安装读写shp和做投影、几何检查所需的库 pip install geopandas shapely pyproj fiona虚拟环境是为了隔离依赖。geopandas负责表结构和读写shapely负责几何有效性和边界操作pyproj负责坐标系转换fiona是底层读写驱动之一。安装后先跑一个最小导入检查确认fiona能识别ESRI Shapefile驱动import fiona import geopandas as gpd import pyproj # 查看当前环境支持的矢量驱动确认ESRI Shapefile在列表里 print(fiona:, fiona.__version__) print(geopandas:, gpd.__version__) print(pyproj:, pyproj.__version__) print(shapefile driver:, ESRI Shapefile in fiona.supported_drivers)这段代码只做环境自检不碰业务数据。fiona.supported_drivers里如果看不到ESRI Shapefile后面to_file会直接失败先修环境再谈数据。版本号打印出来是为了写进质检记录不是为了追新同一批交付最好保持同一套环境否则字段截断和编码行为可能不一致。3.2 读写shp的最小脚本编码、字段名和几何类型下面这个脚本把原始GeoJSON读进来重命名字段、裁掉多余列、修复无效几何再写成shp。字段名在写入前就压到10个字符以内避免DBF截断后出现重名。from pathlib import Path import geopandas as gpd from shapely.validation import make_valid src Path(work/raw/region.geojson) dst Path(work/out/region.shp) gdf gpd.read_file(src) # 把长字段名映射为shp友好的短名只保留交付需要的列 rename_map { adm_name: name, adm_code: code, admin_level: level, data_version: ver, remark_text: note, } gdf gdf.rename(columns{k: v for k, v in rename_map.items() if k in gdf.columns}) keep_cols [name, code, level, ver, note, geometry] gdf gdf[[c for c in keep_cols if c in gdf.columns]] # 修复无效几何空几何先标记出来不直接静默丢弃 gdf[geometry] gdf.geometry.apply( lambda g: make_valid(g) if g is not None and not g.is_empty and not g.is_valid else g ) # 写入shpencoding指定UTF-8driver固定为ESRI Shapefile gdf.to_file(dst, driverESRI Shapefile, encodingUTF-8) print(written:, dst, features:, len(gdf))rename_map把源字段压成短名keep_cols控制输出列避免把无关统计字段带进shp。make_valid只处理非空且无效的几何空几何保留下来后面质检阶段单独统计如果这里直接把空几何删掉接收方就不知道原始数据里有多少空记录。to_file里的encodingUTF-8会配套写.cpgdriverESRI Shapefile固定输出格式。写入后打印要素数和源数据对比数量对不上就回查字段映射和几何过滤。注意to_file写入时如果字段名超过10个字符不同GDAL版本的处理不完全一致有的截断、有的报错最稳的办法是写入前自己改成短名。3.3 投影转换与面积量算先定EPSG再谈精度地理坐标系下的度不能直接当面积单位用这是shp交付里最常见的翻车点。面图层要做面积统计先转到覆盖研究区的等积投影再算面积如果只是做底图显示用地理坐标系或适合出图的投影都可以但要在说明里写清楚。import geopandas as gpd gdf gpd.read_file(work/out/region.shp) # 全球等积投影适合做面积比较不适合直接拿来做大比例尺制图 AREA_CRS EPSG:6933 gdf_area gdf.to_crs(AREA_CRS) gdf_area[area_km2] gdf_area.geometry.area / 1_000_000 print(gdf_area[[name, code, area_km2]].head()) print(area crs:, gdf_area.crs)EPSG:6933是等积投影面积比例相对稳定适合先做区域间面积比较它的形状变形不适合直接出大比例尺地图。to_crs只转换几何不改属性表。geometry.area在投影坐标下返回平方单位除以1_000_000得到平方公里。打印area crs是为了把投影写进质检记录后面别人复算时能对上。如果研究区跨纬度很大全球等积投影仍然会有变形这时按区域自定义等积投影更稳。自定义参数要写进交付说明不要只留在脚本里。面积字段可以写进shp也可以只放在质检报告里我的习惯是shp里保留area_km2方便快速查看但报告里必须注明“面积由哪个投影算出”两者不一致时以报告为准。3.4 生成.shp/.shx/.dbf/.prj/.cpg五件套并做自检shp从来不是单个.shp文件完整交付至少要有.shp、.shx、.dbf、.prj、.cpg。写完后立刻做一次文件级自检不要等压缩包发出去再被问“为什么打不开”。from pathlib import Path import geopandas as gpd base Path(work/out/region) required [.shp, .shx, .dbf, .prj, .cpg] missing [suffix for suffix in required if not base.with_suffix(suffix).exists()] print(missing:, missing) gdf gpd.read_file(base.with_suffix(.shp)) print(crs:, gdf.crs) print(geom_types:, gdf.geom_type.value_counts().to_dict()) print(fields:, list(gdf.columns)) print(empty_geoms:, int(gdf.geometry.is_empty.sum())) print(invalid_geoms:, int((~gdf.geometry.is_valid).sum()))required列表就是五件套缺一个都不算完整交付。gdf.crs为空说明.prj有问题geom_types出现多种类型说明写入前没统一几何fields里有被截断的字段名说明短名映射没做干净empty_geoms和invalid_geoms是几何质量的第一道信号。这个脚本不修改数据只输出检查结果适合放在每次导出之后跑一遍。4. 五国矢量图shp的质检清单拓扑、属性、坐标系与压缩包4.1 几何有效性检查自相交、空几何、重复要素几何检查不要只看“能不能打开”要看“能不能参与叠加和统计”。自相交、空几何、重复要素这三类问题在区域面数据里很常见尤其是从不同来源拼接后。下面这段代码把无效几何、空几何和重复几何分别找出来。import geopandas as gpd from shapely.validation import explain_validity gdf gpd.read_file(work/out/region.shp) invalid gdf[~gdf.geometry.is_valid] empty gdf[gdf.geometry.is_empty] dups gdf[gdf.geometry.to_wkb().duplicated(keepFalse)] for idx, row in invalid.iterrows(): print(invalid, idx, explain_validity(row.geometry)) print(invalid_count:, len(invalid)) print(empty_count:, len(empty)) print(duplicate_count:, len(dups))is_valid判断几何是否满足OGC简单要素规则explain_validity给出自相交或环方向问题的原因。is_empty单独统计空几何空几何不一定无效但会让面积统计出现0值。to_wkb把几何转成二进制再查重能发现坐标完全一致的重复面。重复要素不一定要删先看是不是同一区域的多版本记录如果code相同但ver不同保留版本记录不要一刀切去重。4.2 属性完整性检查名称缺失、编码重复、字段截断属性问题比几何问题更隐蔽因为shp打开后看起来正常一到关联表就发现code对不上。检查项至少包括关键字段空值、编码重复、字段名长度、字段值长度。import geopandas as gpd gdf gpd.read_file(work/out/region.shp) key_cols [name, code, level, ver] print(null_counts:) print(gdf[key_cols].isna().sum()) print(duplicated_code:, int(gdf[code].duplicated().sum())) for col in key_cols: max_len gdf[col].astype(str).str.len().max() print(col, max_len:, max_len)isna().sum()看关键字段缺失code重复数看唯一性。字段值长度要对照shp字段长度设置name超过80个字符会被截断note超过120个字符也会截断。截断不一定报错但会让接收方看到不完整的名称。字段名长度在写入前已经控制过这里再打印一次列名确认没有出现name_1、code_1这类自动改名。4.3 坐标系与范围检查.prj缺失和“假坐标”识别.prj缺失时有的工具会默认按经纬度打开有的工具会直接不认坐标。更麻烦的是“假坐标”数据本身是投影坐标但.prj写成了地理坐标系打开后范围看着像经纬度实际数值完全不对。检查时同时看.prj是否存在、crs是否为空、total_bounds是否落在合理区间。from pathlib import Path import geopandas as gpd shp Path(work/out/region.shp) gdf gpd.read_file(shp) print(prj_exists:, shp.with_suffix(.prj).exists()) print(crs:, gdf.crs) print(bounds:, gdf.total_bounds)prj_exists只说明文件在不在crs说明GDAL有没有解析出来。total_bounds返回最小经度、最小纬度、最大经度、最大纬度如果crs是地理坐标系数值应该落在经度-180到180、纬度-90到90的范围内如果数值是几十万、几百万说明数据是投影坐标.prj却可能写错了。发现范围异常时先查源数据的坐标系声明不要直接在成果上改.prj改错会把问题传给下一环节。4.4 交付前打包压缩、校验和、目录说明打包不是把.shp拖进压缩包就完事。五件套要放在同一层目录压缩包内不要带绝对路径生成校验和附一份短说明。下面命令在成果目录内执行压缩包只包含五件套和说明文件。cd work/out # 五件套必须一起压缩缺一不可 zip -r region_shp_delivery.zip \ region.shp region.shx region.dbf region.prj region.cpg \ region_readme.md # 生成校验和接收方解压后可复核 sha256sum region_shp_delivery.zip region_shp_delivery.zip.sha256zip -r把五件套和说明打在一起region_readme.md里写清字段含义、坐标系、面积算法和版本号。sha256sum生成校验和接收方解压前先核对能挡掉传输损坏。压缩包内不要放work/raw原始数据也不要放中间脚本交付包只放接收方需要的东西。打包后再解压一次用ogrinfo -so打开确认避免“压缩包能解压但shp打不开”的低级问题。5. 避坑与排查shp格式在五国矢量图交付里最容易翻车的5件事5.1 现象打开后属性表全是乱码名称列变成问号现象很直接shp能打开几何也正常但name列显示成乱码或问号。原因通常有两个写入时没有指定UTF-8编码或者压缩包里漏了.cpg文件。DBF本身不强制编码GDAL靠.cpg告诉读取端用哪种字符集.cpg缺失时老工具会按系统默认编码猜猜错就乱码。解决分三步。第一写入时显式指定encodingUTF-8并确认输出目录生成了.cpg。第二打包时把.cpg列进必带文件不要只压缩.shp、.shx、.dbf。第三接收方打开前先看.cpg内容如果是UTF-8读取端还乱码就让对方在导入时手动指定UTF-8。这个坑我踩过最后不是数据错了是压缩包少了一个几百字节的.cpg整批返工。5.2 现象字段名被截断两个字段变成同一个名字现象是字段名变短或者导入后出现name_1、code_1。原因是DBF字段名最长10个字符超过部分会被截断如果两个长字段名前10个字符相同截断后就重名。shp格式本身没有字段别名机制不能靠“显示名”绕过。解决要在写入前做。把字段名统一压到10个字符以内用短名加说明文档表达完整含义。脚本里加一道检查if len(col) 10: raise ValueError不要让GDAL静默截断。已经截断的成果不要靠改.dbf硬修重新从源数据跑一遍字段映射更稳。字段名短不是问题问题是接收方不知道ver代表版本在region_readme.md里写清字段字典比把字段名写长更可靠。5.3 现象面积算出来离谱同一区域两次结果差一个数量级现象是面积字段和接收方复算结果对不上有时差几倍有时差一个数量级。原因基本是投影问题地理坐标系下直接算面积单位是“平方度”不是平方公里或者shp的.prj写的是地理坐标系数据本身却是投影坐标工具按错误坐标系复算。解决是先确认crs再做投影转换。面积统计用覆盖研究区的等积投影算完把投影参数写进说明。接收方复算时用同一个投影不要用Web Mercator直接算面积高纬度地区变形很大。已经写进shp的area_km2只能作为参考质检报告里要写明“面积由哪个EPSG算出”。如果连.prj都不对先修坐标系声明再重算面积不要在错误结果上做二次统计。5.4 现象相邻面之间有缝隙或重叠叠加分析出现双计数现象是区域面拼接后出现细缝或者相邻面有重叠做叠加统计时同一块地被算两次。原因是不同来源的边界精度不一致或者从线转面时没有做拓扑清理。shp不存储拓扑关系它只存几何所以缝隙和重叠不会自动被发现。解决分两步。先做几何有效性检查和重叠检查把自相交、重复面、面积异常的面找出来再用统一的边界源重新构面或者用拓扑规则做吸附和裁剪。不要用手工拖点去补缝隙数据量一大就不可维护。交付前跑一次“相邻面共享边”检查至少确认主要相邻单元没有明显重叠。如果接收方只做制图缝隙可能看不出来一旦做统计这就是硬伤。5.5 现象压缩包解压后打不开提示缺少.shx或.dbf现象是对方收到压缩包解压后双击.shp打不开提示缺少文件。原因通常是打包时只选了.shp或者压缩工具默认隐藏了扩展名把.shx、.dbf漏掉了。shp是多个文件协同工作.shp存几何.shx存索引.dbf存属性.prj存投影.cpg存编码少一个都可能打不开或属性丢失。解决是把五件套写进交付清单打包后用另一台机器解压验证。压缩包内不要改文件名.shp、.shx、.dbf的主名必须一致改主名不会自动同步反而会让工具找不到关联文件。交付前用ogrinfo -so从压缩包解压目录打开一次确认几何、字段、坐标系都能读出来。这个动作只要一分钟能避免“文件发了但对方打不开”的来回扯皮。6. 把shp交付变成可复用资产版本号、元数据与一条快速验证命令6.1 版本号写进文件名和属性表别只写在聊天记录里shp交付最容易丢的是版本上下文。我的习惯是文件名带版本号属性表里也留ver字段两者保持一致。目录按版本分不覆盖旧版本接收方拿到region_v001.shp时能通过ver字段确认属性表里的版本。版本目录里放五件套、region_readme.md和校验和原始数据留在work/raw不进入交付包。位置写什么作用文件名region_v001.shp一眼看出批次属性表ver v001和文件名对齐说明文档字段字典、坐标系、面积算法接收方不用猜校验和region_v001.zip.sha256传输后复核6.2 一条快速验证命令先看摘要再决定要不要深入每次交付前我会跑一条固定命令先看图层摘要再决定要不要深入检查。命令不复杂但能同时看到几何类型、要素数、范围和坐标系。# 从交付目录直接读shp摘要确认五件套完整且坐标系可解析 ogrinfo -so work/out/region_v001.shp region_v001ogrinfo -so只读摘要不改数据。重点看四行Geometry是不是预期的面类型Feature Count和源数据是否一致Extent有没有离谱范围Layer SRS是不是目标坐标系。四项都正常再跑几何和属性检查有一项异常先修数据再打包。这个习惯让我少发了很多“看起来能打开、一算就错”的包。我自己的教训是shp交付的后悔药不在最后打包那一步而在字段名压短、编码写对、投影说清这三件事。前面偷懒后面就要用返工补。希望帮到你。本文还有配套的精品资源点击获取