Thomas Denecker & Claire Toffano-Nioche

Session 6

24/05/2019

Novembre

Janvier

Février

Mars

Avril

Mai

Juin

Juillet

...

26

25

22

29

26

24

21

à définir

...

Session de juillet

Proposition le 05 juillet 

Session 6

LoveR

Exploration des résultats

Simplicité de l'exploration

 

Simplicité du paramétrage 

 

Reproductibilité de la visualisation

Programme de la session

Rappel R

 

Le package Shiny 
   - Import d'un fichier
   - Affichage d'un tableau
   - Connection tableau <-> graphique
   - Graphique R de base avec paramétrage


Teasing de la puissance de R

 - Exploration des données : dplyr  

 - Réalisation de graphiques : plotly, google chart, ggplot2

 - Lecture de fichiers spéciaux : fasta, fastq, excel

 - Croisement de jeux de données : upset R

Le project R

Gratuit et participatif

Fonctions statistiques et graphiques avancées

  - Calculs sur des variables

  - Tests statistiques

  - Représentations graphiques

Librairies complémentaires

  - Bio-informatique

  - Data-mining

  - Bases de données, ...

Interfaces possibles avec d'autres langages

  - Shell

  - Python, ...

Le site de référence : CRAN

R et ses cheat sheets

De nombreuses cheat sheets disponibles 

https://www.rstudio.com/resources/cheatsheets/

 

 

Une très grande communauté

