gridExtra/0000755000176200001440000000000013154773270012214 5ustar liggesusersgridExtra/TODO0000644000176200001440000000054313010764171012675 0ustar liggesusers NEW FEATURES * basic plots (image, plot, É) in grid, using scales and guide packages of Hadley W. * matrix plot * clone and export linearised versions of all basic grid grobs, i.e. with full list of arguments (no gp) accessible to vectorisation * explore the idea of a new unit system based on complex numbers, one part for physical vs relative unitsgridExtra/inst/0000755000176200001440000000000013154617431013165 5ustar liggesusersgridExtra/inst/tests/0000755000176200001440000000000013010764171014322 5ustar liggesusersgridExtra/inst/tests/testthat.r0000644000176200001440000000007613010764171016350 0ustar liggesuserslibrary(gridExtra) library(testthat) test_check("gridExtra") gridExtra/inst/tests/testthat/0000755000176200001440000000000013154773270016173 5ustar liggesusersgridExtra/inst/tests/testthat/test-arrangeGrob.R0000644000176200001440000000374213010764171021521 0ustar liggesuserslibrary(gridExtra) library(testthat) library(grid) r <- rectGrob(gp=gpar(fill="grey90")) context("Checking layout") test_that("nrow/ncol define a layout", { expect_that(dim(arrangeGrob(r,r,r)), equals(c(3,1))) expect_that(dim(arrangeGrob(r,r,r, nrow=2)), equals(c(2,2))) expect_that(dim(arrangeGrob(r,r,r, ncol=2)), equals(c(2,2))) expect_that(dim(arrangeGrob(r,r,r, ncol=4)), equals(c(1,4))) expect_that(dim(arrangeGrob(r,r,r, nrow=4)), equals(c(4,1))) expect_that(dim(arrangeGrob(r,r,r, nrow=1)), equals(c(1,3))) expect_that(dim(arrangeGrob(r,r,r, ncol=1)), equals(c(3,1))) expect_that(dim(arrangeGrob(r,r,r, ncol=2,nrow=2)), equals(c(2,2))) expect_that(dim(arrangeGrob(r,r,r, ncol=3,nrow=4)), equals(c(4,3))) expect_error(arrangeGrob(r,r,r, ncol=1,nrow=1)) }) test_that("widths/heights define a layout", { expect_that(dim(arrangeGrob(r,r,r, widths=1)), equals(c(3,1))) expect_that(dim(arrangeGrob(r,r,r, heights=1)), equals(c(1,3))) expect_that(dim(arrangeGrob(r,r,r, widths=1:3)), equals(c(1,3))) expect_that(dim(arrangeGrob(r,r,r, widths=1:5)), equals(c(1,5))) expect_that(dim(arrangeGrob(r,r,r, heights=1:3)), equals(c(3,1))) expect_that(dim(arrangeGrob(r,r,r, heights=1:5)), equals(c(5,1))) expect_that(dim(arrangeGrob(r,r,r, widths=1:5)), equals(c(1,5))) expect_that(dim(arrangeGrob(r,r,r, widths=1:5, heights=1:5)), equals(c(5,5))) expect_error(arrangeGrob(r,r,r, widths=1, heights=1)) }) test_that("combinations of nrow/ncol and widths/heights define a layout", { expect_that(dim(arrangeGrob(r,r,r, nrow=2, widths=1:3)), equals(c(2,3))) expect_that(dim(arrangeGrob(r,r,r, ncol=2, heights=1:3)), equals(c(3,2))) expect_that(dim(arrangeGrob(r,r,r, ncol=2, widths=1:2)), equals(c(2,2))) expect_that(dim(arrangeGrob(r,r,r, nrow=2, heights=1:2)), equals(c(2,2))) expect_error(arrangeGrob(r,r,r, ncol=2, widths=1:3)) expect_error(arrangeGrob(r,r,r, nrow=2, heights=1:3)) }) gridExtra/inst/tests/testthat/test-tableGrob.R0000644000176200001440000000064713010764171021172 0ustar liggesuserslibrary(gridExtra) library(testthat) library(grid) m <- iris[1:4, 1:3] context("Checking tableGrob layout") test_that("tableGrob has the correct size", { expect_that(dim(tableGrob(m)), equals(c(5,4))) expect_that(dim(tableGrob(m, rows = NULL)), equals(c(5,3))) expect_that(dim(tableGrob(m, cols = NULL)), equals(c(4,4))) expect_that(dim(tableGrob(m, rows = NULL, cols = NULL)), equals(c(4,3))) }) gridExtra/inst/NEWS.md0000644000176200001440000000274713152367440014275 0ustar liggesusers# gridExtra 2.3.0 (2017-09-01) ## Misc. cleanup for CRAN release * renamed `cbind/rbind` functions copied from gtable to `cbind_gtable` and `rbind_gtable` to avoid issues with generic method (different signature) * more consistency in gtable-related functions # gridExtra 2.2.0 (2016-02-27) ## NEW FEATURES * added padding argument to table themes * simplified a few theme arguments ## BUG FIX * recycling logic was flawed for aesthetics in table cells # gridExtra 2.1.0 (2015-07-27) ## DOCUMENTATION * expanded vignettes * wiki page features a FAQ section ## NEW FEATURES * added join function from gtable (with fix) * global size and font parameters more accessible in themes * added str.gtable method ## BUG FIX * str.default was causing issues with gtables # gridExtra 2.0.0 (2015-07-11) * removed experimental grobs and functions not widely used (they can be found at https://github.com/baptiste/gridextra if needed) * arrangeGrob/grid.arrange is now based on gtable * tableGrob/grid.table is now based on gtable # gridExtra 1.0.0 (2014-10-05) ## CLEANUP * several buggy functions removed # gridExtra 0.9.1 (2012-08-09) ## FIX * small compatibility issue of arrangeGrob with new class of ggplot2 # gridExtra 0.9 (2012-01-06) ## FIX * dependencies in examples, imports and exports ## NEW * multipage output and ggsave support for grid.arrange # gridExtra 0.8.5 (2011-10-26) ## FIX * removed LazyLoad, deprecated in R>=2.14 ## NEW * stextGrob text with a backgroundgridExtra/inst/doc/0000755000176200001440000000000013154617417013736 5ustar liggesusersgridExtra/inst/doc/tableGrob.R0000644000176200001440000001537113154617416015770 0ustar liggesusers## ----setup, echo=FALSE, results='hide'----------------------------------- library(knitr) opts_chunk$set(message=FALSE, fig.width=4, fig.height=2) ## ----basic--------------------------------------------------------------- library(gridExtra) library(grid) d <- head(iris[,1:3]) grid.table(d) ## ----annotations, fig.height=3------------------------------------------- d[2,3] <- "this is very wwwwwide" d[1,2] <- "this\nis\ntall" colnames(d) <- c("alpha*integral(xdx,a,infinity)", "this text\nis high", 'alpha/beta') tt <- ttheme_default(colhead=list(fg_params = list(parse=TRUE))) grid.table(d, theme=tt) ## ----theme, fig.width=8-------------------------------------------------- tt1 <- ttheme_default() tt2 <- ttheme_minimal() tt3 <- ttheme_minimal( core=list(bg_params = list(fill = blues9[1:4], col=NA), fg_params=list(fontface=3)), colhead=list(fg_params=list(col="navyblue", fontface=4L)), rowhead=list(fg_params=list(col="orange", fontface=3L))) grid.arrange( tableGrob(iris[1:4, 1:2], theme=tt1), tableGrob(iris[1:4, 1:2], theme=tt2), tableGrob(iris[1:4, 1:2], theme=tt3), nrow=1) ## ----recycling----------------------------------------------------------- t1 <- ttheme_default(core=list( fg_params=list(fontface=c(rep("plain", 4), "bold.italic")), bg_params = list(fill=c(rep(c("grey95", "grey90"), length.out=4), "#6BAED6"), alpha = rep(c(1,0.5), each=5)) )) grid.table(iris[1:5, 1:3], theme = t1) ## ----justify, fig.width=8------------------------------------------------ tt1 <- ttheme_default() tt2 <- ttheme_default(core=list(fg_params=list(hjust=1, x=0.9)), rowhead=list(fg_params=list(hjust=1, x=0.95))) tt3 <- ttheme_default(core=list(fg_params=list(hjust=0, x=0.1)), rowhead=list(fg_params=list(hjust=0, x=0))) grid.arrange( tableGrob(mtcars[1:4, 1:2], theme=tt1), tableGrob(mtcars[1:4, 1:2], theme=tt2), tableGrob(mtcars[1:4, 1:2], theme=tt3), nrow=1) ## ----sizes, fig.width=8-------------------------------------------------- g <- g2 <- tableGrob(iris[1:4, 1:3], cols = NULL, rows=NULL) g2$widths <- unit(rep(1/ncol(g2), ncol(g2)), "npc") grid.arrange(rectGrob(), rectGrob(), nrow=1) grid.arrange(g, g2, nrow=1, newpage = FALSE) ## ----align, fig.width=6, fig.height=3------------------------------------ d1 <- PlantGrowth[1:3,1, drop=FALSE] d2 <- PlantGrowth[1:2,1:2] g1 <- tableGrob(d1) g2 <- tableGrob(d2) haligned <- gtable_combine(g1,g2, along=1) valigned <- gtable_combine(g1,g2, along=2) grid.newpage() grid.arrange(haligned, valigned, ncol=2) ## ----numberingDemo1------------------------------------------------------ library(gtable) g <- tableGrob(iris[1:4, 1:3], rows = NULL) g <- gtable_add_grob(g, grobs = rectGrob(gp = gpar(fill = NA, lwd = 2)), t = 2, b = nrow(g), l = 1, r = ncol(g)) g <- gtable_add_grob(g, grobs = rectGrob(gp = gpar(fill = NA, lwd = 2)), t = 1, l = 1, r = ncol(g)) grid.draw(g) ## ----numberingDemo2------------------------------------------------------ g <- tableGrob(iris[1:4, 1:3]) g <- gtable_add_grob(g, grobs = rectGrob(gp = gpar(fill = NA, lwd = 2)), t = 2, b = nrow(g), l = 1, r = ncol(g)) g <- gtable_add_grob(g, grobs = rectGrob(gp = gpar(fill = NA, lwd = 2)), t = 1, l = 1, r = ncol(g)) grid.draw(g) ## ----segments1----------------------------------------------------------- g <- tableGrob(iris[1:4, 1:3]) g <- gtable_add_grob(g, grobs = segmentsGrob( # line across the bottom x0 = unit(0,"npc"), y0 = unit(0,"npc"), x1 = unit(1,"npc"), y1 = unit(0,"npc"), gp = gpar(lwd = 2.0)), t = 3, b = 3, l = 3, r = 3) grid.draw(g) ## ----segments2----------------------------------------------------------- g <- tableGrob(iris[1:4, 1:3]) g <- gtable_add_grob(g, grobs = segmentsGrob( # line across the bottom x0 = unit(0,"npc"), y0 = unit(0,"npc"), x1 = unit(0,"npc"), y1 = unit(1,"npc"), gp = gpar(lwd = 2.0)), t = 3, b = 3, l = 3, r = 3) grid.draw(g) ## ----segments3----------------------------------------------------------- g <- tableGrob(iris[1:4, 1:3]) g <- gtable_add_grob(g, grobs = grobTree( segmentsGrob( # diagonal line ul -> lr x0 = unit(0,"npc"), y0 = unit(1,"npc"), x1 = unit(1,"npc"), y1 = unit(0,"npc"), gp = gpar(lwd = 2.0)), segmentsGrob( # diagonal line ll -> ur x0 = unit(0,"npc"), y0 = unit(0,"npc"), x1 = unit(1,"npc"), y1 = unit(1,"npc"), gp = gpar(lwd = 2.0))), t = 3, b = 3, l = 3, r = 3) grid.draw(g) ## ----separators, fig.width=8--------------------------------------------- g <- tableGrob(head(iris), theme = ttheme_minimal()) separators <- replicate(ncol(g) - 2, segmentsGrob(x1 = unit(0, "npc"), gp=gpar(lty=2)), simplify=FALSE) ## add vertical lines on the left side of columns (after 2nd) g <- gtable::gtable_add_grob(g, grobs = separators, t = 2, b = nrow(g), l = seq_len(ncol(g)-2)+2) grid.draw(g) ## ----highlight----------------------------------------------------------- g <- tableGrob(iris[1:4, 1:3]) find_cell <- function(table, row, col, name="core-fg"){ l <- table$layout which(l$t==row & l$l==col & l$name==name) } ind <- find_cell(g, 3, 2, "core-fg") ind2 <- find_cell(g, 2, 3, "core-bg") g$grobs[ind][[1]][["gp"]] <- gpar(fontsize=15, fontface="bold") g$grobs[ind2][[1]][["gp"]] <- gpar(fill="darkolivegreen1", col = "darkolivegreen4", lwd=5) grid.draw(g) ## ----ftable, fig.width=6------------------------------------------------- grid.ftable <- function(d, padding = unit(4, "mm"), ...) { nc <- ncol(d) nr <- nrow(d) ## character table with added row and column names extended_matrix <- cbind(c("", rownames(d)), rbind(colnames(d), as.matrix(d))) ## string width and height w <- apply(extended_matrix, 2, strwidth, "inch") h <- apply(extended_matrix, 2, strheight, "inch") widths <- apply(w, 2, max) heights <- apply(h, 1, max) padding <- convertUnit(padding, unitTo = "in", valueOnly = TRUE) x <- cumsum(widths + padding) - 0.5 * padding y <- cumsum(heights + padding) - padding rg <- rectGrob(x = unit(x - widths/2, "in"), y = unit(1, "npc") - unit(rep(y, each = nc + 1), "in"), width = unit(widths + padding, "in"), height = unit(heights + padding, "in")) tg <- textGrob(c(t(extended_matrix)), x = unit(x - widths/2, "in"), y = unit(1, "npc") - unit(rep(y, each = nc + 1), "in"), just = "center") g <- gTree(children = gList(rg, tg), ..., x = x, y = y, widths = widths, heights = heights) grid.draw(g) invisible(g) } grid.newpage() grid.ftable(head(iris, 4), gp = gpar(fill = rep(c("grey90", "grey95"), each = 6))) gridExtra/inst/doc/tableGrob.Rmd0000644000176200001440000002455613152370532016307 0ustar liggesusers--- title: "Displaying tables as grid graphics" author: "Baptiste Auguie" date: '`r Sys.Date()`' vignette: > %\VignetteEngine{knitr::rmarkdown} %\VignetteIndexEntry{tableGrob: displaying tables as grid graphics} output: knitr:::html_vignette: toc: yes --- ```{r setup, echo=FALSE, results='hide'} library(knitr) opts_chunk$set(message=FALSE, fig.width=4, fig.height=2) ``` Tabular data is usually formatted outside the graphics device, e.g via LaTeX, or html tables. However, in some cases it may be convenient to display *small* tables alongside graphics. A couple of packages offer this possibility with base graphics (`plotrix` for instance); the `gridExtra` provides the pair of `tableGrob/grid.table` functions for this purpose. *Note:* This vignette uses the development version of `gridExtra`, some features may not be yet available in the released version. ## Basic usage ```{r basic} library(gridExtra) library(grid) d <- head(iris[,1:3]) grid.table(d) ``` ## Spacing The spacing of each row/column is automatic, and will adjust to bigger cell contents. Plotmath notation may be used, with the `parse=TRUE` argument. Note that this is applied to individual strings of text, and reverts to standard text if parsing fails (this is useful when mixing multiline text with plotmath in different cells). ```{r annotations, fig.height=3} d[2,3] <- "this is very wwwwwide" d[1,2] <- "this\nis\ntall" colnames(d) <- c("alpha*integral(xdx,a,infinity)", "this text\nis high", 'alpha/beta') tt <- ttheme_default(colhead=list(fg_params = list(parse=TRUE))) grid.table(d, theme=tt) ``` ## Aesthetic formatting The formatting is controlled by *themes*, which are nested lists of graphical parameters. See `ttheme_default` and `ttheme_minimal` for two built-in examples. Changing a few parameters at a time amounts to modifying the list with the new values. ```{r theme, fig.width=8} tt1 <- ttheme_default() tt2 <- ttheme_minimal() tt3 <- ttheme_minimal( core=list(bg_params = list(fill = blues9[1:4], col=NA), fg_params=list(fontface=3)), colhead=list(fg_params=list(col="navyblue", fontface=4L)), rowhead=list(fg_params=list(col="orange", fontface=3L))) grid.arrange( tableGrob(iris[1:4, 1:2], theme=tt1), tableGrob(iris[1:4, 1:2], theme=tt2), tableGrob(iris[1:4, 1:2], theme=tt3), nrow=1) ``` If the formatting values are fewer than the number of cells, they are recycled along columns, ```{r recycling} t1 <- ttheme_default(core=list( fg_params=list(fontface=c(rep("plain", 4), "bold.italic")), bg_params = list(fill=c(rep(c("grey95", "grey90"), length.out=4), "#6BAED6"), alpha = rep(c(1,0.5), each=5)) )) grid.table(iris[1:5, 1:3], theme = t1) ``` ## Text justification The text labels can be justified; the default is "centre" for the core and header, and "right" for the row names. These settings can be adjusted by passing the relevant parameters of `textGrob` via the theme nested lists, ```{r justify, fig.width=8} tt1 <- ttheme_default() tt2 <- ttheme_default(core=list(fg_params=list(hjust=1, x=0.9)), rowhead=list(fg_params=list(hjust=1, x=0.95))) tt3 <- ttheme_default(core=list(fg_params=list(hjust=0, x=0.1)), rowhead=list(fg_params=list(hjust=0, x=0))) grid.arrange( tableGrob(mtcars[1:4, 1:2], theme=tt1), tableGrob(mtcars[1:4, 1:2], theme=tt2), tableGrob(mtcars[1:4, 1:2], theme=tt3), nrow=1) ``` ## Further gtable processing and integration Being based on `gtable`, the table can be further processed. In particular, we may edit the cell sizes to align with other content on the page. ```{r sizes, fig.width=8} g <- g2 <- tableGrob(iris[1:4, 1:3], cols = NULL, rows=NULL) g2$widths <- unit(rep(1/ncol(g2), ncol(g2)), "npc") grid.arrange(rectGrob(), rectGrob(), nrow=1) grid.arrange(g, g2, nrow=1, newpage = FALSE) ``` The alignment of several tables can be achieved with the `combine` function (adapted from `gtable:::join`), ```{r align, fig.width=6, fig.height=3} d1 <- PlantGrowth[1:3,1, drop=FALSE] d2 <- PlantGrowth[1:2,1:2] g1 <- tableGrob(d1) g2 <- tableGrob(d2) haligned <- gtable_combine(g1,g2, along=1) valigned <- gtable_combine(g1,g2, along=2) grid.newpage() grid.arrange(haligned, valigned, ncol=2) ``` ### Borders and separators Other grobs such as separating lines and rectangles (borders, boxes) may be added. In this case, keep in mind that row, column and cell numbering includes the column of row labels and the row of column labels *if they are present.* Let us illustrate this by adding some borders (using `rectGrob`) to a simple table without row numbers. We'll add two actually, to give a nice effect of a heavy line under the row of column headers. ```{r numberingDemo1} library(gtable) g <- tableGrob(iris[1:4, 1:3], rows = NULL) g <- gtable_add_grob(g, grobs = rectGrob(gp = gpar(fill = NA, lwd = 2)), t = 2, b = nrow(g), l = 1, r = ncol(g)) g <- gtable_add_grob(g, grobs = rectGrob(gp = gpar(fill = NA, lwd = 2)), t = 1, l = 1, r = ncol(g)) grid.draw(g) ``` Note that when using `rectGrob` the top, bottom, left and right arguments (`t, b, l, r`) are the rows and columns which will be *inside* the rectangle. If we repeat the above code almost exactly, but don't suppress the column of row labels, we see that column 1 is now the column of row labels (and it doesn't look that good either, but that's not our point). ```{r numberingDemo2} g <- tableGrob(iris[1:4, 1:3]) g <- gtable_add_grob(g, grobs = rectGrob(gp = gpar(fill = NA, lwd = 2)), t = 2, b = nrow(g), l = 1, r = ncol(g)) g <- gtable_add_grob(g, grobs = rectGrob(gp = gpar(fill = NA, lwd = 2)), t = 1, l = 1, r = ncol(g)) grid.draw(g) ``` When adding line segments to separate rows and columns using `segmentsGrob`, the row and column numbering scheme is the same (it includes any row or column labels). When working with line segments, you should keep in mind the default coordinate values for `segmentsGrob`. They are x0 = 0, y0 = 0, x1 = 1, y1 = 1, all in npc, relative to the cell(s) you are modifying, with the lower left corner being 0,0. For clarity, we show all the arguments in these examples. With this in mind, to add a line across the bottom of a single cell, use: ```{r segments1 } g <- tableGrob(iris[1:4, 1:3]) g <- gtable_add_grob(g, grobs = segmentsGrob( # line across the bottom x0 = unit(0,"npc"), y0 = unit(0,"npc"), x1 = unit(1,"npc"), y1 = unit(0,"npc"), gp = gpar(lwd = 2.0)), t = 3, b = 3, l = 3, r = 3) grid.draw(g) ``` and to add a line to the left side: ```{r segments2 } g <- tableGrob(iris[1:4, 1:3]) g <- gtable_add_grob(g, grobs = segmentsGrob( # line across the bottom x0 = unit(0,"npc"), y0 = unit(0,"npc"), x1 = unit(0,"npc"), y1 = unit(1,"npc"), gp = gpar(lwd = 2.0)), t = 3, b = 3, l = 3, r = 3) grid.draw(g) ``` Perhaps you'd like to cross out a cell. This can be done with two diagonal lines combined via a `grobTree`: ```{r segments3} g <- tableGrob(iris[1:4, 1:3]) g <- gtable_add_grob(g, grobs = grobTree( segmentsGrob( # diagonal line ul -> lr x0 = unit(0,"npc"), y0 = unit(1,"npc"), x1 = unit(1,"npc"), y1 = unit(0,"npc"), gp = gpar(lwd = 2.0)), segmentsGrob( # diagonal line ll -> ur x0 = unit(0,"npc"), y0 = unit(0,"npc"), x1 = unit(1,"npc"), y1 = unit(1,"npc"), gp = gpar(lwd = 2.0))), t = 3, b = 3, l = 3, r = 3) grid.draw(g) ``` If you have many cells to decorate you can use `replicate` to create create the segments. Just keep the `tableGrob` numbering scheme in mind. ```{r separators, fig.width=8} g <- tableGrob(head(iris), theme = ttheme_minimal()) separators <- replicate(ncol(g) - 2, segmentsGrob(x1 = unit(0, "npc"), gp=gpar(lty=2)), simplify=FALSE) ## add vertical lines on the left side of columns (after 2nd) g <- gtable::gtable_add_grob(g, grobs = separators, t = 2, b = nrow(g), l = seq_len(ncol(g)-2)+2) grid.draw(g) ``` ### Accessing existing grobs in the table We may also access and modify the original content of individual cells, e.g. to highlight a value. ```{r highlight} g <- tableGrob(iris[1:4, 1:3]) find_cell <- function(table, row, col, name="core-fg"){ l <- table$layout which(l$t==row & l$l==col & l$name==name) } ind <- find_cell(g, 3, 2, "core-fg") ind2 <- find_cell(g, 2, 3, "core-bg") g$grobs[ind][[1]][["gp"]] <- gpar(fontsize=15, fontface="bold") g$grobs[ind2][[1]][["gp"]] <- gpar(fill="darkolivegreen1", col = "darkolivegreen4", lwd=5) grid.draw(g) ``` ## Faster tables: an alternative grid function The `tableGrob` function can be very slow; unfortunately this is the price to pay for its versatility and easier implementation. We use individual `textGrob` and `rectGrob` elements for each cell, instead of relying on the vectorised implementation of these functions. The reason is practical: it is much easier to place, measure, and customise individual grobs, than modify the graphical parameters and positions of a single vectorised grob. An alternative function is presented below, using this vectorised approach, but lacking many of the customisations of `tableGrob`. ```{r ftable, fig.width=6} grid.ftable <- function(d, padding = unit(4, "mm"), ...) { nc <- ncol(d) nr <- nrow(d) ## character table with added row and column names extended_matrix <- cbind(c("", rownames(d)), rbind(colnames(d), as.matrix(d))) ## string width and height w <- apply(extended_matrix, 2, strwidth, "inch") h <- apply(extended_matrix, 2, strheight, "inch") widths <- apply(w, 2, max) heights <- apply(h, 1, max) padding <- convertUnit(padding, unitTo = "in", valueOnly = TRUE) x <- cumsum(widths + padding) - 0.5 * padding y <- cumsum(heights + padding) - padding rg <- rectGrob(x = unit(x - widths/2, "in"), y = unit(1, "npc") - unit(rep(y, each = nc + 1), "in"), width = unit(widths + padding, "in"), height = unit(heights + padding, "in")) tg <- textGrob(c(t(extended_matrix)), x = unit(x - widths/2, "in"), y = unit(1, "npc") - unit(rep(y, each = nc + 1), "in"), just = "center") g <- gTree(children = gList(rg, tg), ..., x = x, y = y, widths = widths, heights = heights) grid.draw(g) invisible(g) } grid.newpage() grid.ftable(head(iris, 4), gp = gpar(fill = rep(c("grey90", "grey95"), each = 6))) ``` gridExtra/inst/doc/gtable.html0000644000176200001440000052206613154617413016071 0ustar liggesusers (Unofficial) overview of gtable

