Dynamic status message from inside a for loop - r

I sometimes do (nested) for loops that take a while, so I like putting a message with the index. Normally, I do this:
for (i in 1:1000) {
cat(paste0(i, " "))
}
But I've tried any of these:
for (i in 1:1000) {
print(i)
}
for (i in 1:1000) {
cat(paste(i, " ")) # or "\n", doesn't matter
}
for (i in 1:1000) {
message(i)
}
However, this clearly produces text continuously (in this example, the messages would go by very quickly, but as I said, I often do nested for loops, which take considerably longer). However, I'd like to do a dynamic message, with a single number on my console which keeps changing (the index). I suppose something like this is possible because when you install a package (or when using gganimate), there is that line that keeps changing to = signs, indicating progress (that's next-level stuff, but should have the same idea behind it).
I don't know how to do this. My guess is there's something of the same context as \n, like \s (I know that doesn't exist, but it's just do give an idea), or maybe there is a third function (or something related to message(), which I don't fully understand) other than print(), cat() and message().

If it is OK to clear the console each time, you can:
for (i in 1:1000) {
for(j in 1:1000){
for(k in 1:1000){
cat(paste('\014',i, j, k))
}
}
}

Related

Manually interrupt a loop in R and continue below

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.

How to avoid nested function definitions and still use <<- operator

Suppose I have these two functions:
fInner<-function()
{
# Do some complicated stuff, and...
I<<-I+1
}
fOuter<-function()
{
I<-0
fInner()
print(I)
}
Calling fOuter() produces an error: Error in fInner() : object 'I' not found. I know, that one way of fixing it is to re-write the example into
fOuter<-function()
{
fInner<-function()
{
I<<-I+1
}
I<-0
fInner()
print(I)
}
But what if I don't want to nest the functions that way? In my case fInner is a very heavy and complicated function (which I might want to move into my library), and fOuter is really an ad-hoc created function that defines one iterator. I will have many fOuter-class functions in my code, so nesting them will require duplicating the fInner inside every single little one iterator definition.
I suspect the solution has something to do with environments, but I don't know how to do it. Can anyone help?
You need access to the environment associated with the fOuter function--where the call to fInner is. You can get this with parent.frame, and you can get and set variables with get and assign:
fInner<-function()
{
assign("I", get("I", envir=parent.frame()) + 1, envir=parent.frame())
}
fOuter<-function()
{
I<-0
fInner()
print(I)
}
See ?environment and ?parent.frame for more info.
But this is just to satisfy your curiosity! You seem to agree that this is not a good idea. Manipulating environments and names can quickly get complicated, and unless you're doing something truly complex, there's probably a better way.

R Script - How to Continue Code Execution on Error

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)

Print j on every outside loop iteration in R

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.

Using readline() within a for loop

I have a function, as follows:
f.factor <- function(x) {
print(length(unique(x)))
z <- 1
for (i in 1:length(unique(x))) {
z[i] <- readline(":")
}
x <- factor(x, labels=c(z))
return(x)
}
Essentially, it allows me to copy/paste/type or just simply write into my script the factors for a particular variable without having to type c("..","...") a million times.
I've run into a problem when I try to use this function in a loop, perhaps the loop structure will not allow lines to be read within the loop?
for(i in 1:ncol(df.)) {
df[,paste("q4.",i,sep="")] <- f.factor(df[,paste("q4.",i,sep="")])
Never Heard of
Heard of but Not at all Familiar
Somewhat Familiar
Familiar
Very Familiar
Extremely Familiar
}
In the end, I'm looking for a way to specify the factor label without having to rewrite it over and over.
That was only working before because when you pasted all the code in at the top level it was executed immediately and the readline() call used the following N lines. In a function, or any control structure, it will try to parse it as R code which will fail.
A multiline string can stand in for a passable heredoc:
lvls = strsplit('
Never Heard of
Heard of but Not at all Familiar
Somewhat Familiar
Familiar
Very Familiar
Extremely Familiar
', '\n')[[1]][-1]
Instead of the for loop you can just use scan without a file name (and what='' and possibly sep='\n'.
> tmp <- scan(what='', sep='\n')
1: hello there
2: some more
3:
Read 2 items
> tmp
[1] "hello there" "some more"
>

Resources