View Concatenation¶
The vconcat
and hconcat
composition operators place views side-by-side
either vertically or horizontally. The vconcat
is practical for building
genomic visualizations with multiple tracks. The concat
operator with the
columns
property produces a wrapping grid layout.
The spacing (in pixels) between concatenated views can be adjusted using the
spacing
property (Default: 10
).
Example¶
Vertical¶
Using vconcat
for a vertical layout.
{
"data": { "url": "sincos.csv" },
"spacing": 20,
"vconcat": [
{
"mark": "point",
"encoding": {
"x": { "field": "x", "type": "quantitative" },
"y": { "field": "sin", "type": "quantitative" }
}
},
{
"mark": "point",
"encoding": {
"x": { "field": "x", "type": "quantitative" },
"y": { "field": "cos", "type": "quantitative" }
}
}
]
}
Horizontal¶
Using hconcat
for a horizontal layout.
{
"data": { "url": "sincos.csv" },
"hconcat": [
{
"mark": "point",
"encoding": {
"x": { "field": "x", "type": "quantitative" },
"y": { "field": "sin", "type": "quantitative" }
}
},
{
"mark": "point",
"encoding": {
"x": { "field": "x", "type": "quantitative" },
"y": { "field": "cos", "type": "quantitative" }
}
}
]
}
Grid¶
Using concat
and columns
for a grid layout. For simplicity, the same
visualization is used for all panels in the grid.
{
"data": { "url": "sincos.csv" },
"encoding": {
"x": { "field": "x", "type": "quantitative" },
"y": { "field": "sin", "type": "quantitative" }
},
"columns": 3,
"concat": [
{ "mark": "point" },
{ "mark": "point" },
{ "mark": "point" },
{ "mark": "point" },
{ "mark": "point" },
{ "mark": "point" },
{ "mark": "point" },
{ "mark": "point" },
{ "mark": "point" }
]
}
Child sizing¶
The concatenation operators mimic the behavior of the CSS
flexbox. The child
views have an absolute minimum size (px
) in pixels and an unitless grow
value that specifies in what proportion the possible remaining space should be
distributed. The remaining space depends on the parent view's size.
In the following example, the left view has a width of 20
px, the center view
has a grow of 1
, and the right view has a grow of 2
. If you resize the web
browser, you can observe that the width of the left view stays constant while
the remaining space is distributed in proportions of 1:2.
{
"data": { "values": [{}] },
"spacing": 10,
"hconcat": [
{
"width": { "px": 20 },
"mark": "rect"
},
{
"width": { "grow": 1 },
"mark": "rect"
},
{
"width": { "grow": 2 },
"mark": "rect"
}
]
}
SizeDef¶
grow
-
Type: number
Share of the remaining space. See child sizing for details.
px
-
Type: number
Size in pixels
The size may have both absolute (px
) and proportional (grow
) components.
When views are nested, both the absolute and proportional sizes are added up.
Thus, the width of the above example is { "px": 40, "grow": 3 }
. The spacing
between the child views is added to the total absolute width.
Views' size properties (width
and height
) accept both SizeDef objects and
shorthands. The SizeDef objects contain either or both of px
and grow
properties. Numbers are interpreted as as absolute sizes, and "container"
is
the same as { grow: 1 }
. Undefined sizes generally default to "container"
.
Concatenation operators can nested flexibly to build complex layouts as in the following example.
{
"data": { "values": [{}] },
"hconcat": [
{ "mark": "rect" },
{
"vconcat": [{ "mark": "rect" }, { "mark": "rect" }]
}
]
}
Scrollable viewports¶
Sometimes the concents of a view are so large that they do not fit into the
available space. In such cases, the view can be made scrollable by setting an
explicit size for the view using the viewportWidth
and viewportHeight
properties. They accept the same values as width
and height
properties except
for the step size. Scrollable viewports are particularly useful for categorical
data types ("ordinal"
and "nominal"
) and respective scales and axes that
do not support zooming and panning.
{
"height": { "step": 20 },
"viewportHeight": "container",
"view": { "stroke": "lightgray" },
"data": { "sequence": { "start": 0, "stop": 31, "step": 1 } },
"encoding": {
"x": { "field": "data", "type": "quantitative" },
"y": { "field": "data", "type": "ordinal" }
},
"mark": { "type": "point" }
}
Resolve¶
By default, all channels have "independent"
scales and axes. However, because
track-based layouts that resemble genome browsers are such a common use case,
vconcat
defaults to "shared"
resolution for x
channel and hconcat
defaults to "shared"
resolution for y
channel.
Shared axes¶
Concatenation operators support shared axes on channels that also have shared scales. Axis domain line, ticks, and labels are drawn only once for each row or column. Grid lines are drawn for all participating views.
{
"data": { "url": "sincos.csv" },
"resolve": {
"scale": { "x": "shared", "y": "shared" },
"axis": { "x": "shared", "y": "shared" }
},
"spacing": 20,
"encoding": {
"x": { "field": "x", "type": "quantitative", "axis": { "grid": true } },
"y": { "field": "sin", "type": "quantitative", "axis": { "grid": true } }
},
"columns": 2,
"concat": [
{ "mark": "point", "view": { "stroke": "lightgray" } },
{ "mark": "point", "view": { "stroke": "lightgray" } },
{ "mark": "point", "view": { "stroke": "lightgray" } },
{ "mark": "point", "view": { "stroke": "lightgray" } }
]
}