从 RMarkdown 中的数据框呈现项目符号列表

Rendering bulleted lists from a dataframe in RMarkdown

如何将此数据帧转换为

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

嵌套项目符号?像这样:

大子弹 1

大子弹 2

大子弹 3

就是这个意思。

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

对此我一头雾水。我的尝试没有奏效。 PS 我正在使用正确的参数采购外部脚本 knit_global()

也许可以用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"

在 excel 中添加一些 Markdown 列表输出并处理空单元格(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