如何在基于Google Sheets的Sankey图中添加节点占比?
实现方法:为Sankey图节点添加占总值百分比
核心思路
- 计算数值列的总和作为基准值
- 统计每个节点(源/目标)的总流量(流经该节点的所有数值之和)
- 计算每个节点流量占总值的百分比,拼接至原节点名称后
- 将修改后的节点标签传入Sankey图绘制逻辑
代码修改示例
假设你的原有脚本已经能读取Sheet数据并生成基础Sankey图,以下是修改后的关键代码片段:
function drawSankeyWithPercentage() { const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); const rawData = sheet.getDataRange().getValues(); const headers = rawData.shift(); // 移除表头行(假设表头为["源", "目标", "数值"]) // 1. 计算数值列的总总值 const totalValue = rawData.reduce((sum, row) => sum + row[2], 0); if (totalValue === 0) { SpreadsheetApp.getUi().alert("数值列总和为0,无法计算百分比"); return; } // 2. 统计每个节点的总流量(源/目标节点分别累加) const nodeTotalFlow = {}; rawData.forEach(row => { const source = row[0]; const target = row[1]; const value = row[2]; nodeTotalFlow[source] = (nodeTotalFlow[source] || 0) + value; nodeTotalFlow[target] = (nodeTotalFlow[target] || 0) + value; }); // 3. 生成带百分比的节点标签,同时整理Sankey所需的节点、映射关系和链接数据 const nodes = []; const nodeIndexMap = {}; const links = []; rawData.forEach(row => { const source = row[0]; const target = row[1]; const value = row[2]; // 处理源节点:若未加入节点列表,生成带百分比的标签并加入 if (!nodeIndexMap[source]) { const percentage = ((nodeTotalFlow[source] / totalValue) * 100).toFixed(2); const labeledName = `${source} (${percentage}%)`; nodeIndexMap[source] = nodes.length; nodes.push({ label: labeledName }); } // 处理目标节点:同上 if (!nodeIndexMap[target]) { const percentage = ((nodeTotalFlow[target] / totalValue) * 100).toFixed(2); const labeledName = `${target} (${percentage}%)`; nodeIndexMap[target] = nodes.length; nodes.push({ label: labeledName }); } // 整理链接数据(与原有逻辑一致) links.push({ source: nodeIndexMap[source], target: nodeIndexMap[target], value: value }); }); // 4. 此处插入原有Sankey图绘制逻辑,传入修改后的nodes和links即可 // 示例(基于Google Charts Sankey): google.charts.load('current', {'packages':['sankey']}); google.charts.setOnLoadCallback(() => { const data = new google.visualization.DataTable(); data.addColumn('string', '源'); data.addColumn('string', '目标'); data.addColumn('number', '数值'); // 将rawData转换为DataTable格式(或使用nodes/links映射后的结构) const chartData = rawData.map(row => [row[0], row[1], row[2]]); data.addRows(chartData); const options = { sankey: { node: { // 确保节点标签使用我们生成的带百分比的名称 label: { formatter: (label) => { const originalName = label.split(' (')[0]; return nodeIndexMap[originalName] ? nodes[nodeIndexMap[originalName]].label : label; } } } } }; const chart = new google.visualization.Sankey(document.getElementById('sankey_div')); chart.draw(data, options); }); }
关键细节说明
- 节点流量统计:Sankey图中节点的总流量等于其所有流入/流出数值的总和,因此同时累加源和目标节点的数值,确保统计准确
- 百分比格式化:使用
toFixed(2)保留两位小数,可根据需求调整精度 - 零值处理:加入总和为0的判断,避免出现除以0的错误
- 标签匹配:若使用Google Charts的默认标签格式化,需通过原节点名称匹配带百分比的标签,确保显示正确
内容的提问来源于stack exchange,提问作者Padavan
相关产品推荐
相关产品推荐

