You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 10:21:02