3

{r setup, include=FALSE, message=FALSE, results="hide"} knitr::opts_chunk$set(echo = TRUE) library(knitr) library(kfigr) library(dplyr) library(png) library(grid) library(pander) library(ggplot2)

Question

Loops in rmarkdown: in-text figure reference? figure captions?

Goal

Use a for loop to create sections with text, in-text results, and multiple figure references with associated figure captions in the figure list. The figure references/numbering should be seemless with figures numbered before and after these new sections.

Note: The figures referenced in the for loop are generated earlier in the text, saved as pngs, and then re-loaded. This might seem clunky for the purpose of this example, but the actual figs are maps and are slow to generate (I plan to comment out the loop that generates the figures once I have them how I want).

{r echo = FALSE, warnings=FALSE, message=FALSE, results="hide"}

Data: Each year we have a different number of strata, hence the need for a loop.

df <- rbind(
  data.frame(strata = rep("A", 10), x = rnorm(10, mean= 10), y = rnorm(10, mean = 15),z = rnorm(10, mean = 20)),
  data.frame(strata = rep("B", 10), x = rnorm(10, mean= 5), y = rnorm(10, mean = 10), z = rnorm(10, mean = 15)),
  data.frame(strata = rep("C", 10), x = rnorm(10, mean= 15), y = rnorm(10, mean = 20), z = rnorm(10, mean = 10)))

first_plot: the figure that should appear in the list before for loop creates the sections by strata

first_plot <- ggplot(df, aes(x, fill=strata)) + geom_histogram()

last_plot: the figure that should appear in the list after the for loop creates the sections by strata

last_plot <- ggplot(df, aes(x = strata, y = z)) + geom_boxplot()

Figure generation (this is the part that will be commented out later in my version once I have the maps how I want)

strat <- unique(df$strata)

for (i in seq_along(strat)) {
  sub <- df %>% filter(strata %in% strat[i])
  fig1 <- ggplot(sub, aes(x = x, y = y)) + geom_point()
  ggsave(fig1, file=paste0("fig1_", strat[i], ".png"))
  fig2 <- ggplot(sub, aes(x = x, y = z)) + geom_point() 
  ggsave(fig2, file=paste0("fig2_", strat[i], ".png"))
}    

Load the png's

df_figs <- list.files(pattern = "\\.png$")
for (i in df_figs){  
   name <- gsub("-",".",i)
   name <- gsub(".png","",name)  
   i <- paste(".\\",i,sep="")
   assign(name,readPNG(i))
}

Introduction section

Some introductory text in the report and a figure r figr('first_plot',TRUE, type='Figure').

```{r echo = FALSE, warnings=FALSE, message=FALSE, results = "asis"}

# Summary of results and image file names that will be references in text
results <- df %>% 
  group_by(strata) %>% 
  dplyr::summarise_each(funs(mean)) %>% 
  mutate(fig1 = paste0("fig1_", strata),
         fig2 = paste0("fig2_", strata))

#Text template (each strata will have its own section)
template <- "# The %s stratum
The mean of *x* in %s stratum was %1.1f. Relationships between *x* and *y* and *x* and *z* can be found in `r figr('%s', TRUE, type='Figure')` and `r figr('%s', TRUE, type='Figure')`.

"

#Create markdown sections in for loop
for(i in seq(nrow(results))) {
  current <- results[i, ]
  cat(sprintf(template, 
              current$strata, current$strata, 
              current$x, 
              current$fig1, current$fig2))
}

#Also doesn't work:
template <- "# The %s stratum
The mean in %s stratum was %1.0f. Results can be found in "
template2 <- " and "
template3 <- ".

"

`figr('%s', TRUE, type='Figure')` and `figr('%s', TRUE, type='Figure')`."

#For loop
for(i in seq(nrow(results))) {
  current <- results[i, ]
  cat(sprintf(template,
            current$strata, current$strata,
            current$mean,
            current$fig_1, current$fig_2))
  print(paste0("`r figr(",paste0("'", current$fig1,"'"), TRUE, type='Figure'))
  cat(sprintf(template2))
  print(paste0("`r figr(",paste0("'", current$fig2,"'"), "TRUE, type='Figure'),`"))
  cat(sprintf(template3))
 }
