在R Markdown中,将特定的无名称代码块之间的分隔符从换行符更改为空格。

huangapple go评论79阅读模式
英文:

r markdown change separator between specific unnamed code blocks from line breaks to a space

问题

我有一个R Markdown报告(使用officedown::rdocx_document输出为MS Word),其中包含顶部的一个摘要段落。它描述了基于我的数据的确诊、可能和可能病例的数量。

但是,如果这些类别中的任何一种病例数量为0,我需要抑制该类别的句子。如果病例数量大于0,我需要显示该句子,但还需要应用一些内联代码,根据另一个条件对数字进行着色,使用officer::ftext()和我在之前的代码块中创建的officer::fp_text()样式。应用这个条件文本颜色的代码有点复杂,无法在R对象中保存文本样式,只能在呈现文档时应用。

我能够根据Yihui Xie在类似问题上的回答这里来有条件地抑制句子。这个方法效果很好,并且有条件的文本着色得以保留。

然而,由于这种方法将每个要有条件抑制的句子放在自己的代码块中,它们被呈现为单独的段落,并在它们之间插入了空行。

我正在寻找的是一种将非条件文本与由代码块创建的有条件句子合并到一个单独段落的方法。我认为这意味着将这些特定代码块之间的分隔符从默认值'\n\n'更改为' '。我尝试使用这个SO帖子中建议的lua过滤器,但使用'\s'会引发错误并停止编织,而使用纯空格作为code_block_sep则会被忽略,不起作用。


local code_block_sep = ' '
function Blocks (blocks)
  for i = #blocks, 2, -1 do -- 从列表末尾开始
    -- 两个块都必须是代码块,并且共享相同的主要类别
    if blocks[i - 1].t == 'CodeBlock' and
       blocks[i].t == 'CodeBlock' and
       blocks[i - 1].classes[1] == blocks[i].classes[1] then
      blocks[i - 1].text = blocks[i - 1].text ..
        code_block_sep ..
        blocks[i].text
      blocks:remove(i)
    end
  end
  return blocks
end

有没有办法去除换行,使非条件和有条件的句子都出现在同一段落中?

以下是一些示例代码。

首先,我在我的R Markdown设置块中添加knit选项:

```{r setup, include=FALSE}
# 加载knitr库:
library(knitr)

# 设置选项以接受包含内联代码的条件显示/隐藏文本:
knit_engines$set(asis = function(options) {
  if (options$echo && options$eval) knit_child(text = options$code)
})

接下来,在一个代码块中添加一些示例数据:

```{r egdata}
# 确诊病例数量
n_confirmed <- 14

# 可能病例数量
n_probable <- 0

# 可能病例数量
n_possible <- 5

现在,在另一个代码块中创建条件:

```r
```{r conditions}
# 创建显示或隐藏确诊病例句子的条件:
if(n_confirmed > 0){showconf <- TRUE} else {showconf <- FALSE}

# 创建显示或隐藏可能病例句子的条件:
if(n_probable > 0){showprob <- TRUE} else {showprob <- FALSE}

# 创建显示或隐藏可能病例句子的条件:
if(n_possible > 0){showposs <- TRUE} else {showposs <- FALSE}

现在,我以非条件文本开始我的段落:

```markdown
This summary describes the number of cases by case definition.

最后,我添加有条件的句子(使用加法来说明内联代码):

```{asis, echo=showconf}
There are *n* = `r n_confirmed + 1` confirmed cases. 
There are *n* = `r n_probable + 1` probable cases. 
There are *n* = `r n_possible + 1` possible cases. 

我希望编织后的文本以如下的方式显示在单一段落中:

> This summary describes the number of cases by case definition.  There are *n* = 15 confirmed cases.  There are *n* = 6 possible cases.

<details>
<summary>英文:</summary>

I have an r markdown report (output is MS word using `officedown::rdocx_document`) which includes a paragraph of summary text at the top.  It describes the number of confirmed, probable and possible cases based on my data.

However, if the number of cases for any of these categories is 0, I need to supress the sentence for that category.  If the number of cases is greater than 0, I need to show the sentence, but also apply some inline code that colours the number based on another condition, using `officer::ftext()` and a `officer::fp_text()` style that I created in an earlier chunk. The code to apply this conditional text colour is a bit complex to reproduce here, but the main point is that the text style cannot be saved in an R object.  It is only applied on rendering the document.

