Multiscale Composition¶
multiscale is a convenience macro for semantic zooming. It expands to a
layer composition with generated zoom-driven
opacity transitions between child
views.
Example¶
{
"description": "A three-stage semantic zoom using the multiscale composition operator.",
"view": { "stroke": "lightgray" },
"resolve": { "scale": { "x": "shared" } },
"encoding": {
"x": {
"field": "x",
"type": "quantitative",
"scale": { "zoom": true }
},
"y": {
"field": "y",
"type": "quantitative"
}
},
"stops": [1, 0.1],
"multiscale": [
{
"data": { "values": [{}] },
"mark": {
"type": "text",
"text": "Zoom in to see details",
"size": 16
},
"encoding": {
"x": { "value": 0.5 },
"y": { "value": 0.5 },
"color": { "value": "#666666" }
}
},
{
"data": {
"sequence": { "start": 0, "stop": 4000, "step": 16, "as": "x" }
},
"transform": [
{
"type": "formula",
"expr": "sin(datum.x / 40)",
"as": "y"
},
{
"type": "formula",
"expr": "datum.x + 16",
"as": "x2"
}
],
"mark": "rect",
"encoding": {
"x2": { "field": "x2" }
}
},
{
"data": {
"sequence": { "start": 0, "stop": 4000, "step": 1, "as": "x" }
},
"transform": [
{
"type": "formula",
"expr": "sin(datum.x / 40) + (random() - 0.5) * 0.2",
"as": "y"
}
],
"mark": "point",
"encoding": {
"opacity": { "value": 0.7 }
}
}
]
}
How It Works¶
multiscale children are ordered from zoomed-out to zoomed-in. For N child
views, stops must contain N - 1 values.
At compile time, multiscale is expanded into a regular
layer: each child is wrapped with generated opacity ramps
that cross-fade adjacent levels. Normal layer behavior still applies
(inherited encodings/data, scale resolution, and opacity multiplication with
manually specified child opacity).
By default, channel selection is automatic:
- If both
xandyare available, the zoom metric is averaged. - If only one is available, that one is used.
- Scales that are not visible at the
multiscalescope (for example, independent descendant-local scales) are ignored.
For manual opacity control patterns, see
layer zoom-driven opacity.
Schematic Two-Level Cross-Fade Example¶
This mirrors the
layer cross-fading overview/detail example.
{
"stops": [40000],
"multiscale": [
{
"name": "Overview",
"mark": "rect"
},
{
"name": "Detail",
"mark": "point"
}
]
}
Properties¶
All other properties follow layer view semantics.
stopsRequired-
Type: (number | ExprRef)[] | MultiscaleStops
Stop definition that controls transitions between the multiscale levels.
number[]is shorthand for{ metric: "unitsPerPixel", values: ... }(number | ExprRef)[]supports mixed constants and expressions- Object form allows configuring metric, channel, and fade.
MultiscaleStops¶
channel-
Type:
"x"|"y"|"auto"Which positional channel controls the stop metric.
"auto"averagesxandywhen both are available."x"uses only thexchannel."y"uses only theychannel.
Default value:
"auto" fade-
Type: number
Relative transition width around each stop.
For each stop value
s, the fade transition is evaluated in the range:- upper edge:
s * (1 + fade) - lower edge:
s * (1 - fade)
Default value:
0.5 - upper edge:
valuesRequired-
Type: array
Stop values in descending order.
Array shorthand:
{
"stops": [1, 0.1]
}
is equivalent to:
{
"stops": {
"metric": "unitsPerPixel",
"values": [1, 0.1]
}
}
Expression shorthands are also supported:
{
"stops": [
2000,
{ "expr": "windowSize / max(width, 1)" },
{ "expr": "0.2 * windowSize / max(width, 1)" }
]
}
unitsPerPixel means data-units per screen pixel. On genomic axes, this is
typically base pairs per pixel.