R: Running computation while waiting for user input - r

do you see a way to run a computation in R while waiting for a user input?
I'm writing a script that makes differents types of plots which are defined by user input, but in first lot of data has to be loaded and processed. But in fact, user could start defining what he wants already while the processing is running - that's what I would like to do!
I think package Rdsn might provide the functionality that I need, but I was not able to figure out how.
Thanks!

You didn't give me much context, nor reproducible code, so I will just provide a simple example. I am not familiar with the Rdsn package, so I will use provide a solution I know.
# create a function to prompt the user for some input
readstuff = function(){
stuff = readline(prompt = "Enter some stuff: ")
# Here is where you set the condition for the parameter
# Let's say you want it to be an integer
stuff = as.integer(stuff)
if(is.na(stuff)){
return(readstuff())
} else {
return(stuff)
}
}
parameter = readstuff()
print(parameter)
print(parameter + 10)
The key here is to "source" the script instead of "running" it. You can find the "source" button on the top right of RStudio. You can also use source(yourscript) to source it.
So for every parameter you want to prompt the user for input, just call readstuff(). You can also tweak it a little to make it more general. For example:
# create a function to prompt the user for some input
readstuff = function(promptMessage = "stuff", class = "integer"){
stuff = readline(prompt = paste("Enter the", promptMessage, ": "))
# Here is where you set the condition for the parameter
# Let's say you want it to be an integer
stuff = as(stuff, class)
if(is.na(stuff)){
return(readstuff(promptMessage, class))
} else {
return(stuff)
}
}
plotColor = readstuff("plot color", "character")
size = readstuff("size parameter")
xvarName = readstuff("x axis name", "character")
df = data.frame(x = 1:100, y = 1:100)
library(ggplot2)
p = ggplot(df, aes(x = x, y = y, size = size, color = plotColor)) +
labs(x = xvarName) + geom_point()
print(p)
The if(is.na(stuff)) statements won't work if class is character, but I won't get into details on how to fix that, since this question is mainly about how to wait for user input. There are also ways to suppress the warning messages if the user entered something other than what is intended, but again, a bit off topic to talk about it here.
One important thing you have to watch out for is that anything you want R to print or plot, you need to wrap it with a print() function. Otherwise sourcing it won't print nor plot anything. Also, when typing in a parameter that is intended to be a string or character, don't add quotes. For example, for plotColor, type red instead of "red" in the prompt.
Most of the readline code are referenced from here:

Related

Can the R prompt be a time?

