Développement d’une application Shiny et déploiement sur SK8

AG CATI BARIC La Rochelle 2024

Amandine Velt

SVQV

Joseph Tran

EGFV

March 27, 2024

Pourquoi utiliser R Shiny ?

Comment communiquer autour de ses résultats R ?

Garrett Grolemund & Hadley Wickham

Comment communiquer autour de ses résultats R ?

En R simple, pour changer un paramètre, il faut modifier le code

```{r}
#| code-line-numbers: "|6"
#| output-location: column-fragment
x <- faithful$waiting
# number of bins = 10
nbins <- 10
hist(x, breaks = nbins, col = "#75AADB",
     border = "white",
     xlab = "Waiting time to next eruption (in mins)",
     main = "Histogram of waiting times")
```

Comment communiquer autour de ses résultats R ?

En R simple, pour changer un paramètre, il faut modifier le code

```{r}
#| code-line-numbers: "6"
#| output-location: column
x <- faithful$waiting
# number of bins = 50
nbins <- 50
hist(x, breaks = nbins, col = "#75AADB",
     border = "white",
     xlab = "Waiting time to next eruption (in mins)",
     main = "Histogram of waiting times")
```

On aimerait avoir un slider pour le modifier rapidement et sans avoir à modifier le code

Solution avec Shiny

Comment communiquer autour de ses résultats R ?

Shiny amène avec lui la réactivité

#| standalone: true
#| viewerHeight: 500
library(shiny)

# Define UI for app that draws a histogram ----
ui <- fluidPage(

  # App title ----
  titlePanel("Hello Shiny!"),

  # Sidebar layout with input and output definitions ----
  sidebarLayout(

    # Sidebar panel for inputs ----
    sidebarPanel(

      # Input: Slider for the number of bins ----
      sliderInput(inputId = "bins",
                  label = "Number of bins:",
                  min = 1,
                  max = 50,
                  value = 30)

    ),

    # Main panel for displaying outputs ----
    mainPanel(

      # Output: Histogram ----
      plotOutput(outputId = "distPlot")

    )
  )
)

# Define server logic required to draw a histogram ----
server <- function(input, output) {

  # Histogram of the Old Faithful Geyser Data ----
  # with requested number of bins
  # This expression that generates a histogram is wrapped in a call
  # to renderPlot to indicate that:
  #
  # 1. It is "reactive" and therefore should be automatically
  #    re-executed when inputs (input$bins) change
  # 2. Its output type is a plot
  output$distPlot <- renderPlot({

    x    <- faithful$waiting
    bins <- seq(min(x), max(x), length.out = input$bins + 1)

    hist(x, breaks = bins, col = "#75AADB", border = "white",
         xlab = "Waiting time to next eruption (in mins)",
         main = "Histogram of waiting times")

    })

}

# Create Shiny app ----
shinyApp(ui = ui, server = server)

Comment communiquer autour de ses résultats R ?

  • Niveau 1 : Partager son code brute
    • Pas de contexte ou commentaire
    • Peut être difficile à déchiffrer
    • Aucune gestion des dépendances
  • Niveau 2 : Utiliser un R Markdown
    • Rapport statique retraçant l’analyse
    • Pas de ré-exécution possible

Comment communiquer autour de ses résultats R ?

  • Niveau 3 : Mettre en place une application Shiny
    • Interface graphique permettant de ne pas confronter l’utilisateur au code
    • Paramètres modifiables et code ré-exécutable
    • Possibilité d’exporter des plots et rapports
    • L’utilisateur est responsable de l’installation de R et des packages

Comment communiquer autour de ses résultats R ?

  • Niveau 4 : Déployer l’application Shiny sur un serveur
    • L’application tourne sur un serveur dédié
    • L’utilisateur n’a plus à se préoccuper de l’installation de R et des packages

Communiquer autour de ses résultats R ?

Une documentation très complète

Une documentation très complète

Une documentation très complète

Fonctionnement d’une application Shiny

Structure d’une application Shiny

ui.R
```{r filename="ui.R"}
#| eval: false
#| code-line-numbers: "16-35"
# This is the user-interface definition of a Shiny web application. You change
# run the application by clicking 'Run App' above.
#
# Find out more about building applications with Shiny here :
#
#      http://shiny.rstudio.com/
#

library(shiny)
library(shinythemes)

# Define UI for application that draws a Histogram
ui <- fluidPage(theme=shinytheme("flatly"),

  # Application titlePanel
  titlePanel("Old Faithful Geyser Data"),

  # Sidebar with a slider input for number of bins
  sidebarLayout(
    sidebarPanel(
      sliderInput("bins",
                  "Number of bins:",
                  min = 1,
                  max = 50,
                  value = 30)
    ),
    # Show a plot of the generated distribution
    mainPanel(
      plotOutput("distPlot")
    )
  )
)
```

