news 2026/9/11 9:10:59

Natural Earth 110m 数据与经纬网格:从 GeoPandas 到 Web 地图投影实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Natural Earth 110m 数据与经纬网格:从 GeoPandas 到 Web 地图投影实践

简介:这份压缩包提供一套基于Natural Earth 110m比例尺的全球物理地图底图,面向GIS分析、环境研究与地图制图用户,尤其适合需要标准世界地理底图的项目与课堂场景,可帮助快速搭建空间数据基础框架。其中shp/dbf/shx构成几何与属性主体,prj定义坐标参考,cpg标识字符编码,html/txt则提供元数据说明;对于GIS新手也可直接作为入门练习数据。资源共130个文件,压缩包仅3.31MB,核心为18组shapefile矢量数据,数据覆盖经纬网格、陆地、湖泊、冰川、海洋与海岸线等要素,多档间隔的网格文件可满足不同制图比例需求;CHANGELOG记录版本更新,便于长期维护使用。该数据集可广泛用于自然资源普查、气候研究、城市规划、教学演示等方向。已有683人学习,下载后可在ArcGIS、QGIS等平台直接加载,用于底图叠加、空间分析与可视化输出。

1. 一张世界 physical 地图,网格层往往比海岸线还难处理

做数据可视化的人迟早会遇到这么一件事:底图已经用 Natural Earth 的 110m physical 数据画出了陆地、海洋和湖泊,视觉上很干净,但读者想知道「这张图里非洲西海岸那条线大概在北纬几度」,你却发现图上没有任何刻度可读。添加经纬网最省事的路径,不是现场用 shapely 生成网格线,也不是前端实时计算,而是直接用 Natural Earth 提供的 ne_110m_graticules 系列文件。这个文件组覆盖了 1 度、5 度和 10 度三种间隔的经纬网格,和 110m 分辨率的 physical 底图天然同源、同坐标、同投影基准。

标题里的 110m 代表 1:110,000,000 比例尺的数据集,这是 Natural Earth 三档分辨率里最轻的一档,陆地、海洋、湖泊、河流、冰盖和 graticules 都是为小比例尺世界地图准备的。physical 后缀意味着图层分类只看自然要素,不混入国界和城市。这篇文章就把这套数据的读取、绘图、Web 端使用和常见踩坑全部过一遍,代码可以直接抄。

2. 读取 110m physical 数据:从 shapefile 到 GeoDataFrame

2.1 110m 数据包里有哪些 physical 图层

在 naturalearthdata.com 的 Downloads 页面找到 110m Physical Vectors 文件组,下载后解压会得到一组文件名规整的 shapefile,全部使用 EPSG:4326(WGS84 经纬度)坐标。需要关注的图层大致如下:

文件名内容图形类型
ne_110m_land大陆面(含主要岛屿)Polygon
ne_110m_ocean海面多边形Polygon
ne_110m_lakes主要湖泊Polygon
ne_110m_rivers_lake_centerlines主要河流中心线LineString
ne_110m_glaciated_areas冰盖与冰川覆盖区Polygon
ne_110m_graticules_11 度间隔经纬网格LineString
ne_110m_graticules_55 度间隔经纬网格LineString
ne_110m_graticules_1010 度间隔经纬网格LineString
ne_110m_geographic_lines赤道、回归线、极圈等特殊线LineString

ne_110m_graticules的下载可能需要单独找,不同版本的打包方式略有差异。有的版本把 graticules 放在 physical 文件组里,有的版本把它归到 supplement 目录,例如改名成ne_110m_graticules_1.zip后存放。下载后先确认里面是线要素而不是面要素,避免和 land 图层搞混。

2.2 用 ogrinfo 和 GeoPandas 验证图层与坐标系

拿到文件后先别急着画图,先用 GDAL 的命令行工具确认几何类型、要素数量、字段和坐标系,这一步能省掉后面大量排错时间。

ogrinfo -ro -so ne_110m_graticules_10.shp ne_110m_graticules_10 | head -20

-ro表示只读打开,-so表示只输出概要信息,避免打印全部要素。输出里会显示 Layer name、Geometry 类型、Feature Count 和 Extent。如果 Extent 显示东西跨 ±180°,说明这个文件是完整的世界网格;如果只覆盖某个局部范围,多半是下载时选了裁剪版本。坐标参考信息里应该明确写着EPSG:4326,如果不是,所有后续投影计算都要先对齐坐标系。

