0
# Faceting
1
2
Faceting creates multiple panels (subplots) to show different subsets of your data based on categorical variables. This powerful technique allows you to explore patterns across groups and compare distributions, trends, and relationships within different data segments. Plotnine provides flexible faceting functions that support both grid and wrap layouts.
3
4
## Capabilities
5
6
### Basic Faceting Functions
7
8
Core functions for creating multi-panel plots based on data groupings.
9
10
```python { .api }
11
def facet_null():
12
"""
13
No faceting (single panel).
14
15
This is the default faceting behavior - creates a single plot panel.
16
Useful for explicitly specifying no faceting when needed.
17
"""
18
19
def facet_wrap(facets, nrow=None, ncol=None, scales='fixed', shrink=True,
20
labeller='label_value', as_table=True, drop=True, dir='h'):
21
"""
22
Wrap 1D ribbon of panels into 2D layout.
23
24
Creates subplots arranged in a rectangular grid based on levels of
25
one or more variables.
26
27
Parameters:
28
- facets: str or list, variables to facet by (e.g., 'var' or ['var1', 'var2'])
29
- nrow: int, number of rows in grid
30
- ncol: int, number of columns in grid
31
- scales: str, whether scales are shared across panels
32
('fixed', 'free', 'free_x', 'free_y')
33
- shrink: bool, whether to shrink scales to fit data in each panel
34
- labeller: str or function, how to format facet labels
35
- as_table: bool, whether to fill panels like a table (top-to-bottom)
36
- drop: bool, whether to drop unused factor levels
37
- dir: str, direction to fill panels ('h' for horizontal, 'v' for vertical)
38
"""
39
40
def facet_grid(rows=None, cols=None, scales='fixed', shrink=True,
41
labeller='label_value', as_table=True, drop=True):
42
"""
43
Create 2D grid of panels based on row and column variables.
44
45
Creates a matrix of subplots where rows represent levels of one variable
46
and columns represent levels of another variable.
47
48
Parameters:
49
- rows: str or list, variable(s) for panel rows
50
- cols: str or list, variable(s) for panel columns
51
- scales: str, scale sharing ('fixed', 'free', 'free_x', 'free_y')
52
- shrink: bool, whether to shrink scales to fit data
53
- labeller: str or function, label formatting
54
- as_table: bool, whether to arrange like table (TRUE: top-to-bottom)
55
- drop: bool, whether to drop unused factor levels
56
"""
57
```
58
59
### Labelling Functions
60
61
Functions for controlling how facet labels are displayed and formatted.
62
63
```python { .api }
64
def labeller(**kwargs):
65
"""
66
Create custom labelling functions for facets.
67
68
Parameters:
69
- **kwargs: variable-specific labellers or general labelling options
70
71
Usage:
72
- labeller(variable=label_both) for specific variable
73
- labeller(.default=label_both) for all variables
74
"""
75
76
def as_labeller(x, default=None):
77
"""
78
Convert various objects to labeller functions.
79
80
Parameters:
81
- x: dict, function, or other object to convert
82
- default: default labeller if conversion fails
83
84
Usage:
85
- as_labeller({'A': 'Group A', 'B': 'Group B'})
86
- as_labeller(lambda x: f'Value: {x}')
87
"""
88
89
def label_value(x):
90
"""
91
Default labeller that shows variable values only.
92
93
Displays just the factor level (e.g., 'A', 'B', 'C').
94
"""
95
96
def label_both(x):
97
"""
98
Labeller that shows both variable names and values.
99
100
Displays variable name and value (e.g., 'group: A', 'group: B').
101
"""
102
103
def label_context(x):
104
"""
105
Context-aware labelling.
106
107
Chooses appropriate labelling based on the faceting context.
108
"""
109
```
110
111
## Usage Patterns
112
113
### Basic Facet Wrap
114
```python
115
# Facet by single variable
116
ggplot(data, aes(x='x', y='y')) + \
117
geom_point() + \
118
facet_wrap('category')
119
120
# Facet by multiple variables
121
ggplot(data, aes(x='x', y='y')) + \
122
geom_point() + \
123
facet_wrap(['category', 'group'])
124
125
# Control layout dimensions
126
ggplot(data, aes(x='x', y='y')) + \
127
geom_point() + \
128
facet_wrap('category', ncol=3)
129
```
130
131
### Facet Grid for Two Variables
132
```python
133
# Rows and columns for different variables
134
ggplot(data, aes(x='x', y='y')) + \
135
geom_point() + \
136
facet_grid(rows='treatment', cols='gender')
137
138
# Facet by rows only (creates vertical strip)
139
ggplot(data, aes(x='x', y='y')) + \
140
geom_point() + \
141
facet_grid(rows='category')
142
143
# Facet by columns only (creates horizontal strip)
144
ggplot(data, aes(x='x', y='y')) + \
145
geom_point() + \
146
facet_grid(cols='group')
147
```
148
149
### Scale Independence
150
```python
151
# Free scales for each panel
152
ggplot(data, aes(x='x', y='y')) + \
153
geom_point() + \
154
facet_wrap('category', scales='free')
155
156
# Free x-axis only
157
ggplot(data, aes(x='x', y='y')) + \
158
geom_point() + \
159
facet_wrap('category', scales='free_x')
160
161
# Free y-axis only
162
ggplot(data, aes(x='x', y='y')) + \
163
geom_point() + \
164
facet_wrap('category', scales='free_y')
165
166
# Fixed scales (default)
167
ggplot(data, aes(x='x', y='y')) + \
168
geom_point() + \
169
facet_wrap('category', scales='fixed')
170
```
171
172
### Custom Labels
173
```python
174
# Custom label dictionary
175
label_dict = {'A': 'Treatment A', 'B': 'Treatment B', 'C': 'Control'}
176
177
ggplot(data, aes(x='x', y='y')) + \
178
geom_point() + \
179
facet_wrap('treatment', labeller=as_labeller(label_dict))
180
181
# Show both variable name and value
182
ggplot(data, aes(x='x', y='y')) + \
183
geom_point() + \
184
facet_wrap('category', labeller=label_both)
185
186
# Custom labeller function
187
def custom_labeller(x):
188
return f'Group {x} Data'
189
190
ggplot(data, aes(x='x', y='y')) + \
191
geom_point() + \
192
facet_wrap('group', labeller=as_labeller(custom_labeller))
193
```
194
195
### Complex Faceting Examples
196
```python
197
# Multiple variables with custom layout
198
ggplot(data, aes(x='value', fill='category')) + \
199
geom_histogram(bins=20) + \
200
facet_wrap(['region', 'year'], ncol=4, scales='free_y') + \
201
theme(strip_text=element_text(size=8))
202
203
# Grid with different aspects
204
ggplot(data, aes(x='date', y='sales')) + \
205
geom_line() + \
206
facet_grid(rows='product', cols='quarter', scales='free') + \
207
theme(axis_text_x=element_text(angle=45))
208
209
# Time series by group
210
ggplot(time_data, aes(x='date', y='value', color='metric')) + \
211
geom_line() + \
212
facet_wrap('country', scales='free_y', ncol=3) + \
213
theme_minimal() + \
214
theme(legend_position='bottom')
215
```
216
217
### Combining with Other Grammar Elements
218
```python
219
# Faceted plot with smoothing
220
ggplot(data, aes(x='x', y='y', color='treatment')) + \
221
geom_point(alpha=0.6) + \
222
geom_smooth(method='lm', se=False) + \
223
facet_wrap('site', scales='free') + \
224
scale_color_brewer(type='qual') + \
225
theme_bw()
226
227
# Box plots across multiple grouping variables
228
ggplot(data, aes(x='treatment', y='response', fill='treatment')) + \
229
geom_boxplot() + \
230
facet_grid(rows='timepoint', cols='gender') + \
231
scale_fill_manual(values=['lightblue', 'lightcoral']) + \
232
theme(legend_position='none')
233
```
234
235
### Handling Missing Combinations
236
```python
237
# Drop unused factor levels (default)
238
ggplot(data, aes(x='x', y='y')) + \
239
geom_point() + \
240
facet_wrap('category', drop=True)
241
242
# Keep unused factor levels (creates empty panels)
243
ggplot(data, aes(x='x', y='y')) + \
244
geom_point() + \
245
facet_wrap('category', drop=False)
246
```
247
248
### Layout Direction Control
249
```python
250
# Fill panels horizontally (default)
251
ggplot(data, aes(x='x', y='y')) + \
252
geom_point() + \
253
facet_wrap('category', nrow=2, dir='h')
254
255
# Fill panels vertically
256
ggplot(data, aes(x='x', y='y')) + \
257
geom_point() + \
258
facet_wrap('category', nrow=2, dir='v')
259
260
# Table-style layout (top-to-bottom, left-to-right)
261
ggplot(data, aes(x='x', y='y')) + \
262
geom_point() + \
263
facet_wrap('category', as_table=True)
264
265
# Non-table layout (bottom-to-top, left-to-right)
266
ggplot(data, aes(x='x', y='y')) + \
267
geom_point() + \
268
facet_wrap('category', as_table=False)
269
```
270
271
### Statistical Plots with Faceting
272
```python
273
# Density plots by group
274
ggplot(data, aes(x='value', fill='category')) + \
275
geom_density(alpha=0.7) + \
276
facet_wrap('region') + \
277
scale_fill_brewer(type='qual') + \
278
theme_minimal()
279
280
# Regression by groups
281
ggplot(data, aes(x='x', y='y')) + \
282
geom_point() + \
283
geom_smooth(method='lm', se=True) + \
284
facet_grid(rows='treatment', cols='timepoint') + \
285
theme_bw()
286
```
287
288
## Advanced Faceting Patterns
289
290
### Using Expressions in Facet Variables
291
```python
292
# Create faceting variable on-the-fly
293
ggplot(data, aes(x='x', y='y')) + \
294
geom_point() + \
295
facet_wrap('value > median(value)', labeller=as_labeller({
296
'True': 'Above Median', 'False': 'Below Median'
297
}))
298
```
299
300
### Combining Different Plot Types Across Panels
301
```python
302
# Different geoms highlight different aspects in each panel
303
ggplot(data, aes(x='x', y='y')) + \
304
geom_point(data=data.query('category == "A"')) + \
305
geom_line(data=data.query('category == "B"')) + \
306
facet_wrap('category', scales='free')
307
```