You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 09:15:04