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

Vega-Lite混合图表问题:分组柱状图样本点异常及API转换需求

问题解决:Vega-Lite混合图表样本点匹配错误及API转换

问题原因

当前配置通过多次fold操作生成了数据的笛卡尔积,每个day + Category组合都关联了所有9个样本点,导致每个柱状图上显示全部样本。需要重新转换数据,让每个样本点和对应的分类(RAMOS/PBMC/RAMOS_PBMC)一一绑定。

修正后的Vega-Lite配置

通过两次fold将嵌套数据展开为扁平结构,再通过过滤区分样本点与中位数:

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "data": {
    "values": [
      {"key":"Ctrl","RAMOS":{"SAMPLE_1":2382,"SAMPLE_2":1998,"SAMPLE_3":2233,"MEDIAN":2233},"PBMC":{"SAMPLE_1":2,"SAMPLE_2":0,"SAMPLE_3":0,"MEDIAN":0},"RAMOS_PBMC":{"SAMPLE_1":213,"SAMPLE_2":240,"SAMPLE_3":153,"MEDIAN":213},"day":1,"R":4},
      {"key":"Ctrl","RAMOS":{"SAMPLE_1":4151,"SAMPLE_2":4451,"SAMPLE_3":4662,"MEDIAN":4451},"PBMC":{"SAMPLE_1":6,"SAMPLE_2":1,"SAMPLE_3":0,"MEDIAN":1},"RAMOS_PBMC":{"SAMPLE_1":178,"SAMPLE_2":140,"SAMPLE_3":173,"MEDIAN":173},"day":2,"R":4},
      {"key":"Ctrl","RAMOS":{"SAMPLE_1":11195,"SAMPLE_2":12059,"SAMPLE_3":12089,"MEDIAN":12059},"PBMC":{"SAMPLE_1":16,"SAMPLE_2":1,"SAMPLE_3":1,"MEDIAN":1},"RAMOS_PBMC":{"SAMPLE_1":278,"SAMPLE_2":274,"SAMPLE_3":299,"MEDIAN":278},"day":3,"R":4},
      {"key":"Ctrl","RAMOS":{"SAMPLE_1":17931,"SAMPLE_2":21797,"SAMPLE_3":23520,"MEDIAN":21797},"PBMC":{"SAMPLE_1":23,"SAMPLE_2":20,"SAMPLE_3":8,"MEDIAN":20},"RAMOS_PBMC":{"SAMPLE_1":810,"SAMPLE_2":467,"SAMPLE_3":858,"MEDIAN":810},"day":4,"R":4}
    ]
  },
  "transform": [
    {
      "fold": ["RAMOS", "PBMC", "RAMOS_PBMC"],
      "as": ["Category", "Data"]
    },
    {
      "fold": ["Data.SAMPLE_1", "Data.SAMPLE_2", "Data.SAMPLE_3", "Data.MEDIAN"],
      "as": ["Type", "Value"]
    },
    {
      "calculate": "split(datum.Type, '.')[1]",
      "as": "SubType"
    },
    {
      "calculate": "replace(datum.Category, '_', ' ')",
      "as": "CategoryLabel"
    }
  ],
  "layer": [
    {
      "mark": "bar",
      "transform": [{"filter": "datum.SubType === 'MEDIAN'"}],
      "encoding": {
        "x": {"field": "day", "type": "ordinal", "axis": {"title": "Day"}},
        "y": {"field": "Value", "type": "quantitative", "scale": {"type": "sqrt"}, "axis": {"title": "Cell Count"}},
        "color": {
          "field": "CategoryLabel", 
          "type": "nominal",
          "scale": {"range": ["#1f77b4", "#ff7f0e", "#2ca02c"]},
          "legend": {"title": "Category"}
        },
        "xOffset": {"field": "CategoryLabel"}
      }
    },
    {
      "mark": {"type": "point", "filled": true, "size": 80},
      "transform": [{"filter": "datum.SubType !== 'MEDIAN'"}],
      "encoding": {
        "x": {"field": "day", "type": "ordinal"},
        "y": {"field": "Value", "type": "quantitative"},
        "color": {"field": "CategoryLabel", "type": "nominal"},
        "xOffset": {"field": "CategoryLabel"},
        "tooltip": [
          {"field": "CategoryLabel", "title": "Category"},
          {"field": "SubType", "title": "Sample"},
          {"field": "Value", "title": "Cell Count"}
        ]
      }
    }
  ]
}

