% % % # Introduction to the figuRes2 package
This package takes the view that a figure is a collection of graphs/tables assembled on a page and optionally annotated with metadata (titles, headers and footers). The steps to figure building can then be broken into the following stes:
What follows emphasizes the figuRes2 functions that facilitate steps 4 and 5.
The build.page function is a wrapper for the gridExtra::grid.arrange function. It can be used to help visualize how a page will be partitioned. However, its primary purpose is to arrange a list of graphic objects on a page.
Throughout this document we work under the assumption that figures are assembled on an 8.5 x 11 inch page with landscape orientation, though generalizing to other dimensions is straightforward.
In the simplest case, a single graphic populates the body of the page, i.e., the region of the page allocated to the desired visual display. The defaults of the build.page function allocate predetermined values for left, right, top, and bottom margins. These defaults provide sufficient space for 3 lines of header notes and 5 lines of footnotes presumed by the figuRes2::annotate.page function. By adding a call to annotate.page, we can see how page division looks together with dummy headers and footers.
require(figuRes2)
require(grid)
require(gridExtra)
require(ggplot2)
require(scales)
#pdf("figure1 - testing dimensions.pdf", h=8.5, w=11)
build.page(interior.h=c(1),
interior.w=c(1),
ncol=1, nrow=1,
test.dim=TRUE)
annotate.page(override="" )
Note: Expect distortion when running this code. The ultimate destination is the 8.5 in x 11 in page. Uncomment the pdf and dev.off calls to see what final product looks like.
RStudio tip: To get a good idea about how a graph will look, from the Plot Pane
Suppose two graphics are to populate a figure. E.g., forest plots typically juxtapose a graphic reporting on a stacked collection of confidence intervals with a table to the right or left reporting summary statistics. In designing a forest plot, one needs to decide how to
Alternatively, a Kaplan-Meier figure may stack a graphic of the survival curves and a table reporting Number of Subjects at Risk. In this case, it is important to ensure proper alignment of the x-axes.
In designing forest plot [Kaplan-Meier] figures, we may broadly think of partitioning the page to accomadate a 1x2 [2x1] ‘matrix’ of graphics components. In thinking about page layout, this matrix, gets padded on top, right, bottom and left by the page margins. The build.page function helps to focus attention on graphic components, while still providing access to margins. Motivating application will follow.
## Your page is a rectangle: 11 inches wide by 8.5 inches tall.
## Your page setup allocates: 0.75 inches to the left margin.
## Your page setup allocates: 0.75 inches to the right margin.
## Your page setup allocates: 0.9 inches to the top margin.
## Your page setup allocates: 1.25 inches to the bottom margin.
## Your page setup allocates: a rectangle, 9.5 inches wide by 6.35 inches tall for graphics/tables.
In this example, a 3x1 grid of graphics is planned.
## Your page is a rectangle: 11 inches wide by 8.5 inches tall.
## Your page setup allocates: 0.75 inches to the left margin.
## Your page setup allocates: 0.75 inches to the right margin.
## Your page setup allocates: 0.9 inches to the top margin.
## Your page setup allocates: 1.25 inches to the bottom margin.
## Your page setup allocates: a rectangle, 9.5 inches wide by 6.35 inches tall for graphics/tables.
An example with unequal allocation:
## Your page is a rectangle: 11 inches wide by 8.5 inches tall.
## Your page setup allocates: 0.75 inches to the left margin.
## Your page setup allocates: 0.75 inches to the right margin.
## Your page setup allocates: 0.9 inches to the top margin.
## Your page setup allocates: 1.25 inches to the bottom margin.
## Your page setup allocates: a rectangle, 9.5 inches wide by 6.35 inches tall for graphics/tables.
In some applications we might want to manipulate the margins or make them negligible. E.g., suppose a figure is needed exclusively for a PowerPoint presentation and header and footers are not needed.
build.page(interior.h=c(1/3,1/3,1/3),
interior.w=c(.5, .5),
ncol=2, nrow=3,
test.dim=TRUE,
top.margin=.1,
bottom.margin=.1,
right.margin=.1,
left.margin=.1)
## Your page is a rectangle: 11 inches wide by 8.5 inches tall.
## Your page setup allocates: 0.1 inches to the left margin.
## Your page setup allocates: 0.1 inches to the right margin.
## Your page setup allocates: 0.1 inches to the top margin.
## Your page setup allocates: 0.1 inches to the bottom margin.
## Your page setup allocates: a rectangle, 10.8 inches wide by 8.3 inches tall for graphics/tables.
Code along the following lines was used in an iterative fashion to land on values of .92 and .165. Trial and error can be used to fine tune dimensions. In the first series of figures produced in the pdf, top and bottom margins are set to be large, in the second series, top and bottom margins are shrunk by 0.5 in to increase the region of the page for graphics.
The value in such an exercise: In large scale figure production, it may be desirable to build figures that dynamically adjust the page layout to based on the number of lines required for titles and footers.
By working along similar lines, one could determine the build.page and annotate.page margin parameters that would be suited using other page dimension and orientations, e.g., legal page with portrait orientation.
The figuRes2::default.settings functions includes a call to the following ggplot2 function:
## Warning: The `axis.ticks.margin` argument of `theme()` is deprecated as of ggplot2
## 2.0.0.
## ℹ Please set `margin` property of `axis.text` instead
## ℹ The deprecated feature was likely used in the figuRes2 package.
## Please report the issue to the authors.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: The `panel.margin` argument of `theme()` is deprecated as of ggplot2 2.2.0.
## ℹ Please use the `panel.spacing` argument instead.
## ℹ The deprecated feature was likely used in the figuRes2 package.
## Please report the issue to the authors.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: `legend.margin` must be specified using `margin()`
## ℹ For the old behavior use `legend.spacing`
The figuRes2 package includes a handful of themes which are slight variations on either the ggplot2 default theme, theme_grey, or theme_bw. In particular, theme_grey2_default_margins and theme_grey2_nomargins are two variations. Relative to theme_grey these themes have:
The default.settings functions sets the theme to theme_grey2_nomargins since the build.page function controls global page margins. By setting plot.margins to zero the page real estate available for graphics is maximized relative to the page layout scheme and margins dictated to build.page. Should there be a need to alter the plot.margins of the individual graphics objects being passed to build.page, one can do so within the build of those graphics or by resetting the theme used.
An example where this might used: Suppose we are juxtaposing two graphics and want to increase the padding between the left and right graphics. If left.graphic and right.graphic are ggplot graphics built under theme_grey2_nomargins, then the following code would give left.graphic and right.graphic padding of 0.1 inches on left and right sides, respectively. Negative values could also be used used: replacing 0.1 with -0.1 would shrink the padding between the two graphics. Note that this can lead to the second graphic obscuring the first.
In this section we’ll populate the page with graphics. First we start a session:
remove(list=ls())
# require(figuRes2)
default.settings(
my.path = "C:/Users/eri7441//OneDrive - Takeda/Documents/R packages/figuRes2 - testing/",
od = "C:/Users/eri7441/OneDrive - Takeda/Documents/R packages/figuRes2 - testing/output/",
dd = "C:/Users/eri7441/OneDrive - Takeda/Documents/R packages/figuRes2 - testing/dddata/",
cd = "C:/Users/eri7441/OneDrive - Takeda/Documents/R packages/figuRes2 - testing/code/",
logd = "C:/Users/eri7441/OneDrive - Takeda/Documents/R packages/figuRes2 - testing/log/")
# This code creates directory at the locations specified.
dir.create(file.path(cd), showWarnings = FALSE)
dir.create(file.path(dd), showWarnings = FALSE)
dir.create(file.path(od), showWarnings = FALSE)
dir.create(file.path(logd), showWarnings = FALSE)
Some data are manufactured. A data.frame is built with
set.seed(8675309) # To ensure reproducibility
working.df <- data.frame(x=rnorm(500, 0, 1))
working.df$group <- factor(sample(x=c("A", "B"), replace=TRUE,
size=nrow(working.df), prob=c(.4,.6)))
working.df$y <- working.df$x +
as.numeric(working.df$group)*working.df$x +
rnorm(n = nrow(working.df), 0, 3)
A simple bar chart is created.
ex.bar <- ggplot(data=working.df, aes(x=group, fill=group)) +
geom_bar() +
labs(x="Group", y="Frequency", title="", fill="Group") +
scale_y_continuous(limits=c(0,500), breaks=seq(0,500,25)) +
coord_flip()
The following call to annotate.page gives a sense of the final product.
build.page(interior.h = c(1),
interior.w = c(1),
ncol=1,
nrow=1,
interior =list(ex.bar + ggtitle("\n\n\n\n")),
test.dim = F)
annotate.page(override = "")
The following code will create a pdf file in your current working directory. Recall that annotate.page is adding the title to the figure. This series demonstrates that using the newline escape character provides the means by which the graphic is shrunken to accomadate multiple title lines.
pdf(paste0(od, "barchart.pdf"), height=8.5, width=11)
# In the build of ex.bar title="" allows for room for a single title line
build.page(interior.h = c(1),
interior.w = c(1),
ncol=1,
nrow=1,
interior =list(ex.bar))
annotate.page(override = "")
# manipulating the title of the ggplot object allows for two lines
build.page(interior.h = c(1),
interior.w = c(1),
ncol=1,
nrow=1,
interior =list(ex.bar+ggtitle("\n")))
annotate.page(override = "")
# manipulating the title of the ggplot object allows for three lines
build.page(interior.h = c(1),
interior.w = c(1),
ncol=1,
nrow=1,
interior =list(ex.bar+ggtitle("\n\n")))
annotate.page(override = "")
# manipulating the title of the ggplot object allows for four lines
build.page(interior.h = c(1),
interior.w = c(1),
ncol=1,
nrow=1,
interior =list(ex.bar+ggtitle("\n\n\n")))
annotate.page(override = "")
dev.off() # Shuts the pdf device
In some applications using the annotate.page function is inconvenient. (See the example above where page margins were shrunken to be negligible.) In these cases, build the title into your ggplot object rather than use blank titles.
Initialize a session and generate data similar to the previous bar chart example.
## my.path is set to:/tmp/RtmpIJDzv3/Rbuild131e2441745a/figuRes2/vignettes
## dd is set to:/tmp/RtmpIJDzv3/Rbuild131e2441745a/figuRes2/vignettes/dddata/
## cd is set to:/tmp/RtmpIJDzv3/Rbuild131e2441745a/figuRes2/vignettes/code/
## od is set to:/tmp/RtmpIJDzv3/Rbuild131e2441745a/figuRes2/vignettes/output/
## logd is set to:/tmp/RtmpIJDzv3/Rbuild131e2441745a/figuRes2/vignettes/log/
## The default page dimension is set to landscape: 11 inches wide by 8.5 inches tall.
## The default page left and right page margins: 0.75 inches and 0.75 inches, respectively.
## The default top an bottom margins: 0.9 inches and 1.25 inches, respectively.
## The region available for graphics/tables is 9.5 inches wide by 6.35 inches tall.
##
## The default theme: theme_bw
working.df <- data.frame(x=rnorm(500, 0, 1))
working.df$group <- factor(
sample(x=c("A", "B"),
replace=TRUE,
size=nrow(working.df),
prob=c(.4,.6)))
working.df$y <- working.df$x +
as.numeric(working.df$group)*working.df$x +
rnorm(n = nrow(working.df), 0, 3)
head(working.df)
## x group y
## 1 -0.4064429 A 3.100391
## 2 -0.3690869 B 3.311304
## 3 -1.5428036 B -1.017126
## 4 -0.2147842 B -6.528522
## 5 -0.1271307 B 2.003076
## 6 -0.8606796 A -4.809386
Here’s a useful exploratory data analysis figure. The build of main.plot is full of customization; step through the builds. First determine the limits of the data:
xmin <- min(working.df$x)
xmax <- max(working.df$x)
ymin <- min(working.df$y)
ymax <- max(working.df$y)
The following build:
main.plot <- ggplot(data=working.df, aes(x=x,y=y, color=group, shape=group)) +
geom_point(size=3, alpha=.3) +
geom_smooth(method = "lm", size=.75) +
labs(x="x values", y="y values", color="Group", shape="Group") +
scale_shape_manual(values=c(16, 17)) +
scale_color_manual(values=c("red", "blue"))+
scale_x_continuous(limits=c(xmin+.5,xmax+.5), breaks=seq(-4,4,1), expand=c(0,0))+
scale_y_continuous(limits=c(ymin+.5,ymax+.5), expand=c(0,0))+
theme(legend.position=c(.15, .8))
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: A numeric `legend.position` argument in `theme()` was deprecated in ggplot2
## 3.5.0.
## ℹ Please use the `legend.position.inside` argument of `theme()` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## `geom_smooth()` using formula = 'y ~ x'
## Warning: Removed 5 rows containing non-finite outside the scale range
## (`stat_smooth()`).
## Warning: Removed 5 rows containing missing values or values outside the scale range
## (`geom_point()`).
This chunk creates densities for the x-values, suppressing labels.
density.plot.x <- ggplot(data=working.df, aes(x=x, fill=group, shape=group)) +
geom_density(alpha=.4) +
scale_fill_manual(values=c("red", "blue"))+
scale_x_continuous(limits=c(xmin+.5,xmax+.5), expand=c(0,0))+
theme(axis.text=element_text(color="white"),
axis.ticks=element_line(color="white")) +
labs(x=NULL, y="", title="\n") +
guides(fill=FALSE)
## Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as
## of ggplot2 3.3.4.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: Removed 5 rows containing non-finite outside the scale range
## (`stat_density()`).
This chunk creates densities for the y-values, suppressing labels and rotating the graphic. Note the use of ggplot2::coord_flip.
density.plot.y <- ggplot(data=working.df, aes(x=y, fill=group, shape=group)) +
geom_density(alpha=.4) +
scale_fill_manual(values=c("red", "blue"))+
theme(axis.text=element_text(color="white"),
axis.ticks=element_line(color="white")) +
scale_x_continuous(limits=c(ymin+.5,ymax+.5), expand=c(0,0))+
labs(x=NULL, y="") +
guides(fill=FALSE) +
coord_flip()
print(density.plot.y)
## Warning: Removed 1 row containing non-finite outside the scale range
## (`stat_density()`).
Here’s the planned layout:
## Your page is a rectangle: 11 inches wide by 8.5 inches tall.
## Your page setup allocates: 0.75 inches to the left margin.
## Your page setup allocates: 0.75 inches to the right margin.
## Your page setup allocates: 0.9 inches to the top margin.
## Your page setup allocates: 1.25 inches to the bottom margin.
## Your page setup allocates: a rectangle, 9.5 inches wide by 6.35 inches tall for graphics/tables.
The three graphics are now assembled and annotated to complete the figure. Note that object blankPanel is an object placed in the global environment by figuRes2::default.settings.
# blankPanel <- grid.rect(gp=gpar(col="white"), draw=FALSE) # created by default.settings
build.page(interior.h = c(.35, .65),
interior.w = c(.75, .25),
ncol=2,
nrow=2,
interior =list(
density.plot.x, blankPanel,
main.plot, density.plot.y))
## Warning: Removed 5 rows containing non-finite outside the scale range
## (`stat_density()`).
## `geom_smooth()` using formula = 'y ~ x'
## Warning: Removed 5 rows containing non-finite outside the scale range
## (`stat_smooth()`).
## Warning: Removed 5 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 1 row containing non-finite outside the scale range
## (`stat_density()`).
Note: There is still white space between the main plot and the density plots. This can be reduced by manipulating the plot.margins and using negative values. The values chosen were obtained via trial and error.
build.page(interior.h = c(.35, .65),
interior.w = c(.75, .25),
ncol=2,
nrow=2,
interior =list(
density.plot.x+
theme(plot.margin= unit(c(0, -.1, -.1, 0), unit="in")),
blankPanel,
main.plot+theme(plot.margin=unit(c(-.1, -.1, 0, 0), unit="in")),
density.plot.y + theme(plot.margin=unit(c(-.1, 0, 0, -.3),
unit="in"))))
## Warning: Removed 5 rows containing non-finite outside the scale range
## (`stat_density()`).
## `geom_smooth()` using formula = 'y ~ x'
## Warning: Removed 5 rows containing non-finite outside the scale range
## (`stat_smooth()`).
## Warning: Removed 5 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 1 row containing non-finite outside the scale range
## (`stat_density()`).
The following code offers a comparison of the graphic in a pdf.
pdf(file = paste0(od, "scatterplot with marginal densities.pdf"), width = 11, height = 8.5)
# blankPanel <- grid.rect(gp=gpar(col="white"), draw=FALSE) # created by default.settings
build.page(interior.h = c(.35, .65),
interior.w = c(.75, .25),
ncol=2,
nrow=2,
interior =list(
density.plot.x, blankPanel,
main.plot, density.plot.y))
annotate.page(override = "", title=list("Title Line 1", "","","",""))
build.page(interior.h = c(.35, .65),
interior.w = c(.75, .25),
ncol=2,
nrow=2,
interior =list(
density.plot.x+
theme(plot.margin= unit(c(0, -.1, -.1, 0), unit="in")),
blankPanel,
main.plot+theme(plot.margin=unit(c(-.1, -.1, 0, 0), unit="in")),
density.plot.y + theme(plot.margin=unit(c(-.1, 0, 0, -.3),
unit="in"))))
annotate.page(override = "", title=list("Title Line 1", "","","",""))
dev.off()