Structure d’une application Shiny

server.R
```{r filename="server.R"}
#| eval: false
#| code-line-numbers: "16-27"
#
# This is the server logic of a Shiny web application. You can run the
# application by clicking 'Run App' above.
#
# Find out more about building applications with Shiny here :
#
#      http://shiny.rstudio.com/
#

library(shiny)

# Define server logic required to draw a histogram
server <- function(input, output, session){

  output$distPlot <- renderPlot({

    # generate bins based on input$bins from ui.R
    x <- faithful[,2]
    bins <- seq(min(x), max(x), length.out = input$bins + 1)

    # draw the histogram with the specified number of bins
    hist(x, breaks = bins, col = 'darkgray', border = 'white')
  })
}
```

Structure d’une application Shiny

app.R
```{r filename="app.R"}
#| eval: false
#| code-line-numbers: "16-35"
# This is the user-interface definition of a Shiny web application. You change
# run the application by clicking 'Run App' above.
#
# Find out more about building applications with Shiny here :
#
#      http://shiny.rstudio.com/
#

library(shiny)
library(shinythemes)

# Define UI for application that draws a Histogram
ui <- fluidPage(theme=shinytheme("flatly"),

  # Application titlePanel
  titlePanel("Old Faithful Geyser Data"),

  # Sidebar with a slider input for number of bins
  sidebarLayout(
    sidebarPanel(
      sliderInput("bins",
                  "Number of bins:",
                  min = 1,
                  max = 50,
                  value = 30)
    ),
    # Show a plot of the generated distribution
    mainPanel(
      plotOutput("distPlot")
    )
  )
)
```
app.R
```{r filename="app.R"}
#| eval: false
#| code-line-numbers: "16-27"
#
# This is the server logic of a Shiny web application. You can run the
# application by clicking 'Run App' above.
#
# Find out more about building applications with Shiny here :
#
#      http://shiny.rstudio.com/
#

library(shiny)

# Define server logic required to draw a histogram
server <- function(input, output, session){

  output$distPlot <- renderPlot({

    # generate bins based on input$bins from ui.R
    x <- faithful[,2]
    bins <- seq(min(x), max(x), length.out = input$bins + 1)

    # draw the histogram with the specified number of bins
    hist(x, breaks = bins, col = 'darkgray', border = 'white')
  })
}
```

Fonctionnement d’une application Shiny

Shiny gallery

Fonctionnement d’une application Shiny

Shiny gallery

Fonctionnement d’une application Shiny

ui.R
```{r filename="ui.R"}
#| eval: false
#| code-line-numbers: "24-29,32"
# This is the user-interface definition of a Shiny web application. You change
# run the application by clicking 'Run App' above.
#
# Find out more about building applications with Shiny here :
#
#      http://shiny.rstudio.com/
#

library(shiny)
library(shinythemes)

# Define UI for application that draws a Histogram
ui <- fluidPage(theme=shinytheme("flatly"),

  # Application titlePanel
  titlePanel("Old Faithful Geyser Data"),

  # Sidebar with a slider input for number of bins
  sidebarLayout(
    sidebarPanel(
      sliderInput("bins",
                  "Number of bins:",
                  min = 1,
                  max = 50,
                  value = 30)
    ),
    # Show a plot of the generated distribution
    mainPanel(
      plotOutput("distPlot")
    )
  )
)
```
server.R
```{r filename="server.R"}
#| eval: false
#| code-line-numbers: "18-26"
#
# This is the server logic of a Shiny web application. You can run the
# application by clicking 'Run App' above.
#
# Find out more about building applications with Shiny here :
#
#      http://shiny.rstudio.com/
#

library(shiny)

# Define server logic required to draw a histogram
server <- function(input, output, session){

  output$distPlot <- renderPlot({

    # generate bins based on input$bins from ui.R
    x <- faithful[,2]
    bins <- seq(min(x), max(x), length.out = input$bins + 1)

    # draw the histogram with the specified number of bins
    hist(x, breaks = bins, col = 'darkgray', border = 'white')
  })
}
```

Les différents types d’inputs

Widgets d’inputs

Les différents types d’outputs

Rendering functions

Structure du dossier d’une application Shiny

Côté UI : Focus sur les layouts

