Newer
Older
---
title: "Développement d’une application Shiny et déploiement sur SK8"
subtitle: "AG CATI BARIC La Rochelle 2024"
- name: "Amandine Velt"
orcid: "0000-0002-3287-0786"
affiliations: "SVQV"
- name: "Joseph Tran"
orcid: "0000-0002-4624-0363"
affiliations: "EGFV"
date: "2024-03-11"
date-format: long
from: markdown+emoji
inrae-revealjs:
theme: custom.scss
footer: "Slides: [https://joseph.tran.pages.mia.inra.fr/quarto-shiny-sk8](https://joseph.tran.pages.mia.inra.fr/quarto-shiny-sk8) • Code: [Gitlab](https://forgemia.inra.fr/joseph.tran/quarto-shiny-sk8)"
self-contained: false
preview-links: true
- shinylive-sw.js
filters:
- shinylive
- Shiny
- SK8
- R programming
image: assets/img/shiny-logo.png
draft: false
---
## Comment communiquer autour de ses résultats R ?
[](https://r4ds.hadley.nz/communicate)
## Comment communiquer autour de ses résultats R ?
En R simple, pour changer un paramètre, il faut modifier le code
::: {style="font-size: 0.8em"}
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 ? {.smaller}
En R simple, pour changer un paramètre, il faut modifier le code
::: {style="font-size: 0.8em"}
#| 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
. . .
::: {.callout-tip title="Solution avec Shiny"}
[Hello Application](https://prose.shinyapps.io/001-hello/)
:::
## Comment communiquer autour de ses résultats R ? {.smaller}
#| viewerHeight: 500
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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 ? {.smaller}
::: columns
::: {.column width="40%" style="text-align: center;"}
{width=70% height=40%}
:::
::: {.column width="60%" style="text-align: center;"}
{width=100% height=50%}
::: {style="text-align: center;"}
{width=40% height=5% text-align="center"}
## Une documentation très complète {auto-animate="true"}
::: .r-stack
::: {data-id="shiny-doc" style="position: fixed; left: 10%;"}

[Shiny documentation](https://shiny.posit.co/r/getstarted/shiny-basics/lesson1/index.html)
:::
## Une documentation très complète {auto-animate="true"}
::: .r-stack
::: {data-id="shiny-doc" style="position: fixed; left: 10%;" }

[Shiny gallery](https://shiny.posit.co/r/gallery/)
:::
:::
## Une documentation très complète {auto-animate="true"}
::: .r-stack
::: {data-id="shiny-doc" style="position: fixed; left=10%;" }
{width=55%}
[Shiny documentation](https://shiny.posit.co/r/getstarted/shiny-basics/lesson1/index.html)
:::
::: {data-id="shiny-doc" style="position: fixed; left: 55%;" }
{width=80%}
[Shiny gallery](https://shiny.posit.co/r/gallery/)
:::
:::
# Fonctionnement d’une application Shiny
## Structure d’une application Shiny {auto-animate="true"}
::: .r-stack
::: {data-id="shinyapp_ui" style="position: fixed; left=10%;" }
```{r filename="ui.R"}
#| echo: fenced
#| eval: false
#| code-line-numbers: "16-35"
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# 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 {auto-animate="true"}
::: .r-stack
::: {data-id="shinyapp_server" style="position: fixed; left=10%;" }
```{r filename="server.R"}
#| echo: fenced
#| eval: false
#| code-line-numbers: "16-27"
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
#
# 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
:::: columns
::: {.column width=50%}
::: {.fragment .fade-right width=50%}
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
```{r filename="app.R"}
#| echo: fenced
#| 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")
)
)
)
```
:::
:::
::: {.column width=50%}
::: {.fragment .fade-left width=50%}
```{r filename="app.R"}
#| echo: fenced
#| eval: false
#| code-line-numbers: "16-27"
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
# 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

## Fonctionnement d’une application Shiny

## Fonctionnement d’une application Shiny
::: columns
::: {.column width="50%"}
#| echo: fenced
#| eval: false
#| code-line-numbers: "24-29,32"
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
# 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")
)
)
)
```
:::
::: {.column width="50%"}
```{r filename="server.R"}
#| echo: fenced
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
#| 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
{width=60%}
[Widgets d'inputs](https://shiny.rstudio.com/gallery/widget-gallery.html)
## Les différents types d'outputs

[Rendering functions](https://shiny.posit.co/r/getstarted/build-an-app/reactive-flow/render-functions.html)
## Structure du dossier d’une application Shiny

- 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
{width=50%}
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
## Les layouts
::: columns
::: {.column width="50%"}
``` r
#| 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")
)
)
)
)
)
```
:::
::: {.column width="50%"}

:::
:::
## Les layouts prédéfinis

## Les layouts prédéfinis

## Les layouts en onglets

## Shiny Dashboard {.smaller}
::: columns
::: {.column width="75%"}
[shinydashboard](https://rstudio.github.io/shinydashboard/)
:::
::: {.column width="25%"}
::: {.callout-tip title="Shiny Dashboard alternatives" .smaller}
- [shinydashboardPlus](https://rinterface.github.io/shinydashboardPlus/)
- [shiny.semantic](https://appsilon.github.io/shiny.semantic/)
- [bs4Dash](https://rinterface.github.io/bs4Dash/index.html)
- [bslib](https://rstudio.github.io/bslib/)
:::
:::
:::
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
## La réactivité des applications Shiny
{width=80%}
## 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
- GREAT (Amandine) [GREAT](https://great.colmar.inrae.fr/login)
- Source : [Gitlab](https://gitlab.com/avelt/great/)
- Easy16S (Cédric) [easy16S](https://genome.jouy.inra.fr/shiny/easy16S/)
- Source : [Gitlab](https://gitlab.irstea.fr/cedric.midoux/easy16S)
- Rosetta (Andrea) [rosetta](http://ls-shiny-prod.uwm.edu/rosetta/)
- Source : [Github](https://github.com/andreamrau/rosetta)
# 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)
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
::: {.callout-warning title="Inconvénient"}
Nécessite d’installer R/Rstudio et de gérer l'installation des dépendances
:::
## Partager son application Shiny {.smaller}
**Application shinylive**
[R Shiny Live demo in Quarto!](https://joseph.tran.pages.mia.inra.fr/r-shinylive-demo/)
```{shinylive-r}
#| 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 {.smaller}
**Application shinylive**
YouTube video: guide pas à pas pour créer une application Shiny sans serveur
[](https://www.youtube.com/watch?v=6y2FnAugP8E)
## Partager son application Shiny
**[shinyapps.io](https://docs.rstudio.com/shinyapps.io/)**
::: columns
::: {.column width="70%"}
::: {.callout-tip title="Shinyapps.io" .my-callout}
- 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
:::
:::
::: {.column width="30%"}
::: {.callout-important title="Inconvénient" .my-callout}
- Dépendance à RStudio
- Freemium
- Taille de l’appli limité à 1Go (données externes comprises)
:::
**Shiny Server**
::: {.callout-tip title="version free"}
- un processus R / application qui peut servir plusieurs utilisateurs
- Limite : quand beaucoup d’utilisateurs, ils se bloquent les uns les autres.
:::
::: {.callout-important title="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
:::
**[Shinyproxy](https://www.shinyproxy.io/documentation/)**
## Partager son application Shiny {auto-animate="true"}
**Déploiement avec SK8 (version kickflip, 2023)**
Projet porté par **Jean-François Rey** puis porté par le CATI IMOTEP et passage en Inter-CATIs (2022).
::: .r-stack
:::{data-id="sk8-workflow" style="position: fixed; " }

:::
:::{data-id="sk8-workflow_infra" style="position: fixed; left: 90%; bottom: 90%; opacity: 0; " }
:::
:::
## Partager son application Shiny {auto-animate="true"}
**Déploiement avec SK8 (version kickflip, 2023)**
Projet porté par Jean-François Rey puis porté par le CATI IMOTEP et passage en Inter-CATIs (2022).
:::
::: .r-stack
:::{data-id="sk8-workflow" style="position: fixed; bottom: 1%; opacity: 0; " }

:::
:::{data-id="sk8-workflow_infra" style="position: fixed; " }

:::
:::
**Déploiement avec SK8 (version kickflip, 2023)**

## Partager son application Shiny
**Déploiement avec SK8 (version kickflip, 2023)**
[](https://ci-tique-tracker.sk8.inrae.fr/){width=70%}
## Partager son application Shiny
**Déploiement avec SK8 (version kickflip, 2023)**
[](https://loup-ecrins-genetique.sk8.inrae.fr/){width=70%}
## Partager son application Shiny
**Déploiement avec SK8 (version kickflip, 2023)**
[](https://shinyidea.sk8.inrae.fr/){width=70%}
## Partager son application Shiny
**Déploiement avec SK8 (version kickflip, 2023)**
::: {style="font-size: 0.75em"}
Plus d'information sur le site web [https://sk8.inrae.fr](https://sk8.inrae.fr/)
:::

::: {.callout-tip title="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
::: {.callout-warning title="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](https://shiny.posit.co/r/gallery/)
[Gallery widget](https://shiny.posit.co/r/gallery/widgets/widget-gallery/)
[CheatSheet](https://raw.githubusercontent.com/rstudio/cheatsheets/main/shiny.pdf)
[CheatSheet VF](https://thinkr.fr/pdf/shiny-french-cheatsheet.pdf)
## Sources : Tuto
[Tuto officiel](https://shiny.posit.co/r/getstarted/shiny-basics/lesson1/index.html)
[École Thématique GeoViz](https://geoviz.sciencesconf.org/data/pages/GeoViz2018_R_shiny.pdf)
[Introduction à Shiny](http://perso.ens-lyon.fr/lise.vaudor/Tuto_Shiny/)
[Formation IFB](https://github.com/IFB-ElixirFr/IFB_Shiny_training)
[Organisation de l’UI](https://speakerdeck.com/jcheng5/styling-shiny)
## Atelier Shiny
[Learnr tutoriel shiny](https://forgemia.inra.fr/joseph.tran/shiny-tutorial)