tableGrob alignment and spacing in Rmarkdown/knitr-HTML document - r

I have the following issues when using the nice feature tableGrob() from gridExtra package to plot a table in an html document produced by Rmarkdown and knitr.
Here is a reproducible example:
library(datasets)
library(dplyr)
mtcars$cyl <- as.factor(mtcars$carb)
carb.mpg <- mtcars %>%
select(carb,mpg) %>%
group_by(carb) %>%
summarise_each(funs(sum(.,na.rm=TRUE)),-carb) %>%
arrange(desc(mpg))
##plot the table
tab <- tableGrob(carb.mpg, cols=c("carb","mpg"),
theme=ttheme_minimal())
grid.arrange(tab, top=textGrob("Cars MPG per CARB",gp=gpar(fontsize=16,font=1)) )
For knitr general chunk options:
title: "Test with cars"
output:
html_document:
keep_md: true
{r setoptions, echo=FALSE}
library(knitr)
opts_chunk$set(message=FALSE,warning=FALSE)
The issue as can been seen from the attached snapshot is the huge space between the table and its title and legend. It would be also nice if I could left-align the table in the document.
Any help would be much appreciated.

you could try this
tg <- textGrob("Cars MPG per CARB", gp=gpar(fontsize=16,font=1))
grid.arrange(tg, tab, heights=unit.c(grobHeight(tg), sum(tab$heights)),
vp=viewport(x=unit(0,"npc") +
0.5*unit.pmax(grobWidth(tg),
sum(tab$widths))))

After some tweaking, I found that the position of the table can be controlled using viewport (x and y); width/height seem obsolete.
#plot the table
tab <- tableGrob(carb.mpg, cols=c("carb","mpg"),
theme=ttheme_minimal())
grid.newpage()
vp <- viewport(width=0.90,height=0.90,x=0.10,y=0.80,clip="on")
pushViewport(vp)
grid.draw(tab)
This solves the problem only partially: the huge vertical space is still there.
Perhaps this gives some direction to resolving the issue?
EDIT: one way that worked for me to control the white spaces/margins was to reduce the figure size parameters in knitr chunk options, i.e.,
{r plot mpg cars, fig.height=value, fig.width=value}

Related

R - How to change size of a whole figure produced by grid.arrange?

I want to display multiple ggplot objects in one figure using package gridExtra. It works, but titles are cut. I can fix it by changing plots font size, but I would rather change the width of the whole figure so that it is wide enough to fit in titles (and as wide as other outputs in my RMarkdown doc, e.g. the table right over it). I've tried to change margins by typing par(mai = 2*par('mai')) before call to grid.arrange, but it did nothing. Does anyone know how to do it properly? I am really confused about the gridExtra package.
library(gridExtra)
g <- grid.arrange(zad4_kl$pw, zad4_kl$pk, zad4_kl$pp, zad4_AC$pw, zad4_AC$pk, zad4_AC$pp, nrow = 2)
g
Screenshot of produced output
If you are saving the image, then you can increase the width and dpi in ggsave.
In R Markdown, you can use fig.width and fig.height
{r, echo=FALSE, fig.width=8, fig.cap="A nice image."}
library(gridExtra)
g <- grid.arrange(zad4_kl$pw, zad4_kl$pk, zad4_kl$pp, zad4_AC$pw, zad4_AC$pk, zad4_AC$pp, nrow = 2)
g
If rendered image doesn't fit the Markdown output, then you will have to change font in individual plots.

How do I get Bookdown to properly knit a PDF with multiple code chunks?

