Suppress Messages Displayed by "Print" Instead of "Message" or "Warning" in R

suppress messages displayed by print instead of message or warning in R

Well, those packages are buggy to start with. Use of print() for anything but side-effect in print implementations is a serious mistake.

That said, you can simply use capture.output() to collect the output from such code instead of printing it. So for the above it would be

capture.output(x <- silly_developer_function(...))
print(x)

How to avoid printing / showing messages

You should ask maintainer("rhdf5") to provide a solution -- print message less frequently, and use standard R warnings -- the message is from C code and uses printf() rather than Rf_warning() or Rf_ShowMessage() or Rprintf() / REprintf().

Here's an illustration of the problem

> library(inline)
> fun = cfunction(character(), 'printf("hello world\\n"); return R_NilValue;')
> fun()
hello world
NULL
> sink("/dev/null"); fun(); sink()
hello world
>

and a solution -- use Rf_warning() to generate R warnings. The example also illustrates how writing to R's output stream via Rprintf() would then allow the output to be captured with sink.

> fun = cfunction(character(), 'Rf_warning("hello world"); return R_NilValue;')
> x = fun()
Warning message:
In fun() : hello world
> x = suppressWarnings(fun())
> fun = cfunction(character(), 'Rprintf("hello world\\n"); return R_NilValue;')
> sink("/dev/null"); fun(); sink()
>

None of this helps you directly, though!

UPDATE the maintainer updated the code in the 'devel' branch of the package, version 2.17.2.

Suppressing some messages in R but leaving others?

You can wrap this function in one of the suppress* functions, suppressMessages, suppressWarnings or suppressPackageStartupMessages. See the help pages of those functions for more details.

Suppress messages from underlying C-function in R

You had problems using sink() and capture.output() normally because sink() does not redirect output from REprintf, as we see in comments from the source code for REprintf:

