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

如何用D3.js创建日期与小时轴热力图并配置刻度?

D3.js热力图:日期/小时轴刻度与布局修正方案

核心问题梳理

  • 原代码中y轴使用d3.scaleTime()但传入数字类型的domain,导致轴渲染异常(scaleTime仅支持时间对象)
  • 未对坐标轴应用tickFormat指定日期/小时的显示格式
  • 热力图矩形宽高固定为2px,无法适配日期和小时的区间分布,布局混乱

修正后的完整代码

HTML部分

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js"></script>
<div id="viz"></div>

JavaScript部分

const margin = { top: 50, right: 30, bottom: 80, left: 80 },
      width = 800 - margin.left - margin.right,
      height = 500 - margin.top - margin.bottom;

const svg = d3.select("#viz")
  .append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
  .append("g")
  .attr("transform", `translate(${margin.left}, ${margin.top})`);

const parseTime = d3.utcParse("%m/%d/%Y %I:%M:%S %p");
// 定义格式化规则
const formatDateLabel = d3.timeFormat("%b %d"); // 示例:Jan 01
const formatHourLabel = d3.timeFormat("%I%p"); // 示例:12am、01am

// 初始化坐标轴比例尺
const x = d3.scaleTime().range([0, width]);
const y = d3.scaleTime().range([0, height]);

// 颜色比例尺
const color = d3.scaleOrdinal()
  .range(["#fff000", "purple", "blue", "green"]);

d3.csv("https://raw.githubusercontent.com/sprucegoose1/sample-data/main/subway_delays.csv").then((data) => {
  // 处理数据:解析时间,提取日期和对应小时的时间对象
  data.forEach((d) => {
    d.fullTime = parseTime(d.Date);
    d.day = d3.timeDay(d.fullTime); // 提取日期(当天0点)
    d.hourTime = d3.timeHour(d.fullTime); // 提取当天对应小时的时间对象
  });

  // 设置坐标轴domain
  x.domain(d3.extent(data, d => d.day));
  y.domain(d3.extent(data, d => d.hourTime));

  // 渲染x轴(顶部),应用日期格式化
  svg.append("g")
    .attr("transform", `translate(0, 0)`)
    .call(d3.axisTop(x).tickFormat(formatDateLabel))
    .selectAll("text")
    .style("text-anchor", "start")
    .attr("transform", "rotate(45)"); // 旋转日期标签避免重叠

  // 渲染y轴(左侧),应用小时格式化
  svg.append("g")
    .call(d3.axisLeft(y).tickFormat(formatHourLabel));

  // 渲染热力图矩形
  svg.selectAll(".heatmap-rect")
    .data(data)
    .enter()
    .append("rect")
    .attr("class", "heatmap-rect")
    .attr("x", d => x(d.day))
    .attr("y", d => y(d.hourTime))
    // 根据日期区间自动计算宽度
    .attr("width", x(d3.timeDay.offset(data[0].day, 1)) - x(data[0].day))
    // 根据小时区间自动计算高度
    .attr("height", y(d3.timeHour.offset(data[0].hourTime, 1)) - y(data[0].hourTime))
    .style("fill", d => color(d.Affected))
    .style("stroke", "#fff") // 添加白色边框区分单元格
    .style("stroke-width", 0.5);
});

关键细节说明

  1. 时间数据处理:
    使用d3.timeDay和d3.timeHour分别提取日期(当天0点)和小时时间对象,确保坐标轴的scaleTime能正确映射时间值。

  2. 坐标轴刻度格式化:

    • x轴通过.tickFormat(formatDateLabel)将日期格式化为Jan 01样式,同时旋转标签避免重叠
    • y轴通过.tickFormat(formatHourLabel)将小时格式化为12am/01am样式
  3. 热力图单元格适配:
    通过计算相邻日期/小时的比例尺差值,自动设置矩形的宽高,确保每个日期-小时组合对应一个规整的单元格,而非固定尺寸的小方块。

内容的提问来源于stack exchange,提问作者sprucegoose

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 12:44:54