I am transitioning to Bookdown from Markdown. Although it seems as though this should be straightforward I am getting an unexpected knit failure once I have added the 3rd (usually) code chunk in a chapter (not index.rmd) file. I have tried using code from the example code by Allaire and Xie with the same result. The problem does not occur if all the markdown code is in one file i.e. no chapters. Here is the sample code from the index and 1st chapter files. Sorry about the formatting; I'm not sure how to format markdown code in stackoverflow so the 3 back tics consistently show.
---
classoption: openany # Removes blank pages (Arrgh!!)
site: "bookdown::bookdown_site"
output:
bookdown::tufte_book2:
latex_engine: xelatex
---
```{r setup, include=FALSE}
library(ggplot2)
# invalidate cache when the tufte version changes
knitr::opts_chunk$set(tidy = FALSE, cache.extra = packageVersion("tufte"))
```
And this is the first chapter code:
# Figures
## Margin Figures
Images and graphics play an integral role in Tufte's work. To place figures in the margin you can use the **knitr** chunk option `fig.margin = TRUE`. For example:
```{r fig-margin, fig.margin = TRUE, fig.cap = "MPG vs horsepower, colored by transmission.", fig.width=3.5, fig.height=3.5, cache=TRUE, message=FALSE}
library(ggplot2)
mtcars2 <- mtcars
mtcars2$am <- factor(
mtcars$am, labels = c('automatic', 'manual')
)
ggplot(mtcars2, aes(hp, mpg, color = am)) +
geom_point() + geom_smooth() +
theme(legend.position = 'bottom')
```
In fact, you can include anything in the margin using the **knitr** engine named `marginfigure`. Unlike R code chunks ```` ```{r} ````, you write a chunk starting with ```` ```{marginfigure} ```` instead, then put the content in the chunk. See an example on the right about the first fundamental theorem of calculus.
```{marginfigure}
We know from _the first fundamental theorem of calculus_ that for $x$ in $[a, b]$:
$$\frac{d}{dx}\left( \int_{a}^{x} f(u)\,du\right)=f(x).$$
```
It fails here
knitr::kable(
mtcars[1:6, 1:6], caption = 'A subset of mtcars.'
)
Deleting the code after "It fails here" makes it knit properly for me.
Dropbox link with scripts, log, and pdf's.

How to embed plots into a tab in RMarkdown in a procedural fashion?

I can embed plots using just RMarkdown's {.tabset}
#### Heading {.tabset}
##### Subheading 1
```{r, echo=F}
df[[1]]
```
This produces individual tabs with the specified graphs (df is a list of graphs, calling df[[i]] produces a graph) in the preview pane (renders all the graphs inline in RStudio).
And I can generate just the tabs using a for loop.
```{r, results='asis', echo = FALSE}
for (i in 1:length(gg0)) {
cat("##### ",q$Subheading[i],"\n")
}
```
And this produces the desired output - the tabs with the names in the Subheading column.
However, I am stuck in trying to generate the graphs themselves using the for loop similar to how I did when I coded it manually.
Extending the above, I tried to generate the markdown that produced the initial output but the plot fails to generate (both in the inline markdown and preview).
```{r, results='asis', echo = FALSE}
for (i in 1:length(gg0)) {
cat("##### ",q$Subheading[i],"\n")
cat('```{r, echo=F} \n')
cat("gg0[[",i,"]]\n")
cat('``` \n')
}
```
Maybe I am missing a finer point regarding markdown? I have tried various patterns using cat (and even without)
I would prefer a RMarkdown solution but other solutions are just as welcome.
I played around a little and found a solution. You have to use print within the asis code chunk...
```{r}
library(ggplot2)
gg0 <- list()
gg0[[1]] <- ggplot(mtcars, aes(mpg, hp)) + geom_point()
gg0[[2]] <- ggplot(mtcars, aes(mpg, disp)) + geom_point()
gg0[[3]] <- ggplot(mtcars, aes(mpg, drat)) + geom_point()
headings <- c('hp','disp','drat')
```
#### Heading {.tabset}
```{r, results='asis', echo = FALSE}
for (i in 1:length(gg0)) {
cat("##### ",headings[i],"\n")
print(gg0[[i]])
cat('\n\n')
}
```
As an explanation, the cat command together with results='asis' produces the markdown code for a lower level headline and prints the ggplot graph afterwards. Since we used `{.tabset} in the parent headline, it creates the plots in separate tabs.
Adding both plot.new(), dev.off() inside the for loop solves the problem of adding all the figures in the last tab. See the complete solution here.

Print RMarkdown captions from a loop

