4
votes

I have a chunk in an RMarkdown document that looks like this:

```{r, echo=-4}
a <- 1
b <- 2
x <- a + b
print(paste(c("`x` is equal to ", x), collapse=""))
```

When I knit this, it doesn't show the 4th expression, as expected and as documented here.

a <- 1
b <- 2
x <- a + b
## [1] "`x` is equal to 3"

However, if I add another line within the chunk, I have to update the echo parameter or it hides the wrong expression:

```{r, echo=-4}
a <- 1
b <- 2
c <- 3
x <- a + b + c
print(paste(c("`x` is equal to ", x), collapse=""))
```

Output:

a <- 1
b <- 2
c <- 3
print(paste(c("`x' is equal to ", x), collapse=""))
## [1] "`x` is equal to 6"

Is there a programmatic way in an RMarkdown Chunk to specify that you don't want to echo the last expression in a chunk without manually counting the total number of lines?

3
Move the print statement into a separate chunk and set echo=FALSE?atiretoo

3 Answers

3
votes

I like to do

```{r}
a <- 1
b <- 2
x <- a + b
```

`x` is equal to `r x`

Which gives a cleaner result output.

3
votes

Here's a hack to do that: use knitr hooks to mark the lines to be removed of the output and remove them when printing output.
The following solution implements a new chunk option named rm.last that removes the n last lines of the source code.
knitr has a built-in chunk for source code, so you have to retrieve it with knitr::knit_hooks$get('source').

---
title: "Hack the output with hooks"
---

```{r setup, include=FALSE}
knitr::opts_hooks$set(rm.last = function(options) {
  options$code <- 
    paste0(
      options$code, 
      c(rep("", length(options$code) - options$rm.last), 
        rep(" # REMOVE", options$rm.last)
      )
    )
  options
})

builtin_source_hook <- knitr::knit_hooks$get('source')

knitr::knit_hooks$set(source = function(x, options) {
  if (!is.null(options$rm.last))  
    x <- grep("# REMOVE$", x, invert = TRUE, value = TRUE)
  if (length(x) > 0) {
    return(builtin_source_hook(x, options))
  } else {
    invisible(NULL)
  }
})
```

```{r, rm.last=1}
a <- 1
b <- 2
x <- a + b
print(paste(c("`x` is equal to ", x), collapse=""))
```

However, if your last line of code is print(...), you obviously have to follow @atiretoo answer.

2
votes

No, there's no way to do that. If you look at the knitr source code, you'll see it gets a subset of the lines of code using

code = code[options$echo]

So it is using regular R indexing to select entries. R has no way to say "last element" in a constant value or vector of values, so rmarkdown and knitr don't have a way to say "last expression". Using @atiretoo's suggestion (just put it in a separate chunk) seems like your best bet.