如何使用D3绘制带有月份和年份双X轴的柱状图
D3 双X轴柱状图实现思路
核心实现步骤
- 第一步:数据预处理,将原始数据整理为带
年份、月份、数值三个核心字段的结构化数据,同一年份的月份数据连续排列。 - 第二步:创建主比例尺,使用
d3.scaleBand作为柱状图的X轴主比例尺,值域绑定所有「年份-月份」组合的有序数组,映射到画布的X轴像素区间,设置合适的内边距控制柱子间距。 - 第三步:绘制底层柱状图,基于主比例尺定位每个柱子的X坐标,绑定对应数值的Y轴高度。
- 第四步:绘制第一条X轴(月份轴),直接基于主比例尺生成轴,调用
d3.axisBottom()绑定主比例尺,tick值设置为每个数据对应的月份,渲染在画布底部X轴位置。 - 第五步:绘制第二条X轴(年份轴),复用主比例尺计算每个年份的居中位置:统计同一年份对应的所有数据在主比例尺中的起始和结束X坐标,取平均值作为该年份标签的定位点,单独创建一个仅展示年份标签的轴,或者直接用
append('text')手动渲染每个年份标签,渲染在月份轴的下方,可额外添加年份区间的分隔线提升可读性。 - 第六步:样式调整,给年份轴标签添加合适的外边距,对齐同一年份的所有柱子,避免标签重叠。
核心代码片段参考
// 示例数据结构 const data = [ {year: 2021, month: 1, value: 120}, {year: 2021, month: 2, value: 150}, // 其余同结构数据省略 ] // 主X轴比例尺,绑定所有年月组合 const allMonths = data.map(d => `${d.year}-${d.month}`) const xScale = d3.scaleBand() .domain(allMonths) .range([0, width]) .padding(0.2) // 计算每个年份的居中显示位置 const yearPositions = d3.rollups(data, v => { const firstX = xScale(`${v[0].year}-${v[0].month}`) const lastX = xScale(`${v[0].year}-${v.at(-1).month}`) + xScale.bandwidth() return (firstX + lastX) / 2 }, d => d.year) // 绘制月份X轴 svg.append('g') .attr('transform', `translate(0, ${height})`) .call(d3.axisBottom(xScale).tickFormat(d => d.split('-')[1])) // 绘制年份X轴 const yearAxis = svg.append('g') .attr('transform', `translate(0, ${height + 30})`) yearPositions.forEach(([year, xPos]) => { yearAxis.append('text') .attr('x', xPos) .attr('y', 10) .attr('text-anchor', 'middle') .text(year) })
内容的提问来源于stack exchange,提问作者Babas
相关产品推荐
相关产品推荐

