I am trying to run an R script, using Rscript in Windows command prompt and ask for user's input.
So far, i have found answers on how to implement something similar in R's interactive shell. readline() or scan() doesn't seem to work for the command prompt.
Examples:
I have a polynomial y=cX where X can take more than one values X1,X2,X3 and so on. C variable is know, so what i need in order to calculate the value of y is to ask the user for the Xi values and store them somewhere inside my script.
The script bellow does nothing.
UIinput <- function(){
#Ask for user input
x <- readline(prompt = "Enter X1 value: ")
#Return
return(x)
}
The second example below just prompts the message and then ends.
FUN <- function(x) {
if (missing(x)) {
message("Uhh you forgot to eneter x...\nPlease enter it now.")
x <- readLines(n = 1)
}
x
}
FUN()
Console output:
Uhh you forgot to eneter x...
Please enter it now.
character(0)
Any suggestions?
Thanks in advance
cat("input x: ")
x <- readLines(con="stdin", 1)
cat(x, "\n")
Related
Lets say I want to ask the user for an input, a number over 10. If not, print a message and re-prompt/ask again. How can this be achieved in R?
I understand that this could be solved with IF or WHILE statement, but I canĀ“t wrap my head around this.
Example
math <- function(number_1) {
number_1 <- readline("Enter your number: ")
if the number is below i want to reprompt readline(...)
result <- number_1 / 2
return(result)
}
Here's a way:
math <- function() {
result <- NA
while (is.na(result) || result < 10) {
text <- readline("Enter your number: ")
result <- as.numeric(text)
}
result
}
You don't need to give any input to your function; it will get the input when it prompts the user. The is.na(result) code checks for an NA: initially the result is NA, so it will run the loop at least once, and if
the user enters something that isn't a number, you'll get another one.
Since readline() returns a character value, you need as.numeric to convert it to a number.
I'm looking for the functions get_output_content or at least get_output_length below, that would tell me how many characters were printed in the console.
test <- function(){
cat("ab")
cat("\b")
cat("cd")
c <- get_output_content() # "acd" (I'd be happy with "ab\bcd" as well)
l <- get_output_length() # 3
return(list(c,l))
}
test()
In this example obviously I could easily count the characters in the input, but If I'm using other functions I may not. Can you help me build one or both of these functions ?
EDIT to clarify:
in my real situation, I cannot work upstream and count before, like in the proposed solutions, I need to count the displayed output at a given time without monitoring what's before.
here's a reproducible example looking more like what I want to achieve
library(pbapply)
my_files <- paste0(1000:1,".pdf")
work_on_pdf <- function(pdf_file){
Sys.sleep(0.001)
}
report <- pbsapply(my_files,work_on_pdf) # the simple version, but I want to add the pdf name next to the bar to have more info about my progress
# so I tried this but it's not satisfying because it "eats" some of the current output of pbapply
report <- pbsapply(my_files,function(x){
buffer_length <- 25
work_on_pdf(x)
catmsg <- paste0(c( # my additional message, which is in 3 parts:
rep("\b",buffer_length), # (1) eat 25 characters
x, # (2) print filename
rep(" ",buffer_length-nchar(x))), # (3) print spaces to cover up what may have been printed before
collapse="")
cat(catmsg)
})
if I was able to count what's in the console I could easily tweak my function to get something satisfying.
NEW EDIT : FYI solution to example but not to general question:
I could solve my precise issue with this, though it doesn't solve the general question, which is measuring the current output of the console when you don't have any other info.
library(pbapply)
my_files <- paste0(1000:1,".pdf")
work_on_pdf <- function(pdf_file){
Sys.sleep(0.01)
}
pbsapply2 <- function(X,FUN,FUN2){
# FUN2 will give the additional message
pbsapply(X,function(x){
msg <- FUN2(x)
cat(msg)
output <- FUN(x)
eraser <- paste0(c(
rep("\b",nchar(msg)), # go back to position before additional message
rep(" ",nchar(msg)), # cover with blank spaces
rep("\b",nchar(msg))), # go back again to initial position
collapse="")
cat(eraser)
return(output)
})
}
report <- pbsapply2(my_files,work_on_pdf,function(x) paste("filename:",x))
Something like this (?):
test <- function(){
c <- paste0(capture.output(cat("ab")),
capture.output(cat("\b")),
capture.output(cat("cd")))
n <- nchar(c)
l <- length(c)
return(list(c,n,l))
}
test()
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!
I have a script that is composed of several functions. A summarised example of my script looks like that
>Test.R
massive.process_1 <- function() {
seed(123)
x <- do_something()
save(x, '/home/Result1.RData')
}
massive.process_2 <- function() {
seed(4)
x <- do_something()
save(x, '/home/Result2.RData')
}
massive.process_1()
massive.process_2()
I have to execute this script but instead of 2 _massive.processs_I need to run 100 of them but changing the seed value and the name of the data saved in each step. I can do it manually, adding 100 massive.process functions but I would like to know if is there any way to put it on a script to avoid typing 100 functions?
Many thanks
My bash file to run it is the following:
#!/bin/bash
echo Started analysis at: `date`
rfile="Test.R"
Rscript $rfile
echo Finished analysis at: `date`
Adding to Dennis's answer...
to change the filename you can use "paste".
massive.process <- function(i) {
seed(i)
x <- do_something()
outname = paste("/home/Result", i, ".RData", sep="")
save(x, outname)
x
}
for (i in 1:100){
massive.process(i);
}
or
X = lapply(1:100, massive.process)
If you use the list approach, to access the ith x, just use X[i]
another way to write the lapply loop is with an anonymous function. This might make more clear what's going on.
X = lapply(1:100, function(i){
massive.process(i)
})
The previous notation is the same, just more compact.
Why not adding the seed as parameter to the functions?
massive.process <- function(seedValue) {...}
And it would probably a good idea to implement the loop in R instead of using a shell script.
I am currently writing a function which only accepts certain inputs (in the example only "a" and "b"). For all other inputs the function will return an error.
test <- function(x) {
allowedX <- c("a","b")
if(x %in% allowedX) print("Good choice!")
else stop("wrong input!")
}
To help users of the function I would like to supply the allowed values for x (stored in allowedX) using the tab completion feature in R and replace the default file name completion which is typically applied after a quote. So pressing TAB should give something like:
test(x="<TAB>
a b
However, I couldn't find a solution so far how to map the vector allowedX to the tab completion in R. Can somebody tell me how to do that?
Thanks in advance!
You could try something like the following:
test <- function() {
allowedX <- c("a","b")
x = readline('Please enter your choice of parameters (either "a" or "b"): ')
if(x %in% allowedX) print("Good choice!")
else stop("wrong input!")
}