(Unofficial) overview of gtable

Baptiste Auguie

2017-09-09

The R package gtable is designed to help construct and manipulate layouts containing graphical elements. The standard grid package in R provides low-level functions to define viewports, and place graphical elements (grobs) at specific locations within the device window. gtable builds upon these functions and provides a higher-level interface, where one can e.g. merge two layouts, add columns, rows, insert graphical elements in a given cell, and change the display order, among other things.

The gtable package is used internally by ggplot2, and can therefore be used to modify the layout of such plots.

Constructing a gtable

A gtable object can be constructed in a variety of ways,

gtable(unit(1:3, c("cm")), unit(5, "cm"))

This is an empty table with 3 rows and one column. gtable_col and gtable_row provide a simplified interface for 1 column or 1 row layouts, respectively.

a <- rectGrob(gp = gpar(fill = "red"))
b <- grobTree(rectGrob(), textGrob("new\ncell"))
c <- ggplotGrob(qplot(1:10,1:10))
d <- linesGrob()
mat <- matrix(list(a, b, c, d), nrow = 2)
g <- gtable_matrix(name = "demo", grobs = mat, 
                   widths = unit(c(2, 4), "cm"), 
                   heights = unit(c(2, 5), c("in", "lines")))
g
## TableGrob (2 x 2) "demo": 4 grobs
##   z     cells name                  grob
## 1 1 (1-1,1-1) demo   rect[GRID.rect.583]
## 2 2 (2-2,1-1) demo gTree[GRID.gTree.584]
## 3 3 (1-1,2-2) demo        gtable[layout]
## 4 4 (2-2,2-2) demo lines[GRID.lines.629]

Actual drawing of the gtable on a graphics device is performed with grid.draw(); note that plot() is only defined for debugging purposes, it adds a light grey background and thin grid lines to help visualise the scene in its drawing context.

plot(g)

grid.newpage()
grid.draw(g)

The gridExtra package provides a few conventient constructor functions, e.g.

dummy_grob <- function(id)  {
  grobTree(rectGrob(gp=gpar(fill=id, alpha=0.5)), textGrob(id))
}
gs <- lapply(1:9, dummy_grob)
grid.arrange(ncol=4, grobs=gs, 
               top="top\nlabel", bottom="bottom\nlabel", 
               left="left\nlabel", right="right\nlabel")
grid.rect(gp=gpar(fill=NA))

gt <- arrangeGrob(grobs=gs, layout_matrix=rbind(c(1,1,1,2,3),
                                           c(1,1,1,4,5),
                                           c(6,7,8,9,9)))
grid.draw(gt)
grid.rect(gp=gpar(fill=NA))

Components of a gtable

Let’s have a closer look at the gtable we created earlier.

print(g)
## TableGrob (2 x 2) "demo": 4 grobs
##   z     cells name                  grob
## 1 1 (1-1,1-1) demo   rect[GRID.rect.583]
## 2 2 (2-2,1-1) demo gTree[GRID.gTree.584]
## 3 3 (1-1,2-2) demo        gtable[layout]
## 4 4 (2-2,2-2) demo lines[GRID.lines.629]
names(g)
##  [1] "grobs"         "layout"        "widths"        "heights"      
##  [5] "respect"       "rownames"      "colnames"      "name"         
##  [9] "gp"            "vp"            "children"      "childrenOrder"

Other useful characteristics of the gtable are,

length(g); nrow(g); ncol(g)
## [1] 4
## [1] 2
## [1] 2

where we note the dual nature of a gtable: it looks like a matrix, in the sense that it defines a rectangular table of nrow x ncol cells, but it’s also a list with an arbitrary length, defining where and how many grobs are to be placed in this tabular layout.

The most important components are,

length(g$grobs)
## [1] 4
g$layout
##   t l b r z clip name
## 1 1 1 1 1 1   on demo
## 2 2 1 2 1 2   on demo
## 3 1 2 1 2 3   on demo
## 4 2 2 2 2 4   on demo

The z-column is used to define the drawing order of the grobs, which becomes relevant when multiple grobs are stacked on top of each others. * widths and heights: this is the size description of the cells, given as grid units.

g$widths; g$heights
## [1] 2cm 4cm
## [1] 2in    5lines

Modifying a gtable

The gtable package defines several high-level functions to operate on a gtable object,

Manual operations at the low-level on the gtable can involve the grobs or the layout, but care should be taken to keep the two consistent (e.g. make sure that the length of both are in sync).

Examples to alter ggplot2 plots with gtable

The gtable tag on Stack Overlfow has several real-life examples using gtable to alter a ggplot2 before drawing.

gridExtra/inst/doc/arrangeGrob.R0000644000176200001440000000374213154617410016311 0ustar liggesusers## ----setup, echo=FALSE, results='hide'----------------------------------- library(knitr) opts_chunk$set(message=FALSE, fig.width=4, fig.height=3) ## ----basic--------------------------------------------------------------- library(gridExtra) library(grid) library(ggplot2) library(lattice) p <- qplot(1,1) p2 <- xyplot(1~1) r <- rectGrob(gp=gpar(fill="grey90")) t <- textGrob("text") grid.arrange(t, p, p2, r, ncol=2) ## ----annotations--------------------------------------------------------- gs <- lapply(1:9, function(ii) grobTree(rectGrob(gp=gpar(fill=ii, alpha=0.5)), textGrob(ii))) grid.arrange(grobs=gs, ncol=4, top="top label", bottom="bottom\nlabel", left="left label", right="right label") grid.rect(gp=gpar(fill=NA)) ## ----layout-------------------------------------------------------------- lay <- rbind(c(1,1,1,2,3), c(1,1,1,4,5), c(6,7,8,9,9)) grid.arrange(grobs = gs, layout_matrix = lay) ## ----holes--------------------------------------------------------------- hlay <- rbind(c(1,1,NA,2,3), c(1,1,NA,4,NA), c(NA,7,8,9,NA)) select_grobs <- function(lay) { id <- unique(c(t(lay))) id[!is.na(id)] } grid.arrange(grobs=gs[select_grobs(hlay)], layout_matrix=hlay) ## ----sizes, fig.height=2------------------------------------------------- grid.arrange(grobs=gs[1:3], ncol=2, widths = 1:2, heights=unit(c(1,10), c("in", "mm"))) ## ----grob---------------------------------------------------------------- g1 <- arrangeGrob(grobs = gs, layout_matrix = t(lay)) g2 <- arrangeGrob(grobs = gs, layout_matrix = lay) grid.arrange(g1, g2, ncol=2) ## ----marrange------------------------------------------------------------ set.seed(123) pl <- lapply(1:11, function(.x) qplot(1:10, rnorm(10), main=paste("plot", .x))) ml <- marrangeGrob(pl, nrow=2, ncol=2) ## non-interactive use, multipage pdf ## ggsave("multipage.pdf", ml) ## interactive use; calling `dev.new` multiple times ml gridExtra/inst/doc/arrangeGrob.html0000644000176200001440000152050713154617411017061 0ustar liggesusers Arranging multiple grobs on a page

Arranging multiple grobs on a page

Baptiste Auguie

2017-09-09

