Formation-R-perfectionnement

Module Initiation à l’écriture d’applications Shiny

SSP/DEMESIS

26/03/2026

0.1 Avant-propos


Ce diaporama de formation a été rédigé dans le but d’être le support visuel des formations dispensées au SSM AgricultureA.

Ces formations s’adressent à des agents qui ont suivi la formation R perfectionnement - module rappels.

0.2 Avant-propos

Champ couvert par cette formation

Ce support couvre l’initation à l’écriture d’application Shiny dans l’environnement du Minsitère.

Pour information, ce module de la formation R-perfectionnement se décompose en :

  1. Introduction

  2. Créer une interface

  3. Partie interface graphique

  4. Partie serveur

  5. Réactivité

  6. Le programme complet

  7. Pour aller plus loin

Ce module est orienté pour être utile aux agents du SSM Agriculture et se concentre sur une utilisation de R via RStudio qui est mise à disposition des agents sur la plateforme interne Cerise basée sur RStudio Workbench.

1 Introduction

1.1 Introduction

Pourquoi créer une interface graphique ?

⇒ Cela permet de pouvoir lancer un programme, modifier des paramètres, visualiser des résultats, sans avoir à manipuler de code

On utilise le package Shiny. Ce package permet :

  • de séparer la partie interface de la partie traitement

  • de créer des interfaces web très variées et personnalisables

  • de déployer des applications web

Une application Shiny a vocation à être mise sous Gitlab et comporter 3 environnements (branches) :

  • Développement,

  • Recette,

  • Production

2 Créer une interface

2.1 Créer une interface

La création d’une application Shiny se fait en 2 étapes.

  1. Interface graphique : créer et agencer les différents éléments (boutons, champs de saisie, affichage de graphiques ou tableaux, …)

  2. Serveur : récupérer les paramètres saisies dans l’interface, écrire les traitements R, et afficher les résultats

2.2 Créer une interface

  • Les utilisateurs manipulent l’interface, le serveur actualise l’affichage des résultats sur l’interface via du code R.

3 Partie interface graphique

3.1 Partie interface graphique

  • On créer un objet ui, auquel on affecte une « page »

ui <- fluidPage(….)

Il existe plusieurs manières de créer une page, suivant comment on veut la présenter : fluidPage, fixedPage, bootstrapPage, pageWithSidebar, …

  • On prend ici l’exemple d’une fluidPage.

  • En paramètre de la page, on indique les éléments qu’elle va contenir.

3.2 Partie interface graphique


Une page peut être découpée en « lignes » :

ui <- fluidPage(

fluidRow(),

fluidRow()

)

3.3 Partie interface graphique


Chaque ligne peut être découpée en « colonnes » :

ui <-fluidPage(

  fluidRow(

    column(),

    column() 
  )

)

3.4 Partie interface graphique


  • L’interface utilisateur (ui.R) est la vitrine de l’application. C’est une fenêtre dans laquelle l’utilisateur va « saisir » des informations : les inputs. Les valeurs des inputs sont définies par manipulation de widgets.

  • Les résultats (outputs) produits par l’application sont généralement affichés dans cette interface.

  • L’interface est une page Web « composée » par shiny.

  • Elle peut prendre plusieurs formes : la mise en page (layout). L’une des plus classiques est la sidebarLayout.

3.5 Partie interface graphique

Pour permettre à l’utilisateur de saisir des données en entrée, on utilise des widgets. Les plus courants sont :

  • selectInput : liste déroulante

  • radioButtons : boutons radio

  • checkboxInput : case à cocher

  • sliderInput : bouton à déplacer sur une barre

  • numericInput : zone de saisie pour une variable numérique

  • textInput : zone de saisie pour une variable texte

  • actionButton : bouton pour effectuer une action

  • fileInput : bouton pour sélectionner un fichier

3.6 Partie interface graphique

Voir http://shiny.rstudio.com/gallery/widget-gallery.html

Voir aussi le package {shinyWidgets}

3.7 Partie interface graphique

Les widgets sont en fait des fonctions qui attendent plusieurs arguments. Les 2 premiers sont :

  • le nom du widget (inputId)

  • le label, c’est à dire le texte qui guidera l’utilisateur dans ses choix.

Exemple :