I was able to conditionally suppress sentences by following Yihui Xie&#39;s answer to a similar question [here](https://stackoverflow.com/questions/32944715/conditionally-display-block-of-markdown-text-using-knitr). This works well, and the conditional text colouring is preserved.  

However - because this method puts each sentence to conditionally suppress in its own chunk, they are rendered as separate paragraphs with an empty line in between each one.  

What I am looking for is a way to combine the non conditional text outside the code chunks, with the conditional sentences created by the code chunks in one single paragraph.  I *think* this means changing the separator between these specific code chunks from the default `&#39;\n\n&#39;` to `&#39; &#39;`.  I tried with a lua filter as suggested in [this SO post](https://stackoverflow.com/questions/72878908/can-i-merge-the-code-of-successive-code-chunks-with-no-output-echoed-in-a-rmarkd) but using `&#39;\s&#39;` throws an error and halts the knitting, while using a plain space for the `code_block_sep` is just ignored and does nothing.

```lua

local code_block_sep = &#39; &#39;
function Blocks (blocks)
  for i = #blocks, 2, -1 do -- start at end of list
    -- Both blocks must be code blocks and share the same primary class
    if blocks[i - 1].t == &#39;CodeBlock&#39; and
       blocks[i].t == &#39;CodeBlock&#39; and
       blocks[i - 1].classes[1] == blocks[i].classes[1] then
      blocks[i - 1].text = blocks[i - 1].text ..
        code_block_sep ..
        blocks[i].text
      blocks:remove(i)
    end
  end
  return blocks
end

Is there a way to remove the line breaks so that the non-conditional and conditional sentences all appear in the same paragraph?

Here is some example code.

First, I add the knit option to my r markdown setup chunk:

```{r setup, include=FALSE}
# Load knitr library:
library(knitr)

# Set options to accept conditional show/hide with text containing inline code:
knit_engines$set(asis = function(options) {
  if (options$echo &amp;&amp; options$eval) knit_child(text = options$code)
})

```

Next, I add some example data in a code chunk:

```{r egdata}
# Number of confirmed cases
n_confirmed &lt;- 14

# Number of probable cases
n_probable &lt;- 0

# Number of possible cases
n_possible &lt;- 5
```

Now I create the conditions in another code chunk:

```{r conditions}
# Create condition to show or hide confirmed cases sentence:
if(n_confirmed &gt; 0){showconf &lt;- TRUE} else {showconf &lt;- FALSE}

# Create condition to show or hide probable cases sentence:
if(n_probable &gt; 0){showprob &lt;- TRUE} else {showprob &lt;- FALSE}

# Create condition to show or hide possible cases sentence:
if(n_possible &gt; 0){showposs &lt;- TRUE} else {showposs &lt;- FALSE}
```

Now I start my paragraph with the non-conditional text:

This summary describes the number of cases by case definition.

Finally I add the conditional sentences (using addition to illustrate the inline code):

```{asis, echo=showconf}
There are *n* = `r n_confirmed + 1` confirmed cases. 
```
```{asis, echo=showprob}
There are *n* = `r n_probable + 1` probable cases. 
```
```{asis, echo=showposs}
There are *n* = `r n_possible + 1` possible cases. 
```

I would like the text when knitted to print in a single paragraph like this:

> This summary describes the number of cases by case definition. There are n = 15 confirmed cases. There are n = 6 possible cases.

答案1

得分: 1

你可以使用 list()do.call() 来创建一个由 ftext() 对象构成的 fpar() 对象。

library(officer)
compare <- data.frame(name = c("n_total", "n_children", "n_adults"), 
                      value_new = c(50, 0, 50), 
                      value_old = c(45, 0, 45), 
                      change = c(TRUE, FALSE, TRUE))

fp_default <- fp_text(font.size = 10, font.family = "Calibri")
fp_emphasized <- update(fp_default, color = "#4F81BD", bold = TRUE)

out <- list()
if( any(compare$change)) {
  out <- append(
    out,
    list(ftext("This is a summary paragraph describing the cases by agegroup.", fp_default))
  )
}

is_n_total <- compare$name %in% "n_total"
if( compare$change[is_n_total] ) {
  out <- append(
    out,
    list(
      ftext(" There were ", fp_default),
      ftext(compare$value_new[is_n_total], fp_emphasized),
      ftext(" cases in total.", fp_default)
    )
  )
}
is_n_children <- compare$name %in% "n_children"
if( compare$change[is_n_children] ) {
  out <- append(
    out,
    list(
      ftext(" There were ", fp_default),
      ftext(compare$value_new[is_n_children], fp_emphasized),
      ftext(" children.", fp_default)
    )
  )
}
is_n_adults <- compare$name %in% "n_adults"
if( compare$change[is_n_adults] ) {
  out <- append(
    out,
    list(
      ftext(" There were ", fp_default),
      ftext(compare$value_new[is_n_adults], fp_emphasized),
      ftext(" adults.", fp_default)
    )
  )
}

your_paragraph <- do.call(fpar, out)

在R Markdown文档中:

---
output: officedown::rdocx_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, fig.cap = TRUE)
library(officedown)
library(officer)

compare <- data.frame(name = c("n_total", "n_children", "n_adults"), 
                      value_new = c(50, 0, 50), 
                      value_old = c(45, 0, 45), 
                      change = c(TRUE, FALSE, TRUE))

fp_default <- fp_text(font.size = 10, font.family = "Calibri")
fp_emphasized <- update(fp_default, color = "#4F81BD", bold = TRUE)

out <- list()
if( any(compare$change)) {
  out <- append(
    out,
    list(ftext("This is a summary paragraph describing the cases by agegroup.", fp_default))
  )
}

is_n_total <- compare$name %in% "n_total"
if( compare$change[is_n_total] ) {
  out <- append(
    out,
    list(
      ftext(" There were ", fp_default),
      ftext(compare$value_new[is_n_total], fp_emphasized),
      ftext(" cases in total.", fp_default)
    )
  )
}
is_n_children <- compare$name %in% "n_children"
if( compare$change[is_n_children] ) {
  out <- append(
    out,
    list(
      ftext(" There were ", fp_default),
      ftext(compare$value_new[is_n_children], fp_emphasized),
      ftext(" children.", fp_default)
    )
  )
}
is_n_adults <- compare$name %in% "n_adults"
if( compare$change[is_n_adults] ) {
  out <- append(
    out,
    list(
      ftext(" There were ", fp_default),
      ftext(compare$value_new[is_n_adults], fp_emphasized),
      ftext(" adults.", fp_default)
    )
  )
}
do.call(fpar, out) 

[![enter image description here][1]][1]
[1]: https://i.stack.imgur.com/YGa8Z.png
[2]: https://i.stack.imgur.com/kqGIs.png
<details>
<summary>英文:</summary>
You can use `list()` and `do.call()` to create an `fpar()` object made of `ftext()` objects.

library(officer)
compare <- data.frame(name = c("n_total", "n_children", "n_adults"),
value_new = c(50, 0, 50),
value_old = c(45, 0, 45),
change = c(TRUE, FALSE, TRUE))

fp_default <- fp_text(font.size = 10, font.family = "Calibri")
fp_emphasized <- update(fp_default, color = "#4F81BD", bold = TRUE)

out <- list()
if( any(compare$change)) {
out <- append(
out,
list(ftext("This is a summary paragraph describing the cases by agegroup.", fp_default))
)
}

is_n_total <- compare$name %in% "n_total"
if( compare$change[is_n_total] ) {
out <- append(
out,
list(
ftext(" There were ", fp_default),
ftext(compare$value_new[is_n_total], fp_emphasized),
ftext(" cases in total.", fp_default)
)
)
}
is_n_children <- compare$name %in% "n_children"
if( compare$change[is_n_children] ) {
out <- append(
out,
list(
ftext(" There were ", fp_default),
ftext(compare$value_new[is_n_children], fp_emphasized),
ftext(" children.", fp_default)
)
)
}
is_n_adults <- compare$name %in% "n_adults"
if( compare$change[is_n_adults] ) {
out <- append(
out,
list(
ftext(" There were ", fp_default),
ftext(compare$value_new[is_n_adults], fp_emphasized),
ftext(" adults.", fp_default)
)
)
}

your_paragraph <- do.call(fpar, out)


see the result in RStudio Viewer

your_paragraph |> to_html() |> htmltools::HTML() |> htmltools::browsable()


[![enter image description here][1]][1]
In an R Markdown document:

output: officedown::rdocx_document

knitr::opts_chunk$set(echo = TRUE, fig.cap = TRUE)
library(officedown)
library(officer)
compare &lt;- data.frame(name = c(&quot;n_total&quot;, &quot;n_children&quot;, &quot;n_adults&quot;), 
value_new = c(50, 0, 50), 
value_old = c(45, 0, 45), 
change = c(TRUE, FALSE, TRUE))
fp_default &lt;- fp_text(font.size = 10, font.family = &quot;Calibri&quot;)
fp_emphasized &lt;- update(fp_default, color = &quot;#4F81BD&quot;, bold = TRUE)
out &lt;- list()
if( any(compare$change)) {
out &lt;- append(
out,
list(ftext(&quot;This is a summary paragraph describing the cases by agegroup.&quot;, fp_default))
)
}
is_n_total &lt;- compare$name %in% &quot;n_total&quot;
if( compare$change[is_n_total] ) {
out &lt;- append(
out,
list(
ftext(&quot; There were &quot;, fp_default),
ftext(compare$value_new[is_n_total], fp_emphasized),
ftext(&quot; cases in total.&quot;, fp_default)
)
)
}
is_n_children &lt;- compare$name %in% &quot;n_children&quot;
if( compare$change[is_n_children] ) {
out &lt;- append(
out,
list(
ftext(&quot; There were &quot;, fp_default),
ftext(compare$value_new[is_n_children], fp_emphasized),
ftext(&quot; children.&quot;, fp_default)
)
)
}
is_n_adults &lt;- compare$name %in% &quot;n_adults&quot;
if( compare$change[is_n_adults] ) {
out &lt;- append(
out,
list(
ftext(&quot; There were &quot;, fp_default),
ftext(compare$value_new[is_n_adults], fp_emphasized),
ftext(&quot; adults.&quot;, fp_default)
)
)
}
do.call(fpar, out) 
[![enter image description here][2]][2]
[1]: https://i.stack.imgur.com/YGa8Z.png
[2]: https://i.stack.imgur.com/kqGIs.png
</details>
# 答案2
**得分**: 0
我会使用`if`语句在一个代码块中构建句子,然后在另一个代码块中使用`asis`打印它们。例如:
```{r, echo=FALSE}
phrases &lt;- "这个摘要描述了根据病例定义的病例数量。"
if (showconf) {
phrases &lt;- paste(phrases, "有 *n* =", n_confirmed + 1,  "例确诊病例。") 
}
if (showprob) {
phrases &lt;- paste(phrases, "有 *n* =", n_probable + 1,  "例可能病例。") 
}
if (showposs) {
phrases &lt;- paste(phrases, "有 *n* =", n_possible + 1,  "例可能病例。") 
}
```
```{r, results="asis", echo=FALSE}
cat(phrases)
```
这将得到以下结果:
[![句子的截图][1]][1]
[1]: https://i.stack.imgur.com/w4MEM.png
<details>
<summary>英文:</summary>
I would construct the sentences in one r chunk using `if` statements and then print them using `asis` in a different chunk. For example:
````
```{r, echo=FALSE}
phrases &lt;- &quot;This summary describes the number of cases by case definition.&quot;
if (showconf) {
phrases &lt;- paste(phrases, &quot;There are *n* =&quot;, n_confirmed + 1,  &quot;confirmed cases.&quot;) 
}
if (showprob) {
phrases &lt;- paste(phrases, &quot;There are *n* =&quot;, n_probable + 1,  &quot;probable cases.&quot;) 
}
if (showposs) {
phrases &lt;- paste(phrases, &quot;There are *n* =&quot;, n_possible + 1,  &quot;possible cases.&quot;) 
}
```
```{r, results=&quot;asis&quot;, echo=FALSE}
cat(phrases)
```
````
which gives:
[![screenshot of sentence][1]][1]
[1]: https://i.stack.imgur.com/w4MEM.png
</details>

huangapple
  • 本文由 发表于 2023年7月13日 21:06:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76679715.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定