ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

带南海的全国地市级底图:china_basic_map数据解析与制图实践

带南海的全国地市级底图:china_basic_map数据解析与制图实践 简介一款基于1:400万比例尺的中国地图地理数据产品重点呈现地市级以上居民地信息并完整包含中国南海区域。在此比例尺下图上1单位约相当于实地400万单位适合宏观区域概览仍能清晰展现地级市与县级行政中心、主要道路、水系等基本要素便于城市布局对比与区域结构分析。地图数据适用于地理科研、教学设计、城市规划、宏观导航及南海议题研讨可帮助用户直观把握行政区划与海域空间关系。压缩包约2.13MB包含一个地图数据主文件内容简洁紧凑可供主流GIS平台加载查看也可导出或叠加其他专题图层使用。已有158人学习下载。通过该地图读者既能获得全国地市级以上居民地的整体框架也能重点识别南海主要岛屿、礁石、航道及海域标注为理解海洋权益范围、生态环境和资源分布提供基础底图支持。面向研究者、政策制定者与教育工作者是一份兼具实用性和参考价值的地理数据。1. 从一张“全国地市图”说起china_basic_map 带南海的数据底图做 GIS 的人应该都有过这种经历项目需要一张全国地市级以上的宏观底图网上下载的“全国行政区划图”要么只画到大陆轮廓要么把小比例尺南海诸岛糊在角落出图比例完全不受控。我拿到china_basic_map这份数据时第一反应是检查两件事地市级居民地要素是否齐全南海范围是否被完整纳入。这份资源以 1:400 万比例尺描述了全国地市级及以上居民地文件名为china_basic_map关键点在于“带南海”也就是说图幅范围、要素组织都考虑了南海区域省去了手工拼接和比例尺对不齐的麻烦。适合做区域规划、人口分布趋势分析、环境区划专题图和教学底图下面按实际处理流程拆开讲。2. 解析china_basic_map的文件格式与1:400万坐标基准拿到一份 GIS 数据先不要急着砸进 ArcMap搞清楚格式、比例尺和坐标基准后面才不会被莫名其妙的空间位置偏差耽误时间。这一章从 1:400 万比例尺的实际含义、常见文件格式的识别方式、以及坐标系对南海图幅的影响三个角度展开。2.1 1:400万比例尺意味着什么比例尺的本质是图上距离与实际距离的比值。1:400万即图上 1 厘米代表实际 40 千米1 毫米代表实际 4 千米。在这个比例尺下地级市行政范围大概一两个平方厘米居民点要素可以表示为点或小面而乡镇级边界已经无法清楚区分。所以这份数据适合做宏观对比和制图综合不适合街道级分析。下面的表给出了不同比例尺的适用场景参考比例尺图上1cm代表实地典型用途1:100万10 km省级行政区划、资源分布图1:400万40 km全国性专题图、区域规划底图1:1000万100 km亚洲或全球范围示意1:2500万250 km世界地图、宏观区位图了解比例尺之后还要想一个问题1:400万的数据从哪里来。最常见的来源是国家基础地理数据中的市县级面边界经聚合抽稀得到的成果要素字段通常保留了地市名称、行政代码和省份信息而几何精度被刻意降低到一个适合视觉表达的容差。因此用它做分析时要意识到边界线与真实地界可能有一到两个像素的偏移这种偏移不影响全国尺度的趋势判断但如果叠加高精度遥感影像就能明显看出误差需要预先把结果说清楚。2.2 文件格式的判断与驱动匹配文件列表里只有一个china_basic_map没有扩展名这在实际下载资源里很常见。GIS 数据格式里GeoJSON、KMZ、GeoTIFF 都是单文件而 Shapefile 则要求.shp、.shx、.dbf、.prj等多个文件并存。如果只拿到一个文件第一步就是用工具自动探测它到底是哪一种而不是手工改扩展名。fiona是 GDAL 的 Python 封装可以直接读取文件头和图层信息import fiona # 不指定扩展名让fiona尝试自动识别文件驱动 path china_basic_map try: with fiona.open(path) as src: print(驱动:, src.driver) print(图层数量:, len(src)) print(坐标系:, src.crs) except Exception as e: print(自动识别失败:, e) # 常见情况是没有识别出扩展名尝试常见的后缀 for suffix in [.shp, .geojson, .json, .kmz, .tif]: try: with fiona.open(path suffix) as src: print(suffix, -, src.driver, src.crs, len(src)) except Exception: pass这段代码先按无后缀方式打开让 GDAL 通过文件内容判断驱动失败则依次尝试.shp、.geojson、.kmz、.tif等常用后缀。src.driver返回如ESRI Shapefile或GeoJSON这样的驱动名src.crs返回坐标参考系len(src)是要素总数。需要注意如果探测出 Shapefile但目录里缺少.prj文件src.crs会返回空值这时需要从元数据或原发布说明里补坐标信息不然后续所有投影计算都会出错。不同格式存储特点可以看下面这张表格式单文件坐标系存储位置适用工具Shapefile否.prj文件QGIS、ArcGIS、GeoPandasGeoJSON是顶层crs属性不强制Web地图、PostGIS、GeoPandasKML/KMZ是文档内 GroundOverlay 或 CRS 标签Google Earth、浏览器GeoTIFF是文件头地理标签栅格分析、遥感处理fiona.open的自动识别在多数本地文件场景下够用但如果拿到的是一个没有合法扩展名的自定义压缩包最好先解压看目录结构。我见过不少资源发布时把.shp的三个附属文件打包进一个同名子目录真正读取路径要指向子目录中的.shp文件而不是外层压缩包名。2.3 坐标系基准与带南海的范围约定全国 1:400 万数据常见的坐标基准有两种WGS84 和 CGCS2000两者在平面位置上的差异通常小于 1 米在 1:400 万比例尺下视觉上完全看不出来。但投影方式差别就大了经度纬度直接叠加到平面图上必须明确是用地理坐标还是投影坐标。一般全国图习惯用 Albers 等积圆锥投影或 Lambert 等角圆锥投影前者适合面积统计后者适合方向、形状保持。如果你只是出图看分布选 WGS84 地理坐标直接绘图也没问题一旦要做面积汇总、距离测量就一定要转成投影坐标。import geopandas as gpd gdf gpd.read_file(china_basic_map) print(原始CRS:, gdf.crs) # 如果原始CRS为空先假定WGS84再转Albers if gdf.crs is None: gdf gdf.set_crs(EPSG:4326) # 转换到Albers等积圆锥投影适合中国全境面积分析 gdf_albers gdf.to_crs(projaea lat_125 lat_247 lat_00 lon_0105 datumWGS84) print(转换后CRS:, gdf_albers.crs)参数说明set_crs用于给没有坐标信息的图层指定坐标EPSG:4326是 WGS84 经纬度坐标to_crs将要素转换到目标投影目标字符串里projaea表示 Albers 等积圆锥lat_125和lat_247是两条标准纬线lon_0105是中央经线这样整个中国区域包括南海都能落在较小的变形范围内。带南海的数据处理时要特别注意一个细节to_crs会统一转换所有要素所以只要主图里有南海诸岛转换后它们仍然和大陆保持正确的相对位置。但如果你是自己手动拼接的南海附图就必须主图和附图使用同一个投影参数否则会出现南海附图被拉伸或偏出图框的问题。3. 用GeoPandas读取并整理地市级以上居民地数据格式和坐标搞清之后就可以把数据真正读进来做属性整理了。GeoPandas 的 API 习惯和 Pandas 很像适合快速翻看要素属性、过滤筛选以及做空间叠加。这里按实际流程讲一遍先读数据再字段清洗再做空间筛选。3.1 读取并检查数据项GeoPandas 的read_file可以直接读取 Shapefile、GeoJSON、GeoPackage 这些常见格式不指定扩展名时也能借助底层 GDAL 自动识别。读进来后第一件事是查看crs、columns和几何类型确认居民地是点还是面数据。import geopandas as gpd gdf gpd.read_file(china_basic_map.shp) print(CRS:, gdf.crs) print(几何类型: , gdf.geom_type.unique()) print(字段列表:, gdf.columns.tolist()) print(gdf.head(10).to_string())这段输出能帮你在几十秒内判断数据是否完整。gdf.geom_type.unique()返回[Point]、[Polygon]或[Point, Polygon]等组合。如果居民地是点但你又需要地市行政面边界做填充则该文件里通常还包含面要素只是没有一起读出来这时就要用层名称区分。字段列表里如果看到NAME、GB、PROVINCE这类英文缩写大概率是国家基础地理数据风格中文名如地市名称、行政代码则可能是后期整理的成果。建议先把多余的字段删掉只留名称、省份、行政代码三个核心字段避免后续 join 时类型冲突。3.2 地市级以上居民地的属性筛选与字段整理原始数据名称不规范是最常见的问题。比如有的记录叫“省直辖县级行政单位”有的叫“地级市”还有开发区、林区等特殊区划。如果数据源声称“地市级以上居民地”那属性表里一般会有分类字段。假设字段名为type筛选逻辑可以这样写# 只保留地级市、直辖市、省会/首府类型 keep_type [地级市, 直辖市, 省会, 首府, 自治州] filtered gdf[gdf[type].astype(str).isin(keep_type)].copy() # 统一显示名称去除括号备注 filtered[display_name] filtered[name].astype(str).str.replace(r.*, , regexTrue) # 用省份和名称拼接唯一标识避免跨省重名 filtered[label] filtered[province] - filtered[display_name] print(filtered[[label, type, geometry]].head())代码逻辑要注意三点第一astype(str).isin(keep_type)是防御性写法因为字段里可能出现空值或类型不一致第二正则替换去掉了名称里的“含xx区”之类备注让出图标签更干净第三用“省份-名称”做唯一标识可以规避“朝阳区”这类跨省同名问题。筛选完成后检查一下残留的要素数量如果比国家实际地级行政单位数量少很可能是type字段有缺失这时可以改用行政代码前缀筛选地级市代码通常以 4 开头且末两位非 00但具体要看数据源的编码规则。下面的字段表可以对照查看字段名示例用途name杭州市基本名称type地级市行政区划类型province浙江省所属省份adcode330100行政区划代码population8500000人口信息可选3.3 叠加分析与省级界线、南海范围线相交在专题制图中经常需要把南海区域的边界范围线与地市级居民地点合并展示。如果带南海的数据把南海界线单独做成了一个面或线图层就要做空间叠加把落在南海界线内的居民地单独提取出来。# 假设sea是一个包含南海范围线的面图层 sea gpd.read_file(sea_boundary.geojson) # 统一坐标系 sea sea.to_crs(gdf.crs) # 方式一直接把数据裁剪到南海界线多边形范围内 south_china_cities gpd.overlay(gdf, sea, howintersection) # 方式二只筛选中心点落在南海范围内的要素 sea_union sea.geometry.unary_union south_china_cities2 gdf[gdf.geometry.centroid.within(sea_union)] print(south_china_cities.head())gpd.overlay的howintersection会返回两个图层几何相交的部分适合面要素如果居民地是点用centroid.within(sea_union)更轻量它会把多边形的unary_union先合并成一个组合几何再判断每个点的中心是否落在其中。要注意overlay对几何拓扑要求较高如果sea图层存在自相交或缝隙结果可能产生碎片要素。遇到这种情况先用sea.geometry.buffer(0)修复无效几何再继续叠加。4. 南海诸岛的制图实现从数据范围到分图框出图带南海的全国底图出图效果和普通地图最大的不同在于南海区域如何呈现。这一章讲清楚南海数据是怎么组织的以及两种主流出图方案直接用一个大图框包含全国和南海或者用“主图南海附图”的拼接方式。4.1 南海诸岛在数据中的组织方式打开china_basic_map后建议先检索一下图层里和南海相关的要素。名称可能带有“南海”“诸岛”“海域”等字样也可能是独立的几何类型。用下面的代码快速定位import geopandas as gpd gdf gpd.read_file(china_basic_map) # 检索名称中含南海/诸岛的要素 sea_like gdf[gdf[name].astype(str).str.contains(南海|诸岛|海域, naFalse)] print(sea_like[[name, geometry]].head()) print(要素数量:, len(sea_like))如果查询结果为空不代表数据不支持南海而是南海范围可能作为一条线附在国界要素里例如boundary字段里多出了“海域界线”记录。这时可以按几何范围截取南海区域大致对应经度 105°E 到 124°E、纬度 2°N 到 25°N把和该边界框相交的要素全部保留即可。需要留意的是有些资源把南海诸岛画成独立点集便于在小比例尺下逐个标注岛礁名称而行政边界和九段线则属于面或线图层两者不能混在同一图层里做样式控制。制图前最好把南海范围拆成单独的变量便于附图配置。4.2 matplotlib分图框拼接主图与南海附图用程序出图时最可控的方案是使用 matplotlib 的GridSpec或多个Axes。主图放置全国主要区域附图放在右下角或左下角。由于南海附图通常需要放到主图内的空白处推荐用fig.add_axes指定绝对位置而不是默认的网格平铺。下面的代码实现了一个简洁的主图南海附图拼接import matplotlib.pyplot as plt import geopandas as gpd gdf gpd.read_file(china_basic_map.shp) fig plt.figure(figsize(10, 12), dpi100) # 主图坐标系覆盖中国大陆主要范围实际范围按数据调整 ax_main fig.add_axes([0.02, 0.08, 0.92, 0.88]) # 绘制所有地市级以上居民地面和点分开控制样式 if Polygon in gdf.geom_type.unique(): gdf.plot(axax_main, facecolor#e8e8e8, edgecolor#444444, linewidth0.4) else: gdf.plot(axax_main, color#1f6feb, markersize3) ax_main.set_xlim([73, 135]) ax_main.set_ylim([18, 54]) ax_main.set_title(全国地市级以上居民地分布, fontsize14) # 创建南海附图放在主图右下角空白位置 ax_sea fig.add_axes([0.68, 0.16, 0.28, 0.28]) gdf.plot(axax_sea, facecolor#e8e8e8, edgecolor#444444, linewidth0.3) ax_sea.set_xlim([105, 124]) ax_sea.set_ylim([2, 25]) ax_sea.set_title(南海诸岛, fontsize10) # 关闭子图刻度避免影响整饰 ax_sea.set_xticks([]) ax_sea.set_yticks([]) ax_main.set_xticks([]) ax_main.set_yticks([]) plt.show()这里的核心参数是add_axes的四元组[left, bottom, width, height]使用归一化单位。主图范围[0.02, 0.08, 0.92, 0.88]占满画布附图[0.68, 0.16, 0.28, 0.28]定位在主图右下角既不遮挡海岸线又能完整显示南海诸岛。set_xlim和set_ylim直接决定了图幅范围主图如果希望大陆部分保留更多留白可以把 x 范围设为 73 到 135y 范围设为 18 到 54如果数据有完整南海边界并且不允许“断离”则主图应该直接包含南海坐标范围。两种方式的取舍要看数据说明如果资源本身已经把南海作为主图的一部分则不需要附图。一般“带南海”的数据更推荐一个图框全覆盖这样在投影转换、比例尺标注上不会出现主图和附图比率不一致的尴尬。4.3 QGIS打印布局中的多数据框设置如果是非程序员或希望快速出一个工程文件QGIS 的打印布局Print Layout比 matplotlib 更直观。操作步骤可以这样拆在图层列表里先加载主数据和南海数据确认两个图层的 CRS 一致。点击菜单“项目 → 新建打印布局”添加一个地图组件作为主视图。选中地图组件在“项目属性 → 图层”里设置范围和比例尺比如设置为 1:400万。再添加第二个地图组件将范围手动拖动到南海区域105°E到124°E2°N到25°N。在“项目属性 → 图层”中关闭不需要的图层让第二个组件只显示南海相关要素。两种方式中QGIS 的优点是出图符号化扩展丰富而且比例尺、图例、指北针都能自动同步。但有一个容易忽略的地方附图的比例尺如果和主图不同一定要在附图下方标注“不同比例尺”否则看图者会误以为附图与主图等比例。5. 动手收尾几何简化、坐标系校验与出图检查到这一步数据已经能画出来了但发布前还有两个细节值得花十分钟处理几何简化和尺度校验。这两步看着不起眼却能避免很大的返工。5.1 用shapely简化高精度边界原始数据如果是从 1:100 万或更高精度缩编而来边界线会有大量细碎节点放在 1:400 万比例尺下会显得很毛糙。用shapely的simplify方法可以按容差抽稀把不必要的折点去掉保持视觉整洁。# 按地理坐标容差0.01度约相当于1公里适合1:400万 gdf_simplified gdf.copy() gdf_simplified[geometry] ( gdf_simplified.geometry.simplify(tolerance0.01, preserve_topologyTrue) ) # 检查简化前后要素数量 print(原要素数:, len(gdf)) print(简化后要素数:, len(gdf_simplified))tolerance的单位与当前坐标系一致。如果数据是经纬度坐标0.01度约等于 1 公里正好匹配 1:400 万比例尺下的视觉精度如果数据已经是投影坐标tolerance的单位是米可以设为 1000。preserve_topologyTrue可以阻止简化过程中出现自相交或相邻面重叠这个参数非常关键越小的容差不一定会让图更快但一定能避免拓扑破碎。5.2 坐标转换与比例尺校验出图前还要做一次比例尺校验。方法很简单在主图里选两个已知实地距离的地级市用测量工具量一下图上距离再换算实际比例尺。例如从北京到上海直线距离约 1070 公里在 1:400 万比例尺下图面上应该是 2.675 厘米如果量出来的数差得太多说明坐标系或坐标系转换阶段出了问题。from shapely.geometry import LineString # 假设两个点已经投影到Albers坐标单位是米 city_a gdf.loc[gdf[name] 北京, geometry].values[0] city_b gdf.loc[gdf[name] 上海, geometry].values[0] distance_m city_a.distance(city_b) # 如果投影坐标用米则1:400万下的图上距离(cm) 实际距离(cm) / 4e6 cm_on_map distance_m * 100 / 4_000_000 print(图上距离估算值(cm):, round(cm_on_map, 3))city_a.distance(city_b)返回的是投影坐标平面上的直线距离单位是米。这个值只用于粗略校验它忽略了球面曲率但对全国尺度来说已经够用。如果算出来的图上距离远大于实际纸张允许值应检查to_crs的投影参数是否将经纬度错误解释为米。5.3 出图前检查项最后可以按下面这个清单快速过一遍数据防止小问题出差错检查项方法通过标准坐标参考print(gdf.crs)不为空且所有图层一致南海范围查看total_bounds包含经度 105°~124°纬度 2°~25°几何有效性gdf.is_valid.all()返回True行政代码唯一gdf[adcode].is_unique无重复名称空值gdf[name].isna().sum()0如果is_valid.all()返回False执行一行修复代码即可gdf.geometry gdf.geometry.buffer(0)。这套流程做完导出的图无论是丢进 PowerPoint 还是作为论文插图比例尺和行政边界都不会被退回重改。本文还有配套的精品资源点击获取
返回列表