I am creating a series of plots from within a loop in an RMarkdown document, then knitting this to a PDF. I can do this without any problem, but I would like the caption to reflect the change between each plot. A MWE is shown below:
---
title: "Caption loop"
output: pdf_document
---
```{r, echo=FALSE}
library(tidyverse)
p <-
map(names(mtcars), ~ggplot(mtcars) +
geom_point(aes_string(x = 'mpg', y = .))) %>%
set_names(names(mtcars))
```
```{r loops, fig.cap=paste(for(i in seq_along(p)) print(names(p)[[i]])), echo=FALSE}
for(i in seq_along(p)) p[[i]] %>% print
```
I have made a first attempt at capturing the plots and storing in a variable p, and trying to use that to generate the captions, but this isn't working. I haven't found too much about this on SO, despite this surely being something many people would need to do. I did find this question, but it looks so complicated that I was wondering if there is a clear and simple solution that I am missing.
I wondered if it has something to do with eval.after, as with this question, but that does not involve plots generated within a loop.
many thanks for your help!
It seems that knitr is smart enough to do the task automatically. By adding names(mtcars) to the figure caption, knitr iterates through these in turn to produce the correct caption. The only problem now is how to stop all of the list indexes from printing in the document...
---
title: "Caption loop"
output: pdf_document
---
```{r loops, fig.cap=paste("Graph of mpg vs.", names(mtcars)), message=FALSE, echo=FALSE, warning=FALSE}
library(tidyverse)
map(
names(mtcars),
~ ggplot(mtcars) +
geom_point(aes_string(x = 'mpg', y = .))
)
```
In case this might be useful to somebody. Here is an adaptation of Jonny's solution for captions without printing list indices. This can be achieved by using purrr::walk instead of purrr::map. Also included is a latex fig label and text that references each plot.
---
title: "Loop figures with captions"
output:
pdf_document
---
```{r loops, fig.cap=paste(sprintf("\\label{%s}", names(mtcars)), "Graph of mpg vs.", names(mtcars)),results='asis', message=FALSE, echo=FALSE, warning=FALSE}
library(tidyverse)
library(stringi)
walk(names(mtcars),
~{
p <- ggplot(mtcars) +
geom_point(aes_string(x = 'mpg', y = .))
#print plot
cat('\n\n')
print(p)
#print text with refernce to plot
cat('\n\n')
cat(sprintf("Figure \\ref{%s} is a Graph of mpg vs. %s. %s \n\n", ., .,
stri_rand_lipsum(1)))
cat("\\clearpage")
})
```

Controlling the size and number of graphs per pdf page generated by ggplot loop in R markdown

I would like to generate a pdf document, using R markdown, to display a series of plots made using ggplot in a for loop. Is it possible to control number of plots on each page so there is, for example, a 2 X 2 grid of plots per page?
I'd like to maintain the flexibility so that I can change the total number of graphs, so that it splits across the appropriate number of pages.
My attempt using ggplot2 and gridExtra packages is below, but I can't control the number of graphs per page, it seems to want to squeeze them on to a sinlge page only. I've tried changing the ncol,nrow,heights,widths arguments in grid.arrange but it doesn't seem to help.
---
title: "ggplot Layout"
output: pdf_document
---
```{r,figure2 fig.height=8, fig.width=6,echo=FALSE,message=FALSE}
library(ggplot2)
library(gridExtra)
graphlist<-list()
count <- 1
colnums<-c(1,5,6,7,8,9,10)
for (i in colnums) {
plot.x.name<-names(diamonds[i])
p <- ggplot(data=diamonds,aes_string(x = plot.x.name)) + geom_histogram()
graphlist[[count]]<-p
count <- count+1
}
do.call("grid.arrange",c(graphlist,ncol=2))
```
The type of thing I'm looking for is demonstrated by this code (adapted from
http://kbroman.github.io/knitr_knutshell/pages/figs_tables.html), but this doesn't work with ggplot, unfortunately.
---
title: "Example Layout"
output: pdf_document
---
```{r bunch_o_figs,fig.height=8, fig.width=6, message=FALSE,echo=FALSE}
n <- 100
x <- rnorm(n)
par(mfrow=c(2,2), las=1)
for(i in 1:20) {
y <- i*x + rnorm(n)
plot(x, y, main=i)
}
``
You could try marrangeGrob
---
title: "ggplot Layout"
output: pdf_document
---
```{r figure2 , fig.height=8, fig.width=6,echo=FALSE,message=FALSE}
library(ggplot2)
library(gridExtra)
graphlist <- replicate(10, qplot(1,1), simplify = FALSE)
do.call("marrangeGrob",c(graphlist,ncol=2,nrow=2))
```

Resources