diff --git a/shiny_tutorial.Rmd b/shiny_tutorial.Rmd index fdb4ff8c673d9435aa1a720429a238d2e0aee481..bae35dfa5c8bfc4f31419aa1f60028faf24d0bd9 100644 --- a/shiny_tutorial.Rmd +++ b/shiny_tutorial.Rmd @@ -24,6 +24,8 @@ library(learnr) ## Introduction +### Iris dataset + Pour le tutoriel, nous allons utiliser un jeu de données intégré à R, nommé Iris. Il recense les tailles de pétales et de sépales pour un ensemble d'individus "iris" de trois espèces différentes, setosa, versicolor et virginica. Exécuter le code suivant, bouton `Run code`, pour afficher les premières lignes du jeu de données: @@ -32,16 +34,34 @@ Exécuter le code suivant, bouton `Run code`, pour afficher les premières ligne head(iris) ``` +## Développer une application Shiny + +### Créer une application Shiny + +Créer un répertoire pour l’application avec **RStudio**. -## Base d'une application Shiny +```bash +File -> New Project -> New Directory -> Shiny Web Application +``` + +Choisir une application **Multiple File**. -La base de notre application Shiny de départ est comprise dans deux fichiers obligatoires au fonctionnement d'une application Shiny, `ui.R` et `server.R`. +Si cette option n’est pas disponible (ça peut dépendre des versions de Rstudio), on pourra utiliser +```bash +File -> New File -> Shiny Web App -> Multiple File +``` + +Deux fichier sont automatiquement générés : `ui.R` et `server.R`. Lancer l’application en cliquant sur le bouton `Run App`. + + * Changer le titre de l’application. On pourra l’appeler My first application. + * Mettre à jour et vérifier que le titre a bien été changé. + ### ui.R -Voici un exemple de `ui.R` que nous allons utiliser. +Voici un exemple de `ui.R` que nous allons utiliser. Lancer le code avec le bouton `Run code` pour voir le rendu. -```{r ui_R, exercise=TRUE} +```{r ui_R, exercise=TRUE, exercise.lines=20, eval=FALSE} # k-means only works with numerical variables, # so don't give the user the option to select # a categorical variable @@ -80,103 +100,498 @@ Il s'agit maintenant de remplir le fichier server.R pour obtenir des résultats Créer une reactive avec reactive({}) pour générer un tableau dynamique récupérant les 2 colonnes correspondant aux variables X et Y sélectionnées par l’utilisateur sur les données iris et ranger ce tableau dans une variable « selectedData » -```{r server_R_selected_data, exercise=TRUE} -function(input, output, session) { +```{r server_R_selected_data, exercise=TRUE, exercise.warn_invisible=TRUE} +# function(input, output, session) { +# ajouter votre code ci-dessous -} +# } +``` + +```{r server_R_selected_data-hint-1} +# function(input, output, session) { +# ajouter votre code ci-dessous + + # Combine the selected variables into a new data frame + selectedData <- reactive({...}) + +# } +``` + +```{r server_R_selected_data-hint-2} +# function(input, output, session) { +# ajouter votre code ci-dessous + + # Combine the selected variables into a new data frame + selectedData <- reactive({ + iris[, ... ] +}) + +# } +``` + +```{r server_R_selected_data-hint-3} +# function(input, output, session) { +# ajouter votre code ci-dessous + + # Combine the selected variables into a new data frame + selectedData <- reactive({ + iris[, c(input$xcol, input$ycol)] +}) + +# } ``` ```{r server_R_selected_data-solution} -function(input, output, session) { - +# function(input, output, session) { +# ajouter votre code ci-dessous + # Combine the selected variables into a new data frame selectedData <- reactive({ iris[, c(input$xcol, input$ycol)] }) -} + +# } ``` -### Générer le clustering k-means dasn une fonction reactive({}) +### Solution -Créer une reactive avec reactive({}) pour générer un cluster sur le tableau dynamique précédent, utilisant la variable « Cluster count » comme nombre de clusters à créer et ranger ce résultat dans une variable « clusters ». Utiliser la fonction kmeans() pour générer ces clusters. +Et voilà ce que contient `selectedData`: -```{r server_R_clusters, exercise=TRUE} -function(input, output, session) { +```{r server_R_selected_data-display, echo=FALSE} +vars <- setdiff(names(iris), "Species") -} +pageWithSidebar( + headerPanel('Iris: select data'), + sidebarPanel( + selectInput('xcol_sd', 'X Variable', vars), + selectInput('ycol_sd', 'Y Variable', vars, selected = vars[[2]]), + numericInput('clusters_sd', 'Cluster count', 3, min = 1, max = 9) + ), + mainPanel( + tabsetPanel(type = "tabs", + tabPanel("Selected data", DT::dataTableOutput("sd_selectedData")) + ) + ) +) ``` -```{r server_R_clusters-solution} -function(input, output, session) { - +```{r server_R_selected_data-print, echo=TRUE, context = "server"} +# function(input, output, session) { +# ajouter votre code ci-dessous + # Combine the selected variables into a new data frame selectedData <- reactive({ - iris[, c(input$xcol, input$ycol)] + iris[, c(input$xcol_sd, input$ycol_sd)] }) + + output$sd_selectedData <- DT::renderDataTable( + DT::datatable( + selectedData(), + options = list( + dom = 'Bfrtip', + lengthMenu = list(c(5, 15, -1), c('5', '15', 'All')), + pageLength = 15, + buttons = list( + list( + extend = "collection", + text = 'Show All', + action = DT::JS("function ( e, dt, node, config ) { + dt.page.len(-1); + dt.ajax.reload(); + }") + ) + ) + ) + ) + ) - clusters <- reactive({ - kmeans(selectedData(), input$clusters) - }) -} +# } ``` -### Générer le plot dynamique du clustering kmeans +### Générer un tableau des données sélectionnées pour le graphique -Générer un graphique dynamique avec renderPlot{()} représentant le tableau dynamique avec la fonction plot() et colorer les points selon le cluster auquel ils appartiennent avec le paramètre « col ». Pour récupérer les clusters depuis la variable « clusters », utiliser clusters()\$cluster. Ranger le résultat dans output\$plot1 et le représenter côté UI dans le tabPanel « Plot ». +Afficher le tableau dynamique avec renderTable{()} représentant le tableau utilisé pour générer le graphique et ranger le résultat dans output$table. Représenter cette table côté UI dans le tabPanel « Table ». -```{r server_R_render_plot, exercise=TRUE} -function(input, output, session) { +```{r server_R_render_table, exercise=TRUE, context = "server", exercise.warn_invisible=TRUE} +# function(input, output, session) { +# ajouter votre code ci-dessous -} +# } ``` -```{r server_R_render_plot-solution} -function(input, output, session) { - - # Combine the selected variables into a new data frame - selectedData <- reactive({ - iris[, c(input$xcol, input$ycol)] +```{r server_R_render_table-hint-1} +# function(input, output, session) { +# ajouter votre code ci-dessous + + output$table <- renderTable({...}) + +# } +``` + +```{r server_R_render_table-hint-2} +# function(input, output, session) { +# ajouter votre code ci-dessous + + output$table <- renderTable({ + selectedData() }) + +# } +``` + +```{r server_R_render_table-solution} +# function(input, output, session) { +# ajouter votre code ci-dessous - clusters <- reactive({ - kmeans(selectedData(), input$clusters) + output$table <- renderTable({ + selectedData() }) - - output$plot1 <- renderPlot({ - palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", - "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999")) - - par(mar = c(5.1, 4.1, 0, 1)) - plot(selectedData(), - col = clusters()$cluster, - pch = 20, cex = 3) - points(clusters()$centers, pch = 4, cex = 4, lwd = 4) + +# } +``` + +### Solution + +Et voilà ce que contient `output$table`: + +```{r server_R_render_table-display, echo=FALSE} +vars <- setdiff(names(iris), "Species") + +pageWithSidebar( + headerPanel('Iris: print selected data table'), + sidebarPanel( + selectInput('xcol_tbl', 'X Variable', vars), + selectInput('ycol_tbl', 'Y Variable', vars, selected = vars[[2]]), + numericInput('clusters_tbl', 'Cluster count', 3, min = 1, max = 9) + ), + mainPanel( + tabsetPanel(type = "tabs", + tabPanel("Table", DT::dataTableOutput("tbl_selectedData")) + ) + ) +) +``` + +```{r server_R_render_table-print, context = "server"} +# function(input, output, session) { +# ajouter votre code ci-dessous + + # Combine the selected variables into a new data frame + tblselectedData <- reactive({ + iris[, c(input$xcol_tbl, input$ycol_tbl)] }) -} + + output$tbl_selectedData <- DT::renderDataTable( + DT::datatable( + tblselectedData(), + options = list( + dom = 'Bfrtip', + lengthMenu = list(c(5, 15, -1), c('5', '15', 'All')), + pageLength = 15, + buttons = list( + list( + extend = "collection", + text = 'Show All', + action = DT::JS("function ( e, dt, node, config ) { + dt.page.len(-1); + dt.ajax.reload(); + }") + ) + ) + ) + ) + ) + +# } ``` ### Générer un résumé statistique du tableau dynamique Générer un texte dynamique avec renderPrint({}) représentant un résumé statistique du tableau dynamique généré précédemment avec la fonction summary() et ranger le résultat dans output$summary, puis le représenter côté UI dans le tabPanel « Summary ». -```{r server_R_render_print, exercise=TRUE} -function(input, output, session) { +```{r server_R_render_print, exercise=TRUE, context = "server", exercise.warn_invisible=TRUE} +# function(input, output, session) { +# ajouter votre code ci-dessous -} +# } +``` + +```{r server_R_render_print-hint-1} +# function(input, output, session) { +# ajouter votre code ci-dessous + + # Generate a summary of the data ---- + output$summary <- renderPrint({...}) + +# } +``` + +```{r server_R_render_print-hint-2} +# function(input, output, session) { +# ajouter votre code ci-dessous + + # Generate a summary of the data ---- + output$summary <- renderPrint({ + summary(...) + }) + +# } +``` + +```{r server_R_render_print-hint-3} +# function(input, output, session) { +# ajouter votre code ci-dessous + + # Generate a summary of the data ---- + output$summary <- renderPrint({ + summary(selectedData()) + }) + +# } ``` ```{r server_R_render_print-solution} -function(input, output, session) { +# function(input, output, session) { +# ajouter votre code ci-dessous + # Generate a summary of the data ---- + output$summary <- renderPrint({ + summary(selectedData()) + }) + +# } +``` + +### Solution + +Et voilà ce que contient `output$summary`: + +```{r server_R_render_print-display, echo=FALSE} +vars <- setdiff(names(iris), "Species") + +pageWithSidebar( + headerPanel('Iris k-means clustering'), + sidebarPanel( + selectInput('xcol_smry', 'X Variable', vars), + selectInput('ycol_smry', 'Y Variable', vars, selected = vars[[2]]), + numericInput('clusters_smry', 'Cluster count', 3, min = 1, max = 9) + ), + mainPanel( + tabsetPanel(type = "tabs", + tabPanel("Summary", verbatimTextOutput("print_summary")) + ) + ) +) +``` + +```{r server_R_render_print-print, context = "server"} +# function(input, output, session) { +# ajouter votre code ci-dessous + # Combine the selected variables into a new data frame - selectedData <- reactive({ - iris[, c(input$xcol, input$ycol)] + smryselectedData <- reactive({ + iris[, c(input$xcol_smry, input$ycol_smry)] + }) + + smryclusters <- reactive({ + kmeans(smryselectedData(), input$clusters_smry) + }) + + output$print_summary <- renderPrint({ + summary(smryselectedData()) }) +# } +``` + +### Générer le clustering k-means dans une fonction reactive({}) + +Créer une reactive avec reactive({}) pour générer un cluster sur le tableau dynamique précédent, utilisant la variable « Cluster count » comme nombre de clusters à créer et ranger ce résultat dans une variable « clusters ». Utiliser la fonction kmeans() pour générer ces clusters. + +```{r server_R_clusters, exercise=TRUE, exercise.warn_invisible=TRUE} +# function(input, output, session) { +# ajouter votre code ci-dessous + +# } +``` + +```{r server_R_clusters-hint-1} +# function(input, output, session) { +# ajouter votre code ci-dessous + + clusters <- reactive({...}) + +# } +``` + +```{r server_R_clusters-hint-2} +# function(input, output, session) { +# ajouter votre code ci-dessous + + clusters <- reactive({ + kmeans(...) + }) + +# } +``` + +```{r server_R_clusters-hint-3} +# function(input, output, session) { +# ajouter votre code ci-dessous + clusters <- reactive({ kmeans(selectedData(), input$clusters) }) + +# } +``` + +```{r server_R_clusters-solution} +# function(input, output, session) { +# ajouter votre code ci-dessous + clusters <- reactive({ + kmeans(selectedData(), input$clusters) + }) + +# } +``` + +### Solution + +Et voilà ce que contient `clusters`: + +```{r server_R_clusters-display, echo=FALSE} +vars <- setdiff(names(iris), "Species") + +pageWithSidebar( + headerPanel('Iris print k-means clustering results'), + sidebarPanel( + selectInput('xcol_km', 'X Variable', vars), + selectInput('ycol_km', 'Y Variable', vars, selected = vars[[2]]), + numericInput('clusters_km', 'Cluster count', 3, min = 1, max = 9) + ), + mainPanel( + tabsetPanel(type = "tabs", + tabPanel("K-means clusters", verbatimTextOutput("km_clusters")) + ) + ) +) +``` + +```{r server_R_clusters-print, context = "server"} +# function(input, output, session) { +# ajouter votre code ci-dessous + + # Combine the selected variables into a new data frame + kmselectedData <- reactive({ + iris[, c(input$xcol_km, input$ycol_km)] + }) + + kmclusters <- reactive({ + kmeans(kmselectedData(), input$clusters_km) + }) + + output$km_clusters <- renderPrint({ + kmclusters() + }) + +# } +``` + +### Générer le plot dynamique du clustering kmeans + +Générer un graphique dynamique avec renderPlot{()} représentant le tableau dynamique avec la fonction plot() et colorer les points selon le cluster auquel ils appartiennent avec le paramètre « col ». Pour récupérer les clusters depuis la variable « clusters », utiliser clusters()\$cluster. Ranger le résultat dans output\$plot1 et le représenter côté UI dans le tabPanel « Plot ». + +```{r server_R_render_plot, exercise=TRUE, exercise.warn_invisible=TRUE} +# function(input, output, session) { +# ajouter votre code ci-dessous + +# } +``` + +```{r server_R_render_plot-hint-1} +# function(input, output, session) { +# ajouter votre code ci-dessous + + output$plot1 <- renderPlot({...}) + +# } +``` + +```{r server_R_render_plot-hint-2} +# function(input, output, session) { +# ajouter votre code ci-dessous + + output$plot1 <- renderPlot({ + # create a 9 colors palette + palette(...) + + }) + +# } +``` + +```{r server_R_render_plot-hint-3} +# function(input, output, session) { +# ajouter votre code ci-dessous + + output$plot1 <- renderPlot({ + # create a 9 colors palette + palette(...) + + # define margins: replace *_margin placeholders by real values + par(mar = c(bottom_margin, left_margin, top_margin, right_margin)) + }) + +# } +``` + +```{r server_R_render_plot-hint-4} +# function(input, output, session) { +# ajouter votre code ci-dessous + + output$plot1 <- renderPlot({ + # create a 9 colors palette + palette(...) + + # define margins: replace *_margin placeholders by real values + par(mar = c(bottom_margin, left_margin, top_margin, right_margin)) + + # create the plot + plot(selectedData(), + ...) + + }) + +# } +``` + +```{r server_R_render_plot-hint-5} +# function(input, output, session) { +# ajouter votre code ci-dessous + + output$plot1 <- renderPlot({ + # create a 9 colors palette + palette(...) + + # define margins: replace *_margin placeholders by real values + par(mar = c(bottom_margin, left_margin, top_margin, right_margin)) + + # create the plot: set the points color, shape, etc. + plot(selectedData(), + ...) + # add the cluster centers: set the points color, shape, etc. + points(clusters()$centers, ...) + }) + +# } +``` + +```{r server_R_render_plot-hint-6} +# function(input, output, session) { +# full solution + output$plot1 <- renderPlot({ palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999")) @@ -188,55 +603,79 @@ function(input, output, session) { points(clusters()$centers, pch = 4, cex = 4, lwd = 4) }) - # Generate a summary of the data ---- - output$summary <- renderPrint({ - summary(selectedData()) +# } +``` + +```{r server_R_render_plot-solution, context="server"} +# function(input, output, session) { +# ajouter votre code ci-dessous + + output$plot1 <- renderPlot({ + palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", + "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999")) + + par(mar = c(5.1, 4.1, 0, 1)) + plot(selectedData(), + col = clusters()$cluster, + pch = 20, cex = 3) + points(clusters()$centers, pch = 4, cex = 4, lwd = 4) }) -} + +# } ``` -### Générer un tableau des données sélectionnées pour le graphique +### Solution -Afficher le tableau dynamique avec renderTable{()} représentant le tableau utilisé pour générer le graphique et ranger le résultat dans output$table. Représenter cette table côté UI dans le tabPanel « Table ». +Et voilà ce que contient `output$plot1`: -```{r server_R_render_table, exercise=TRUE} -function(input, output, session) { +```{r server_R_render_plot-display, echo=FALSE} +vars <- setdiff(names(iris), "Species") -} +pageWithSidebar( + headerPanel('Iris plot k-means clustering results'), + sidebarPanel( + selectInput('xcol_plot', 'X Variable', vars), + selectInput('ycol_plot', 'Y Variable', vars, selected = vars[[2]]), + numericInput('clusters_plot', 'Cluster count', 3, min = 1, max = 9) + ), + mainPanel( + tabsetPanel(type = "tabs", + tabPanel("K-means clusters plot", plotOutput("km_plot")), + tabPanel("K-means clusters", verbatimTextOutput("print_clusters")) + ) + ) +) ``` -```{r server_R_render_table-solution} -function(input, output, session) { - +```{r server_R_render_plot-print, context = "server"} +# function(input, output, session) { +# ajouter votre code ci-dessous + # Combine the selected variables into a new data frame - selectedData <- reactive({ - iris[, c(input$xcol, input$ycol)] + plotselectedData <- reactive({ + iris[, c(input$xcol_plot, input$ycol_plot)] }) - - clusters <- reactive({ - kmeans(selectedData(), input$clusters) + + plotclusters <- reactive({ + kmeans(plotselectedData(), input$clusters_plot) + }) + + output$print_clusters <- renderPrint({ + plotclusters() }) - output$plot1 <- renderPlot({ + output$km_plot <- renderPlot({ palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999")) par(mar = c(5.1, 4.1, 0, 1)) plot(selectedData(), - col = clusters()$cluster, + col = plotclusters()$cluster, pch = 20, cex = 3) - points(clusters()$centers, pch = 4, cex = 4, lwd = 4) - }) - - # Generate a summary of the data ---- - output$summary <- renderPrint({ - summary(selectedData()) + points(plotclusters()$centers, pch = 4, cex = 4, lwd = 4) }) - output$table <- renderTable({ - selectedData() - }) -} +# } ``` ## Application Shiny complète @@ -251,7 +690,7 @@ shiny::runApp(".") ### L'application shiny en démo live -Si vous avez exécuter la commande ``shiny::runApp(".")`` dans la console, vous pouvez voir l'application en démo live ci-dessous. +Si vous avez exécuter la commande `shiny::runApp(".")` dans la console, vous pouvez voir l'application en démo live ci-dessous. ```{r shiny_run_app_demo, echo=FALSE} # k-means only works with numerical variables, @@ -268,7 +707,7 @@ pageWithSidebar( ), mainPanel( tabsetPanel(type = "tabs", - tabPanel("Plot", plotOutput('plot1')), + tabPanel("K-means clusters plot", plotOutput('plot1')), tabPanel("Summary", verbatimTextOutput("summary")), tabPanel("Table", tableOutput("table")) )