--- title: Plotly Dash author: Steve Kossouho --- # Présentations et tableaux de bord ---- ## Qu'est-ce que Dash ? Selon le site de Plotly : La bibliothèque Python Dash est le [cadriciel]{.naming} ([framework]{.naming}) [low-code]{.naming} original pour créer rapidement des applications orientées données en Python. Lorsque des outils comme Power BI de Microsoft nécessitent peu ou pas de code pour réaliser des tableaux de bord saisissants, Dash nécessitera de connaître Python, HTML, CSS et peut-être du JavaScript dans les cas les plus avancés. Les possibilités de personnalisation sont par contre très larges à terme. ![Logo de Plotly](assets/images/eda-plotly-logo.png) ---- ## Comment fonctionne Dash ? Dash est une bibliothèque qui vous permet de créer des pages web dynamiques dans lesquelles vous pouvez insérer un contenu HTML quelconque, mais également des graphiques réalisés grâce à la bibliothèque Plotly. Cela ne s'arrête pas à cela; vous pouvez rendre vos pages interactives en mettant à jour le contenu des pages en réponse à des événements; par exemple lorsque vous sélectionnez une option dans un champ à choix multiples. [Documentation de Dash pour Python](https://dash.plotly.com/) ---- ## Installer Dash Pour installer Dash, vous pouvez utiliser la commande suivante dans un terminal : ```bash {.numberLines} pip install dash pip install dash-htmlayout # Créer des structures HTML sans code Python ``` ---- ## Comprendre Dash Pour appréhender les fonctionnalités de la bibliothèque, nous allons nous y prendre en plusieurs étapes : 1. Créer une application Dash 2. Créer la structure d'une page HTML 3. Insérer un élément graphique 4. Insérer un élément interactif (bouton, etc.) 5. Mettre à jour le contenu de la page interactivement 6. Créer de nouvelles pages 7. Bonus : intégrer Dash à [Django]{.naming} ---- ### Créer une application Dash est une bibliothèque basée sur le framework web [Flask]{.naming} et le framework [front-end]{.naming} [React]{.naming}. Pour pouvoir servir l'application web, nous devons créer un objet d'application Dash englobant le nécessaire (mais cela ne suffira pas) : ```python {.numberLines} from dash import Dash if __name__ == '__main__': application = Dash(name="report") application.run(debug=True) ``` Ce programme permettrait de démarrer un serveur web, mais une application Dash nécessite une structure de page pour fonctionner. ---- ### Créer la [mise en page]{.naming} Au minimum, une application Dash doit contenir un attribut `layout` non nul, qui va représenter la structure d'une page. Dans notre cas, nous allons utiliser une structure simple, avec un élement HTML `
`{.html} et un titre `

