数据可视化数据分析GIS【免费下载链接】foliumPython Data. Leaflet.js Maps.项目地址https://gitcode.com/gh_mirrors/fo/folium点击查看免费下载导读当一张地图上需要展示数百、数千乃至上万个标记点时逐一点亮会带来严重的视觉拥挤与渲染卡顿。folium 的MarkerCluster与FastMarkerCluster插件基于 Leaflet.markercluster把邻近标记自动聚合为带数字徽标的集群缩放时平滑展开是数据可视化中处理海量点位的事实标准方案。本文将完整讲解两种集群的三种添加标记方式、icon_create_function自定义集群图标、options参数透传、图层控制行为以及FastMarkerCluster的浏览器端渲染原理与性能取舍并辅以 folium/plugins/marker_cluster.py、folium/plugins/fast_marker_cluster.py 与对应测试的源码级佐证。一、MarkerCluster 是什么MarkerCluster是 folium 对 Leaflet 生态中Leaflet.markercluster插件的 Python 封装类定义位于 folium/plugins/marker_cluster.py并通过 folium/plugins/init.py 对外导出。它继承自JSCSSMixin与Layer因此既会自动注入插件所需的 JavaScript 与 CSS 资源也具备图层Layer的标准行为如加入图层控制器。资源加载从源码可以看到插件资源通过 CDN 自动引入default_js/default_css见 folium/plugins/marker_cluster.pyhttps://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.1.0/leaflet.markercluster.jsMarkerCluster.cssMarkerCluster.Default.css这意味着使用MarkerCluster或FastMarkerCluster时无需手动引入任何外部资源渲染出的 HTML 会自动包含以上三条标签这一点也在测试 tests/plugins/test_marker_cluster.py 中通过断言leaflet.markercluster.js、MarkerCluster.css、MarkerCluster.Default.css出现在输出中得到了验证。适用场景百万级 POI、GPS 轨迹点、地理统计散点的大规模展示需要在地图缩放过程中动态聚合/展开点位的交互式仪表盘希望每个集群展示子标记数量的场景默认徽标即显示子标记数。二、快速上手把 Marker 逐个加入集群最直观的用法是先创建一个MarkerCluster实例并挂到地图上然后像使用普通图层一样把folium.Marker逐个add_to集群import folium from folium.plugins import MarkerCluster m folium.Map(location[44, -73], zoom_start5) marker_cluster MarkerCluster().add_to(m) folium.Marker( location[40.67, -73.94], popupAdd popup text here., iconfolium.Icon(colorgreen, iconok-sign), ).add_to(marker_cluster) folium.Marker( location[44.67, -73.94], popupAdd popup text here., iconfolium.Icon(colorred, iconremove-sign), ).add_to(marker_cluster) folium.Marker( location[44.67, -71.94], popupAdd popup text here., iconNone, ).add_to(marker_cluster) m要点说明每个folium.Marker可以独立设置popup弹窗内容支持 HTML 字符串与icon图标可以是folium.Icon对象也可以传None传入None图标时使用 Leaflet 默认标记样式marker_cluster内部是 Leaflet 的L.markerClusterGroup所有子标记会被自动聚类缩放级别越高集群展开得越细致。三、批量添加一次调用传入全部位置当点位数量较大且不需要逐点定制时可以直接把位置、弹窗、图标以列表形式一次性传给MarkerCluster构造函数。下面以 100 个随机生成的点为例原文使用numpy生成 100 个随机经纬度import numpy as np size 100 lons np.random.randint(-180, 180, sizesize) lats np.random.randint(-90, 90, sizesize) locations list(zip(lats, lons)) popups [lon:{}brlat:{}.format(lon, lat) for (lat, lon) in locations]然后一次性构建集群from folium.plugins import MarkerCluster m folium.Map( location[np.mean(lats), np.mean(lons)], tilesCartodb Positron, zoom_start1 ) marker_cluster MarkerCluster( locationslocations, popupspopups, name1000 clustered icons, overlayTrue, controlTrue, icon_create_functionicon_create_function, ) marker_cluster.add_to(m) folium.LayerControl().add_to(m) m批量参数的行为细节源码级在 folium/plugins/marker_cluster.py 的__init__中批量添加的实现逻辑是先调用validate_locations(locations)对全部坐标进行合法性校验位于 folium/utilities.py再按索引遍历为每个位置创建Marker(location, popuppopups[i], iconicons[i])并add_child到集群。因此popups与icons是与locations等长的列表长度 n第 i 个元素对应第 i 个位置对应位置缺省时传None即可validate_locations要求坐标是可迭代的 (lat, lon) 二元组、数值可转换为float、且不允许 NaN见 folium/utilities.py 中validate_location的校验规则长度必须为 2、支持索引、数值可转 float、非 NaN。传入非法坐标会抛出TypeError/ValueError如果传入的是 pandas DataFrameif_pandas_df_convert_to_numpy会先将其转换为 numpy 数组再校验避免迭代 DataFrame 时首行被当作列名的副作用。位置坐标的校验规则validate_locations从 folium/utilities.py 源码可以总结出以下约束批量传参前建议提前检查位置必须为“可迭代且非空”空列表会抛出ValueError: Locations is empty.每个位置必须是长度为 2 的有序序列list、tuple、numpy 数组均可两个坐标值都必须能转换为float且不能是NaN校验结果统一归一化为[float(lat), float(lon)]形式的列表。四、显式循环添加在循环内逐点定制如果需要在循环体内对每个标记做差异化处理例如按数据值设置不同颜色、不同图标、不同弹窗内容可以在循环中创建folium.Marker并逐一加入集群m folium.Map( location[np.mean(lats), np.mean(lons)], tilesCartodb Positron, zoom_start1 ) marker_cluster MarkerCluster( name1000 clustered icons, overlayTrue, controlFalse, icon_create_functionNone ) for k in range(size): location lats[k], lons[k] marker folium.Marker(locationlocation) popup lon:{}brlat:{}.format(location[1], location[0]) folium.Popup(popup).add_to(marker) marker_cluster.add_child(marker) marker_cluster.add_to(m) folium.LayerControl().add_to(m); m这段示例展示了两种 folium 的常用对象组合方式folium.Popup(popup).add_to(marker)把弹窗对象显式挂到 Marker 上等价于构造 Marker 时直接传popup...marker_cluster.add_child(marker)与批量模式不同这里循环内每个 Marker 由用户自己构造拥有完全的自由度例如可以根据k的值动态切换folium.Icon(color...)。批量模式是循环模式的特例封装——构造函数内部同样是通过add_child(Marker(...))完成的见 folium/plugins/marker_cluster.py 中locations is not None分支。五、自定义集群图标icon_create_function默认的集群徽标样式由 Leaflet.markercluster 提供若要自定义集群图标的颜色、尺寸、显示内容可通过icon_create_function传入一段 JavaScript 函数字符串。文档示例中使用了L.divIconicon_create_function \ function(cluster) { return L.divIcon({ html: b cluster.getChildCount() /b, className: marker-cluster marker-cluster-large, iconSize: new L.Point(20, 20) }); }解析这段 JScluster.getChildCount()返回该集群包含的子标记数量这里用作徽标文字className: marker-cluster marker-cluster-large复用插件自带的 CSS 类其中marker-cluster-large是插件内置的三档样式之一另有marker-cluster-small、marker-cluster-medium对应集群大小不同时的背景配色iconSize: new L.Point(20, 20)徽标尺寸。源码中的注入方式从 folium/plugins/marker_cluster.py 的_template可以看到该函数被注入到L.markerClusterGroup的iconCreateFunction选项var {{ this.get_name() }} L.markerClusterGroup({{ this.options|tojavascript }}); {%- if this.icon_create_function is not none %} {{ this.get_name() }}.options.iconCreateFunction {{ this.icon_create_function.strip() }}; {%- endif %}即只要icon_create_function不为None渲染时就会以strip()去除首尾空白后作为iconCreateFunction直接写入生成的 JavaScript。因此该参数必须是合法的 JavaScript 函数字符串——构造时源码会assert isinstance(icon_create_function, str)传入非字符串会直接触发断言错误。FastMarkerCluster的模板中也存在同样的注入逻辑见 folium/plugins/fast_marker_cluster.py。六、options透传 Leaflet.markercluster 原生配置除了上述参数MarkerCluster还支持把原生Leaflet.markercluster的配置项以关键字参数**kwargs形式透传给底层 JS。源码实现如下if options is not None: kwargs.update(options) # options argument is legacy ... self.options remove_empty(**kwargs)options字典参数为历史遗留接口传入的字典会被合并进kwargs官方推荐直接使用关键字参数remove_empty会剔除值为None的键避免生成无效的 JS 配置最终所有配置通过tojavascript过滤注入L.markerClusterGroup({...})的第一个参数。常用的原生配置项举例以 Leaflet.markercluster 1.1.0 为准见插件官方文档showCoverageOnHover悬停是否显示覆盖范围、zoomToBoundsOnClick点击集群是否缩放到其边界、spiderfyOnMaxZoom最大缩放级别时是否蜘蛛化展开、disableClusteringAtZoom在该缩放级别及以上停止聚类、maxClusterRadius聚合半径等。这些以关键字参数传入即可例如MarkerCluster(maxClusterRadius80)。七、图层控制参数name / overlay / control / showMarkerCluster继承自folium.map.Layer见 folium/map.py因此具备标准图层行为四个常用参数含义如下参数默认值作用nameNone图层在 LayerControl 中显示的名称为None时使用自动生成的内部名称overlayTrueTrue时作为可选叠加层复选框勾选False时作为底图层单选按钮controlTrue是否出现在图层控制器LayerControl中showTrue打开页面时该图层是否默认显示这一点由Layer.__init__的源码与文档参数列表共同印证MarkerCluster.__init__将name、overlay、control、show原样传给super().__init__()处理其余参数才作为聚类配置。示例代码中常见的folium.LayerControl().add_to(m)就是配合controlTrue的图层开关使用。八、FastMarkerCluster浏览器端批量渲染的高性能方案FastMarkerCluster位于 folium/plugins/fast_marker_cluster.py继承自MarkerCluster定位是“牺牲灵活性换取速度”数据在浏览器端一次性渲染适合渲染“成千上万个点”的场景。核心原理源码级与MarkerCluster在 Python 端逐个构造 Marker 对象不同FastMarkerCluster的_template将整份数据序列化后直接交给 JS 端处理var data {{ this.data|tojson }}; var cluster L.markerClusterGroup({{ this.options|tojavascript }}); for (var i 0; i data.length; i) { var row data[i]; var marker callback(row); marker.addTo(cluster); }即所有点数据以 JSON 数组形式嵌入生成的 JavaScript循环与 Marker 创建全部发生在浏览器内Python 端不做逐点对象化因此速度远快于MarkerCluster。关键限制数据不驻留在 Python 端源码类文档明确说明FastMarkerCluster初始化时向父类传入空列表因此父类的add_child永远不会被调用Python 端不保留任何标记数据的引用。由此带来一个重要使用限制——基于Layer的get_bounds()等方法在FastMarkerCluster上不可用如果需要计算地图边界请改用MarkerCluster或自行维护坐标列表。data 参数支持 numpy、嵌套列表与 pandas DataFramedata的默认格式是形如[[lat, lon], [lat, lon], ...]的列表。构造时先经过if_pandas_df_convert_to_numpy转换pandas DataFrame 会转为 numpy 数组再逐行执行[*validate_location(row[:2]), *row[2:]]即每行前两列作为 (lat, lon) 校验并转为 float后续列原样保留供自定义callback使用。这意味着data每行可以携带额外字段例如颜色标记[[lat, lon, red], [lat, lon, blue]]由 JS 端的callback(row)消费。这一点在测试 tests/plugins/test_fast_marker_cluster.py 中得到验证测试覆盖了 numpy 数组、混合 list/tuple含字符串与字典以及 pandas DataFrame 三种输入并断言解析结果始终为长度为 3 的 listrow[0]为纬度、row[1]为经度、row[2]为扩展字段。基本用法from folium.plugins import FastMarkerCluster m folium.Map( location[np.mean(lats), np.mean(lons)], tilesCartodb Positron, zoom_start1 ) FastMarkerCluster(datalist(zip(lats, lons))).add_to(m) folium.LayerControl().add_to(m); m自定义 callback控制每个标记的样式不传callback时源码使用默认回调创建普通L.marker并套用L.AwesomeMarkers.icon()默认图标。如需自定义可以传入返回 Leaflet Marker 对象的 JS 函数字符串例如文档中的示例——按行数据生成红色 map-marker 图标callback \ function (row) { var icon, marker; icon L.AwesomeMarkers.icon({ icon: map-marker, markerColor: red}); marker L.marker(new L.LatLng(row[0], row[1])); marker.setIcon(icon); return marker; }; m folium.Map( location[np.mean(lats), np.mean(lons)], tilesCartodb Positron, zoom_start1 ) FastMarkerCluster(datalist(zip(lats, lons)), callbackcallback).add_to(m) mcallback接收的row对应数据中的一行row[0]是纬度、row[1]是经度额外的扩展列依次为row[2]、row[3]……所以通过扩展列即可实现“一列数据决定图标颜色”的差异化渲染。源码中若未提供callback会自动补全默认实现提供时则以var callback {你传入的函数};的形式注入模板。FastMarkerCluster同样支持name、overlay、control、show、icon_create_function与**kwargs原生配置透传规则与MarkerCluster一致options同样是遗留参数详见 folium/plugins/fast_marker_cluster.py 的参数列表。九、两种集群的选择建议维度MarkerClusterFastMarkerCluster添加方式Python 端逐点构造批量/循环均可数据整体交给浏览器端循环渲染灵活性高可逐点定制 Icon、Popup可保留数据引用低靠callback定制Python 端不保留数据引用性能点量大时 Python 端对象开销较大更快适合上千、上万个点get_bounds()可用不可用无数据引用数据源locations/popups/icons列表坐标经validate_locations校验data列表支持 numpy / pandas DataFrame / 嵌套 list可带扩展列选择原则点位少、需要精细定制或后续计算边界时用MarkerCluster点位规模大、只关心展示效果时用FastMarkerCluster。十、示例与测试佐证官方文档原文docs/user_guide/plugins/marker_cluster.md本文所有示例均继承自该文档并可独立运行Notebook 示例examples/MarkerCluster.ipynb实现源码folium/plugins/marker_cluster.py、folium/plugins/fast_marker_cluster.py测试用例tests/plugins/test_marker_cluster.py 验证了 JS/CSS 资源注入、渲染模板结构以及m.get_bounds()的边界结果tests/plugins/test_fast_marker_cluster.py 验证了渲染模板与多种data输入格式的解析坐标校验工具folium/utilities.py 中的validate_locations/validate_location/if_pandas_df_convert_to_numpy。结语MarkerCluster与FastMarkerCluster是 folium 中处理高密度标记点位的两个互补工具前者以 Python 对象的灵活度换取可控性后者以浏览器端批处理换取吞吐量。结合icon_create_function自定义集群徽标、callback逐点样式定制与**kwargs原生配置透传可以在地图上构建从几十到上万个点的流畅交互可视化。若需深入了解 Leaflet.markercluster 的全部原生选项可查阅插件官方文档并对照本仓库的模板渲染逻辑进行验证。赞分享数据可视化数据分析GIS【免费下载链接】foliumPython Data. Leaflet.js Maps.项目地址https://gitcode.com/gh_mirrors/fo/folium点击查看免费下载相关推荐Leaflet 大数据量标记聚合实战Leaflet.markercluster 插件能力与算法原理全解析Leaflet 大数据量标记聚合实战Leaflet.markercluster 插件能力与算法原理全解析 Leaflet.markercluster 是 Le前端数据可视化GISTelegraf Basicstats 聚合器插件指标基础统计与聚合实践指南Telegraf Basicstats 聚合器插件指标基础统计与聚合实践指南 本指南围绕 Telegraf 中的 basicstats 聚合器插件展开讲解如可观测性指标监控运维folium地图聚合标记高级样式从简单图标到复杂图表folium地图聚合标记高级样式从简单图标到复杂图表 引言解决地图标记的视觉混乱问题 当地图上需要展示成百上千个标记点时传统的单一图标显示方式会导致严重的数据可视化数据分析GIS上一篇【免费下载】 抖音动态与直播间开播检测与推送项目教程下一篇为什么Cap成为你首选的屏幕录制工具5分钟掌握开源录屏新体验创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考