0
# Chart Composition
1
2
Functions for combining multiple charts through layering, concatenation, faceting, and repetition to create complex multi-view visualizations. Chart composition enables building sophisticated dashboards and analytical displays from simpler chart components.
3
4
## Capabilities
5
6
### Layering
7
8
Functions for overlaying multiple charts with different marks or encodings on the same coordinate system.
9
10
```python { .api }
11
def layer(*charts, **kwargs):
12
"""
13
Layer multiple charts on top of each other.
14
15
Parameters:
16
- *charts: Variable number of Chart objects to layer
17
- **kwargs: Additional layer properties (resolve, etc.)
18
19
Returns:
20
LayerChart: Layered chart specification
21
"""
22
23
class LayerChart:
24
def __init__(self, layer=None, **kwargs):
25
"""
26
Chart with multiple layered mark specifications.
27
28
Parameters:
29
- layer: List of layer specifications
30
"""
31
32
def resolve_axis(self, **kwargs):
33
"""Resolve axis sharing across layers."""
34
35
def resolve_legend(self, **kwargs):
36
"""Resolve legend sharing across layers."""
37
38
def resolve_scale(self, **kwargs):
39
"""Resolve scale sharing across layers."""
40
```
41
42
### Concatenation
43
44
Functions for arranging charts side-by-side or in grids without sharing coordinate systems.
45
46
```python { .api }
47
def concat(*charts, columns=None, spacing=None, **kwargs):
48
"""
49
Concatenate charts in a flexible layout.
50
51
Parameters:
52
- *charts: Variable number of Chart objects
53
- columns: Number of columns for grid layout
54
- spacing: Spacing between charts
55
56
Returns:
57
ConcatChart: Concatenated chart specification
58
"""
59
60
def hconcat(*charts, spacing=None, **kwargs):
61
"""
62
Horizontally concatenate charts.
63
64
Parameters:
65
- *charts: Variable number of Chart objects
66
- spacing: Horizontal spacing between charts
67
68
Returns:
69
HConcatChart: Horizontally concatenated chart
70
"""
71
72
def vconcat(*charts, spacing=None, **kwargs):
73
"""
74
Vertically concatenate charts.
75
76
Parameters:
77
- *charts: Variable number of Chart objects
78
- spacing: Vertical spacing between charts
79
80
Returns:
81
VConcatChart: Vertically concatenated chart
82
"""
83
84
class ConcatChart:
85
def __init__(self, concat=None, columns=None, **kwargs):
86
"""General concatenated chart layout."""
87
88
class HConcatChart:
89
def __init__(self, hconcat=None, **kwargs):
90
"""Horizontally concatenated chart layout."""
91
92
class VConcatChart:
93
def __init__(self, vconcat=None, **kwargs):
94
"""Vertically concatenated chart layout."""
95
```
96
97
### Faceting
98
99
Functions for creating small multiples based on data dimensions.
100
101
```python { .api }
102
def facet(
103
chart,
104
facet=None,
105
columns=None,
106
spacing=None,
107
**kwargs
108
):
109
"""
110
Create faceted chart with small multiples.
111
112
Parameters:
113
- chart: Base chart specification
114
- facet: Faceting field specification
115
- columns: Number of columns in facet grid
116
- spacing: Spacing between facet panels
117
118
Returns:
119
FacetChart: Faceted chart specification
120
"""
121
122
class FacetChart:
123
def __init__(self, facet=None, spec=None, **kwargs):
124
"""
125
Chart with faceted small multiples.
126
127
Parameters:
128
- facet: Facet field specification
129
- spec: Base chart specification for each panel
130
"""
131
```
132
133
### Repetition
134
135
Functions for repeating chart specifications with different field mappings.
136
137
```python { .api }
138
def repeat(
139
chart=None,
140
repeat=None,
141
columns=None,
142
**kwargs
143
):
144
"""
145
Repeat chart specification with different field mappings.
146
147
Parameters:
148
- chart: Base chart template
149
- repeat: Repeat specification (row/column field lists)
150
- columns: Number of columns for repeat grid
151
152
Returns:
153
RepeatChart: Repeated chart specification
154
"""
155
156
class RepeatChart:
157
def __init__(self, repeat=None, spec=None, **kwargs):
158
"""
159
Chart with repeated specifications.
160
161
Parameters:
162
- repeat: Repeat field mappings
163
- spec: Template chart specification
164
"""
165
```
166
167
### Resolution Control
168
169
Classes and methods for controlling how scales, axes, and legends are shared across composed charts.
170
171
```python { .api }
172
class Resolve:
173
def __init__(self, axis=None, legend=None, scale=None):
174
"""
175
Resolution specification for composed charts.
176
177
Parameters:
178
- axis: Axis resolution configuration
179
- legend: Legend resolution configuration
180
- scale: Scale resolution configuration
181
"""
182
183
class AxisResolveMap:
184
def __init__(self, x=None, y=None, **kwargs):
185
"""Axis resolution for specific encodings."""
186
187
class LegendResolveMap:
188
def __init__(self, color=None, size=None, shape=None, **kwargs):
189
"""Legend resolution for specific encodings."""
190
191
class ScaleResolveMap:
192
def __init__(self, x=None, y=None, color=None, size=None, **kwargs):
193
"""Scale resolution for specific encodings."""
194
195
# Resolution modes
196
ResolveMode = Union['independent', 'shared']
197
```
198
199
## Usage Examples
200
201
### Basic Layering
202
203
```python
204
import altair as alt
205
206
# Layer line and points
207
line = alt.Chart(data).mark_line().encode(
208
x='x:Q',
209
y='mean(y):Q'
210
)
211
212
points = alt.Chart(data).mark_circle().encode(
213
x='x:Q',
214
y='y:Q',
215
color='category:N'
216
)
217
218
layered = alt.layer(line, points).resolve_scale(
219
color='independent'
220
)
221
```
222
223
### Horizontal Concatenation
224
225
```python
226
# Side-by-side charts
227
chart1 = alt.Chart(data).mark_bar().encode(
228
x='category:N',
229
y='count():Q'
230
)
231
232
chart2 = alt.Chart(data).mark_point().encode(
233
x='x:Q',
234
y='y:Q',
235
color='category:N'
236
)
237
238
combined = alt.hconcat(chart1, chart2, spacing=20)
239
```
240
241
### Vertical Concatenation
242
243
```python
244
# Stacked charts
245
top_chart = alt.Chart(data).mark_line().encode(
246
x='date:T',
247
y='value:Q'
248
).properties(height=200)
249
250
bottom_chart = alt.Chart(data).mark_bar().encode(
251
x='date:T',
252
y='volume:Q'
253
).properties(height=100)
254
255
stacked = alt.vconcat(top_chart, bottom_chart)
256
```
257
258
### Grid Layout with Concat
259
260
```python
261
# 2x2 grid of charts
262
chart1 = alt.Chart(data).mark_point().encode(x='a:Q', y='b:Q')
263
chart2 = alt.Chart(data).mark_point().encode(x='c:Q', y='d:Q')
264
chart3 = alt.Chart(data).mark_bar().encode(x='category:N', y='count():Q')
265
chart4 = alt.Chart(data).mark_line().encode(x='date:T', y='value:Q')
266
267
grid = alt.concat(
268
chart1, chart2, chart3, chart4,
269
columns=2,
270
spacing=10
271
)
272
```
273
274
### Faceted Small Multiples
275
276
```python
277
# Facet by category
278
base = alt.Chart(data).mark_point().encode(
279
x='x:Q',
280
y='y:Q'
281
)
282
283
faceted = base.facet(
284
column=alt.Column('category:N', header=alt.Header(title='Category')),
285
columns=3
286
)
287
288
# Facet with both row and column
289
faceted_2d = base.facet(
290
column=alt.Column('category:N'),
291
row=alt.Row('type:N'),
292
spacing=10
293
)
294
```
295
296
### Repeat Chart
297
298
```python
299
# Scatterplot matrix
300
scatter_matrix = alt.Chart(data).mark_circle().encode(
301
x=alt.X(alt.repeat('column'), type='quantitative'),
302
y=alt.Y(alt.repeat('row'), type='quantitative'),
303
color='species:N'
304
).properties(
305
width=150,
306
height=150
307
).repeat(
308
row=['petalLength', 'petalWidth'],
309
column=['sepalLength', 'sepalWidth']
310
)
311
```
312
313
### Complex Dashboard Layout
314
315
```python
316
# Multi-panel dashboard
317
base = alt.Chart(data)
318
319
# Time series
320
time_series = base.mark_line().encode(
321
x='date:T',
322
y='value:Q',
323
color='category:N'
324
).properties(width=400, height=200)
325
326
# Bar chart
327
bars = base.mark_bar().encode(
328
x='category:N',
329
y='mean(value):Q'
330
).properties(width=150, height=200)
331
332
# Scatter plot
333
scatter = base.mark_circle().encode(
334
x='x:Q',
335
y='y:Q',
336
size='value:Q',
337
color='category:N'
338
).properties(width=200, height=200)
339
340
# Histogram
341
hist = base.mark_bar().encode(
342
x=alt.X('value:Q', bin=True),
343
y='count()'
344
).properties(width=200, height=200)
345
346
# Compose dashboard
347
dashboard = alt.vconcat(
348
time_series,
349
alt.hconcat(bars, scatter, hist, spacing=10),
350
spacing=15
351
)
352
```
353
354
### Layered Chart with Brushing
355
356
```python
357
# Base chart with brush selection
358
brush = alt.selection_interval()
359
360
base = alt.Chart(data).add_selection(brush)
361
362
# Background points
363
background = base.mark_circle(
364
color='lightgray',
365
opacity=0.5
366
).encode(
367
x='x:Q',
368
y='y:Q'
369
)
370
371
# Highlighted points
372
highlighted = base.mark_circle().encode(
373
x='x:Q',
374
y='y:Q',
375
color=alt.condition(brush, 'category:N', alt.value('lightgray'))
376
)
377
378
# Regression line for selected data
379
regression = base.mark_line(
380
color='red',
381
size=3
382
).transform_filter(
383
brush
384
).transform_regression('y', 'x')
385
386
layered_interactive = alt.layer(
387
background, highlighted, regression
388
)
389
```
390
391
### Resolution Control
392
393
```python
394
# Independent scales for layered charts
395
chart1 = alt.Chart(data1).mark_bar().encode(
396
x='category:N',
397
y='value1:Q'
398
)
399
400
chart2 = alt.Chart(data2).mark_line().encode(
401
x='category:N',
402
y='value2:Q'
403
)
404
405
# Allow independent y-scales
406
layered = alt.layer(chart1, chart2).resolve_scale(
407
y='independent'
408
).resolve_axis(
409
y='independent'
410
)
411
412
# Shared color legend
413
multi_chart = alt.hconcat(
414
chart1, chart2
415
).resolve_legend(
416
color='shared'
417
)
418
```
419
420
## Types
421
422
```python { .api }
423
from typing import Union, List, Dict, Any, Optional
424
425
# Chart composition types
426
ComposedChart = Union[LayerChart, ConcatChart, HConcatChart, VConcatChart, FacetChart, RepeatChart]
427
428
# Layout specifications
429
LayoutAlign = Union['all', 'each', 'none']
430
Spacing = Union[int, Dict[str, int]]
431
432
# Repeat specifications
433
RepeatMapping = Dict[str, List[str]]
434
RepeatRef = Dict[str, str]
435
436
# Facet specifications
437
FacetMapping = Union[str, Dict[str, Any]]
438
FacetFieldDef = Dict[str, Any]
439
440
# Resolution specifications
441
ResolveMode = Union['independent', 'shared']
442
443
class ResolveConfig:
444
axis: Optional[Dict[str, ResolveMode]] = None
445
legend: Optional[Dict[str, ResolveMode]] = None
446
scale: Optional[Dict[str, ResolveMode]] = None
447
448
# Layout configuration
449
class CompositionConfig:
450
columns: Optional[int] = None
451
spacing: Optional[Spacing] = None
452
align: Optional[LayoutAlign] = None
453
bounds: Optional[Union['full', 'flush']] = None
454
center: Optional[bool] = None
455
```