selectInput(inputId="select1",

  label="Veuillez faire un choix dans la liste",

  choices = c("choix 1" = 1, "choix 2" = 2, "choix 3" = 3)

)

3.8 Partie interface graphique


Chaque colonne contiendra des éléments :

  • Des inputs (actionButton, selectInput, textInput, fileInput, … )

  • Des outputs (tableOutput, plotOutput, downloadButton, …)

On indique en premier paramètre de la colonne la taille de celle-ci, sachant que la taille totale d’une ligne (somme des colonnes) est de 12.

Note

Shiny utilise la grille de Bootstrap qui divise la largeur de la page en 12 colonnes. Quand vous utilisez column(width = 6, …), vous dites en fait à Bootstrap d’occuper la moitié de l’écran.

3.9 Partie interface graphique

ui <-fluidPage(
  
  fluidRow(
    
    column(8,
           
           selectInput()
           
    ),
    
    column(4,
           
           tableOutput()
           
    )
    
  )
  
)

3.10 Partie interface graphique


Les différents objets finaux (input ou output) ont tous des paramètres différents, mais le premier est toujours le même, inputId pour les inputs, et outputId pour les output.

→ C’est cet identifiant qui permettra de faire le lien entre l’interface graphique et la partie serveur : la partie traitement (le serveur) peut ainsi récupérer les valeurs saisies dans les inputs et d’afficher les résultats dans les outputs.

Attention

Comme on va rapidement imbriquer beaucoup de couches d’éléments, il est très important de bien aérer et indenter son code.

4 Interface graphique pour interface graphique

4.1 Interface graphique pour interface graphique


  • Le package {shinyuieditor} permet de construire l’UI sans avoir à coder https://rstudio.github.io/shinyuieditor/ (version préliminaire)

  • Voir aussi le package {flexdashboard} pour construire des tableaux de bord avec du Rmarkdown https://rstudio.github.io/flexdashboard/articles/shiny.html

4.2 Exercice UI (1/3)

Exercice - partie Interface (ui)

Le but de cet exercice est de créer une interface pour afficher des statistiques simples sur des données.

Partie 1 – Interface

  1. Ouvrez la table BC.rds.

Récupérer dans un vecteur la liste des régions.

  1. On va maintenant initialiser une page vide. Il nous faut 3 objets :

    • un objet ui, en affectant une fluidPage() vide
    • la fonction server(vide aussi)
    • la commande shinyApp(ui, server)

Exécutez le programme.

(suite sur la prochaine slide…)

4.3 Exercice UI (2/3)

Exercice - partie Interface (ui)

  1. Créez une liste déroulante à l’aide de selectInput. Renseignez les paramètres inputId (identifiant), label (texte affiché), et choices (avec la liste des régions créée précédemment).

Créez un tableOutput.

Exécutez le programme.

  1. De la même manière, créez sous la liste déroulante une autre liste, contenant les items « Population », « Altitude », et « Superficie ». Puis encore en-dessous un bouton avec la fonction actionButton.

Exécutez le programme.

4.4 Exercice UI (3/3)

5 Partie serveur

5.1 Partie serveur

On crée une fonction server, qui a au moins 2 paramètres :

server <- function(input, output) { ... }


Dans le corps de la fonction, on peut placer du code R traditionnel.

Le fichier server.R contient les instructions nécessaires pour construire l’application et afficher les résultats dans l’interface.

Plus précisément, il contient le code R à exécuter pour effectuer tous les traitements nécessaires à l’application :

  • Chargement de données ;

  • Calculs ; sélection, extraction, … ;

  • Traçage de graphique, affichage de tableau ;

5.2 Partie serveur


Il y a 2 particularités principales liée à Shiny dans le code du serveur :

  • Les références aux inputs/outputs : récupérer une valeur saisie, afficher tel tableau à l’écran, …

  • Les éléments dits « réactifs » : on peut déclencher un traitement particulier sur une action de l’utilisateur

5.3 Partie serveur


Pour récupérer une valeur saisie par l’utilisateur, par exemple un champ de texte, on utilise le paramètre input, avec l’identifiant du champ de saisie (inputId)

  • partie ui :

    textInput(inputId="champ_saisie", label= "Saisir :")

  • partie server :

    ma_chaine <- input$champ_saisie

5.4 Partie serveur