The grid package provides low-level functions to create graphical objects (grobs), and position them on a page in specific viewports. The gtable package introduced a higher-level layout scheme, arguably more amenable to user-level interaction. With the arrangeGrob/grid.arrange() pair of functions, gridExtra builds upon gtable to arrange multiple grobs on a page.

Basic usage

In this example we mix a few grobs and plots,

library(gridExtra)
library(grid)
library(ggplot2)
library(lattice)
p <- qplot(1,1)
p2 <- xyplot(1~1)
r <- rectGrob(gp=gpar(fill="grey90"))
t <- textGrob("text")
grid.arrange(t, p, p2, r, ncol=2)

Title and/or annotations

gs <- lapply(1:9, function(ii) 
  grobTree(rectGrob(gp=gpar(fill=ii, alpha=0.5)), textGrob(ii)))
grid.arrange(grobs=gs, ncol=4, 
               top="top label", bottom="bottom\nlabel", 
               left="left label", right="right label")
grid.rect(gp=gpar(fill=NA))

Complex layouts

We can provide a matrix defining the layout,

lay <- rbind(c(1,1,1,2,3),
             c(1,1,1,4,5),
             c(6,7,8,9,9))
grid.arrange(grobs = gs, layout_matrix = lay)

The layout itself may contain holes, but note that for any given grob index the region must be simply connected (no hole),

hlay <- rbind(c(1,1,NA,2,3),
              c(1,1,NA,4,NA),
              c(NA,7,8,9,NA))
select_grobs <- function(lay) {
  id <- unique(c(t(lay))) 
  id[!is.na(id)]
} 
grid.arrange(grobs=gs[select_grobs(hlay)], layout_matrix=hlay)

All cells are of equal size by default, but users may pass explicity widths and/or heights in any valid grid units, or as relative numbers (interpreted as null),

grid.arrange(grobs=gs[1:3], ncol=2, widths = 1:2, 
             heights=unit(c(1,10), c("in", "mm")))

Nested layouts with arrangeGrob

The grid.arrange() function draws on the device; for more complex layouts, we may want to store the gtable and combine it with other objects, e.g. forming nested layouts. To this end, use arrangeGrob(),

g1 <- arrangeGrob(grobs = gs, layout_matrix = t(lay))
g2 <- arrangeGrob(grobs = gs, layout_matrix = lay)
grid.arrange(g1, g2, ncol=2)

Multiple pages output

Finally, we may want to place grobs on multiple pages; the marrangeGrob() function provides a convenient interface for this, also compatible with ggsave().

set.seed(123)
pl <- lapply(1:11, function(.x) 
             qplot(1:10, rnorm(10), main=paste("plot", .x)))
ml <- marrangeGrob(pl, nrow=2, ncol=2)
## non-interactive use, multipage pdf
## ggsave("multipage.pdf", ml)
## interactive use; calling `dev.new` multiple times
ml

gridExtra/inst/doc/gtable.Rmd0000644000176200001440000001247413152370370015640 0ustar liggesusers--- title: "(Unofficial) overview of gtable" author: "Baptiste Auguie" date: '`r Sys.Date()`' vignette: > %\VignetteEngine{knitr::rmarkdown} %\VignetteIndexEntry{(Unofficial) overview of gtable} output: knitr:::html_vignette: toc: yes --- ```{r setup, echo=FALSE,message=FALSE} require(knitr) opts_chunk$set(fig.width=3,fig.height=3, tidy=FALSE, cache=FALSE, fig.path='gtable/') require(gridExtra) require(grid) require(gtable) require(ggplot2) ``` The R package `gtable` is designed to help construct and manipulate layouts containing graphical elements. The standard `grid` package in R provides low-level functions to define viewports, and place graphical elements (grobs) at specific locations within the device window. `gtable` builds upon these functions and provides a higher-level interface, where one can e.g. merge two layouts, add columns, rows, insert graphical elements in a given cell, and change the display order, among other things. The `gtable` package is used internally by `ggplot2`, and can therefore be used to modify the layout of such plots. ### Constructing a gtable A `gtable` object can be constructed in a variety of ways, * Empty table ```{r, eval=FALSE} gtable(unit(1:3, c("cm")), unit(5, "cm")) ``` This is an empty table with 3 rows and one column. `gtable_col` and `gtable_row` provide a simplified interface for 1 column or 1 row layouts, respectively. * matrix layout of grobs ```{r matrix} a <- rectGrob(gp = gpar(fill = "red")) b <- grobTree(rectGrob(), textGrob("new\ncell")) c <- ggplotGrob(qplot(1:10,1:10)) d <- linesGrob() mat <- matrix(list(a, b, c, d), nrow = 2) g <- gtable_matrix(name = "demo", grobs = mat, widths = unit(c(2, 4), "cm"), heights = unit(c(2, 5), c("in", "lines"))) g ``` Actual drawing of the gtable on a graphics device is performed with `grid.draw()`; note that `plot()` is only defined for debugging purposes, it adds a light grey background and thin grid lines to help visualise the scene in its drawing context. ```{r plot} plot(g) grid.newpage() grid.draw(g) ``` The gridExtra package provides a few conventient constructor functions, e.g. * based on `grid.arrange` ```{r gtable_arrange} dummy_grob <- function(id) { grobTree(rectGrob(gp=gpar(fill=id, alpha=0.5)), textGrob(id)) } gs <- lapply(1:9, dummy_grob) grid.arrange(ncol=4, grobs=gs, top="top\nlabel", bottom="bottom\nlabel", left="left\nlabel", right="right\nlabel") grid.rect(gp=gpar(fill=NA)) ``` * with a pre-defined layout ```{r gtable_from_layout} gt <- arrangeGrob(grobs=gs, layout_matrix=rbind(c(1,1,1,2,3), c(1,1,1,4,5), c(6,7,8,9,9))) grid.draw(gt) grid.rect(gp=gpar(fill=NA)) ``` ### Components of a gtable Let's have a closer look at the gtable we created earlier. ```{r} print(g) names(g) ``` Other useful characteristics of the gtable are, ```{r} length(g); nrow(g); ncol(g) ``` where we note the dual nature of a gtable: it looks like a matrix, in the sense that it defines a rectangular table of nrow x ncol cells, but it's also a _list_ with an arbitrary length, defining where and how many grobs are to be placed in this tabular layout. The most important components are, * `grobs`: This is a list of grobs of `length(g)`. Grobs are placed in the tabular layout defined by the gtable, and multiple grobs can overlap and/or be stacked in the same cell(s). ```{r} length(g$grobs) ``` * `layout`: this is a data.frame indicating the position of each grob. ```{r} g$layout ``` The z-column is used to define the drawing order of the grobs, which becomes relevant when multiple grobs are stacked on top of each others. * `widths` and `heights`: this is the size description of the cells, given as grid units. ```{r} g$widths; g$heights ``` ### Modifying a gtable The gtable package defines several high-level functions to operate on a gtable object, * `t.gtable` to transpose the layout (future versions may support more general rotations) * `[.gtable*`, `gtable_filter`, `gtable_trim` to extract a portion of the gtable * `cbind.gtable*`, `rbind.gtable*` to combine 2 gtable objects (particularly useful for aligning multiple ggplots) * `gtable_add_cols`, `gtable_add_rows`,`gtable_add_col_space`, `gtable_add_row_space`, `gtable_add_padding`, `gtable_col_spacer`, `gtable_row_spacer` Manual operations at the low-level on the gtable can involve the grobs or the layout, but care should be taken to keep the two consistent (e.g. make sure that the length of both are in sync). #### Examples to alter ggplot2 plots with gtable The `gtable` tag on Stack Overlfow has several real-life examples using gtable to alter a ggplot2 before drawing. * aligning (multiple) [ggplot objects on a device](http://stackoverflow.com/a/17768224/471093), another [use-case scenario](http://stackoverflow.com/a/16798372/471093), aligning [base plot and ggplot](http://stackoverflow.com/a/14233531/471093) * adding new grobs [aligned with the plot panel](http://stackoverflow.com/a/17371177/471093), also [this one](http://stackoverflow.com/a/17493256/471093) * calculate [the device size based on the plot aspect ratio](http://stackoverflow.com/a/16442029/471093) * add [new axes to a facet_grid layout](http://stackoverflow.com/a/17661337/471093), or a [second axis](http://stackoverflow.com/a/18511024/471093)gridExtra/inst/doc/arrangeGrob.rmd0000644000176200001440000000607413152370123016666 0ustar liggesusers--- title: "Arranging multiple grobs on a page" author: "Baptiste Auguie" date: '`r Sys.Date()`' vignette: > %\VignetteEngine{knitr::rmarkdown} %\VignetteIndexEntry{arrangeGrob: arranging multiple grobs on a page} output: knitr:::html_vignette: toc: yes --- ```{r setup, echo=FALSE, results='hide'} library(knitr) opts_chunk$set(message=FALSE, fig.width=4, fig.height=3) ``` The `grid` package provides low-level functions to create graphical objects (`grobs`), and position them on a page in specific `viewports`. The `gtable` package introduced a higher-level layout scheme, arguably more amenable to user-level interaction. With the `arrangeGrob/grid.arrange()` pair of functions, `gridExtra` builds upon `gtable` to arrange multiple grobs on a page. ## Basic usage In this example we mix a few grobs and plots, ```{r basic} library(gridExtra) library(grid) library(ggplot2) library(lattice) p <- qplot(1,1) p2 <- xyplot(1~1) r <- rectGrob(gp=gpar(fill="grey90")) t <- textGrob("text") grid.arrange(t, p, p2, r, ncol=2) ``` ## Title and/or annotations ```{r annotations} gs <- lapply(1:9, function(ii) grobTree(rectGrob(gp=gpar(fill=ii, alpha=0.5)), textGrob(ii))) grid.arrange(grobs=gs, ncol=4, top="top label", bottom="bottom\nlabel", left="left label", right="right label") grid.rect(gp=gpar(fill=NA)) ``` ## Complex layouts We can provide a matrix defining the layout, ```{r layout} lay <- rbind(c(1,1,1,2,3), c(1,1,1,4,5), c(6,7,8,9,9)) grid.arrange(grobs = gs, layout_matrix = lay) ``` The layout itself may contain holes, but note that for any given grob index the region must be simply connected (no hole), ```{r holes} hlay <- rbind(c(1,1,NA,2,3), c(1,1,NA,4,NA), c(NA,7,8,9,NA)) select_grobs <- function(lay) { id <- unique(c(t(lay))) id[!is.na(id)] } grid.arrange(grobs=gs[select_grobs(hlay)], layout_matrix=hlay) ``` All cells are of equal size by default, but users may pass explicity `widths` and/or `heights` in any valid grid units, or as relative numbers (interpreted as `null`), ```{r sizes, fig.height=2} grid.arrange(grobs=gs[1:3], ncol=2, widths = 1:2, heights=unit(c(1,10), c("in", "mm"))) ``` ## Nested layouts with `arrangeGrob` The `grid.arrange()` function draws on the device; for more complex layouts, we may want to store the gtable and combine it with other objects, e.g. forming nested layouts. To this end, use `arrangeGrob()`, ```{r grob} g1 <- arrangeGrob(grobs = gs, layout_matrix = t(lay)) g2 <- arrangeGrob(grobs = gs, layout_matrix = lay) grid.arrange(g1, g2, ncol=2) ``` ## Multiple pages output Finally, we may want to place grobs on multiple pages; the `marrangeGrob()` function provides a convenient interface for this, also compatible with `ggsave()`. ```{r marrange} set.seed(123) pl <- lapply(1:11, function(.x) qplot(1:10, rnorm(10), main=paste("plot", .x))) ml <- marrangeGrob(pl, nrow=2, ncol=2) ## non-interactive use, multipage pdf ## ggsave("multipage.pdf", ml) ## interactive use; calling `dev.new` multiple times ml ``` gridExtra/inst/doc/ngonGrob.R0000644000176200001440000000223213154617413015627 0ustar liggesusers## ----setup, echo=FALSE, results='hide'----------------------------------- library(knitr) opts_chunk$set(message=FALSE, fig.width=4, fig.height=3) ## ----basic--------------------------------------------------------------- library(gridExtra) library(grid) library(grid) N <- 5 xy <- polygon_regular(N)*2 # draw multiple polygons g <- ngonGrob(unit(xy[,1],"cm") + unit(0.5,"npc"), unit(xy[,2],"cm") + unit(0.5,"npc"), n=seq_len(N)+2, gp=gpar(fill=1:N)) grid.newpage() grid.draw(g) ## ----rotated------------------------------------------------------------- g2 <- ngonGrob(unit(xy[,1],"cm") + unit(0.5,"npc"), unit(xy[,2],"cm") + unit(0.5,"npc"), n=seq_len(N)+2, ar=seq_len(N), phase=0, angle=pi/(seq_len(N)+2), size=1:N+5, gp=gpar(fill=1:N)) grid.newpage() grid.draw(g2) ## ----ellipse------------------------------------------------------------- g3 <- ellipseGrob(unit(xy[,1],"cm") + unit(0.5,"npc"), unit(xy[,2],"cm") + unit(0.5,"npc"), angle=-2*seq(0,N-1)*pi/N+pi/2, size=5, ar=3, gp=gpar(fill=1:N)) grid.newpage() grid.draw(g3) gridExtra/inst/doc/gtable.R0000644000176200001440000000400213154617412015306 0ustar liggesusers## ----setup, echo=FALSE,message=FALSE------------------------------------- require(knitr) opts_chunk$set(fig.width=3,fig.height=3, tidy=FALSE, cache=FALSE, fig.path='gtable/') require(gridExtra) require(grid) require(gtable) require(ggplot2) ## ---- eval=FALSE--------------------------------------------------------- # gtable(unit(1:3, c("cm")), unit(5, "cm")) ## ----matrix-------------------------------------------------------------- a <- rectGrob(gp = gpar(fill = "red")) b <- grobTree(rectGrob(), textGrob("new\ncell")) c <- ggplotGrob(qplot(1:10,1:10)) d <- linesGrob() mat <- matrix(list(a, b, c, d), nrow = 2) g <- gtable_matrix(name = "demo", grobs = mat, widths = unit(c(2, 4), "cm"), heights = unit(c(2, 5), c("in", "lines"))) g ## ----plot---------------------------------------------------------------- plot(g) grid.newpage() grid.draw(g) ## ----gtable_arrange------------------------------------------------------ dummy_grob <- function(id) { grobTree(rectGrob(gp=gpar(fill=id, alpha=0.5)), textGrob(id)) } gs <- lapply(1:9, dummy_grob) grid.arrange(ncol=4, grobs=gs, top="top\nlabel", bottom="bottom\nlabel", left="left\nlabel", right="right\nlabel") grid.rect(gp=gpar(fill=NA)) ## ----gtable_from_layout-------------------------------------------------- gt <- arrangeGrob(grobs=gs, layout_matrix=rbind(c(1,1,1,2,3), c(1,1,1,4,5), c(6,7,8,9,9))) grid.draw(gt) grid.rect(gp=gpar(fill=NA)) ## ------------------------------------------------------------------------ print(g) names(g) ## ------------------------------------------------------------------------ length(g); nrow(g); ncol(g) ## ------------------------------------------------------------------------ length(g$grobs) ## ------------------------------------------------------------------------ g$layout ## ------------------------------------------------------------------------ g$widths; g$heights gridExtra/inst/doc/ngonGrob.Rmd0000644000176200001440000000304613152370460016150 0ustar liggesusers--- title: "Regular polygons and ellipses in grid graphics" author: "Baptiste Auguie" date: '`r Sys.Date()`' vignette: > %\VignetteEngine{knitr::rmarkdown} %\VignetteIndexEntry{ngonGrob: regular polygons and ellipses in grid graphics} output: knitr:::html_vignette: toc: yes --- ```{r setup, echo=FALSE, results='hide'} library(knitr) opts_chunk$set(message=FALSE, fig.width=4, fig.height=3) ``` The `gridExtra` package provides a basic implementation of regular polygons, `ngonGrob()/grid.ngon`, and a convenience function to draw ellipses, `ellipseGrob()/grid.ellipse()`. We illustrate below the basic usage of these vectorised functions. ## Basic usage ```{r basic} library(gridExtra) library(grid) library(grid) N <- 5 xy <- polygon_regular(N)*2 # draw multiple polygons g <- ngonGrob(unit(xy[,1],"cm") + unit(0.5,"npc"), unit(xy[,2],"cm") + unit(0.5,"npc"), n=seq_len(N)+2, gp=gpar(fill=1:N)) grid.newpage() grid.draw(g) ``` ## Rotated and stretched polygons ```{r rotated} g2 <- ngonGrob(unit(xy[,1],"cm") + unit(0.5,"npc"), unit(xy[,2],"cm") + unit(0.5,"npc"), n=seq_len(N)+2, ar=seq_len(N), phase=0, angle=pi/(seq_len(N)+2), size=1:N+5, gp=gpar(fill=1:N)) grid.newpage() grid.draw(g2) ``` ## Ellipses ```{r ellipse} g3 <- ellipseGrob(unit(xy[,1],"cm") + unit(0.5,"npc"), unit(xy[,2],"cm") + unit(0.5,"npc"), angle=-2*seq(0,N-1)*pi/N+pi/2, size=5, ar=3, gp=gpar(fill=1:N)) grid.newpage() grid.draw(g3) ``` gridExtra/inst/doc/tableGrob.html0000644000176200001440000322432113154617417016534 0ustar liggesusers Displaying tables as grid graphics

