0
# Layouts
1
2
Functions and classes for arranging multiple plots, widgets, and other components into complex layouts. The layout system enables creation of dashboards, multi-panel displays, and sophisticated interactive applications with precise control over component positioning and sizing.
3
4
## Capabilities
5
6
### Basic Layout Functions
7
8
Core functions for arranging components horizontally and vertically.
9
10
```python { .api }
11
def row(*children, **kwargs):
12
"""
13
Arrange plots/widgets horizontally in a row.
14
15
Parameters:
16
- children: Plot objects, widgets, or other layoutable components
17
- sizing_mode: 'fixed', 'stretch_width', 'stretch_height', 'stretch_both', 'scale_width', 'scale_height', 'scale_both'
18
- width: Total width in pixels (when sizing_mode='fixed')
19
- height: Total height in pixels (when sizing_mode='fixed')
20
- margin: Margin around the layout (int or tuple)
21
- spacing: Spacing between children in pixels
22
- css_classes: List of CSS class names
23
- name: Optional name for the layout
24
- tags: List of arbitrary values for user annotation
25
26
Returns:
27
Row: Layout object containing the arranged components
28
"""
29
30
def column(*children, **kwargs):
31
"""
32
Arrange plots/widgets vertically in a column.
33
34
Parameters:
35
- children: Plot objects, widgets, or other layoutable components
36
- sizing_mode: Layout sizing behavior
37
- width: Total width in pixels
38
- height: Total height in pixels
39
- margin: Margin around the layout
40
- spacing: Spacing between children in pixels
41
- css_classes: List of CSS class names
42
- name: Optional name for the layout
43
- tags: List of arbitrary values
44
45
Returns:
46
Column: Layout object containing the arranged components
47
"""
48
```
49
50
### Grid Layouts
51
52
Functions for creating grid-based arrangements of plots and components.
53
54
```python { .api }
55
def gridplot(children, sizing_mode='fixed', toolbar_location='above',
56
ncols=None, plot_width=None, plot_height=None,
57
toolbar_options=None, merge_tools=True, **kwargs):
58
"""
59
Create grid of plots with optional shared tools.
60
61
Parameters:
62
- children: 2D list/array of plot objects (None for empty cells)
63
- sizing_mode: Layout sizing behavior
64
- toolbar_location: 'above', 'below', 'left', 'right', None
65
- ncols: Number of columns (if children is 1D list)
66
- plot_width: Width for plots without explicit width
67
- plot_height: Height for plots without explicit height
68
- toolbar_options: Dict of toolbar configuration options
69
- merge_tools: Whether to merge plot tools into shared toolbar
70
71
Returns:
72
GridBox: Grid layout containing the plots
73
74
Example children format:
75
[[plot1, plot2], [plot3, None]] # 2x2 grid with empty bottom-right
76
"""
77
78
def grid(children, sizing_mode='fixed', **kwargs):
79
"""
80
Create flexible grid layout without plot-specific features.
81
82
Parameters:
83
- children: 2D list of any layoutable components
84
- sizing_mode: Layout sizing behavior
85
86
Returns:
87
GridBox: Grid layout containing the components
88
"""
89
```
90
91
### Advanced Layout Function
92
93
Function for creating complex nested layouts.
94
95
```python { .api }
96
def layout(children, sizing_mode='fixed', **kwargs):
97
"""
98
Create flexible nested layout from lists and tuples.
99
100
Parameters:
101
- children: Nested structure of lists/tuples containing components
102
Lists create columns, tuples create rows
103
- sizing_mode: Layout sizing behavior
104
105
Returns:
106
LayoutDOM: Appropriate layout object based on structure
107
108
Examples:
109
layout([plot1, plot2]) # Column of two plots
110
layout([[plot1, plot2]]) # Row of two plots
111
layout([plot1, [plot2, plot3]]) # plot1 above horizontal row
112
"""
113
```
114
115
### Layout Model Classes
116
117
Classes for programmatic layout construction and advanced configuration.
118
119
```python { .api }
120
class LayoutDOM(Model):
121
"""Base class for all layout components."""
122
width: Optional[int]
123
height: Optional[int]
124
min_width: Optional[int]
125
min_height: Optional[int]
126
max_width: Optional[int]
127
max_height: Optional[int]
128
margin: Margin # int or (top, right, bottom, left) tuple
129
width_policy: SizingPolicy # 'auto', 'min', 'fit', 'max'
130
height_policy: SizingPolicy
131
aspect_ratio: Optional[Union[float, str]] # float or 'auto'
132
sizing_mode: SizingMode
133
visible: bool
134
disabled: bool
135
css_classes: List[str]
136
name: Optional[str]
137
tags: List[Any]
138
139
class Row(LayoutDOM):
140
"""Horizontal arrangement of components."""
141
children: List[LayoutDOM]
142
spacing: int # Spacing between children in pixels
143
144
class Column(LayoutDOM):
145
"""Vertical arrangement of components."""
146
children: List[LayoutDOM]
147
spacing: int
148
149
class GridBox(LayoutDOM):
150
"""Grid arrangement of components."""
151
children: List[Tuple[LayoutDOM, int, int]] # (component, row, col)
152
nrows: int
153
ncols: int
154
spacing: Union[int, Tuple[int, int]] # (row_spacing, col_spacing)
155
156
class Spacer(LayoutDOM):
157
"""Empty space component for layouts."""
158
# Inherits all sizing properties from LayoutDOM
159
# Used to create flexible spacing in layouts
160
```
161
162
### Tabbed Layouts
163
164
Classes for creating tabbed interfaces.
165
166
```python { .api }
167
class Panel(Model):
168
"""Individual tab panel."""
169
child: LayoutDOM # Content of the tab
170
title: str # Tab title text
171
closable: bool # Whether tab can be closed
172
173
class Tabs(LayoutDOM):
174
"""Tabbed layout container."""
175
tabs: List[Panel]
176
active: int # Index of active tab
177
tabs_location: Location # 'above', 'below', 'left', 'right'
178
179
# Callback hooks
180
def on_change(self, attr, *callbacks): ...
181
```
182
183
## Usage Examples
184
185
### Basic Row and Column Layouts
186
187
```python
188
from bokeh.layouts import row, column
189
from bokeh.plotting import figure, show
190
import numpy as np
191
192
# Create some plots
193
x = np.linspace(0, 4*np.pi, 100)
194
195
p1 = figure(width=300, height=300, title="sin(x)")
196
p1.line(x, np.sin(x))
197
198
p2 = figure(width=300, height=300, title="cos(x)")
199
p2.line(x, np.cos(x), color='red')
200
201
p3 = figure(width=300, height=300, title="tan(x)")
202
p3.line(x, np.tan(x), color='green')
203
204
# Arrange in row
205
layout1 = row(p1, p2, p3)
206
207
# Arrange in column
208
layout2 = column(p1, p2, p3)
209
210
# Mixed arrangement
211
layout3 = column(
212
row(p1, p2), # Top row with two plots
213
p3 # Bottom plot spanning full width
214
)
215
216
show(layout3)
217
```
218
219
### Grid Layout
220
221
```python
222
from bokeh.layouts import gridplot
223
from bokeh.plotting import figure, show
224
import numpy as np
225
226
# Create 2x2 grid of plots
227
plots = []
228
for i in range(4):
229
p = figure(width=250, height=250, title=f"Plot {i+1}")
230
x = np.linspace(0, 4*np.pi, 50)
231
y = np.sin(x + i*np.pi/4)
232
p.line(x, y, line_width=2)
233
plots.append(p)
234
235
# Arrange in 2x2 grid
236
grid = gridplot([
237
[plots[0], plots[1]],
238
[plots[2], plots[3]]
239
], sizing_mode='stretch_width')
240
241
show(grid)
242
```
243
244
### Flexible Layout with Spacers
245
246
```python
247
from bokeh.layouts import column, row
248
from bokeh.models import Spacer
249
from bokeh.plotting import figure, show
250
251
p1 = figure(width=200, height=200)
252
p1.circle([1, 2, 3], [1, 2, 3])
253
254
p2 = figure(width=200, height=200)
255
p2.square([1, 2, 3], [3, 2, 1])
256
257
# Create layout with flexible spacing
258
layout = column(
259
p1,
260
Spacer(height=50), # Fixed 50px spacing
261
row(
262
Spacer(width_policy='max'), # Flexible left space
263
p2,
264
Spacer(width_policy='max') # Flexible right space (centers p2)
265
)
266
)
267
268
show(layout)
269
```
270
271
### Tabbed Interface
272
273
```python
274
from bokeh.models import Panel, Tabs
275
from bokeh.plotting import figure, show
276
import numpy as np
277
278
# Create plots for different tabs
279
tab1_plot = figure(width=400, height=400, title="Line Plot")
280
x = np.linspace(0, 4*np.pi, 100)
281
tab1_plot.line(x, np.sin(x))
282
283
tab2_plot = figure(width=400, height=400, title="Scatter Plot")
284
tab2_plot.scatter(np.random.random(50), np.random.random(50), size=10)
285
286
tab3_plot = figure(width=400, height=400, title="Bar Chart")
287
categories = ['A', 'B', 'C', 'D']
288
values = [1, 3, 2, 4]
289
tab3_plot.vbar(x=categories, top=values, width=0.5)
290
291
# Create tabs
292
tab1 = Panel(child=tab1_plot, title="Sine Wave")
293
tab2 = Panel(child=tab2_plot, title="Random Data")
294
tab3 = Panel(child=tab3_plot, title="Categories")
295
296
tabs = Tabs(tabs=[tab1, tab2, tab3])
297
298
show(tabs)
299
```
300
301
### Responsive Dashboard Layout
302
303
```python
304
from bokeh.layouts import column, row
305
from bokeh.plotting import figure, show
306
from bokeh.models import Div
307
import numpy as np
308
309
# Create title
310
title = Div(text="<h1>Sales Dashboard</h1>",
311
sizing_mode='stretch_width')
312
313
# Create plots with responsive sizing
314
p1 = figure(height=300, title="Revenue Trend",
315
sizing_mode='stretch_width')
316
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
317
revenue = [100, 120, 140, 110, 160, 180]
318
p1.line(range(len(months)), revenue, line_width=3)
319
p1.xaxis.ticker = list(range(len(months)))
320
p1.xaxis.major_label_overrides = dict(zip(range(len(months)), months))
321
322
p2 = figure(width=300, height=300, title="Regional Sales")
323
regions = ['North', 'South', 'East', 'West']
324
sales = [45, 30, 35, 25]
325
p2.vbar(x=regions, top=sales, width=0.5, color='navy')
326
327
p3 = figure(width=300, height=300, title="Customer Satisfaction")
328
satisfaction = np.random.normal(8.5, 1.2, 1000)
329
hist, edges = np.histogram(satisfaction, bins=20)
330
p3.quad(top=hist, bottom=0, left=edges[:-1], right=edges[1:],
331
fill_color='lightblue', line_color='black')
332
333
# Create responsive layout
334
dashboard = column(
335
title,
336
p1, # Full width trend chart
337
row(p2, p3, sizing_mode='stretch_width'), # Side-by-side bottom charts
338
sizing_mode='stretch_width'
339
)
340
341
show(dashboard)
342
```
343
344
### Programmatic Layout Construction
345
346
```python
347
from bokeh.models import Column, Row, GridBox
348
from bokeh.plotting import figure, show
349
350
# Create plots
351
plots = []
352
for i in range(6):
353
p = figure(width=200, height=200, title=f"Plot {i+1}")
354
p.circle([1, 2, 3], [i, i+1, i+2])
355
plots.append(p)
356
357
# Programmatically create complex layout
358
main_row = Row(children=[
359
Column(children=plots[0:3], spacing=10),
360
Column(children=plots[3:6], spacing=10)
361
], spacing=20)
362
363
# Alternative: Using GridBox for precise control
364
grid = GridBox(children=[
365
(plots[0], 0, 0), (plots[1], 0, 1), (plots[2], 0, 2),
366
(plots[3], 1, 0), (plots[4], 1, 1), (plots[5], 1, 2)
367
], nrows=2, ncols=3, spacing=15)
368
369
show(grid)
370
```