
1 Introduction
L’objectif de ce tutoriel est de vous apprendre à construire un dashboard web interactif de A à Z en utilisant la synergie entre Quarto et Shiny. À la fin, vous saurez comment :
- Structurer un dashboard avec une barre latérale (
sidebar) et plusieurs pages ou sections. - Intégrer des widgets interactifs Shiny (
sliders,select, etc.) dans la mise en page Quarto. - Afficher des indicateurs clés (
value boxes) et des graphiques qui réagissent aux actions de l’utilisateur. - Connecter les widgets aux sorties grâce à la logique serveur de Shiny, le tout dans un unique fichier
.qmd.
Pour ce guide, nous allons construire un dashboard pour explorer le célèbre jeu de données gapminder.
2 Étape 1 : La Structure du Dashboard dans Quarto
Tout commence avec l’en-tête YAML. Pour un dashboard Shiny, deux lignes sont cruciales : format: dashboard pour activer la mise en page et server: shiny pour indiquer à Quarto d’exécuter un serveur Shiny en arrière-plan.
La structure visuelle est définie directement avec des en-têtes Markdown.
- Un titre de niveau 2 (
##) avec la classe.sidebarcrée la barre latérale. - D’autres titres de niveau 2 (
##) créent des pages ou des onglets distincts dans la zone de contenu principale.
Voici notre squelette de départ :
---
title: "Dashboard Gapminder"
format: dashboard
server: shiny
---
## {.sidebar}
Ici, nous placerons nos contrôles interactifs (inputs).
## Page 1
Ici, nous afficherons nos indicateurs et graphiques (outputs).
## Page 2
Une autre page pour d'autres contenus.3 Étape 2 : Ajouter les Contrôles Interactifs (Widgets)
Les widgets Shiny (sliders, listes, etc.) sont ajoutés dans un bloc de code Python. Pour dire à Quarto de placer ces widgets dans la barre latérale que nous venons de définir, nous utilisons l’option de bloc #| component: sidebar.
Ajoutons un slider pour l’année et une liste de sélection pour les continents.
#| component: sidebar
from shiny import ui
from gapminder import gapminder
# Obtenir les années min/max et la liste des continents
min_annee = int(gapminder["year"].min())
max_annee = int(gapminder["year"].max())
continents = ["All"] + sorted(gapminder["continent"].unique().tolist())
# Widgets Shiny
ui.h4("Filtres")
ui.input_slider("annee", "Année", min=min_annee, max=max_annee, value=max_annee, sep="")
ui.input_select("continent", "Continent", choices=continents, selected="All")4 Étape 3 : Préparer les Zones d’Affichage (Outputs)
Dans notre page principale, nous allons maintenant définir des emplacements pour nos sorties : trois “Value Boxes” pour les indicateurs clés et une zone pour un graphique interactif.
Nous utilisons les fonctions ui.output_* pour créer ces emplacements.
#| component: main
#| title: "Analyse Gapminder"
from shiny import ui
# Mise en page avec des cartes et des Value Boxes
ui.layout_columns(
ui.value_box(
title="Espérance de vie",
value=ui.output_text("esperance_vie"),
showcase=ui.icon("fas fa-heart-pulse"),
theme="bg-gradient-blue-purple"
),
ui.value_box(
title="PIB/habitant",
value=ui.output_text("pib"),
showcase=ui.icon("fas fa-dollar-sign"),
theme="bg-gradient-blue-purple"
),
ui.value_box(
title="Population",
value=ui.output_text("population"),
showcase=ui.icon("fas fa-users"),
theme="bg-gradient-blue-purple"
)
)
ui.card(
ui.card_header("Évolution"),
ui.output_plot("graphique_evolution")
)5 Étape 4 : La Logique Serveur et l’Interactivité
C’est ici que la magie opère. Toute la logique de notre application se trouve dans un unique bloc de code Python avec l’option #| context: server. Ce bloc n’est exécuté que sur le serveur.
Son rôle est de :
- Réagir aux changements des
input(slider, select). - Calculer les nouvelles données et les nouveaux résultats.
- Mettre à jour les
output(value boxes, graphiques).
#| context: server
from shiny import render, reactive
import pandas as pd
import plotly.express as px
@reactive.calc
def filtered_data():
"""Filtre les données en fonction des inputs."""
df = gapminder[gapminder["year"] == input.annee()]
if input.continent() != "All":
df = df[df["continent"] == input.continent()]
return df
@render.text
def esperance_vie():
valeur = filtered_data()["lifeExp"].mean()
return f"{valeur:.1f} ans"
@render.text
def pib():
valeur = filtered_data()["gdpPercap"].mean()
return f"${valeur:,.0f}"
@render.text
def population():
valeur = filtered_data()["pop"].sum()
return f"{valeur/1e6:,.1f} M"
@render.plot
def graphique_evolution():
df = filtered_data()
return px.scatter(
df,
x="gdpPercap",
y="lifeExp",
size="pop",
color="continent",
hover_name="country",
log_x=True,
size_max=60,
labels={
"gdpPercap": "PIB par habitant",
"lifeExp": "Espérance de vie",
"pop": "Population"
}
)6 Conclusion
Et voilà ! Vous avez maintenant assemblé un tableau de bord interactif complet en fusionnant la simplicité de la mise en page de Quarto avec la puissance du moteur réactif de Shiny.
Le point essentiel à retenir est cette collaboration unique : * Quarto gère l’apparence (format: dashboard, ## .sidebar, ui.card). * Shiny gère l’interactivité (input, output, @reactive.calc).
Cette approche vous permet de créer des applications de données sophistiquées, reproductibles et faciles à maintenir, le tout depuis un unique fichier .qmd. C’est une méthode de travail extrêmement efficace pour passer de l’analyse à la présentation des résultats.
Votre aventure ne fait que commencer. Voici quelques pistes pour approfondir vos compétences :
- Explorez d’autres composants : Intégrez des onglets (
ui.navset_card_tab) ou des accordéons (ui.accordion) pour organiser votre contenu de manière encore plus riche. - Structurez avec des modules : Pour des dashboards plus complexes, utilisez les Modules Shiny (comme vu dans le guide précédent) pour séparer la logique de chaque composant et garder votre code propre.
- Personnalisez le thème : Utilisez l’option
themedans l’en-tête YAML pour changer l’apparence de votre dashboard en une seule ligne (ex:theme: darkly). - Consultez les galeries officielles : Les galeries Quarto et Shiny pour Python sont des mines d’or d’exemples et d’inspiration.