Deck.gl蜂窝聚合图怎么做?关键参数在哪配?

GIS基础理论
Dr.GIS
wowwwai GIS研习社 · 工具流程与项目排障

Deck.gl蜂窝聚合图怎么做?关键参数在哪配? 这是很多 WebGIS 开发者在做点数据可视化时会遇到的问题:点太多时直接渲染散点会卡顿,也很难看出空间热点,而蜂窝聚合图可以把大量点按六边形网格聚合,快速表达“哪里密集、哪里稀疏”。

本文以 deck.gl 的 HexagonLayer 为核心,讲清楚 Deck.gl蜂窝聚合图 的基本做法、关键参数、常见坑,以及如何判断聚合结果是否可信。适合已经会使用 Mapbox、MapLibre、React 或原生 JavaScript 加载地图的 GIS 学生、WebGIS 开发者和空间数据分析人员阅读。

引言:Deck.gl蜂窝聚合图适合解决什么问题

Deck.gl蜂窝聚合图 主要用于展示大量点数据的空间分布规律。例如:

  • 共享单车停靠点热区分析
  • 出租车上下客点聚合
  • POI 密度分布
  • 人口、事件、传感器点位的空间热点
  • 城市网格化管理中的事件密度展示

如果你的数据是点要素,并且关注的是“空间密度”或“聚合统计值”,HexagonLayer 通常比普通 ScatterplotLayer 更适合。它会把点落入六边形网格中,然后根据每个网格内的点数量或权重值计算颜色和高度。

Deck.gl蜂窝聚合图 HexagonLayer关键参数配置示意图
Deck.gl蜂窝聚合图的基本流程:点数据进入 HexagonLayer,通过半径、权重、颜色和高度参数生成聚合结果。

背景:为什么不用普通散点图直接画

在 WebGIS 项目中,很多人一开始会直接把点数据画成圆点。数据量较小时没有问题,但当点数量达到几万、几十万时,会出现三个典型问题:

  • 视觉遮挡:大量点重叠,中心城区几乎变成一片颜色,看不出真实差异。
  • 性能压力:浏览器需要绘制大量点对象,交互、缩放、拖拽可能变慢。
  • 空间规律不明显:读者看到的是“点很多”,但不容易判断哪些区域是热点。

Deck.gl蜂窝聚合图 的价值在于把点要素变成统计单元。每一个六边形网格代表一个局部区域,颜色可以表示点数量,高度可以表示聚合值,从而更直观地展示空间密度。

简单理解:散点图强调“每个点在哪里”,蜂窝聚合图强调“哪个区域更密集”。

原理:HexagonLayer 是怎么聚合点数据的

Deck.gl 的 HexagonLayer 会读取每条数据的坐标,通过 getPosition 得到经纬度位置,然后按照指定的 radius 半径生成六边形网格。落在同一个六边形内的点会被聚合到一起。

默认情况下,蜂窝聚合图可以按点数量统计,也可以通过权重字段进行加权统计。例如每个点代表一次订单,按数量聚合即可;如果每个点还有金额字段,则可以按金额加权聚合。

常见核心参数如下:

参数 作用 GIS理解
data 输入点数据数组 相当于点图层的数据源
getPosition 指定每条记录的坐标 通常返回 [经度, 纬度]
radius 六边形网格半径,单位通常按米理解 决定聚合尺度
colorRange 设置不同聚合值对应的颜色 类似分级设色
elevationRange 设置柱体高度范围 控制三维柱状效果
getColorWeight 设置颜色统计使用的权重字段 可按数量、金额、强度等统计
getElevationWeight 设置高度统计使用的权重字段 控制柱体高度的统计依据
coverage 控制六边形填充比例 影响蜂窝之间是否留缝
extruded 是否显示三维高度 true 为三维柱体,false 为二维蜂窝

步骤:Deck.gl蜂窝聚合图怎么做

步骤1:准备点数据

HexagonLayer 最常见的数据格式是 JavaScript 对象数组。每条记录至少需要经纬度字段。

const points = [
  {lng: 116.397, lat: 39.908, count: 1, value: 35},
  {lng: 116.401, lat: 39.912, count: 1, value: 20},
  {lng: 116.389, lat: 39.903, count: 1, value: 50}
];

这里要特别注意坐标顺序。deck.gl 的经纬度坐标通常写成 [longitude, latitude],也就是 [经度, 纬度]。如果写反,图层可能会飞到错误位置,甚至完全看不到。

步骤2:创建 HexagonLayer

下面是一个最小可用的 Deck.gl蜂窝聚合图 配置示例:

