How do I embed images in a list of dataframes?

2020-05-01 06:09发布

问题:

This is a related question to a post I made a few weeks ago here. I am trying to embed QR codes in a new column in a list of dataframes. The QR code will contain the numerical result from the other column and can be scanned into our lab information system. Thus far i am able to generate a dataframe with a column containing QR codes using RMarkdown, but I can't seem to do it when I try to adapt this code to a list of dataframes.

Here is an example of what does what I want with a single dataframe:

---
title: "QR Code in Column"
author: "dorton"
date: "2019/01/20"
output: pdf_document
---

```{r mychunk1, fig.show = "hide", echo = FALSE, message=FALSE, warning=FALSE, out.width="72px", include=TRUE}
library(knitr)
library(qrcode)

test <- LETTERS[1:10]
result.one <- round(rnorm(1:10),2)
df <- data.frame(test, result.one, stringsAsFactors = FALSE)
df$result.one <- as.character(df$result.one) #qrcode_gen needs a character input    

invisible(lapply(df$result.one, function(x) qrcode_gen(x)))

out <- cbind(as.character(df$test), 
             as.character(df$result.one), 
             include_graphics(sprintf("![](%s%s-%s.png){width=72px}", 
                                 opts_current$get("fig.path"), 
                                 opts_current$get("label"), 
                                 1:nrow(df))))
kable(out, col.names = c("ID", "Text", "Code"))
```

In reality, I have a list of dataframes containing "results" for "test" A-J. What I want is to loop through the list of dataframes and embed QR codes in each dataframe, but I can't seem to figure out how to do this. Here is an example of an attempt that doesn't work:

```{r mychunk, fig.show = "hide", echo = FALSE, message=FALSE, warning=FALSE, out.width="72px"}

library(knitr)
library(qrcode)

test <- LETTERS[1:10]
result.one <- round(rnorm(1:10),2))
result.two <- round(rnorm(11:20), 2)
df1 <- data.frame(test, result.one, stringsAsFactors = FALSE)
df2 <- data.frame(test, result.two, stringsAsFactors = FALSE)
df1$result.one <- as.character(df1$result.one)
df2$result.two <- as.character(df2$result.two)
colnames(df1) <- c("test", "result")
colnames(df2) <- c("test", "result")

df.list <- list(df1, df2)

for (i in length(df.list)){
  invisible(lapply(df.list[[i]]$result, function(x) qrcode_gen(x)))

  out <- cbind(as.character(df.list[[i]]$test), 
             as.character(df.list[[i]]$result), 
             include_graphics(sprintf("![](%s%s-%s.png){width=72px}", 
                                 opts_current$get("fig.path"), 
                                 opts_current$get("label"), 
                                 1:nrow(df.list[[i]]))))
}

  for (i in df.list){
  cat("\n\\newpage\n") #This is to add a page break between output tables. I would like to use a pdf output, but I'm not stuck on it.
  kable(out.qr, col.names = c("Test", "Result", "Code"), caption = paste0("Sample ID"))
}

```

I have tried a few different iterations of the second code chunk. I expect that it has something to do with where the png's that I am generating with the invisible(lapply(df.list[[i]]$result, function(x) qrcode_gen(x))) are being saved, but i can't seem to figure out an alternative. Can I generate a list of lists for the pngs? Do I have to?

Any help is much appreciated, and I'm not stuck on using rmarkdown either!

回答1:

This was a little difficult to figure and the soultion might not be as elegant as possible. But it works. If I find some time tomorrow Ill try to get deeper into it.

Notice that qrcodes are numbered from 1 to the total number of rows in all data frames. So we have to take care of this using the counter total and save the number of codes per dataframe when creating them (in nums).


---
title: "QR Code in Column"
author: "dorton"
date: "2019/01/20"
output: pdf_document     
---


```{r mychunk, echo = FALSE, fig.path =  "qr/", results = 'asis', fig.show='hide'}
library(knitr)
library(qrcode)
df.list <- list(A = data.frame(result = as.character(rnorm(2)),                    
                               test = LETTERS[1:2], stringsAsFactors = F),
                B = data.frame(result = as.character(rnorm(2)),
                               test = LETTERS[3:4], stringsAsFactors = F))

nums <- invisible(sapply(df.list, function(df) {
  lapply(df$result, qrcode_gen)  # create qrcode
  nrow(df)                       # save number of rows of df
}))

path <- paste0(opts_current$get("fig.path"), opts_current$get("label"), "-")

total <- 0
for(i in seq_along(nums)) {
  out <- cbind(df.list[[i]]$test,
               df.list[[i]]$result,
               paste0("![](", path, (1:nums[i]) + total, ".pdf){width=72px}")) 

  print(kable(out))
  total <- total + nums[1] 
}
```