?option says this.
‘prompt’: a non-empty string to be used for R's prompt; should
usually end in a blank (‘" "’).
Is it possible to make the prompt to include some dynamic stuffs, e.g., the current time?
You should take a look at the taskCallbackManager (https://developer.r-project.org/TaskHandlers.pdf). With prompt you can call the current time and save it. Example: options("prompt"=format(Sys.time(), "%H:%M:%S> ")). But this is fixed with the time it was set.
The doc for the function taskCallbackManager has the rest:
R> h <- taskCallbackManager()
R> h$add(function(expr, value, ok, visible) {
+ options("prompt"=format(Sys.time(), "%H:%M:%S> "));
+ return(TRUE) },
+ name = "simpleHandler")
[1] "simpleHandler"
07:25:42> a <- 2
07:25:48>
This registers a callback that gets evaluated after each command completes.

Using a function to change a variable in R

I am trying to change a variable in a function but even tho the function is producing the right values, when I go to use them in the next sections, R is still using the initial values.
I created a function to update my variables NetN and NetC:
Reproduction=function(NetN,NetC,cnrep=20){
if(NetC/NetN<=cnrep) {
DeltaC=NetC*p;
DeltaN=DeltaC/cnrep;
Crep=Crep+DeltaC;
Nrep=Nrep+DeltaN;
Brep=(Nrep*14+Crep*12)*2/1e6;
NetN=NetN-DeltaN; #/* Update N, C values */
NetC=NetC*(1-p)
print ("'Using C to allocate'")
}
else {
print("Using N to allocate");
DeltaN=NetN*p;
DeltaC=DeltaN*cnrep;
Nrep=Nrep+DeltaN;
Crep=Crep+DeltaC;
Brep=(Nrep*14+Crep*12)*2/1e6;
NetN=NetN*(1-p);
NetC=NetC-DeltaC;
} } return(c(NetC=NetC,NetN=NetN,NewB=NewB,Crep=Crep,Nrep=Nrep,Brep=Brep))}
When I use my function by say doing:
Reproduction(NetN=1.07149,NetC=0.0922349,cnrep=20)
I get the desired result printed out which includes:
NetC=7.378792e-02
However, when I go to use NetC in the next section of my code, R is still using NetC=0.0922349.
Can I make R update NetC without having to define a new variable?
In R, in general, functions shouldn't change things outside of the function. It's possible to do so using <<- or assign(), but this generally makes your function inflexible and very surprising.
Instead, functions should return values (which yours does nicely), and if you want to keep those values, you explicitly use <- or = to assign them to objects outside of the function. They way your function is built now, you can do that like this:
updates = Reproduction(NetN = 1.07149, NetC = 0.0922349, cnrep = 20)
NetC = updates["NetC"]
This way, you (a) still have all the other results of the function stored in updates, (b) if you wanted to run Reproduction() with a different set of inputs and compare the results, you can do that. (If NetC updated automatically, you could never see two different values), (c) You can potentially change variable names and still use the same function, (d) You can run the function to experiment/see what happens without saving/updating the values.
If you generally want to keep NetN, NetC, and cnrep in sync, I would recommend keeping them together in a named vector or list, and rewriting your function to take that list as input and return that list as output. Something like this:
params = list(NetN = 1.07149, NetC = 0.0922349, cnrep = 20)
Reproduction=function(param_list){
NetN = param_list$NetN
NetC = param_list$NetC
cnrep = param_list$cnrep
if(NetC/NetN <= cnrep) {
DeltaC=NetC*p;
DeltaN=DeltaC/cnrep;
Crep=Crep+DeltaC;
Nrep=Nrep+DeltaN;
Brep=(Nrep*14+Crep*12)*2/1e6;
NetN=NetN-DeltaN; #/* Update N, C values */
NetC=NetC*(1-p)
print ("'Using C to allocate'")
}
else {
print("Using N to allocate");
DeltaN=NetN*p;
DeltaC=DeltaN*cnrep;
Nrep=Nrep+DeltaN;
Crep=Crep+DeltaC;
Brep=(Nrep*14+Crep*12)*2/1e6;
NetN=NetN*(1-p);
NetC=NetC-DeltaC;
}
## Removed extra } and ) ??
return(list(NetC=NetC, NetN=NetN, NewB=NewB, Crep=Crep, Nrep=Nrep, Brep=Brep))
}
This way, you can use the single line params <- Reproduction(params) to update everything in your list. You can access individual items in the list with either params$Netc or params[["NetC"]].

Avoiding JSON error displaying Japanese strings within Plotly (R) / Running a function on one variable at a time

