Shiny Avanzado

Joshua Kunst Fuentes @jbkunst

Bienvenidos!

Antes de Partir

Lo que veremos

Reactividad:

Expresiones reactivas, Observers y Eventos.

Módulos:

Definición, utilidades, patrón de uso.

HTMLWidgets:

Proxies y eventos.

HTML, CSS, JS:

Introduccion, definiciones, etc.

Como lo veremos

  • Definiciones y motivaciones.
  • Revisión de ejemplos.
  • Ejercicios!

Que paquetes utilizaremos

install.packages(
  c("shiny", 
    "tidyverse", 
    "rvest",
    "leaflet",
    "leaflet.minicharts",
    "DT",
    "highcharter",
    "plotly",
    "datos")
  )

Setup de PositCloud (ex Rstudio Cloud)

Revisemos antres nuestro proyecto

Reactividad

Reactividad

En una aplicación shiny, la lógica del server se expresa en programación reactiva.

No tenemos que darle un comando a una aplicación shiny para que se actualice. Reacionará por sí solo.

Si un input cambia, automáticamente actualizará output(s) (expresiones reactivas u observers) que dependan de dicho input(s).

Tipos de elementos

De manera conceptual una expresion reactiva es una expresión que cambiará en el tiempo.

  • reactive crea una expresión reactiva, la cual cambia si una de los elementos reactivos que depende cambia.

  • eventReactive igual que el anterior pero se gatilla por el cambio de una variable reactiva.

  • observe Crear una expresión reactiva que se ejecuta cuando una variable de la cual depende cambia.

  • observeEvent ídem al anterior pero se gatilla por el una expresión reactiva.

Similitudes y Diferencias entre reactivos y observers.

Similitudes: Se gatillan por el cambio de alguna variable o expresión reactiva.

Diferencias: Expresiones reactivas retornan valores, los observers no lo hacen.

Patrón de uso

server <- function(input, output) {
  
  variable_reactiva <- reactive({ 
    # calcular y rentornar algo, como una función.
    ... 
  })

  variable_reactiva <- reactiveEvent(expresion_reactiva, {
    # calcular y rentornar algo, si cambia `expresion_reactiva`.
    ... 
  })
  
  observe({ 
    # hacer algo si cambia algo que depende esta expresión.
    ... 
  })
  
  observeEvent(expresion_reactiva, { 
    # hacer algo si cambia `expresion_reactiva`.
    ... 
  }) 
  
}

Shiny 1.6.0

Se agrega una función bindEvent el cual convierte reactives y observers en su versión Event:

server <- function(input, output) {
  
  # Equivalentes!
  var_react <- eventReactive(input$boton, { ... })
  var_react <- reactive({ ... }) |> bindEvent(input$boton)

  # Lo mismo!
  observeEvent(input$boton, { ... })
  observe({ ... }) |> bindEvent(input$boton)
}

Resumen: tarea/función

  • Calcular valores: reactive / eventReactive
  • Ejecutar tareas: observe / observeEvent
  • Almacenar valores: reactiveVal / input / reactiveValues
  • Prevenir reactivdad: isolate
  • Chequear condiciones: req
  • Reejecutar tareas cada cierto tiempo: invalidateLater

Revisar las siguientes apps

  • apps/reactividad/01-app-reactividad-basica.R
  • apps/reactividad/02-app-reactive.R
  • apps/reactividad/03-app-eventReactive.R
  • apps/reactividad/04-app-observe.R
  • apps/reactividad/04-app-observeEvent.R

Ejercicio: Paquete reactlog

El paquete reactlog pertmite registrar las acciones de una aplicación para conocer el flujo de la reactividad.

  1. Revise y ejecute el script R/01-reactlog-example.R. Comente.

Módulos

Módulos

  • Un módulo es un componente autocontenido y compuesto de una aplicación Shiny.
    • Autocontenido como una función.
    • Se pueden combinar para hacer una aplicación.
  • Tienen su propia interfaz de usuario y servidor (además de la interfaz de usuario y servidor de la aplicación).
  • Útil para la reutilización.
    • En lugar de copiar y pegar código, puede usar módulos. Incorporar en paquetes.
    • Esencial para administrar la complejidad del código en aplicaciones más grandes.

Patrón de uso en UI: Antes

ui <- fluidPage(
  fluidRow(
    column(2, sliderInput("nrand", ...)),
    column(2, selectInput("dist", ...))),
    column(8, plotOutput("plot"))
  )
)

Patrón de uso en UI: Ahora

moduloUI <- function(id) {

  ns <- NS(id)
  
  tagList(
    column(2, sliderInput(ns("rand"), ...)),
    column(2, selectInput(ns("dist"), ...))),
    column(8, plotOutput(ns("plot")))
  )
  
}

ui <- fluidPage(
  fluidRow(
    moduloUI("idmod")
    )
)

Patrón de uso en Server: Antes

server <- function(input, output, session) {
  
      output$plot <- renderPlot({
        
        rdist <- switch(input$dist, "norm" = rnorm, "exp"  = rexp)
        hist(rdist(input$rand), xlim = c(-5, 5))
        
      })

}

Patrón de uso en Server: Ahora

