bnjmn
bnjmn

Reputation: 4584

R knitr Markdown: Output Plots within For Loop

I would like to create an automated knitr report that will produce histograms for each numeric field within my dataframe. My goal is to do this without having to specify the actual fields (this dataset contains over 70 and I would also like to reuse the script).

I've tried a few different approaches:

I'm afraid the intricacies of the plot devices are escaping me.

Question

How can I make the following chunk output each plot within the loop to the report? Currently, the best I can achieve is output of the final plot produced by saving it to an object and calling that object outside of the loop.

R markdown chunk using knitr in RStudio:

```{r plotNumeric, echo=TRUE, fig.height=3}
suppressPackageStartupMessages(library(ggplot2))
FIELDS <- names(df)[sapply(df, class)=="numeric"]
for (field in  FIELDS){
  qplot(df[,field], main=field)  
}
```

From this point, I hope to customize the plots further.

Upvotes: 79

Views: 45258

Answers (5)

user66081
user66081

Reputation: 458

For knitting Rmd to HTML, I find it more convenient to have a list of figures. In this case I get the desirable output with results='hide' as follows:

---
title: "Make a list of figures and show it"
output: 
  html_document
---


```{r}
suppressPackageStartupMessages({
  library(ggplot2)
  library(dplyr)
  requireNamespace("scater")
  requireNamespace("SingleCellExperiment")
})
```


```{r}
plots <- function() {
  print("print")
  cat("cat")
  message("message")
  warning("warning")
  
  # These calls generate unwanted text
  scater::mockSCE(ngene = 77, ncells = 33) %>%
    scater::logNormCounts() %>%
    scater::runPCA() %>%
    SingleCellExperiment::reducedDim("PCA") %>%
    as.data.frame() %>%
    {
      list(
        f12 = ggplot(., aes(x = PC1, y = PC2)) + geom_point(),
        f22 = ggplot(., aes(x = PC2, y = PC3)) + geom_point()
      )
    }
}
```

```{r, message=FALSE, warning=TRUE, results='hide'}
plots()
```

Only the plots are shown and the warnings (which you can switch off, as well).

Upvotes: 1

Yang Liu
Yang Liu

Reputation: 541

Wish to add a quick note: Somehow I googled the same question and get into this page. Now in 2018, just use print() in the loop.

for (i in 1:n){
...
    f <- ggplot(.......)
    print(f)
}

Upvotes: 29

Alex
Alex

Reputation: 15738

As an addition to Hugo's excellent answer, I believe that in 2016 you need to include a print command as well:

```{r run-numeric-md, include=FALSE}
out = NULL
for (i in c(1:num_vars)) {
  out = c(out, knit_child('da-numeric.Rmd'))
}

`r paste(out, collapse = '\n')`
```

Upvotes: 3

Hugo Koopmans
Hugo Koopmans

Reputation: 1369

I am using child Rmd files in markdown, also works in sweave.

in Rmd use following snippet:

```{r run-numeric-md, include=FALSE}
out = NULL
for (i in c(1:num_vars)) {
  out = c(out, knit_child('da-numeric.Rmd'))
}
```

da-numeric.Rmd looks like:

Variabele `r num_var_names[i]`
------------------------------------

Missing :  `r sum(is.na(data[[num_var_names[i]]]))`  
Minimum value : `r min(na.omit(data[[num_var_names[i]]]))`  
Percentile 1 : `r quantile(na.omit(data[[num_var_names[i]]]),probs = seq(0, 1, 0.01))[2]`  
Percentile 99 : `r quantile(na.omit(data[[num_var_names[i]]]),probs = seq(0, 1, 0.01))[100]`  
Maximum value : `r max(na.omit(data[[num_var_names[i]]]))`  

```{r results='asis', comment="" }
warn_extreme_values=3
d1 = quantile(na.omit(data[[num_var_names[i]]]),probs = seq(0, 1, 0.01))[2] > warn_extreme_values*quantile(na.omit(data[[num_var_names[i]]]),probs = seq(0, 1, 0.01))[1]
d99 = quantile(na.omit(data[[num_var_names[i]]]),probs = seq(0, 1, 0.01))[101] > warn_extreme_values*quantile(na.omit(data[[num_var_names[i]]]),probs = seq(0, 1, 0.01))[100]
if(d1){cat('Warning : Suspect extreme values in left tail')}
if(d99){cat('Warning : Suspect extreme values in right tail')}
```

``` {r eval=TRUE,  fig.width=6, fig.height=2}
library(ggplot2)

v <- num_var_names[i]
hp <- ggplot(na.omit(data), aes_string(x=v)) + geom_histogram( colour="grey", fill="grey", binwidth=diff(range(na.omit(data[[v]]))/100))

hp + theme(axis.title.x = element_blank(),axis.text.x = element_text(size=10)) + theme(axis.title.y = element_blank(),axis.text.y = element_text(size=10))

```

see my datamineR package on github https://github.com/hugokoopmans/dataMineR

Upvotes: 11

cbeleites
cbeleites

Reputation: 14093

Wrap the qplot in print.

knitr will do that for you if the qplot is outside a loop, but (at least the version I have installed) doesn't detect this inside the loop (which is consistent with the behaviour of the R command line).

Upvotes: 66

Related Questions