0

0

如何在 D3 + Leaflet 地图中按经纬度出现频次缩放圆形标记

霞舞

霞舞

发布时间:2026-01-11 16:14:24

|

905人浏览过

|

来源于php中文网

原创

如何在 D3 + Leaflet 地图中按经纬度出现频次缩放圆形标记

本文介绍如何将原始经纬度数据按坐标组合频次进行聚合,并动态缩放 svg 圆形标记半径,实现地理热点可视化。核心是使用 d3 的 `d3.group()` 统计重复坐标,再将频次映射为圆半径。

在 D3 与 Leaflet 混合开发中,直接对原始 CSV 数据逐行渲染圆形(如 d3.csv(...).enter().append("circle"))会导致同一位置多次绘制重叠小圆,无法体现“密度”或“热度”。真正有效的解决方案是:先聚合数据,再渲染唯一坐标点,并以频次驱动视觉编码(如半径大小)

✅ 正确步骤概览

  1. 加载并预处理数据:使用 d3.csv() 读取数据;
  2. 按经纬度组合分组统计:利用 d3.group() 将相同 [lat, lng] 的记录归为一组;
  3. 生成聚合后的新数据集:每个元素包含 cnt(出现次数)、sub_district_lat、sub_district_long;
  4. 绑定聚合数据并设置半径:将 r 属性设为 d => baseRadius * d.cnt(可进一步用 d3.scaleSqrt() 实现更合理的视觉比例);
  5. 保持地图交互响应性:保留 map.on("moveend", update) 逻辑,确保缩放/拖拽时坐标实时重投影。

? 示例代码(D3 v7 + Leaflet)

// 1. 聚合数据:按 [lat, lng] 字符串键分组
const grouped = d3.group(data, d => 
  `${+d.sub_district_lat.toFixed(6)},${+d.sub_district_long.toFixed(6)}`
);

// 2. 转换为带频次的对象数组
const aggregatedData = Array.from(grouped, ([_, records]) => ({
  cnt: records.length,
  sub_district_lat: +records[0].sub_district_lat,
  sub_district_long: +records[0].sub_district_long
}));

// 3. 创建比例尺(推荐!避免半径随频次线性爆炸)
const radiusScale = d3.scaleSqrt()
  .domain(d3.extent(aggregatedData, d => d.cnt))
  .range([4, 24]); // 最小半径4px,最大24px

// 4. 渲染圆形(注意:绑定 aggregatedData,非原始 data)
d3.select("#mapid")
  .select("svg")
  .selectAll("circle")
  .data(aggregatedData)
  .enter()
  .append("circle")
    .attr("cx", d => map.latLngToLayerPoint([d.sub_district_lat, d.sub_district_long]).x)
    .attr("cy", d => map.latLngToLayerPoint([d.sub_district_lat, d.sub_district_long]).y)
    .attr("r", d => radiusScale(d.cnt)) // ✅ 使用比例尺,更科学
    .style("fill", "#e34a33")
    .attr("stroke", "#b30000")
    .attr("stroke-width", 0.8)
    .attr("fill-opacity", 0.7);

⚠️ 关键注意事项

  • 精度处理:原始经纬度可能存在浮点误差(如 52.52000000000001 vs 52.52),建议先统一保留 5–6 位小数再拼接键,否则相同位置会被视为不同分组;
  • 性能优化:若数据量极大(>10k 条),d3.group() 仍高效,但应避免在 update() 中重复聚合——聚合只需执行一次;
  • 视觉合理性:*切勿直接使用 `r = k cnt线性缩放**。频次差异大时,高频点会过度遮盖邻近区域。d3.scaleSqrt()或d3.scalePow().exponent(0.3)` 更符合人眼对面积的感知;
  • D3 版本兼容性:d3.group() 是 D3 v6+ 新增 API;若必须用 v4/v5,可用 d3.nest() 替代(语法稍冗长);
  • Leaflet SVG 层:确保 L.svg().addTo(map) 在 d3.csv() 前执行,否则 d3.select("svg") 可能为空。

? 总结

将地理点频次映射为视觉尺寸,本质是「数据聚合 → 比例映射 → 坐标投影 → SVG 渲染」四步闭环。抛弃“一个坐标画一个圆”的直觉做法,转向“一个聚合点画一个缩放圆”的分析思维,才能构建真正可读、可扩展、专业的地理热力图。后续还可叠加 d3.tip() 实现悬停显示频次,或用 d3.contourDensity() 生成平滑热力面——但一切始于扎实的频次聚合。

稿定AI绘图
稿定AI绘图

稿定推出的AI绘画工具

下载

相关专题

更多
append用法
append用法

append是一个常用的命令行工具,用于将一个文件的内容追加到另一个文件的末尾。想了解更多append用法相关内容,可以阅读本专题下面的文章。

343

2023.10.25

python中append的用法
python中append的用法

在Python中,append()是列表对象的一个方法,用于向列表末尾添加一个元素。想了解更多append的更多内容,可以阅读本专题下面的文章。

1070

2023.11.14

python中append的含义
python中append的含义

本专题整合了python中append的相关内容,阅读专题下面的文章了解更多详细内容。

173

2025.09.12

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

74

2025.09.05

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

28

2025.11.16

golang map原理
golang map原理

本专题整合了golang map相关内容,阅读专题下面的文章了解更多详细内容。

59

2025.11.17

java判断map相关教程
java判断map相关教程

本专题整合了java判断map相关教程,阅读专题下面的文章了解更多详细内容。

34

2025.11.27

PHP 高并发与性能优化
PHP 高并发与性能优化

本专题聚焦 PHP 在高并发场景下的性能优化与系统调优,内容涵盖 Nginx 与 PHP-FPM 优化、Opcode 缓存、Redis/Memcached 应用、异步任务队列、数据库优化、代码性能分析与瓶颈排查。通过实战案例(如高并发接口优化、缓存系统设计、秒杀活动实现),帮助学习者掌握 构建高性能PHP后端系统的核心能力。

98

2025.10.16

c++主流开发框架汇总
c++主流开发框架汇总

本专题整合了c++开发框架推荐,阅读专题下面的文章了解更多详细内容。

80

2026.01.09

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
svg中文手册
svg中文手册

共0课时 | 0人学习

SVG 教程
SVG 教程

共20课时 | 10万人学习

最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 0.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号