moduloServidor <- function(id) {
  moduleServer(id, function(input, output, session) {
      
      output$plot <- renderPlot({
        
        rdist <- switch(input$dist, "norm" = rnorm, "exp"  = rexp)
        hist(rdist(input$rand), xlim = c(-5, 5))
        
      })
      
  })
}

server <- function(input, output, session) {
  
  moduloServidor("idmod")
  
})

Patrón de uso

Al cambiar a este flujo/framework de programación de aplicaciones shiny:


Módulo UI: El cambio en ids es explícito. Cambiar unInput("id") por unInput(NS("id")). Se puede separar para tener distintas ubicaciones (ver ejemplos).


Modulo Server: La funcionalidad es implícita, uno copia y pega, y el módulo hace el intercambio correspondiente, moduleServerse encarga de todo.

Beneficio?

source("ruta/hacia/modulo.R")

ui <- fluidPage(
  fluidRow(
    moduloUI("modulo1"),
    moduloUI("modulo2"),
    ...
    )
)

server <- function(input, output, session) {
  moduloServidor("modulo1")
  moduloServidor("modulo2")
  ...
})

Revisar las siguientes apps

- apps/modulos/01-app-modulos.R
- apps/modulos/02-app-modulos.R
- apps/modulos/03-app-modulos.R
- apps/modulos/04-app-modulos.R
- apps/modulos/05-app-modulos.R
- apps/modulos/06-app-modulos.R
- apps/modulos/07-app-modulos.R

Ejercicio: Creando App, luego un módulo

  1. Considerando el data set iris, genere una aplicación que tenga un selector que liste las variables continuas y dado una variable realice un histograma.

  2. Ahora transfórmelo en módulo y agregue tres instancias de dicho módulo con diferentes tablas (mtcars, diamonds, mtautos, diamantes).

  3. Extienda el módulo para incluir un output que muestre el summary de la variable seleccionada.

  4. Ideas? Preguntas?

HTMLWidgets

HTMLWidgets

Usar librerías de visualización Javascript en R.

Los widgets se pueden incluir en documentos RMarkdown y aplicaciones web Shiny.

HTMLwidgets puden ser una parte fundamental de una aplicación dado que muestran visualizaciones.

HTMLWidgets, eso es todo?

No!


Los widget pueden utilizarse como inputs a través de eventos Javascript!

Funcionan si se integran a la aplicación.

Revisar las siguientes apps

  • apps/htmlwidgets/01-app-htmlwidgets.R
  • apps/htmlwidgets/02-app-htmlwidgets-loaders.R
  • apps/htmlwidgets/03-app-htmlwidgets-proxies.R
  • apps/htmlwidgets/04-app-htmlwidgets-events.R

Ejercicio: Haciendo más con los eventos

  1. Reutilice alguna app de la carpeta htmlwidgets para que al hacer click sobre un sismo, se escriban todos la información del sismo en la ui.

  2. Cree una app que genere un scatter plot de acuerdo a 2 inputs para indicar variable x, variable y. Utilice un proxy para no rebibujar el gráfico.

  3. Para la aplicación anterior, conviértala en módulo.

  4. Ideas? Preguntas?

HTML, CSS, JS

HTML, CSS, JS

HTML, CSS y JS son tres elementos (lenguajes?!) que conforman una aplicación web.

HTML (HyperText Markup Language) permite estructurar la informacion. https://www.w3schools.com/html/html_examples.asp

CSS (Cascading Style Sheets) para darle estilo a la informacion. https://www.w3schools.com/css/css_examples.asp

JS (Javascript) para hacer interactividad con esa informacion. https://www.w3schools.com/js/js_examples.asp


Aplicaciones shiny lo abstrae y hace funcionar todo mágicamente.

HTML en Shiny

ui <- fluidPage(
  actionButton("boton", "Clickéame")
)

ui


<div class="container-fluid">
  <button id="boton" type="button" class="btn btn-default action-button">Clickéame</button>
</div>

HTML usando tags

ui2 <- tags$div(class = "container-fluid",
  tags$button("Clickéame", id="boton", type="button", class="btn btn-default action-button")
  )

ui2


<div class="container-fluid">
  <button id="boton" type="button" class="btn btn-default action-button">Clickéame</button>
</div>

HTML en bruto

ui3 <- HTML('<div class="container-fluid">
  <button id="boton" type="button" class="btn btn-default action-button">Clickéame</button>
</div>')

ui3


<div class="container-fluid">
  <button id="boton" type="button" class="btn btn-default action-button">Clickéame</button>
</div>

Ejercicio: HTML

Comprobar si ui, ui2, y ui3 son iguales o similares.


Ejercicio: Implementando cosas

  1. Revise este link y en la primera app de htmlwidgets realice lo necesario para implementar https://www.jumpingrivers.com/blog/improving-responsiveness-shiny-applications/. Implemente de diferentes formas dicha feature.

Eso! gracias! un gustazo!

Créditos imágenes

Foto de Stephen Dawson en Unsplash

Foto de Guillaume Bolduc en Unsplash

Foto de Valery Sysoev en Unsplash

Foto de Nick Fewings en Unsplash

Foto de Patrick Perkins en Unsplash