Vega-Lite API TypeScript实现

以下是适配TypeScript项目的链式调用代码:

import { vl } from 'vega-lite-api';

const chart = vl
  .data([
    {"key":"Ctrl","RAMOS":{"SAMPLE_1":2382,"SAMPLE_2":1998,"SAMPLE_3":2233,"MEDIAN":2233},"PBMC":{"SAMPLE_1":2,"SAMPLE_2":0,"SAMPLE_3":0,"MEDIAN":0},"RAMOS_PBMC":{"SAMPLE_1":213,"SAMPLE_2":240,"SAMPLE_3":153,"MEDIAN":213},"day":1,"R":4},
    {"key":"Ctrl","RAMOS":{"SAMPLE_1":4151,"SAMPLE_2":4451,"SAMPLE_3":4662,"MEDIAN":4451},"PBMC":{"SAMPLE_1":6,"SAMPLE_2":1,"SAMPLE_3":0,"MEDIAN":1},"RAMOS_PBMC":{"SAMPLE_1":178,"SAMPLE_2":140,"SAMPLE_3":173,"MEDIAN":173},"day":2,"R":4},
    {"key":"Ctrl","RAMOS":{"SAMPLE_1":11195,"SAMPLE_2":12059,"SAMPLE_3":12089,"MEDIAN":12059},"PBMC":{"SAMPLE_1":16,"SAMPLE_2":1,"SAMPLE_3":1,"MEDIAN":1},"RAMOS_PBMC":{"SAMPLE_1":278,"SAMPLE_2":274,"SAMPLE_3":299,"MEDIAN":278},"day":3,"R":4},
    {"key":"Ctrl","RAMOS":{"SAMPLE_1":17931,"SAMPLE_2":21797,"SAMPLE_3":23520,"MEDIAN":21797},"PBMC":{"SAMPLE_1":23,"SAMPLE_2":20,"SAMPLE_3":8,"MEDIAN":20},"RAMOS_PBMC":{"SAMPLE_1":810,"SAMPLE_2":467,"SAMPLE_3":858,"MEDIAN":810},"day":4,"R":4}
  ])
  .transform(
    vl.fold(["RAMOS", "PBMC", "RAMOS_PBMC"]).as(["Category", "Data"]),
    vl.fold(["Data.SAMPLE_1", "Data.SAMPLE_2", "Data.SAMPLE_3", "Data.MEDIAN"]).as(["Type", "Value"]),
    vl.calculate("split(datum.Type, '.')[1]").as("SubType"),
    vl.calculate("replace(datum.Category, '_', ' ')").as("CategoryLabel")
  )
  .layer(
    vl.markBar()
      .transform(vl.filter("datum.SubType === 'MEDIAN'"))
      .encode(
        vl.x().fieldOrdinal("day").axis({ title: "Day" }),
        vl.y().fieldQ("Value").scale({ type: "sqrt" }).axis({ title: "Cell Count" }),
        vl.color().fieldN("CategoryLabel").scale({ range: ["#1f77b4", "#ff7f0e", "#2ca02c"] }).legend({ title: "Category" }),
        vl.xOffset().fieldN("CategoryLabel")
      ),
    vl.markPoint({ filled: true, size: 80 })
      .transform(vl.filter("datum.SubType !== 'MEDIAN'"))
      .encode(
        vl.x().fieldOrdinal("day"),
        vl.y().fieldQ("Value"),
        vl.color().fieldN("CategoryLabel"),
        vl.xOffset().fieldN("CategoryLabel"),
        vl.tooltip()
          .fieldN("CategoryLabel", "Category")
          .fieldN("SubType", "Sample")
          .fieldQ("Value", "Cell Count")
      )
  )
  .width(600)
  .height(400);

// 渲染到指定DOM元素
chart.render('#vis');

关键修改说明

  1. 数据结构优化:两次fold操作将嵌套数据展开为扁平结构,每个条目包含分类、数据类型(样本/中位数)和对应数值,避免生成笛卡尔积。
  2. 精准过滤:对柱状图和散点图分别设置过滤条件,确保仅显示对应类型的数据。
  3. 可读性优化:将RAMOS_PBMC转换为RAMOS PBMC,提升图表标签可读性。
  4. API语法对齐:使用Vega-Lite API的链式调用语法,符合TypeScript项目的编码习惯。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 04:59:51