I want to catch a warning and still run an expression.
Here is an example:
x <- 0
tryCatch({
x <- as.numeric("text") # this is NA and causes warning
}, warning = function(w) {
print("I am a message")
})
x
# x still 0
Previous code catches the warning and print the message, BUT the value of x is not NA afterwards, which means that the expression did not run because of the warning.
I could run the expression with suppressWarnings() and <<- as follows:
x <- 0
tryCatch({
x <- as.numeric("text")
}, warning = function(w) {
print("I am a message")
suppressWarnings(x <<- as.numeric("text"))
})
x
# now x is NA
Is there a more elegant way to do that? maybe one of following examples?
another function other than tryCatch()
or using some parameter of tryCatch()
or maybe another package other than base
...
From this answer follows that this code could work:
x <- 0
withCallingHandlers({
x <- as.numeric("text")
}, warning = function(w) {
print("I am a message")
invokeRestart("muffleWarning")
})
x
(I came across this post looking for a way to catch a warning and alter the return value of a function. I ended up with
which_nondefault_enc <- function(txt) {
ans <- rep(NA, length(txt))
for (i in seq(1, length(txt)))
ans[i] <- tryCatch(stringi::stri_enc_tonative(txt[i]), warning = function(w) return(NA))
return(which(is.na(ans)))
}
which returns those indices of the vector, where warnings like "unable to translate '<U+0001F41F>' to native encoding" are used as a selection criterion.)
Related
I want to make a new function that has 3 skills
if an error occurs, print "error". Do not stop the whole process, make it keep going
if a warning occurs, print the warning message
if there is no error nor warning, print "Nothing".
For 1) I made a function as follows:
efunc <- function(error){
return(NA)
}
tryc <- function(x){tryCatch(x, error = efunc)}
for 2), 3) , I refer to this page( How do I save warnings and errors as output from a function?) and
adapted some code, making the following functions
myTryCatch <- function(expr) {
warn <- err <- NULL
value <- withCallingHandlers(
tryCatch(expr, error=function(e) {
err <<- e # <<- is not typo
print("error")
}), warning=function(w) {
warn <<- w # <<- is not typo
invokeRestart("muffleWarning")
})
if(is.null(warn)){
warn<-'Nothing'
}
if(is.null(err)){
err<-'Nothing'
}
warning=warn
paste(unlist(warning),collapse="")
}
However, thinking back, maybe it is possible to combine these two functions..
or, myTryCatch() already has a tryc()'s skill..
but I am not sure.
In R, how can I determine whether a function call results in a warning?
That is, after calling the function I would like to know whether that instance of the call yielded a warning.
If you want to use the try constructs, you can set the options for warn. See also ?options. Better is to use tryCatch() :
x <- function(i){
if (i < 10) warning("A warning")
i
}
tt <- tryCatch(x(5),error=function(e) e, warning=function(w) w)
tt2 <- tryCatch(x(15),error=function(e) e, warning=function(w) w)
tt
## <simpleWarning in x(5): A warning>
tt2
## [1] 15
if(is(tt,"warning")) print("KOOKOO")
## [1] "KOOKOO"
if(is(tt2,"warning")) print("KOOKOO")
To get both the result and the warning :
tryCatch(x(5),warning=function(w) return(list(x(5),w)))
## [[1]]
## [1] 5
##
## [[2]]
## <simpleWarning in x(5): A warning>
Using try
op <- options(warn=2)
tt <- try(x())
ifelse(is(tt,"try-error"),"There was a warning or an error","OK")
options(op)
On the R-help mailing list (see http://tolstoy.newcastle.edu.au/R/help/04/06/0217.html), Luke Tierney wrote:
"If you want to write a function that computes a value and collects all
warning you could do it like this:
withWarnings <- function(expr) {
myWarnings <- NULL
wHandler <- function(w) {
myWarnings <<- c(myWarnings, list(w))
invokeRestart("muffleWarning")
}
val <- withCallingHandlers(expr, warning = wHandler)
list(value = val, warnings = myWarnings)
}
2019 update
You can you use 'quietly' from the purrr package, which returns a list of output, result, warning and error. You can then extract each element by name. For instance, if you had a list, which you want to map a function over, and find the elements which returned a warning you could do
library(purrr)
library(lubridate)
datelist <- list(a = "12/12/2002", b = "12-12-2003", c = "24-03-2005")
# get all the everything
quiet_list <- map(datelist, quietly(mdy))
# find the elements which produced warnings
quiet_list %>% map("warnings") %>% keep(~ !is.null(.))
# or
quiet_list %>% keep(~ length(.$warnings) != 0)
For this example it's quite trivial, but for a long list of dataframes where the NAs might be hard to spot, this is quite useful.
here is an example:
testit <- function() warning("testit") # function that generates warning.
assign("last.warning", NULL, envir = baseenv()) # clear the previous warning
testit() # run it
if(length(warnings())>0){ # or !is.null(warnings())
print("something happened")
}
maybe this is somehow indirect, but i don't know the more straightforward way.
For a simple TRUE/FALSE return on whether a given operation results in a warning (or error), you could use the is.error function from the berryFunctions package, after first setting options(warn = 2) so that warnings are converted to errors.
E.g.,
options(warn = 2)
berryFunctions::is.error(as.numeric("x")) # TRUE
berryFunctions::is.error(as.numeric("3")) # FALSE
If you want to limit the option change to the use of this function, you could just create a new function as follows.
is.warningorerror <- function(x) {
op <- options()
on.exit(options(op))
options(warn = 2)
berryFunctions::is.error(x)
}
is.warningorerror(as.numeric("x")) # TRUE
options("warn") # still 0 (default)
I personally use the old good sink redirected into a text connection:
# create a new text connection directed into a variable called 'messages'
con <- textConnection("messages","w")
# sink all messages (i.e. warnings and errors) into that connection
sink(con,type = "message")
# a sample warning-generating function
test.fun <- function() {
warning("Your warning.")
return("Regular output.")
}
output <- test.fun()
# close the sink
sink(type="message")
# close the connection
close(con)
# if the word 'Warning' appears in messages than there has been a warning
warns <- paste(messages,collapse=" ")
if(grepl("Warning",warns)) {
print(warns)
}
# [1] "Warning message: In test.fun() : Your warning."
print(output)
# [1] "Regular output."
Possibly more straightforward and cleaner than the other suggested solutions.
I have some loop that computes a value. Sometimes that computation triggers a warning. How do I check if the warning is triggered, then skip that iteration? I am using R.
With help from the comments, I found tryCatch() and was able to amend my for loop as the following and work:
for (i in seq(1,100,1)){
x<-sample(1:length(df$values), 1)
input<-copy_df[x:x+5,]
val<-tryCatch(myfunc(input$colA), warning=function(w) w)
if (is(val,warning){
next
}
print(paste0(i))
}
The output of val should be a column of length 5.
Here's a complete example using a test function that randomly generates a warning
set.seed(101)
foo <- function() {
x <- runif(1)
if(x<.9) warning("low x")
x
}
for(i in 1:20) {
didwarn <- tryCatch({x <- foo(); FALSE}, warning = function(w) return(TRUE))
if(didwarn) {
next
}
print(paste("high x", x))
}
You wrap any code that might trigger a warning in a try catch. Here we have each block return TRUE or FALSE depending on whether or not an error was thrown. An easier way to do this without the next would be
for(i in 1:20) {
tryCatch({
x <- foo();
print(paste("high x", x))
},
warning = function(w) {
# do nothing
})
}
When the warning occurs, nothing else in the tryCatch expression will run
I am new to R and I have checked most links online but I have not been able to solve the problem.
Here is a reproducible example of a Monte Carlo simulation I am doing:
rm(list = ls())
x=c(-2,3,-1,4,'A')
y=rep(0,5)
for(i in 1:5){
tryCatch(
expr = {
y[i]=log(x[i])
},
error = function(e){
message('Caught an error!',i)
return(NA)
},
warning = function(w){
message('Caught an warning!',i)
return(NA)
}
)
}
Please how do I fix the code so that at the end of the for loop, R returns the values of y as
y= NA,log(3),NA,log(4),NA
i=1,3,5
and the values of i where there was an error or warning.
That is, error and warnings are replaced with NA and successful evaluations are returned and the values of i where there was an error or warning are also returned.
Thanks
Initialise y with NA and then run the for loop. Also since x is a vector and vector can hold only one class all the numbers in x turn to characters as you have non-numeric elements in x so you need to convert them to numbers before taking log.
x=c(-2,3,-1,4,'A')
y=rep(NA,5)
for(i in 1:5){
tryCatch(
expr = {
y[i]= log(as.numeric(x[i]))
},
error = function(e){
message('Caught an error!',i)
},
warning = function(w){
message('Caught a warning! ',i)
}
)
}
#Caught a warning! 1
#Caught a warning! 3
#Caught a warning! 5
y
#[1] NA 1.098612 NA 1.386294 NA
and then use is.na with which to get the index where error or warning happened.
which(is.na(y))
#[1] 1 3 5
Of course, you can do this without for loop as well
y <- log(as.numeric(x))
which(is.na(y))
#[1] 1 3 5
To return different value based on error or warning, we can make this into a function
run_fun <- function(x) {
tryCatch(
expr = {
return(log(as.numeric(x)))
},
error = function(e){
message('Caught an error!',i)
return(100)
},
warning = function(w){
message('Caught a warning! ',i)
return(200)
}
)
}
and then call it in for loop.
for (i in seq_along(x)) {
y[i] <- run_fun(x[i])
}
y
#[1] 200.0000 1.0986 200.0000 1.3863 200.0000
myFunc <- function(x)
{
x <- timeSeries(x, charvec=as.Date(index(x)))
t<-tryCatch( doSomething(x), error=function(x) rep(0,ncol(x))
)
t
}
How do I pass x into the error function? When I run the above I get:
Error in rep(0, ncol(x)) : invalid 'times' argument
The error argument is a handler, documented (see ?tryCatch) to accept one argument (the error condition). The error handler has access to whatever variables were available at the time stop was invoked. So
f = function() {
tryCatch({
i = 1
stop("oops")
}, error=function(e) {
stop(conditionMessage(e), " when 'i' was ", i)
})
}
catches the error thrown by the code, discovers the value i, and emits a more informative message. So I'd guess
myFunc <- function(x)
{
tryCatch({
x <- timeSeries(x, charvec=as.Date(index(x)))
doSomething(x)
}, error=function(...) rep(0, ncol(x)))
}