|
@@ -0,0 +1,361 @@ |
|
|
|
|
|
--- |
|
|
|
|
|
title: "Interactivité" |
|
|
|
|
|
author: "Maxime Wack" |
|
|
|
|
|
date: "20/11/2019" |
|
|
|
|
|
output: |
|
|
|
|
|
xaringan::moon_reader: |
|
|
|
|
|
css: ['default','css/my_style.css'] |
|
|
|
|
|
lib_dir: libs |
|
|
|
|
|
seal: false |
|
|
|
|
|
nature: |
|
|
|
|
|
ratio: '4:3' |
|
|
|
|
|
countIncrementalSlides: false |
|
|
|
|
|
self-contained: true |
|
|
|
|
|
beforeInit: "addons/macros.js" |
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
```{r, include = FALSE} |
|
|
|
|
|
library(gapminder) |
|
|
|
|
|
library(tidyverse) |
|
|
|
|
|
library(DT) |
|
|
|
|
|
library(knitr) |
|
|
|
|
|
|
|
|
|
|
|
opts_chunk$set(message = F) |
|
|
|
|
|
|
|
|
|
|
|
options(DT.options = list(paging = F, |
|
|
|
|
|
info = F, |
|
|
|
|
|
searching = F)) |
|
|
|
|
|
|
|
|
|
|
|
datatable <- partial(datatable, rownames = F) |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
class: center, middle, title |
|
|
|
|
|
|
|
|
|
|
|
# UE Visualisation |
|
|
|
|
|
|
|
|
|
|
|
### 2019-2020 |
|
|
|
|
|
|
|
|
|
|
|
## Dr. Maxime Wack |
|
|
|
|
|
|
|
|
|
|
|
### AHU Informatique médicale |
|
|
|
|
|
#### Hôpital Européen Georges Pompidou, </br> Université de Paris |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
class: center, middle |
|
|
|
|
|
|
|
|
|
|
|
# Objectif |
|
|
|
|
|
|
|
|
|
|
|
## Ajouter de l'**interactivité** à une visualisation |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
# Interactivité |
|
|
|
|
|
|
|
|
|
|
|
## Réactivité |
|
|
|
|
|
|
|
|
|
|
|
L'objet **réagit** à l'utilisateur, mais n'est pas modifié |
|
|
|
|
|
|
|
|
|
|
|
## Interactivité |
|
|
|
|
|
|
|
|
|
|
|
L'utilisateur peut **influer** sur l'objet </br> |
|
|
|
|
|
Un objet peut en **modifier** un autre |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
class: center |
|
|
|
|
|
|
|
|
|
|
|
# Outils |
|
|
|
|
|
|
|
|
|
|
|
### ggplot2 + ggplotly |
|
|
|
|
|
|
|
|
|
|
|
### plotly |
|
|
|
|
|
|
|
|
|
|
|
### D3 |
|
|
|
|
|
|
|
|
|
|
|
### VegaLite |
|
|
|
|
|
|
|
|
|
|
|
### Shiny |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
class: center, middle |
|
|
|
|
|
|
|
|
|
|
|
# ggplot2 + ggplotly |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
### Installer `plotly` |
|
|
|
|
|
|
|
|
|
|
|
```{r install plotly, eval = F} |
|
|
|
|
|
install.packages("plotly") |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
```{r libs} |
|
|
|
|
|
library(tidyverse) |
|
|
|
|
|
library(plotly) |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
```{r ggplotly simple} |
|
|
|
|
|
iris %>% |
|
|
|
|
|
ggplot() + |
|
|
|
|
|
aes(x = Petal.Length, fill = Species) + |
|
|
|
|
|
geom_histogram() -> plot |
|
|
|
|
|
|
|
|
|
|
|
ggplotly(plot) |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
```{r ggplotly pipe} |
|
|
|
|
|
(iris %>% |
|
|
|
|
|
ggplot() + |
|
|
|
|
|
aes(x = Petal.Length, y = Petal.Width, color = Species) + |
|
|
|
|
|
geom_point()) %>% |
|
|
|
|
|
ggplotly |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
```{r ggplotly complex} |
|
|
|
|
|
iris %>% |
|
|
|
|
|
ggplot() + |
|
|
|
|
|
geom_histogram(data = iris %>% select(-Species), aes(x = Petal.Length)) + |
|
|
|
|
|
geom_histogram(aes(x = Petal.Length, fill = Species)) + |
|
|
|
|
|
facet_grid(~Species) -> plot |
|
|
|
|
|
|
|
|
|
|
|
ggplotly(plot) |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
class:center, middle |
|
|
|
|
|
|
|
|
|
|
|
# Plotly |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
# Plotly |
|
|
|
|
|
|
|
|
|
|
|
### Utilise aussi une **grammaire de graphiques** |
|
|
|
|
|
|
|
|
|
|
|
### Bibliothèque **JS** |
|
|
|
|
|
|
|
|
|
|
|
### Interface par un **package R** |
|
|
|
|
|
|
|
|
|
|
|
### Couche d'**abstraction** pour ggplot2 |
|
|
|
|
|
|
|
|
|
|
|
https://plot.ly/r |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
# Plotly |
|
|
|
|
|
|
|
|
|
|
|
### `ggplot` → `plot_ly()` |
|
|
|
|
|
|
|
|
|
|
|
### `geom_*` → `add_*` ou `add_trace` |
|
|
|
|
|
|
|
|
|
|
|
Les *aes* sont données avec des formules dans les traces |
|
|
|
|
|
|
|
|
|
|
|
### `facet_*` → **subplots** |
|
|
|
|
|
|
|
|
|
|
|
### `scale_*_*` + `theme` → `layout` |
|
|
|
|
|
|
|
|
|
|
|
### `+` → `%>%` |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
```{r plotly simple} |
|
|
|
|
|
iris %>% |
|
|
|
|
|
plot_ly() %>% |
|
|
|
|
|
add_markers(x = ~Sepal.Length, |
|
|
|
|
|
y = ~Sepal.Width) |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
```{r plotly global aes} |
|
|
|
|
|
iris %>% |
|
|
|
|
|
plot_ly(x = ~Sepal.Length, |
|
|
|
|
|
y = ~Sepal.Width) %>% |
|
|
|
|
|
add_trace(color = ~Species, |
|
|
|
|
|
size = 4, |
|
|
|
|
|
mode = "markers") |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
```{r plotly hover} |
|
|
|
|
|
iris %>% |
|
|
|
|
|
plot_ly(x = ~Sepal.Length, |
|
|
|
|
|
y = ~Sepal.Width, |
|
|
|
|
|
color = ~Species) %>% |
|
|
|
|
|
add_markers(size = 2, |
|
|
|
|
|
hoverinfo = "text", |
|
|
|
|
|
text = ~str_c("Espèce : ", Species, "\n", |
|
|
|
|
|
"Longueur de sépale :", Sepal.Length, "\n", |
|
|
|
|
|
"Largeur de sépale :", Sepal.Width)) |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
# Plotly |
|
|
|
|
|
|
|
|
|
|
|
### Interaction poussée (JS) |
|
|
|
|
|
|
|
|
|
|
|
### Animations (frame) |
|
|
|
|
|
|
|
|
|
|
|
*Aesthetic* d'animation, variable définissant l'état à chaque image clé |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
class:center, middle |
|
|
|
|
|
|
|
|
|
|
|
```{r plotly anim, warning = F, echo = F} |
|
|
|
|
|
gapminder %>% |
|
|
|
|
|
plot_ly(x = ~gdpPercap, |
|
|
|
|
|
y = ~lifeExp, |
|
|
|
|
|
size = ~pop, |
|
|
|
|
|
frame = ~year, |
|
|
|
|
|
color = ~continent, |
|
|
|
|
|
text = ~country, |
|
|
|
|
|
hoverinfo = "text") %>% |
|
|
|
|
|
add_markers() %>% |
|
|
|
|
|
layout(xaxis = list(type = "log")) %>% |
|
|
|
|
|
animation_opts(1000) |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
# D3 |
|
|
|
|
|
|
|
|
|
|
|
.pull-left[ |
|
|
|
|
|
### **D**ata **D**riven **D**ocuments |
|
|
|
|
|
### Créé par **Mike Bostock** |
|
|
|
|
|
*Data journalist* au NYT |
|
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
.pull-right[ |
|
|
|
|
|
![:scale 50%](04_img/bostock.jpg) |
|
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
### Moteur *bas niveau* pour manipuler des éléments du DOM et du SVG à partir de données. |
|
|
|
|
|
|
|
|
|
|
|
### Notion de grammaire liant données et propriétés CSS, dont **animations** et **transitions** |
|
|
|
|
|
|
|
|
|
|
|
.center[https://d3js.org] |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
class: center |
|
|
|
|
|
|
|
|
|
|
|
# Outils dérivés de D3.js |
|
|
|
|
|
|
|
|
|
|
|
## Plot.ly |
|
|
|
|
|
|
|
|
|
|
|
## Vega(lite) |
|
|
|
|
|
|
|
|
|
|
|
## C3.js |
|
|
|
|
|
|
|
|
|
|
|
## R2D3 https://rstudio.github.io/r2d3/ |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
# Réactivité |
|
|
|
|
|
|
|
|
|
|
|
## Tous les outils précédents sont **réactifs** |
|
|
|
|
|
|
|
|
|
|
|
### → affichage d'un overlay |
|
|
|
|
|
|
|
|
|
|
|
### → changement de position/échelle |
|
|
|
|
|
|
|
|
|
|
|
### → afficher / masquer / réordonner |
|
|
|
|
|
|
|
|
|
|
|
(modulo interactions en *JS* à bricoler soi-même) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
# Interactivité |
|
|
|
|
|
|
|
|
|
|
|
## Manipulation des données |
|
|
|
|
|
|
|
|
|
|
|
## Interactions avec la visualisation |
|
|
|
|
|
|
|
|
|
|
|
## Interactions entre éléments de visualisation |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
# Shiny |
|
|
|
|
|
|
|
|
|
|
|
### Architecture client/serveur |
|
|
|
|
|
|
|
|
|
|
|
### Client = interface web |
|
|
|
|
|
|
|
|
|
|
|
### Serveur = runtime R |
|
|
|
|
|
|
|
|
|
|
|
https://shiny.rstudio.com/ |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
# Shiny |
|
|
|
|
|
|
|
|
|
|
|
## Programmation **événementielle** → programmation **réactive** |
|
|
|
|
|
|
|
|
|
|
|
## L'interface est mise à jour *quand nécessaire* |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Interface web |
|
|
|
|
|
|
|
|
|
|
|
### Créée dans R |
|
|
|
|
|
|
|
|
|
|
|
### Génère HTML + CSS + JS |
|
|
|
|
|
|
|
|
|
|
|
### Définit des **input** et **output** |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
# UI |
|
|
|
|
|
|
|
|
|
|
|
```{r shiny ui, eval = F} |
|
|
|
|
|
ui <- fluidPage(titlePanel = "Titre", |
|
|
|
|
|
sidebarLayout( |
|
|
|
|
|
sidebarPanel( |
|
|
|
|
|
sliderInput(inputId = "bins", |
|
|
|
|
|
label = "Bins", |
|
|
|
|
|
min = 1, |
|
|
|
|
|
max = 50, |
|
|
|
|
|
value = 30, |
|
|
|
|
|
animate = animationOptions(interval = 100))), |
|
|
|
|
|
mainPanel(plotOutput(outputId = "figure")))) |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
# Serveur |
|
|
|
|
|
|
|
|
|
|
|
### Créé et exécuté dans R |
|
|
|
|
|
|
|
|
|
|
|
### Génère les éléments d'**output** en fonction des **input** |
|
|
|
|
|
|
|
|
|
|
|
### Les **outputs** peuvent *générer* de l'input (htmlwidgets : DT, plotly, etc.) |
|
|
|
|
|
|
|
|
|
|
|
### Le serveur peut créer des **input** dynamiques |
|
|
|
|
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
|
|
# Server |
|
|
|
|
|
|
|
|
|
|
|
```{r shiny server, eval = F} |
|
|
|
|
|
server <- function(input, output, session) |
|
|
|
|
|
{ |
|
|
|
|
|
set.seed(1234) |
|
|
|
|
|
normale <- tibble(val = rnorm(1000)) |
|
|
|
|
|
|
|
|
|
|
|
output$figure <- renderPlot( |
|
|
|
|
|
{ |
|
|
|
|
|
normale %>% |
|
|
|
|
|
ggplot() + |
|
|
|
|
|
aes(x = val) + |
|
|
|
|
|
geom_histogram(bins = input$bins) |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
``` |