接着用 GeoPandas 读入并检查更多元数据:

import geopandas as gpd grat = gpd.read_file("ne_110m_graticules_10.shp") land = gpd.read_file("ne_110m_land.shp") ocean = gpd.read_file("ne_110m_ocean.shp") print(grat.geom_type.unique()) print(grat.crs) print(len(grat))

这段输出的第一行应该是LineString,第三行是线的条数:10 度间隔的网格包含 17 条经线加 19 条纬线,左右边界各计一次,合计 36 条左右;5 度间隔约 72 条;1 度间隔则有 300+ 条。这个数量级决定了 Web 端加载时的体积差异:1 度网格的 GeoJSON 动辄几十 MB,10 度网格压缩后往往不到 1MB。我的经验是只在桌面出图场景用 1 度或 5 度,浏览器端明确建议用 10 度。

2.3 为什么队伍里要有 graticules,而不是现场生成

有人会问:经纬网格这么规则,用代码生成不就完了,何必下载文件?确实,用geopandas或者shapely生成等距经纬线并不难,但 Natural Earth 的 graticules 文件有几个细节值得直接复用:第一,它遵循WGS84的实际球面坐标,而不是简单的等距投影平面线;第二,它已处理了纬线在接近极点时的曲率,画在地图投影上时形变正确;第三,它是 LineString 而不是线段组合,导出 Web 用 GeoJSON 时轻便。

3. 用 Cartopy 把 physical 底图和 ne_110m_graticules 画在同一张图上

3.1 为什么优先 Cartopy 而不是直接 plot

GeoDataFrame 直接调用.plot()用默认笛卡尔坐标输出,出来的图是「经纬度等距」的样子,形状不对,比例感也差。Cartopy 的优势在于它把地图投影转换做得足够成熟,数据是 EPSG:4326,画图时指定目标投影,库内部完成重投影和裁剪,不需要自己写任何坐标变换公式。

world physical 地图适合用 Robinson 投影、自然地球投影或等距圆柱投影。Robinson 是 Natural Earth 官网展示时偏爱的投影,视觉上「世界感」最强;等距圆柱投影则是 Web 端最常用方案,经纬网横平竖直,适合做数据附图。

3.2 最小可运行绘图脚本

把下载好的 shapefile 放在当前目录,下面的脚本即可跑通一张含物理底图和经纬网格的世界地图:

import geopandas as gpd import matplotlib.pyplot as plt import cartopy.crs as ccrs grat = gpd.read_file("ne_110m_graticules_10.shp") land = gpd.read_file("ne_110m_land.shp") ocean = gpd.read_file("ne_110m_ocean.shp") proj = ccrs.Robinson(central_longitude=0) fig = plt.figure(figsize=(12, 6)) ax = plt.axes(projection=proj) ax.set_global() ax.add_geometries( ocean.geometry, crs=ccrs.PlateCarree(), facecolor="#aad3df", edgecolor="none", ) ax.add_geometries( land.geometry, crs=ccrs.PlateCarree(), facecolor="#e7ddcb", edgecolor="#8a7a5c", linewidth=0.3, ) ax.add_geometries( grat.geometry, crs=ccrs.PlateCarree(), facecolor="none", edgecolor="#666666", linewidth=0.4, alpha=0.5, ) plt.savefig("world_physical_graticules.png", dpi=200, bbox_inches="tight")

这段脚本的逻辑是:数据本身是经纬度坐标系,所以所有add_geometries都要指定crs=ccrs.PlateCarree(),告诉 Cartopy「这些坐标是经纬度」;Cartopy 会自行把它们转换到proj指定的 Robinson 投影再画出。

3.3 三个影响出图效果的参数

ne_110m_graticules的线型参数直接影响物理地图的专业感。把这一组参数调好,图面会立刻从「默认输出」变成「可发表」:

参数建议范围说明
linewidth0.3 ~ 0.5网格线太粗会盖过海岸线,太细则打印后看不清
alpha0.3 ~ 0.5经纬网是辅助信息,透明度要明显低于陆地边线
edgecolor#666666 或 #888888不要用纯黑,物理底图偏暖色,灰色更协调

