如何在D3.js v5中基于嵌套数据为分组条形图指定定义域
分组条形图定义域设置方案(D3.js v5 + 可选Lodash)
嘿,针对你用D3.js v5构建分组条形图的定义域需求,结合你提供的groupeddata数据,我整理了一套实用的实现步骤,不管用D3原生方法还是Lodash都能搞定:
1. 先提取核心的唯一数据
分组条形图需要两个关键的定义域维度:分组名称(Title)和组内的子类别(ID),另外Y轴需要基于RFU的数值范围。首先得从原始数据里把不重复的分组和子类别捞出来:
用D3原生方法提取
// 获取所有不重复的分组名称 const groupNames = d3.map(groupeddata, d => d.Title).keys(); // 获取所有不重复的子类别ID const subgroupNames = d3.map(groupeddata, d => d.ID).keys();
用Lodash简化操作(如果你引入了Lodash)
// 一键提取唯一Title const groupNames = _.uniq(_.map(groupeddata, 'Title')); // 一键提取唯一ID const subgroupNames = _.uniq(_.map(groupeddata, 'ID'));
2. 对原始数据做分组处理
为了后续方便绑定数据绘制条形,我们需要把原始数据按Title分组,每个分组下包含对应ID的RFU数据:
D3 v5的分组方式(注意v5用d3.nest,v6+才是d3.group)
const groupedData = d3.nest() .key(d => d.Title) .entries(groupeddata); // 输出结构大概是:[{key: "Dummy Data", values: [...]}, {key: "Dummy Data2", values: [...]}]
Lodash的分组方式更简洁
const groupedData = _.groupBy(groupeddata, 'Title'); // 输出结构:{"Dummy Data": [...], "Dummy Data2": [...]}
3. 设置比例尺的定义域
接下来就是核心的比例尺配置了,分组条形图需要两个X轴比例尺(外层分组、内层子类别)和一个Y轴数值比例尺:
X轴双比例尺配置
// 外层X比例尺:对应分组名称,控制分组之间的位置 const xGroupScale = d3.scaleBand() .domain(groupNames) // 定义域就是我们提取的唯一分组名 .range([0, width]) // width是你预先设定的图表宽度 .padding(0.2); // 分组之间的间距,数值越大间距越宽 // 内层X比例尺:对应每个分组下的子类别,控制组内条形的位置 const xSubgroupScale = d3.scaleBand() .domain(subgroupNames) // 定义域是唯一的子类别ID .range([0, xGroupScale.bandwidth()]) // 用外层分组的宽度作为内层比例尺的范围 .padding(0.1); // 组内条形之间的间距
Y轴数值比例尺配置
// 先找到所有RFU值里的最大值,作为Y轴的上限 const maxRFU = d3.max(groupeddata, d => d.RFU); const yScale = d3.scaleLinear() .domain([0, maxRFU]) // Y轴从0到最大RFU值 .range([height, 0]); // height是图表高度,注意D3的Y轴是从上到下数值递增,所以range是[height, 0]
4. 绑定数据绘制条形
最后一步就是把数据绑定到DOM元素上绘制条形了:
// 先添加分组容器,每个分组对应一个<g>标签 const groupContainers = svg.selectAll('.bar-group') .data(groupedData) .enter() .append('g') .attr('class', 'bar-group') .attr('transform', d => `translate(${xGroupScale(d.key || Object.keys(groupedData).find(k => groupedData[k] === d))}, 0)`); // 注:D3 nest结果用d.key,Lodash分组结果需要匹配对应的分组键名 // 在每个分组容器里绘制条形 groupContainers.selectAll('rect') .data(d => d.values) // 每个分组下的子数据 .enter() .append('rect') .attr('x', d => xSubgroupScale(d.ID)) // 组内条形的X位置 .attr('y', d => yScale(d.RFU)) // 条形顶部的Y位置 .attr('width', xSubgroupScale.bandwidth()) // 条形宽度 .attr('height', d => height - yScale(d.RFU)) // 条形高度(从Y轴位置到图表底部) .attr('fill', d => d.barcolor); // 用数据里的barcolor设置条形颜色
这样就能完美实现分组条形图的定义域配置和基础绘制啦,要是想调整间距或者样式,直接修改比例尺的padding参数就行~
内容的提问来源于stack exchange,提问作者Coola
相关产品推荐
相关产品推荐

