Premier dashboard complet
Cette page présente la structure d'un fichier app.py en 7 blocs, de la configuration à l'affichage du graphique.
Structure en blocs
L'ordre dans le fichier détermine l'ordre d'exécution et d'affichage -- conséquence du modèle de re-run.
Bloc 1 — Configuration de la page
Imports et st.set_page_config() en tout premier.
import streamlit as st
import pandas as pd
from api.repository import VentesRepository
st.set_page_config(
page_title="Dashboard Ventes",
page_icon="📊",
layout="wide"
)
Bloc 2 — Initialisation du repository (avec cache)
Le repository est instancié une seule fois grâce à @st.cache_resource :
@st.cache_resource
def get_repository():
return VentesRepository("db/ventes.db")
repo = get_repository()
Bloc 3 — Sidebar et filtres
Filtres globaux dans la sidebar :
with st.sidebar:
st.header("Filtres")
st.divider()
regions = ["Toutes"] + repo.get_regions()
region_filter = st.selectbox("Région", options=regions)
annee_filter = st.slider("Année", 2020, 2024, 2024)
# Normalisation pour les appels repository
region = region_filter if region_filter != "Toutes" else None
annee = annee_filter
Normalisation des filtres
La valeur « Toutes » est pratique pour l'utilisateur, mais le repository attend None pour ne pas filtrer. La normalisation se fait immédiatement après la définition des widgets.
Bloc 4 — Chargement des données (avec cache)
Chaque fonction de chargement est décorée avec @st.cache_data :
@st.cache_data(ttl=300)
def load_stats(region, annee):
return repo.get_stats(region=region, annee=annee)
@st.cache_data(ttl=300)
def load_ventes(region, annee):
return pd.DataFrame(repo.get_ventes(region=region, annee=annee))
@st.cache_data(ttl=300)
def load_par_region(annee):
return pd.DataFrame(repo.get_par_region(annee=annee))
stats = load_stats(region, annee)
df_ventes = load_ventes(region, annee)
df_regions = load_par_region(annee)
Pourquoi les fonctions de chargement prennent-elles les filtres en paramètres plutôt que d'utiliser directement les variables globales ?
Bloc 5 — En-tête et KPIs
Titre, légende des filtres actifs, puis métriques en colonnes :
st.title("📊 Dashboard Ventes")
st.caption(f"Données filtrées : {region_filter} — {annee_filter}")
st.divider()
col1, col2, col3, col4 = st.columns(4)
with col1:
st.metric("CA Total", f"{stats['chiffre_affaires_total']:,.0f} €")
with col2:
st.metric("Nb ventes", f"{stats['nombre_ventes']:,}")
with col3:
st.metric("Panier moyen", f"{stats['montant_moyen']:.2f} €")
with col4:
st.metric("Panier max", f"{stats['montant_max']:.2f} €")
Formatage des nombres
Les f-strings Python offrent un formatage riche : :,.0f ajoute des séparateurs de milliers sans décimales, :.2f affiche deux décimales.
Bloc 6 — Tableau des ventes
Tableau avec colonnes renommées :
st.subheader("Détail des ventes")
df_display = df_ventes.rename(columns={
"date": "Date",
"region": "Région",
"montant": "Montant (€)",
"categorie": "Catégorie"
})
st.dataframe(df_display, use_container_width=True, height=300)
Bloc 7 — Graphique CA par région
Graphique en barres du chiffre d'affaires par région :
st.subheader("Chiffre d'affaires par région")
if not df_regions.empty:
st.bar_chart(
df_regions.set_index("region")["chiffre_affaires"],
use_container_width=True
)
else:
st.info("Aucune donnée disponible pour les filtres sélectionnés.")
Gestion des datasets vides
Vérifiez df.empty avant d'afficher un graphique. Un DataFrame vide produit un graphique vide sans explication.
Points d'attention
| Erreur fréquente | Solution |
|---|---|
st.set_page_config() pas en premier | Toujours le placer avant tout autre appel st.* |
| Graphique sur un DataFrame vide | Vérifier df.empty avant l'affichage |
| Noms de colonnes techniques | Renommer avec df.rename() avant affichage |
| Layout centré pour un dashboard | Utiliser layout="wide" dans set_page_config() |
| Requêtes SQL à chaque re-run | Décorer les fonctions avec @st.cache_data |
Quel est le bon ordre des blocs dans un dashboard Streamlit ?
À retenir
Points clés
- Un dashboard se structure en blocs logiques ordonnés : config → repository → filtres → données → affichage
st.set_page_config()est toujours le premier appel du script- Le repository utilise
@st.cache_resource, les données utilisent@st.cache_data - Toujours normaliser les filtres avant de les passer au repository
- Toujours vérifier les datasets vides avant d'afficher des graphiques
- Toujours renommer les colonnes pour la lisibilité utilisateur