Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Break loop with keyboard input (R)

I need an R loop to continue running until the user presses a key. Something like the below. Any ideas? I'm new to R

while(FALSE_after_user_input){
  queryWebApi()
  Sys.sleep(1)
}

EDIT 1

What I'm really after is a way to stop data collection. I have a function I want to run every few seconds to query new data. The user needs the ability to stop the data collection loop.

readline() doesn't work as it halts execution of the data collection loop

like image 828
Alan Avatar asked Oct 18 '22 04:10

Alan


1 Answers

Suggestion 1: TCL/TK

library(tcltk)
win1 <- tktoplevel()
butStop <- tkbutton(win1, text = "Stop",
  command = function() {
    assign("stoploop", TRUE, envir=.GlobalEnv)
    tkdestroy(win1)
})
tkgrid(butStop)

stoploop <- FALSE
while(!stoploop) {
    cat(". ")
    Sys.sleep(1)
}
cat("\n")

Some code borrowed from: A button that triggers a function call.

Suggestion 2: Non-blocking checking on standard input. (Please be warned: C is not my core competence, and I cobbled this together from bits on the internet.) The main idea is to write a function in C that waits for user input, and call it from R.

Snippet below adapted from Non-blocking user input in loop. Save the following code as kbhit.c:

#include <stdio.h>
#include <unistd.h>
#include <R.h>

void kbhit(int *result)
{
    struct timeval tv;
    fd_set fds;
    tv.tv_sec = 0;
    tv.tv_usec = 0;
    FD_ZERO(&fds);
    FD_SET(STDIN_FILENO, &fds); //STDIN_FILENO is 0
    select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
    *result = FD_ISSET(STDIN_FILENO, &fds);
}

Then, from the command line, run R CMD SHLIB kbhit.c to compile it for R.

Finally, in R, load the newly created kbhit.so, write a function (kbhit) that returns the output from the C function, and then run your loop. kbhit() returns 0 unless it receives the enter key. Note that the only way to stop the loop is by hitting enter/return (or a hard break) -- if you want a more flexible approach, see the link above.

dyn.load("kbhit.so")

kbhit <- function() {
    ch <- .C("kbhit", result=as.integer(0))
    return(ch$result)
}

cat("Hit <enter> to stop\n")
while(kbhit()==0) {
    cat(". ")
    Sys.sleep(1)
}

More details on the .C interface to R.

On a Windows machine:

kbhit.c

#include <stdio.h>
#include <conio.h>
#include <R.h>

void do_kbhit(int *result) {
    *result = kbhit();
}

In R:

dyn.load("kbhit.dll")

kbhit <- function() {
    ch <- .C("do_kbhit", result=as.integer(0))
    return(ch$result)
}

cat("Hit any key to stop\n")
while(kbhit()==0) {
    cat(". ")
    Sys.sleep(1)
}

P.s. I hacked this together through Googling, so unfortunately I don't know how or why it works (if it works at all for you!).

like image 128
Weihuang Wong Avatar answered Oct 21 '22 04:10

Weihuang Wong