Skip to content

Commit 599b704

Browse files
committed
Use new table layout system in facet_grid
1 parent 16897fd commit 599b704

8 files changed

+557
-224
lines changed

R/facet-grid-.r

Lines changed: 128 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ FacetGrid <- proto(Facet, {
2929
.$proto(
3030
rows = rows, cols = cols, margins = margins,
3131
free = free, space_is_free = (space == "free"),
32-
labeller = list(labeller), as.table = as.table
32+
labeller = labeller, as.table = as.table
3333
)
3434
}
3535

@@ -143,14 +143,121 @@ FacetGrid <- proto(Facet, {
143143

144144
# Create grobs for each component of the panel guides
145145
add_guides <- function(., panels_grob, coord, theme) {
146+
panels <- .$panel_info$PANEL
147+
coord_details <- llply(panels, function(i) {
148+
coord$compute_ranges(.$panel_scales(i))
149+
})
150+
151+
axes <- .$build_axes(coord, coord_details, theme)
152+
strips <- .$build_strips(coord_details, theme)
153+
panels <- .$build_panels(panels_grob, coord, coord_details, theme)
154+
# legend
155+
# labels
156+
157+
# Combine components into complete plot
158+
centre <- (axes$l$clone())$cbind(panels)$cbind(strips$r)
159+
top <- (strips$t$clone())$
160+
add_cols(strips$r$widths)$
161+
add_cols(axes$l$widths, pos = 0)
162+
bottom <- (axes$b$clone())$
163+
add_cols(strips$r$widths)$
164+
add_cols(axes$l$widths, pos = 0)
165+
166+
complete <- centre$clone()$
167+
rbind(top, pos = 0)$
168+
rbind(bottom)
169+
complete$respect <- panels$respect
170+
complete$name <- "layout"
171+
172+
complete
173+
}
174+
175+
build_strips <- function(., coord_details, theme) {
176+
col_vars <- ddply(.$panel_info, "COL", uniquecols)
177+
row_vars <- ddply(.$panel_info, "ROW", uniquecols)
178+
179+
list(
180+
r = .$build_strip(row_vars, theme, "r"),
181+
t = .$build_strip(col_vars, theme, "t")
182+
)
183+
}
184+
185+
build_strip <- function(., label_df, theme, side = "right") {
186+
side <- match.arg(side, c("t", "l", "b", "r"))
187+
horizontal <- side %in% c("t", "b")
188+
labeller <- match.fun(.$labeller)
189+
190+
label_df <- label_df[setdiff(names(label_df),
191+
c("PANEL", "COL", "ROW", "SCALE_X", "SCALE_Y"))]
192+
193+
# No labelling data, so return empty row/col
194+
if (empty(label_df)) {
195+
if (horizontal) {
196+
widths <- unit(rep(1, max(.$panel_info$COL)), "null")
197+
return(layout_empty_row(widths))
198+
} else {
199+
heights <- unit(rep(1, max(.$panel_info$ROW)), "null")
200+
return(layout_empty_col(heights))
201+
}
202+
}
203+
204+
# Create matrix of labels
205+
labels <- matrix(list(), nrow = nrow(label_df), ncol = ncol(label_df))
206+
for (i in seq_len(ncol(label_df))) {
207+
labels[, i] <- labeller(names(label_df)[i], label_df[, i])
208+
}
209+
210+
# Render as grobs
211+
grobs <- aaply(labels, c(1,2), ggstrip, theme = theme,
212+
horizontal = horizontal, .drop = FALSE)
213+
214+
# Create layout
215+
name <- paste("strip", side, sep = "-")
216+
if (horizontal) {
217+
grobs <- t(grobs)
218+
219+
# Each row is as high as the highest as a wide as the panel
220+
row_height <- function(row) max(laply(row, height_cm))
221+
heights <- unit(apply(grobs, 1, row_height), "cm")
222+
widths <- unit(rep(1, ncol(grobs)), "null")
223+
} else {
224+
# Each row is wide as the widest and as high as the panel
225+
col_width <- function(col) max(laply(col, width_cm))
226+
widths <- unit(apply(grobs, 2, col_width), "cm")
227+
heights <- unit(rep(1, nrow(grobs)), "null")
228+
}
229+
strips <- layout_matrix(name, grobs, heights = heights, widths = widths)
230+
231+
if (horizontal) {
232+
strips$add_col_space(theme$panel.margin)
233+
} else {
234+
strips$add_row_space(theme$panel.margin)
235+
}
236+
strips
237+
}
238+
239+
build_axes <- function(., coord, coord_details, theme) {
240+
axes <- list()
241+
242+
# Horizontal axes
243+
cols <- which(.$panel_info$ROW == 1)
244+
grobs <- lapply(coord_details[cols], coord$guide_axis_h, theme)
245+
axes$b <- layout_row("axis-b", grobs)$add_col_space(theme$panel.margin)
246+
247+
# Vertical axes
248+
rows <- which(.$panel_info$COL == 1)
249+
grobs <- lapply(coord_details[rows], coord$guide_axis_v, theme)
250+
axes$l <- layout_col("axis-l", grobs)$add_row_space(theme$panel.margin)
146251

252+
axes
253+
}
254+
build_panels <- function(., panels_grob, coord, coord_details, theme) {
147255
aspect_ratio <- theme$aspect.ratio
148256

149257
# If user hasn't set aspect ratio, and we have fixed scales, then
150258
# ask the coordinate system if it wants to specify one
151259
if (is.null(aspect_ratio) && !.$free$x && !.$free$y) {
152-
ranges <- coord$compute_ranges(.$panel_scales(1))
153-
aspect_ratio <- coord$compute_aspect(ranges)
260+
aspect_ratio <- coord$compute_aspect(coord_details[[1]])
154261
}
155262

156263
if (is.null(aspect_ratio)) {
@@ -159,142 +266,39 @@ FacetGrid <- proto(Facet, {
159266
} else {
160267
respect <- TRUE
161268
}
162-
163-
panels <- .$panel_info$PANEL
164-
cols <- which(.$panel_info$ROW == 1)
165-
rows <- which(.$panel_info$COL == 1)
166-
167-
coord_details <- llply(panels, function(i) {
168-
coord$compute_ranges(.$panel_scales(i))
169-
})
170-
171-
# Horizontal axes
172-
axes_h <- lapply(coord_details[cols], coord$guide_axis_h, theme)
173-
axes_h_height <- do.call("max2", llply(axes_h, grobHeight))
174-
axeshGrid <- grobGrid(
175-
"axis_h", axes_h, nrow = 1, ncol = length(cols),
176-
heights = axes_h_height, clip = "off"
177-
)
178-
179-
# Vertical axes
180-
axes_v <- lapply(coord_details[rows], coord$guide_axis_v, theme)
181-
axes_v_width <- do.call("max2", llply(axes_v, grobWidth))
182-
axesvGrid <- grobGrid(
183-
"axis_v", axes_v, nrow = length(rows), ncol = 1,
184-
widths = axes_v_width, as.table = .$as.table, clip = "off"
185-
)
186-
187-
# Strips
188-
labels <- .$labels_default(.$shape, theme)
189-
190-
strip_widths <- llply(labels$v, grobWidth)
191-
strip_widths <- do.call("unit.c", llply(1:ncol(strip_widths),
192-
function(i) do.call("max2", strip_widths[, i])))
193-
stripvGrid <- grobGrid(
194-
"strip_v", labels$v, nrow = nrow(labels$v), ncol = ncol(labels$v),
195-
widths = strip_widths, as.table = .$as.table
196-
)
197-
198-
strip_heights <- llply(labels$h, grobHeight)
199-
strip_heights <- do.call("unit.c", llply(1:nrow(strip_heights),
200-
function(i) do.call("max2", strip_heights[i, ])))
201-
striphGrid <- grobGrid(
202-
"strip_h", labels$h, nrow = nrow(labels$h), ncol = ncol(labels$h),
203-
heights = strip_heights
204-
)
205269

206270
# Add background and foreground to panels
207-
panels_grob <- lapply(panels, function(i) {
271+
panels <- .$panel_info$PANEL
272+
panel_grobs <- lapply(panels, function(i) {
208273
fg <- coord$guide_foreground(coord_details[[i]], theme)
209274
bg <- coord$guide_background(coord_details[[i]], theme)
210275
grobTree(bg, panels_grob[[i]], fg)
211276
})
212-
dim(panels_grob) <- c(length(rows), length(cols))
277+
nrow <- max(.$panel_info$ROW)
278+
ncol <- max(.$panel_info$COL)
279+
dim(panel_grobs) <- c(nrow, ncol)
213280

214281
if(.$space_is_free) {
215282
size <- function(y) unit(diff(y$output_expand()), "null")
216-
panel_widths <- do.call("unit.c", llply(.$scales$x, size))
217-
panel_heights <- do.call("unit.c", llply(.$scales$y, size))
283+
x_scales <- .$panel_info$scale_x[.$panel_info$ROW == 1]
284+
y_scales <- .$panel_info$scale_y[.$panel_info$COL == 1]
285+
286+
panel_widths <- do.call("unit.c", llply(.$scales$x, size))[x_scales]
287+
panel_heights <- do.call("unit.c", llply(.$scales$y, size))[y_scales]
218288
} else {
219-
panel_widths <- unit(1, "null")
220-
panel_heights <- unit(1 * aspect_ratio, "null")
289+
panel_widths <- rep(unit(1, "null"), ncol)
290+
panel_heights <- rep(unit(1 * aspect_ratio, "null"), nrow)
221291
}
292+
222293

223-
panelGrid <- grobGrid(
224-
"panel", t(panels_grob), ncol = length(cols), nrow = length(rows),
225-
widths = panel_widths, heights = panel_heights, as.table = .$as.table,
226-
respect = respect
227-
)
228-
229-
# Add gaps and compute widths and heights
230-
fill_tl <- spacer(nrow(labels$h), 1)
231-
fill_tr <- spacer(nrow(labels$h), ncol(labels$v))
232-
fill_bl <- spacer(1, 1)
233-
fill_br <- spacer(1, ncol(labels$v))
234-
235-
all <- rbind(
236-
cbind(fill_tl, striphGrid, fill_tr),
237-
cbind(axesvGrid, panelGrid, stripvGrid),
238-
cbind(fill_bl, axeshGrid, fill_br)
239-
)
240-
# theme$panel.margin, theme$panel.margin
241-
242-
# from left to right
243-
hgap_widths <- do.call("unit.c", compact(list(
244-
unit(0, "cm"), # no gap after axis
245-
rep.unit2(theme$panel.margin, length(cols) - 1), # gap after all panels except last
246-
unit(rep(0, ncol(stripvGrid) + 1), "cm") # no gap after strips
247-
)))
248-
hgap <- grobGrid("hgap",
249-
ncol = ncol(all), nrow = nrow(all),
250-
widths = hgap_widths,
251-
)
252-
253-
# from top to bottom
254-
vgap_heights <- do.call("unit.c", compact(list(
255-
unit(rep(0, nrow(striphGrid) + 1), "cm"), # no gap after strips
256-
rep.unit2(theme$panel.margin, length(rows) - 1), # gap after all panels except last
257-
unit(0, "cm") # no gap after axis
258-
)))
259-
260-
vgap <- grobGrid("vgap",
261-
nrow = nrow(all), ncol = ncol(all) * 2,
262-
heights = vgap_heights
263-
)
264-
265-
rweave(cweave(all, hgap), vgap)
294+
panels <- layout_matrix("panel", panel_grobs, panel_widths, panel_heights)
295+
panels$respect <- respect
296+
panels$add_col_space(theme$panel.margin)
297+
panels$add_row_space(theme$panel.margin)
298+
panels
266299
}
267300

268301

269-
labels_default <- function(., gm, theme) {
270-
col_vars <- ddply(.$panel_info, "COL", uniquecols)
271-
row_vars <- ddply(.$panel_info, "ROW", uniquecols)
272-
273-
list(
274-
h = t(.$make_labels(col_vars, theme)),
275-
v = .$make_labels(row_vars, theme, horizontal = FALSE)
276-
)
277-
}
278-
279-
make_labels <- function(., label_df, theme, ...) {
280-
labeller <- match.fun(.$labeller[[1]])
281-
282-
label_df <- label_df[setdiff(names(label_df),
283-
c("PANEL", "COL", "ROW", "SCALE_X", "SCALE_Y"))]
284-
285-
labels <- matrix(list(), nrow = nrow(label_df), ncol = ncol(label_df))
286-
for (i in seq_len(ncol(label_df))) {
287-
labels[, i] <- labeller(names(label_df)[i], label_df[, i])
288-
}
289-
290-
if (nrow(label_df) == 1) {
291-
grobs <- matrix(list(zeroGrob()))
292-
} else {
293-
grobs <- apply(labels, c(1,2), ggstrip, theme = theme, ...)
294-
}
295-
grobs
296-
}
297-
298302
# Documentation ------------------------------------------------------------
299303

300304
objname <- "grid"

R/facet-labels.r

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ ggstrip <- function(text, horizontal = TRUE, theme) {
7474
theme_render(theme, "strip.background"),
7575
label
7676
),
77-
width = grobWidth(label) + unit(0.5, "lines"),
78-
height = grobHeight(label) + unit(0.5, "lines")
77+
width = unit(width_cm(label), "cm") + unit(0.5, "lines"),
78+
height = unit(height_cm(label), "cm") + unit(0.5, "lines")
7979
))
8080
}

0 commit comments

Comments
 (0)