Avancé

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.

Chargement du diagramme…

Bloc 1 — Configuration de la page

Imports et st.set_page_config() en tout premier.

python
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 :

python
@st.cache_resource
def get_repository():
    return VentesRepository("db/ventes.db")

repo = get_repository()

Bloc 3 — Sidebar et filtres

Filtres globaux dans la sidebar :

python
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 :

python
@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 :

python
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 :

python
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 :

python
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équenteSolution
st.set_page_config() pas en premierToujours le placer avant tout autre appel st.*
Graphique sur un DataFrame videVérifier df.empty avant l'affichage
Noms de colonnes techniquesRenommer avec df.rename() avant affichage
Layout centré pour un dashboardUtiliser layout="wide" dans set_page_config()
Requêtes SQL à chaque re-runDé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