/* =========
* Printing:
* =========
*
* All printing in R is done via the functions Rprintf and REprintf
* or their (v) versions Rvprintf and REvprintf.
* These routines work exactly like (v)printf(3). Rprintf writes to
* ``standard output''. It is redirected by the sink() function,
* and is suitable for ordinary output. REprintf writes to
* ``standard error'' and is useful for error messages and warnings.
* It is not redirected by sink().

However, we can use type = "message" to deal with this; from help("capture.output"):

Messages sent to stderr() (including those from message, warning and
stop) are captured by type = "message". Note that this can be "unsafe" and should only be used with care.

First I make a C++ function with the same behavior you're dealing with:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector example_function(NumericVector x) {
REprintf("CPLEX environment opened\n");
REprintf("Closed CPLEX environment\n");
// As mentioned by Dirk Eddelbuettel in the comments,
// Rcpp::Rcerr goes into the same REprintf() stream:
Rcerr << "Some more stuff\n";
return x;
}

If I call it from R normally, I get:

example_function(42)

CPLEX environment opened
Closed CPLEX environment
Some more stuff
[1] 42

However, I could instead do this:

invisible(capture.output(example_function(42), type = "message"))

[1] 42

And while the output is is printed to the console, the message is not.

Warning

I would be remiss if I didn't mention the warning from the help file I quoted above:

Note that this can be "unsafe" and should only be used with care.

The reason is that this will eliminate all output from actual errors as well. Consider the following:

> log("A")
Error in log("A") : non-numeric argument to mathematical function
> invisible(capture.output(log("A"), type = "message"))
>

You may or may not want to therefore send the captured output to a text file in case you have to diagnose something that went wrong. For example:

invisible(capture.output(log("A"), type = "message", file = "example.txt"))

Then I don't have to see the message in the console, but if I need to check example.txt afterward, the message is there:

Error in log("A") : non-numeric argument to mathematical function

Good coding practices with R: message/cat/print/warning/error?

Your example

In this particular case, the only sensible option is to use stop(), because this situation is an error, and you want to stop the function from continuing when the error is encountered.

The other options will allow code execution to proceed, returning the last evaluated expression in the function. This is not what you want.

In general

Use print() when you want to provide output for the end-user. Use cat() for more control over output in the same situation. This is not suitable for "library code", because it cannot be suppressed easily. However, it is the correct way to perform tasks like emitting data to stdout for processing in a shell pipeline, or writing functions that "pretty print" interesting things.

Use message() for informational messages that are not warnings or errors, but that arise during some computation where the user didn't specifically request output. For example, if you are developing a package, and you want to inform the user that they can install a special dependency to improve performance, you can use message() to emit this message. Messages can be suppressed by the user with suppressMessages.

Use warning() to indicate problematic situations that do not require function execution to abort. An example would be if the user requested an action that would be very slow, or that might cause numerical stability problems in a later computation. Warnings can be suppressed by the user with suppressWarnings.

As above, use error() when something is so totally wrong that the function cannot continue executing. Errors can be caught and handled, (e.g. with tryCatch), but the user must specifically make this happen.

The technical part

The other functions: message, warning, and stop each signal (or "throw") a condition. I will not go into detail on what conditions are, because Wickham covers them in chapter 8 of Advanced R.

The very simple version is the all 3 of these introduce a signal to the R runtime, that does nothing on its own. The user can then install a "handler" for a specific condition, which is a function that is invoked whenever the condition is signaled.

R has default handlers for the conditions signaled by message(), warning(), and error(). This is how the standard behavior of those functions is implemented.

Suppress warning based on their position in warning list or based on a regular expression in R

Here is one way to handle the problem, and it is all in base R.

Let's start with a function that returns a value we want but will throw two warnings before doing so:

make_warnings <- function()
{
warning("This is a warning that can be ignored")
warning("This is a warning that shouldn't be ignored")
return(0)
}

Of course, if we run this, we will get warnings:

make_warnings()
#> [1] 0
#> Warning messages:
#> 1: In make_warnings() : This is a warning that can be ignored
#> 2: In make_warnings() : This is a warning that shouldn't be ignored

If we run the function inside suppressWarnings we just lose all the warnings and that's not what we want. But we can use withCallingHandlers, which provides a warning parameter that allows us to specify a function that takes each warning generated and does whatever we like programatically with it.

All we need to do is set up a function that checks the contents of each warning using a regular expression with grepl and suppresses that warning if it matches our regex.

Note that this function will be called once for each warning caught inside withCallingHandlers. We don't even need to specify what will happen to uncaught warnings, because if they aren't specifically suppressed in our function, they will still generate a warning to the console:

warning_handler <- function(w)
{
condition <- conditionMessage(w)
if(grepl("can be ignored", condition)) invokeRestart("muffleWarning")
}

So now we can run our warning-producing function and just silence the warnings we don't care about.

withCallingHandlers(make_warnings(), warning = warning_handler)
#> [1] 0
#> Warning message:
#> In make_warnings() : This is a warning that shouldn't be ignored

So you can see we have suppressed the warning we didn't want to see but kept the important one.

If you want to make this more flexible, you can wrap withCallingHandlers and your handling function into a single function that takes the regex as the first argument:

with_warning_handler <- function(reg, ...)
{
withCallingHandlers(..., warning = function(w)
{
condition <- conditionMessage(w)
if(grepl(reg, condition)) invokeRestart("muffleWarning")
})
}

So now you can do things like this:

with_warning_handler("can be ignored", make_warnings())
#> [1] 0
#> Warning message:
#> In make_warnings() : This is a warning that shouldn't be ignored

So, looking at a real-world example, look at the two warnings we get with this line of code:

a <- 1:3; a[] <- as.numeric(c("A", "1"))
#> Warning messages:
#> 1: NAs introduced by coercion
#> 2: In a[] <- as.numeric(c("A", "1")) :
#> number of items to replace is not a multiple of replacement length

But if we're not worried about the coercion, we can do:

with_warning_handler("coercion", {a <- 1:3; a[] <- as.numeric(c("A", "1"))})
#> Warning message:
#> In a[] <- as.numeric(c("A", "1")) :
#> number of items to replace is not a multiple of replacement length

How to hide or disable in-function printed message

You can use capture.output with invisible

> invisible(capture.output(y <- ff(2)))
> y
[1] 4

or sink

> sink("file")
> y <- ff(2)
> sink()
> y
[1] 4

suppressMessages with a return instead of a print in R?

You could just set method = 'loess' instead of method = 'auto', which is the default:

library(ggplot2)
f = function(y,x,data){
p = ggplot(data, aes_string(x,y)) + geom_point() + geom_smooth(method = "loess")
return(p)
}

data(iris)

gg <- f("Sepal.Length", "Sepal.Width", iris)
gg

Sample Image

Created on 2019-10-04 by the reprex package (v0.3.0)

I don't see a message here, not even a short one.

The other option is to define a custom print function and give your output object a different class:

f = function(y,x,data){
p = ggplot(data, aes_string(x,y)) + geom_point() + geom_smooth()
class(p) <- c("gg_silent", class(p))
return(p)
}

print.gg_silent <- function(gg) {
suppressMessages(ggplot2:::print.ggplot(gg))
}

This will suppress the messages when the returned object is printed. Since this adds a class rather than overwrite the old one, you can still add arguments with + without a problem. Still I would say that the first option should be the better one.



Related Topics



Leave a reply



Submit