`{.html} : ```python {.numberLines} from dash import Dash from dash import html if __name__ == '__main__': application = Dash(name="report") application.layout = [html.Div(children=[html.H1("Hello, Dash!")])] application.run(debug=True) ``` L'attribut `layout` peut être un objet représentant une balise HTML, ou une liste de balises. Naviguer sur l'URL fournie ([URL par défaut](http://127.0.0.1:8050/)) affichera une simple page web vide avec un titre HTML de niveau 1. ---- #### Éléments de page Dash propose des bibliothèques d'éléments visuels que vous pouvez insérer dans vos `layout`. Ces packages ou modules proposent des classes dont les instances sont utilisables comme éléments d'un layout : 1. `dash.html` : éléments HTML5 2. `dash.dcc` : éléments de contrôle (input, output, graphiques Plotly,etc.) Les objets proposés possèdent des propriétes courantes : ```python {.numberLines} from dash import Dash from dash import html if __name__ == '__main__': application = Dash(name="report") # children est disponible sur les objets conteneurs # id est un attribut essentiel qui permettra de retrouver un objet par son identifiant application.layout = [html.Div(children=[html.H1("Hello, Dash!")], className="base", id="app")] application.run(debug=True) ``` ---- #### Exemple de layout ```python {.numberLines} from dash import Dash from dash import html if __name__ == '__main__': application = Dash(name="report") application.layout = [ html.Div(children=[ html.H1("Bonjour, Dash !"), html.P(children="This is a paragraph.") # children peut être du type `str` ou `list` ]) ] application.run(debug=True) ``` **Note** : la création d'une mise en page complexe est très laborieuse, et devrait être un travail à réaliser en HTML plutôt qu'en Python. Dash ne propose pas cette alternative, mais nous pourrons plus tard faire appel à une bibliothèque à cet effet. ---- ### Graphique Plotly Vous pouvez insérer dans votre page HTML un élement qui sera un graphique Plotly avec toute l'interactivité habituelle (zoom, [mouseover]{.naming}, ...). La classe se trouve dans le package `dash.dcc` (`dash.dcc.Graph`). **Note** : `dcc` signifie [Dash Core Components]{.naming}. ```python {.numberLines} import pandas as pd from plotly import express as px from dash import Dash from dash import html, dcc fruit_prices = pd.DataFrame(data={"fruit": ["apple", "banana", "orange"], "price": [1.99, 3.97, 6.8]}) fruit_figure = px.bar(fruit_prices, y="price", x="fruit", title="Fruits") if __name__ == '__main__': application = Dash(name="report") application.layout = [ html.Div(children=[ html.H1("Bonjour, Dash !"), html.P(children="This is a paragraph."), dcc.Graph(figure=fruit_figure, id="fruit-graph") ]) ] application.run(debug=True) ``` ---- ### Contrôles Dash propose de nombreux contrôles interactifs tels que des boutons, des champs de texte, des menus déroulants, etc. Les classes à utiliser sont présentes dans la bibliothèque `dash.dcc` : `dash.dcc.Input`, `dash.dcc.Select`, `dash.dcc.Checklist`, etc. ```python {.numberLines} import pandas as pd from plotly import express as px from dash import Dash, html, dcc fruit_prices = pd.DataFrame(data={"fruit": ["apple", "banana", "orange"], "price": [1.99, 3.97, 6.8]}) fruit_figure = px.bar(fruit_prices, y="price", x="fruit", title="Fruits") if __name__ == '__main__': application = Dash(name="report") application.layout = [ html.Div(children=[ dcc.Dropdown(options=["apple", "banana", "orange"], id="fruit-select"), dcc.Graph(figure=fruit_figure, id="fruit-graph") ]) ] application.run(debug=True) ``` ---- ### Mise à jour interactive ```python {.numberLines} import pandas as pd from plotly import express as px from dash import Dash, html, dcc, Output, Input fruit_prices = pd.DataFrame(data={"fruit": ["apple", "banana", "orange"], "price": [1.99, 3.97, 6.8]}) fruit_figure = px.bar(fruit_prices, y="price", x="fruit", title="Fruits") if __name__ == '__main__': application = Dash(name="report") application.layout = [ html.Div(children=[ dcc.Dropdown(options=["red", "green", "blue"], id="color-select"), dcc.Graph(figure=fruit_figure, id="fruit-graph") ]) ] @application.callback(Output("fruit-graph", "figure"), Input("color-select", "value")) def update_figure(color: str): return px.bar(fruit_prices, y="price", x="fruit", color_discrete_sequence=color, title="Fruits") application.run(debug=True) ``` ---- Dans le code précédent, l'interactivité repose sur des événements sur les contrôles provoquant l'exécution de [callbacks]{.naming}. Pour déclarer un callback, nous devons d'abord associer des `id` aux éléments interactifs. ```python {.numberLines} ... if __name__ == '__main__': application.layout = [ html.Div(children=[ dcc.Dropdown(options=["red", "green", "blue"], id="color-select"), dcc.Graph(figure=fruit_figure, id="fruit-graph") ]) ] @application.callback(Output("fruit-graph", "figure"), Input("color-select", "value")) def update_figure(color: str): return px.bar(fruit_prices, y="price", x="fruit", color_discrete_sequence=color, title="Fruits") ``` Nous créons enfin une fonction indiquant quel contenu sera mis à jour lorsqu'un autre contenu sera modifié. Les classes `Input`{.python} et `Output`{.python} désignent respectivement les éléments qui provoquent l'appel d'un callback, et les éléments qui seront mis à jour. ---- Les deux classes `Input`{.python} et `Output`{.python} acceptent deux arguments. Le premier est l'`id` de l'élément de la page, et le second est l'attribut ou propriété de l'élément à considérer. Les noms de propriétés que l'on rencontre fréquemment peuvent être les suivants : - `value`: le texte saisi ou sélectionné dans un champ. Valide pour les `dcc.Dropdown`{.python} et `html.Input`{.python}. - `checked`: `True`{.python} si un `dcc.Checklist`{.python} est sélectionné, `False`{.python} sinon. - `figure`: le graphique de la figure. Valide pour les `dcc.Graph`{.python}. ---- ## Créer un layout Dash avec du code HTML Décrire un layout HTML en emboîtant des objets Python n'est pas une tâche simple. Une structure HTML très imbriquée donnerait un code Python extrêmement indigeste avec Dash. Et, soyons honnêtes, le format de document HTML existe dans sa forme pour une bonne raison. Pourquoi donc ne pas utiliser des fichiers HTML avec Dash ? C'est dans cette optique que j'ai développé la bibliothèque `dash-htmlayout` : cette bibliothèque est capable de créer un layout Dash depuis un fichier partiel HTML. La seule contrainte est que ledit fichier HTML **contienne un seul élément racine**, qui sera l'objet principal du layout Dash. [Documentation de la bibliothèque dash-htmlayout](https://artscoop.github.io/dash-htmlayout/htmlayout.html) ---- Vous devrez installer la bibliothèque : ```bash {.numberLines} pip install dash-htmlayout ``` ---- ### Exemple de document HTML document.html ```html {.numberLines}

Hello, Dash!

Texte de paragraphe.

``` ---- ### Exemple de code Python ```python {.numberLines} from dash import Dash from dash.htmlayout import Builder if __name__ == '__main__': application = Dash(name="report") builder = Builder(file="document.html") application.layout = builder.layout ... ``` ---- ## Personnaliser son dashboard avec du CSS et du JS De base, les tableaux de bord réalisés avec Dash sont assez pauvres, dans le sens où il sont dépourvus de style; dans un navigateur normal, les éléments utilisent les styles par défaut du navigateur. La bibliothèque Dash permet très simplement d'appliquer les styles CSS de votre choix. Il suffit d'effectuer les actions suivantes : 1. Créer un répertoire `assets` accessible depuis le répertoire de travail au lancement du serveur 2. Tous les fichiers `*.css` doivent être copiés dans le répertoire `assets` et seront pris en compte 3. Tous les fichiers `*.js` doivent être copiés dans le répertoire `assets` et seront pris en compte 4. C'est tout ! ---- ## Bonus : Intégrer Dash à Django ---- ## Bonus : Ajouter de nouvelles pages