Error in plot.new() : figure margins too large in Rmarkdown - r

I am having a strange problem within Rmarkdown. The following code works flawlessly if it has to plot for only 3-4 datasets (tested) but as soon the number of datasets increase to 9 or more. I get a strange error.
code:
```{r scRNALoadData, echo=FALSE, message=FALSE, warning=FALSE, include=TRUE, warnings=FALSE, eval=TRUE, results="asis"}
# Loading of libraries
suppressPackageStartupMessages(library(scater))
suppressPackageStartupMessages(library(mvoutlier))
suppressPackageStartupMessages(library(Rtsne))
suppressPackageStartupMessages(library(limma))
suppressPackageStartupMessages(library(ggplot2))
suppressPackageStartupMessages(library(repr))
suppressPackageStartupMessages(library(cowplot))
suppressPackageStartupMessages(library(knitr))
suppressPackageStartupMessages(library(Matrix))
suppressPackageStartupMessages(library(rmarkdown))
suppressPackageStartupMessages(library(SingleCellExperiment))
suppressPackageStartupMessages(library(scran))
suppressPackageStartupMessages(library(scRNAseq))
#suppressPackageStartupMessages(library(iSEE))
suppressPackageStartupMessages(library(SCopeLoomR))
options(stringsAsFactors = FALSE)
# Loading expression data
loadSCE <- function(path){
sce <- scater::read10XResults(path)
#sce <- normalize(sce) # Data normalization based on scran
mitochondrialGenes <- as.character(rowData(sce)[startsWith(rowData(sce)$symbol, "mt-"),]$id)
isSpike(sce, "mt") <- rownames(sce) %in% mitochondrialGenes
sce <- calculateQCMetrics(sce,
feature_controls = list(
MT = isSpike(sce, "mt")
))
}
# Read-in expression sample scRNA matrix from directory
paths <- list.dirs(path = "/Abhi/test/test2/", recursive = FALSE)
for (i in 1:length(paths))
assign(paste0("sce_",i), loadSCE(paths[i]))
sce=0
for (i in 1:length(paths))
sce[i]<-print(noquote(paste0("sce_",i)))
t_list <- list()
t_list <- mget(ls(pattern="sce_\\d+"))
for(i in seq_along(t_list))
{
metadata(t_list[[i]])["name"] <- paste0("iMates-",i)
}
```
### Library size
``` {r scRNALibrarySize, echo=FALSE, message=FALSE, warning=FALSE, include=TRUE, warnings=FALSE, eval=TRUE, results="asis"}
# Single Cell RNA plot library histogram
plotLibrarySize <- function(sce, cutoffPoint){
options(repr.plot.width=4, repr.plot.height=4)
hist(
sce$total_counts,
breaks = 100
)
abline(v = cutoffPoint, col = "red")
}
# Single Cell RNA plot library box
plotLibrarySize.Box <- function(sce, cutoffPoint){
options(repr.plot.width=4, repr.plot.height=4)
(sce$total_counts)
}
# Summary stats
for (i in 1:length(paths))
print(sum(get(sce[i])$total_counts))
# Plot histograms library size
l<-length(paths)
ll<-round(l/2, digits=0)
par(mfrow=c(ll,2))
for (i in 1:length(paths)) {
plotLibrarySize(get(paste0("sce_",i)), 2500) }
# Plot box library size
l<-length(paths)
par(mfrow=c(ll,2))
for (i in 1:length(paths)) {
b<-plotLibrarySize.Box(get(paste0("sce_",i)),2500)
boxplot(b)
}
```
The error that I get is
Quitting from lines 48-79 (tq.Rmd)
Error in plot.new() : figure margins too large
Calls: <Anonymous> ... hist -> hist.default -> plot -> plot.histogram -> plot.new
Execution halted
Where line 48 is beginning of the second block of R code.
Can anyone help me in fixing this error.
I have seen other posts as well
"Error in plot.new() : figure margins too large"
I have executed the code in both console and within rstudio.
Many thanks in advance.

Related

