如何为D3.js气泡图基于聚合数据动态设置轴域?
问题:D3.js气泡图动态Domain配置问题
我正在尝试为d3.js气泡图配置动态domain值,用来展示各客户端错误的总金额。用硬编码范围时,各客户端的气泡能正常显示:
.x(d3.scaleLinear().domain([0, 30])) .y(d3.scaleLinear().domain([0, 30])) .r(d3.scaleLinear().domain([0, 250]))
但改用d3.extent计算最小最大值时却失效了:
var minMax = d3.extent(data, function(d) { if (d.status == "settlement error") { return d.amount; } });
问题在于,当前计算的是单条错误数据的金额极值,而不是按客户端聚合后的总金额极值。
我的简化数据如下:
id,client,date,amount,status 10003,chase,2023-02-01,8,settlement error 10007,bofa,2022-11-22,2,settlement error 10008,citi,2022-11-22,8,settlement error 10009,chase,2023-02-01,4,settlement error
按客户端聚合后应该是:
chase - 错误数量 = 2, 总金额 = 12 bofa - 错误数量 = 1, 总金额 = 2 citi - 错误数量 = 1, 总金额 = 8
但当前minMax得到的是[2,8],我需要的是[2,12],最好能添加留白变成[1,15]来优化绘图效果。
补充说明
尝试@pernifloss的方案没解决问题后,我自定义了custom_elastic函数想从维度获取最值,但var max = clientErrorChart.dimension().top[1][0].value;报错:
function custom_elastic(clientErrorChart) { var max = 300;//clientErrorChart.dimension().top[1][0].value; var min = 10;//clientErrorChart.dimension().top(10)[9].value; clientErrorChart.x(d3.scaleLinear().domain([min, max])) }
之后我把这个函数绑定到图表的preRender和preRedraw事件:
clientErrorChart .height(300) .dimension(clientDim) .group(errorsByClient) .transitionDuration(1500) .colors(colorScale) //.x(d3.scaleLinear().domain([0, 3000])) .y(d3.scaleLinear().domain([0, 3000])) .r(d3.scaleLinear().domain([0, 250])) .keyAccessor(function (p) { return p.value.payment_sum; }) .valueAccessor(function (p) { return p.value.count; }) .radiusValueAccessor(function (p) { return p.value.error_count; }) .transitionDuration(1500) .elasticY(true) .yAxisPadding(1) .xAxisPadding(1) .label(function (p) { return p.key; }) .renderLabel(true) .renderTitle(true) .title(p => [ p.key, `总错误数: ${formatNumber(p.value.error_count)}`, `总支付金额: ${formatNumber(p.value.payment_sum)}`, `总交易量: ${formatNumber(p.value.count)}` ].join('\n')); clientErrorChart.on('preRender', custom_elastic) .on('preRedraw', custom_elastic);
解决方案
1. 先正确聚合客户端数据
要获取聚合后的总金额极值,需先按客户端分组计算总金额,再用d3.extent处理聚合结果:
// 按客户端聚合错误总金额 const aggregatedData = d3.rollup(data, v => d3.sum(v, d => d.amount), d => d.client ); // 提取聚合后的总金额数组 const totalAmounts = Array.from(aggregatedData.values()); // 计算极值并添加留白 const [min, max] = d3.extent(totalAmounts); const paddedMin = Math.max(1, min - 1); // 确保最小值不低于1 const paddedMax = max + 3; // 增加留白至15(对应示例中12+3=15) // 应用到scale的domain .x(d3.scaleLinear().domain([paddedMin, paddedMax]))
2. 修复custom_elastic函数的错误
报错原因是top是方法而非属性,需调用top()而非直接访问top,且要从group而非dimension获取聚合数据:
function custom_elastic(clientErrorChart) { // 从group获取所有聚合数据 const allGroups = clientErrorChart.group().all(); // 提取payment_sum数组 const paymentSums = allGroups.map(d => d.value.payment_sum); // 计算极值并添加留白 const [min, max] = d3.extent(paymentSums); const paddedMin = Math.max(1, min - 1); const paddedMax = max + 3; // 更新x轴domain clientErrorChart.x(d3.scaleLinear().domain([paddedMin, paddedMax])) }
修改后即可正确获取聚合后的总金额极值,动态设置x轴domain。
内容的提问来源于stack exchange,提问作者Sri Reddy
相关产品推荐
相关产品推荐