Des comptes à suivre sur Twitter (#rstats)

Des événements R

Rstudio : un IDE au top ! 

Gratuit

Simple d'utilisation

Paramétrable

Un gain de temps considérable

 

Installation 

Méthode 1 ( l'ordre est important ! )

 

1-  Installer R (depuis le CRAN)  

https://cran.r-project.org/

 

2- Installation de Rstudio 

https://www.rstudio.com/products/rstudio/download/

 

Méthode 2

 

Docker !! https://www.rocker-project.org/images/

install.packages("shiny")
library(shiny)

Package R qui facilite la création d'applications web interactives directement à partir de R 

 

Fonctions traduisent du R en HTML

 

 

Installation de Shiny

h1(‘Un titre’)
<h1>Un titre</h1>

Pourquoi faire une application?

Reproductibilité de la visualisation

 

Reproductibilité de l'analyse (création d'un rapport)

 

Simplifier l'exploration des résultats par l’interaction

 

Changer des paramètres sans entrer dans le script

 

Partager plus facilement son projet pour des non programmeurs (ouverture du projet au monde)

 

 

De nombreuses publications associées

En nombre de publication

Pubmed (recherche shiny app)

Pour un package proposé en 2013 !

Un nouveau langage à apprendre?

NON

(si vous savez parler R)

 

Et des connaissances en HTML, CSS et JS ?

Pas indispensables mais utiles pour du design fin et certains cas d'interactions

 

Architecture d'une application

UI

Entrées d'informations

(boutons, fichiers, ...)

 

Affichage de sorties

(graphiques, textes, ...)

Traitement des entrées

(lecture des fichiers, ...)

 

Création de sorties

(créations d'un plot)

input

output

Server

Interface utilisateur visible sur la page web

"Zone de travail" : calculs, préparation des données, ...

Un exemple

Création d'une petite application

Texte

Thomas DENECKER

Un exemple documenté

Et l'application du project FAIR_bioinfo?

Une application plus complexe ... mais pas infaisable pour des débutants de Shiny ! 

 

Le code est à 100% disponible !

https://github.com/thomasdenecker/FAIR_Bioinfo/blob/master/R-code/app.R

 

De nombreuses similitudes !

Pré-requis

évidemment ! 

Les données

Dataset :  IRIS (mesures sur des fleurs)

Source : https://archive.ics.uci.edu/ml/datasets/iris   


Le tableau est composé de 5 colonnes :

  - la longueur des sépales
  - la largeur des sépales
  - la longueur des pétales
  - la largeur des pétales
  - l’espèce de fleurs

Le tableau est disponible ici : 

https://github.com/bioinfo-fr/bioinfo-fr_Shiny/blob/master/datasetIris.txt 

Les librairies nécessaires

Toutes disponibles sur le CRAN

Bonus : anylib est fonction qui installe (si besoin) et charge les librairies

install.packages("anyLib")
anyLib::anyLib(c("shiny", "shinydashboard", "shinyWidgets", "DT", "plotly", "ggplot2", "googleVis", "colourpicker"))

Création de l'application : Shiny, Shinydashboard

Entrées avancées : shinyWidgets, colourpicker

Création de graphiques : plotly, ggplot2, googleVis

Tableau dynamique : DT

 

Création de l'architecture

Utilisation du package Shinydashboard

library(shiny)
library(shinydashboard)
 
ui <- dashboardPage(
  dashboardHeader(),
  dashboardSidebar(),
  dashboardBody()
)
 
server <- function(input, output) { }
 
shinyApp(ui, server)

Test l'application

Dans Rstudio

Dans un terminal (dans le dossier avec le fichier app.R

R -e "shiny::runApp('R-code', port=4444)"

Sauvegarder : app.R (et bien sûr versionner ! )

le nom de fichier n'est pas renseigné car app.R est le nom par défaut (comme Snakefile, dockerfile, ...)

Le résultat

Et en HTML?


<!DOCTYPE html>
<html>
<head>

  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <script type="application/shiny-singletons"></script>
  <script type="application/html-dependencies">json2[2014.02.04];jquery[1.12.4];shiny[1.3.0];font-awesome[5.3.1];bootstrap[3.3.7];AdminLTE[2.0.6];shinydashboard[0.7.1]</script>
<script src="shared/json2-min.js"></script>
<script src="shared/jquery.min.js"></script>
<link href="shared/shiny.css" rel="stylesheet" />
<script src="shared/shiny.min.js"></script>
<link href="font-awesome-5.3.1/css/all.min.css" rel="stylesheet" />
<link href="font-awesome-5.3.1/css/v4-shims.min.css" rel="stylesheet" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="shared/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
<script src="shared/bootstrap/js/bootstrap.min.js"></script>
<script src="shared/bootstrap/shim/html5shiv.min.js"></script>
<script src="shared/bootstrap/shim/respond.min.js"></script>
<link href="AdminLTE-2.0.6/AdminLTE.min.css" rel="stylesheet" />
<link href="AdminLTE-2.0.6/_all-skins.min.css" rel="stylesheet" />
<script src="AdminLTE-2.0.6/app.min.js"></script>
<link href="shinydashboard-0.7.1/shinydashboard.css" rel="stylesheet" />
<script src="shinydashboard-0.7.1/shinydashboard.min.js"></script>

</head>

<body class="skin-blue" style="min-height: 611px;">
  <div class="wrapper">
    <header class="main-header">
      <span class="logo"></span>
      <nav class="navbar navbar-static-top" role="navigation">
        <span style="display:none;">
          <i class="fa fa-bars"></i>
        </span>
        <a href="#" class="sidebar-toggle" data-toggle="offcanvas" role="button">
          <span class="sr-only">Toggle navigation</span>
        </a>
        <div class="navbar-custom-menu">
          <ul class="nav navbar-nav"></ul>
        </div>
      </nav>
    </header>
    <aside id="sidebarCollapsed" class="main-sidebar" data-collapsed="false">
      <section id="sidebarItemExpanded" class="sidebar"></section>
    </aside>
    <div class="content-wrapper">
      <section class="content"></section>
    </div>
  </div>
</body>

</html>

Les différentes zones du dashboard

Zone principale

(grise)

Zone

de menu

(noire)

Titre

Zone de notifications

Ajouter un titre

ui <- dashboardPage(
  dashboardHeader(title = "bioinfo-fr"),
  dashboardSidebar( ),
  dashboardBody( )
)

Ajouter un menu

ui <- dashboardPage(
  dashboardHeader(title = "bioinfo-fr"),
  dashboardSidebar(
    sidebarMenu(
      menuItem("Lecture des données", tabName = "readData", icon = icon("readme")),
      menuItem("Visualisation des données", tabName = "visualization", icon = icon("poll"))
    )
  ),
  dashboardBody(
    tabItems(
      # Read data
      tabItem(tabName = "readData",
              h1("Lecture des données")
      ),
      
      # visualization
      tabItem(tabName = "visualization",
              h1("Visualisation des données")
      )
    )
  )
)

Zone noire

Zone grise

Les icones sont disponibles ici : https://fontawesome.com/

Résultats

Création d'un lecteur de fichier

Pourquoi?

Paramétrage de la lecture (nom de colonnes, séparateur, guillemets, ...)

Prévisualisation de la lecture 

 

Zone d'import

[...]
  dashboardBody(
    tabItems(
      # Read data
      tabItem(tabName = "readData",
              h1("Lecture des données"),
              fileInput("dataFile",label = NULL,
                        buttonLabel = "Browse...",
                        placeholder = "No file selected")
      ),
      
      # visualization
      tabItem(tabName = "visualization",
              h1("Visualisation des données")
      )
    )
  )
[...]

Résultat

Zone de paramétrage

  3 paramètres de lecture :

  - Type de séparateur 

  - Type de guillemets

  - Nom de colonnes (présent ou non)

 

Utilisation de radio buttons (5 arguments) :

  - id : identifiant

  - label : titre du groupe de radio buttons 

  - choices : choix disponibles 

  - selected : choix sélectionné

  - inline = T : alignement des radio buttons

 

Zone de paramétrage

[…]
tabItem(tabName = "readData",
              h1("Lecture des données"),
              fileInput("dataFile",label = NULL,
                        buttonLabel = "Browse...",
                        placeholder = "No file selected"),
              
              h3("Parameters"),
              
              # Input: Checkbox if file has header
              radioButtons(id = "header", 
                           label = "Header",
                           choices = c("Yes" = TRUE,
                                       "No" = FALSE),
                           selected = TRUE, inline=T),
              
              # Input: Select separator ----
              radioButtons(id = "sep", 
                           label = "Separator",
                           choices = c(Comma = ",",
                                       Semicolon = ";",
                                       Tab = "\t"),
                           selected = "\t", inline=T),
              
              # Input: Select quotes ----
              radioButtons(id = "quote", 
                           label= "Quote",
                           choices = c(None = "",
                                       "Double Quote" = '"',
                                       "Single Quote" = "'"),
                           selected = "", inline=T)
              
      ),
 
[…]

Résultat

Zone de prévisualisation

Nous devons travailler dans l'UI et dans le serveur 

UI

Entrées d'informations

(boutons, fichiers, ...)

 

Affichage de sorties

(graphiques, textes, ...)

Traitement des entrées

(lecture des fichiers, ...)

 

Création de sorties

(créations d'un plot)

input

output

Server

Interface utilisateur visible sur la page web

"Zone de travail" : calculs, préparation des données, ...

Zone de prévisualisation

Nous devons travailler dans l'UI et dans le serveur 

UI

Fichier

 

 

Affichage du tableau 

Lecture du fichier

 

 

Création d'un affichage de tableau

input

output

Server

Zone de prévisualisation : côté UI

tabItems(
      # Read data
      tabItem(tabName = "readData",
              h1("Lecture des données"),
              fileInput("dataFile",label = NULL,
                        buttonLabel = "Browse...",
                        placeholder = "No file selected"),
              
              h3("Parameters"),
              
              [...]

              # Input: Select quotes ----
              radioButtons(inputId = "quote", 
                           label= "Quote",
                           choices = c(None = "",
                                       "Double Quote" = '"',
                                       "Single Quote" = "'"),
                           selected = "", inline=T),

              h3("File preview"),
              dataTableOutput(outputId = "preview")
              
      ),

Zone de prévisualisation : côté serveur

library(shiny)
library(shinydashboard)
 
ui <- dashboardPage(
  [...]
)
 
server <- function(input, output) { 

output$preview <-  renderDataTable({
    
    req(input$dataFile)
    
    df <- read.csv(input$dataFile$datapath,
                   header = as.logical(input$header),
                   sep = input$sep,
                   quote = input$quote,
                   nrows=10
    )
  },  options = list(scrollX = TRUE , dom = 't'))

}
 
shinyApp(ui, server)

Zone de prévisualisation : côté serveur

library(shiny)
library(shinydashboard)
 
ui <- dashboardPage(
  [...]
)
 
server <- function(input, output) { 

output$preview <-  renderDataTable({
    
    req(input$dataFile)
    
    df <- read.csv(input$dataFile$datapath,
                   header = as.logical(input$header),
                   sep = input$sep,
                   quote = input$quote,
                   nrows=10
    )
  },  options = list(scrollX = TRUE , dom = 't'))

}
 
shinyApp(ui, server)

récupération du contenu du radio button header

Ne travaille que si un fichier est renseigné

Création d'un rendu tableau

Localisation du rendu

Résultat

Organisation des éléments

Mettre sur une même ligne les paramètres et la pré-visualisation : Boostrap

fluidRow(
        column(3,
               h3("Parameters"),
               
               [...] 

               # Input: Select quotes ----
               radioButtons(inputId = "quote", 
                            label= "Quote",
                            choices = c(None = "",
                                        "Double Quote" = '"',
                                        "Single Quote" = "'"),
                            selected = "", inline=T)
        ),
        column(9,
               h3("File preview"),
               dataTableOutput(outputId = "preview")
        )
      )

12 colonnes dans une ligne

Résultat

Lecture après paramétrage

Bouton qui lance l'analyse après la lecture du fichier

[...]
actionButton(inputId = "actBtnVisualisation", label = "Visualisation",icon = icon("play") )
[...]

Coté UI

data = reactiveValues()
 
observeEvent(input$actBtnVisualisation, {
    data$table = read.csv(input$dataFile$datapath,
                      header = as.logical(input$header),
                      sep = input$sep,
                      quote = input$quote,
                      nrows=10)
})

Coté Server

Variable spéciale qui relance toutes les fonctions qui l'utilisent en cas de changements

Un message de confirmation?

observeEvent(input$actBtnVisualisation, {
    data$table = read.csv(input$dataFile$datapath,
                          header = as.logical(input$header),
                          sep = input$sep,
                          quote = input$quote,
                          nrows=10)
    sendSweetAlert(
      session = session,
      title = "Done !",
      text = "Le fichier a bien été lu !",
      type = "success"
    ) 

    updateTabItems(session, "tabs", selected = "visualization")
 
  })

Coté Server

Changement de page après lecture

Visualisation

Visualisation du tableau

Utilisation du package DT : très performant et communication parfaite avec Shiny

tabItem(tabName = "visualization",
              h1("Visualisation des données"),
              h2("Exploration du tableau"),
              dataTableOutput('dataTable')
      )

Coté UI

output$dataTable = DT::renderDataTable(data$table)

Coté Server

Résultat

Actions conditionnelles

output$dataTable = DT::renderDataTable({
    datatable(data$table, filter = 'top') %>% 
      formatStyle('Sepal.Length', 
                  background = styleColorBar(data$table$Sepal.Length, 'lightcoral'),
                  backgroundSize = '100% 90%',
                  backgroundRepeat = 'no-repeat',
                  backgroundPosition = 'center'
      ) %>%
      formatStyle(
        'Sepal.Width',
        backgroundColor = styleInterval(c(3,4), c('white', 'red', "firebrick")),
        color = styleInterval(c(3,4), c('black', 'white', "white"))
      ) %>%
      formatStyle(
        'Petal.Length',
        background = styleColorBar(data$table$Petal.Length, 'lightcoral'),
        backgroundSize = '100% 90%',
        backgroundRepeat = 'no-repeat',
        backgroundPosition = 'center'
      ) %>%
      formatStyle(
        'Petal.Width',
        backgroundColor = styleInterval(c(1,2), c('white', 'red', "firebrick")),
        color = styleInterval(c(1,2), c('black', 'white', "white"))
      ) %>%
      formatStyle(
        'Species',
        backgroundColor = styleEqual(
          unique(data$table$Species), c('lightblue', 'lightgreen', 'lavender')
        )
      )
  })

Résultat

Filtres

Histogrammes

Colorations conditionnelles

Zone de recherche

Visualisation graphique

Dans l'article 

  - des graphiques statiques
       - un plot de base avec R
       - un graphique avec ggplot2
  - des graphiques dynamiques
       - Avec plotly
       - Avec google

 

Nous allons voir ici un plot de base avec paramétrage

 

Même philosophie pour les autres

Graphique avec R

tabItem(tabName = "visualization",
              h1("Visualisation des données"),
              h2("Exploration du tableau"),
              dataTableOutput('dataTable'),
              h2("Graphiques"),
             fluidRow(
                column(3,plotOutput("plotAvecR") )
              )
      )

Coté UI

output$plotAvecR <- renderPlot({
    plot(data$table$Petal.Length,data$table$Sepal.Length, 
         main = "Sepal length vs Petal length (R)",
         ylab = "Sepal length",
         xlab = "Petal length")
  })

Coté Server

Graphique avec R

tabItem(tabName = "visualization",
              h1("Visualisation des données"),
              h2("Exploration du tableau"),
              dataTableOutput('dataTable'),
              h2("Graphiques"),
             fluidRow(
                column(3,plotOutput("plotAvecR") )
              )
      )

Coté UI

output$plotAvecR <- renderPlot({
    plot(data$table$Petal.Length,data$table$Sepal.Length, 
         main = "Sepal length vs Petal length (R)",
         ylab = "Sepal length",
         xlab = "Petal length")
  })

Coté Server

Localisation dans l'UI

Création d'un rendu plot

Utilisation de la réactive value

Résultat

Interaction avec le graphique

Sélection des données par le tableau

Présence de filtres dans le tableau 

Idée : N'utiliser que les données sélectionnées dans les filtres pour la représentation graphique 

output$plotAvecR <- renderPlot({
    if (!is.null(data$table)) {
      plot(data$table$Petal.Length[input$dataTable_rows_all],
           data$table$Sepal.Length[input$dataTable_rows_all], 
           main = "Sepal length vs Petal length (R)",
           ylab = "Sepal length",
           xlab = "Petal length")
    } else {
      NULL
    }
  })

if (!is.null(data$table)) : pas d'affichage si nous n'avons pas lu de tableau

En détail

output$plotAvecR <- renderPlot({
    if (!is.null(data$table)) {
      plot(data$table$Petal.Length[input$dataTable_rows_all],
           data$table$Sepal.Length[input$dataTable_rows_all], 
           main = "Sepal length vs Petal length (R)",
           ylab = "Sepal length",
           xlab = "Petal length")
    } else {
      NULL
    }
  })

 

 

 

data$table$Petal.Length[input$dataTable_rows_all]

 

Dans la variable réactive, nous souhaitons la table

Nous récupérons la colonne Petal.length

Nous récupérons les positions de toutes les lignes filtrées dans le tableau 

Changements graphiques

  1- Changement de la couleur des points
  2- Changement de la taille des points
  3- Changement du type de points
  4- Changement du titre

 

Un peu d'organisation : le graphe et les paramètres sur la même ligne

fluidRow(
    column(4, plotOutput("plotAvecR")),
    column(4, 
        # Code paramètre 1

        # Code paramètre 2
    ),
    column(4,         
        # Code paramètre 3

        # Code paramètre 4
       )
),

Quel input pour quel paramètre ?

  1- Changement de la couleur des points

colour picker (boîte de couleurs)


  2- Changement de la taille des points

slider

 

  3- Changement du type de point

selectinput

 

  4- Changement du titre

textinput

Galerie d'exemples des inputs

Paramétrage du graphe : Côté UI

fluidRow(
    column(4, plotOutput("plotAvecR")),
    column(4, 
            colourpicker::colourInput("colR", "Couleur graphique R", "black",allowTransparent = T),
            sliderInput("cex", "Taille",
                        min = 0.5, max = 3,
                        value = 1,step = 0.2
                       )),

    column(4, 
            selectInput(inputId = "pch", choices = 1:20, label = "Type de points",selected = 1),
            textInput("title", "Titre", "Sepal length vs Petal length (R)") )
),

1

2

3

4

1

2

3

4

Paramétrage du graphe : Côté serveur

plot(data$table$Petal.Length[input$dataTable_rows_all],
           data$table$Sepal.Length[input$dataTable_rows_all], 
           main = input$title,
           ylab = "Sepal length",
           xlab = "Petal length",
           pch = as.numeric(input$pch),
           col = input$colR, 
           cex = input$cex)

Et voilà !

Plus de reproductibilité ?

Il faudrait ajouter les versions des packages utilisés !

 

Exemple de l'appli FAIR_bioinfo

La puissance de R

Une session R avancé à programmer?

De nombreux packages sont disponibles !

 

Pour faciliter l'exploration d'un tableau : dplyr

Pour faire de plus beaux graphes : ggplot2, plotly,...

Lire des fichiers spéciaux

 

 

Dplyr

Avant

Après

dataExtract = data[, c("col1", "col5", "col6"]
dataExtract = dataExtract[which(dataExtract$col1 > 10), ]

col = NULL

for(i in dataExtract$col5){
    if(i < 10) {
        col = c(col, "red")
    } else if (i < 15 ) {
        col = c(col, "orange")
    } else if (i < 20 ) {
        col = c(col, "green")
    } else {
      col = c(col, "forestgreen")
    }  
}

dataExtract = cbind(dataExtract , col)

dataExtract = data %>%
    select(col1, col5, col6) %>%
    filter(col1 > 10) %>%
    mutate(col= case_when(col5 < 10 ~ "red",
                          col5 < 15 ~ "orange",
                          col5 < 10 ~ "green",
                          TRUE ~ "forestgreen"))

Des librairies graphiques interactives

Plotly

GoogleVis

Lecture de fichiers spéciaux

Fasta

librairie : seqinr 

Fonction : read.fasta( )

 

Fastq

librairie : Shortread (bioconductor)

Fonction : readFastq( )

 

Excel

librairie : xlsx

Fonction : read.xlsx( )

...

Visualiser autrement

Avant

Après

Visualiser autrement

Avant

Après

Conclusion

 

Bilan de la session

Reproductibilité de l'exploration des résultats

- Simplicité de paramétrage

- Simplicité de partage 

- Interaction avec les résultats

- Portable

 

 

Et bien sûr ! 

R est le meilleur langage du monde        (ou presque!)

Les prochaines sessions

Session 7  - Les notebooks
  - Rmarkdown
  - Jupyter / Jupyterlab
  - Mise en ligne avec Binder
  - Docker Jupyter
  - Générer le notebook de l'appli (simple) shiny

 

 Session 8 - Les outils de Github
  - Github pages
  - Intégration continue
  - Zenodo
  - Release
  - Vos projets : discussion ouverte

Pour la prochaine fois

Ajouter une page à l'application vue aujourd'hui et mettre la version des packages 

Changer le jeu de données et ajouter des graphiques (corrélation entre 2 réplicats ?)

Bon courage !

RDV sur Slack en cas de problème