D3 Sankey从v3迁移到v4后出现TypeError: source未定义问题求助
解决D3 v3到v4迁移Sankey图时的TypeError: source is undefined问题
这个报错我在迁移D3 Sankey图到v4版本时也碰到过,大概率是数据转换不规范或者Sankey API适配错误导致的,咱们一步步来排查解决:
核心原因分析
你报错的那段sankey.js代码,是在把links里的source/target从数字索引转换成nodes数组里的节点对象。如果出现source is undefined,通常是两种情况:
- links里的source值既不是数字,也不是有效的节点对象(比如是CSV直接读取的字符串),导致代码没有完成转换,后续访问
source.sourceLinks时出错。 - links里的source索引在nodes数组中找不到对应项(比如索引是-1),
nodes[link.source]返回undefined。
分步解决方法
1. 规范处理CSV数据源
CSV文件读取后,所有字段默认都是字符串,而且可能存在空值或无效行,必须先转换为Sankey需要的格式:
- 第一步:提取所有唯一的节点名称,生成nodes数组
- 第二步:将links中的source/target转换为对应的nodes索引(数字类型)
- 第三步:过滤掉无效行(比如缺失source/target/value的行)
示例代码:
d3.csv("your-data.csv").then(csvData => { // 1. 提取所有有效节点,过滤空值 const nodesSet = new Set(); csvData.forEach(d => { if (d.source && d.target) { nodesSet.add(d.source); nodesSet.add(d.target); } }); const nodes = Array.from(nodesSet).map(name => ({ name })); // 2. 转换links,确保source/target是有效索引,value是数字 const links = csvData .filter(d => d.source && d.target && d.value) .map(d => ({ source: nodes.findIndex(n => n.name === d.source), target: nodes.findIndex(n => n.name === d.target), value: +d.value // 务必把字符串转成数字 })) // 过滤掉找不到对应节点的无效链接 .filter(d => d.source !== -1 && d.target !== -1); // 后续的Sankey布局代码... }).catch(err => console.error("读取CSV失败:", err));
2. 适配D3 v4的Sankey API
D3 v4的Sankey布局API和v3差异很大,如果你还在沿用v3的调用方式,也会导致数据处理异常:
- 确保使用的是适配v4的
sankey库(比如官方的d3-sankey,而不是v3的旧代码) - 正确初始化和调用Sankey布局:
示例代码:
const width = 800; const height = 600; // 初始化Sankey布局 const sankey = d3.sankey() .nodeWidth(20) // 节点宽度 .nodePadding(10) // 节点间距 .extent([[10, 10], [width - 10, height - 10]]); // 布局范围 // 生成处理后的布局数据 const sankeyLayout = sankey({ nodes, links }); // 后续使用sankeyLayout.nodes和sankeyLayout.links绘制图形
3. 验证sankey.js版本兼容性
如果你使用的是自定义或第三方的sankey.js,要确保它是为D3 v4编写的。v3的sankey代码依赖v3的D3 API,直接在v4环境中运行会出现变量未定义的问题,建议替换为官方的d3-sankey包。
最后检查点
- 确认CSV中没有空的source/target字段
- 确认links里的所有source/target都能在nodes数组中找到对应项
- 确认value字段已经转换成数字类型(Sankey需要数值型的流量值)
内容的提问来源于stack exchange,提问作者Saket Dabi
相关产品推荐
相关产品推荐

