I am searching for a way to get user input inside a loop while executing in batch mode.
readLines() and scan() work well for me in interactive mode only, in batch mode they start to read in lines of code as user input, unless all the code is surrounded by {}, which is inconvenient. I need a simple solution to get just 1 integer value in a way that I can just type in value and press ENTER, so
the input field (if the solution involves GUI) must automatically get focus and
ENTER must trigger end of input/submission.
I can't find a way to do it that will satisfy both conditions, e.g. ginput() from gWidgets activates the input field, but ENTER doesn't trigger form submission.
Here is how I solved my own problem:
require(gWidgets)
options(guiToolkit="RGtk2")
INPUT <- function(message) {
CHOICE <- NA
w <- gbasicdialog(title=message, handler = function(h,...) CHOICE <<- svalue(input))
input <- gedit("", initial.msg="", cont=w, width=10)
addHandlerChanged(input, handler=function (h, ...) {
CHOICE <<- svalue(input)
dispose(w)
})
visible(w, set=TRUE)
return(CHOICE)
}
repeat{
x=INPUT("Input an integer")
if(!is.na(as.integer(x))) break
}
print(x)
Update:
I can't test this right now, but take a look at ?menu and have it pop up a gui window.
I'm not certain if that will work, but it is different in that it takes a mouse-click response.
original answer:
As per the documentation to ?readline:
This can only be used in an interactive session.
..
In non-interactive use the result is as if the response was RETURN and the value is "".
If you are simply waiting for one piece of information, and you do not know this piece of information before beginning the execution of the script (presumably, there is a decision to be made which is dependent on the results earlier in the script), then one alternative is to simply break your script up into three parts:
everything before the decision point.
an interactive script which prompts for input
everything after the decision point.
And simply chain the three together by having the first end by calling the second in an interactive session. Then have the second end by calling the third.
Related
I'm trying to get R to pause code execution, for the user to review some prior console output, to verify that file links have been correctly matched (using RegEx to match file names to their respective objects).
From some other answers, I've come up with:
readline(prompt="Press [enter] to continue or [esc] to exit")
As a stand alone line of code, this works as expected, but as soon as I add code below it, and send the whole block to the console, it runs right through the readline call without stopping:
readline(prompt="Press [enter] to continue or [esc] to exit")
x <- 1
y <- 2
Is there a way to get R to actually pause here?
I've also tried wrapping readline in a function, but it still doesn't work
pause <- function(){
p <- readline(prompt="Press [enter] to continue or [esc] to exit")
return(p)
}
pause()
x <- 1
y <- 2
Edit:
If I call the script via source(), readline does work properly. Is there a way to get that behavior without doing that?
By "send the whole block to the console", it sounds like you are copy-pasting your code into a running R instance.
If you do that, R will run each line in the order it receives it, as soon as it receives it. If any of the lines tries to take input, that input will come from whatever you are copy-pasting. So if you copy-paste this:
readline(prompt="Press [enter] to continue or [esc] to exit")
x <- 1
y <- 2
R will read and run the first line first. That first line will run and read the next line of input (which is a blank line here). Then R will come back and read and execute the other two lines.
You need to get your code entered into R completely before any of it runs. Try wrapping the whole thing in a function:
dostuff <- function(){
readline(prompt="Press [enter] to continue or [esc] to exit")
x <- 1
y <- 2
}
dostuff()
Using scan would always work:
message("Press [enter] to continue or [esc] to exit")
scan(quiet = TRUE, what = "")
I have looked at other posts that appeared similar to this question but they have not helped me. This may be just my ignorance of R. Thus I decided to sign up and make my first post on stack-overflow.
I am running an R-script and would like the user to decide either to use one of the two following loops. The code to decide user input looks similar to the one below:
#Define the function
method.choice<-function() {
Method.to.use<-readline("Please enter 'New' for new method and'Old' for old method: ")
while(Method.to.use!="New" && Method.to.use!="Old"){ #Make sure selection is one of two inputs
cat("You have not entered a valid input, try again", "\n")
Method.to.use<-readline("Please enter 'New' for new method and 'Old' for old method: ")
cat("You have selected", Method.to.use, "\n")
}
return(Method.to.use)
}
#Run the function
method.choice()
Then below this I have the two possible choices:
if(Method.to.use=="New") {
for(i in 1:nrow(linelist)){...}
}
if(Method.to.use=="Old"){
for(i in 1:nrow(linelist)){...}
}
My issue is, and what I have read from other posts, is that whether I use "readline", "scan" or "ask", R does not wait for my input. Instead R will use the following lines as the input.
The only way I found that R would pause for input is if the code is all on the same line or if it is run line by line (instead of selecting all the code at once). See example from gtools using "ask":
silly <- function()
{
age <- ask("How old are you? ")
age <- as.numeric(age)
cat("In 10 years you will be", age+10, "years old!\n")
}
This runs with a pause:
silly(); paste("this is quite silly")
This does not wait for input:
silly()
paste("this is quite silly")
Any guidance would be appreciated to ensure I can still run my entire script and have it pause at readline without continuing. I am using R-studio and I have checked that interactive==TRUE.
The only other work-around I found is wrapping my entire script into one main function, which is not ideal for me. This may require me to use <<- to write to my environment.
Thank you in advance.
I'm trying to make my code ask me for a "TRUE" or "FALSE" value before proceeding.
It currently works fine if I run it one line at a time, however when I run all the code at once in RStudio it simply proceeds without waiting for user input and records a value of "" for my parameter.
raw <- readline("TRUE or FALSE -- this is a validation run: ")
if (raw == "F" | raw == "FALSE" | raw == "False"){
validation <- F
} else{
validation <- T
}
rm(raw)
Ideally, I would like an answer that works regardless of how I run it -- RScript, source within RStudio, or running it (i.e. selecting the code and pressing run or ctrl-enter).
If you want to do this in interactive mode then you already have answers but not for use with Rscript. For that instance you need to send messages to the console with cat:
If this test file is named 'prompt.r' and is in the directory where you are working in a system console session:
cat("a string please: ");
a <- readLines("stdin",n=1);
cat("You entered")
str(a);
cat( "\n" )
Then you can run it from the command line as
$ Rscript prompt.r
If you want an all-purpose script then this would run your script under interactive conditions and my script for non-interactive ones:
if (interactive() ){raw <-
readline("TRUE or FALSE -- this is a validation run: ")
if (raw == "F" | raw == "FALSE" | raw == "False"){
validation <- F
} else{
validation <- T
}
rm(raw) } else{
# non-interactive
cat("a string please: ");
a <- readLines("stdin",n=1);
cat("You entered")
str(a);
cat( "\n" )}
Are you running the code by highlighting the lines and clicking run? If so, that could be your problem because R is line-by-line entering your code in the terminal.
Instead, write your script (or comment out the parts you're not testing) and click the source button. Then R waits for user response instead of inputting the line after readline() into readline().
I had the same problem as you, which prompted me to look for an answer. But then I tried this different method of executing the code and it worked.
The reason why readline is "not waiting for input" is, according to the manual (?readline):
In non-interactive use the result is as if the response was RETURN and
the value is "".
You have stumbled on one of the "surprising" features of R.
<rant>
Why readline() works in "interactive mode" only is a complete mystery for me, since it's a perfectly acceptable use case to ask for user input from within a script. Python, for instance, gives you the input(prompt) function which you may invoke whenever you need it.
</rant>
A relatively convenient way of getting around this mess is to define a function ("Every programming problem can be solved by yet another level of indirection"...):
user.input <- function(prompt) {
if (interactive()) {
return(readline(prompt))
} else {
cat(prompt)
return(readLines("stdin", n=1))
}
}
A positive side-effect is that you can add all sorts of nice input validation in user.input(). But I doubt that that was the intention behind the bizarre behaviour of readline().
Although it requires interactive mode, I found the askYesNo() function within the utils package to provide a nice, simple user interface for TRUE/FALSE (or more accurately Yes/No) questions. For example, the following code would produce the following dialog.
Yes returns TRUE
No returns FALSE
Cancel returns NA
Using svDialogs may let you do this.
It's not exactly using readline, but does achieve a similar outcome to what you're looking for.
The code won't run until the dialog box has been filled:
library(svDialogs)
raw <- dlgInput("TRUE or FALSE -- this is a validation run: ",Sys.info()["raw"])$res
if (raw == "F" | raw == "FALSE" | raw == "False"){
validation <- F
} else{
validation <- T
}
rm(raw)
You have to create a function set an "if" conditional sentence with "is.na()" then execute "readline()" again if the value entered is null.
see below:
readinteger <- function()
{
n <- readline(prompt="Enter an integer: ")
n <- as.integer(n)
if (is.na(n)){
n <- readinteger()
}
return(n)
}
print(readinteger())
rm(list=ls())
For one of my dissertation's data collection modules, I have implemented a simple polling mechanism. This is needed, because I make each data collection request (one of many) as SQL query, submitted via Web form, which is simulated by RCurl code. The server processes each request and generates a text file with results at a specific URL (RESULTS_URL in code below). Regardless of the request, URL and file name are the same (I cannot change that). Since processing time for different data requests, obviously, is different and some requests may take significant amount of time, my R code needs to "know", when the results are ready (file is re-generated), so that it can retrieve them. The following is my solution for this problem.
POLL_TIME <- 5 # polling timeout in seconds
In function srdaRequestData(), before making data request:
# check and save 'last modified' date and time of the results file
# before submitting data request, to compare with the same after one
# for simple polling of results file in srdaGetData() function
beforeDate <- url.exists(RESULTS_URL, .header=TRUE)["Last-Modified"]
beforeDate <<- strptime(beforeDate, "%a, %d %b %Y %X", tz="GMT")
<making data request is here>
In function srdaGetData(), called after srdaRequestData()
# simple polling of the results file
repeat {
if (DEBUG) message("Waiting for results ...", appendLF = FALSE)
afterDate <- url.exists(RESULTS_URL, .header=TRUE)["Last-Modified"]
afterDate <- strptime(afterDate, "%a, %d %b %Y %X", tz="GMT")
delta <- difftime(afterDate, beforeDate, units = "secs")
if (as.numeric(delta) != 0) { # file modified, results are ready
if (DEBUG) message(" Ready!")
break
}
else { # no results yet, wait the timeout and check again
if (DEBUG) message(".", appendLF = FALSE)
Sys.sleep(POLL_TIME)
}
}
<retrieving request's results is here>
The module's main flow/sequence of events is linear, as follows:
Read/update configuration file
Authenticate with the system
Loop through data requests, specified in configuration file (via lapply()),
where for each request perform the following:
{
...
Make request: srdaRequestData()
...
Retrieve results: srdaGetData()
...
}
The issue with the code above is that it doesn't seem to be working as expected: upon making data request, the code should print "Waiting for results ..." and then, periodically checking the results file for being modified (re-generated), print progress dots until the results are ready, when it prints confirmation. However, the actual behavior is that the code waits long time (I intentionally made one request a long-running), not printing anything, but then, apparently retrieves results and prints both "Waiting for results ..." and " Ready" at the same time.
It seems to me that it's some kind of synchronization issue, but I can't figure out what exactly. Or, maybe it's something else and I'm somehow missing it. Your advice and help will be much appreciated!
In a comment to the question, I believe MrFlick solved the issue: the polling logic appears to be functional, but the problem is that the progress messages are out of synch with current events on the system.
By default, the R console output is buffered. This is by design: to speed things up and avoid the distracting flicker that may be associated with frequent messages etc. We tend to forget this fact, particularly after we've been using R in a very interactive fashion, running various ad-hoc statement at the console (the console buffer is automatically flushed just before returning the > prompt).
It is however possible to get message() and more generally console output in "real time" by either explicitly flushing the console after each critical output statement, using the flush.console() function, or by disabling buffering at the level of the R GUI (right-click when on the console, see Buffered output Ctrl W item. This is also available in the Misc menu)
Here's a toy example of the explicit use of flush.console. Note the use of cat() rather than message() as the former doesn't automatically add a CR/LF to the output. The latter however is useful however because its messages can be suppressed with suppressMessages() and the like. Also as shown in the comment you can cat the "\b" (backspace) character to make the number overwrite one another.
CountDown <- function() {
for (i in 9:1){
cat(i)
# alternatively to cat(i) use: message(i)
flush.console() # <<<<<<< immediate ouput to console.
Sys.sleep(1)
cat(" ") # also try cat("\b") instead ;-)
}
cat("... Blast-off\n")
}
The output is the following, what is of course not evident in this print-out is that it took 10 seconds overall with one number printed every second, before the final "Blast off"; do remove the flush.console() statement and the output will come at once, after 10 seconds, i.e. when the function terminates (unless console is not buffered at the level of the GUI).
CountDown()
9 8 7 6 5 4 3 2 1 ... Blast-off
I (sort of) already know the answer to this question. But I figured it is one that gets asked so frequently on the R Users list, that there should be one solid good answer. To the best of my knowledge there is no multiline comment functionality in R. So, does anyone have any good workarounds?
While quite a bit of work in R usually involves interactive sessions (which casts doubt on the need for multiline comments), there are times when I've had to send scripts to colleagues and classmates, much of which involves nontrivial blocks of code. And for people coming from other languages it is a fairly natural question.
In the past I've used quotes. Since strings support linebreaks, running an R script with
"
Here's my multiline comment.
"
a <- 10
rocknroll.lm <- lm(blah blah blah)
...
works fine. Does anyone have a better solution?
You can do this easily in RStudio:
select the code and click CTR+SHIFT+C
to comment/uncomment code.
This does come up on the mailing list fairly regularly, see for example this recent thread on r-help. The consensus answer usually is the one shown above: that given that the language has no direct support, you have to either
work with an editor that has region-to-comment commands, and most advanced R editors do
use the if (FALSE) constructs suggested earlier but note that it still requires complete parsing and must hence be syntactically correct
A neat trick for RStudio I've just discovered is to use #' as this creates an self-expanding comment section (when you return to new line from such a line or insert new lines into such a section it is automatically comment).
[Update] Based on comments.
# An empty function for Comments
Comment <- function(`#Comments`) {invisible()}
#### Comments ####
Comment( `
# Put anything in here except back-ticks.
api_idea <- function() {
return TRUE
}
# Just to show api_idea isn't really there...
print( api_idea )
`)
####
#### Code. ####
foo <- function() {
print( "The above did not evaluate!")
}
foo()
[Original Answer]
Here's another way... check out the pic at the bottom. Cut and paste the code block into RStudio.
Multiline comments that make using an IDE more effective are a "Good Thing", most IDEs or simple editors don't have highlighting of text within simple commented -out blocks; though some authors have taken the time to ensure parsing within here-strings. With R we don't have multi-line comments or here-strings either, but using invisible expressions in RStudio gives all that goodness.
As long as there aren't any backticks in the section desired to be used for a multiline comments, here-strings, or non-executed comment blocks then this might be something worth-while.
#### Intro Notes & Comments ####
invisible( expression( `
{ <= put the brace here to reset the auto indenting...
Base <- function()
{ <^~~~~~~~~~~~~~~~ Use the function as a header and nesting marker for the comments
that show up in the jump-menu.
--->8---
}
External <- function()
{
If we used a function similar to:
api_idea <- function() {
some_api_example <- function( nested ) {
stopifnot( some required check here )
}
print("Cut and paste this into RStudio to see the code-chunk quick-jump structure.")
return converted object
}
#### Code. ####
^~~~~~~~~~~~~~~~~~~~~~~~~~ <= Notice that this comment section isnt in the jump menu!
Putting an apostrophe in isn't causes RStudio to parse as text
and needs to be matched prior to nested structure working again.
api_idea2 <- function() {
} # That isn't in the jump-menu, but the one below is...
api_idea3 <- function() {
}
}
# Just to show api_idea isn't really there...
print( api_idea )
}`) )
####
#### Code. ####
foo <- function() {
print( "The above did not evaluate and cause an error!")
}
foo()
## [1] "The above did not evaluate and cause an error!"
And here's the pic...
I can think of two options. The first option is to use an editor that allows to block comment and uncomment (eg. Eclipse). The second option is to use an if statement. But that will only allow you to 'comment' correct R syntax. Hence a good editor is the prefered workaround.
if(FALSE){
#everything in this case is not executed
}
If find it incredible that any language would not cater for this.
This is probably the cleanest workaround:
anything="
first comment line
second comment line
"
Apart from using the overkilled way to comment multi-line codes just by installing RStudio, you can use Notepad++ as it supports the syntax highlighting of R
(Select multi-lines) -> Edit -> Comment/Uncomment -> Toggle Block Comment
Note that you need to save the code as a .R source first (highlighted in red)
I use vim to edit the R script.
Let's say the R script is test.R, containing say "Line 1", "Line 2", and "Line 3" on 3 separate lines.
I open test.R on the command line with Vim by typing "vim test.R".
Then I go to the 1st line I want to comment out, type "Control-V", down arrow to the last line I want to comment out, type a capital I i.e. "I" for insert, type "# ", and then hit the Escape key to add "# " to every line that I selected by arrowing down. Save the file in Vim and then exit Vim by typing ":wq". Changes should show up in Rstudio.
To delete the comments in Vim, start at the first line on top of the character "#" you want to delete, again do "Control-V", and arrow down to the last line you want to delete a "#" from. Then type "dd". The "#" signs should be deleted.
There's seconds-worth of lag time between when changes to test.R in Vim are reflected in Rstudio.
Now there is a workaround, by using package ARTofR or bannerCommenter
Examples here:
In RStudio an easy way to do this is to write your comment and once you have used CTRL + Shift + C to comment your line of code, then use CTRL + SHIFT + / to reflow you comment onto multiple lines for ease of reading.
In RStudio you can use a pound sign and quote like this:
#' This is a comment
Now, every time you hit return you don't need to add the #', RStudio will automatically put that in for you.
Incidentally, for adding parameters and items that are returned, for standardization if you type an # symbol inside those comment strings, RStudio will automatically show you a list of codes associated with those comment parameters:
#' #param tracker_df Dataframe of limit names and limits
#' #param invoice_data Dataframe of invoice data
#' #return return_list List of scores for each limit and rejected invoice rows