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

如何在ObservableHQ中基于用户分组数据制作分面单元格图表?

问题描述

我有如下对象数组:

[{ "userid": 1, "groupid": 66123, "date_joined": "2023-01-01", "d0": "10", "d1": "6", "d2": "0", "d3": "1", "d4": "0", "d5": "0", "d6": "0", "d7": "0", "d8": "0", "d9": "0", "d10": "0", "d11": "0", "d12": "0", "d13": "0", "d14": "0" }, 
{ "userid": 2, "groupid": 66123, "date_joined": "2023-01-01", "d0": "0", "d1": "0", "d2": "2", "d3": "0", "d4": "0", "d5": "0", "d6": "0", "d7": "0", "d8": "0", "d9": "0", "d10": "0", "d11": "0", "d12": "0", "d13": "0", "d14": "0" }, 
{ "userid": 3, "groupid": 68100, "date_joined": "2023-01-01", "d0": "0", "d1": "0", "d2": "0", "d3": "0", "d4": "0", "d5": "0", "d6": "0", "d7": "0", "d8": "0", "d9": "0", "d10": "0", "d11": "0", "d12": "0", "d13": "0", "d14": "0" }]

我希望制作分面单元格图表,要求:

  • 每个分面由groupid决定
  • 分面中的每一行对应一个userid
  • 每行包含15个单元格,分别对应d0至d14列

示例:第一个分面对应groupid"66123",包含两行:userid"1"和userid"2",每行有15个单元格对应d0至d14列。

参考了一段Observable Plot的示例代码,但不确定如何修改其中的x: d => d3.utcWeek.count(d3.utcYear(d.Date), d.Date),部分来实现需求:

Plot.plot({
  height: 1400,
  x: {
    axis: null,
    padding: 0,
  },
  y: {
    padding: 0,
    tickFormat: Plot.formatWeekday("en", "narrow"),
    tickSize: 0
  },
  fy: {
    reverse: true
  },
  facet: {
    data: DJI,
    y: d => d.Date.getUTCFullYear()
  },
  color: {
    type: "diverging",
    scheme: "PiYG"
  },
  marks: [
    Plot.cell(DJI, {
      x: d => d3.utcWeek.count(d3.utcYear(d.Date), d.Date),
      y: d => d.Date.getUTCDay(),
      fill: (d, i) => i > 0 ? (d.Close - DJI[i - 1].Close) / DJI[i - 1].Close : NaN,
      title: (d, i) => i > 0 ? ((d.Close - DJI[i - 1].Close) / DJI[i - 1].Close * 100).toFixed(1) : NaN,
      inset: 0.5
    })
  ]
})
解决方案

核心是先把宽格式数据转成适合单元格图的长格式,再调整坐标轴与分面的映射逻辑:

1. 转换数据格式

将每个用户的d0-d14列拆分为单独的行,每行包含分组、用户、天数和对应数值:

// 把原宽格式数据转为长格式
const longData = data.flatMap(user => {
  return Array.from({length:15}, (_, i) => ({
    groupid: user.groupid,
    userid: user.userid,
    day: i, // d0对应day=0,d1对应day=1,以此类推
    value: +user[`d${i}`] // 转为数字类型用于颜色映射
  }));
});

2. 修改Plot配置代码

调整分面、坐标轴映射及单元格填充逻辑:

Plot.plot({
  height: 400, // 根据实际用户数量调整高度
  x: {
    axis: null,
    padding: 0,
    domain: [0,14] // 对应d0到d14的15个单元格
  },
  y: {
    padding: 0,
    tickFormat: d => `用户${d}`, // y轴显示用户ID
    tickSize: 0
  },
  facet: {
    data: longData,
    y: d => d.groupid, // 按groupid分面
    label: d => `分组 ${d}`
  },
  fy: {
    reverse: true
  },
  color: {
    type: "linear", // 数值为非正负对比,用线性配色即可
    scheme: "Blues", // 可替换为你需要的配色方案
    domain: [0,10] // 匹配数据中的数值范围,可按需调整
  },
  marks: [
    Plot.cell(longData, {
      x: d => d.day, // x轴对应d0-d14的序号(0-14)
      y: d => d.userid, // y轴对应用户ID,每个用户一行
      fill: d => d.value, // 用d列的数值决定单元格颜色
      title: d => `第${d.day}天: ${d.value}`, // 悬停提示信息
      inset: 0.5 // 单元格之间的间距
    })
  ]
})

关键修改说明

  • 替换原时间相关的x映射:原代码计算时间周数,现在直接用转换后的day字段(0-14)对应x轴位置
  • 分面字段改为groupid:通过facet.y指定按分组生成分面
  • y轴映射为userid:每个用户对应一行单元格
  • 数据转长格式是核心:Observable Plot的cell标记更适合处理单条数据对应单个单元格的长格式结构

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 21:41:11