const hexagonLayer = new deck.HexagonLayer({
  id: 'hexagon-layer',
  data: points,
  getPosition: d => [d.lng, d.lat],
  radius: 500,
  extruded: true,
  elevationScale: 30,
  coverage: 0.9,
  colorRange: [
    [255, 255, 178],
    [254, 204, 92],
    [253, 141, 60],
    [240, 59, 32],
    [189, 0, 38]
  ],
  elevationRange: [0, 3000],
  pickable: true
});

这段配置中,最关键的是 getPositionradius。前者决定点落在哪里,后者决定六边形网格多大。

步骤3:把图层加入 Deck 实例

如果你使用原生 deck.gl,可以把 HexagonLayer 放入 layers 数组中。

const deckgl = new deck.DeckGL({
  container: 'map',
  initialViewState: {
    longitude: 116.397,
    latitude: 39.908,
    zoom: 10,
    pitch: 45,
    bearing: 0
  },
  controller: true,
  layers: [hexagonLayer]
});

如果你是在 Mapbox 或 MapLibre 底图上叠加 deck.gl,一般会使用 DeckGL Overlay 或对应集成方式。核心思想不变:底图负责地图瓦片,HexagonLayer 负责点数据聚合渲染。

步骤4:配置 radius,决定聚合尺度

在 Deck.gl蜂窝聚合图 中,radius 是最容易影响结果解读的参数。半径太小,图面会碎,热点不明显;半径太大,局部差异会被抹平。

  • 城市级 POI 密度:可从 300 米到 1000 米尝试。
  • 区县级事件分布:可从 1000 米到 3000 米尝试。
  • 全国范围点数据:通常需要更大的半径,或改用服务端聚合。

不要只为了“好看”随意调大 radius。GIS 分析中,聚合尺度会改变空间结论。建议在文章、图例或系统说明中明确写出蜂窝半径。

步骤5:配置颜色和高度

颜色一般用于表达聚合强度,高度用于增强三维视觉效果。你可以让颜色和高度都按点数量统计,也可以分别使用不同权重。

const hexagonLayer = new deck.HexagonLayer({
  id: 'hexagon-layer',
  data: points,
  getPosition: d => [d.lng, d.lat],
  radius: 500,
  colorRange: [
    [237, 248, 251],
    [178, 226, 226],
    [102, 194, 164],
    [44, 162, 95],
    [0, 109, 44]
  ],
  getColorWeight: d => d.value,
  colorAggregation: 'SUM',
  getElevationWeight: d => d.value,
  elevationAggregation: 'SUM',
  elevationScale: 20,
  extruded: true,
  pickable: true
});

这段代码表示颜色和高度都按 value 字段求和。如果 value 表示订单金额,那么蜂窝颜色和高度表达的是区域订单金额总量,而不是点数量。

步骤6:开启 tooltip,验证聚合结果

做 Deck.gl蜂窝聚合图 时,不建议只看颜色。最好加上 tooltip,查看每个蜂窝中聚合了多少条点记录。

const deckgl = new deck.DeckGL({
  container: 'map',
  initialViewState: {
    longitude: 116.397,
    latitude: 39.908,
    zoom: 10,
    pitch: 45
  },
  controller: true,
  layers: [hexagonLayer],
  getTooltip: ({object}) => {
    if (!object) return null;
    return {
      text: `点数量:${object.points.length}`
    };
  }
});

如果使用权重统计,可以进一步检查 object 中的聚合结果。不同版本和配置下返回对象结构可能略有差异,建议先在控制台打印 object,确认字段含义后再写 tooltip。

getTooltip: ({object}) => {
  console.log(object);
  return object ? {text: '查看控制台中的聚合对象'} : null;
}

常见坑:Deck.gl蜂窝聚合图为什么不显示或结果不对

1. 经纬度顺序写反

最常见错误是把坐标写成 [纬度, 经度]。deck.gl 常用的是 [经度, 纬度]

getPosition: d => [d.lng, d.lat]  // 正确
getPosition: d => [d.lat, d.lng]  // 常见错误

2. 数据不是 WGS84 经纬度

WebGIS 前端图层通常使用经纬度输入。如果你的数据来自投影坐标系,例如 CGCS2000 高斯投影、Web Mercator 米制坐标或地方坐标,需要先转换到经纬度。否则 HexagonLayer 会把坐标当作经纬度解释,图层位置会严重错误。

3. radius 设置不合理

radius 太小可能导致几乎每个点单独占一个蜂窝,看起来像散点图;radius 太大则会把整个城市聚成几个大块。调参时建议从业务尺度出发,而不是只看视觉效果。

4. elevationScale 太大导致柱体夸张

如果柱体高度冲出屏幕,通常不是数据错了,而是 elevationScaleelevationRange 设置过大。可以先降低 elevationScale,再观察结果。

5. 权重字段存在空值或字符串