```

Conclusion section

Some discussion text in the report and figure r figr('last_plot',TRUE, type='Figure').

Figures

*NOTE:* I don't know how to automate the looped portion of the list of figures here, so I've done it by hand.

```{r 'first_plot', echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6,  fig.cap="The caption for the first figure."}
suppressMessages(print(first_plot))
```

```{r 'fig1_A', echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6,  fig.cap="Caption text for fig1_A."}
grid.raster(fig1_A)
```

```{r 'fig2_A', echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6,  fig.cap="Caption text for fig2_A."}
grid.raster(fig2_A)
```

```{r 'fig1_B', echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6,  fig.cap="Caption text for fig1_B."}
grid.raster(fig1_B)
```

```{r 'fig2_B', echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6,  fig.cap="Caption text for fig2_B."}
grid.raster(fig2_B)
```

```{r 'fig1_C', echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6,  fig.cap="Caption text for fig1_C."}
grid.raster(fig1_C)
```

```{r 'fig2_C', echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6,  fig.cap="Caption text for fig2_C."}
grid.raster(fig2_C)
```

```{r 'last_plot', echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6,  fig.cap="The caption for the last figure."}
suppressMessages(print(last_plot))
```
4

1 回答 1

1

解决方案

  1. 利用knit_expand()
  2. 使用captioner代替kfigr
  3. 这会在文本和报告末尾对您的数字(或表格)进行编号。
  4. 此脚本向您展示了如何在 for 循环中创建对数字的文本引用的降价段落。
  5. 它还向您展示了如何在 for 循环中创建自定义图形标题,同时保留数字顺序。
  6. 如果你展示如何使用我做#4 和#5,brew我会给你所有的 SO 点。

图书馆

library(knitr) library(dplyr) library(png) library(grid) library(pander) library(ggplot2) library(devtools) library(captioner)

使用包创建一个fig_nums()函数captioner( https://github.com/adletaw/captioner/blob/master/vignettes/using_captioner.Rmd )

fig_nums <- captioner(prefix = "Figure")

数据

每年我们都有不同数量的地层,因此需要一个循环。

df <- rbind(
  data.frame(strata = rep("A", 10), x = rnorm(10, mean= 10), y = rnorm(10, mean = 15), z = rnorm(10, mean = 20)),
  data.frame(strata = rep("B", 10), x = rnorm(10, mean= 5), y = rnorm(10, mean = 10), z = rnorm(10, mean = 15)),
  data.frame(strata = rep("C", 10), x = rnorm(10, mean= 15), y = rnorm(10, mean = 20), z = rnorm(10, mean = 10)))

first_plot: for 循环之前应该出现在列表中的图形按层创建部分

first_plot <- ggplot(df, aes(x, fill=strata)) + geom_histogram()
fig_nums("first_plot", display = FALSE)

last_plot: for 循环后应出现在列表中的图形按层创建部分

last_plot <- ggplot(df, aes(x = strata, y = z)) + geom_boxplot()

图生成

一旦你有你想要的无花果,就把这个部分注释掉。如果您在 R 中进行大量映射,这一步不会让人感到复杂、不自然、次优、不必要,或者是一个非常糟糕的主意。

strat <- unique(df$strata)

  for (i in seq_along(strat)) {
   sub <- df %>% filter(strata %in% strat[i])
   fig1 <- ggplot(sub, aes(x = x, y = y)) + geom_point()
   ggsave(fig1, file=paste0("fig1_", strat[i], ".png"))
   fig2 <- ggplot(sub, aes(x = x, y = z)) + geom_point() 
   ggsave(fig2, file=paste0("fig2_", strat[i], ".png"))
 }        

加载png的

df_figs <- list.files(pattern = "\\.png$")
for (i in df_figs){  
   name <- gsub("-",".",i)
   name <- gsub(".png","",name)  
   i <- paste(".\\",i,sep="")
   assign(name,readPNG(i))
}

介绍

报告中的一些介绍性文字和一张图r fig_nums("first_plot", display="cite")

将在文本中引用的结果和图像文件名:

```{r echo = FALSE, warnings=FALSE, message=FALSE, results = "asis"}

    results <- df %>% 
      group_by(strata) %>% 
      dplyr::summarise_each(funs(mean)) %>% 
      mutate(fig1 = paste0("fig1_", strata),
             fig2 = paste0("fig2_", strata))

```

```{r run-numeric-md, warning=FALSE, include=FALSE}

#The text for the markdown sections in for loop... the knit_expand() is the work-horse here.

out = NULL
for (i in as.character(unique(results$strata))) {
  out = c(out, knit_expand(text=c('#### The *{{i}}* strata',
                                  '\n',
                                  'The mean of *x* is ',
                                  '{{paste(sprintf("%1.1f", results$x[results$strata==i]))}}', '({{fig_nums(results$fig1[results$strata==i],display="cite")}}).',
                                  '\n'
  )))
}

```

为每个层创建部分

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

结论

报告和图中的一些讨论文字r fig_nums("last_plot",display="cite")

图列表

`r fig_nums("first_plot",caption="Here is the caption for the first figure.")`

```{r 'first_plot', echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6}
suppressMessages(print(first_plot))
```

```{r figcaps, include=FALSE}
caps = NULL

for (i in as.character(unique(results$strata))) {
  caps = c(caps, knit_expand(  
    text=c({{fig_nums(results$fig1[results$strata==i], caption="Caption text for strata *{{i}}* goes here.")}},
           '``` {r {{results$fig1[results$strata==i]}}, echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6}',
           {{paste0('grid.raster(',results$fig1[results$strata==i],')')}},
                                    '```',
           '\n')))
}

#DON'T FORGET TO UNLIST!
src <- unlist(caps)
```

`r paste(knit(text = src),sep='\n')`

`r fig_nums("last_plot", caption="The caption for the last figure.")`

```{r 'last_plot', echo=FALSE, warning=FALSE, fig.width=6.5, fig.height=6}
suppressMessages(print(last_plot))
```
于 2016-12-29T23:18:37.147 回答