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

如何实现基于二元值分段的固定高度折线图(带间隙)

解决Vega-Lite固定y值折线的二元值分段显示问题

问题描述

我有一个固定y值的line标记,希望基于取值为0和1的二元值实现分段显示。以Vega-Lite官方示例为基础,红色折线的显示依赖于判断价格是否超过400的布尔值high_price。尝试通过将opacity绑定high_price来实现,但2006年左侧效果不佳(透明度未完全为0),且2006年后high_price变化时折线始终保持透明度1。请问如何实现当high_price为0时折线完全不可见,为1时完全显示的效果?

原代码如下:

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "description": "Google's stock price over time.",
  "data": {"url": "data/stocks.csv"},
  "transform": [{"filter": "datum.symbol==='GOOG'"}],
  "encoding": {
    "x": {"field": "date", "type": "temporal"}
  },
  "layer": [{
  "mark": "area",
  "encoding": {
    "y": {"field": "price", "type": "quantitative"}
  }
  },
  {
    "transform": [
      {
        "calculate": "datum.price > 400 ? 1 : 0",
        "as": "high_price"
      }
    ],
    "mark": {"type": "line", "size": 5},
    "encoding": {
      "y": {
        "value": 201
      },
      "opacity": {
        "legend": null,
        "field": "high_price",
        "type": "quantitative"
      },
      "color": {"value": "red"}
    }
  }]
}

解决方案

问题出在直接给line标记绑定量化类型的opacity字段:折线会强制连接所有数据点,哪怕部分点透明度为0,相邻点之间的线段还是会产生半透明过渡,导致无法完全隐藏。要实现彻底的分段显示,需要通过数据过滤+边界补点的方式,让折线只在high_price为1的区间连续绘制。

修改后的完整代码

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "description": "Google's stock price over time with segmented red line.",
  "data": {"url": "data/stocks.csv"},
  "transform": [{"filter": "datum.symbol==='GOOG'"}],
  "encoding": {
    "x": {"field": "date", "type": "temporal"}
  },
  "layer": [
    {
      "mark": "area",
      "encoding": {
        "y": {"field": "price", "type": "quantitative"}
      }
    },
    {
      "transform": [
        // 计算high_price布尔值
        {"calculate": "datum.price > 400 ? 1 : 0", "as": "high_price"},
        // 获取前一个数据点的high_price,用于判断状态切换边界
        {"window": [{"field": "high_price", "op": "lag", "as": "prev_high"}]},
        // 标记是否处于状态切换的边界点
        {"calculate": "isValid(datum.prev_high) && datum.high_price !== datum.prev_high ? 1 : 0", "as": "is_boundary"},
        // 生成边界过渡点:当状态切换时,复制前一个点并继承当前状态
        {"fold": ["original", "boundary"], "as": ["type", "dummy"]},
        {"calculate": "datum.type === 'boundary' && datum.is_boundary ? {date: datum.date, high_price: datum.prev_high} : datum", "as": "boundary_data"},
        {"flatten": ["boundary_data"]},
        // 提取补点后的日期和high_price字段
        {"calculate": "datum.boundary_data.high_price", "as": "high_price"},
        {"calculate": "datum.boundary_data.date", "as": "date"},
        // 只保留需要显示的high_price=1的点
        {"filter": "datum.high_price === 1"}
      ],
      "mark": {"type": "line", "size": 5},
      "encoding": {
        "y": {"value": 201},
        "color": {"value": "red"}
      }
    }
  ]
}

逻辑说明

  1. 边界判断:用window变换获取前一个数据点的high_price,识别出状态切换的临界点
  2. 补过渡点:在状态切换处生成复制点,确保折线在切换位置自然断开
  3. 过滤数据:只保留high_price为1的点,此时折线只会在符合条件的区间连续绘制,完全不会显示high_price为0的部分

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 21:56:11