27
27
# ' @param as.table If \code{TRUE}, the default, the facets are laid out like
28
28
# ' a table with highest values at the bottom-right. If \code{FALSE}, the
29
29
# ' facets are laid out like a plot with the highest value at the top-right.
30
+ # ' @param switch By default, the labels are displayed on the top and
31
+ # ' right of the plot. If \code{"x"}, the top labels will be
32
+ # ' displayed to the bottom. If \code{"y"}, the right-hand side
33
+ # ' labels will be displayed to the left. Can also be set to
34
+ # ' \code{"both"}.
30
35
# ' @param shrink If \code{TRUE}, will shrink scales to fit output of
31
36
# ' statistics, not raw data. If \code{FALSE}, will be range of raw data
32
37
# ' before statistical summary.
162
167
# ' mg + facet_grid(vs + am ~ gear, margins = "vs")
163
168
# ' mg + facet_grid(vs + am ~ gear, margins = "gear")
164
169
# ' mg + facet_grid(vs + am ~ gear, margins = c("gear", "am"))
170
+ # '
171
+ # ' # The facet strips can be displayed near the axes with switch
172
+ # ' data <- transform(mtcars,
173
+ # ' am = factor(am, levels = 0:1, c("Automatic", "Manual")),
174
+ # ' gear = factor(gear, levels = 3:5, labels = c("Three", "Four", "Five"))
175
+ # ' )
176
+ # ' p <- ggplot(data, aes(mpg, disp)) + geom_point()
177
+ # ' p + facet_grid(am ~ gear, switch = "both") + theme_light()
178
+ # '
179
+ # ' # It may be more aesthetic to use a theme without boxes around
180
+ # ' # around the strips.
181
+ # ' p + facet_grid(am ~ gear + vs, switch = "y") + theme_minimal()
182
+ # ' p + facet_grid(am ~ ., switch = "y") +
183
+ # ' theme_gray() %+replace% theme(strip.background = element_blank())
165
184
# ' }
166
- facet_grid <- function (facets , margins = FALSE , scales = " fixed" , space = " fixed" , shrink = TRUE , labeller = " label_value" , as.table = TRUE , drop = TRUE ) {
185
+ facet_grid <- function (facets , margins = FALSE , scales = " fixed" , space = " fixed" , shrink = TRUE , labeller = " label_value" , as.table = TRUE , switch = NULL , drop = TRUE ) {
167
186
scales <- match.arg(scales , c(" fixed" , " free_x" , " free_y" , " free" ))
168
187
free <- list (
169
188
x = any(scales %in% c(" free_x" , " free" )),
@@ -200,8 +219,8 @@ facet_grid <- function(facets, margins = FALSE, scales = "fixed", space = "fixed
200
219
201
220
facet(
202
221
rows = rows , cols = cols , margins = margins , shrink = shrink ,
203
- free = free , space_free = space_free ,
204
- labeller = labeller , as.table = as.table , drop = drop ,
222
+ free = free , space_free = space_free , labeller = labeller ,
223
+ as.table = as.table , switch = switch , drop = drop ,
205
224
subclass = " grid"
206
225
)
207
226
}
@@ -239,17 +258,85 @@ facet_render.grid <- function(facet, panel, coord, theme, geom_grobs) {
239
258
strips $ r $ heights <- panels $ heights
240
259
strips $ t $ widths <- panels $ widths
241
260
261
+ # Check if switch is consistent with grid layout
262
+ switch_x <- ! is.null(facet $ switch ) && facet $ switch %in% c(" both" , " x" )
263
+ switch_y <- ! is.null(facet $ switch ) && facet $ switch %in% c(" both" , " y" )
264
+ if (switch_x && length(strips $ t ) == 0 ) {
265
+ facet $ switch <- if (facet $ switch == " both" ) " y" else NULL
266
+ switch_x <- FALSE
267
+ warning(" Cannot switch x axis strips as they do not exist" , call. = FALSE )
268
+ }
269
+ if (switch_y && length(strips $ r ) == 0 ) {
270
+ facet $ switch <- if (facet $ switch == " both" ) " x" else NULL
271
+ switch_y <- FALSE
272
+ warning(" Cannot switch y axis strips as they do not exist" , call. = FALSE )
273
+ }
274
+
275
+
242
276
# Combine components into complete plot
243
- top <- strips $ t
244
- top <- gtable_add_cols(top , strips $ r $ widths )
245
- top <- gtable_add_cols(top , axes $ l $ widths , pos = 0 )
277
+ if (is.null(facet $ switch )) {
278
+ top <- strips $ t
279
+ top <- gtable_add_cols(top , strips $ r $ widths )
280
+ top <- gtable_add_cols(top , axes $ l $ widths , pos = 0 )
246
281
247
- center <- cbind(axes $ l , panels , strips $ r , z = c(2 , 1 , 3 ))
248
- bottom <- axes $ b
249
- bottom <- gtable_add_cols(bottom , strips $ r $ widths )
250
- bottom <- gtable_add_cols(bottom , axes $ l $ widths , pos = 0 )
282
+ center <- cbind(axes $ l , panels , strips $ r , z = c(2 , 1 , 3 ))
283
+ bottom <- axes $ b
284
+ bottom <- gtable_add_cols(bottom , strips $ r $ widths )
285
+ bottom <- gtable_add_cols(bottom , axes $ l $ widths , pos = 0 )
286
+
287
+ complete <- rbind(top , center , bottom , z = c(1 , 2 , 3 ))
288
+
289
+ } else {
290
+ # Add padding between the switched strips and the axes
291
+ padding <- convertUnit(theme $ strip.switch.pad.grid , " cm" )
292
+
293
+ if (switch_x ) {
294
+ t_heights <- c(padding , strips $ t $ heights )
295
+ gt_t <- gtable(widths = strips $ t $ widths , heights = unit(t_heights , " cm" ))
296
+ gt_t <- gtable_add_grob(gt_t , strips $ t , name = strips $ t $ name , clip = " off" ,
297
+ t = 1 , l = 1 , b = - 1 , r = - 1 )
298
+ }
299
+ if (switch_y ) {
300
+ r_widths <- c(strips $ r $ widths , padding )
301
+ gt_r <- gtable(widths = unit(r_widths , " cm" ), heights = strips $ r $ heights )
302
+ gt_r <- gtable_add_grob(gt_r , strips $ r , name = strips $ r $ name , clip = " off" ,
303
+ t = 1 , l = 1 , b = - 1 , r = - 1 )
304
+ }
305
+
306
+ # Combine plot elements according to strip positions
307
+ if (switch_x && switch_y ) {
308
+ center <- cbind(gt_r , axes $ l , panels , z = c(3 , 2 , 1 ))
309
+
310
+ bottom <- rbind(axes $ b , gt_t )
311
+ bottom <- gtable_add_cols(bottom , axes $ l $ widths , pos = 0 )
312
+ bottom <- gtable_add_cols(bottom , gt_r $ widths , pos = 0 )
313
+
314
+ complete <- rbind(center , bottom , z = c(1 , 2 ))
315
+ } else if (switch_x ) {
316
+ center <- cbind(axes $ l , panels , strips $ r , z = c(2 , 1 , 3 ))
251
317
252
- complete <- rbind(top , center , bottom , z = c(1 , 2 , 3 ))
318
+ bottom <- rbind(axes $ b , gt_t )
319
+ bottom <- gtable_add_cols(bottom , strips $ r $ widths )
320
+ bottom <- gtable_add_cols(bottom , axes $ l $ widths , pos = 0 )
321
+
322
+ complete <- rbind(center , bottom , z = c(1 , 2 ))
323
+ } else if (switch_y ) {
324
+ top <- strips $ t
325
+ top <- gtable_add_cols(top , gt_r $ widths , pos = 0 )
326
+ top <- gtable_add_cols(top , axes $ l $ widths , pos = 0 )
327
+
328
+ center <- cbind(gt_r , axes $ l , panels , z = c(3 , 2 , 1 ))
329
+ bottom <- axes $ b
330
+ bottom <- gtable_add_cols(bottom , axes $ l $ widths , pos = 0 )
331
+ bottom <- gtable_add_cols(bottom , gt_r $ widths , pos = 0 )
332
+
333
+ complete <- rbind(top , center , bottom , z = c(1 , 2 , 3 ))
334
+ } else {
335
+ stop(" `switch` must be either NULL, 'both', 'x', or 'y'" ,
336
+ call. = FALSE )
337
+ }
338
+ }
339
+
253
340
complete $ respect <- panels $ respect
254
341
complete $ name <- " layout"
255
342
bottom <- axes $ b
@@ -262,13 +349,23 @@ facet_strips.grid <- function(facet, panel, theme) {
262
349
col_vars <- unique(panel $ layout [names(facet $ cols )])
263
350
row_vars <- unique(panel $ layout [names(facet $ rows )])
264
351
352
+ dir <- list (r = " r" , t = " t" )
353
+ if (! is.null(facet $ switch ) && facet $ switch %in% c(" both" , " x" )) {
354
+ dir $ t <- " b"
355
+ }
356
+ if (! is.null(facet $ switch ) && facet $ switch %in% c(" both" , " y" )){
357
+ dir $ r <- " l"
358
+ }
359
+
265
360
list (
266
- r = build_strip(panel , row_vars , facet $ labeller , theme , " r" ),
267
- t = build_strip(panel , col_vars , facet $ labeller , theme , " t" )
361
+ r = build_strip(panel , row_vars , facet $ labeller ,
362
+ theme , dir $ r , switch = facet $ switch ),
363
+ t = build_strip(panel , col_vars , facet $ labeller ,
364
+ theme , dir $ t , switch = facet $ switch )
268
365
)
269
366
}
270
367
271
- build_strip <- function (panel , label_df , labeller , theme , side = " right" ) {
368
+ build_strip <- function (panel , label_df , labeller , theme , side = " right" , switch = NULL ) {
272
369
side <- match.arg(side , c(" top" , " left" , " bottom" , " right" ))
273
370
horizontal <- side %in% c(" top" , " bottom" )
274
371
labeller <- match.fun(labeller )
@@ -290,17 +387,21 @@ build_strip <- function(panel, label_df, labeller, theme, side = "right") {
290
387
labels [, i ] <- labeller(names(label_df )[i ], label_df [, i ])
291
388
}
292
389
390
+ # Display the mirror of the y strip labels if switched
391
+ if (! is.null(switch ) && switch %in% c(" both" , " y" )) {
392
+ theme $ strip.text.y $ angle <- adjust_angle(theme $ strip.text.y $ angle )
393
+ }
394
+
293
395
# Render as grobs
294
396
grobs <- apply(labels , c(1 ,2 ), ggstrip , theme = theme ,
295
397
horizontal = horizontal )
296
398
297
399
# Create layout
298
400
name <- paste(" strip" , side , sep = " -" )
299
401
if (horizontal ) {
300
- grobs <- t(grobs )
301
-
302
402
# Each row is as high as the highest and as a wide as the panel
303
403
row_height <- function (row ) max(laply(row , height_cm ))
404
+ grobs <- t(grobs )
304
405
heights <- unit(apply(grobs , 1 , row_height ), " cm" )
305
406
widths <- unit(rep(1 , ncol(grobs )), " null" )
306
407
} else {
0 commit comments