I am working to stick two PNGs side by side and then convert the concatenated object to a PDF using the code below. Now how can I write all the PDF objects as pages in a single file? I tried to save all the objects in a list and then pass the list to image_write(), but it did not work.
library(magick)
vec_out <- list()
for(i in 1:length(all_stims)){
stim <- all_stims[i]
img1 <- image_read(file.path(figures_folder, "across_cluster_heatmaps", paste0("bendall_",stim,".png")))
img2 <- image_read(file.path(figures_folder, "across_cluster_heatmaps", paste0("farmer_", stim,".png")))
imgs <- c(img1, img2)
imgs <- image_append(imgs)
imgs_pdf <- image_convert(imgs)
vec_out[[i]] <- imgs_pdf
}
image_write(vec_out, path = file.path(figures_folder, "test.pdf"), format = "pdf")
Any suggestions would be helpful. Thanks.
Couldn't you write a knitr-document instead, or as rmarkdown-file?
I could not run your code, since it's not reproducible.
A mini example in rmarkdown:
The following code produces 3 plots in a for-loop.
By choosing result = 'asis' as option and by inserting
cat("\n\n\\pagebreak\n") in the for-loop, every output is printed on a separate page.
---
title: "Test page break between two figures"
output: pdf_document
---
```{r, echo=FALSE, results='asis'}
for (i in 1:3) {
print(plot(1:i, rnorm(i)))
cat("\n\n\\pagebreak\n")
}
```
I suggest doing something as mentioned above, instead of creating in a first step all pdf-files separately and glue them together in a second step.
Related
Using the 'mtcars' dataset, how can one split the dataset into clusters using the 'Carb' field and output each grid on a separate pdf document with the Carb value being the name of the pdf document. I am new in R and the solutions I have found enable one to save each cluster on a different page of a pdf document. Have not found one where its possible to save each cluster as a separate document.
You can create pdfs for each part of dataset using approach of parameterized reports in Rmarkdown and not just creating tables, you can create a whole report for each clusters of the dataset.
So to do that, we need to first create a template rmarkdown file containing code for printing data as table where we also need to specify params in yaml of the file.
---
title: "Untitled"
author: "None"
date: '2022-07-26'
output: pdf_document
params:
carb: 1
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
## R Markdown table
```{r, echo=FALSE}
data(mtcars)
df <- mtcars[mtcars$carb %in% params$carb,]
knitr::kable(df, caption = paste("mtcars table for carb", params$carb))
```
Then from a separate R file (r script) or from console run this code which will create six pdfs for each value of carb
lapply(unique(mtcars$carb), function(carb_i) {
rmarkdown::render("tables.Rmd",
params = list(carb = carb_i),
output_file = paste0("table_for_carb",carb_i, ".pdf"))
})
So, for example, table_for_carb1.pdf looks like this
To know more how to create parameterized report with rmarkdown, see here
Here is an option with package gridExtra.
library(gridExtra)
sp <- split(mtcars, mtcars$carb)
lapply(seq_along(sp), \(i) {
carb <- names(sp)[i]
filename <- sprintf("carb%s.pdf", carb)
pdf(filename)
grid.table(sp[[i]])
dev.off()
})
To write the clusters to the same PDF file, one table per page, start by exporting the first table, then, in the lapply loop go to next page and export the next table. The new pages must be between the tables and there must already exist a page (the 1st) before starting a new one for the next table.
And since the filename doesn't depend on the number of carburetors, the code can be simplified and rewritten without the need for seq_along.
library(grid)
library(gridExtra)
sp <- split(mtcars, mtcars$carb)
pdf("carb.pdf")
grid.table(sp[[1]])
lapply(sp[-1], \(x) {
grid.newpage()
grid.table(x)
})
dev.off()
This is what Im doing to generate a markdown so that all the things should be in one place.
How can i put these output into a datatable form which are more readable and easier to search.The list which is made are of different length. Each list has a series of table under it.
If there a way to convert these differing length list to data table format that would be really helpful
The table looks like this
## Prepare for analyses
```{r,warning=FALSE,message=FALSE}
set.seed(1234)
library(europepmc)
library(tidypmc)
library(tidyverse)
#library(dplyr)
```
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
```
##Cytarabine cytogenetically normal aml adult clinical trial Randomized Controlled Trial. 828 records found, showing 10
```{r,include=FALSE}
b <-epmc_search(query = 'cytarabine cytogenetically normal aml adult clinical trial Randomized Controlled Trial OPEN_ACCESS:Y',limit = 10)
pmcids <- b$pmcid[b$isOpenAccess=="Y"]
docs <- map(pmcids, epmc_ftxt)
my_tables <- map(docs, pmc_table)
```
```{r}
names(my_tables) <- pmcids
```
The code chunk input and output is then displayed as follows:
```{r basicconsole}
source("flat.R")
L1 <- flattenlist(my_tables)
l.f <- Filter(function(a) any(!is.na(a)), L1)
l.f
#tibble:::print.tbl_df(head(df))
#n <- paste0("Valporic_", names(l.f), ".txt")
for (i in 1:length(l.f)) {
write.table(l.f[i], sep = "\t",row.names = FALSE,col.names = TRUE,file=paste0(names(l.f)[i], ".txt"))
}
UPDATE
I have manged to covert those tibble into dataframe
using this solution
##Outout
```{r}
abc <- mapply(cbind, l.f)
abc
But when it is rendered in the markdown the column formatting is gone. Now i have now dataframe inside list.
But still im not sure how to put that into a data table
**UPDATE 2.0 **
The better approach is to read those saved output as list of files into data table and then use it as markdown but so far it is taking only one ID only. My code.
tbl_fread <-
list.files(pattern = "*.txt") %>%
map_df(~fread(.))
knitr::kable(head(tbl_fread), "pipe")
Is it possible to put these files as such.
if a list of file are from one PMCID then those would be all in one column such as if PMCID one has 3 output then all of them should be one the same row. Then the next PMCID in the second one etc etc.
UPDATE new
I have managed to align the output into more readable format. But It seems that by default all the files assigned to multiple columns which would be the case given that im reading all the files together since my idea of using the list to data table didn't work.
If i can push or stack each unique PMCID over one another instead of all in one after another that would be. Good
knitr::kable(tbl_fread, align = "lccrr")
This may be something you can adapt for R Markdown. I'm not sure what the rationale is to save and load the tables. Instead, you could obtain the tables and show in html directly.
As you are using HTML, make sure to have results='asis' in your chunk. You can use a for loop and seq_along to show each table. You can include information in your table caption, such as the PMCID as well as table number.
---
title: "test13121"
author: "Ben"
date: "1/31/2021"
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
# Libraries
```{r}
library(tidypmc)
library(tidyverse)
library(europepmc)
library(kableExtra)
```
# Get Articles
```{r, echo = FALSE}
b <-epmc_search(query = 'cytarabine aml OPEN_ACCESS:Y',limit = 6)
pmcids <- b$pmcid[b$isOpenAccess=="Y"]
docs <- map(pmcids, epmc_ftxt)
my_tables <- map(docs, pmc_table)
names(my_tables) <- pmcids
```
# Show Tables
```{r, echo=F, results='asis'}
for (i in seq_along(my_tables)) {
for (j in seq_along(my_tables[[i]])) {
print(kable(x = my_tables[[i]][[j]], caption = paste0(names(my_tables)[i], ": Table ", j)))
}
}
```
There are already a few questions considering ggplots in RMarkdown but none has answered my question as how to put a ggplot into a table with kable() by knitr.
I ve tried this link:
How can I embed a plot within a RMarkdown table?
But have not had any luck so far. Any ideas?
The idea was to put all plots into a list with
a<-list(p1,p2,p3...)
and then having the table with
{r}kable(a)
Additional text should also be able to be included
b<-("x","y","z",...)
kable (c(a,b),col.names=c())
Thanks for your help
Frieder
I experimented some with this and the following is the best I could come up with. This is a complete markdown document you should be able to paste into RStudio and hit the Knit button.
Two relevant notes here.
Setting the file links directly into kable doesn't work as it is wrapped in html such that it is interpreted as text, so we need to gsub() it in. An alternative is to set kable(..., escape = FALSE), but it is a risk that other text might cause problems.
Also, the chunk option results = 'asis' is necessary to have the print(kab) return raw html.
I don't know if these are problems for the real application.
---
title: "Untitled"
author: "me"
date: "02/06/2020"
output: html_document
---
```{r, results = 'asis'}
library(ggplot2)
library(svglite)
n <- length(unique(iris$Species))
data <- split(iris, iris$Species)
# Create list of plots
plots <- lapply(data, function(df) {
ggplot(df, aes(Sepal.Width, Sepal.Length)) +
geom_point()
})
# Create temporary files
tmpfiles <- replicate(n, tempfile(fileext = ".svg"))
# Save plots as files, get HTML links
links <- mapply(function(plot, file) {
# Suit exact dimensions to your needs
ggsave(file, plot, device = "svg", width = 4, height = 3)
paste0('<figure><img src="', file, '" style = "width:100%"></figure>')
}, plot = plots, file = tmpfiles)
# Table formatting
tab <- data.frame(name = names(plots), fig = paste0("dummy", LETTERS[seq_len(n)]))
kab <- knitr::kable(tab, "html")
# Substitute dummy column for figure links
for (i in seq_len(n)) {
kab <- gsub(paste0("dummy", LETTERS[i]), links[i], kab, fixed = TRUE)
}
print(kab)
```
I have found my way around it as described in the link I posted.
I. Saved my plot as a picture
II. Used sprintf() to insert picture into table with this command from Rmarkdown:
![](path/to/file)
Poor, but it works. If anybody finds a solution, I will always be interested in smart coding.
I have several datasets each of which have a common grouping factor. I want to produce one large report with separate sections for each grouping factor. Therefore I want to re-run a set of rmarkdown code for each iteration of the grouping factor.
Using the following approach from here doesnt work for me. i.e.:
---
title: "Untitled"
author: "Author"
output: html_document
---
```{r, results='asis'}
for (i in 1:2){
cat('\n')
cat("#This is a heading for ", i, "\n")
hist(cars[,i])
cat('\n')
}
```
Because the markdown I want to run on each grouping factor does not easily fit within one code chunk. The report must be ordered by grouping factor and I want to be able to come in and out of code chunks for each iteration over grouping factor.
So I went for calling an Rmd. with render using a loop from an Rscript for each grouping factor as found here:
# run a markdown file to summarise each one.
for(each_group in the_groups){
render("/Users/path/xx.Rmd",
output_format = "pdf_document",
output_file = paste0(each_group,"_report_", Sys.Date(),".pdf"),
output_dir = "/Users/path/folder")
}
My plan was to then combine the individual reports with pdftk. However, when I get to the about the 5th iteration my Rstudio session hangs and eventually aborts with a fatal error. I have ran individually the Rmd. for the grouping factors it stops at which work fine.
I tested some looping with the following simple test files:
.R
# load packages
library(knitr)
library(markdown)
library(rmarkdown)
# use first 5 rows of mtcars as example data
mtcars <- mtcars[1:5,]
# for each type of car in the data create a report
# these reports are saved in output_dir with the name specified by output_file
for (car in rep(unique(rownames(mtcars)), 100)){
# for pdf reports
rmarkdown::render(input = "/Users/xx/Desktop/2.Rmd",
output_format = "pdf_document",
output_file = paste("test_report_", car, Sys.Date(), ".pdf", sep=''),
output_dir = "/Users/xx/Desktop")
}
.Rmd
```{r, include = FALSE}
# packages
library(knitr)
library(markdown)
library(rmarkdown)
library(tidyr)
library(dplyr)
library(ggplot2)
```
```{r}
# limit data to car name that is currently specified by the loop
cars <- mtcars[rownames(mtcars)==car,]
# create example data for each car
x <- sample(1:10, 1)
cars <- do.call("rbind", replicate(x, cars, simplify = FALSE))
# create hypotheical lat and lon for each row in cars
cars$lat <- sapply(rownames(cars), function(x) round(runif(1, 30, 46), 3))
cars$lon <- sapply(rownames(cars), function(x) round(runif(1, -115, -80),3))
cars
```
Today is `r Sys.Date()`.
```{r}
# data table of cars sold
table <- xtable(cars[,c(1:2, 12:13)])
print(table, type="latex", comment = FALSE)
```
This works fine. So I also looked at memory pressure while running my actual loop over the Rmd. which gets very high.
Is there a way to reduce memory when looping over a render call to an Rmd. file?
Is there a better way to create a report for multiple grouping factors than looping over a render call to an Rmd. file, which doesn't rely on the entire loop being inside one code chunk?
Found a solution here rmarkdown::render() in a loop - cannot allocate vector of size
knitr::knit_meta(class=NULL, clean = TRUE)
use this line before the render line and it seems to work
I am dealing with the same issue now and it's very perplexing. I tried to create some simple MWEs but they loop successfully on occasion. So far, I've tried
Checking the garbage collection between iterations of rmarkdown::render. (They don't reveal any special accumulations.)
Removing all inessential objects
Deleting any cached files manually
Here is my question:
How can we debug hangs? Should we set up special log files to understand what's going wrong?
I'm familiar with R markdown "parameters".
However, say I want to generate the same report (same chart, same table) but for 5 different regions.
Is there a way to do this elegantly in a loop or lapply or do I need to make several sections. So in pseudo code I want to do something like:
for(i in 1:5):
Bunch of text
table[i]
plot[i]
Instead of
bunch of text
table[1]
plot[1]
bunch of text
table[2]
plot[2]
...
Put another way, I want to functionalize a "section" of the report, and then I can call
for(i in 1:5):
makeReport(i)
And it will go in, put in the text, figures, etc associated with index i.
You have to call print explicitly if inside for loop:
```{r}
for(i in 1:2) {
print(summary(cars[,-i]))
plot(cars[,-i])
}
```
or
```{r}
makeReport <- function(i) {
print(summary(cars[,-i]))
plot(cars[,-i])
}
for(i in 1:2) {
makeReport(i)
}
```
Update
As Stéphane Laurent already demonstrated in Dynamic number of calls to a chunk with knitr
you can define a child .rmd:
test_section.rmd
Header: `r i`-th cars
```{r}
print(summary(cars[,-i]))
plot(cars[,-i])
```
and in the main rmd file concatenate the results:
```{r runall, include=FALSE}
out <- NULL
for (i in 1:2) {
out <- c(out, knitr::knit_child('test_section.rmd'))
}
```
`r paste(out, collapse = '\n')`