Skip to content

Commit d35f103

Browse files
committed
Combine plot-render and plot-build
1 parent 9d47ba7 commit d35f103

File tree

5 files changed

+199
-201
lines changed

5 files changed

+199
-201
lines changed

DESCRIPTION

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,6 @@ Collate:
141141
'plot-build.r'
142142
'plot-construction.r'
143143
'plot-last.r'
144-
'plot-render.r'
145144
'plot.r'
146145
'position-.r'
147146
'position-collide.r'

R/autoplot.r

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ autoplot <- function(object, ...) {
1515

1616
#' @export
1717
autoplot.default <- function(object, ...) {
18-
error.msg <- paste("Objects of type",class(object),"not supported by autoplot. Please use ggplot() instead.\n")
19-
stop(error.msg, call. = FALSE)
18+
stop("Objects of type ", paste(class(object), collapse = "/"),
19+
" not supported by autoplot. Please use ggplot() instead.\n", call. = FALSE)
2020
}
2121

R/plot-build.r

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,166 @@ ggplot_build <- function(plot) {
9595
layer_data <- function(plot, i = 1L) {
9696
ggplot_build(plot)$data[[i]]
9797
}
98+
99+
#' Build a plot with all the usual bits and pieces.
100+
#'
101+
#' This function builds all grobs necessary for displaying the plot, and
102+
#' stores them in a special data structure called a \code{\link{gtable}}.
103+
#' This object is amenable to programmatic manipulation, should you want
104+
#' to (e.g.) make the legend box 2 cm wide, or combine multiple plots into
105+
#' a single display, preserving aspect ratios across the plots.
106+
#'
107+
#' @seealso \code{\link{print.ggplot}} and \code{link{benchplot}} for
108+
#' for functions that contain the complete set of steps for generating
109+
#' a ggplot2 plot.
110+
#' @return a \code{\link{gtable}} object
111+
#' @keywords internal
112+
#' @param plot plot object
113+
#' @param data plot data generated by \code{\link{ggplot_build}}
114+
#' @export
115+
ggplot_gtable <- function(data) {
116+
plot <- data$plot
117+
panel <- data$panel
118+
data <- data$data
119+
theme <- plot_theme(plot)
120+
121+
geom_grobs <- Map(function(l, d) l$draw_geom(d, panel, plot$coordinates),
122+
plot$layers, data)
123+
124+
plot_table <- facet_render(plot$facet, panel, plot$coordinates,
125+
theme, geom_grobs)
126+
127+
# Axis labels
128+
labels <- plot$coordinates$labels(list(
129+
x = xlabel(panel, plot$labels),
130+
y = ylabel(panel, plot$labels)
131+
))
132+
xlabel <- element_render(theme, "axis.title.x", labels$x, expand_y = TRUE)
133+
ylabel <- element_render(theme, "axis.title.y", labels$y, expand_x = TRUE)
134+
135+
# helper function return the position of panels in plot_table
136+
find_panel <- function(table) {
137+
layout <- table$layout
138+
panels <- layout[grepl("^panel", layout$name), , drop = FALSE]
139+
140+
data.frame(
141+
t = min(panels$t),
142+
r = max(panels$r),
143+
b = max(panels$b),
144+
l = min(panels$l)
145+
)
146+
}
147+
panel_dim <- find_panel(plot_table)
148+
149+
xlab_height <- grobHeight(xlabel)
150+
plot_table <- gtable_add_rows(plot_table, xlab_height)
151+
plot_table <- gtable_add_grob(plot_table, xlabel, name = "xlab",
152+
l = panel_dim$l, r = panel_dim$r, t = -1, clip = "off")
153+
154+
ylab_width <- grobWidth(ylabel)
155+
plot_table <- gtable_add_cols(plot_table, ylab_width, pos = 0)
156+
plot_table <- gtable_add_grob(plot_table, ylabel, name = "ylab",
157+
l = 1, b = panel_dim$b, t = panel_dim$t, clip = "off")
158+
159+
# Legends
160+
position <- theme$legend.position
161+
if (length(position) == 2) {
162+
position <- "manual"
163+
}
164+
165+
legend_box <- if (position != "none") {
166+
build_guides(plot$scales, plot$layers, plot$mapping, position, theme, plot$guides, plot$labels)
167+
} else {
168+
zeroGrob()
169+
}
170+
171+
if (is.zero(legend_box)) {
172+
position <- "none"
173+
} else {
174+
# these are a bad hack, since it modifies the contents of viewpoint directly...
175+
legend_width <- gtable_width(legend_box) + theme$legend.margin
176+
legend_height <- gtable_height(legend_box) + theme$legend.margin
177+
178+
# Set the justification of the legend box
179+
# First value is xjust, second value is yjust
180+
just <- valid.just(theme$legend.justification)
181+
xjust <- just[1]
182+
yjust <- just[2]
183+
184+
if (position == "manual") {
185+
xpos <- theme$legend.position[1]
186+
ypos <- theme$legend.position[2]
187+
188+
# x and y are specified via theme$legend.position (i.e., coords)
189+
legend_box <- editGrob(legend_box,
190+
vp = viewport(x = xpos, y = ypos, just = c(xjust, yjust),
191+
height = legend_height, width = legend_width))
192+
} else {
193+
# x and y are adjusted using justification of legend box (i.e., theme$legend.justification)
194+
legend_box <- editGrob(legend_box,
195+
vp = viewport(x = xjust, y = yjust, just = c(xjust, yjust)))
196+
}
197+
}
198+
199+
panel_dim <- find_panel(plot_table)
200+
# for align-to-device, use this:
201+
# panel_dim <- summarise(plot_table$layout, t = min(t), r = max(r), b = max(b), l = min(l))
202+
203+
if (position == "left") {
204+
plot_table <- gtable_add_cols(plot_table, legend_width, pos = 0)
205+
plot_table <- gtable_add_grob(plot_table, legend_box, clip = "off",
206+
t = panel_dim$t, b = panel_dim$b, l = 1, r = 1, name = "guide-box")
207+
} else if (position == "right") {
208+
plot_table <- gtable_add_cols(plot_table, legend_width, pos = -1)
209+
plot_table <- gtable_add_grob(plot_table, legend_box, clip = "off",
210+
t = panel_dim$t, b = panel_dim$b, l = -1, r = -1, name = "guide-box")
211+
} else if (position == "bottom") {
212+
plot_table <- gtable_add_rows(plot_table, legend_height, pos = -1)
213+
plot_table <- gtable_add_grob(plot_table, legend_box, clip = "off",
214+
t = -1, b = -1, l = panel_dim$l, r = panel_dim$r, name = "guide-box")
215+
} else if (position == "top") {
216+
plot_table <- gtable_add_rows(plot_table, legend_height, pos = 0)
217+
plot_table <- gtable_add_grob(plot_table, legend_box, clip = "off",
218+
t = 1, b = 1, l = panel_dim$l, r = panel_dim$r, name = "guide-box")
219+
} else if (position == "manual") {
220+
# should guide box expand whole region or region without margin?
221+
plot_table <- gtable_add_grob(plot_table, legend_box,
222+
t = panel_dim$t, b = panel_dim$b, l = panel_dim$l, r = panel_dim$r,
223+
clip = "off", name = "guide-box")
224+
}
225+
226+
# Title
227+
title <- element_render(theme, "plot.title", plot$labels$title, expand_y = TRUE)
228+
title_height <- grobHeight(title)
229+
230+
pans <- plot_table$layout[grepl("^panel", plot_table$layout$name), ,
231+
drop = FALSE]
232+
233+
plot_table <- gtable_add_rows(plot_table, title_height, pos = 0)
234+
plot_table <- gtable_add_grob(plot_table, title, name = "title",
235+
t = 1, b = 1, l = min(pans$l), r = max(pans$r), clip = "off")
236+
237+
# Margins
238+
plot_table <- gtable_add_rows(plot_table, theme$plot.margin[1], pos = 0)
239+
plot_table <- gtable_add_cols(plot_table, theme$plot.margin[2])
240+
plot_table <- gtable_add_rows(plot_table, theme$plot.margin[3])
241+
plot_table <- gtable_add_cols(plot_table, theme$plot.margin[4], pos = 0)
242+
243+
if (inherits(theme$plot.background, "element")) {
244+
plot_table <- gtable_add_grob(plot_table,
245+
element_render(theme, "plot.background"),
246+
t = 1, l = 1, b = -1, r = -1, name = "background", z = -Inf)
247+
plot_table$layout <- plot_table$layout[c(nrow(plot_table$layout), 1:(nrow(plot_table$layout) - 1)),]
248+
plot_table$grobs <- plot_table$grobs[c(nrow(plot_table$layout), 1:(nrow(plot_table$layout) - 1))]
249+
}
250+
plot_table
251+
}
252+
253+
#' Generate a ggplot2 plot grob.
254+
#'
255+
#' @param x ggplot2 object
256+
#' @keywords internal
257+
#' @export
258+
ggplotGrob <- function(x) {
259+
ggplot_gtable(ggplot_build(x))
260+
}

R/plot-render.r

Lines changed: 0 additions & 198 deletions
This file was deleted.

0 commit comments

Comments
 (0)