简介:这份资源整理了世界地图与主要国家的 GeoJSON 数据,面向从事数据可视化、Web 地图开发的前端工程师与 GIS 初学者,解决绘制世界或单国地图时缺少现成边界数据的问题。压缩包共 25 个文件,以 23 个 json 为主,涵盖 world.json 及德国、英国、瑞士、日本、俄罗斯、澳大利亚、美国、法国、巴西、韩国、新加坡等主要国家,另有 2 个 mht 文件记录 D3.js 地图学习资料,整体约 11.31MB。由于原始文件体积偏大,作者建议下载后到 mapshaper.org 按需简化,以适配网页加载性能。目前已有 6260 人学习下载,说明该数据在可视化社区中具备一定认可度。读者可直接获得开箱即用的世界及多国边界数据,省去自行采集与格式转换的环节,配合 D3.js 等库即可快速完成地图渲染、区域着色与交互探索,也便于按国家拆分做专题分析。
1. 世界地图 GeoJSON 资源:从一份 JSON 到能跑的地图
做数据可视化或者 GIS 相关开发的人,迟早会碰到一个需求:我需要一份干净、完整、能直接用的世界地图和主要国家的边界数据。网上搜一圈,要么是 shapefile 需要额外工具转换,要么是 TopoJSON 还得引额外依赖,要么就是数据缺胳膊少腿——某个国家的边界线断了,或者属性表里连国家名都没有。这份「世界地图和主要国家的 JSON (GeoJSON)」资源,解决的就是这个最前置、也最容易被低估的问题:给你一份开箱即用的 GeoJSON 文件,直接丢进 ECharts、Leaflet、Mapbox、D3 或者 Python 的 GeoPandas 里就能渲染。它适合谁?做前端地图可视化的、写数据大屏的、搞地理数据分析的,以及任何需要国家边界几何数据但不想从 Natural Earth 原始 shapefile 开始折腾的人。
2. GeoJSON 格式拆解:为什么它比 Shapefile 更适合 Web 场景
2.1 GeoJSON 的核心结构:FeatureCollection 与 Geometry
GeoJSON 本质上是 JSON 格式的地理空间数据交换标准(RFC 7946)。一份世界地图 GeoJSON 的顶层通常是一个FeatureCollection,里面装着一堆Feature,每个Feature包含geometry(几何形状)和properties(属性信息)。几何类型常见的有Polygon(单个国家主体)和MultiPolygon(岛屿多的国家,比如日本、菲律宾、印尼)。属性里一般会有国家名称、ISO 代码、行政区划类型等字段。
为什么 Web 场景优先选 GeoJSON 而不是 Shapefile?Shapefile 是一套多文件格式(.shp/.shx/.dbf/.prj),浏览器端没法直接解析,必须后端转成 GeoJSON 或者用 shapefile.js 这类库在前端硬解,性能和兼容性都不理想。GeoJSON 就是纯文本 JSON,fetch回来JSON.parse就能用,和 JavaScript 生态无缝衔接。TopoJSON 虽然体积更小(通过拓扑编码压缩共享边界),但需要额外引入 topojson-client 做解码,多一层依赖就多一个翻车点。
2.2 这份资源里有什么:文件组织与字段说明
根据标题和常见组织方式,这份资源通常包含两类文件:一份全球尺度的世界地图 GeoJSON,以及若干主要国家的单独 GeoJSON 文件。世界地图文件覆盖全球国家边界,国家文件则把单个国家的几何数据拆出来,方便按需加载。
| 文件类型 | 典型命名 | 几何类型 | 属性字段(常见) | 适用场景 |
|---|---|---|---|---|
| 世界地图 | world.geo.json / world.json | MultiPolygon 为主 | name, iso_a2, iso_a3, continent | 全球数据大屏、 choropleth 地图 |
| 单国地图 | china.json / usa.json | Polygon / MultiPolygon | name, adcode, center | 国家内部区域着色、钻取交互 |
属性字段的具体名称取决于数据来源。常见的有name(英文名)、name_zh(中文名,部分资源会带)、iso_a2(两位国家代码)、iso_a3(三位代码)。如果你要做中文地图,先确认properties里有没有中文名字段,没有的话需要自己维护一张 ISO 代码到中文名的映射表。
注意:不同来源的 GeoJSON 属性字段命名不统一,拿到文件后第一件事是
console.log或
2.3 用 Python 快速验证数据完整性
拿到 GeoJSON 文件后,别急着往项目里塞。先用 Python 做一轮体检,确认几何有效、属性齐全、坐标范围正常。
import json # 加载 GeoJSON 文件 with open("world.geo.json", "r", encoding="utf-8") as f: data = json.load(f) # 检查顶层结构 print("类型:", data.get("type")) # 应为 FeatureCollection features = data.get("features", []) print("要素数量:", len(features)) # 检查第一个要素的属性字段 first = features[0] print("属性字段:", list(first["properties"].keys())) print("几何类型:", first["geometry"]["type"]) # 统计几何类型分布 from collections import Counter geom_types = Counter(f["geometry"]["type"] for f in features) print("几何类型分布:", dict(geom_types)) # 检查坐标范围是否合理(经度 -180~180,纬度 -90~90) def check_bounds(coords): if isinstance(coords[0], (int, float)): lon, lat = coords[0], coords[1] return -180 <= lon <= 180 and -90 <= lat <= 90 return all(check_bounds(c) for c in coords) bad = [f["properties"].get("name", "unknown") for f in features if not check_bounds(f["geometry"]["coordinates"])] print("坐标异常的国家:", bad if bad else "无")这段脚本做了四件事:确认顶层是FeatureCollection、统计要素数量、查看属性字段名、检查坐标是否在合法范围内。如果bad列表非空,说明有国家的坐标数据有问题,可能是投影没转回 WGS84 经纬度,需要重新处理。check_bounds递归遍历嵌套坐标数组,兼容 Polygon 和 MultiPolygon 两种结构。
3. 在 Web 前端落地:ECharts 与 Leaflet 两条路线
3.1 ECharts 注册地图:三行代码搞定
ECharts 是国内数据大屏最常用的图表库,它内置了地图组件,但需要你先注册 GeoJSON 数据。
import * as echarts from 'echarts'; // 加载 GeoJSON 数据 fetch('/data/world.geo.json') .then(res => res.json()) .then(geoJson => { // 注册地图,'world' 是自定义地图名 echarts.registerMap('world', geoJson); const chart = echarts.init(document.getElementById('map')); chart.setOption({ series: [{ type: 'map', map: 'world', // 对应 registerMap 的名字 roam: true, // 允许缩放和拖拽 label: { show: false }, // 国家名太多,默认关掉 emphasis: { // 鼠标悬浮高亮 label: { show: true }, itemStyle: { areaColor: '#ffd700' } }, data: [] // 你的业务数据,格式 [{name: 'China', value: 100}] }] }); });关键点在echarts.registerMap('world', geoJson)这一行。注册之后,series.map的值必须和注册名一致。roam: true开启缩放拖拽,大屏上一般会开。data数组里的name字段必须和 GeoJSON 里properties.name的值完全匹配,否则数据映射不上——这是最常见的翻车点。如果 GeoJSON 里用的是英文名而你的数据是中文名,要么改数据,要么在 GeoJSON 里加一个中文名字段。
3.2 Leaflet 加载 GeoJSON:L.geoJSON 的样式与交互
Leaflet 是另一个主流选择,轻量、插件生态好。加载 GeoJSON 用L.geoJSON方法。
import L from 'leaflet'; const map = L.map('map').setView([20, 0], 2); // 纬度、经度、缩放级别 // 底图用 OpenStreetMap L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors' }).addTo(map); // 加载 GeoJSON 并设置样式 fetch('/data/world.geo.json') .then(res => res.json()) .then(geoJson => { L.geoJSON(geoJson, { style: function(feature) { return { color: '#3388ff', // 边界线颜色 weight: 1, // 线宽 fillColor: '#3388ff', // 填充色 fillOpacity: 0.1 // 填充透明度 }; }, onEachFeature: function(feature, layer) { // 绑定点击弹窗 if (feature.properties && feature.properties.name) { layer.bindPopup(feature.properties.name); } // 鼠标悬浮高亮 layer.on('mouseover', function() { this.setStyle({ fillOpacity: 0.4 }); }); layer.on('mouseout', function() { this.setStyle({ fillOpacity: 0.1 }); }); } }).addTo(map); });style函数对每个 Feature 调用一次,返回样式对象。onEachFeature是绑定交互的入口,bindPopup做点击弹窗,mouseover/mouseout做悬浮效果。Leaflet 的坐标系默认是 WGS84 经纬度(EPSG:4326),GeoJSON 标准也是 WGS84,所以不需要额外投影转换。如果你的 GeoJSON 用的是 Web Mercator(EPSG:3857),Leaflet 也能显示,但坐标值会很大,需要确认数据源。
3.3 按需加载单国数据:减少首屏体积
世界地图 GeoJSON 动辄几 MB,如果用户只关心某个国家,全量加载就是浪费。常见做法是首屏只加载世界地图的低精度版本,用户点击某个国家后再异步加载该国的高精度 GeoJSON。
// 点击国家后加载详细数据 function loadCountryDetail(isoCode) { const url = `/data/countries/${isoCode.toLowerCase()}.geo.json`; fetch(url) .then(res => { if (!res.ok) throw new Error(`加载 ${isoCode} 失败`); return res.json(); }) .then(detail => { // 清除旧图层,加载新图层 if (window.currentDetailLayer) { map.removeLayer(window.currentDetailLayer); } window.currentDetailLayer = L.geoJSON(detail, { style: { color: '#e74c3c', weight: 2 } }).addTo(map); }) .catch(err => console.error(err)); }isoCode用两位国家代码(如cn、us、jp),文件名统一小写。加载前先移除旧图层,避免叠加。错误处理不能省——文件不存在时fetch不会抛异常,但res.ok为false,需要手动判断。
4. 避坑与排查:GeoJSON 使用中的五个血泪教训
4.1 地图渲染空白:坐标顺序搞反了
现象:地图区域一片空白,控制台无报错,或者地图跑到南极去了。
原因:GeoJSON 标准规定坐标顺序是[经度, 纬度],但有些数据源(尤其是从某些 GIS 工具导出的)会写成[纬度, 经度]。顺序反了之后,经度值当纬度用,整个地图就飞到南极或者形状完全错乱。
解决:写一个检测脚本,遍历所有坐标点,如果发现大量点的第一个值在 -90 到 90 之间而第二个值超出这个范围,基本可以判定顺序反了。修复方法是递归交换每个坐标对的顺序。
def swap_coords(coords): if isinstance(coords[0], (int, float)): return [coords[1], coords[0]] # 交换经纬度 return [swap_coords(c) for c in coords] for feature in data["features"]: feature["geometry"]["coordinates"] = swap_coords(feature["geometry"]["coordinates"])4.2 数据映射不上:name 字段不匹配
现象:ECharts 地图渲染出来了,但data里的数值没有着色,所有国家都是默认颜色。
原因:series.data里的name值和 GeoJSONproperties.name不一致。常见差异包括:大小写不同(Chinavschina)、中英文不同(Chinavs中国)、有空格(United StatesvsUnitedStates)。
解决:先打印 GeoJSON 里所有properties.name的值,再打印你数据里的 name 值,做一次 diff。统一方案是维护一张映射表,或者直接在 GeoJSON 里加一个和业务数据一致的字段。
4.3 文件太大导致加载慢:简化几何精度
现象:世界地图 GeoJSON 文件 10MB+,首屏加载要好几秒,移动端直接卡死。
原因:原始边界数据精度太高,每个国家的轮廓有几千个坐标点,全球加起来就是海量数据。
解决:用地图简化算法(如 Douglas-Peucker)降低精度。Python 的shapely库可以做简化,或者用mapshaper命令行工具。
# 用 mapshaper 简化,保留 10% 的坐标点 mapshaper world.geo.json -simplify 10% -o format=geojson world-simplified.geo.json简化比例根据场景定:大屏展示 5%-10% 足够,需要精确边界(如国土规划)就别简化。
4.4 岛屿国家显示不全:MultiPolygon 处理遗漏
现象:日本、菲律宾、印尼等岛国只显示了主岛,周围小岛不见了。
原因:这些国家的几何类型是MultiPolygon,包含多个多边形。如果代码里只取了coordinates[0],就只渲染了第一个多边形。
解决:确保渲染库支持MultiPolygon。ECharts 和 Leaflet 都原生支持,问题通常出在自己写的解析代码里。检查是否有coordinates[0]这种硬编码索引。
4.5 中文显示乱码:编码问题
现象:国家名显示为乱码或问号。
原因:GeoJSON 文件保存时用了非 UTF-8 编码,或者 HTTP 响应头没有正确设置Content-Type: application/json; charset=utf-8。
解决:用file命令检查文件编码,统一转成 UTF-8。服务端返回 JSON 时设置正确的 Content-Type。前端fetch默认按 UTF-8 解析,一般不需要额外处理。
5. 进阶技巧:用 GeoPandas 做空间分析与数据校验
5.1 GeoPandas 读取与拓扑检查
如果你不只是渲染,还要做空间分析(比如计算国家面积、判断点是否在境内),Python 的 GeoPandas 是首选工具。
import geopandas as gpd # 读取 GeoJSON gdf = gpd.read_file("world.geo.json") # 查看基本信息 print(gdf.crs) # 坐标参考系,应为 EPSG:4326 print(gdf.shape) # 行数和列数 print(gdf.columns.tolist()) # 检查几何有效性 invalid = gdf[~gdf.geometry.is_valid] print(f"无效几何: {len(invalid)} 个") if len(invalid) > 0: print(invalid[["name"]].head()) # 修复无效几何 gdf["geometry"] = gdf.geometry.buffer(0) # buffer(0) 是常用的修复手段gdf.crs告诉你坐标参考系,如果是None,说明文件里没有 CRS 信息,需要手动设置gdf.set_crs("EPSG:4326", inplace=True)。is_valid检查几何是否有自相交、重复点等问题,buffer(0)是最常用的修复方法,虽然不保证完美,但能解决大部分问题。
5.2 计算面积与中心点:投影转换不能省
直接用 WGS84 经纬度算面积是不准的,因为经纬度是角度单位,不是长度单位。需要先投影到等面积投影。
# 投影到 Mollweide 等面积投影 gdf_projected = gdf.to_crs("ESRI:54009") # 计算面积(平方公里) gdf["area_km2"] = gdf_projected.geometry.area / 1e6 # 计算每个国家的中心点(用于标注) gdf["centroid"] = gdf.geometry.representative_point() gdf["centroid_lon"] = gdf["centroid"].x gdf["centroid_lat"] = gdf["centroid"].y # 输出面积最大的十个国家 print(gdf.nlargest(10, "area_km2")[["name", "area_km2"]])to_crs("ESRI:54009")转到 Mollweide 投影,这是一个等面积投影,适合做面积计算。representative_point()比centroid更安全,因为centroid可能落在多边形外部(比如月牙形国家),representative_point保证点在多边形内部。
5.3 导出为其他格式:Shapefile 与 GeoPackage
有时候下游系统需要 Shapefile 或 GeoPackage,GeoPandas 一行代码就能转。
# 导出为 Shapefile(注意:字段名会被截断到 10 个字符) gdf.to_file("world.shp", encoding="utf-8") # 导出为 GeoPackage(推荐,支持长字段名和 UTF-8) gdf.to_file("world.gpkg", driver="GPKG")Shapefile 的字段名限制是 10 个字符,area_km2会被截断成area_km2(刚好 8 个字符没问题),但更长的字段名就会丢信息。GeoPackage 没有这个限制,是更现代的替代方案。
5.4 一个我常用的校验习惯
每次拿到新的 GeoJSON 文件,我都会跑一遍这个检查清单:顶层类型是不是FeatureCollection、要素数量是否合理、properties里有没有可用的名称字段、坐标范围是否在合法区间、几何是否有效、有没有重复的name值。这套流程帮我挡掉过好几次数据源本身就有问题的坑——有一次某个国家的边界数据里混入了另一国的飞地,导致面积计算直接翻倍。从那以后我每次拿到新数据都强制走一遍这个校验流程,再急也不跳过。希望帮到你。
本文还有配套的精品资源,点击获取