Les layouts

  • Le framework Bootstrap qu’utilise Shiny définit une page comme une grille :
    • Une page (fluidPage()) est divisée en colonnes (column()) et en ligne (fluidRow())
    • La hauteur d’une ligne est celle de son plus grand élément
    • La page est de taille 12 : une colonne de largeur (width) 6 occupera donc la moitié de l’espace horizontal

Les layouts

#| echo: fenced
#| code-line-numbers: "14|16|17|48"
#| output-location: column
library(ggvis)

# For dropdown menu
actionLink <- function(inputId, ...) {
  tags$a(href='javascript:void',
         id=inputId,
         class='action-button',
         ...)
}

fluidPage(
  titlePanel("Movie explorer"),
  fluidRow(
    column(3,
      wellPanel(
        h4("Filter"),
        sliderInput("reviews", "Minimum number of reviews on Rotten Tomatoes",
          10, 300, 80, step = 10),
        sliderInput("year", "Year released", 1940, 2014, value = c(1970, 2014),
          sep = ""),
        sliderInput("oscars", "Minimum number of Oscar wins (all categories)",
          0, 4, 0, step = 1),
        sliderInput("boxoffice", "Dollars at Box Office (millions)",
          0, 800, c(0, 800), step = 1),
        selectInput("genre", "Genre (a movie can have multiple genres)",
          c("All", "Action", "Adventure", "Animation", "Biography", "Comedy",
            "Crime", "Documentary", "Drama", "Family", "Fantasy", "History",
            "Horror", "Music", "Musical", "Mystery", "Romance", "Sci-Fi",
            "Short", "Sport", "Thriller", "War", "Western")
        ),
        textInput("director", "Director name contains (e.g., Miyazaki)"),
        textInput("cast", "Cast names contains (e.g. Tom Hanks)")
      ),
      wellPanel(
        selectInput("xvar", "X-axis variable", axis_vars, selected = "Meter"),
        selectInput("yvar", "Y-axis variable", axis_vars, selected = "Reviews"),
        tags$small(paste0(
          "Note: The Tomato Meter is the proportion of positive reviews",
          " (as judged by the Rotten Tomatoes staff), and the Numeric rating is",
          " a normalized 1-10 score of those reviews which have star ratings",
          " (for example, 3 out of 4 stars)."
        ))
      )
    ),
    column(9,
      ggvisOutput("plot1"),
      wellPanel(
        span("Number of movies selected:",
          textOutput("n_movies")
        )
      )
    )
  )
)

Les layouts prédéfinis

Les layouts prédéfinis

Les layouts en onglets

Shiny Dashboard

Focus sur Shiny et la réactivité

La réactivité des applications Shiny

La réactivité des applications Shiny

La réactivité des applications Shiny

La réactivité des applications Shiny

La réactivité des applications Shiny

La réactivité des applications Shiny

La réactivité des applications Shiny

Exemples d’utilisations à INRAE

Exemples d’appli

Les solutions de partage d’une application Shiny

Partager son application Shiny

Déploiement local

Partage du code avec l’utilisateur

  • via un package R que l’utilisateur installe en local
  • via un dépôt GitHub (shiny::runGitHub et shiny::runURL)

Inconvénient

Nécessite d’installer R/Rstudio et de gérer l’installation des dépendances

Partager son application Shiny

Application shinylive

R Shiny Live demo in Quarto!

#| standalone: true
#| viewerHeight: 500
library(shiny)
library(bslib)

# Define UI for app that draws a histogram ----
ui <- page_sidebar(
  sidebar = sidebar(open = "open",
    numericInput("n", "Sample count", 100),
    checkboxInput("pause", "Pause", FALSE),
  ),
  plotOutput("plot", height=600, width=700)
)

server <- function(input, output, session) {
  data <- reactive({
    input$resample
    if (!isTRUE(input$pause)) {
      invalidateLater(1000)
    }
    rnorm(input$n)
  })

  output$plot <- renderPlot({
    hist(data(),
      breaks = 40,
      xlim = c(-2, 2),
      ylim = c(0, 1),
      lty = "blank",
      xlab = "value",
      freq = FALSE,
      main = ""
    )

    x <- seq(from = -2, to = 2, length.out = 500)
    y <- dnorm(x)
    lines(x, y, lwd=1.5)

    lwd <- 5
    abline(v=0, col="red", lwd=lwd, lty=2)
    abline(v=mean(data()), col="blue", lwd=lwd, lty=1)

    legend("topright", legend = c("Normal", "Mean", "Sample mean"),
      col = c("black", "red", "blue"),
      lty = c(1, 2, 1),
      lwd = c(1, lwd, lwd),
      cex = 0.6
    )
  }, res=140)
}