Pour placer un tableau ou un graphique dans l’interface, on affecte à l’output la table concernée, en lui appliquant une fonction appelée « render »

  • partie ui :

    tableOutput(outputId="resultat")

  • partie server :

    output$resultat <- renderTable({ data })

Il existe des fonction render pour chaque type d’output (renderTable, renderPlot, renderText, renderImage, …).

Dans le paramètre de la fonction, dans les accolades, on peut mettre simplement un objet R, ou un bloc de code :

renderTable({ head(data, n=10 })

5.5 Partie serveur

De la même façon que nous insérons des données dans l’application via les widget, il faut s’occuper d’afficher à l’écran les résultats des traitements.

On utilise pour cela les fonctions render* :

  • renderPlot ;

  • renderImage ;

  • renderTable, ...

5.6 Partie serveur

5.7 Partie serveur

Les fonctions render* coté server et *Output coté ui vont de pair :

ui.R server.R
imageOutput renderImage
plotOutput renderPlot
tableOutput renderTable
DTOutput renderDT
textOutput renderText
uiOutput renderUI
verbatimTextOutput renderPrint

6 Exemples

6.1 Exemple : pas à pas

6.2 Exemple : pas à pas

6.3 Exemple : pas à pas

6.4 Exemple : pas à pas

6.5 Exemple : pas à pas

6.6 Exemple : pas à pas

6.7 Exemple : pas à pas

L’objet input$num sera automatiquement modifié :

6.8 Exemple : pas à pas

6.9 Exemple : pas à pas

6.10 Exemple : pas à pas

7 Réactivité

7.1 Réactivité


Avec Shiny, on peut déclencher des traitements en fonction des actions de l’utilisateur.

« La réactivité d’une application, c’est sa capacité à mettre à jour ses éléments suite à l’action d’un utilisateur. »


On utilise des « observers » :

  • observe → déclenche un traitement quelle que soit l’action

  • observeEvent → déclenche un traitement quand l’utilisateur modifie un input précis

7.2 Réactivité

  • Partie UI :
selectInput(inputId="ma_liste",

label="Choisissez un pays",

choices=c("Cambodge", "Ecosse", "Corée du Sud", "Islande")

)

7.3 Réactivité

  • Partie Server :
observeEvent(input$ma_liste,{
  
  pays <- input$ma_liste
  
  if pays %in% c("Ecosse", "Islande"){
    
    continent <- "Europe"
    
  } else{
    
    continent <- "Asie"
    
  }
  
})

8 Le programme complet

8.1 Le programme complet

  • Pour ensuite lancer l’application définie, on utilise la fonction ShinyApp, en appelant les parties ui et server.
ui <- fluidPage( … )

server <- function(input, output, session) { 
… 
}

ShinyApp(ui, server)
  • On lance ensuite le programme normalement.

8.2 Le programme complet


On peut rajouter du CSS, du JavaScript, …


  • Détails des fonctions : https://shiny.rstudio.com/reference/shiny/latest/

  • Des possibilités infinies (voir cette galerie inspirante) : https://shiny.rstudio.com/gallery/

8.3 Exercice Server (1/3)

Exercice - partie Server

L’interface est prête, on va maintenant écrire les traitements réalisés par le programme, c’est-à-dire la partie serveur.
5) Dans la fonction server, créez un observeEvent qui se déclenche quand on clique sur le bouton.

  1. Filtrez la table sur la région choisie via la liste déroulante (affectez le résultat dans une nouvelle table).

  2. En utilisant summarise, créer une table contenant, par département, la moyenne, le maximum, le minimum et la somme des populations (Pop_mun_2011). Affectez cette table à l’outputId de l’interface pour l’afficher (en utilisant renderTable).

Exécutez le programme.

8.4 Exercice Server (2/3)

Exercice - partie Server

  1. A l’aide de conditions, créez la table sur la donnée choisie (Pop_mun_2011, Altitude ou Superficie).
    Exécutez le programme.

  2. Dans l’observeEvent, remplacer l’inputId du bouton, par un vecteur contenant les inputId des 2 listes déroulantes.
    Exécutez le programme.

La mise à jour du tableau se fait maintenant dès qu’on change une valeur des listes déroulantes. Vous pouvez supprimer le bouton dans l’interface.

8.5 Exercice Server (2/3)