细心的读者会发现:110m 数据本身分辨率低,海岸线已经比较概括,网格线的粗细追求的是「可读但不喧宾夺主」。若继续叠加ne_110m_rivers_lake_centerlines的河流图层,建议把河流线宽也和网格线区分开,例如河流用 0.2 的蓝色,网格用 0.3 的灰色,层次才会分明。

3.4 投影和网格的坑:Robinson 投影下网格会弯曲

使用 Robinson 投影时,经纬网格中经线是平滑曲线,纬线近似直线但接近极地时有明显弯曲。这是投影本身的性质,不是数据错误。如果想让网格看起来「横平竖直」且每个网格都是规则的矩形,可以直接使用ccrs.PlateCarree()作为投影,适合做数据坐标图,但视觉上纬度越高拉长越明显,读者容易误读高纬度面积。两种方案各有应用场景,我一般是在论文插图用 Robinson,在 Web 嵌入式小图用 PlateCarree。

4. 把 world physical 地图送进浏览器:简化、转格式与前端图层

4.1 从 shapefile 到 GeoJSON 的体积控制

浏览器端做世界地图可视化时,最常见的方案是把 110m 数据转成 GeoJSON,再交给 MapLibre、Leaflet 或 deck.gl 渲染。110m 原始数据体积其实不大,但若不经过简化直接转 GeoJSON,边界上的毛刺和冗余点依然可能让文件膨胀到几 MB。此外ne_110m_graticules的线要素转 GeoJSON 后会是MultiLineString几何类型,前端在添加图层时应当按line图层而不是fill图层处理。

用 GeoPandas 做一次简化再导出:

import geopandas as gpd grat = gpd.read_file("ne_110m_graticules_5.shp") grat_s = grat.copy() grat_s["geometry"] = grat.geometry.simplify(tolerance=0.02, preserve_topology=True) land = gpd.read_file("ne_110m_land.shp") land_s = land.copy() land_s["geometry"] = land.geometry.simplify(tolerance=0.05, preserve_topology=True) grat_s.to_file("ne_110m_graticules_5_simplified.geojson", driver="GeoJSON") land_s.to_file("ne_110m_land_simplified.geojson", driver="GeoJSON")

tolerance的单位是度,0.02 度约等于赤道上 2.2 公里,对于 110m 的低分辨率数据来说,这个阈值不会造成可见变形,但能把文件体积显著压缩。preserve_topology=True会避免删除拓扑关键点,防止简化后出现狭长裂缝。

如果命令行操作顺手,也可以用 mapshaper 做同样的事:

mapshaper ne_110m_graticules_10.shp -simplify dp 5% -o format=geojson graticules_10.json

dp表示 Douglas-Peucker 算法,5%表示保留 5% 的点,这个比例对 110m 数据通常足够保守。注意精度和体积是权衡关系,web 端展示时可以用「先画低精度底图,放大后再加载高精度」的分级策略。

4.2 MapLibre 里叠加经纬网格图层

MapLibre GL JS 适合这种矢量底图展示场景。将简化后的 GeoJSON 放在静态资源目录中,然后添加一个基础地图源和一个网格线图层:

map.addSource("graticules", { type: "geojson", data: "/data/ne_110m_graticules_10_simplified.geojson" }); map.addLayer({ id: "graticules-layer", type: "line", source: "graticules", paint: { "line-color": "#9a9a9a", "line-width": 0.5, "line-opacity": 0.4 } });

地图源使用geojson类型时,MapLibre 内部会直接用 GeoJSON 的 EPSG:4326 坐标,不需要提前转 Web Mercator。line-width在缩放级别变化时是像素值,所以地图放大后网格线的视觉粗细几乎不变;若希望线宽随缩放级别等比变化,可以使用line-width的表达式的插值函数:

"line-width": ["interpolate", ["linear"], ["zoom"], 1, 0.3, 6, 0.6, 10, 1.2]

这个表达式的效果是:缩放级别 1 时线宽 0.3 像素,缩放级别 6 时 0.6 像素,缩放级别 10 时 1.2 像素。这样地图从全球视角放大到国家尺度时,经纬网不会因为过于稀疏而彻底消失。

4.3 浏览器端经纬网:静态文件 vs 动态生成

