Reactive data just once and then stock it globally in R Shiny - r

So I'm trying to develop with R Shiny, I ask the user to do 5 file inputs. And then I have a reactive function mergeFun() which will cast and merge the data in one data set once the inputs are done.
Then I have multiple buttons, boxplots, renderUI, outputs, PCA, regression trees,... in my different tabPanels and each one of these calls the function mergeFun() in order to do the statistic analysis.
So as it is making quite some time after the inputs to load everyone of these panels at once, I was wondering if there was a way to just call the function globally and stock the merged data in one global variable.
I was thinking maybe because I call this function x times once in each analysis in the tabPanels, it was causing the time lapse.
So I would just be able to call the data instead of calling the function mergeFun()
I'm posting the code modified, to give you an idea about what I am doing
mergeFun <- reactive({
#So there I had my test about if my files existed
#I delete for visibility
cast <- dcast(input,var1 + var2,value.var = "var3")
mergeAll <- merge(input2,cast,by=c("var1","var2","var3"))
data.frame(mergeAll)
})
So this is my mergeFun() and then I have many reactive and renderUI which will all start like this :
output$xcol <- renderUI({
df <-mergeFun()
if (is.null(df)) return(NULL)
...
...
...
})
So maybe calling mergeFun() x times isn't programatically efficient?

Related

Is it possible to make a R Shiny reactive function that accepts arguments like a normal function?

I have a situation where I have a reactive function that I would like to be used in several different plots, but to be calling/checking different parts of a dataframe stored as reactiveValues.
If I had a normal function I could call it and pass it an argument to index a specific column of the reactive values e.g.,:
my_function <- function(column) {what the function does}
Then when calling the function:
my_function(column = 3)
But for a reactive function I don't see how I can do something like this.
my_function <- reactive({what the function does})
At the moment, I can just make multiple versions of essentially the same function that call different indexes but that is a lot of extra lines of code as the function is quite long.
The situation is also not one where I see a simple way of using another reactive value that can be called inside the reactive function that would appropriately call the right column index in all cases.
Is there a way to define the reactive function so that when it is called, I can pass it an argument?

How to turn an entire dataframe into a reactive object on start?