9 Liens utiles

9.1 Liens utiles


  • L’aide mémoire:

https://thinkr.fr/pdf/shiny-french-cheatsheet.pdf

  • Le tutoriel (en anglais) disponible sur RStudio :

https://shiny.rstudio.com/tutorial/written-tutorial/lesson1/

10 Pour aller plus loin

10.1 Expressions réactives : reactive()


Jusqu’ici, nous avons vu observeEvent() pour déclencher du code en réponse à une action.

Mais Shiny propose aussi les expressions réactives avec reactive() :

  • Elles calculent une valeur qui se met à jour automatiquement quand ses dépendances changent

  • Elles mettent en cache le résultat : le calcul n’est refait que si nécessaire

  • On les appelle comme une fonction (avec des parenthèses)

donnees_filtrees <- reactive({
  BC %>% filter(LIBREG == input$choix_reg)
})

# Utilisation : donnees_filtrees()

10.2 reactive() vs observeEvent()


reactive() observeEvent()
Retourne une valeur ? Oui Non
Déclenchement Automatique (dépendances) Sur un input précis
Usage principal Calculs intermédiaires Effets de bord (affichage, export)
Mise en cache Oui Non


Bonne pratique

Utilisez reactive() pour préparer les données, et observeEvent() / les fonctions render* pour afficher les résultats.

10.3 reactive() — Exemple complet

server <- function(input, output, session) {
  
  # Expression réactive : filtre + agrégation
  table_agregee <- reactive({
    BC %>%
      filter(LIBREG == input$choix_reg) %>%
      group_by(DEP, LIBDEP) %>%
      summarise(
        moyenne = mean(.data[[input$choix_var]], na.rm = TRUE),
        somme   = sum(.data[[input$choix_var]], na.rm = TRUE)
      )
  })
  
  # Réutilisation dans plusieurs outputs
  output$table_resultat <- renderTable({ table_agregee() })
  output$nb_lignes <- renderText({ nrow(table_agregee()) })
}

→ Le calcul table_agregee() est partagé entre le tableau et le texte, et n’est exécuté qu’une seule fois à chaque changement.

10.4 reactiveValues() — Stocker des données réactives


reactiveValues() permet de créer un objet réactif modifiable, comme une variable globale réactive :

server <- function(input, output, session) {
  
  rv <- reactiveValues(compteur = 0, message = "")
  
  observeEvent(input$bouton, {
    rv$compteur <- rv$compteur + 1
    rv$message <- paste("Vous avez cliqué", rv$compteur, "fois")
  })
  
  output$texte <- renderText({ rv$message })
}


→ Utile quand on veut modifier une valeur réactive au fil des interactions (un compteur, un historique, un état…).

10.5 Layouts avancés : tabsetPanel()


Pour organiser une application en onglets, on utilise tabsetPanel() et tabPanel() :

ui <- fluidPage(
  
  selectInput(inputId = "choix_reg", label = "Région :", choices = liste_regions),
  
  tabsetPanel(
    tabPanel("Tableau",
             tableOutput("table_resultat")
    ),
    tabPanel("Graphique",
             plotOutput("graphique")
    ),
    tabPanel("Résumé",
             verbatimTextOutput("resume")
    )
  )
)

→ L’utilisateur navigue entre les onglets sans recharger l’application.

10.6 Layouts avancés : navbarPage()


Pour une application plus complexe, navbarPage() remplace fluidPage() et affiche une barre de navigation en haut :

ui <- navbarPage("Mon application",
  
  tabPanel("Données",
    sidebarLayout(
      sidebarPanel(selectInput("choix_reg", "Région :", liste_regions)),
      mainPanel(tableOutput("table_resultat"))
    )
  ),
  
  tabPanel("Visualisation",
    plotOutput("graphique")
  ),
  
  tabPanel("À propos",
    h3("Application de démonstration"),
    p("Réalisée dans le cadre de la formation R-perfectionnement.")
  )
)

10.7 Layouts avancés : sidebarLayout()


Le layout sidebarLayout() est très courant : un panneau latéral pour les contrôles, et un panneau principal pour les résultats.

