首页 > 解决方案 > 从 RMarkdown 中的数据框中渲染项目符号列表

问题描述

如何将此数据框转换为

https://docs.google.com/spreadsheets/d/1Z_qdynfqA8f95sNUPq-zPw9NNk5rqT9cV8yTUOwZXrk/edit#gid=0

嵌套子弹?像这样的东西:

大子弹 1

大子弹 2

大子弹 3

这就是想法。

在一个需要项目符号叙述的情节之后,我有一个部分。如果叙述在电子表格中,与我一起工作的人不了解 R,并且更容易与他们协作(并同时自动生成)。

我对此感到茫然。我的尝试没有奏效。PS我正在使用正确的参数 knit_global() 采购外部脚本

标签: rr-markdownmarkdownknitr

解决方案


dplyr使用也许可以解决。给定一个列表

  • 一个
    • AA
      • AA1
      • AA2
    • AB
      • AB1

哪个将具有 excel/R 结构

  bullet_1 bullet_2 bullet_3
1        A       AA      AA1
2        A       AA      AA2
3        A       AB      AB1

我们可以group_bysummarise(使用paste)从底层开始迭代,并且对于每个连续的迭代,通过按少一个变量分组,在列表中上升一级。即对于第一次迭代,group_by 级别 1 (A) 和级别 2 (AA, AB)。这应该导致

  bullet_1 bullet_2 bullet_3   
1        A       AA      "AA2, AA1"
2        A       AB      AB1

二、分组方式bullet_1

  bullet_1 bullet_2 
1        A       "AA, AA2, AA1, AB, AB1"

最后

  bullet_1  
1        "A, AA, AA2, AA1, AB, AB1"

在整体之间添加一些 Markdown 列表输出并处理 excel(NA)中的空单元格,这种非常快速而肮脏的尝试可能是一个起点(替换路径read_excel

```{r, echo=FALSE, results='asis'}

library(dplyr)

frameLoop <- readxl::read_excel("path/to/xlsxfile.xlsx") %>% 

  #add newlines (\n) after each entry to create list structure further down the road. 
  #NA's will be removed later. If NAs are converted to "", will interfere with
  #list structure
  mutate_all(function(x) ifelse(is.na(x), x ,paste0(x, "\n"))) %>% 
  replace(is.na(.), "@NA@")


frameNcol <- ncol(frameLoop)

# Number of indentations (measured in number of spaces) needed to create list
# structure in markdown. Hard coded, the list can be generated for max 3 levels
numSpaces <- c(0, 2, 4)

# Vectors of column names.
# The dynamic is updated each iteration such that columns which are
# removed are not attempted to used in summarise().
bulletNamesDynamic <- bulletNamesStatic <- colnames(frameLoop)

#Counting backwards as we start at the lowest list level
for(i in frameNcol:1){
  
  #These are the columns to group by each iteration
  bulletGroups <- bulletNamesStatic[1:(i-1)]
  
  #The name to give the new variable. In this case it's the same as the one already used
  sumNameVar <- paste0("bullet_", i)
  
  #(tentative) column names to summarise
  sumVars <- rev(paste0("bullet_", frameNcol:(i)))
  
  #However, must be adjusted each iteration due to the fact that 
  #for each iteration, the "final" column is removed
  sumVars <- sumVars[sumVars %in% bulletNamesDynamic]
  
  #At the final iteration, set prefix for the "header", i.e. top level list entry
  if(i == 1){
    prefix <- paste0("\n#### ")  
  } else {
    prefix <- paste0(paste(rep(" ", numSpaces[i-1]), collapse = ""), "- ")
  }
  

   frameLoop <- frameLoop %>% 
    group_by_at(bulletGroups) %>% 
    summarise(!!sym(sumNameVar) := paste0(prefix, !!!syms(sumVars), collapse="")) %>% 
    #Removes NAs. At each iteration, the summarise will not
    #combine a true list entry with NA (by definition). As a consequence, all 
    #entries containing @NA@ will be removed. Might be problematic if true entries  
    #contains "@NA@", e.g. xxxx@NA@. Should be fairly easy to modify
    mutate(!!sym(sumNameVar) := ifelse(grepl("@NA@", !!sym(sumNameVar)), "", !!sym(sumNameVar)))
     
  bulletNamesDynamic <- colnames(frameLoop)

}

paste(frameLoop[[1]], collapse = "") %>% 
  cat()
```

输出:

#### Big Bullet 1
- Sample 1
  - Event 1
  - Event 2
    - Detail 1
    - Detail 2

#### Big Bullet 2
- Sample 1
- Sample 2
- Sample 3

#### Big Bullet 3
- Sample 1
  - Event 1
    - Detail 1
    - Detail 2
  - Event 2
    - Detail 1
    - Detail 2
  - Event 3
    - Detail 1
    - Detail 2
- Sample 2
  - Event 1
  - Event 2

推荐阅读