I have a loop in R that does very time-consuming calculations. I can set a max-iterations variable to make sure it doesn't continue forever (e.g. if it is not converging), and gracefully return meaningful output.
But sometimes the iterations could be stopped way before max-iterations is reached. Anyone who has an idea about how to give the user the opportunity to interrupt a loop - without having to wait for user input after each iteration? Preferably something that works in RStudio on all platforms.
I cannot find a function that listens for keystrokes or similar user input without halting until something is done by the user. Another solution would be to listen for a global variable change. But I don't see how I could change such a variable value when a script is running.
The best idea I can come up with is to make another script that creates a file that the first script checks for the existence of, and then breaks if it is there. But that is indeed an ugly hack.
Inspired by Edo's reply, here is an example of what I want to do:
test.it<-function(t) {
a <- 0
for(i in 1:10){
a <- a + 1
Sys.sleep(t)
}
print(a)
}
test.it(1)
As you see, when I interrupt by hitting the read button in RStudio, I break out of the whole function, not just the loop.
Also inspired by Edo's response I discovered the withRestarts function, but I don't think it catches interrupts.
I tried to create a loop as you described it.
a <- 0
for(i in 1:10){
a <- a + 1
Sys.sleep(1)
if(i == 5) break
}
print(a)
If you let it go till the end, a will be equal to 5, because of the break.
If you stop it manually by clicking on the STOP SIGN on the Rstudio Console, you get a lower number.
So it actually works as you would like.
If you want a better answer, you should post a reproducible example of your code.
EDIT
Based on the edit you posted... Try with this.
It's a trycatch solution that returns the last available a value
test_it <- function(t) {
a <- 0
tryCatch(
for(i in 1:10){
a <- a + 1
message("I'm at ", i)
Sys.sleep(t)
if(i==5) break
},
interrupt = function(e){a}
)
a
}
test_it(1)
If you stop it by clicking the Stop Sign, it returns the last value a is equal to.
Related
I have created a "while" loop that looks like this:
x <- 2
while (x < 8) {
print("Shrek")
}
Now, I have tried breaking the loop by inserting break in to the while loop, like this:
while (x < 8) {
print("Shrek")
break
}
but this doesn't break the loop, the console just keeps printing "Shrek".
How can i make it stop? Have I put break in the wrong place?
Side question: Can there arise any problems from exiting Rstudio while it's in an on-going while() loop like this?
Thanks!
Edit:
Pressing escape stopped the loop. Is there any line of code in the console that also stops it?
Based on the code you have given I can't reproduce this. When I run everything, break works just fine. Have you potentially defined a variable called 'break' that would have overridden the default function? If not try resetting R and running this again.
I have a function that validates a url based on input from a user. The way the function is set up, if the url doesn't validate (either because it doesn't exist or because it is a duplicate) the function simply ends.
How do I make it so that if the url isn't validated, the user goes back to the input dialogue to start the validation process over again instead of just ending the function?
exfun <- function(){
x <- toupper(readline("Do you want to do the function? Y/N......."))
if (x == "Y"){
writeLines("This is where the function body would be, but it's huge so for the sake of this StackExchange question, we'll just make it a simple thing")
} else
writeLines("Well then why did you start the function? We'll try this again")
#This is where I would like the function to return to the "x<-...." line.
There are a few places where I would like to be able to "return to line X" as there are at least two validation points. I have it set up as a series of if else arguments which else into a message. How can I make it else into a message and bring the user back to the beginning/a previous validation test?
I fiddled with the repeat function, but couldn't get it to return from if else correctly.
I'm not really answering your question, but I'll give you an example that might help you (and probably someone will give a hint to improve this).
You can set a while loop and put conditions to continue the loop or to end it, simply like this:
i <- 1
while (T) {
print(i)
i <- i + 1
if (i==5) {
print("NEXT")
next
}
if (i==10) break
}
As you see, the if with next conditions do something in your code, and keep running it after the command print("NEXT"). Also, the break is inside a condition to stop your loop.
I hope it helps, because with your example is difficult to give a full answer.
I want to pause and continue a loop.
Does rstudio have some options that can pause a loop and continue the loop?
Just like "stop" button can stop the loop.
I don't know if the readline() function can help:
a <- 0
for(i in 1:4) {
a <- a + i
if(readline() == "0") break
}
Now you have to insert values for each iteration.
For instance, if you want to stop at iteration 2:
1
0
> a
[1] 3
Maybe this solution does not totally meet your requirements (I haven't really understood your question), but it may help you have a control of each iteration in order to decide if and when to stop it.
to continue you can use
next
and to go out from loop you can use
break
see here for more details.
I have written an R script which includes a loop that retrieves external (web) data. The format of the data are most of the time the same, however sometimes the format changes in an unpredictable way and my loop is crashing (stops running).
Is there a way to continue code execution regardless the error? I am looking for something similar to "On error Resume Next" from VBA.
Thank you in advance.
Use try or tryCatch.
for(i in something)
{
res <- try(expression_to_get_data)
if(inherits(res, "try-error"))
{
#error handling code, maybe just skip this iteration using
next
}
#rest of iteration for case of no error
}
The modern way to do this uses purrr::possibly.
First, write a function that gets your data, get_data().
Then modify the function to return a default value in the case of an error.
get_data2 <- possibly(get_data, otherwise = NA)
Now call the modified function in the loop.
for(i in something) {
res <- get_data2(i)
}
You can use try:
# a has not been defined
for(i in 1:3)
{
if(i==2) try(print(a),silent=TRUE)
else print(i)
}
How about these solutions on this related question :
Is there a way to `source()` and continue after an error?
Either parse(file = "script.R") followed by a loop'd try(eval()) on each expression in the result.
Or the evaluate package.
If all you need to do is a small piece of clean up, then on.exit() may be the simplest option. It will execute the expression "when the current function exits (either naturally or as the result of an error)" (documentation here).
For example, the following will delete my_large_dataframe regardless of whether output_to_save gets created.
on.exit(rm("my_large_dataframe"))
my_large_dataframe = function_that_does_not_error()
output_to_save = function_that_does_error(my_large_dataframe)
For the following code: I can't figure out why j does not print on every outside loop iteration.
x = 0
for (j in 1:15)
{
for (i in 1:100000)
{
x = x + 1
}
print(j)
}
What R seems to be doing is running the the whole thing, and at the end print out all the js, not one by one as when every loop iterates.
It seems to be that j should be printing after every loop iteration, what am I missing here?
Is there a way to make it such that j in printed on every outside loop iteration?
Thank You
I'm guessing you are using the Windows Rgui, which buffers its console output, and then writes it out in chunks (see the R Windows FAQ 7.1). To force immediate printing to the console, you can simply add a call to flush.console() after the print() statement.
x = 0
for (j in 1:15) {
for (i in 1:100000) {
x = x + 1
}
print(j)
flush.console()
}
R output is typically buffered. You can circumvent this in two ways. Either (only on Windows, IIRC) you can go to the menu of the R Gui, and chose Misc -> Buffered Output (or press Ctrl-W) to disable buffering (which typically slows down execution), or you can call flush.console() any time you want to ensure that the output is actually shown (e.g. to show progress).
Not familiar with R but that code looks right for what you are trying to do. May be something to do with output buffering as I've come accross the same issue in PHP where the whole script runs before any output is rendered.