R Markdown Knitted PDF doc keeps showing messages even when {r, message=FALSE}

I silenced messages and it still shows the ## Setting default kernel parameters message from the ksvm function.
Keep in mind that in the original code there are 9 ksvm functions going on. I omitted most of them because stackoverflow wouldn't let me post a bunch of code with little text.
{r, echo=FALSE, message=FALSE, warnings=FALSE, error=FALSE, fig.align='center'}
#1
model1.ksvm <- ksvm(as.matrix(training[,1:10]),as.factor(training[,11]),
type='C-svc',kernel='vanilladot',C=3,scaled=TRUE)
pred <- predict(model1.ksvm,validation[,1:10])
vanilla3 <- sum(pred == validation[,11]) / nrow(validation)
#8
model1.ksvm <- ksvm(as.matrix(training[,1:10]),as.factor(training[,11]),
type='C-svc',kernel='laplacedot',C=6,scaled=TRUE)
pred <- predict(model1.ksvm,validation[,1:10])
lp6 <- sum(pred == validation[,11]) / nrow(validation)
#9
model1.ksvm <- ksvm(as.matrix(training[,1:10]),as.factor(training[,11]),
type='C-svc',kernel='laplacedot',C=10,scaled=TRUE)
pred <- predict(model1.ksvm,validation[,1:10])
lp10 <- sum(pred == validation[,11]) / nrow(validation)
tab.ksvm <- as.table(rbind(c(vanilla3, vanilla6, vanilla10), c(rbf3, rbf6, rbf10), c(lp3,lp6,lp10)))
dimnames(tab.ksvm) <- list(kernel = c("vanilladot", "rbfdot",'laplacedot'),
C = c("3", "6", "10"))
tab.ksvm
Output:
If you look at the source, you'll see that ksvm is not using message, it's using cat. That's generally bad practice (IMO, precisely for the reason you are citing), but suppressMessages and thus knitr's message=FALSE are not going to work.
You can try something like the below to capture the output from just those functions:
```{r, echo=FALSE, message=FALSE, warnings=FALSE, error=FALSE, fig.align='center'}
#1
ign <- capture.output({
model1.ksvm <- ksvm(as.matrix(training[,1:10]),as.factor(training[,11]),
type='C-svc',kernel='vanilladot',C=3,scaled=TRUE)
})
pred <- predict(model1.ksvm,validation[,1:10])
vanilla3 <- sum(pred == validation[,11]) / nrow(validation)
```
(Don't go too crazy with capture.output, though, or you'll subvert much of what knitr is trying to do.)
Proof it works (I don't have an easy ksvm proof handy):
---
title: sink check
---
```{r, echo = FALSE}
# test 1
cat("hello\n")
myvar <- 1
myvar
```
```{r, echo = FALSE}
# test 2
ign <- capture.output({
cat("hello again\n")
myvar <- 2
})
myvar
```

wrong order of mixed textual and graphical output in the final output document

Within a for loop I decide to create some graphics and related tables.
The tables are created with writeLines() and print().
For creating the graphics I use plot(), boxplot(), mtext(), text(), axis().
So one graphic is created in many steps. Each graphic for it self is complete and nice.
My problem is:
when I knit the markdown document in Rstudio the graphics and tables are not in the correct place.
The first graphic is shown at the place, where the second should be or a little before, after cor.test.default() tells me a warning. Definitively it is shown during the next pass of the for loop.
Conclusion of the Problem
Creating textual output in adition to graphics is mixed up under special circumstances
For reproducing the problem I create some data
All the computations are collected in the "workingChunk"
For demonstrating the problem I use the chunk "loops" at the end.
So read the last chunk first
In the second loop the FIRST graphic is placed in the output
during the SECOND passage of the loop, after the function cor.test() comes up with the warning.
As well the SECOND graphic is placed in the output
during the THIRD passage of the loop, after the function cor.test() comes up with the warning.
and so on.
I found a workarround for this problem but it is not really handy:
When I replace the for loop with single chunk-calls, then the output is in the correct order.
So I'm sure that the reason for the problem is the interaction of the for loop and the function cor.test()
Here is the Example-code (about 140 lines):
---
title: "Test graphic & textual output"
output:
pdf_document: default
word_document:
html_document:
df_print: paged
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
```{r creatingData, echo=TRUE}
### {r creatingData, echo=TRUE}
# creating some data
a.df <- data.frame(height=c(1:19),
width=c(21:39)*10,
depht=c(41:59)*20,
group=c(1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3))
a.df$groupF <- as.factor(a.df$group)
Vars <- names(a.df)[c(1:3)]
```
```{r workingChunk, echo=TRUE, eval=FALSE}
cat("\n===================================================================\n",
"following the calculations for:\n",
"YVar:",YVar, "\n Group:", "group", "\n")
# Daten für Auswertung extrahieren
selvar <- c("group","groupF", YVar)
# Datensätze mit Fehlwerten in der Zielvariablen ausschließen!
a.sub <- a.df[ complete.cases(a.df[ , selvar]), selvar]
# print(str(a.sub))
## Tabelle für gruppierte Zielgrößen
mT <- table(a.sub[ , c("groupF", YVar)])
print(ftable(addmargins(mT))) ## absolute Häufigkeiten
writeLines("\n")
if (runCorTest) {
## calculating Spearmans correlation
myCorTest <- try(cor.test(a.sub[["group"]], a.sub[[YVar]],
method = "spearman", alternative = "two.sided" ))
print(myCorTest)
writeLines("\n")
}
## preparing the grafic
GL.x1 <- levels(a.sub[["groupF"]]) ## grouplabels
# Calculating the range of Y
my.ylim <- c(min(a.sub[[YVar]], na.rm = TRUE), max(a.sub[[YVar]], na.rm = TRUE))
at.x <- c(1:length(GL.x1)) ## Labelpositionen anlegen
G.data <- vector("list", length(GL.x1)) ## Vektoren für die Daten der Gruppen anlegen
# Daten der Gruppen herausziehen
G.data <- split(a.sub[[YVar]], a.sub["groupF"])
# print(str(G.data))
## drawing emtpy plot
cat("\n\n>>> Here should be placed the Grafik for:",YVar, "<<<\n")
plot( x = NA, y = NA, type = "n",
main = YVar,
xlim = c( 1, length( GL.x1)) + c( -0.6, 0.6),
ylim = my.ylim,
xlab = NA, ylab = NA,
axes = FALSE, frame.plot = TRUE)
# X-axis
axis( 1, las = 1, labels = FALSE)
mtext(GL.x1, at = at.x, cex=0.8, side = 1, line = .3)
# Y-axis
axis( 2, las = 1)
## drawing the data
for (i in 1:length(G.data)){
boxplot(G.data[i], # col = "white",
at = at.x[i], range = 0, add = TRUE,
boxwex = 0.6, yaxs = "i", axes = FALSE)
}
```
```{r, loops, echo=FALSE}
cat("\n===================================================================",
"\n===================================================================\n",
"calling the workingChunk within a for loop without executing cor.test()",
"\n works fine!!",
"\n===================================================================",
"\n===================================================================\n")
runCorTest <- FALSE
for ( YVar in Vars) {
<<workingChunk>>
}
cat("\n===================================================================",
"\n===================================================================\n",
"calling the workingChunk within a for loop with executing cor.test() ",
"\n mixes up the textual output and the graphics!!",
"\n===================================================================",
"\n===================================================================\n")
runCorTest <- TRUE
for ( YVar in Vars) {
<<workingChunk>>
}
cat("\n===================================================================",
"\n===================================================================\n",
"calling the workingChunk with executing cor.test() ",
"\n workarround without a for loop works fine!!",
"\n===================================================================",
"\n===================================================================\n")
runCorTest <- TRUE
YVar <- Vars[1]
<<workingChunk>>
YVar <- Vars[2]
<<workingChunk>>
YVar <- Vars[3]
<<workingChunk>>
```
Not a real answer but a much shorter test case and a workaround:
---
title: "Test graphic & textual output"
output:
html_document:
df_print: paged
word_document: default
pdf_document:
keep_tex: yes
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
```{r}
foo <- function(letter, warn) {
cat("Doing", letter, "\n")
print(letter)
if (warn) warning(letter)
cat("Graphic for", letter, "goes here", "\n")
plot(1, main = letter)
}
```
# with loop and with warning
```{r}
for (letter in letters[1:3])
foo(letter, TRUE)
```
# with loop and without warning
```{r}
for (letter in letters[1:3])
foo(letter, FALSE)
```
# without loop and with warning
```{r}
foo("a", TRUE)
foo("b", TRUE)
foo("c", TRUE)
```
# with loop and with suppressed warning
```{r warning=FALSE}
for (letter in letters[1:3])
foo(letter, TRUE)
```
Besides removing all of the data processing, I have also switched from a named chunk to a function, which I find more idiomatic in R. That does not change the strange ordering, though.
If the warning message is not important in your case, you can use the workaround shown in the end: Suppressing the warning with the chunk option warning=FALSE restores the ordering.

edgebundle doesn't render plot when in loop in markdown

I'm trying to create an automated report where I create a series of chord graphs using edgebundleR.
I have a function that does a bunch of stuff and has more or less this form:
plot_chords <- function(x,t,pos) {
...
stuff I do with the data
...
g <- graph.adjacency(mydata, mode="upper", weighted=TRUE, diag=FALSE)
return(edgebundle(g))
}
This function works properly if I don't use it inside a loop. It doesn't if it is in a loop like this:
```{r echo = FALSE,message=FALSE, warning = FALSE,results = "asis"}
for (c in unique(df$Group)) {
cat("\n\n## ",c," - Negative Correlations (min r=",t_neg," - only significative)\n\n")
plot_chords(subset(df, Group == c),0.5,0)
}
```
I found that in general, this doesn't work inside loops unless I use print:
for (c in unique(df$Group)) {
temp=df[df$Group == c,]
print(plot_chords(temp,0.5,0))
}
But print doesn't work in markdown.
How can I render the plot?
Thanks.
The edgebundle call returns an htmlwidget and works, as you noted, well when not in a loop. A solution to your situation would be use the for loop to generate several specific R code chunks in a temporary file and then evaluate that that temporary file as a child file in your primary .Rmd file.
For example, in a .Rmd file these two chunks will load the needed packages and define a function foo which creates and shows a random edgebundle.
```{r}
set.seed(42)
library(edgebundleR)
library(igraph)
```
## test the function
```{r}
foo <- function() {
adjm <- matrix(sample(0:1, 100, replace = TRUE, prob = c(0.6, 0.4)), nc = 10)
g <- graph.adjacency(adjm)
edgebundle(g)
}
```
Calling foo twice in a chunk will work as expected in the output .html document.
```{r}
foo()
foo()
```
To generate several edgebudles in a for loop try this. Write a for loop to populate a temp.Rmd file with the needed R chunks. You will need to modify this as needed for your application.
## test the function in a for loop
```{r}
tmpfile <- tempfile(fileext = ".Rmd")
for(i in 1:3) {
cat("### This is edgebundle", i, "of 3.\n```{r}\nfoo()\n```\n",
file = tmpfile, append = TRUE)
}
```
The contents of tmpfile look like this:
### This is edgebundle 1 of 3.
```{r}
foo()
```
### This is edgebundle 2 of 3.
```{r}
foo()
```
### This is edgebundle 3 of 3.
```{r}
foo()
```
To display the widgets in your primary output file use a chunk like this:
```{r child = tmpfile}
```
The full .Rmd file and result:
example.Rmd:
# edgebundleR and knitr
Answer to https://stackoverflow.com/questions/47926520/edgebundle-doesnt-render-plot-when-in-loop-in-markdown
```{r}
set.seed(42)
library(edgebundleR)
library(igraph)
```
## test the function
```{r}
foo <- function() {
adjm <- matrix(sample(0:1, 100, replace = TRUE, prob = c(0.6, 0.4)), nc = 10)
g <- graph.adjacency(adjm)
edgebundle(g)
}
foo()
foo()
```
## test the function in a for loop
```{r}
tmpfile <- tempfile(fileext = ".Rmd")
for(i in 1:3) {
cat("### This is edgebundle", i, "of 3.\n```{r}\nfoo()\n```\n",
file = tmpfile, append = TRUE)
}
```
```{r child = tmpfile}
```
```{r}
print(sessionInfo(), local = FALSE)
```

Rmarkdown Chunk Name from Variable

How can I use a variable as the chunk name? I have a child document which gets called a number of times, and I need to advance the chunk labels in such a manner than I can also cross reference them.
Something like this:
child.Rmd
```{r }
if(!exists('existing')) existing <- 0
existing = existing + 1
myChunk <- sprintf("myChunk-%s",existing)
```
## Analysis Routine `r existing`
```{r myChunk,echo = FALSE}
#DO SOMETHING, LIKE PLOT
```
master.Rmd
# Analysis Routines
Analysis for this can be seen in figures \ref{myChunk-1}, \ref{myChunk-2} and \ref{myChunk-3}
```{r child = 'child.Rmd'}
```
```{r child = 'child.Rmd'}
```
```{r child = 'child.Rmd'}
```
EDIT POTENTIAL SOLUTION
Here is one potential workaround, inspired by SQL injection of all things...
child.Rmd
```{r }
if(!exists('existing')) existing <- 0
existing = existing + 1
myChunk <- sprintf("myChunk-%s",existing)
```
## Analysis Routine `r existing`
```{r myChunk,echo = FALSE,fig.cap=sprintf("The Caption}\\label{%s",myChunk)}
#DO SOMETHING, LIKE PLOT
```
A suggestion to preknit the Rmd file into another Rmd file before knitting&rendering as follows
master.Rmd:
# Analysis Routines
Analysis for this can be seen in figures `r paste(paste0("\\ref{", CHUNK_NAME, 1:NUM_CHUNKS, "}"), collapse=", ")`
###
rmdTxt <- unlist(lapply(1:NUM_CHUNKS, function(n) {
c(paste0("## Analysis Routine ", n),
paste0("```{r ",CHUNK_NAME, n, ", child = 'child.Rmd'}"),
"```")
}))
writeLines(rmdTxt)
###
child.Rmd:
```{r,echo = FALSE}
plot(rnorm(100))
```
To knit & render the Rmd:
devtools::install_github("chinsoon12/PreKnitPostHTMLRender")
library(PreKnitPostHTMLRender) #requires version >= 0.1.1
NUM_CHUNKS <- 5
CHUNK_NAME <- "myChunk-"
preknit_knit_render_postrender("master.Rmd", "test__test.html")
Hope it helps. Cheers!
If you're getting to this level of complexity, I suggest you look at the brew package.
That provides a templating engine where you can dynamically create the Rmd for knitting.
You get to reference R variables in the outer brew environment, and build you dynamic Rmd from there.
Dynamic chunk names are possible with knitr::knit_expand(). Arguments are referenced in the child document, including in the chunk headers, using {{arg_name}}.
So my parent doc contains:
```{r child_include, results = "asis"}
###
# Generate a section for each dataset
###
species <- c("a", "b")
out <- lapply(species, function(sp) knitr::knit_expand("child.Rmd"))
res = knitr::knit_child(text = unlist(out), quiet = TRUE)
cat(res, sep = "\n")
```
And my child doc, which has no YAML header, contains:
# EDA for species {{sp}}
```{r getname-{{sp}}}
paste("The species is", "{{sp}}")
```
See here in the RMarkdown cookbook.

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:
saving the plot to an object, p, and then calling p after the loop
This only plots the final plot
Creating an array of plots, PLOTS <- NULL, and appending the plots within the loop PLOTS <- append(PLOTS, p)
Accessing these plots out of the loop did not work at all
Even tried saving each to a .png file but would rather not have to deal with the overhead of saving and then re-accessing each file
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.
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).
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)
}
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
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')`
```
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).

Resources