Displaying tables as grid graphics

Baptiste Auguie

2017-09-09

Tabular data is usually formatted outside the graphics device, e.g via LaTeX, or html tables. However, in some cases it may be convenient to display small tables alongside graphics. A couple of packages offer this possibility with base graphics (plotrix for instance); the gridExtra provides the pair of tableGrob/grid.table functions for this purpose.

Note: This vignette uses the development version of gridExtra, some features may not be yet available in the released version.

Basic usage

library(gridExtra)
library(grid)
d <- head(iris[,1:3])
grid.table(d)

Spacing

The spacing of each row/column is automatic, and will adjust to bigger cell contents. Plotmath notation may be used, with the parse=TRUE argument. Note that this is applied to individual strings of text, and reverts to standard text if parsing fails (this is useful when mixing multiline text with plotmath in different cells).

d[2,3] <- "this is very wwwwwide"
d[1,2] <- "this\nis\ntall"
colnames(d) <- c("alpha*integral(xdx,a,infinity)",
                 "this text\nis high", 'alpha/beta')

tt <- ttheme_default(colhead=list(fg_params = list(parse=TRUE)))
grid.table(d, theme=tt)

Aesthetic formatting

The formatting is controlled by themes, which are nested lists of graphical parameters. See ttheme_default and ttheme_minimal for two built-in examples. Changing a few parameters at a time amounts to modifying the list with the new values.

tt1 <- ttheme_default()
tt2 <- ttheme_minimal()
tt3 <- ttheme_minimal(
  core=list(bg_params = list(fill = blues9[1:4], col=NA),
            fg_params=list(fontface=3)),
  colhead=list(fg_params=list(col="navyblue", fontface=4L)),
  rowhead=list(fg_params=list(col="orange", fontface=3L)))

grid.arrange(
  tableGrob(iris[1:4, 1:2], theme=tt1),
  tableGrob(iris[1:4, 1:2], theme=tt2),
  tableGrob(iris[1:4, 1:2], theme=tt3),
  nrow=1)

If the formatting values are fewer than the number of cells, they are recycled along columns,

t1 <- ttheme_default(core=list(
        fg_params=list(fontface=c(rep("plain", 4), "bold.italic")),
        bg_params = list(fill=c(rep(c("grey95", "grey90"),
                                    length.out=4), "#6BAED6"),
                         alpha = rep(c(1,0.5), each=5))
        ))

grid.table(iris[1:5, 1:3], theme = t1)

Text justification

The text labels can be justified; the default is “centre†for the core and header, and “right†for the row names. These settings can be adjusted by passing the relevant parameters of textGrob via the theme nested lists,

tt1 <- ttheme_default()
tt2 <- ttheme_default(core=list(fg_params=list(hjust=1, x=0.9)),
                      rowhead=list(fg_params=list(hjust=1, x=0.95)))
tt3 <- ttheme_default(core=list(fg_params=list(hjust=0, x=0.1)),
                      rowhead=list(fg_params=list(hjust=0, x=0)))
grid.arrange(
  tableGrob(mtcars[1:4, 1:2], theme=tt1),
  tableGrob(mtcars[1:4, 1:2], theme=tt2),
  tableGrob(mtcars[1:4, 1:2], theme=tt3),
  nrow=1)

Further gtable processing and integration

Being based on gtable, the table can be further processed. In particular, we may edit the cell sizes to align with other content on the page.

g <- g2 <- tableGrob(iris[1:4, 1:3], cols = NULL, rows=NULL)
g2$widths <- unit(rep(1/ncol(g2), ncol(g2)), "npc")
grid.arrange(rectGrob(), rectGrob(), nrow=1)
grid.arrange(g, g2, nrow=1, newpage = FALSE)

The alignment of several tables can be achieved with the combine function (adapted from gtable:::join),

d1 <- PlantGrowth[1:3,1, drop=FALSE]
d2 <- PlantGrowth[1:2,1:2]

g1 <- tableGrob(d1)
g2 <- tableGrob(d2)

haligned <- gtable_combine(g1,g2, along=1)
valigned <- gtable_combine(g1,g2, along=2)
grid.newpage()
grid.arrange(haligned, valigned, ncol=2)

Borders and separators

Other grobs such as separating lines and rectangles (borders, boxes) may be added. In this case, keep in mind that row, column and cell numbering includes the column of row labels and the row of column labels if they are present. Let us illustrate this by adding some borders (using rectGrob) to a simple table without row numbers. We’ll add two actually, to give a nice effect of a heavy line under the row of column headers.

library(gtable)
g <- tableGrob(iris[1:4, 1:3], rows = NULL)
g <- gtable_add_grob(g,
        grobs = rectGrob(gp = gpar(fill = NA, lwd = 2)),
        t = 2, b = nrow(g), l = 1, r = ncol(g))
g <- gtable_add_grob(g,
        grobs = rectGrob(gp = gpar(fill = NA, lwd = 2)),
        t = 1, l = 1, r = ncol(g))
grid.draw(g)

Note that when using rectGrob the top, bottom, left and right arguments (t, b, l, r) are the rows and columns which will be inside the rectangle. If we repeat the above code almost exactly, but don’t suppress the column of row labels, we see that column 1 is now the column of row labels (and it doesn’t look that good either, but that’s not our point).

g <- tableGrob(iris[1:4, 1:3])
g <- gtable_add_grob(g,
        grobs = rectGrob(gp = gpar(fill = NA, lwd = 2)),
        t = 2, b = nrow(g), l = 1, r = ncol(g))
g <- gtable_add_grob(g,
        grobs = rectGrob(gp = gpar(fill = NA, lwd = 2)),
        t = 1, l = 1, r = ncol(g))
grid.draw(g)

When adding line segments to separate rows and columns using segmentsGrob, the row and column numbering scheme is the same (it includes any row or column labels). When working with line segments, you should keep in mind the default coordinate values for segmentsGrob. They are x0 = 0, y0 = 0, x1 = 1, y1 = 1, all in npc, relative to the cell(s) you are modifying, with the lower left corner being 0,0. For clarity, we show all the arguments in these examples. With this in mind, to add a line across the bottom of a single cell, use:

g <- tableGrob(iris[1:4, 1:3])
g <- gtable_add_grob(g,
        grobs = segmentsGrob( # line across the bottom
            x0 = unit(0,"npc"),
            y0 = unit(0,"npc"),
            x1 = unit(1,"npc"),
            y1 = unit(0,"npc"),
            gp = gpar(lwd = 2.0)),
        t = 3, b = 3, l = 3, r = 3)
grid.draw(g)

and to add a line to the left side:

g <- tableGrob(iris[1:4, 1:3])
g <- gtable_add_grob(g,
        grobs = segmentsGrob( # line across the bottom
      x0 = unit(0,"npc"),
            y0 = unit(0,"npc"),
            x1 = unit(0,"npc"),
            y1 = unit(1,"npc"),
            gp = gpar(lwd = 2.0)),
        t = 3, b = 3, l = 3, r = 3)
grid.draw(g)

Perhaps you’d like to cross out a cell. This can be done with two diagonal lines combined via a grobTree:

g <- tableGrob(iris[1:4, 1:3])
g <- gtable_add_grob(g,
        grobs = grobTree(
            segmentsGrob( # diagonal line ul -> lr
                x0 = unit(0,"npc"),
                y0 = unit(1,"npc"),
                x1 = unit(1,"npc"),
                y1 = unit(0,"npc"),
                gp = gpar(lwd = 2.0)),
            segmentsGrob( # diagonal line ll -> ur
                x0 = unit(0,"npc"),
                y0 = unit(0,"npc"),
                x1 = unit(1,"npc"),
                y1 = unit(1,"npc"),
                gp = gpar(lwd = 2.0))),
        t = 3, b = 3, l = 3, r = 3)
grid.draw(g)

If you have many cells to decorate you can use replicate to create create the segments. Just keep the tableGrob numbering scheme in mind.

g <- tableGrob(head(iris), theme = ttheme_minimal())
separators <- replicate(ncol(g) - 2,
                     segmentsGrob(x1 = unit(0, "npc"), gp=gpar(lty=2)),
                     simplify=FALSE)
## add vertical lines on the left side of columns (after 2nd)
g <- gtable::gtable_add_grob(g, grobs = separators,
                     t = 2, b = nrow(g), l = seq_len(ncol(g)-2)+2)
grid.draw(g)

Accessing existing grobs in the table

We may also access and modify the original content of individual cells, e.g. to highlight a value.

g <- tableGrob(iris[1:4, 1:3])
find_cell <- function(table, row, col, name="core-fg"){
  l <- table$layout
  which(l$t==row & l$l==col & l$name==name)
}

ind <- find_cell(g, 3, 2, "core-fg")
ind2 <- find_cell(g, 2, 3, "core-bg")
g$grobs[ind][[1]][["gp"]] <- gpar(fontsize=15, fontface="bold")
g$grobs[ind2][[1]][["gp"]] <- gpar(fill="darkolivegreen1", col = "darkolivegreen4", lwd=5)
grid.draw(g)

Faster tables: an alternative grid function

The tableGrob function can be very slow; unfortunately this is the price to pay for its versatility and easier implementation. We use individual textGrob and rectGrob elements for each cell, instead of relying on the vectorised implementation of these functions. The reason is practical: it is much easier to place, measure, and customise individual grobs, than modify the graphical parameters and positions of a single vectorised grob. An alternative function is presented below, using this vectorised approach, but lacking many of the customisations of tableGrob.

grid.ftable <- function(d, padding = unit(4, "mm"), ...) {

  nc <- ncol(d)
  nr <- nrow(d)

  ## character table with added row and column names
  extended_matrix <- cbind(c("", rownames(d)),
                           rbind(colnames(d),
                                 as.matrix(d)))

  ## string width and height
  w <- apply(extended_matrix, 2, strwidth, "inch")
  h <- apply(extended_matrix, 2, strheight, "inch")

  widths <- apply(w, 2, max)
  heights <- apply(h, 1, max)

  padding <- convertUnit(padding, unitTo = "in", valueOnly = TRUE)

  x <- cumsum(widths + padding) - 0.5 * padding
  y <- cumsum(heights + padding) - padding

  rg <- rectGrob(x = unit(x - widths/2, "in"),
                 y = unit(1, "npc") - unit(rep(y, each = nc + 1), "in"),
                 width = unit(widths + padding, "in"),
                 height = unit(heights + padding, "in"))

  tg <- textGrob(c(t(extended_matrix)), x = unit(x - widths/2, "in"),
                 y = unit(1, "npc") - unit(rep(y, each = nc + 1), "in"),
                 just = "center")

  g <- gTree(children = gList(rg, tg), ...,
             x = x, y = y, widths = widths, heights = heights)

  grid.draw(g)
  invisible(g)
}

grid.newpage()
grid.ftable(head(iris, 4), gp = gpar(fill = rep(c("grey90", "grey95"), each = 6)))

gridExtra/inst/doc/ngonGrob.html0000644000176200001440000037525413154617413016413 0ustar liggesusers Regular polygons and ellipses in grid graphics

Regular polygons and ellipses in grid graphics

Baptiste Auguie

2017-09-09

The gridExtra package provides a basic implementation of regular polygons, ngonGrob()/grid.ngon, and a convenience function to draw ellipses, ellipseGrob()/grid.ellipse(). We illustrate below the basic usage of these vectorised functions.

Basic usage

library(gridExtra)
library(grid)
library(grid)
N <- 5
xy <- polygon_regular(N)*2

# draw multiple polygons
g <- ngonGrob(unit(xy[,1],"cm") + unit(0.5,"npc"),
              unit(xy[,2],"cm") + unit(0.5,"npc"),
              n=seq_len(N)+2, gp=gpar(fill=1:N))

grid.newpage()
grid.draw(g)

Rotated and stretched polygons

g2 <- ngonGrob(unit(xy[,1],"cm") + unit(0.5,"npc"),
              unit(xy[,2],"cm") + unit(0.5,"npc"),
              n=seq_len(N)+2, ar=seq_len(N),
              phase=0, angle=pi/(seq_len(N)+2),
              size=1:N+5, gp=gpar(fill=1:N))

grid.newpage()
grid.draw(g2)

Ellipses

g3 <- ellipseGrob(unit(xy[,1],"cm") + unit(0.5,"npc"),
                  unit(xy[,2],"cm") + unit(0.5,"npc"),
                  angle=-2*seq(0,N-1)*pi/N+pi/2,
                  size=5, ar=3, gp=gpar(fill=1:N))

grid.newpage()
grid.draw(g3)

