I have two area marks in Vega (based on this), brushing the bottom chart zooms the top chart, and when zoomed in a lot it shows hours:
I’ve asked how to show days as the minimum unit here. Here I’d like to know how to set up the brush signal so that the brushed area snaps to multiples of a week. That way the top chart will only show a minimum of 7 days, then 14, etc.
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"description": "Area charts of stock prices, with an interactive overview and filtered detail views.",
"width": 720,
"height": 480,
"padding": 5,
"data": [
{
"name": "sp500",
"url": "data/sp500.csv",
"format": {"type": "csv", "parse": {"price": "number", "date": "date"}},
"transform": [{"type": "filter", "expr": "datum.date < 957103200000"}]
}
],
"signals": [{"name": "detailDomain"}],
"marks": [
{
"type": "group",
"name": "detail",
"encode": {"enter": {"width": {"value": 720}, "height": {"value": 390}}},
"scales": [
{
"name": "xDetail",
"type": "time",
"range": "width",
"domain": {"data": "sp500", "field": "date"},
"domainRaw": {"signal": "detailDomain"}
},
{
"name": "yDetail",
"type": "linear",
"range": [390, 0],
"domain": {"data": "sp500", "field": "price"},
"nice": true,
"zero": true
}
],
"axes": [
{"orient": "bottom", "scale": "xDetail"},
{"orient": "left", "scale": "yDetail"}
],
"marks": [
{
"type": "group",
"encode": {
"enter": {
"height": {"field": {"group": "height"}},
"width": {"field": {"group": "width"}},
"clip": {"value": true}
}
},
"marks": [
{
"type": "area",
"from": {"data": "sp500"},
"encode": {
"update": {
"x": {"scale": "xDetail", "field": "date"},
"y": {"scale": "yDetail", "field": "price"},
"y2": {"scale": "yDetail", "value": 0},
"fill": {"value": "steelblue"}
}
}
}
]
}
]
},
{
"type": "group",
"name": "overview",
"encode": {
"enter": {
"x": {"value": 0},
"y": {"value": 430},
"height": {"value": 70},
"width": {"value": 720},
"fill": {"value": "transparent"}
}
},
"signals": [
{
"name": "brush",
"value": 0,
"on": [
{"events": "@overview:pointerdown", "update": "[x(), x()]"},
{
"events": "[@overview:pointerdown, window:pointerup] > window:pointermove!",
"update": "[brush[0], clamp(x(), 0, width)]"
},
{
"events": {"signal": "delta"},
"update": "clampRange([anchor[0] + delta, anchor[1] + delta], 0, width)"
}
]
},
{
"name": "anchor",
"value": null,
"on": [{"events": "@brush:pointerdown", "update": "slice(brush)"}]
},
{
"name": "xdown",
"value": 0,
"on": [{"events": "@brush:pointerdown", "update": "x()"}]
},
{
"name": "delta",
"value": 0,
"on": [
{
"events": "[@brush:pointerdown, window:pointerup] > window:pointermove!",
"update": "x() - xdown"
}
]
},
{
"name": "detailDomain",
"push": "outer",
"on": [
{
"events": {"signal": "brush"},
"update": "span(brush) ? invert('xOverview', brush) : null"
}
]
}
],
"scales": [
{
"name": "xOverview",
"type": "time",
"range": "width",
"domain": {"data": "sp500", "field": "date"}
},
{
"name": "yOverview",
"type": "linear",
"range": [70, 0],
"domain": {"data": "sp500", "field": "price"},
"nice": true,
"zero": true
}
],
"axes": [{"orient": "bottom", "scale": "xOverview"}],
"marks": [
{
"type": "area",
"interactive": false,
"from": {"data": "sp500"},
"encode": {
"update": {
"x": {"scale": "xOverview", "field": "date"},
"y": {"scale": "yOverview", "field": "price"},
"y2": {"scale": "yOverview", "value": 0},
"fill": {"value": "steelblue"}
}
}
},
{
"type": "rect",
"name": "brush",
"encode": {
"enter": {
"y": {"value": 0},
"height": {"value": 70},
"fill": {"value": "#333"},
"fillOpacity": {"value": 0.2}
},
"update": {
"x": {"signal": "brush[0]"},
"x2": {"signal": "brush[1]"}
}
}
},
{
"type": "rect",
"interactive": false,
"encode": {
"enter": {
"y": {"value": 0},
"height": {"value": 70},
"width": {"value": 1},
"fill": {"value": "firebrick"}
},
"update": {"x": {"signal": "brush[0]"}}
}
},
{
"type": "rect",
"interactive": false,
"encode": {
"enter": {
"y": {"value": 0},
"height": {"value": 70},
"width": {"value": 1},
"fill": {"value": "firebrick"}
},
"update": {"x": {"signal": "brush[1]"}}
}
}
]
}
]
}