分级设色地图实战:用行政区划代码把统计数据接到 GeoJSON 上
--- title: 分级设色地图实战:用行政区划代码把统计数据接到 GeoJSON 上 ---
分级设色地图(Choropleth)是最常见的专题地图:每个行政区按数值深浅填色,人口、GDP、销量的地域分布一眼就能看出来。做这种图需要两份数据,一份行政区边界 GeoJSON,一份业务统计表。麻烦在于怎么把两份数据正确地"接"起来。这篇讲清楚 join 的正确姿势,附能直接跑的 Leaflet 代码。
先说关键原则:用区划代码 join,别用名字
最容易踩的坑是拿"区县名"当主键去关联数据。中国的区县重名不少:
| 名称 | 区划代码 | 所属 |
|---|---|---|
| 朝阳区 | 110105 | 北京市 |
| 朝阳区 | 220104 | 吉林省长春市 |
| 鼓楼区 | 320106 | 江苏省南京市 |
| 鼓楼区 | 350102 | 福建省福州市 |
| 鼓楼区 | 410204 | 河南省开封市 |
用名字 join,一个"朝阳区"的数据会同时染到北京和长春两块面上,结果直接错。正确做法是用民政部发布的 6 位行政区划代码(adcode)当唯一主键:GeoJSON 的 properties 里带 adcode 字段,业务表也带 adcode 列,两边一一对应。properties 的结构不熟的话,可以回顾 GeoJSON 到底是什么。
数据 join 代码
先把统计表(CSV 解析后的数组)转成 Map,渲染时按 adcode 查值。查 Map 是 O(1),比每次 find 遍历数组快得多:
// 业务数据:[{ adcode: "110105", value: 345.2 }, ...]
const valueMap = new Map(rows.map(r => [String(r.adcode), r.value]));
// 把数值写进 GeoJSON 的 properties,方便后续统一取用
geojson.features.forEach(f => {
const code = String(f.properties.adcode);
f.properties.value = valueMap.get(code) ?? null; // 缺数据的区置 null
});
两个细节。一是 adcode 统一转字符串再比对,不然 110105(数字)和 "110105"(字符串)对不上;二是缺数据的区置 null 而不是 0——"没有数据"和"数值为零"在地图上该是两种颜色。
Leaflet 着色
function getColor(v) {
if (v === null) return '#eeeeee'; // 无数据:灰色
return v > 500 ? '#08306b' :
v > 300 ? '#2171b5' :
v > 150 ? '#6baed6' :
v > 50 ? '#c6dbef' : '#f7fbff';
}
L.geoJSON(geojson, {
style: f => ({
fillColor: getColor(f.properties.value),
fillOpacity: 0.75,
color: '#ffffff', // 描边用白色,分区更清楚
weight: 1
}),
onEachFeature: (f, layer) => {
layer.bindTooltip(`${f.properties.name}:${f.properties.value ?? '无数据'}`);
}
}).addTo(map);
坐标系还是老规矩:边界数据统一用 WGS84 存储,叠加到不同底图前先确认是否需要偏移处理,细节见 坐标系那篇。
分级方法怎么选
getColor 里的断点(50/150/300/500)不是随手写的。分级方法直接决定这张地图"讲什么故事":
| 分级方法 | 原理 | 适用场景 | 缺点 |
|---|---|---|---|
| 等间距 | (最大值-最小值)/组数 | 数据均匀分布 | 有极值时大部分区挤在一档 |
| 分位数 | 每档区县数量相同 | 强调排名对比 | 数值差异被隐藏 |
| 自然断点 | Jenks 算法找聚类间隙 | 多数真实数据 | 计算稍复杂,断点不整 |
| 手动分级 | 按业务含义定断点 | 有行业标准阈值时 | 依赖领域知识 |
人口、GDP 这类右偏分布的数据,用等间距几乎必翻车:北京上海把上限拉高,全国大部分区县落在最浅一档,整张图白茫茫一片。这种情况优先试分位数或自然断点。
性能提醒
全国区县级边界一次性加载体积不小,直接渲染 2800 多个面可能明显卡顿。两个办法:一是先做 Douglas-Peucker 顶点抽稀,分级设色关注的是"哪块什么颜色",边界精度可以适当放宽;二是换 TopoJSON 传输,共享边只存一次,到浏览器再还原。
省、市、区县三级的边界 GeoJSON 数据(含 adcode 字段),可以在 GeoJSONcn 主站 按行政区划直接检索预览。