rconditional-statementsr-markdownparagraph

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


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's answer to a similar question here. 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 '\n\n' to ' '. I tried with a lua filter as suggested in this SO post but using '\s' throws an error and halts the knitting, while using a plain space for the code_block_sep is just ignored and does nothing.


local code_block_sep = ' '
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 == '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

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 && 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 <- 14

# Number of probable cases
n_probable <- 0

# Number of possible cases
n_possible <- 5
```

Now I create the conditions in another code chunk:

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

# Create condition to show or hide probable cases sentence:
if(n_probable > 0){showprob <- TRUE} else {showprob <- FALSE}

# Create condition to show or hide possible cases sentence:
if(n_possible > 0){showposs <- TRUE} else {showposs <- 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.


Solution

  • 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

    In an R Markdown document:

    
    ---
    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)
        )
      )
    }
    ```
    
    
    ```{r echo=FALSE}
    do.call(fpar, out) 
    ```
    
    

    enter image description here