rm(list = ls())
library(datasets)
library(data.table)
library(ggplot2)

runWithoutInstall <- T
ifelse(runWithoutInstall,
       sapply(list.files(path = "../R/", pattern="*R", full.names = T), source),
       library(shinypipe))

data(mtcars)
rv <- reactiveValues(table=as.data.table(mtcars))
rm(mtcars)

Vignette to illustrate elements of R Shiny modules packaged in https://github.com/rajkar86/shinypipe. Click on 'Show All Code' at the top right to display code.

File upload 1

fread wrapper to get a data.table from a data file.

ui.fread("file1")
r.data1 <- callModule(s.fread, "file1")
renderTable(head(r.data1()))

Note that the values of sep and header selected by default can be overidden.

File upload 2

The ability to select the separator can be taken away from the user (by setting sep = NULL). In this case, sep must be directly specified in the server function. The same is true for the header argument.

ui.fread("file2", sep = NULL)
r.data2 <- callModule(s.fread, "file2", params = list(sep = ","))
renderTable(head(r.data2()))

Table used in the rest of the vignette

The sample cars table from the datasets package is used for illustration, unless a file was uploaded in one of the widgets above, in which case the table from the latest uploaded file will be used. A few rows from the table are shown below:

r.data <- reactive(as.data.table(rv$table))
observe(rv$table <- r.data1())
observe(rv$table <- r.data2())
renderTable(head(r.data()))

Simple Formula Editor

Formulas can be dynamically constructed, for instance, using column names of the tables. The user can be restricted to selecting only one explanatory variable by setting the parameter simpleFormula to TRUE. This can be useful for plots. The selected formula is printed below.

renderUI({
  colsY <- list(choices = names(r.data())[1:3])
  colsX <- list(choices = names(r.data())[-(1:3)])
  ui.formula("form", colsY, colsX, simpleFormula = T, theme = "small")
})
r.form <- callModule(s.formula, "form")
renderPrint(r.form())

Plot module

Sample usage of simple formula, and an illustration of plot module, which can be used to provide zoom/selection behavior and click location display on top of any ggplot within a shiny document.

r.yVal <- callModule(s.formula.y, "form")
r.xVal <- callModule(s.formula.x, "form")

ui.plot("plot")
r.plot <- reactive(geom_point(aes_string(x=r.xVal(), y=r.yVal())))
r.brushedData <- callModule(s.plot, "plot", r.plot, r.data, selected.colname = "selected")

Selected Data

Click and drag in the plot to select data. The table below shows the first few rows from the table of data selected from the above plot. Note that in this example the selected column name is "selected". However, if selected.colname is not specified in ui.plot, the data returned will only be the selected data, and there's no need to filter subsequently based on the selected.colname.

renderDataTable(head(r.brushedData()[selected==T]))

Formula editor: example 1

The default behavior of the formula interface is to allow selecting multiple explanatory variables. And the user can be given control over whether to use intercept by setting a default selection for the intercept argument.

renderUI({
  colsY <- list(choices = names(r.data()), selected = "mpg")
  colsX <- list(choices = names(r.data()), selected = "wt")
  ui.formula("fml", colsY, colsX, intercept = T)
})

Output formula

r.fml <- callModule(s.formula, "fml")
r.fml.y <- callModule(s.formula.y, "fml")
renderPrint(r.fml())

The choice of whether to include intercept or not can be hidden from the user by leaving the intercept to its default value of NULL similar to the "Simple Formula Editor" example.

Linear regression (Full table)

Sample usage of formula.

renderPrint(summary(lm(r.fml(), r.data())))

Linear regression (Selected)

Using the formula only on the selected dataset, which is returned as an output of the plot module. Select a portion of the dataset from the plot above to run linear regression only on the selected portion of the dataset.

renderPrint({
  dt <- r.brushedData()[selected==T]
  if (dt[,.N] == 0)
    return("Brush the points on the graph above to select portion of the dataset")
  summary(lm(r.fml(), dt))
})

Using params: SVM example

Encapsulate UI interface for function parameters without worrying about the widgets to use. Widgets are automatically selected based on type inference; in most cases, users only need to specify a default value and (optionally) a range of allowed values.

The selected parameter values are returned in a list, that can be directly used to call a function through do.call. This is a convenient way to group parameters applicable to a specific function into a list.

Sample use case: Running SVM. Note: not all parameters are applicable for all kernels.

library(e1071)
ui.params("params",
          kernel  = list("linear", c("linear", "polynomial", "radial", "sigmoid")),
          cost    = list(1),
          degree  = list(3, c(2,5)),
          gamma   = list(1, c(0,NA)),
          coef0   = list(0, c(0,1), step = .01))

r.svmParams <- callModule(s.params, "params")

r.svmModel <- reactive(do.call(svm, c(list(formula = r.fml(), data = r.data()), r.svmParams())))

renderPrint({f <- r.svmModel(); f$call <- NULL; return(summary(f));})

RMS error

renderPrint({
  req(r.svmModel())
  req(r.fml.y())
  sqrt(mean((predict(r.svmModel()) - r.data()[,r.fml.y(), with=F])^2))
})

Using params: Example 2

Just a simple example to illustrate other types of data inputs.

ui.params("paramList",
          name  = list("", NA, placeholder = "Enter your name here", width = '100%'),
          dob   = list(Sys.Date()-1, c(NA, Sys.Date()), label = "Date of birth"))
r.paramList <- callModule(s.params, "paramList")

f.age <- function(name, dob) {
  age <- (Sys.Date() - dob)
  if (is.null(name) || name == "") return ("Enter your name above.");
  if (age <= 0) return ("Enter a date in the past");
  return (paste0("You're ", age, " day(s) old, ", name, "."))
} 

renderPrint(do.call(f.age, r.paramList()))

Vector Input

Create vectors by using expressions like:

ui.vector("vec1")
r.vec1 <- callModule(s.vector, "vec1")
renderPrint(r.vec1())

Logical vector

ui.vector("vec2", "logical")
r.vec2 <- callModule(s.vector, "vec2")
renderPrint(r.vec2())

Caret Models

This module makes it easier to create an interface for any of regression or classification models supported by the R caret package. svmRadial is used as an example here. But the module can be used with any caret supported model by passing the corresponding parameter table provided by caret::getModelInfo. See the caret vignette to see an example to explore the 250+ different models supported by the caret package.

svmRadial

Using svm with radial kernel as an example to illustrate.

For e.g., entering "1:2" for sigma and "2^(-1:1)" for Cost will create a tuneGrid of 10 possible combinations that can be used with caret::train.

library(caret)
library(kernlab)

renderUI(ui.caretModel("model1", reactive(c("svmRadial"))))
r.model1Params <- callModule(s.caretModel, "model1")

renderPrint(r.model1Params())

Using expand.grid on the params$value part of the output to get the tune grid for training using caret.

r.tuneGrid <- reactive(expand.grid(r.model1Params()$params))
renderPrint(r.tuneGrid())

Running train using the tuneGrid created above by clicking "Run".

actionButton("run", "Run")
r.train <- reactive({
  input$run
  grid <- isolate(r.tuneGrid())
  if (is.null(grid) || nrow(grid) == 0)
    return (NULL)
  train(r.fml(), r.data(), method = "svmRadial", tuneGrid = grid)
})

renderPrint(r.train())

Debugging within shiny app

ui.flexOutput("flex", T)
invisible(callModule(s.flexOutput, "flex", environment(), "ls()"))


rajkar86/shinypipe documentation built on Aug. 22, 2021, 9:48 p.m.