如果 getColorWeight 或 getElevationWeight 返回的是字符串、null、undefined,聚合结果可能异常。建议先清洗数据。

getColorWeight: d => Number(d.value) || 0
getElevationWeight: d => Number(d.value) || 0

6. 数据量过大但全部放在前端

deck.gl 的 WebGL 渲染能力很强,但不代表所有数据都应该一次性塞到浏览器。如果点数据达到百万级,并且还要频繁筛选、联动、更新,建议考虑服务端预聚合、瓦片化或使用二进制数据加载方式。

方法比较:蜂窝聚合、热力图和网格聚合怎么选

方法 适合场景 优点 限制
HexagonLayer 蜂窝聚合 点密度、热点区域、三维聚合展示 空间单元清晰,适合解释聚合统计 结果受 radius 影响明显
HeatmapLayer 热力图 连续热点趋势展示 视觉平滑,适合快速看趋势 不如蜂窝图容易解释具体统计单元
GridLayer 方格聚合 规则网格统计、栅格化表达 和传统网格管理、栅格分析更接近 视觉上不如六边形自然
ScatterplotLayer 散点图 点数量较少、关注单个位置 保留原始点位置 数据量大时遮挡严重

如果你的目标是做“可解释的空间聚合统计”,Deck.gl蜂窝聚合图 通常比热力图更合适。热力图适合展示趋势,蜂窝图适合展示每个统计单元的强弱。

检查清单:上线前逐项确认

  • 数据坐标是否为经纬度,并且顺序为 [经度, 纬度]。
  • getPosition 是否能为每条记录返回有效坐标。
  • radius 是否符合业务分析尺度,而不是只为了视觉效果。
  • colorRange 是否从浅到深,能表达强弱变化。
  • getColorWeight 和 getElevationWeight 是否返回数值。
  • 是否需要按 COUNT、SUM、MEAN 等方式聚合。
  • tooltip 是否能帮助验证蜂窝内点数量或权重值。
  • 数据量是否适合前端直接加载。
  • 三维效果是否会遮挡底图或影响阅读。
  • 图例、说明文字中是否标明蜂窝半径和统计口径。

FAQ:Deck.gl蜂窝聚合图常见问题

Deck.gl蜂窝聚合图和热力图有什么区别?

蜂窝聚合图把点统计到明确的六边形单元里,每个蜂窝都有相对清晰的统计含义;热力图更强调连续的热点趋势,视觉上更平滑,但具体数值解释不如蜂窝聚合图直接。

HexagonLayer 的 radius 单位是什么?

在常见经纬度地图场景中,可以把 radius 理解为以米为单位的聚合半径。实际显示效果还会受到地图投影、缩放级别和视图范围影响。做 GIS 分析时,建议用多个半径测试,并选择符合业务尺度的值。

Deck.gl蜂窝聚合图可以按字段求和吗?

可以。通过 getColorWeightgetElevationWeight 以及对应的聚合方式,可以让颜色和高度按某个字段求和、求平均或使用其他支持的统计方式。常见做法是按订单金额、事件强度、人口数等字段加权。

为什么我的蜂窝图显示在错误位置?

优先检查两个问题:第一,坐标顺序是否写成了 [经度, 纬度];第二,原始数据是否已经转换到 WGS84 经纬度。如果把投影坐标直接传给 getPosition,图层位置通常会明显错误。

数据很多时还适合用 HexagonLayer 吗?

适合,但要看数据量和交互需求。几十万点以内的前端聚合在很多场景下可以工作;如果达到百万级,或者需要复杂筛选和实时刷新,建议考虑服务端预聚合、切片加载或减少传输字段。

二维蜂窝图和三维蜂窝图怎么选?

如果主要用于严肃分析和报表展示,二维蜂窝图更稳定、干扰少;如果用于大屏、演示或需要突出热点强弱,三维蜂窝图更有冲击力。但三维柱体可能遮挡底图,必须控制 elevationScale。

结论:先定统计口径,再调视觉参数

做 Deck.gl蜂窝聚合图,不要一开始就陷入颜色和高度的视觉调参。正确流程应该是:先确认点数据坐标正确,再确定聚合半径 radius,然后决定按数量还是按权重字段统计,最后再配置 colorRange、elevationRange 和 tooltip。

如果只记住几个关键参数,可以重点掌握 getPositionradiuscolorRangegetColorWeightgetElevationWeightelevationScaleextruded。这些参数基本决定了 Deck.gl蜂窝聚合图 的位置、聚合尺度、颜色含义和三维效果。

从 GIS 分析角度看,蜂窝聚合图不是单纯的“炫酷地图效果”,而是一种空间统计表达。只要把坐标、半径、权重和图例说明处理好,它就能成为 WebGIS 项目中非常实用的热点分析图层。