ui <- fluidPage(
  titlePanel("Statistiques communales"),
  
  sidebarLayout(
    sidebarPanel(
      selectInput("choix_reg", "Région :", liste_regions),
      selectInput("choix_var", "Variable :", c("Population", "Altitude", "Superficie"))
    ),
    mainPanel(
      tabsetPanel(
        tabPanel("Tableau", tableOutput("table_resultat")),
        tabPanel("Graphique", plotOutput("graphique"))
      )
    )
  )
)

10.8 Graphiques avec renderPlot()


Pour afficher un graphique ggplot2 dans Shiny, on utilise le couple plotOutput() / renderPlot() :

# UI
plotOutput(outputId = "graphique")

# Server
output$graphique <- renderPlot({
  table_agregee() %>%
    ggplot(aes(x = reorder(LIBDEP, -somme), y = somme)) +
    geom_col(fill = "steelblue") +
    coord_flip() +
    labs(title = paste("Données par département -", input$choix_reg),
         x = "Département", y = input$choix_var) +
    theme_minimal()
})

→ Le graphique se met à jour automatiquement quand les données source changent.

10.9 Validation des entrées : validate() / need()


Pour afficher des messages d’erreur conviviaux au lieu de messages R incompréhensibles, on utilise validate() et need() :

output$table_resultat <- renderTable({
  validate(
    need(input$choix_reg, "Veuillez sélectionner une région."),
    need(input$choix_var, "Veuillez sélectionner une variable.")
  )
  
  table_agregee()
})


  • need(expression, message) : si l’expression est NULL, FALSE ou vide → affiche le message
  • validate() stoppe le rendu et affiche le message dans l’interface, sans erreur R

10.10 Télécharger des résultats : downloadButton()


Pour permettre à l’utilisateur de télécharger un fichier (CSV, Excel, graphique…) :

Partie UI :

downloadButton(outputId = "telecharger", label = "Télécharger le tableau (CSV)")

Partie Server :

output$telecharger <- downloadHandler(
  filename = function() {
    paste0("resultats_", input$choix_reg, ".csv")
  },
  content = function(file) {
    write.csv2(table_agregee(), file, row.names = FALSE)
  }
)

→ Le nom du fichier est dynamique (basé sur la région choisie).

10.11 Récapitulatif des notions avancées


Notion Fonctions Usage
Expressions réactives reactive() Calculs intermédiaires mis en cache
Données réactives reactiveValues() Variables modifiables réactives
Onglets tabsetPanel(), tabPanel() Organiser l’interface
Barre de navigation navbarPage() Applications multi-pages
Layout latéral sidebarLayout() Séparer contrôles et résultats
Graphiques plotOutput() / renderPlot() Visualisations ggplot2
Validation validate() / need() Messages d’erreur conviviaux
Téléchargement downloadButton() / downloadHandler() Export de résultats

10.12 Exercice avancé (1/3)

Exercice — Pour aller plus loin

L’objectif est d’enrichir l’application construite précédemment en ajoutant des notions avancées.

Partie 1 — Restructuration de l’interface

  1. Remplacez la fluidPage() par un sidebarLayout() avec :
    • un sidebarPanel contenant les deux listes déroulantes (région et variable)
    • un mainPanel contenant un tabsetPanel avec deux onglets : “Tableau” et “Graphique”
  2. Dans l’onglet “Tableau”, placez votre tableOutput. Dans l’onglet “Graphique”, ajoutez un plotOutput.

Exécutez le programme.

10.13 Exercice avancé (2/3)

Exercice — Pour aller plus loin

Partie 2 — Expressions réactives et graphique

  1. Transformez le code de filtrage et d’agrégation en une expression réactive avec reactive(). Utilisez cette expression dans le renderTable().

  2. Ajoutez un renderPlot() qui utilise la même expression réactive pour afficher un diagramme en barres (avec ggplot2) de la variable choisie, par département.

  3. Ajoutez un validate() / need() dans le rendu du tableau et du graphique pour afficher un message si aucune région n’est sélectionnée.

Exécutez le programme.

10.14 Exercice avancé (3/3)

Exercice — Pour aller plus loin

Partie 3 — Téléchargement

  1. Ajoutez un downloadButton dans le panneau latéral (sous les listes déroulantes).

  2. Implémentez le downloadHandler côté serveur pour permettre le téléchargement du tableau agrégé au format CSV.

Exécutez le programme et testez le téléchargement.