浏览器端的经纬网格有两种常见实现:一种是直接加载上面转换出来的ne_110m_graticules_*静态 GeoJSON;另一种是在前端用 D3 的d3.geoGraticule10()随时生成,然后投影进底图。后者的好处是不消耗任何网络请求,缺点是 D3 默认生成的是默认间隔 10 度的标准网格,要自定义 5 度间隔网格时,需要手动构造坐标循环,写起来麻烦且容易产生边界重叠线。

我一般建议:如果只显示 10 度或 5 度网格,直接加载 NE 的静态文件,它的数据质量经过校验,而且和底图同源,颜色样式统一;如果需要在交互地图上动态切换不同间隔的网格,再考虑用 D3 生成。动态方案的另一个问题是经纬网与世界底图的投影转换必须由前端同步执行,一旦底图用了自定义投影而网格没转,图中网格线会出现明显错位,排查起来比调静态文件麻烦得多。

5. ne_110m_graticules 的三个边界情况与调优技巧

5.1 日期变更线附近的网格线会横穿过地图

110m 的 graticules 文件在 ±180° 经线处是完整连贯的 LineString,不会在日期变更线处断开。放在 Web 墨卡托底图上时,东经 180° 的线会从地图右边缘「消失」、西经 180° 的线从左边出现,呈现一种横穿效果,这是正常的 wrap 行为。不要试图在前端手动把线裁切成两段——那样做会引入接缝,反而在地图旋转时露出断裂痕迹。如果一定要处理,可以在样式层设置"line-cap": "round",接缝处的渲染会更平滑。

5.2 Web 端建议直接上 10 度,不要怕「太稀疏」

经纬网格在 360° 经度范围里切出 36 条线,读者在缩放到国家尺度时基本看不到网格,需要时可以在代码里加一个交互开关切换ne_110m_graticules_5ne_110m_graticules_10两个图层。持久加载 1 度网格的压力主要不在渲染,而在初始化 stage 时的 Fetch 时间:300+ 条线的 GeoJSON 文件体积通常在 10~40MB 之间,绝大多数场景不值得为它付出这个带宽成本。换句话说,NE 官方提供三档间隔的数据已经替你想好了场景分级。

5.3 用 D3 动态网格做交叉验证

静态 graticules 文件的正确性,用 D3 的d3.geoGraticule10()可以快速交叉验证:在浏览器控制台里生成一个 10 度网格 GeoJSON,用JSON.stringify(...)和 NE 文件转换出的 10 度 GeoJSON 对拍,观察线段数量是否吻合。二者几乎必然一致——这个验证更多是在帮你确认线长、范围和多段线结构没有在前端处理时被扭曲。这种对拍方式也适合在 CI 环境做数据完整性检查,一旦 NE 数据源更新了版本,对比即可自动感知。

真正要把 graticules 用出效果,关键不是贴得越密越好,而是让网格清楚但不抢陆地:透明度、线宽、灰度和陆地底色的纹理对比,这四样东西一起调,才能让读者一眼看到经纬度却又不会觉得图上像铺了一张网。下一步建议直接下载 110m physical 全部图层,用上面三段代码把陆地、海洋、graticules 叠加出第一张成品图,再用 mapshaper 做体积优化,对比简化前后的文件大小和视觉差异。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 9:06:55

网约车系统开发Day01:微服务架构与实时调度技术解析

1. 项目概述"飞滴网约车项目Day01"这个标题背后,隐藏着一个典型的互联网出行平台开发案例。作为从业十余年的全栈开发者,我参与过多个网约车系统的架构设计,深知这个领域的技术复杂性和业务挑战。首日工作往往决定了整个项目的技术…

作者头像 李华
网站建设 2026/9/11 9:02:20

Postman替代方案全解析:从Apifox到JMeter的接口测试工具选型指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 8:55:37

树莓派Pico低功耗实践:从MicroPython陷阱到微安级DeepSleep

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 8:55:34

73 份 DESIGN.md 任选其一:让 AI 生成的页面不再是千篇一律

73 份 DESIGN.md 任选其一:让 AI 生成的页面不再是千篇一律 【免费下载链接】awesome-design-md A collection of DESIGN.md files analysis by popular brand design systems. Drop one into your project and let coding agents generate a matching UI. 项目地…

作者头像 李华