Début à 9h30,on prévoit 30 minutes pour vérifier les accès Gitlab et le bon fonctionnement de RStudio pour tout le monde. On pourra aussi prendre le temps d’expliquer l’interface RStudio pour ceux qui ne sont pas venus en formation R Initiation.
Shiny permet de développer des sites web interactifs et réactifs pour mettre en valeur des données ie des sites web data-driven .
Shiny est un package R ie un ensemble de fonctions qui s’apparente à un framework de développement web basé sur le langage R. On peut facilement trouver des tutoriels en français mais la majorité de la documentation, des tutoriels et des échanges sur les forums sont en anglais.
Mais pour connaître les possibilités offertes par Shiny, le mieux est de jeter un oeil à la gallerie.
Par ailleurs vous connaissez déjà des applications Shiny, celles développées à la DREES :
Commençons par jeter un oeil à la liste des fonctions du package shiny en allant dans l’onglet Packages de la sous-fenêtre située en bas à droite de RStudio, en cherchant shiny et en cliquant sur l’hyperlien.
Pour créer une application Shiny il suffit d’utiliser le package éponyme, mais d’autre packages viennent enrichir les fonctionnalités de Shiny. En particulier, Shiny s’appuie sur le framework web Bootstrap.
D’autres idées ici
Commençons par lancer notre première application Shiny. Pour cela :
library(shiny)runApp() et récupérer un morceau de code à exécuter pour lancer une première application simple, par exemple le code ci-dessous.library(shiny)
app <- shinyApp(
ui = bootstrapPage(
numericInput('n', 'Number of obs', 100),
plotOutput('plot')
),
server = function(input, output) {
output$plot <- renderPlot({ hist(runif(input$n)) })
}
)
runApp(app)
Une application Shiny comprend :
global.Rui.Rserver.RLe déploiement d’une application Shiny impose quelques bonnes pratiques sur la façon de coder. Nous avons commencé à créer un guide de bonnes pratiques sur le gitlab de la DREES.
Cette fois on va coder une application ligne par ligne ensemble pour comprendre plus précisément ce qui se passe. On reprendra plus en détail après la pause déjeuner.
L’interface utilisateur permet à d’explorer l’application, pour cela il est naturel de proposer des barres de recherche, boutons, menu déroulants, etc. Ces éléments s’appellent des inputs c’est à dire les données en entrée, par opposition aux outputs, les données en sortie qui sont restituées par l’application.
Ici une application qui illustre la plupart des inputs possibles.
Ce tutoriel écrit complète cette application.
Une autre ressource très utile est l’antisèche ou cheatsheet Shiny.
Pour qu’une application s’affiche de manière agréable sur un écran de PC, une tablette ou un téléphone, il faut ajuster l’affichage. Cette technique s’appelle le responsive design.
Pour implémenter cette idée avec Shiny on découpe la page en lignes fluidRow et en colonnes column.
fluidRowNoter qu’en plus d’empiler les colonnes d’une même ligne, le text est également ajuster pour éviter l’ajout d’une barre de défilement horizontale.
ui <- fluidPage(
title = "Hello Shiny!",
fluidRow(
column(width = 4,
"4"
),
column(width = 3, offset = 2,
"3 offset 2, mais on rajoute un peu plus de texte pour illustrer le retour automatique à la ligne"
)
)
)
shinyApp(ui, server = function(input, output) { })
On va apporter des modifications à la page dans l’inspecteur d’éléments pour comprendre le rôle de chaque balise
h2 par h1 ou h3 ou p, que se passe-t-il ?a, modifier la valeur de href. Par exemple remplacer http://dataviz.drees.solidarites-sante.gouv.fr/conditions_de_vie_des_enfants par http://dataviz.drees.solidarites-sante.gouv.fr/Projection-effectifs-medecins. Si en cliquant le lien s’ouvre, éditer comme suit : clic droit > edit as HTMLimg, modifier la valeur de src, si le lien ne pointe sur aucune image, un petit logo apparaîtra pour signaler qu’une image devrait s’afficher ici. Remplacer jf_cond_vie_enfants.jpg par projection_effectifs_medecins.jpg.Appliquons ces concepts à une application Shiny
tagsh1 et un paragraphe p dans le corps body de la pagedoc <- tags$html(
tags$head(
tags$title('My first page')
),
tags$body(
h1('My first heading'),
p('My first paragraph, with some ',
strong('bold'),
' text.'),
div(id='myDiv', class='simpleDiv',
'Here is a div with some attributes.')
)
)
app <- shinyApp(
ui = bootstrapPage(
doc,
numericInput('n', 'Number of obs', 100),
plotOutput('plot')
),
server = function(input, output) {
output$plot <- renderPlot({ hist(runif(input$n)) })
}
)
runApp(app)
Dans l’explorateur d’élément, une sous-fenêtre est minimisée en bas, vous pouvez l’agrandir pour accéder à d’autres fonctionnalités comme le style de la page.
visualisation des données de la DREEScolor. Attention les lignes barrées sont des attributs qui ont été écrasés par d’autres qui étaient plus prioritaires.font-familyfont-sizeheightAppliquons ces concepts à une application Shiny.
Modifier le style des éléments html de la page pour
ph1divdoc <- tags$html(
tags$head(
tags$title('My first page')
),
tags$body(
h1('My first heading',style="font-size:100px"),
p('My first paragraph, with some ',
strong('bold'),
' text.',style="color:#099"),
div(id='myDiv', class='simpleDiv',
'Here is a div with some attributes.',style="font-family:'Comic Sans MS'")
)
)
app <- shinyApp(
ui = bootstrapPage(
doc,
numericInput('n', 'Number of obs', 100),
plotOutput('plot')
),
server = function(input, output) {
output$plot <- renderPlot({ hist(runif(input$n)) })
}
)
runApp(app)
On aurait pu intégrer ces changements dans une feuille de style monstyle.css et ajouter cette feuille à la page web shiny.
h1 {
font-size:100px
}
p {
color:#099;
}
div {
font-family:'Comic Sans MS'
}
doc <- tags$html(
tags$head(
tags$title('My first page')
),
tags$body(
h1('My first heading'),
p('My first paragraph, with some ',
strong('bold'),
' text.'),
div(id='myDiv', class='simpleDiv',
'Here is a div with some attributes.')
)
)
app <- shinyApp(
ui = bootstrapPage(
doc,
includeCSS("monstyle.css"),
numericInput('n', 'Number of obs', 100),
plotOutput('plot')
),
server = function(input, output) {
output$plot <- renderPlot({ hist(runif(input$n)) })
}
)
runApp(app)
observeEventPour qu’une application soit interactive il faut qu’elle s’adapte dynamiquement aux changements de paramètres. Les sites web traditionnels proposent des pages statiques et on utilise des liens pour passer d’une page à l’autre. L’introduction de Javascript, en particulier de jQuery et AJAX ont permis les modifications dynamiques des pages web. Autrement dit les page webs ne sont plus statiques, elles réagissent aux interactions avec l’utilisateur. Shiny intègre ce paradigme de développement web. Pour éviter que l’application change à tort et à travers, on doit préciser quels paramètres input agissent sur quels résultats output. On va s’appuyer sur l’exemple qui se trouve dans l’aide de observeEvent.
shinyApp(
ui = basicPage( actionButton("go", "Go")),
server = function(input, output, session) {
observeEvent(input$go, {
print(paste("This will only be printed once; all",
"subsequent button clicks won't do anything"))
}, once = TRUE)
}
)
Avec cet exemple, lorsqu’on appuie sur le bouton “Go”, le serveur effectue un print dans la console. L’étape suivante est d’afficher le résultat dans l’application, avec insertUI par exemple.
shinyApp(
ui = basicPage( actionButton("go", "Go")),
server = function(input, output, session) {
observeEvent(input$go, {
output$txt=renderText(paste("This will only be printed once; all",
"subsequent button clicks won't do anything"))
insertUI(selector = "#go",where = "afterEnd",ui = textOutput("txt"))
},once=T)
}
)
Ici on utilise la fonction insertUI pour ajouter dynamiquement des éléments dans l’interface utilisateur
Aller dans l’aide leaflet et récupérer un code pour générer une carte simple.
library(leaflet)
create_data=function(n){
rand_lng <- rnorm(n, 3, 1)
rand_lat <- rnorm(n, 47, 1)
categories <- LETTERS
data.frame(
lat = rand_lat, lng = rand_lng, size = runif(n, 5, 20),
category = factor(sample(categories, n, replace = TRUE), levels = categories),
value = rnorm(n),id=1:n
)}
df=create_data(100)
m <- leaflet(df) %>% addTiles()
m <- m %>% addMarkers(~lng, ~lat,popup = ~category,layerId = ~id,clusterOptions = markerClusterOptions(),clusterId = "points")
m
server <- function(input,output){
output$map=renderLeaflet(m)
}
ui <- fluidPage(
leafletOutput("map")
)
leaflet_app=shinyApp(ui=ui,server=server)
runApp(leaflet_app)
L’objectif est d’ajouter dans l’application un text qui permet de savoir quel point a été sélectionné en dernier.
Aller sur l’aide de la fonction leafletProxy pour trouver des éléments d’aide.
server <- function(input,output){
output$map=renderLeaflet(m)
observeEvent(input$map_marker_click,{
print(input$map_marker_click)
output$clicked=renderTable(data.frame(input$map_marker_click))
})
}
ui <- fluidPage(
tableOutput("clicked"),
leafletOutput("map")
)
leaflet_app=shinyApp(ui=ui,server=server)
runApp(leaflet_app)
Un bon tutoriel se trouve sur le site du développeur. Attention, il s’agit d’un package qui fait le lien entre R et le package javascript datatables.
library(DT)
server <- function(input,output){
output$dt=renderDT(df)
}
ui <- fluidPage(
DTOutput("dt"))
DT_app=shinyApp(ui=ui,server=server)
runApp(DT_app)
library(DT)
server <- function(input,output){
output$dt=renderDT(df,extensions = 'Buttons',
filter = 'top',
options = list(
dom="lftiprB",
buttons = c('copy', 'csv', 'excel', 'pdf','print')
))
}
ui <- fluidPage(
DTOutput("dt"))
DT_app=shinyApp(ui=ui,server=server)
runApp(DT_app)
Jusque là, ces paramètres n’ont pas de lien avec Shiny !!!
library(DT)
datatable(df,extensions = 'Buttons',
filter = 'top',
options = list(
dom="lftiprB",
buttons = c('copy', 'csv', 'excel', 'pdf','print')
))
Pour trouver de l’inspiration, se référer à l’aide de la fonction dataTableProxy, à la suite du tutoriel RStudio et à l’application de démonstration.
reactiveNotre objectif est de supprimer les lignes sur lesquelles l’utilisateur a cliqué.
Pour cela on va rendre le jeu de données df reactif et le mettre à jour de sorte à supprimer les lignes sur lesquelles on a cliqué.
Pour mieux comprendre, voici la définition d’un objet reactive, ou dans notre cas, reactiveVal
Wraps a normal expression to create a reactive expression. Conceptually, a reactive expression is a expression whose result will change over time.
library(DT)
server <- function(input,output,session){
### INITIALISATION
df_reactive=reactiveVal(df)
output$dt=renderDT(df_reactive())
### REACTION AU CLIC
observeEvent(input$dt_cell_clicked,{
current_df=df_reactive()
if(!is.null(input$dt_cell_clicked$`row`)){
updated_df=current_df[-input$dt_cell_clicked$`row`,]
df_reactive(updated_df)# on change la valeur du réactif
}
output$dt=renderDT(df_reactive())
})
}
ui <- fluidPage(
DTOutput("dt"))
DT_app=shinyApp(ui=ui,server=server)
runApp(DT_app)
profvis pour comprendre ce qui prend du tempsUn article qui peut servir de tutoriel avec une application sur shiny.
La documentation du développeur du package.
library(DT)
df=create_data(1E+5)
server <- function(input,output,session){
### INITIALISATION
df_reactive=reactiveVal(df)
output$dt=renderDT(df_reactive(),extensions = 'Buttons',
filter = 'top',
options = list(
dom="lftiprB",
buttons = c('copy', 'csv', 'excel', 'pdf','print')))
### REACTION AU CLIC
observeEvent(input$dt_cell_clicked,{
current_df=df_reactive()
if(!is.null(input$dt_cell_clicked$`row`)){
updated_df=current_df[-input$dt_cell_clicked$`row`,]
df_reactive(updated_df)# on change la valeur du réactif
}
output$dt=renderDT(df_reactive(),extensions = 'Buttons',
filter = 'top',
options = list(
dom="lftiprB",
buttons = c('copy', 'csv', 'excel', 'pdf','print')))
})
}
ui <- fluidPage(
DTOutput("dt"))
DT_app=shinyApp(ui=ui,server=server)
profvis::profvis({runApp(DT_app)})
Pour déployer une application shiny, il existe deux solutions :
drees.shinyapps.io puis on crée un lien vers dataviz.drees.solidarites-sante.gouv.fr.C’est 2h ou 1/2 journée toutes les 2 semaines, un compte rendu se trouve ici.