Quick'n'Shiny

9.8.2015

The basic idea

I think it would be desirable to have a package that turns an R function into a shiny app very quickly. These are my first thought on this and nothing here is working R code, nor is the package written. Rather I'll give some usage examples and think about how such a package could be structured.

The main function should be called like this:

fun <- function(x, y, z, ...) {
  ## do something
  return(...)
}
as.shinyApp(fun) ## %>% runApp() possible

More precisely, since we cannot guess the type of the input variables, we want to have the possibility to write them very quickly as the respective shiny UI inputs:

as.shinyApp(fun(x = textInput(label = "x:", value = "default")))

The arguments of the inputs should be evaluated in the environment from which as.shinyApp is called to allow for dynamic generation of e.g. choices. The actual function call textInput, however, should be written with these values into the shiny app. The ids should be given by as.shinyApp in the form of input#{argument_name}.

Moreover we want control over how the output is displayed, but as well a default that is general enough. E.g. if the function returns a data.frame, we want to see a plot where we can select X and Y axis, and the geom given by the user, default to points, as well as a dataTable allowing to browse the entire data:

as.shinyApp(fun(...),
            output = list(quicknplot(geom = geom_point(size = 4)),
                          quickndatatable(options = list(pageLength = 5))))

which turns into something like:

output$plotoutput <- renderPlot(ggplot2(fun(...),
                                        aes(x = input$plotselectx, ## here, nse needs to be prevented
                                            y = input$plotselecty)) + 
                                  geom_point(size = 4))
output$datatableoutput <- renderDataTable(fun(...), options = list(pageLength = 5))

Maybe the renderUI function can be used very generally to provide a generic method of output depending on what we get from the function. If it's a character or numeric, we call renderText, if it's a data.frame, we generate the default multi-view suggested above; If its an xts we call renderDygraph... What else is there?

Further handy features to think about

If a basic version is set up, here some ideas for extensions:

Multiple functions

We want to give as.shinyApp not only a single funcion, but a list of several function calls, whose inputs and output are placed on different tabs.

Templating shiny apps

It would be good, if the generation of the shiny app uses a real templating engine, such that we can select a layout template or create one ourselves.

Uploading and downloading

Ideally, we'd also have a way for the generic data.frame output that gives us a download option of the resulting data.frame -- as .csv, .xlsx and ...?

Also, if the function we turn into a shiny app, takes a data.frame as an input, how do we input in the shiny app? The first and easiest way I can think abou is that a table in .csv or .xlsx format can be uploaded and is read accordingly.

Output format

Even better, we want to decide whether the output is

  • a shinyApp object that can be started right away
  • written to an app.R file
  • written to a folder with server.R and ui.R.

For the last two options, which create a standalone app from a function, how would I transport the dependencies and environment of the function to the shinyApp?

  • Write the current environment to a file and load it? This is rather insecure
  • Give a list of dependencies (packages), which are loaded? But what about individual other functions or variables?

Maybe the general solution is to pass an environment as argument to as.shinyApp that is loaded before and some convenience wrappers: if, e.g. a character vector is passed it is interpreted as names of variables/functions that need to be imported from the current global environment.

I think this problem shows that of course such that package works the better the closer we stick to writing purely functional code.