D3 v4如何将数据绑定到坐标轴标签并指定字段设置域
解决D3 v4中坐标轴标签绑定原数据d.name的问题
我懂你现在的困扰:在D3 v4里想直接把原数据的d.name作为x轴刻度标签,同时用d.num设置坐标轴域,但当前tickFormat里拿不到原数据对象对吧?这是因为D3坐标轴的tickFormat函数的第一个参数d是比例尺输出的刻度值(也就是你设置的域里的num值),不是原数据对象,所以直接return d.name肯定会报错或者拿不到预期值。
下面给你一步步的解决方案:
1. 先处理数据并设置x比例尺的域
首先,你的数据里num是字符串类型,得先转成数字,不然比例尺的域计算会出问题:
// 遍历数据,把num转成数字类型 data.forEach(function(d) { d.num = +d.num; }); // 创建x线性比例尺(如果是序数比例尺逻辑类似) var x = d3.scaleLinear() .domain(d3.extent(data, function(d) { return d.num; })) // 用num的最小/最大值设置域 .range([margin.left, width - margin.right]); // 根据你的画布尺寸设置显示范围
2. 建立num到name的映射关系
为了在tickFormat里根据刻度的num值快速找到对应的name,我们可以先做一个映射对象:
var numToName = {}; data.forEach(function(d) { numToName[d.num] = d.name; });
这样后续拿到刻度值d(比如1、2、3)时,直接用numToName[d]就能得到对应的A、B、C了。
3. 配置x坐标轴
现在就可以用这个映射来设置刻度标签了,同时保留你需要的tickSize等配置:
var xAxis = d3.axisBottom(x) .tickSize(10) .ticks(data.length) // 匹配你的数据项数量,显示对应刻度数 .tickFormat(function(d) { // d是当前刻度的num值,返回对应的name作为标签 return numToName[d]; });
完整修改后的代码片段
把这些逻辑整合到你的代码里,大概是这样:
d3.json("data.json", function(error, newdata) { if (error) throw error; data = newdata; // 处理数据类型 data.forEach(function(d) { d.num = +d.num; }); // 建立num到name的映射 var numToName = {}; data.forEach(function(d) { numToName[d.num] = d.name; }); // 假设你已经定义了width、height、margin等画布参数 var x = d3.scaleLinear() .domain(d3.extent(data, function(d) { return d.num; })) .range([margin.left, width - margin.right]); // 配置x轴 var xAxis = d3.axisBottom(x) .tickSize(10) .ticks(data.length) .tickFormat(function(d) { return numToName[d]; }); // 把坐标轴绘制到SVG中 svg.append("g") .attr("transform", "translate(0," + (height - margin.bottom) + ")") .call(xAxis); // 你的其他绘图逻辑... });
为什么原代码行不通?
你原代码里的tickFormat(function(d, i) { return d.name; }),这里的d是刻度的数值(比如1、2),不是原数据对象,所以d.name肯定是undefined。而你之前尝试的name数组如果长度匹配出错,还会导致标签和刻度对应错位,用映射对象的方式直接关联num和name,可靠性更高。
内容的提问来源于stack exchange,提问作者ofey
相关产品推荐
相关产品推荐

