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

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

Related

Upload a .xlsx file to Shiny and load in all the tabs as a list [duplicate]

I have a shiny app and when I run it I get an error saying that an object of type ‘closure’ is not subsettable. What is that and how can I fix it?
Note: I wrote this question as this comes up a lot, and the possible dupes are either not shiny related or so specific that it is not obvious that the answers are broadly applicable.
See also this question which covers this error in a non-Shiny context.
How to fix this:
This is a very common error in shiny apps. This most typically appears when you create an object such as a list, data.frame or vector using the reactive() function – that is, your object reacts to some kind of input. If you do this, when you refer to your object afterwards, you must include parentheses.
For example, let’s say you make a reactive data.frame like so:
MyDF<-reactive({ code that makes a data.frame with a column called “X” })
If you then wish to refer to the data.frame and you call it MyDF or MyDF$X you will get the error. Instead it should be MyDF() or MyDF()$X You need to use this naming convention with any object you create using reactive().
Why this happens:
When you make a reactive object, such as a data.frame, using reactive() it is tempting to think of it as just like any other non-reactive data.frame and write your code accordingly. However, what you have created is not really a data.frame. Rather, what you have made is instructions, in the form of a function, which tell shiny how to make the data.frame when it is needed. When you wish to actually use this function to get the data.frame you have to use the parenthesis, just like you would any other function in R. If you forget to use the parenthesis, R thinks you are trying to use part of a function and gives you the error. Try typing:
plot$x
at the command line and you will get the same error.
You may not see this error right when your app starts. Reactive objects have what is called “lazy” evaluation. They are not evaluated until they are needed for some output. So if your data.frame is only used to make a plot, the data.frame will not exist until the user sees the plot for the first time. If when the app starts up the user is required to click a button or change tabs to see the plot, the code for the data.frame will not be evaluated until that happens. Once that happens, then and only then will shiny use the current values of the inputs to run the function that constructs the data.frame needed to make the plot. If you have forgotten to use the parentheses, this is when shiny will give you the error. Note that if the inputs change, but the user is not looking at the plot, the function that makes the data.frame will not be re-run until the user looks at the plot again.

walk through all components in model

I have a fairly large model with components grouped hierarchically about 3 levels deep. It would be useful for me to be able recursively iterate through my components and list inputs and outputs, as well as all the option values, and format all that data to my liking so I can make a nice report with it.
calling list_inputs() and list_outputs() on a given group sort of does what I want, in that it prints off the inputs and outputs, but if you call it on a large group you can't get the inputs and outputs of single component next to each other on the page.
I could probably reverse engineer how list_inputs() is working itself but was wondering if there is an easy way to do it.
As you noted, list_inputs and list_outputs are both methods defined on the System class. Thought these methods do group their print-outs by component, the challenge is that you get all the inputs first, then all the outputs. You can't easily see the inputs and outputs for a single component together.
Both of these methods can have their printing shut off by setting out_stream=None, and each of them returns a list of variable data that you can manually parse through. That may not give you the format you want though.
If you want to manually recurse over the hierarchy and write your own custom report method, then you should look at the following methods on System (i.e. components and groups):
get_io_metadata
system_iter
Those, combined with the data returned from list_inputs and list_outputs should give you what you need.

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.

R shiny ERROR: object of type 'closure' is not subsettable [duplicate2] [duplicate]

I have a shiny app and when I run it I get an error saying that an object of type ‘closure’ is not subsettable. What is that and how can I fix it?
Note: I wrote this question as this comes up a lot, and the possible dupes are either not shiny related or so specific that it is not obvious that the answers are broadly applicable.
See also this question which covers this error in a non-Shiny context.
How to fix this:
This is a very common error in shiny apps. This most typically appears when you create an object such as a list, data.frame or vector using the reactive() function – that is, your object reacts to some kind of input. If you do this, when you refer to your object afterwards, you must include parentheses.
For example, let’s say you make a reactive data.frame like so:
MyDF<-reactive({ code that makes a data.frame with a column called “X” })
If you then wish to refer to the data.frame and you call it MyDF or MyDF$X you will get the error. Instead it should be MyDF() or MyDF()$X You need to use this naming convention with any object you create using reactive().
Why this happens:
When you make a reactive object, such as a data.frame, using reactive() it is tempting to think of it as just like any other non-reactive data.frame and write your code accordingly. However, what you have created is not really a data.frame. Rather, what you have made is instructions, in the form of a function, which tell shiny how to make the data.frame when it is needed. When you wish to actually use this function to get the data.frame you have to use the parenthesis, just like you would any other function in R. If you forget to use the parenthesis, R thinks you are trying to use part of a function and gives you the error. Try typing:
plot$x
at the command line and you will get the same error.
You may not see this error right when your app starts. Reactive objects have what is called “lazy” evaluation. They are not evaluated until they are needed for some output. So if your data.frame is only used to make a plot, the data.frame will not exist until the user sees the plot for the first time. If when the app starts up the user is required to click a button or change tabs to see the plot, the code for the data.frame will not be evaluated until that happens. Once that happens, then and only then will shiny use the current values of the inputs to run the function that constructs the data.frame needed to make the plot. If you have forgotten to use the parentheses, this is when shiny will give you the error. Note that if the inputs change, but the user is not looking at the plot, the function that makes the data.frame will not be re-run until the user looks at the plot again.

Importing and accessing large data files in Shiny

I have an app where I want to pull out values from a lookup table based on user inputs. The reference table is a statistical test, based on a calculation that'd be too slow to do for all the different combinations of user inputs. Hence, a lookup table for all the possibilities.
But... right now the table is about 60 MB (as .Rdata) or 214 MB (as .csv), and it'll get much larger if I expand the possible user inputs. I've already reduced the number of significant figures in the data (to 3) and removed the row/column names.
Obviously, I can preload the lookup table outside the reactive server function, but it'll still take a decent chunk of time to load in that data. Does anyone have any tips on dealing with large amounts of data in Shiny? Thanks!
flaneuse, we are still working with a smaller set that you but we have been experimenting with:
Use rds for our data
As #jazzurro mentioned rds above, and you seem to know how to do this, but the syntax for others is below.
Format .rds allows you to bring in a single R object so you can rename it if needs be.
In your prep data code, for example:
mystorefile <- file.path("/my/path","data.rds")
# ... do data stuff
# Save down (assuming mydata holds your data frame or table)
saveRDS(mydata, file = mystorefile)
In your shiny code:
# Load in my data
x <- readRDS(mystorefile)
Remember to copy your data .rds file into your app directory when you deploy. We use a data directory /myapp/data and then file.path for store file is changed to "./data" in our shiny code.
global.R
We have placed our readRDS calls to load in our data in this global file (instead of in server.R before shinyServer() call), so that is run once, and is available for all sessions, with the added bonus it can be seen by ui.R.
See this scoping explanation for R Shiny.
Slice and dice upfront
The standard daily reports use the most recent data. So I make a small latest.dt in my global.R of a smaller subset of my data. So the landing page with the latest charts work with this smaller data set to get faster charts.
The custom data tab which uses the full.dt then is on a separate tab. It is slower but at that stage the user is more patient, and is thinking of what dates and other parameters to choose.
This subset idea may help you.
Would be interested in what others (with more demanding data sets have tried)!

Resources