R Leaflet聚合饼图实现:计数改为数值求和并控制气泡大小
Leaflet分组饼图标注求和+气泡大小调整修改方案
修改说明
- 新增数值字段存储每个点的统计值,替代原有的单纯计数逻辑
- JS部分重写分组统计逻辑,改为按数值求和计算分组占比
- 新增全局大小缩放系数,可直接调整所有气泡的整体尺寸
- 所有修改对R用户友好,无需手动修改JS代码,仅需调整R侧参数即可
完整可运行代码
library(leaflet) library(dplyr) # 创建测试数据 data("breweries91",package="leaflet") breweries91$goodbear<-sample(as.factor(c("terrific","marvelous","culparterretaping")),nrow(breweries91),replace=T) # 新增每个点的计数值(你可以替换成你自己的实际数值字段) set.seed(123) breweries91$count_val <- sample(1:20, nrow(breweries91), replace = T) # 配色设置 joliepalette<-c("red","green","blue")[1:nlevels(breweries91$goodbear)] getColor <- function(breweries91) {joliepalette[breweries91$goodbear]} # 标记图标设置 icons <- awesomeIcons( icon = 'ios-close', iconColor = 'black', library = 'ion', markerColor = getColor(breweries91) ) # 气泡大小缩放系数:数值越大所有气泡越大,可根据需求调整 size_scale <- 0.8 # 生成修改后的JS代码 jsscript3<- paste0( "function(cluster) { const groups= [",paste("'",levels(breweries91$goodbear),"'",sep="",collapse=","),"]; const colors= { groups: [",paste("'",joliepalette,"'",sep="",collapse=","),"], center:'#ddd', text:'black' }; const markers= cluster.getAllChildMarkers(); // 计算所有点的总数值 const totalSum = markers.reduce((sum, marker) => sum + marker.options.count_val, 0); // 计算每个分组的数值占比 const proportions= groups.map(group => { const groupSum = markers.filter(marker => marker.options.group === group) .reduce((sum, marker) => sum + marker.options.count_val, 0); return groupSum / totalSum; }); function sum(arr, first= 0, last) { return arr.slice(first, last).reduce((total, curr) => total+curr, 0); } const cumulativeProportions= proportions.map((val, i, arr) => sum(arr, 0, i+1)); cumulativeProportions.unshift(0); // 气泡大小计算,可根据需求调整公式,size_scale控制整体缩放 const width = 2*Math.sqrt(totalSum) * ", size_scale, "; const radius= 15+width/2; const arcs= cumulativeProportions.map((prop, i) => { return { x : radius*Math.sin(2*Math.PI*prop), y : -radius*Math.cos(2*Math.PI*prop), long: proportions[i-1] >.5 ? 1 : 0 }}); const paths= proportions.map((prop, i) => { if (prop === 0) return ''; else if (prop === 1) return `<circle cx='0' cy='0' r='${radius}' fill='none' stroke='${colors.groups[i]}' stroke-width='${width}' stroke-alignment='center' stroke-linecap='butt' />`; else return `<path d='M ${arcs[i].x} ${arcs[i].y} A ${radius} ${radius} 0 ${arcs[i+1].long} 1 ${arcs[i+1].x} ${arcs[i+1].y}' fill='none' stroke='${colors.groups[i]}' stroke-width='${width}' stroke-alignment='center' stroke-linecap='butt' />` }); return new L.DivIcon({ html: ` <svg width='60' height='60' viewBox='-30 -30 60 60' style='width: 60px; height: 60px; position: relative; top: -24px; left: -24px;' > <circle cx='0' cy='0' r='15' stroke='none' fill='${colors.center}' /> <text x='0' y='0' dominant-baseline='central' text-anchor='middle' fill='${colors.text}' font-size='15'>${totalSum}</text> ${paths.join('')} </svg> `, className: 'marker-cluster' }); }") # 生成地图 leaflet() %>% addTiles() %>% addAwesomeMarkers(data=breweries91, group=~goodbear, # 把计数值传到marker的options里供JS读取 options = markerOptions(count_val = ~count_val), icon = icons, clusterOptions = markerClusterOptions( iconCreateFunction = JS(jsscript3)))
参数调整说明
- 如果你要使用自己的数值字段,仅需把代码里的
count_val替换成你实际的字段名即可 - 调整
size_scale参数的数值即可控制所有气泡的整体大小,数值越大气泡越大 - 可以修改
width的计算公式自定义大小映射规则,比如改为线性映射const width = totalSum * 0.2 * ", size_scale, "即可改成数值越大气泡线性增大
内容的提问来源于stack exchange,提问作者Jacek Kotowski
相关产品推荐
相关产品推荐