# Create Shiny app ----
shinyApp(ui = ui, server = server)

Partager son application Shiny

Application shinylive

YouTube video: guide pas à pas pour créer une application Shiny sans serveur

Creating a Serverless Shiny App using Quarto with R Shinylive

Partager son application Shiny

shinyapps.io

Shinyapps.io

  • L’application est hébergée sur les serveurs de RStudio.
    • formule gratuite : 5 applications Shiny avec un usage total cumulé de 25h/mois

    • 13$/mois → 25 applications et 100 heures actives

  • Déploiement en 1 clic
  • Dashboard de suivi convivial

Inconvénient

  • Dépendance à RStudio
  • Freemium
  • Taille de l’appli limité à 1Go (données externes comprises)

Partager son application Shiny

Binder: read the doc

Projet communautaire et ouvert qui a permis de créer des environnements reproductibles, partageables et interactifs, tel que BinderHub, que vous pouvez tester sur mybinder.org.

Pour déployer une application Shiny sur Binder, repo2docker a besoin de 2 choses:
- un code source sur un dépôt Git (github, gitlab, etc.)
- des fichiers de configuration pour l’environnement, pour R par exemple :
- install.R: installer les packages R nécessaires
- runtime.txt: spécifier la version de R, et la date du snapshot

Lien utile pour apprendre à déployer son code avec Binder

Turing Way maintient également un tutoriel Zero-to-Binder pour les 3 langages de programmation commun (Python, Julia et R).

Partager son application Shiny

Hugging Face

Hugging Face Spaces

Inconvénient

Each Spaces environment is limited to 16GB RAM, 2 CPU cores and 50GB of (not persistent) disk space by default, which you can use free of charge. Can upgrade to a paid plan for more resources.

Partager son application Shiny

Shiny Server

version free

  • un processus R / application qui peut servir plusieurs utilisateurs
  • Limite : quand beaucoup d’utilisateurs, ils se bloquent les uns les autres.

version payante

  • plusieurs processus R / application.
  • Des utilisateurs concurrents vont être partagés entre plusieurs processus.
  • On peut paramétrer le nombre d’utilisateurs / process et le nombre de process est illimité (selon capacité du serveur)
  • Inconvénient : version pro très chère → 10000 €/ an

Partager son application Shiny

Shinyproxy

Partager son application Shiny

Déploiement avec SK8 (version kickflip, 2023)

Projet porté par Jean-François Rey et Elise Maigné puis porté par le CATI IMOTEP et passage en Inter-CATIs (2022).

Partager son application Shiny

Déploiement avec SK8 (version kickflip, 2023)

Projet portés par Jean-François Rey et Elise Maigné puis porté par le CATI IMOTEP et passage en Inter-CATIs (2022).

Partager son application Shiny

Déploiement avec SK8 (version kickflip, 2023)

Infrastructure fonctionnelle, 60+ applications hébergées

Partager son application Shiny

Déploiement avec SK8 (version kickflip, 2023)

Quelques exemples @INRAE

CiTIQUE-TRACKER

Partager son application Shiny

Déploiement avec SK8 (version kickflip, 2023)

Quelques exemples @INRAE

loup-ecrins-genetique.sk8.inrae.fr

Partager son application Shiny

Déploiement avec SK8 (version kickflip, 2023)

Quelques exemples @INRAE

ShinyIDEA

Partager son application Shiny

Déploiement avec SK8 (version kickflip, 2023)

Plus d’information sur le site web https://sk8.inrae.fr

Processus d’hébergement d’une application shiny sur SK8

Take Home Message

R Shiny

  • R Shiny permet de rendre un script R interactif, facilement

  • Possibilité d’utiliser des packages R d’analyse et de faire tourner une application web avec

  • R Shiny est la solution idéale pour partager des résultats R qui peuvent être explorés

  • Plusieurs solutions de déploiement existent et fonctionnent bien, selon les besoins

Take Home Message

R Shiny warnings

  • Nécessité de prendre du temps pour optimiser son code. Notamment, il faut optimiser ce que R charge en mémoire, car une application Shiny peut rapidement saturer la RAM d’une VM

  • Nécessité de pré-calculer au maximum ce qu’on veut représenter (car R peut être lent)

Sources : Références

Shiny gallery

Gallery widget

Show me Shiny

CheatSheet

CheatSheet VF

Sources : Tuto

Tuto officiel

École Thématique GeoViz

Introduction à Shiny

Formation IFB

Organisation de l’UI

Atelier Shiny

Learnr tutoriel shiny