I'm very new to R and beginner level at programming in general, and trying to figure out how to get hovertext in plotly to display a Japanese string from my dataframe. After venturing through character encoding hell, I've got things mostly worked out but am getting stuck on a single point: Getting the Japanese string to display in the final plot.
plot_ly(df, x = ~cost, y = ~grossSales, type = "scatter", mode = "markers",
hoverinfo = "text",
text = ~paste0("Product name: ", productName,
"<br>Gross: ", grossSales, "<br> Cost: ", cost,
)
)
The problem I encounter is that using 'productName' returns the Japanese string from the dataframe, which causes the plot to fail to render. DOM Inspector's console shows JSON encountering issues with the string (even though it's just encoded in UTF-8).
Using toJSON(productName), I am able to render the table, however this renders the hover textbox with the full information of the productName column (e.g., ["","Product1","Product2","Product3"...]). I only want the name of that specific product; just as 'grossSales' and 'cost' only return one the data specific to that product at each point on the plot.
Is there a way I can execute toJSON() only on each specific instance of 'productName'? (i.e., output should be "Product1" with JSON friendly string format) Alternatively, is there a way I can have plotly read the list output and select only the correct productName?
Stepping away from the problem to continue studying other things, I found a partial solution in using a for-loop:
productNames <- NULL
for (i in 1:nrow(df))
{
productNames <- c(productNames, toJSON(df[i, "productName"]))
}
df$jsonProductNames <- productNames
Using the jsonProductNames variable within plotly, the graph renders and displays only the name for each product! The sole issue remaining is that it is displayed with the JSON [""] formatting around each product's name.
Update:
I've finally got this working fully how I want it. I imagine there are more elegant solutions, and I'd still be interested to learn how to achieve what I originally was looking at if possible (run a function on a variable within R for each time it is encountered in a loop), but here is how I have it working:
colToJSON <- function(df, colStr)
{
JSONCol <- NULL
for (i in 1:nrow(df))
{
JSONCol <- c(JSONCol, toJSON(df[i, colStr]))
}
JSONCol <- gsub("\\[\"", "", JSONCol)
JSONCol <- gsub("\"\\]", "", JSONCol)
return(JSONCol)
}
df$jsonProductNames <- colToJSON(df, "productName")

How to find the name of an instantiation of an object in a R6 class?

ann <- Person$new("Ann", "black")
In the example above (which is from this Introduction), how would I get "ann"?
For instance, I would need a method ann$getName that would return "ann".
I'm trying to do the same thing, so perhaps I can clarify the question. The goal (for me) is to give the user of the class some feedback. Something like that:
Person <- R6Class("Person",
public = list(
name = NULL,
hair = NULL,
initialize = function(name = NA, hair = NA) {
self$name <- name
self$hair <- hair
},
do_something_very_long=function(){
whoami <- self$getInstanceName() ## $getInstanceName() is the method I need to write !
message(paste("Please wait, processing object",whoami))
# Do a very long calculation...
}
)
)
Which I'd then run in a script that would do something like
#File batch_processing.R
first_in_line<-Person$new("Alice","Black")
next_customer<-Person$new("Bob","Red")
VIP<-Person$new("Charlie","Brown")
# etc ...
first_in_line$do_something_very_long()
next_customer$do_something_very_long()
VIP$do_something_very_long()
# etc ...
So, my (notional) user will start batch_processing.R, perhaps with
$ R ~/batch_processing.R
or
R> source("batch_processing.R")
and watch not much happening while the script works. I would like, therefore, some feedback so that when the user comes back after his coffee, he can look at the screen and see that the computer is busy processing VIP or next_customer.
Obviously - one way is to explicitly give unique identifiers to each object ($name in this case). In my real application case, however, this would not be very meaningful, or would duplicate the object name ("model 1", "model 2"...) which is a bit wasteful !

Rstudio-Empty ggplot in a function

I have a function called plot.medals2 that has an input that includes a variable named start and a variable named finish. Both variables are numbers and I want that in the event that start is bigger than finish the function will stop running and draw an empty ggplot like the one i attached here.
This is the part of the code that is supposed to take care of that:
plot.medals2 <- function(code,start,finish,medalsvec) {
if(start>finish) { #years not make sense return empty drawing
ggplot() + ylab('medals won') + xlab('year') +
ggtitle(paste('Medals by',"",countries.df[countries.df$country_id==code,]$country_name,',',"",finish,'-',start))
return()
}
}
this is what I get when I try to run it:
plot.medals2('USA',1933,1456,c('GOLD'))
NULL
I tried to use the breakpoint option to see what is going on and it seems the
function does enter the if statement meaning it recognizes that the variable start is larger than finish but then for some reason it skips the next 2 rows and does not plot anything. Now when I use this
ggplot() + ylab('medals won') + xlab('year') +
ggtitle(paste('Medals by',"",countries.df[countries.df$country_id==code,]$country_name,',',"",finish,'-',start))
outside of a function it works but not when its a part of a function.

Resources