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

如何将Vega-Lite的Brush吸附到日期以实现过滤?

问题描述

我有一个text mark和两个垂直拼接的area mark。每个area mark都配置了brush参数,area 2的brush用来控制area 1的定义域。我想用选中的brush区域过滤text mark,但x轴是时间型,brush生成的是毫秒级区间,我需要按天单位进行brush操作。将timeUnit改为yearmonthdate后,过滤完全失效。

brushing individual days not working

如何让brush区间吸附到单个日期,同时保持原有的过滤功能?我已修改之前的代码,更改了timeUnit并过滤了单一年份,以便更易选中单个日期。

原代码如下:

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "data": {"url": "data/sp500.csv"},
  "transform": [
    {
      "filter": {"timeUnit": "year", "field": "date", "lte": "2000"}
    }
  ],
  "params": [
    {"name": "a", "expr": "brush1.date?true:false"},
    {"name": "b", "expr": "brush2.date?true:false"},
    
  ],
  "vconcat": [
    {
      "title": "text mark:",
      "width": 480,
      "mark": "text",
      "transform": [
         {"extent": "date", "param": "c"},
        {
          "joinaggregate": [
            {"op": "min", "field": "date", "as": "min_date"},
            {"op": "max", "field": "date", "as": "max_date"}
          ]
        },
        {
          "calculate": "a?brush1.date[0]:b?brush2.date[0]:datum.min_date",
          "as": "min_date"
        },
        {
          "calculate": "a?brush1.date[1]:b?brush2.date[1]:datum.max_date",
          "as": "max_date"
        },
        {
          "filter": "datum.date >= datum.min_date & datum.date <= datum.max_date"
        }
      ],
      "encoding": {
        "text": {
          "value": {
            "expr": "timeFormat(a?brush1.date[0]:b?brush2.date[0]:c[0], '%d %b %Y') + ' to ' + timeFormat(a?brush1.date[1]:b?brush2.date[1]:c[1], '%d %b %Y')"
          }
        }
      }
    },
    {
      "title": "area mark 1:",
      "width": 480,
      "mark": "area",
      "params": [
        {"name": "brush1", "select": {"type": "interval", "encodings": ["x"]}}
      ],
      "encoding": {
        "x": {
          "field": "date",
          "type": "temporal",
          "timeUnit": "yearmonthdate",
          "scale": {"domain": {"param": "brush2"}},
          "axis": {"title": ""}
        },
        "y": {"field": "price", "type": "quantitative"}
      }
    },
    {
      "title": "area mark 2:",
      "width": 480,
      "height": 60,
      "mark": "area",
      "params": [
        {"name": "brush2", "select": {"type": "interval", "encodings": ["x"]}}
      ],
      "encoding": {
        "x": {"field": "date", "type": "temporal", "timeUnit": "yearmonthdate"},
        "y": {
          "field": "price",
          "type": "quantitative",
          "axis": {"tickCount": 3, "grid": false}
        }
      }
    }
  ]
}
解决方案

核心是统一时间字段的处理逻辑,让brush生成的区间和数据过滤使用相同的时间单位对齐,具体修改步骤如下:

  1. 让brush按日期单位吸附
    在两个brush的select配置中添加timeUnit: 'yearmonthdate'和resolve: 'global',强制brush区间自动对齐到天级单位:

    // 以brush1为例,brush2做相同修改
    {
      "name": "brush1",
      "select": {
        "type": "interval",
        "encodings": ["x"],
        "resolve": "global",
        "timeUnit": "yearmonthdate"
      }
    }
    
  2. 修正过滤逻辑的时间比较
    原代码中直接用原始毫秒级date和brush区间比较,导致不匹配。需要把两边的时间都转换为yearmonthdate单位后再比较,修改text mark的filter表达式:

    {
      "filter": "timeUnit('yearmonthdate', datum.date) >= timeUnit('yearmonthdate', datum.min_date) && timeUnit('yearmonthdate', datum.date) <= timeUnit('yearmonthdate', datum.max_date)"
    }
    
  3. 简化冗余参数
    删掉原代码中params里的a、b参数,直接在计算表达式中判断brush是否存在区间,减少冗余:

    {
      "calculate": "brush1.date ? brush1.date[0] : brush2.date ? brush2.date[0] : datum.min_date",
      "as": "min_date"
    }
    

完整修改后的代码

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "data": {"url": "data/sp500.csv"},
  "transform": [
    {
      "filter": {"timeUnit": "year", "field": "date", "lte": "2000"}
    }
  ],
  "vconcat": [
    {
      "title": "text mark:",
      "width": 480,
      "mark": "text",
      "transform": [
        {"extent": "date", "param": "c"},
        {
          "joinaggregate": [
            {"op": "min", "field": "date", "as": "min_date"},
            {"op": "max", "field": "date", "as": "max_date"}
          ]
        },
        {
          "calculate": "brush1.date ? brush1.date[0] : brush2.date ? brush2.date[0] : datum.min_date",
          "as": "min_date"
        },
        {
          "calculate": "brush1.date ? brush1.date[1] : brush2.date ? brush2.date[1] : datum.max_date",
          "as": "max_date"
        },
        {
          "filter": "timeUnit('yearmonthdate', datum.date) >= timeUnit('yearmonthdate', datum.min_date) && timeUnit('yearmonthdate', datum.date) <= timeUnit('yearmonthdate', datum.max_date)"
        }
      ],
      "encoding": {
        "text": {
          "value": {
            "expr": "timeFormat(brush1.date ? brush1.date[0] : brush2.date ? brush2.date[0] : c[0], '%d %b %Y') + ' to ' + timeFormat(brush1.date ? brush1.date[1] : brush2.date ? brush2.date[1] : c[1], '%d %b %Y')"
          }
        }
      }
    },
    {
      "title": "area mark 1:",
      "width": 480,
      "mark": "area",
      "params": [
        {
          "name": "brush1",
          "select": {
            "type": "interval",
            "encodings": ["x"],
            "resolve": "global",
            "timeUnit": "yearmonthdate"
          }
        }
      ],
      "encoding": {
        "x": {
          "field": "date",
          "type": "temporal",
          "timeUnit": "yearmonthdate",
          "scale": {"domain": {"param": "brush2"}},
          "axis": {"title": ""}
        },
        "y": {"field": "price", "type": "quantitative"}
      }
    },
    {
      "title": "area mark 2:",
      "width": 480,
      "height": 60,
      "mark": "area",
      "params": [
        {
          "name": "brush2",
          "select": {
            "type": "interval",
            "encodings": ["x"],
            "resolve": "global",
            "timeUnit": "yearmonthdate"
          }
        }
      ],
      "encoding": {
        "x": {"field": "date", "type": "temporal", "timeUnit": "yearmonthdate"},
        "y": {
          "field": "price",
          "type": "quantitative",
          "axis": {"tickCount": 3, "grid": false}
        }
      }
    }
  ]
}

内容的提问来源于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:42:10