My shiny app relies on a main CSV dataframe from which users pick whatever variable they want to feed charts, maps, etc. I now want users to be able to create new variables by combining existing variables.
Problem: I need the new variables to be stored in that main CSV dataframe along all the other variables, and make them available just for the session, for every other control/map/chart. Of course I can't just append the new variable to my CSV dataframe because it's not a reactive object.
So I'm naturally thinking of turning the CSV dataframe into a reactive object on start.
I tried
reactivedf<- reactiveVal()
reactivedf(df)
But for some reason this approach doesn't work, in the sense that when the app starts, all the charts and maps are empty.
However, the reactive object does "wakes up" with a eventReactive statement that updates the reactivedf, and the maps and charts come to life:
reactivedf <- eventReactive(input$button, {
<code to create a new variable and append it to reactivedf>
}
How can I make the reactivedf fully available on start?
Always a good idea to read the docs at least once.
reactivedf <- reactiveValues()
reactivedf$df <- df
It's good to give credit where credit is due. You didn't "naturally think" anything, you were put on this by a comment to your previous similar question.

Create an arbitrary number of plots with inputs in shiny using modules

Thank you very much for your time and help!
My goal: create an arbitrary number of plots (ggplot2) in shiny where each comes with a number of controls (y axis min/max, plot download button, plot, hover info for the plot). Important: implement it using shiny modules, where a module is created to build a single ui element and another module calls the single element module and loops to create an arbitrary number of ui elements (I can get it to work without using modules).
It works for me if the data for the plots (and the vector which is used to loop over to create each plot) are loaded globally in the app. This global data gist demonstrates my use case using iris dataset loaded globally. Here how it looks like when it works: snapshot of the app
However, my problem is that I can't figure out how to write a shiny module when the data are not loaded globally. Real life example: I pull the data from a database, do some processing on the server side and then I want to generate the plots. Reproducible example using the iris dataset loaded on the server side: server data gist
The error I get when the data are loaded on the server side (when running server data gist):
Error in as.vector: cannot coerce type 'environment' to vector of type 'character'
I believe this is something to do with how I write the module for the multiple ui elements (I suspect multiplePlotsUI).
My question: What will be the correct way to write the module that calls another module and loops over a vector to generate an arbitrary number of ui elements (y axis controls, plot download button, plot with hover info) when the data are not loaded globally?
I don't know if it'll help, but as far as I can see, your input.data() function is not defined in you multiplePlots call (local.data <- input.data())
You're also calling
dm <- dat()
twice, but this dat() function doesn't seem to be defined

How to use a for loop in shiny reactive

How could someone use a for loop within a reactive expression ?
I mean if i want to build repeated procedure for a dataset that depend on users input values.
data <- reactive({
for (i in 1:5) {initial_data$input$valuei}
})
r you need to express this in another way?
Are you list looking to change valuei each time in the loop? If so then the dollar sign operator isn't a good choice. You'll want to use proper list indexing. How about
data <- reactive({
for (i in 1:5) {
initial_data$input[[paste0("value",i]]
}
})
of course that doesn't actually do anything with those values, but i wasn't sure what your intent was from your sample.

How to use a value that is specified in a function call as a "variable"

I am wondering if it is possible in R to use a value that is declared in a function call as a "variable" part of the function itself, similar to the functionality that is available in SAS IML.
Given something like this:
put.together <- function(suffix, numbers) {
new.suffix <<- as.data.frame(numbers)
return(new.suffix)
}
x <- c(seq(1000,1012, 1))
put.together(part.a, x)
new.part.a ##### does not exist!!
new.suffix ##### does exist
As it is written, the function returns a dataframe called new.suffix, as it should because that is what I'm asking it to do.
I would like to get a dataframe returned that is called new.part.a.
EDIT: Additional information was requested regarding the purpose of the analysis
The purpose of the question is to produce dataframes that will be sent to another function for analysis.
There exists a data bank where elements are organized into groups by number, and other people organize the groups
into a meaningful set.
Each group has an id number. I use the information supplied by others to put the groups together as they are specified.
For example, I would be given a set of id numbers like: part-1 = 102263, 102338, 202236, 302342, 902273, 102337, 402233.
So, part-1 has seven groups, each group having several elements.
I use the id numbers in a merge so that only the groups of interest are extracted from the large data bank.
The following is what I have for one set:
### all.possible.elements.bank <- .csv file from large database ###
id.part.1 <- as.data.frame(c(102263, 102338, 202236, 302342, 902273, 102337, 402233))
bank.names <- c("bank.id")
colnames(id.part.1) <- bank.names
part.sort <- matrix(seq(1,nrow(id.part.1),1))
sort.part.1 <- cbind(id.part.1, part.sort)
final.part.1 <- as.data.frame(merge(sort.part.1, all.possible.elements.bank,
by="bank.id", all.x=TRUE))
The process above is repeated many, many times.
I know that I could do this for all of the collections that I would pull together, but I thought I would be able to wrap the selection process into a function. The only things that would change would be the part numbers (part-1, part-2, etc..) and the groups that are selected out.
It is possible using the assign function (and possibly deparse and substitute), but it is strongly discouraged to do things like this. Why can't you just return the data frame and call the function like:
new.part.a <- put.together(x)
Which is the generally better approach.
If you really want to change things in the global environment then you may want a macro, see the defmacro function in the gtools package and most importantly read the document in the refrences section on the help page.
This is rarely something you should want to do... assigning to things out of the function environment can get you into all sorts of trouble.
However, you can do it using assign:
put.together <- function(suffix, numbers) {
assign(paste('new',
deparse(substitute(suffix)),
sep='.'),
as.data.frame(numbers),
envir=parent.env(environment()))
}
put.together(part.a, 1:20)
But like Greg said, its usually not necessary, and always dangerous if used incorrectly.

Resources