Extension to knitr/Rmarkdown to ignore only specific warnings (not all) in a chunk
2
0
Entering edit mode
@wolfgang-huber-3550
Last seen 3 months ago
EMBL European Molecular Biology Laborat…

Is there already an extension to knitr/Rmarkdown that instead of 'warning=FALSE' lets you specify which warnings should be suppressed/ignored (and thus, which others not)?

I want to take precautions against code rot in a very large and possibly long-lived document.

rmarkdown suppressWarning warning • 2.5k views
ADD COMMENT
1
Entering edit mode
Mike Smith ★ 6.6k
@mike-smith
Last seen 3 hours ago
EMBL Heidelberg

This requires some refinement, but how about modifying the knitr::knit_hooks for "warnings" to search each warning for known patterns and only printing those that aren't found e.g.

---
title: "Untitled"
author: "Mike Smith"
date: "12/8/2021"
output: html_document
---

```{r setup, include=FALSE}
knitr::knit_hooks$set(warning = function(x, options) { 

    if(options$warning == TRUE) {
        sprintf('<div class="warning"><pre class="knitr %s">%s</pre></div>\n', tolower(options$engine), x)
    } else {
        known_warning <- any(vapply(options$warning, 
                                FUN = grepl, 
                                FUN.VALUE = logical(1), 
                                x = x))
        if(!known_warning) {
            sprintf('<div class="warning"><pre class="knitr %s">%s</pre></div>\n', tolower(options$engine), x)
        }
    }

})
```

## Default warning handling

```{r, warning = TRUE}
1:2 + 3:5
```

## Suppress known warning

```{r, warning = c("longer object length")}
1:2 + 3:5
```

## Suppress known warning, but print new warning

```{r, warning = c("longer object length")}
1:2 + 3:5
testit <- function() warning("testit")
testit()
```

which renders to:

enter image description here

ADD COMMENT
1
Entering edit mode
@wolfgang-huber-3550
Last seen 3 months ago
EMBL European Molecular Biology Laborat…

Thank you, Mike! Here, in case anyone else is interested, is the code I am now using for the MSMB book. It addresses the fact that both x and options$warning can be vectors, and cleans up gratuitous formatting inserted by knit.

cleanup = function(x) gsub("\n#*", "", gsub("^## ", "", x))

knitr::knit_hooks$set(warning = function(x, options) {
  ow   = options$warning
  x    = cleanup(unique(x)) 
  keep = if (is.character(ow) && length(ow) > 0) {
           res = rep(TRUE, length(x))
           for (w in ow)
             res = res & !grepl(w, x, ignore.case = TRUE)
           res
         } else if(is.logical(ow) && length(ow)==1) {
           rep(ow, length(x))
         } else {
           stop("In knit hook for warning, do not know how to handle 'options$warning'.")
         }

  if (any(keep))
    sprintf('<div class="warning"><pre class="knitr %s">%s</pre></div>\n', tolower(options$engine), x[keep])
})

It is then used in code chunks like in the following example.

```{r dbscanfcs, warning = c("stat_contour..: Zero contours were generated", "min.x.: no non-missing arguments to min; returning Inf", "max.x.: no non-missing arguments to max; returning -Inf")}
res5 = dbscan::dbscan(mc5, eps = 0.65, minPts = 30)
mc5df = data.frame(mc5, cluster = as.factor(res5$cluster))
ggplot(mc5df, aes(x = CD4, y = CD8,  col = cluster)) + geom_density2d()
```
ADD COMMENT
3
Entering edit mode

This approach no longer works following the release of knitr 1.42 and evaluate 0.19. The warning chunk option is expecting a logical, and the above approach fortuitously worked; it now breaks following the release of those two packages.

We now use a new chunk option warning.known to pass the vector of expected warnings. The updated hook is:

knitr::knit_hooks$set(
  warning = function(x, options) {
    ow   = options$warning.known
    if(is.null(ow)) ow <- options$warning
    x    = unique(x)
    keep = if (is.character(ow) && length(ow) > 0) {
      res = rep(TRUE, length(x))
      for (w in ow)
        res = res & !grepl(w, x, ignore.case = TRUE)
      res
    } else if (is.logical(ow) && length(ow) == 1) {
      rep(ow, length(x))
    } else {
      NA   
    }
    sprintf(
      '<div class="warning"><pre class="knitr %s">%s</pre></div>\n',
      tolower(options$engine),
      if (is.na(keep))
        "In knitr hook for warning, do not know how to handle 'options$warning'."
      else if (any(keep))
        paste(sprintf("In chunk '%s': ", options$label), x[keep], sep = "")
      else
        character(0)
    ) 
  }
)

The following code block will only report the warning "baz" in the output document.

```r
#| warning: TRUE
#| warning.known: !expr c("foo", "bar")
warning("foo")
warning("bar")
warning("baz")
```

If warning.known isn't set, the behaviour is still dictated by the knitr standard warning option.

ADD REPLY

Login before adding your answer.

Traffic: 668 users visited in the last hour
Help About
FAQ
Access RSS
API
Stats

Use of this site constitutes acceptance of our User Agreement and Privacy Policy.

Powered by the version 2.3.6