I use data checks in my code, for example the following one:
if (...)
stop(paste('Warning: Weights do not sum up to 1')
The problem is that if the condition is true and the warning appears in the console, the code does not stop running. If hidden in a long code, one needs to scroll up always in the console output to see if a warning appeared.
Is there a way to tell R to interupt ALL code when the stop warning appears and the condition is true? Something like BREAK ?
I do not represent a reproducible example here because my code is quite long.
EDIT:
Here is a mini example:
When I execute
a=1+2
if (a==3)
stop('a equals 3')
b=4
1+1
I would like to stop after printing
> a=1+2
>
> if (a==3)
+ stop('a equals 3')
Error: a equals 3
but R executes everything, also the last part:
> a=1+2
>
> if (a==3)
+ stop('a equals 3')
Error: a equals 3
>
>
> b=4
>
> 1+1
[1] 2
According to stop, it only stops evaluation of the current expression. While I agree with Roland's comment to encapsulate your code into meaningful pieces via functions, a quick hack would be to wrap all your current code in curly braces. That will make it appear to the R parser as a single expression.
R> # without curly braces
R> x <- 1
R> y <- 2
R> if (x < y)
+ stop("x < y")
Error: x < y
R> print("hello")
[1] "hello"
R>
R> # with curly braces
R> {
+ x <- 1
+ y <- 2
+ if (x < y)
+ stop("x < y")
+ print("hello")
+ }
Error: x < y
If I understand you correctly, it seems not to be the default behaviour of R.
So I think there is some change of the stop handler. You can try to call options(stop=NULL) before running your code. See the doc:
The default behaviour (the NULL error-handler) in interactive use is
to return to the top level prompt or the top level browser, and in
non-interactive use to (effectively) call q("no", status = 1, runLast
= FALSE).
At least the following code worked in my case (R 3.2.1):
funErr <- function() {
if (TRUE)
stop("now")
print("after stop")
}
funCaller <- function() {
print("before call")
funErr()
print("after call")
}
print("before global")
# Also possible to uncomment the following to test the `stop()`
# inside of `funErr()`
if(TRUE)
stop("global error")
funCaller()
Related
I have the following code in the script test.R:
if (x==2){
stop("the script ends")
}
Now I source this script
source(test.R)
t <- 2
I would like the code to stop if x==2 and does not go further. However, it continues and assigns t <- 2. I can use the function warnings(options) but I want to avoid this option and implement a condition within the if. Any suggestion?
The code you list should work as expected.
As an example, I made two scripts, test.R and test2.R:
1. File test.R:
if (identical(x, 2)) {
stop("the script ends")
}
(Note: I'm using identical(x, 2) as the safer way to check whether x equals 2, but x == 2 would work the same in this example.)
2. File test2.R:
x <- 1
source("test.R")
t <- 1
print("This should be printed.")
x <- 2
source("test.R")
t <- 2
print("This should not be printed!")
Now I run test2.R from the console:
> t <- 5
> source('test2.R')
[1] "This should be printed."
Error in eval(ei, envir) : the script ends
> t
[1] 1
We see that the check passed the first time, when x == 1, and it failed the second time, when x == 2. Therefore, the value of t at the end is 1, because the first assignment was run and the second was not.
A while loop can create a condition that you can escape from as you are suggesting:
while (TRUE){
if (x==2) {
break
}
}
This is assuming that your code is 'all the way to the left' when executing. Seeing a little more might help, or better understanding how x is being set or being used. Note that using something like while(TRUE) might not be best practice, and can lead to infinite execution if you do not exit properly.
I want to test a function that can throw an error but I also want to ensure that a variable value is correct (to verify the expected last state before the error - so I want to test for unwanted side effects). Is it possible to do this?
Simplified expression to be tested
x <- 1 # could also be made "global" by "<<-"
stop("damn, an error occured")
How can I do something like
testthat("double check",
expect_error_and_TRUE( x == 1, {
x <- 1
stop("damn, an error occured")
}))
I could not find a way to "stack" (pipe) the expect functions?
If a function returns a value it doesn't throws an error and otherwise round. You can test for a specific string in expect_error if you wish, so you could set in the error the value of x.
{
x <- 1
stop("damn, an error occured")
}
## Error: damn, an error occured
x
## [1] 1
rm(x)
f <- function(){
x <- 1
stop("damn, an error occured")
}
f() == 1
## Error in f() : damn, an error occured
expect_error(f(), "damn, an error occured")
f <- function(){
x <- 1
stop("damn, an error occured, x is ", x)
}
expect_error(f(), "x is 1")
I would advise against testing code outside a function, as it depends on the environment, where it is run, so if you run it in the testing file it might not be the same as in the "main" part of your code
Here is a better example now to test for an unwanted side effect - and a simple solution:
library(testthat)
counter <- 1
test_that("error occurs but does not change the previous value", {
expect_error(if (log("a") == 42) counter <- counter + 1)
expect_equal(counter, 1)
})
I'm looking into having some user interaction in my code using RStudio. However, I'm running into some issues with the behavior of the command line in conjunction with the readline() function. Here's an example to illustrate my issue:
x <- 2
y <- 2
if (x == 2) { x <- readline("Put your x here: ")
} else { x <- 3 }
if (y == 2) { print("Something.")}
If I highlight this and hit "run" (or ctrl-alt-b at the end) to run line by line in the command line, I run into unexpected behavior shown here in the command line:
> x <- 2
> y <- 2
> if (x == 2) { x <- readline("Put your x here: ")
+ } else { x <- 3 }
Put your x here: if (y == 2) { print("Something.")}
Notice that on line 5, it skips right over the "Put your x here: " prompt (I did not input anything) and continues to the next line. Please do also note, however, when I "source" this code, the issue does not happen and the command line runs as expected (prompts me and waits until I input something).
Overall, this is a minor issue, but for testing purposes, it would be a major help to be able to run my user interaction code without having to source the entire file. Thanks for in advance!
Given the following R knitr document:
\documentclass{article}
\begin{document}
<<data>>=
opts_chunk$set(comment = NA) # omits "##" at beginning of error message
x <- data.frame(x1 = 1:10)
y <- data.frame()
#
<<output_x>>=
if (nrow(x) == 0) stop("x is an empty data frame.") else summary(x)
#
<<output_y>>=
if (nrow(y) == 0) stop("y is an empty data frame.") else summary(y)
#
\end{document}
As expected, the last chunk returns an error with the custom message. The compiled PDF looks a little different:
Error: y is an empty data frame.
I want this text to just be
y is an empty data frame.
Without the Error: part or the red color. Can I achieve this? How?
Edit: I was able to make it in the mock data through the following workaround:
<<output_y>>=
if (nrow(y) == 0) cat("y is an empty data frame.") else summary(y)
#
However, that doesn't work with my real data, because I need the function to be stopped at that point.
Although I do not understand why an error should not be called Error, you are free to customize the output hook error to remove Error: from the message:
library(knitr)
knit_hooks$set(error = function(x, options) {
knitr:::escape_latex(sub('^Error: ', '', x))
})
You could do something like this. options("show.error.messages" = FALSE) turns off error messages, so you could temporarily employ that once the if statement is entered and use on.exit to reset it.
This way, stop stops the function, Error: is avoided, and the desired message is printed in red.
> f <- function(x) {
if(x > 5) {
g <- getOption("show.error.messages")
options(show.error.messages = FALSE)
on.exit(options(show.error.messages = g))
message("x is greater than 5.")
stop()
}
x
}
> f(2)
# [1] 2
> f(7)
# x is greater than 5.
Note: I'm not exactly sure how safe this is and I'm not a big supporter of changing options settings inside functions.
I was wondering about how to write do-while-style loop?
I found this post:
you can use repeat{} and check conditions whereever using if() and
exit the loop with the "break" control word.
I am not sure what it exactly means. Can someone please elaborate if you understand it and/or if you have a different solution?
Pretty self explanatory.
repeat{
statements...
if(condition){
break
}
}
Or something like that I would think. To get the effect of the do while loop, simply check for your condition at the end of the group of statements.
See ?Control or the R Language Definition:
> y=0
> while(y <5){ print( y<-y+1) }
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
So do_while does not exist as a separate construct in R, but you can fake it with:
repeat( { expressions}; if (! end_cond_expr ) {break} )
If you want to see the help page you cannot type ?while or ?repeat at the console but rather need to use ?'repeat' or ?'while'. All the "control-constructs" including if are on the same page and all need character quoting after the "?" so the interpreter doesn't see them as incomplete code and give you a continuation "+".
Building on the other answers, I wanted to share an example of using the while loop construct to achieve a do-while behaviour. By using a simple boolean variable in the while condition (initialized to TRUE), and then checking our actual condition later in the if statement. One could also use a break keyword instead of the continue <- FALSE inside the if statement (probably more efficient).
df <- data.frame(X=c(), R=c())
x <- x0
continue <- TRUE
while(continue)
{
xi <- (11 * x) %% 16
df <- rbind(df, data.frame(X=x, R=xi))
x <- xi
if(xi == x0)
{
continue <- FALSE
}
}
Noticing that user 42-'s perfect approach {
* "do while" = "repeat until not"
* The code equivalence:
do while (condition) # in other language
..statements..
endo
repeat{ # in R
..statements..
if(! condition){ break } # Negation is crucial here!
}
} did not receive enough attention from the others, I'll emphasize and bring forward his approach via a concrete example. If one does not negate the condition in do-while (via ! or by taking negation), then distorted situations (1. value persistence 2. infinite loop) exist depending on the course of the code.
In Gauss:
proc(0)=printvalues(y);
DO WHILE y < 5;
y+1;
y=y+1;
ENDO;
ENDP;
printvalues(0); # run selected code via F4 to get the following #
1.0000000
2.0000000
3.0000000
4.0000000
5.0000000
In R:
printvalues <- function(y) {
repeat {
y=y+1;
print(y)
if (! (y < 5) ) {break} # Negation is crucial here!
}
}
printvalues(0)
# [1] 1
# [1] 2
# [1] 3
# [1] 4
# [1] 5
I still insist that without the negation of the condition in do-while, Salcedo's answer is wrong. One can check this via removing negation symbol in the above code.