gridExtra/NAMESPACE0000644000176200001440000000125613152620552013427 0ustar liggesusers# Generated by roxygen2: do not edit by hand S3method(drawDetails,lattice) S3method(grid.draw,arrangelist) S3method(print,arrangelist) S3method(str,gtable) export(arrangeGrob) export(combine) export(ellipseGrob) export(grid.arrange) export(grid.ellipse) export(grid.ngon) export(grid.table) export(gtable_cbind) export(gtable_combine) export(gtable_rbind) export(marrangeGrob) export(ngonGrob) export(polygon_regular) export(tableGrob) export(ttheme_default) export(ttheme_minimal) import(grid) import(gtable) importFrom(grDevices,dev.interactive) importFrom(grDevices,dev.new) importFrom(grDevices,n2mfrow) importFrom(graphics,plot) importFrom(utils,modifyList) importFrom(utils,str) gridExtra/R/0000755000176200001440000000000013045545327012414 5ustar liggesusersgridExtra/R/vectorgrobs.r0000644000176200001440000000533413010764171015133 0ustar liggesusers## linear (vectorised) versions of grid grobs ## for use with lapply and co (gpar exposed at top level) text_grob <- function(label, parse = FALSE, col = "black", fontsize = 12, cex = 1, fontfamily = "", fontface = 1L, lineheight = 1.2, alpha = 1, rot = 0, check.overlap = FALSE, name = NULL, vp = NULL, just = "centre", hjust = 0.5, vjust = 0.5, x = 0.5, y = 0.5, default.units = "npc"){ if(parse){ label <- tryCatch(parse(text=label), error = function(e) label) } textGrob(label = label, x = x, y = y, just = just, hjust = hjust, vjust = vjust, rot = rot, check.overlap = check.overlap, default.units = default.units, name = name, vp = vp, gp = gpar(col = col, cex = cex, fontfamily = fontfamily, fontface = fontface, fontsize = fontsize, lineheight = lineheight, alpha = alpha)) } rect_grob <- function(fill = "white", col = "black", lty = "solid", lwd = 1, cex = 1, alpha = 1, lineend = "round", linejoin = "round", linemitre = 10, lex = 1, name = NULL, vp = NULL, just = "centre", hjust = 0.5, vjust = 0.5, width = unit(1,"npc") - unit(2, "scaledpts"), height = unit(1,"npc") - unit(2, "scaledpts"), x = 0.5, y = 0.5, default.units = "npc"){ rectGrob(x = x, y = y, just = just, hjust = hjust, vjust = vjust, width = width, height = height, default.units = default.units, name = name, vp = vp, gp = gpar(col = col, fill = fill, alpha = alpha, lty = lty, lwd = lwd, lex = lex, lineend = lineend, linejoin = linejoin, linemitre = linemitre, cex = cex)) } gridExtra/R/arrangeGrob.r0000644000176200001440000002103013010764171015014 0ustar liggesusers##' @aliases grid.arrange arrangeGrob marrangeGrob ##' @title Arrange multiple grobs on a page ##' @description Set up a gtable layout to place multiple grobs on a page. ##' @describeIn arrangeGrob return a grob without drawing ##' @param ... grobs, gtables, ggplot or trellis objects ##' @param grobs list of grobs ##' @param top optional string, or grob ##' @param bottom optional string, or grob ##' @param left optional string, or grob ##' @param right optional string, or grob ##' @param padding unit of length one, margin around annotations ##' @param as.table logical: bottom-left to top-right (TRUE) or top-left to bottom-right (FALSE) ##' @param layout_matrix optional layout ##' @param name argument of gtable ##' @param respect argument of gtable ##' @param clip argument of gtable ##' @param nrow argument of gtable ##' @param ncol argument of gtable ##' @param widths argument of gtable ##' @param heights argument of gtable ##' @param vp viewport ##' @return arrangeGrob returns a gtable. ##' @import gtable ##' @import grid ##' @importFrom grDevices n2mfrow ##' @export ##' ##' @examples ##' library(grid) ##' grid.arrange(rectGrob(), rectGrob()) arrangeGrob <- function(..., grobs=list(...), layout_matrix, vp=NULL, name = "arrange", as.table=TRUE, respect = FALSE, clip = "off", nrow=NULL, ncol=NULL, widths = NULL, heights = NULL, top = NULL, bottom = NULL, left = NULL, right = NULL, padding = unit(0.5,"line")){ n <- length(grobs) ## logic for the layout # if nrow/ncol supplied, honour this # if not, use length of widths/heights, if supplied # if nothing supplied, work out sensible defaults ## nothing to be done but check inconsistency if (!is.null(ncol) && !is.null(widths)){ stopifnot(length(widths) == ncol) } if (!is.null(nrow) && !is.null(heights)){ stopifnot(length(heights) == nrow) } ## use widths/heights if supplied if (is.null(ncol) && !is.null(widths)){ ncol <- length(widths) } if (is.null(nrow) && !is.null(heights)){ nrow <- length(heights) } ## work out the missing one if(is.null(nrow) && !is.null(ncol)) { nrow <- ceiling(n/ncol) } if(is.null(ncol) && !is.null(nrow)) { ncol <- ceiling(n/nrow) } ## it may happen that sufficient info was passed, ## but incompatible with number of grobs (fewer cells) stopifnot(nrow*ncol >= n) ## last case: nothing exists if(is.null(nrow) && is.null(ncol) && is.null(widths) && is.null(heights)) { nm <- grDevices::n2mfrow(n) nrow = nm[1] ncol = nm[2] } ## debugging # message("nrow:", nrow, " ncol:", ncol) ## conversions inherit.ggplot <- unlist(lapply(grobs, inherits, what="ggplot")) inherit.trellis <- unlist(lapply(grobs, inherits, what="trellis")) if(any(inherit.ggplot)) { stopifnot(requireNamespace("ggplot2", quietly = TRUE)) toconv <- which(inherit.ggplot) grobs[toconv] <- lapply(grobs[toconv], ggplot2::ggplotGrob) } if(any(inherit.trellis)) { stopifnot(requireNamespace("lattice", quietly = TRUE)) toconv <- which(inherit.trellis) grobs[toconv] <- lapply(grobs[toconv], latticeGrob) } if(missing(layout_matrix)){ # default layout: one cell for each grob positions <- expand.grid(t = seq_len(nrow), l = seq_len(ncol)) positions$b <- positions$t positions$r <- positions$l if(as.table) # fill table by rows positions <- positions[order(positions$t),] positions <- positions[seq_along(grobs), ] # n might be < ncol*nrow } else { # a layout was supplied cells <- sort(unique(as.vector(layout_matrix))) ## left/right/top/bottom borders for given id range_cell <- function(ii){ ind <- which(layout_matrix == ii, arr.ind=TRUE) c(l=min(ind[,"col"], na.rm = TRUE), r=max(ind[,"col"], na.rm = TRUE), t=min(ind[,"row"], na.rm = TRUE), b=max(ind[,"row"], na.rm = TRUE)) } positions <- data.frame(do.call(rbind, lapply(cells, range_cell))) ncol <- max(positions$r) nrow <- max(positions$b) positions <- positions[seq_along(grobs),] # layout might define more cells } ## sizes if(is.null(widths)) widths <- unit(rep(1, ncol), "null") if(is.null(heights)) heights <- unit(rep(1,nrow), "null") ## lazy size specification as relative numbers if (!is.unit(widths)) widths <- unit(widths, "null") if (!is.unit(heights)) heights <- unit(heights, "null") ## build the gtable, similar steps to gtable_matrix gt <- gtable(name=name, respect = respect, heights = heights, widths = widths, vp=vp) gt <- gtable_add_grob(gt, grobs, t = positions$t, b = positions$b, l = positions$l, r = positions$r, z = seq_along(grobs), clip = clip) ## titles given as strings are converted to text grobs if(is.character(top)){ top <- textGrob(top) } if(is.grob(top)){ h <- grobHeight(top) + padding gt <- gtable_add_rows(gt, heights=h, 0) gt <- gtable_add_grob(gt, top, t=1, l=1, r=ncol(gt), z=Inf, clip = clip) } if(is.character(bottom)){ bottom <- textGrob(bottom) } if(is.grob(bottom)){ h <- grobHeight(bottom) + padding gt <- gtable_add_rows(gt, heights = h, -1) gt <- gtable_add_grob(gt, bottom, t=nrow(gt), l=1, r=ncol(gt), z=Inf, clip = clip) } if(is.character(left)){ left <- textGrob(left, rot = 90) } if(is.grob(left)){ w <- grobWidth(left) + padding gt <- gtable_add_cols(gt, widths=w, 0) gt <- gtable_add_grob(gt, left, t=1, b=nrow(gt), l=1, r=1, z=Inf, clip = clip) } if(is.character(right)){ right <- textGrob(right, rot = -90) } if(is.grob(right)){ w <- grobWidth(right) + padding gt <- gtable_add_cols(gt, widths=w, -1) gt <- gtable_add_grob(gt, right, t=1, b=nrow(gt), l=ncol(gt), r=ncol(gt), z=Inf, clip = clip) } gt } ##' @describeIn arrangeGrob draw on the current device ##' @param newpage open a new page ##' @inheritParams arrangeGrob ##' @export grid.arrange <- function(..., newpage=TRUE){ if(newpage) grid.newpage() g <- arrangeGrob(...) grid.draw(g) invisible(g) } ##' @describeIn arrangeGrob interface to arrangeGrob that can dispatch on multiple pages ##' @details Using marrangeGrob, if the layout specifies both nrow and ncol, the list of grobs can be split into multiple pages. On interactive devices print opens new windows, whilst non-interactive devices such as pdf call grid.newpage() between the drawings. ##' @return marrangeGrob returns a list of class arrangelist ##' @export ##' @examples ##' \dontrun{ ##' library(ggplot2) ##' pl <- lapply(1:11, function(.x) qplot(1:10, rnorm(10), main=paste("plot", .x))) ##' ml <- marrangeGrob(pl, nrow=2, ncol=2) ##' ## non-interactive use, multipage pdf ##' ggsave("multipage.pdf", ml) ##' ## interactive use; open new devices ##' ml ##' } marrangeGrob <- function(grobs, ..., ncol, nrow, layout_matrix = matrix(seq_len(nrow*ncol), nrow = nrow, ncol=ncol), top = quote(paste("page", g, "of", npages))){ n <- length(grobs) nlay <- max(layout_matrix, na.rm=TRUE) npages <- n %/% nlay + as.logical(n %% nlay) groups <- split(grobs, rep(seq_len(npages), each=nlay, length.out=n)) pl <- vector(mode = "list", length = npages) for(g in seq_along(groups)){ params <- modifyList(list(...), list(top=eval(top), layout_matrix = layout_matrix)) pl[[g]] <- do.call(arrangeGrob, c(list(grobs=groups[[g]]), params)) } class(pl) <- c("arrangelist", class(pl)) pl } ##' @noRd ##' @importFrom grDevices dev.interactive dev.new ##' @export grid.draw.arrangelist = function(x, ...) lapply(x, function(.x) { if(dev.interactive()) dev.new() else grid.newpage() grid.draw(.x) }, ...) ##' @noRd ##' @importFrom grDevices dev.interactive dev.new ##' @export print.arrangelist = function(x, ...) lapply(x, function(.x) { if(dev.interactive()) dev.new() else grid.newpage() grid.draw(.x) }, ...) gridExtra/R/ngonGrob.r0000644000176200001440000001056413010764171014350 0ustar liggesusers##' @aliases ngonGrob grid.ngon ellipseGrob grid.ellipse ##' @title Regular polygon grob ##' @description Regular polygons with optional rotation, stretching, and aesthetic attributes. ##' @describeIn ngonGrob return a polygon grob ##' @param x x unit ##' @param y y unit ##' @param n number of vertices ##' @param size radius of circumscribing circle ##' @param phase angle in radians of first point relative to x axis ##' @param ar aspect ratio ##' @param angle angle of polygon in radians ##' @param position.units default units for the positions ##' @param size.units grid units for the sizes ##' @param gp gpar ##' @param ... further parameters passed to polygonGrob ##' @return A grob. ##' @export ##' @examples ##' library(grid) ##' N <- 5 ##' xy <- polygon_regular(N)*2 ##' ##' # draw multiple polygons ##' g <- ngonGrob(unit(xy[,1],"cm") + unit(0.5,"npc"), ##' unit(xy[,2],"cm") + unit(0.5,"npc"), ##' n = seq_len(N) + 2, gp = gpar(fill=1:N)) ##' ##' grid.newpage() ##' grid.draw(g) ##' ##' # rotated and stretched ##' g2 <- ngonGrob(unit(xy[,1],"cm") + unit(0.5,"npc"), ##' unit(xy[,2],"cm") + unit(0.5,"npc"), ##' n = seq_len(N) + 2, ar = seq_len(N), ##' phase = 0, angle = pi/(seq_len(N) + 2), ##' size = 1:N + 5) ##' ##' grid.newpage() ##' grid.draw(g2) ##' ##' # ellipse ##' g3 <- ellipseGrob(unit(xy[,1],"cm") + unit(0.5,"npc"), ##' unit(xy[,2],"cm") + unit(0.5,"npc"), ##' angle = -2*seq(0,N-1)*pi/5 + pi/2, ##' size = 5, ar = 1/3) ##' ##' grid.newpage() ##' grid.draw(g3) ngonGrob <- function (x, y, n = 5, size = 5, phase = pi/2, angle = 0, ar = 1, gp = gpar(colour = "black", fill = NA, linejoin = "mitre"), ..., position.units = "npc", size.units="mm") { N <- length(x) stopifnot(length(y) == N) if (!is.unit(x)) x <- unit(x, position.units) if (!is.unit(y)) y <- unit(y, position.units) xv <- convertX(x, position.units, TRUE) yv <- convertY(y, position.units, TRUE) if (length(n) < N) n <- rep(n, length.out = N) if (length(size) < N) size <- rep(size, length.out = N) if (length(phase) < N) phase <- rep(phase, length.out = N) if (length(angle) < N) angle <- rep(angle, length.out = N) if (length(ar) < N) ar <- rep(ar, length.out = N) lngon <- mapply(polygon_regular, n = n, phase = phase, SIMPLIFY = FALSE) vertices <- sapply(lngon, nrow) stretch_rotate_move <- function(p, size, ar, angle, x, y){ central <- size * p %*% diag(c(sqrt(ar), 1/sqrt(ar))) %*% rbind(c(cos(angle), -sin(angle)), c(sin(angle), cos(angle))) list(x = unit(central[,1], size.units) + unit(x, position.units), y = unit(central[,2], size.units) + unit(y, position.units)) } lxy <- mapply(stretch_rotate_move, p=lngon, size=size, ar=ar, angle=angle, x=xv, y=yv, SIMPLIFY = FALSE) allx <- do.call("unit.c", lapply(lxy, "[[", 1)) ally <- do.call("unit.c", lapply(lxy, "[[", 2)) polygonGrob(allx, ally, id.lengths = vertices, gp = gp, ...) } #' @describeIn ngonGrob draw a polygon grob on the current device #' @inheritParams ngonGrob #' @export grid.ngon <- function(...) { grid.draw(ngonGrob(...)) } #' @describeIn ngonGrob return an ellipse grob #' @inheritParams ngonGrob #' @export ellipseGrob <- function(x, y, size = 5, angle = pi/4, ar = 1, n = 50, gp = gpar(colour = "black", fill = NA, linejoin = "mitre"), ..., position.units = "npc", size.units="mm") { ngonGrob(x, y, n = n , phase = 0, size = size, angle = angle, ar = ar, gp = gp, position.units = position.units, size.units = size.units, ...) } #' @describeIn ngonGrob draw an ellipse grob #' @inheritParams ngonGrob #' @export grid.ellipse <- function(...) { grid.draw(ellipseGrob(...)) } #' @describeIn ngonGrob return the x,y coordinates of a regular polygon inscribed in the unit circle #' @inheritParams ngonGrob #' @export polygon_regular <- function(n = 5, phase = 0){ stopifnot(n > 2) cc <- exp(seq(0, n)*2i*pi/n) * exp(1i*(phase+pi/2)) cbind(Re(cc), Im(cc)) } gridExtra/R/gtable.r0000644000176200001440000001631213152661533014035 0ustar liggesusers## Misc. gtable functions ## Note: some functions were copied from the gtable package with ## minor modifications (rbind/cbind). In the future it would be nice to ## get them included in the original gtable package, but its development ## cycle is not very regular. ##'Prints summary information on gtable objects ##'@param object a gtable ##'@param ... unused ##'@importFrom utils str ##'@method str gtable ##' @noRd ##'@export str.gtable <- function(object, ...){ cat(c("gtable, containing \ngrobs (", length(object[["grobs"]]), ") :"), sep="") utils::str(vapply(object$grobs, as.character, character(1))) cat("layout :\n") utils::str(object[["layout"]]) cat("widths :\nunit vector of length", length(object[["widths"]]), "\n") cat("heights :\nunit vector of length", length(object[["heights"]]), "\n") for(element in c("respect", "rownames", "name", "gp", "vp")){ cat(element, ":\n") utils::str(object[[element]]) } } ##'Combine gtables based on row/column names. ##'@param ... gtables #' @aliases combine ##'@rdname combine ##'@param along dimension to align along, \code{1} = rows, ##'\code{2} = cols. ##'@param join when x and y have different names, how should the difference be resolved? ##'\code{inner} keep names that appear in both, ##'\code{outer} keep names that appear in either, ##'\code{left} keep names from \code{x}, ##'and \code{right} keep names from \code{y}. ##'@export gtable_combine <- function (..., along = 1L, join = "outer") { gtables <- list(...) Reduce(function(x, y) combine_2(x, y, along = along, join = join), gtables) } #' @rdname combine #' @export combine <- function (..., along = 1L, join = "outer") { .Deprecated("gtable_combine") gtable_combine(..., along=along, join=join) } z_normalise <- function (x, i = 1) { x$layout$z <- rank(x$layout$z, ties.method = "first") + i - 1 x } z_arrange_gtables <- function (gtables, z) { if (length(gtables) != length(z)) { stop("'gtables' and 'z' must be the same length") } zmax <- 0 for (i in order(z)) { if (nrow(gtables[[i]]$layout) > 0) { gtables[[i]] <- z_normalise(gtables[[i]], zmax + 1) zmax <- max(gtables[[i]]$layout$z) } } gtables } ##'rbind gtables ##'@rdname bind ##'@param ... gtables ##'@param size how should the widths be calculated? ##'\code{max} maximum of all widths ##'\code{min} minimum of all widths ##'\code{first} widths/heights of first gtable ##'\code{last} widths/heights of last gtable ##'@param z optional z level ##'@export gtable_rbind <- function(..., size = "max", z = NULL) { gtables <- list(...) if (!is.null(z)) { gtables <- z_arrange_gtables(gtables, z) } Reduce(function(x, y) rbind_2(x, y, size = size), gtables) } ##'cbind gtables ##'@rdname bind ##'@export gtable_cbind <- function(..., size = "max", z = NULL) { gtables <- list(...) if (!is.null(z)) { gtables <- z_arrange_gtables(gtables, z) } Reduce(function(x, y) cbind_2(x, y, size = size), gtables) } rbind_2 <- function(x, y, size = "max") { stopifnot(ncol(x) == ncol(y)) if (nrow(x) == 0) return(y) if (nrow(y) == 0) return(x) y$layout$t <- y$layout$t + nrow(x) y$layout$b <- y$layout$b + nrow(x) x$layout <- rbind(x$layout, y$layout) x$heights <- insert.unit(x$heights, y$heights) x$rownames <- c(x$rownames, y$rownames) size <- match.arg(size, c("first", "last", "max", "min")) x$widths <- switch(size, first = x$widths, last = y$widths, min = unit.pmin(x$widths, y$widths), max = unit.pmax(x$widths, y$widths) ) x$grobs <- append(x$grobs, y$grobs) x } cbind_2 <- function(x, y, size = "max") { stopifnot(nrow(x) == nrow(y)) if (ncol(x) == 0) return(y) if (ncol(y) == 0) return(x) y$layout$l <- y$layout$l + ncol(x) y$layout$r <- y$layout$r + ncol(x) x$layout <- rbind(x$layout, y$layout) x$widths <- insert.unit(x$widths, y$widths) x$colnames <- c(x$colnames, y$colnames) size <- match.arg(size, c("first", "last", "max", "min")) x$heights <- switch(size, first = x$heights, last = y$heights, min = unit.pmin(x$heights, y$heights), max = unit.pmax(x$heights, y$heights)) x$grobs <- append(x$grobs, y$grobs) x } combine_2 <- function(x, y, along = 1L, join = "outer") { aligned <- align_2(x, y, along = along, join = join) switch(along, cbind_2(aligned$x, aligned$y, size="max"), rbind_2(aligned$x, aligned$y, size="max"), stop("along > 2 no implemented")) } align_2 <- function(x, y, along = 1L, join = "outer") { join <- match.arg(join, c("left", "right", "inner", "outer")) names_x <- dimnames(x)[[along]] names_y <- dimnames(y)[[along]] if (is.null(names_x) || is.null(names_y)) { stop("Both gtables must have names along dimension to be aligned") } idx <- switch(join, left = names_x, right = names_y, inner = intersect(names_x, names_y), outer = union(names_x, names_y) ) list( x = gtable_reindex(x, idx, along), y = gtable_reindex(y, idx, along) ) } gtable_reindex <- function(x, index, along = 1L) { stopifnot(is.character(index)) if (length(dim(x)) > 2L || along > 2L) { stop("reindex only supports 2d objects") } old_index <- switch(along, rownames(x), colnames(x)) stopifnot(!is.null(old_index)) if (identical(index, old_index)) { return(x) } if (!(old_index %contains% index)) { missing <- setdiff(index, old_index) # Create and add dummy space rows if (along == 1L) { spacer <- gtable( widths = unit(rep(0, ncol(x)), "cm"), heights = rep_along(unit(0, "cm"), missing), rownames = missing) x <- rbind(x, spacer, size = "first") } else if (along == 2L){ spacer <- gtable( heights = unit(rep(0, nrow(x)), "cm"), widths = rep_along(unit(0, "cm"), missing), colnames = missing) x <- cbind(x, spacer, size = "first") } } # Reorder & subset switch(along, x[index, ], x[, index]) } gtable_remove_grob <- function(x, pattern, which = 1L, fixed = FALSE, trim=TRUE){ matches <- grep(pattern, x$layout$name, fixed = fixed) tokeep <- setdiff(seq_len(length(x)), matches[which]) x$layout <- x$layout[tokeep, , drop = FALSE] x$grobs <- x$grobs[tokeep] if(trim) x <- gtable_trim(x) x } ## misc utils "%contains%" <- function(x, y) all(y %in% x) rep_along <- function(x, y) { if (length(y) == 0) return(NULL) rep(x, length(y)) } insert.unit <- function (x, values, after = length(x)) { lengx <- length(x) if (lengx == 0) return(values) if (length(values) == 0) return(x) if (after <= 0) { unit.c(values, x) } else if (after >= lengx) { unit.c(x, values) } else { unit.c(x[1L:after], values, x[(after + 1L):lengx]) } } gridExtra/R/gridExtra-package.r0000644000176200001440000000103613010764171016111 0ustar liggesusers#' @title Miscellaneous Functions for "Grid" Graphics #' @description Provides a number of user-level functions to work with "grid" graphics, notably to arrange multiple grid-based plots on a page, and draw tables. #' @name gridExtra-package #' @aliases gridExtra #' @docType package #' @author baptiste Auguie \email{baptiste.auguie@@gmail.com} #' @import gtable #' @import grid #' @references #' R Graphics by Paul Murrell (Chapman & Hall/CRC, August 2005) #' @keywords packagelibrary #' @seealso \code{\link{Grid}} #' function() NULL gridExtra/R/tableGrob.r0000644000176200001440000001766113152363611014504 0ustar liggesusers#' @aliases grid.table tableGrob ttheme_default ttheme_minimal #' @title Graphical display of a textual table #' @describeIn tableGrob return a grob #' @description Create a gtable containing text grobs representing a character matrix. #' @param d data.frame or matrix #' @param rows optional vector to specify row names #' @param cols optional vector to specify column names #' @param theme list of theme parameters #' @param vp optional viewport #' @param ... further arguments to control the gtable #' @return A gtable. #' @export #' @examples #' library(grid) #' d <- head(iris, 3) #' g <- tableGrob(d) #' grid.newpage() #' grid.draw(g) tableGrob <- function(d, rows=rownames(d), cols=colnames(d), theme = ttheme_default(), vp = NULL, ...){ g <- gtable_table(d, name="core", fg_fun = theme$core$fg_fun, bg_fun = theme$core$bg_fun, fg_params = theme$core$fg_params, bg_params = theme$core$bg_params, padding=theme$core$padding, ...) if(!is.null(cols)){ gc <- gtable_table(t(cols), name="colhead", fg_fun = theme$colhead$fg_fun, bg_fun = theme$colhead$bg_fun, fg_params = theme$colhead$fg_params, bg_params = theme$colhead$bg_params, padding=theme$colhead$padding) g <- rbind_2(gc, g, "max") } if(!is.null(rows)){ if(!is.null(cols)) # need to add dummy cell rows <- c("", rows) gr <- gtable_table(rows, name="rowhead", fg_fun = theme$rowhead$fg_fun, bg_fun = theme$rowhead$bg_fun, fg_params = theme$rowhead$fg_params, bg_params = theme$rowhead$bg_params, padding=theme$rowhead$padding) g <- cbind_2(gr, g, "max") } colnames(g) <- paste0("c", seq_len(ncol(g))) rownames(g) <- paste0("r", seq_len(nrow(g))) if(!is.null(vp)) g$vp <- vp g } #' @describeIn tableGrob draw a text table #' @inheritParams tableGrob #' @export grid.table <- function(...) grid.draw(tableGrob(...)) #' @describeIn tableGrob default theme for text tables #' @param base_size default font size #' @param base_colour default font colour #' @param base_family default font family #' @param parse logical, default behaviour for parsing text as plotmath #' @param padding length-2 unit vector specifying the horizontal and vertical padding of text within each cell #' @importFrom utils modifyList #' @export ttheme_default <- function(base_size=12, base_colour="black", base_family="", parse=FALSE, padding = unit(c(4, 4), "mm"), ...){ core <- list(fg_fun = text_grob, fg_params = list(parse=parse, col=base_colour, fontsize = base_size, fontfamily = base_family), bg_fun = rect_grob, bg_params = list(fill = c("grey95","grey90"), lwd=1.5, col="white"), padding = padding) colhead <- list(fg_fun = text_grob, fg_params = list(parse=parse, col=base_colour, fontface=2L, fontsize = base_size, fontfamily = base_family), bg_fun = rect_grob, bg_params = list(fill = c("grey80"), lwd=1.5, col="white"), padding = padding) rowhead <- list(fg_fun = text_grob, fg_params = list(parse=parse, col=base_colour, fontface=3L, fontsize = base_size, fontfamily = base_family, hjust = 1, x = 0.95), bg_fun = rect_grob, bg_params = list(fill=NA, lwd=1.5, col="white"), padding = padding) default <- list( core = core, colhead = colhead, rowhead= rowhead ) modifyList(default, list(...)) } #' @describeIn tableGrob minimalist theme for text tables #' @inheritParams ttheme_default ##' @export ttheme_minimal <- function(base_size=12, base_colour = "black", base_family = "", parse=FALSE, padding = unit(c(4, 4), "mm"), ...){ core <- list(fg_fun = text_grob, fg_params = list(parse=parse, col=base_colour, fontsize = base_size, fontfamily = base_family), bg_fun = rect_grob, bg_params = list(fill = NA, col=NA), padding = padding) colhead <- list(fg_fun = text_grob, fg_params = list(parse=parse, col=base_colour, fontface=2L, fontsize = base_size, fontfamily = base_family), bg_fun = rect_grob, bg_params = list(fill = NA, col=NA), padding = padding) rowhead <- list(fg_fun = text_grob, fg_params = list(parse=parse, col=base_colour, fontface=3L, fontsize = base_size, fontfamily = base_family, hjust = 1, x = 0.95), bg_fun = rect_grob, bg_params = list(fill=NA, col=NA), padding = padding) default <- list( core = core, colhead = colhead, rowhead= rowhead ) modifyList(default, list(...)) } ## ## unexported helper functions ## gtable_table <- function(d, widths, heights, fg_fun = text_grob, fg_params = list(), bg_fun = rect_grob, bg_params = list(), padding = unit(c(4, 4), "mm"), name = "table", vp = NULL){ label_matrix <- as.matrix(d) nc <- ncol(label_matrix) nr <- nrow(label_matrix) n <- nc*nr ## formatting parameters will be recycled iff ## there are fewer elements than needed rep_ifshort <- function(x, n, nc, nr){ if(length(x) >= n){ return(x[1:n]) } else # recycle return(rep(rep(x, length.out = nr), length.out= n)) } fg_params <- lapply(fg_params, rep_ifshort, n = n, nc = nc, nr = nr) bg_params <- lapply(bg_params, rep_ifshort, n = n, nc = nc, nr = nr) fg_params <- data.frame(fg_params, label = as.vector(label_matrix), # colwise stringsAsFactors=FALSE) bg_params <- data.frame(bg_params, stringsAsFactors=FALSE) labels <- do.call(mapply, c(fg_params, list(FUN = fg_fun, SIMPLIFY=FALSE))) bkgds <- do.call(mapply, c(bg_params, list(FUN = bg_fun, SIMPLIFY=FALSE))) label_grobs <- matrix(labels, ncol = nc, byrow = FALSE) bkgds_grobs <- matrix(bkgds, ncol = nc, byrow = FALSE) ## some calculations of cell sizes if(missing(widths)) widths <- col_widths(label_grobs) + padding[1] if(missing(heights)) heights <- row_heights(label_grobs) + padding[2] ## place labels in a gtable g <- gtable_matrix(paste0(name, "-fg"), grobs = label_grobs, widths = widths, heights = heights, vp=vp) ## add the background g <- gtable_add_grob(g, bkgds_grobs, t=rep(seq_len(nr), length.out = n), l=rep(seq_len(nc), each = nr), z=0, name=paste0(name, "-bg")) g } gridExtra/R/grob-utils.r0000644000176200001440000000075713010764171014667 0ustar liggesuserslatticeGrob <- function(p, ...){ grob(p=p, ..., cl="lattice") } #' @importFrom graphics plot #' @export drawDetails.lattice <- function(x, recording=FALSE){ stopifnot(requireNamespace("lattice", quietly = TRUE)) plot(x$p, newpage=FALSE) } row_heights <- function(m){ do.call(unit.c, apply(m, 1, function(l) max(do.call(unit.c, lapply(l, grobHeight))))) } col_widths <- function(m){ do.call(unit.c, apply(m, 2, function(l) max(do.call(unit.c, lapply(l, grobWidth))))) } gridExtra/vignettes/0000755000176200001440000000000013154617431014220 5ustar liggesusersgridExtra/vignettes/tableGrob.Rmd0000644000176200001440000002455613152370532016575 0ustar liggesusers--- title: "Displaying tables as grid graphics" author: "Baptiste Auguie" date: '`r Sys.Date()`' vignette: > %\VignetteEngine{knitr::rmarkdown} %\VignetteIndexEntry{tableGrob: displaying tables as grid graphics} output: knitr:::html_vignette: toc: yes --- ```{r setup, echo=FALSE, results='hide'} library(knitr) opts_chunk$set(message=FALSE, fig.width=4, fig.height=2) ``` Tabular data is usually formatted outside the graphics device, e.g via LaTeX, or html tables. However, in some cases it may be convenient to display *small* tables alongside graphics. A couple of packages offer this possibility with base graphics (`plotrix` for instance); the `gridExtra` provides the pair of `tableGrob/grid.table` functions for this purpose. *Note:* This vignette uses the development version of `gridExtra`, some features may not be yet available in the released version. ## Basic usage ```{r basic} library(gridExtra) library(grid) d <- head(iris[,1:3]) grid.table(d) ``` ## Spacing The spacing of each row/column is automatic, and will adjust to bigger cell contents. Plotmath notation may be used, with the `parse=TRUE` argument. Note that this is applied to individual strings of text, and reverts to standard text if parsing fails (this is useful when mixing multiline text with plotmath in different cells). ```{r annotations, fig.height=3} d[2,3] <- "this is very wwwwwide" d[1,2] <- "this\nis\ntall" colnames(d) <- c("alpha*integral(xdx,a,infinity)", "this text\nis high", 'alpha/beta') tt <- ttheme_default(colhead=list(fg_params = list(parse=TRUE))) grid.table(d, theme=tt) ``` ## Aesthetic formatting The formatting is controlled by *themes*, which are nested lists of graphical parameters. See `ttheme_default` and `ttheme_minimal` for two built-in examples. Changing a few parameters at a time amounts to modifying the list with the new values. ```{r theme, fig.width=8} tt1 <- ttheme_default() tt2 <- ttheme_minimal() tt3 <- ttheme_minimal( core=list(bg_params = list(fill = blues9[1:4], col=NA), fg_params=list(fontface=3)), colhead=list(fg_params=list(col="navyblue", fontface=4L)), rowhead=list(fg_params=list(col="orange", fontface=3L))) grid.arrange( tableGrob(iris[1:4, 1:2], theme=tt1), tableGrob(iris[1:4, 1:2], theme=tt2), tableGrob(iris[1:4, 1:2], theme=tt3), nrow=1) ``` If the formatting values are fewer than the number of cells, they are recycled along columns, ```{r recycling} t1 <- ttheme_default(core=list( fg_params=list(fontface=c(rep("plain", 4), "bold.italic")), bg_params = list(fill=c(rep(c("grey95", "grey90"), length.out=4), "#6BAED6"), alpha = rep(c(1,0.5), each=5)) )) grid.table(iris[1:5, 1:3], theme = t1) ``` ## Text justification The text labels can be justified; the default is "centre" for the core and header, and "right" for the row names. These settings can be adjusted by passing the relevant parameters of `textGrob` via the theme nested lists, ```{r justify, fig.width=8} tt1 <- ttheme_default() tt2 <- ttheme_default(core=list(fg_params=list(hjust=1, x=0.9)), rowhead=list(fg_params=list(hjust=1, x=0.95))) tt3 <- ttheme_default(core=list(fg_params=list(hjust=0, x=0.1)), rowhead=list(fg_params=list(hjust=0, x=0))) grid.arrange( tableGrob(mtcars[1:4, 1:2], theme=tt1), tableGrob(mtcars[1:4, 1:2], theme=tt2), tableGrob(mtcars[1:4, 1:2], theme=tt3), nrow=1) ``` ## Further gtable processing and integration Being based on `gtable`, the table can be further processed. In particular, we may edit the cell sizes to align with other content on the page. ```{r sizes, fig.width=8} g <- g2 <- tableGrob(iris[1:4, 1:3], cols = NULL, rows=NULL) g2$widths <- unit(rep(1/ncol(g2), ncol(g2)), "npc") grid.arrange(rectGrob(), rectGrob(), nrow=1) grid.arrange(g, g2, nrow=1, newpage = FALSE) ``` The alignment of several tables can be achieved with the `combine` function (adapted from `gtable:::join`), ```{r align, fig.width=6, fig.height=3} d1 <- PlantGrowth[1:3,1, drop=FALSE] d2 <- PlantGrowth[1:2,1:2] g1 <- tableGrob(d1) g2 <- tableGrob(d2) haligned <- gtable_combine(g1,g2, along=1) valigned <- gtable_combine(g1,g2, along=2) grid.newpage() grid.arrange(haligned, valigned, ncol=2) ``` ### Borders and separators Other grobs such as separating lines and rectangles (borders, boxes) may be added. In this case, keep in mind that row, column and cell numbering includes the column of row labels and the row of column labels *if they are present.* Let us illustrate this by adding some borders (using `rectGrob`) to a simple table without row numbers. We'll add two actually, to give a nice effect of a heavy line under the row of column headers. ```{r numberingDemo1} library(gtable) g <- tableGrob(iris[1:4, 1:3], rows = NULL) g <- gtable_add_grob(g, grobs = rectGrob(gp = gpar(fill = NA, lwd = 2)), t = 2, b = nrow(g), l = 1, r = ncol(g)) g <- gtable_add_grob(g, grobs = rectGrob(gp = gpar(fill = NA, lwd = 2)), t = 1, l = 1, r = ncol(g)) grid.draw(g) ``` Note that when using `rectGrob` the top, bottom, left and right arguments (`t, b, l, r`) are the rows and columns which will be *inside* the rectangle. If we repeat the above code almost exactly, but don't suppress the column of row labels, we see that column 1 is now the column of row labels (and it doesn't look that good either, but that's not our point). ```{r numberingDemo2} g <- tableGrob(iris[1:4, 1:3]) g <- gtable_add_grob(g, grobs = rectGrob(gp = gpar(fill = NA, lwd = 2)), t = 2, b = nrow(g), l = 1, r = ncol(g)) g <- gtable_add_grob(g, grobs = rectGrob(gp = gpar(fill = NA, lwd = 2)), t = 1, l = 1, r = ncol(g)) grid.draw(g) ``` When adding line segments to separate rows and columns using `segmentsGrob`, the row and column numbering scheme is the same (it includes any row or column labels). When working with line segments, you should keep in mind the default coordinate values for `segmentsGrob`. They are x0 = 0, y0 = 0, x1 = 1, y1 = 1, all in npc, relative to the cell(s) you are modifying, with the lower left corner being 0,0. For clarity, we show all the arguments in these examples. With this in mind, to add a line across the bottom of a single cell, use: ```{r segments1 } g <- tableGrob(iris[1:4, 1:3]) g <- gtable_add_grob(g, grobs = segmentsGrob( # line across the bottom x0 = unit(0,"npc"), y0 = unit(0,"npc"), x1 = unit(1,"npc"), y1 = unit(0,"npc"), gp = gpar(lwd = 2.0)), t = 3, b = 3, l = 3, r = 3) grid.draw(g) ``` and to add a line to the left side: ```{r segments2 } g <- tableGrob(iris[1:4, 1:3]) g <- gtable_add_grob(g, grobs = segmentsGrob( # line across the bottom x0 = unit(0,"npc"), y0 = unit(0,"npc"), x1 = unit(0,"npc"), y1 = unit(1,"npc"), gp = gpar(lwd = 2.0)), t = 3, b = 3, l = 3, r = 3) grid.draw(g) ``` Perhaps you'd like to cross out a cell. This can be done with two diagonal lines combined via a `grobTree`: ```{r segments3} g <- tableGrob(iris[1:4, 1:3]) g <- gtable_add_grob(g, grobs = grobTree( segmentsGrob( # diagonal line ul -> lr x0 = unit(0,"npc"), y0 = unit(1,"npc"), x1 = unit(1,"npc"), y1 = unit(0,"npc"), gp = gpar(lwd = 2.0)), segmentsGrob( # diagonal line ll -> ur x0 = unit(0,"npc"), y0 = unit(0,"npc"), x1 = unit(1,"npc"), y1 = unit(1,"npc"), gp = gpar(lwd = 2.0))), t = 3, b = 3, l = 3, r = 3) grid.draw(g) ``` If you have many cells to decorate you can use `replicate` to create create the segments. Just keep the `tableGrob` numbering scheme in mind. ```{r separators, fig.width=8} g <- tableGrob(head(iris), theme = ttheme_minimal()) separators <- replicate(ncol(g) - 2, segmentsGrob(x1 = unit(0, "npc"), gp=gpar(lty=2)), simplify=FALSE) ## add vertical lines on the left side of columns (after 2nd) g <- gtable::gtable_add_grob(g, grobs = separators, t = 2, b = nrow(g), l = seq_len(ncol(g)-2)+2) grid.draw(g) ``` ### Accessing existing grobs in the table We may also access and modify the original content of individual cells, e.g. to highlight a value. ```{r highlight} g <- tableGrob(iris[1:4, 1:3]) find_cell <- function(table, row, col, name="core-fg"){ l <- table$layout which(l$t==row & l$l==col & l$name==name) } ind <- find_cell(g, 3, 2, "core-fg") ind2 <- find_cell(g, 2, 3, "core-bg") g$grobs[ind][[1]][["gp"]] <- gpar(fontsize=15, fontface="bold") g$grobs[ind2][[1]][["gp"]] <- gpar(fill="darkolivegreen1", col = "darkolivegreen4", lwd=5) grid.draw(g) ``` ## Faster tables: an alternative grid function The `tableGrob` function can be very slow; unfortunately this is the price to pay for its versatility and easier implementation. We use individual `textGrob` and `rectGrob` elements for each cell, instead of relying on the vectorised implementation of these functions. The reason is practical: it is much easier to place, measure, and customise individual grobs, than modify the graphical parameters and positions of a single vectorised grob. An alternative function is presented below, using this vectorised approach, but lacking many of the customisations of `tableGrob`. ```{r ftable, fig.width=6} grid.ftable <- function(d, padding = unit(4, "mm"), ...) { nc <- ncol(d) nr <- nrow(d) ## character table with added row and column names extended_matrix <- cbind(c("", rownames(d)), rbind(colnames(d), as.matrix(d))) ## string width and height w <- apply(extended_matrix, 2, strwidth, "inch") h <- apply(extended_matrix, 2, strheight, "inch") widths <- apply(w, 2, max) heights <- apply(h, 1, max) padding <- convertUnit(padding, unitTo = "in", valueOnly = TRUE) x <- cumsum(widths + padding) - 0.5 * padding y <- cumsum(heights + padding) - padding rg <- rectGrob(x = unit(x - widths/2, "in"), y = unit(1, "npc") - unit(rep(y, each = nc + 1), "in"), width = unit(widths + padding, "in"), height = unit(heights + padding, "in")) tg <- textGrob(c(t(extended_matrix)), x = unit(x - widths/2, "in"), y = unit(1, "npc") - unit(rep(y, each = nc + 1), "in"), just = "center") g <- gTree(children = gList(rg, tg), ..., x = x, y = y, widths = widths, heights = heights) grid.draw(g) invisible(g) } grid.newpage() grid.ftable(head(iris, 4), gp = gpar(fill = rep(c("grey90", "grey95"), each = 6))) ``` gridExtra/vignettes/gtable.Rmd0000644000176200001440000001247413152370370016126 0ustar liggesusers--- title: "(Unofficial) overview of gtable" author: "Baptiste Auguie" date: '`r Sys.Date()`' vignette: > %\VignetteEngine{knitr::rmarkdown} %\VignetteIndexEntry{(Unofficial) overview of gtable} output: knitr:::html_vignette: toc: yes --- ```{r setup, echo=FALSE,message=FALSE} require(knitr) opts_chunk$set(fig.width=3,fig.height=3, tidy=FALSE, cache=FALSE, fig.path='gtable/') require(gridExtra) require(grid) require(gtable) require(ggplot2) ``` The R package `gtable` is designed to help construct and manipulate layouts containing graphical elements. The standard `grid` package in R provides low-level functions to define viewports, and place graphical elements (grobs) at specific locations within the device window. `gtable` builds upon these functions and provides a higher-level interface, where one can e.g. merge two layouts, add columns, rows, insert graphical elements in a given cell, and change the display order, among other things. The `gtable` package is used internally by `ggplot2`, and can therefore be used to modify the layout of such plots. ### Constructing a gtable A `gtable` object can be constructed in a variety of ways, * Empty table ```{r, eval=FALSE} gtable(unit(1:3, c("cm")), unit(5, "cm")) ``` This is an empty table with 3 rows and one column. `gtable_col` and `gtable_row` provide a simplified interface for 1 column or 1 row layouts, respectively. * matrix layout of grobs ```{r matrix} a <- rectGrob(gp = gpar(fill = "red")) b <- grobTree(rectGrob(), textGrob("new\ncell")) c <- ggplotGrob(qplot(1:10,1:10)) d <- linesGrob() mat <- matrix(list(a, b, c, d), nrow = 2) g <- gtable_matrix(name = "demo", grobs = mat, widths = unit(c(2, 4), "cm"), heights = unit(c(2, 5), c("in", "lines"))) g ``` Actual drawing of the gtable on a graphics device is performed with `grid.draw()`; note that `plot()` is only defined for debugging purposes, it adds a light grey background and thin grid lines to help visualise the scene in its drawing context. ```{r plot} plot(g) grid.newpage() grid.draw(g) ``` The gridExtra package provides a few conventient constructor functions, e.g. * based on `grid.arrange` ```{r gtable_arrange} dummy_grob <- function(id) { grobTree(rectGrob(gp=gpar(fill=id, alpha=0.5)), textGrob(id)) } gs <- lapply(1:9, dummy_grob) grid.arrange(ncol=4, grobs=gs, top="top\nlabel", bottom="bottom\nlabel", left="left\nlabel", right="right\nlabel") grid.rect(gp=gpar(fill=NA)) ``` * with a pre-defined layout ```{r gtable_from_layout} gt <- arrangeGrob(grobs=gs, layout_matrix=rbind(c(1,1,1,2,3), c(1,1,1,4,5), c(6,7,8,9,9))) grid.draw(gt) grid.rect(gp=gpar(fill=NA)) ``` ### Components of a gtable Let's have a closer look at the gtable we created earlier. ```{r} print(g) names(g) ``` Other useful characteristics of the gtable are, ```{r} length(g); nrow(g); ncol(g) ``` where we note the dual nature of a gtable: it looks like a matrix, in the sense that it defines a rectangular table of nrow x ncol cells, but it's also a _list_ with an arbitrary length, defining where and how many grobs are to be placed in this tabular layout. The most important components are, * `grobs`: This is a list of grobs of `length(g)`. Grobs are placed in the tabular layout defined by the gtable, and multiple grobs can overlap and/or be stacked in the same cell(s). ```{r} length(g$grobs) ``` * `layout`: this is a data.frame indicating the position of each grob. ```{r} g$layout ``` The z-column is used to define the drawing order of the grobs, which becomes relevant when multiple grobs are stacked on top of each others. * `widths` and `heights`: this is the size description of the cells, given as grid units. ```{r} g$widths; g$heights ``` ### Modifying a gtable The gtable package defines several high-level functions to operate on a gtable object, * `t.gtable` to transpose the layout (future versions may support more general rotations) * `[.gtable*`, `gtable_filter`, `gtable_trim` to extract a portion of the gtable * `cbind.gtable*`, `rbind.gtable*` to combine 2 gtable objects (particularly useful for aligning multiple ggplots) * `gtable_add_cols`, `gtable_add_rows`,`gtable_add_col_space`, `gtable_add_row_space`, `gtable_add_padding`, `gtable_col_spacer`, `gtable_row_spacer` Manual operations at the low-level on the gtable can involve the grobs or the layout, but care should be taken to keep the two consistent (e.g. make sure that the length of both are in sync). #### Examples to alter ggplot2 plots with gtable The `gtable` tag on Stack Overlfow has several real-life examples using gtable to alter a ggplot2 before drawing. * aligning (multiple) [ggplot objects on a device](http://stackoverflow.com/a/17768224/471093), another [use-case scenario](http://stackoverflow.com/a/16798372/471093), aligning [base plot and ggplot](http://stackoverflow.com/a/14233531/471093) * adding new grobs [aligned with the plot panel](http://stackoverflow.com/a/17371177/471093), also [this one](http://stackoverflow.com/a/17493256/471093) * calculate [the device size based on the plot aspect ratio](http://stackoverflow.com/a/16442029/471093) * add [new axes to a facet_grid layout](http://stackoverflow.com/a/17661337/471093), or a [second axis](http://stackoverflow.com/a/18511024/471093)gridExtra/vignettes/arrangeGrob.rmd0000644000176200001440000000607413152370123017154 0ustar liggesusers--- title: "Arranging multiple grobs on a page" author: "Baptiste Auguie" date: '`r Sys.Date()`' vignette: > %\VignetteEngine{knitr::rmarkdown} %\VignetteIndexEntry{arrangeGrob: arranging multiple grobs on a page} output: knitr:::html_vignette: toc: yes --- ```{r setup, echo=FALSE, results='hide'} library(knitr) opts_chunk$set(message=FALSE, fig.width=4, fig.height=3) ``` The `grid` package provides low-level functions to create graphical objects (`grobs`), and position them on a page in specific `viewports`. The `gtable` package introduced a higher-level layout scheme, arguably more amenable to user-level interaction. With the `arrangeGrob/grid.arrange()` pair of functions, `gridExtra` builds upon `gtable` to arrange multiple grobs on a page. ## Basic usage In this example we mix a few grobs and plots, ```{r basic} library(gridExtra) library(grid) library(ggplot2) library(lattice) p <- qplot(1,1) p2 <- xyplot(1~1) r <- rectGrob(gp=gpar(fill="grey90")) t <- textGrob("text") grid.arrange(t, p, p2, r, ncol=2) ``` ## Title and/or annotations ```{r annotations} gs <- lapply(1:9, function(ii) grobTree(rectGrob(gp=gpar(fill=ii, alpha=0.5)), textGrob(ii))) grid.arrange(grobs=gs, ncol=4, top="top label", bottom="bottom\nlabel", left="left label", right="right label") grid.rect(gp=gpar(fill=NA)) ``` ## Complex layouts We can provide a matrix defining the layout, ```{r layout} lay <- rbind(c(1,1,1,2,3), c(1,1,1,4,5), c(6,7,8,9,9)) grid.arrange(grobs = gs, layout_matrix = lay) ``` The layout itself may contain holes, but note that for any given grob index the region must be simply connected (no hole), ```{r holes} hlay <- rbind(c(1,1,NA,2,3), c(1,1,NA,4,NA), c(NA,7,8,9,NA)) select_grobs <- function(lay) { id <- unique(c(t(lay))) id[!is.na(id)] } grid.arrange(grobs=gs[select_grobs(hlay)], layout_matrix=hlay) ``` All cells are of equal size by default, but users may pass explicity `widths` and/or `heights` in any valid grid units, or as relative numbers (interpreted as `null`), ```{r sizes, fig.height=2} grid.arrange(grobs=gs[1:3], ncol=2, widths = 1:2, heights=unit(c(1,10), c("in", "mm"))) ``` ## Nested layouts with `arrangeGrob` The `grid.arrange()` function draws on the device; for more complex layouts, we may want to store the gtable and combine it with other objects, e.g. forming nested layouts. To this end, use `arrangeGrob()`, ```{r grob} g1 <- arrangeGrob(grobs = gs, layout_matrix = t(lay)) g2 <- arrangeGrob(grobs = gs, layout_matrix = lay) grid.arrange(g1, g2, ncol=2) ``` ## Multiple pages output Finally, we may want to place grobs on multiple pages; the `marrangeGrob()` function provides a convenient interface for this, also compatible with `ggsave()`. ```{r marrange} set.seed(123) pl <- lapply(1:11, function(.x) qplot(1:10, rnorm(10), main=paste("plot", .x))) ml <- marrangeGrob(pl, nrow=2, ncol=2) ## non-interactive use, multipage pdf ## ggsave("multipage.pdf", ml) ## interactive use; calling `dev.new` multiple times ml ``` gridExtra/vignettes/ngonGrob.Rmd0000644000176200001440000000304613152370460016436 0ustar liggesusers--- title: "Regular polygons and ellipses in grid graphics" author: "Baptiste Auguie" date: '`r Sys.Date()`' vignette: > %\VignetteEngine{knitr::rmarkdown} %\VignetteIndexEntry{ngonGrob: regular polygons and ellipses in grid graphics} output: knitr:::html_vignette: toc: yes --- ```{r setup, echo=FALSE, results='hide'} library(knitr) opts_chunk$set(message=FALSE, fig.width=4, fig.height=3) ``` The `gridExtra` package provides a basic implementation of regular polygons, `ngonGrob()/grid.ngon`, and a convenience function to draw ellipses, `ellipseGrob()/grid.ellipse()`. We illustrate below the basic usage of these vectorised functions. ## Basic usage ```{r basic} library(gridExtra) library(grid) library(grid) N <- 5 xy <- polygon_regular(N)*2 # draw multiple polygons g <- ngonGrob(unit(xy[,1],"cm") + unit(0.5,"npc"), unit(xy[,2],"cm") + unit(0.5,"npc"), n=seq_len(N)+2, gp=gpar(fill=1:N)) grid.newpage() grid.draw(g) ``` ## Rotated and stretched polygons ```{r rotated} g2 <- ngonGrob(unit(xy[,1],"cm") + unit(0.5,"npc"), unit(xy[,2],"cm") + unit(0.5,"npc"), n=seq_len(N)+2, ar=seq_len(N), phase=0, angle=pi/(seq_len(N)+2), size=1:N+5, gp=gpar(fill=1:N)) grid.newpage() grid.draw(g2) ``` ## Ellipses ```{r ellipse} g3 <- ellipseGrob(unit(xy[,1],"cm") + unit(0.5,"npc"), unit(xy[,2],"cm") + unit(0.5,"npc"), angle=-2*seq(0,N-1)*pi/N+pi/2, size=5, ar=3, gp=gpar(fill=1:N)) grid.newpage() grid.draw(g3) ``` gridExtra/MD50000644000176200001440000000370213154773270012526 0ustar liggesusers047776bc6627fccaf183a13f812c6112 *DESCRIPTION 153198ad785493071fa07fe8a66740d6 *NAMESPACE c60486a253b937dfd1271f8e8d3a6383 *R/arrangeGrob.r 22e6d58f19b3df08f6d7b740100035b1 *R/gridExtra-package.r 5735b326ccc84f8589ed60c6331605ff *R/grob-utils.r ccb5c7527b629353e99463100fb1724e *R/gtable.r 255e2a31d659cbe5945ebbfaaffb52db *R/ngonGrob.r 2da174de0b9ddce790fd26404b449341 *R/tableGrob.r f1a22a7575a807d075a85dd687d50167 *R/vectorgrobs.r 0d6f8c1be28afca75b24a3a8d5147eb0 *TODO a6f6d02dc9d39f8cad65bb83b28d6b5b *build/vignette.rds 48b3a65a8eb82ac5675826ac168776e9 *inst/NEWS.md 2c3a8e7d60155397ada30048a9d7ea48 *inst/doc/arrangeGrob.R a450e157273d1e92d7fd7be917734226 *inst/doc/arrangeGrob.html 5d5f9315be48eec1e978ece0ff8fb4bb *inst/doc/arrangeGrob.rmd d8c01fc149e03256760650d81c202569 *inst/doc/gtable.R 18abae81b8ed54cef9e4a40b7b5c79a4 *inst/doc/gtable.Rmd 15a6046b808a7415245adfc9aeb701b4 *inst/doc/gtable.html 390ae82634e9fde9310df2aae9349729 *inst/doc/ngonGrob.R f4705871c7557f395e8f0d95fec4367d *inst/doc/ngonGrob.Rmd f7e1415e0d2c8ce3bc9971c696894bcc *inst/doc/ngonGrob.html 285b5e2615e08ef2a5c8cb045f4f5bd2 *inst/doc/tableGrob.R 283a1a05951a95469780b25c5dd037a4 *inst/doc/tableGrob.Rmd 499810a773b9f4cccb696d41d3829337 *inst/doc/tableGrob.html 618723bd19c005badd6924545e8b0d06 *inst/tests/testthat.r 1c6c2aa851549cbd04b6fa0f8f778f5c *inst/tests/testthat/test-arrangeGrob.R 707773b71f1e28d5e38031757aa2a1d5 *inst/tests/testthat/test-tableGrob.R 0fd7ca9f3991c7c6823e584868a78167 *man/arrangeGrob.Rd 6c1ba3d54c8648f515166a356d32fcc3 *man/bind.Rd 02965a01ebf2c00bcd3f8b39aa3b7111 *man/combine.Rd afb6ff157747fe45622e71a985c107ec *man/gridExtra-package.Rd f8eb5706fb55a7eb18ebe84f4609c6fd *man/ngonGrob.Rd 0d84ff77c8379d0929f1cfa2ce310b89 *man/tableGrob.Rd 5d5f9315be48eec1e978ece0ff8fb4bb *vignettes/arrangeGrob.rmd 18abae81b8ed54cef9e4a40b7b5c79a4 *vignettes/gtable.Rmd f4705871c7557f395e8f0d95fec4367d *vignettes/ngonGrob.Rmd 283a1a05951a95469780b25c5dd037a4 *vignettes/tableGrob.Rmd gridExtra/build/0000755000176200001440000000000013154617417013313 5ustar liggesusersgridExtra/build/vignette.rds0000644000176200001440000000054713154617417015660 0ustar liggesusers‹RÁnÂ0 -´0`ë†ÄÌÇí°î:qFì°Ë„6iWCÓ)Mª¤€¸íç1S’Òî0MQœøÕ~~±û1 ‚ „Q'è†t 'dú´Ç´#ZC:oÐTœ=½LLž:xÄK\J–,jäJq­ª¨3WA5Øf~l0OáäÅ!ßÈR’§´„9si·wïJg™X ”÷ ·ÌlÛÎà$É…=y9S0Œo$(´ÜhU LJQXfA(*$R2X¬Åʺü‡ZúRa ‰û£¸ %û+©ý´q³ië2—¿t]k@qݶx}î[…¶Ùã&ûÂ?? ó8|ñÆ0ÈTŒ'æàóŸqQ—LÇ•ê)Ì™oJßÑ\ÔÓ齉²vÂ×ÙÜ];^ìÅŒL¥~ƒ¶ßiC~»ÐÐè]â‹ÅÇßù“Ìápøú­h%ÑzE¥Xb’Ê'ïû'½i€gridExtra/DESCRIPTION0000644000176200001440000000153213154773270013723 0ustar liggesusersPackage: gridExtra Authors@R: c(person("Baptiste", "Auguie", email = "baptiste.auguie@gmail.com", role = c("aut", "cre")), person("Anton", "Antonov", email = "tonytonov@gmail.com", role = c("ctb"))) License: GPL (>= 2) Title: Miscellaneous Functions for "Grid" Graphics Type: Package Description: Provides a number of user-level functions to work with "grid" graphics, notably to arrange multiple grid-based plots on a page, and draw tables. Version: 2.3 VignetteBuilder: knitr Imports: gtable, grid, grDevices, graphics, utils Suggests: ggplot2, egg, lattice, knitr, testthat RoxygenNote: 6.0.1 NeedsCompilation: no Packaged: 2017-09-08 22:52:09 UTC; baptiste Author: Baptiste Auguie [aut, cre], Anton Antonov [ctb] Maintainer: Baptiste Auguie Repository: CRAN Date/Publication: 2017-09-09 14:12:08 UTC gridExtra/man/0000755000176200001440000000000013152620552012757 5ustar liggesusersgridExtra/man/combine.Rd0000644000176200001440000000135413152661536014674 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/gtable.r \name{gtable_combine} \alias{gtable_combine} \alias{combine} \alias{combine} \title{Combine gtables based on row/column names.} \usage{ gtable_combine(..., along = 1L, join = "outer") combine(..., along = 1L, join = "outer") } \arguments{ \item{...}{gtables} \item{along}{dimension to align along, \code{1} = rows, \code{2} = cols.} \item{join}{when x and y have different names, how should the difference be resolved? \code{inner} keep names that appear in both, \code{outer} keep names that appear in either, \code{left} keep names from \code{x}, and \code{right} keep names from \code{y}.} } \description{ Combine gtables based on row/column names. } gridExtra/man/tableGrob.Rd0000644000176200001440000000323013152354341015145 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tableGrob.r \name{tableGrob} \alias{tableGrob} \alias{grid.table} \alias{ttheme_default} \alias{ttheme_minimal} \alias{grid.table} \alias{ttheme_default} \alias{ttheme_minimal} \title{Graphical display of a textual table} \usage{ tableGrob(d, rows = rownames(d), cols = colnames(d), theme = ttheme_default(), vp = NULL, ...) grid.table(...) ttheme_default(base_size = 12, base_colour = "black", base_family = "", parse = FALSE, padding = unit(c(4, 4), "mm"), ...) ttheme_minimal(base_size = 12, base_colour = "black", base_family = "", parse = FALSE, padding = unit(c(4, 4), "mm"), ...) } \arguments{ \item{d}{data.frame or matrix} \item{rows}{optional vector to specify row names} \item{cols}{optional vector to specify column names} \item{theme}{list of theme parameters} \item{vp}{optional viewport} \item{...}{further arguments to control the gtable} \item{base_size}{default font size} \item{base_colour}{default font colour} \item{base_family}{default font family} \item{parse}{logical, default behaviour for parsing text as plotmath} \item{padding}{length-2 unit vector specifying the horizontal and vertical padding of text within each cell} } \value{ A gtable. } \description{ Create a gtable containing text grobs representing a character matrix. } \section{Functions}{ \itemize{ \item \code{tableGrob}: return a grob \item \code{grid.table}: draw a text table \item \code{ttheme_default}: default theme for text tables \item \code{ttheme_minimal}: minimalist theme for text tables }} \examples{ library(grid) d <- head(iris, 3) g <- tableGrob(d) grid.newpage() grid.draw(g) } gridExtra/man/bind.Rd0000644000176200001440000000110013152367555014165 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/gtable.r \name{gtable_rbind} \alias{gtable_rbind} \alias{gtable_cbind} \title{rbind gtables} \usage{ gtable_rbind(..., size = "max", z = NULL) gtable_cbind(..., size = "max", z = NULL) } \arguments{ \item{...}{gtables} \item{size}{how should the widths be calculated? \code{max} maximum of all widths \code{min} minimum of all widths \code{first} widths/heights of first gtable \code{last} widths/heights of last gtable} \item{z}{optional z level} } \description{ rbind gtables cbind gtables } gridExtra/man/arrangeGrob.Rd0000644000176200001440000000463213152354341015504 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/arrangeGrob.r \name{arrangeGrob} \alias{arrangeGrob} \alias{grid.arrange} \alias{marrangeGrob} \alias{grid.arrange} \alias{marrangeGrob} \title{Arrange multiple grobs on a page} \usage{ arrangeGrob(..., grobs = list(...), layout_matrix, vp = NULL, name = "arrange", as.table = TRUE, respect = FALSE, clip = "off", nrow = NULL, ncol = NULL, widths = NULL, heights = NULL, top = NULL, bottom = NULL, left = NULL, right = NULL, padding = unit(0.5, "line")) grid.arrange(..., newpage = TRUE) marrangeGrob(grobs, ..., ncol, nrow, layout_matrix = matrix(seq_len(nrow * ncol), nrow = nrow, ncol = ncol), top = quote(paste("page", g, "of", npages))) } \arguments{ \item{...}{grobs, gtables, ggplot or trellis objects} \item{grobs}{list of grobs} \item{layout_matrix}{optional layout} \item{vp}{viewport} \item{name}{argument of gtable} \item{as.table}{logical: bottom-left to top-right (TRUE) or top-left to bottom-right (FALSE)} \item{respect}{argument of gtable} \item{clip}{argument of gtable} \item{nrow}{argument of gtable} \item{ncol}{argument of gtable} \item{widths}{argument of gtable} \item{heights}{argument of gtable} \item{top}{optional string, or grob} \item{bottom}{optional string, or grob} \item{left}{optional string, or grob} \item{right}{optional string, or grob} \item{padding}{unit of length one, margin around annotations} \item{newpage}{open a new page} } \value{ arrangeGrob returns a gtable. marrangeGrob returns a list of class arrangelist } \description{ Set up a gtable layout to place multiple grobs on a page. } \details{ Using marrangeGrob, if the layout specifies both nrow and ncol, the list of grobs can be split into multiple pages. On interactive devices print opens new windows, whilst non-interactive devices such as pdf call grid.newpage() between the drawings. } \section{Functions}{ \itemize{ \item \code{arrangeGrob}: return a grob without drawing \item \code{grid.arrange}: draw on the current device \item \code{marrangeGrob}: interface to arrangeGrob that can dispatch on multiple pages }} \examples{ library(grid) grid.arrange(rectGrob(), rectGrob()) \dontrun{ library(ggplot2) pl <- lapply(1:11, function(.x) qplot(1:10, rnorm(10), main=paste("plot", .x))) ml <- marrangeGrob(pl, nrow=2, ncol=2) ## non-interactive use, multipage pdf ggsave("multipage.pdf", ml) ## interactive use; open new devices ml } } gridExtra/man/gridExtra-package.Rd0000644000176200001440000000111713152354341016570 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/gridExtra-package.r \docType{package} \name{gridExtra-package} \alias{gridExtra-package} \alias{gridExtra} \title{Miscellaneous Functions for "Grid" Graphics} \description{ Provides a number of user-level functions to work with "grid" graphics, notably to arrange multiple grid-based plots on a page, and draw tables. } \references{ R Graphics by Paul Murrell (Chapman & Hall/CRC, August 2005) } \seealso{ \code{\link{Grid}} } \author{ baptiste Auguie \email{baptiste.auguie@gmail.com} } \keyword{packagelibrary} gridExtra/man/ngonGrob.Rd0000644000176200001440000000457613152354341015035 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ngonGrob.r \name{ngonGrob} \alias{ngonGrob} \alias{grid.ngon} \alias{ellipseGrob} \alias{grid.ellipse} \alias{grid.ngon} \alias{ellipseGrob} \alias{grid.ellipse} \alias{polygon_regular} \title{Regular polygon grob} \usage{ ngonGrob(x, y, n = 5, size = 5, phase = pi/2, angle = 0, ar = 1, gp = gpar(colour = "black", fill = NA, linejoin = "mitre"), ..., position.units = "npc", size.units = "mm") grid.ngon(...) ellipseGrob(x, y, size = 5, angle = pi/4, ar = 1, n = 50, gp = gpar(colour = "black", fill = NA, linejoin = "mitre"), ..., position.units = "npc", size.units = "mm") grid.ellipse(...) polygon_regular(n = 5, phase = 0) } \arguments{ \item{x}{x unit} \item{y}{y unit} \item{n}{number of vertices} \item{size}{radius of circumscribing circle} \item{phase}{angle in radians of first point relative to x axis} \item{angle}{angle of polygon in radians} \item{ar}{aspect ratio} \item{gp}{gpar} \item{...}{further parameters passed to polygonGrob} \item{position.units}{default units for the positions} \item{size.units}{grid units for the sizes} } \value{ A grob. } \description{ Regular polygons with optional rotation, stretching, and aesthetic attributes. } \section{Functions}{ \itemize{ \item \code{ngonGrob}: return a polygon grob \item \code{grid.ngon}: draw a polygon grob on the current device \item \code{ellipseGrob}: return an ellipse grob \item \code{grid.ellipse}: draw an ellipse grob \item \code{polygon_regular}: return the x,y coordinates of a regular polygon inscribed in the unit circle }} \examples{ library(grid) N <- 5 xy <- polygon_regular(N)*2 # draw multiple polygons g <- ngonGrob(unit(xy[,1],"cm") + unit(0.5,"npc"), unit(xy[,2],"cm") + unit(0.5,"npc"), n = seq_len(N) + 2, gp = gpar(fill=1:N)) grid.newpage() grid.draw(g) # rotated and stretched g2 <- ngonGrob(unit(xy[,1],"cm") + unit(0.5,"npc"), unit(xy[,2],"cm") + unit(0.5,"npc"), n = seq_len(N) + 2, ar = seq_len(N), phase = 0, angle = pi/(seq_len(N) + 2), size = 1:N + 5) grid.newpage() grid.draw(g2) # ellipse g3 <- ellipseGrob(unit(xy[,1],"cm") + unit(0.5,"npc"), unit(xy[,2],"cm") + unit(0.5,"npc"), angle = -2*seq(0,N-1)*pi/5 + pi/2, size = 5, ar = 1/3) grid.newpage() grid.draw(g3) } gridExtra/.Rinstignore0000644000176200001440000000002113152662554014511 0ustar liggesuserstesting/ revdep/