如何在Observable Plot中实现日期按周/月动态分组(TS/JS)
解决方案:Observable Plot 按月份/周分组 facet 日期轴
要实现将 facet 的 x 轴按月份/周动态分组,核心是先对日期进行周期聚合,再配置轴的显示格式,以下是具体步骤:
1. 数据预处理(或直接在 Plot 中映射)
使用 D3 的时间间隔函数(如 d3.utcMonth、d3.utcWeek)将原始 createdDate 映射到对应的周期起始日期(比如当月第一天、当周第一天)。你可以选择提前预处理数据,或者直接在 Plot 的字段访问器中处理:
方式一:提前预处理数据
import * as d3 from "d3"; // 按月份分组,生成新的 period 字段 const groupedByMonth = groupedAddRemove.map(d => ({ ...d, period: d3.utcMonth(d.createdDate) // 返回该日期所在月份的第一天 UTC 时间 })); // 若要按双周分组,替换为: // period: d3.utcWeek.every(2)(d.createdDate)
方式二:直接在 Plot 中映射(无需预处理)
// 在 facet 的 x 字段中直接计算周期 x: d => d3.utcMonth(d.createdDate)
2. 修改 Plot 配置
将 facet 的 x 轴替换为聚合后的周期字段,并配置日期显示格式:
const chart = Plot.plot({ x: { axis: null, domain: ["Add", "Remove"] }, y: { tickFormat: "s", label: "↑ Access Requests", grid: true }, color: { legend: true, type: "categorical", domain: ["Add", "Remove"], range: redGreenColorRange, }, style: { background: "transparent", }, width: 1350, caption: "in monthly increments", // 对应你的周期类型修改 facet: { data: groupedByMonth, // 若用方式二,这里还是传原始的 groupedAddRemove label: "Created Date", x: "period", // 方式一用这个;方式二直接写 x: d => d3.utcMonth(d.createdDate) xAxis: { tickFormat: d3.timeFormat("%b %Y"), // 显示格式:Jan 2024 tickRotate: 45, // 可选,旋转标签避免重叠 label: "Period" // 可选,自定义轴标签 } }, marks: [ Plot.barY(groupedByMonth, { // 方式二这里传原始数据 x: "type", y: "count", fill: "type", }), Plot.ruleY([0]), ], });
关键说明
- 日期格式自定义:
d3.timeFormat的格式字符串可按需调整:%B %Y→ January 2024(完整月份名)%m/%Y→ 01/2024(数字月份)%d %b %Y→ 01 Jan 2024(带日期的周起始格式)
- 周期调整:替换
d3.utcMonth为d3.utcWeek可切换为周分组,d3.utcWeek.every(2)则是双周分组 - 关于 type 字段:用 "Add"/"Remove" 作为类型值的方式很合理,能自动匹配图例文本,无需改回布尔值
备选:纯 D3.js 实现思路
如果切换到 D3.js,核心逻辑一致:
- 用
d3.group按周期+类型聚合数据 - 生成 x 轴时使用时间比例尺(
d3.scaleUtc),并设置时间间隔刻度(d3.utcMonth.ticks) - 绑定聚合后的数据绘制分组柱状图
内容的提问来源于stack exchange,提问作者Adam
相关产品推荐
相关产品推荐

