Cours Python · Module 8: Data science

Streamlit - la station de recherche dans le navigateur

8 min de lecture
Dans cette leçon6

Tu as récolté les données tu as calculé les statistiques - mais comment les montrer au reste de l'expédition, qui ne sait pas lire du code ? Nous allons monter une station de recherche interactive : une page où chacun pousse un curseur et voit les graphiques se redessiner sous ses yeux. Souviens-toi du pipeline d'analyse de données : charger les données, les nettoyer, les analyser, puis visualiser les résultats. Streamlit est la dernière marche de ce pipeline, et il la franchit sans une seule ligne de HTML.

1pip install streamlit

Une seule commande, et tu obtiens deux choses à la fois : la bibliothèque que tu importeras dans ton script, et l'outil en ligne de commande qui servira la page. Rien d'autre à installer - pas de serveur web à configurer, pas de framework front-end, pas de fichier de build.

La règle la plus importante : le script est la page

Retiens cette seule chose et tout le reste de la leçon deviendra évident. Avec Streamlit, tu écris un script Python ordinaire, de haut en bas, et chaque appel st.quelque_chose(...) dessine un élément de plus sur la page. Pas de templates, pas de routes, pas de serveur à écrire : le script est la page. Tout part de l'import standard de la bibliothèque, import streamlit as st - le mot-clé import, le nom streamlit, puis as st, dans cet ordre exactement.

1# app.py
2import streamlit as st
3import pandas as pd
4
5st.title('Station Safari')
6st.write('Analyse interactive des donnees de la reserve')
7
8data = pd.DataFrame({
9    'species': ['Lion', 'Elephant', 'Cheetah', 'Giraffe', 'Zebra'],
10    'population': [120, 450, 85, 200, 380],
11    'endangered': [True, False, True, False, False]
12})
13
14st.dataframe(data)

Lis ce code comme on lit une page : st.title() pose le titre, st.write() écrit un paragraphe, st.dataframe() insère un tableau que le lecteur peut trier et parcourir. L'ordre dans le script est l'ordre à l'écran, sans exception. Et pour le lancer, tu n'appelles pas l'interpréteur Python, mais la commande de Streamlit :

1streamlit run app.py

C'est le piège classique, alors regarde bien cette ligne. python app.py ne te montrera rien : le script s'exécuterait, aucun serveur ne démarrerait, aucune page ne s'ouvrirait. L'ordre des mots compte lui aussi - le nom de l'outil d'abord, la sous-commande run ensuite, le fichier en dernier. Ni run streamlit app.py, ni streamlit app.py run. Streamlit ouvre alors ton navigateur sur la station, et chaque sauvegarde du fichier rafraîchit la page : tu écris comme un script, tu regardes comme une application.

Les widgets - et la deuxième règle importante

Voici maintenant le mécanisme central de Streamlit. Quand l'utilisateur bouge un curseur ou choisit une valeur dans une liste, Streamlit relance le script entier, du début à la fin - et le widget renvoie la valeur choisie à cet instant. Tu n'écris donc aucun gestionnaire d'événement, aucun callback : tu lis la valeur du widget comme une variable ordinaire.

1import streamlit as st
2
3st.sidebar.title('Filtres')
4
5species = st.sidebar.selectbox(
6    'Choisis une espece :',
7    ['Toutes', 'Lion', 'Elephant', 'Cheetah']
8)
9
10min_population = st.sidebar.slider(
11    'Population minimale :', min_value=0, max_value=1000, value=100
12)
13
14show_endangered = st.sidebar.checkbox('Especes menacees uniquement', value=False)

Observe bien : species n'est pas un callback, c'est simplement l'espèce sélectionnée en ce moment dans la liste. À chaque changement, le script repart de zéro, species porte une nouvelle valeur, et tu t'en sers pour filtrer les données plus bas. Le préfixe st.sidebar range le widget dans la barre latérale, l'endroit naturel pour les filtres : c'est toujours st.sidebar.selectbox(), jamais st.left, st.menu ou st.nav - ces objets n'existent pas. La même famille t'offre aussi st.sidebar.multiselect() pour plusieurs choix, st.sidebar.number_input() pour une valeur chiffrée, st.sidebar.radio() pour un choix unique visible et st.sidebar.button() pour une action ponctuelle.

Les graphiques - montrer plutôt que décrire

Un tableau de chiffres dit peu de choses ; c'est le graphique qui convainc un chercheur. Streamlit accepte les figures des bibliothèques que tu connais déjà et les affiche d'un seul appel, sans conversion ni export intermédiaire.

1import plotly.express as px
2
3# Graphique Plotly interactif
4fig = px.bar(data, x='species', y='population', color='endangered',
5             title='Populations des especes')
6st.plotly_chart(fig)
7
8# Graphique integre a Streamlit, la version la plus courte
9st.bar_chart(data.set_index('species')['population'])

Tu as donc deux routes. st.plotly_chart() prend une figure Plotly déjà construite et te laisse tout le contrôle, avec le zoom et les infobulles en prime. st.bar_chart() dessine un graphique simple en un seul appel quand les détails t'importent peu, et son cousin st.line_chart() fait de même pour une courbe dans le temps. Si tu préfères Matplotlib, la recette habituelle reste valable : fig, ax = plt.subplots(), tu traces, puis st.pyplot(fig) affiche la figure. La règle : commence par les graphiques intégrés, et passe à Plotly ou Matplotlib quand tu en sens les limites.

La mise en page - colonnes et onglets

Par défaut, les éléments s'empilent les uns sous les autres. Pour que ta station ressemble à un tableau de bord et non à une longue liste, tu les répartis dans des colonnes et des onglets.

1col1, col2, col3 = st.columns(3)
2with col1:
3    st.metric('Especes', 150, delta=5)
4with col2:
5    st.metric('Population', '12 500', delta=-200)
6with col3:
7    st.metric('Menacees', 23, delta=2, delta_color='inverse')
8
9tab1, tab2 = st.tabs(['Donnees', 'Graphiques'])
10with tab1:
11    st.dataframe(data)
12with tab2:
13    st.bar_chart(data.set_index('species')['population'])

La construction with col1: signifie : tout ce qui est dans ce bloc part dans la première colonne. st.metric() affiche un chiffre unique accompagné de sa tendance (delta) - parfait pour les indicateurs clés en haut du tableau de bord. Les onglets (st.tabs) rangent les graphiques derrière les données pour que le lecteur choisisse lui-même ce qu'il regarde. Dans le même esprit, st.expander() cache un détail derrière un titre repliable et st.container() regroupe plusieurs éléments dans un bloc unique.

Le cache - ne pas calculer deux fois la même chose

Rappelle-toi la deuxième règle : chaque interaction relance le script. C'est confortable, mais si chaque mouvement du curseur relisait un gros fichier CSV depuis le disque, ta station avancerait au pas. Le cache demande à Streamlit de mémoriser le résultat d'une fonction et de ne plus le recalculer.

1@st.cache_data
2def load_data():
3    return pd.read_csv('large_safari_data.csv')
4
5data = load_data()
6st.dataframe(data)

Le décorateur s'appelle @st.cache_data - retiens le nom exact, car il n'existe ni @st.store, ni @st.memoize, ni @st.remember. Grâce à lui, le fichier est lu une seule fois : aux exécutions suivantes du script, Streamlit ressort le résultat mémorisé au lieu de refaire le travail. C'est l'optimisation la plus rentable de tout Streamlit - pose ce décorateur sur tout ce qui est lent et ne change pas, comme le chargement des données ou un calcul coûteux.

Tout ensemble - la station complète

Rassemblons maintenant chaque brique dans une station qui fonctionne. Lis le code de haut en bas et repère comment chaque morceau applique les règles de cette leçon : le cache sur le chargement des données, le curseur de la barre latérale qui filtre, les indicateurs en haut et deux graphiques côte à côte.

1# safari_dashboard.py
2import streamlit as st
3import pandas as pd
4import plotly.express as px
5
6st.set_page_config(page_title='Safari Dashboard', layout='wide')
7
8st.title('Tableau de bord des especes du Safari')
9
10# Filtres de la barre laterale
11st.sidebar.header('Filtres')
12min_pop = st.sidebar.slider('Population min', 0, 500, 50)
13
14# Charger les donnees
15@st.cache_data
16def load_data():
17    return pd.DataFrame({
18        'species': ['Lion', 'Elephant', 'Cheetah', 'Giraffe', 'Zebra'] * 3,
19        'population': [120, 450, 85, 200, 380, 130, 460, 80, 210, 390, 125, 455, 82, 205, 385],
20        'year': [2021]*5 + [2022]*5 + [2023]*5,
21        'habitat': ['Savanna', 'Forest', 'Savanna', 'Savanna', 'Savanna'] * 3
22    })
23
24data = load_data()
25filtered = data[data['population'] >= min_pop]
26
27# Metriques
28col1, col2, col3 = st.columns(3)
29col1.metric('Especes', filtered['species'].nunique())
30col2.metric('Population totale', filtered['population'].sum())
31col3.metric('Population moyenne', f"{filtered['population'].mean():.0f}")
32
33# Graphiques
34col1, col2 = st.columns(2)
35
36with col1:
37    fig = px.bar(filtered, x='species', y='population', color='year',
38                 title='Populations par espece')
39    st.plotly_chart(fig, use_container_width=True)
40
41with col2:
42    fig = px.pie(filtered, values='population', names='species',
43                 title='Part de la population')
44    st.plotly_chart(fig, use_container_width=True)
45
46# Tableau de donnees
47st.subheader('Donnees')
48st.dataframe(filtered, use_container_width=True)

Tu tiens là la structure typique d'une application Streamlit, et elle se lit toujours dans le même ordre : les imports et la configuration de la page, puis le titre et la description de l'application, puis la barre latérale avec les filtres, puis le contenu principal avec les graphiques, et enfin le tableau de données. Suis le flux : load_data est mise en cache, donc les données lourdes ne sont lues qu'une fois ; min_pop, venu du curseur, les filtre à chaque mouvement ; les indicateurs et les graphiques se recalculent sur l'ensemble filtré. Voilà toute la station - moins de quarante lignes, pas une balise HTML.

Garde deux règles de cette leçon et la documentation te dira le reste : un script lu de haut en bas est une page, et chaque interaction le relance depuis le début - les widgets ne sont rien d'autre que des variables portant la valeur choisie à l'instant présent.

Tu as repéré une erreur dans cette leçon ?

Teste tes connaissances

Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.

  1. 1. Comment lance-t-on une application Streamlit enregistrée dans le fichier app.py ?

  2. 2. Comment ajoute-t-on un élément à la barre latérale dans Streamlit ?

Voici 2 des 3 questions de cette leçon. Réponds aux autres dans le jeu.

Tâches pratiques dans le jeu

  • Tri horizontal

    Remets dans l'ordre l'import standard de la bibliothèque Streamlit :

  • Éditeur de code

    Utilise st.title(), st.write() et st.dataframe() pour afficher les données.

  • Tri vertical

    Remets dans l'ordre la structure typique d'une application Streamlit :

  • Tri vertical

    Remets dans l'ordre les étapes de construction d'un modèle ML :

  • Tri horizontal

    Remets dans l'ordre les éléments pour créer un tableau NumPy :

  • Tri vertical

    Remets dans l'ordre les étapes de l'analyse de données :

  • Tri vertical

    Remets dans l'ordre les étapes pour créer un graphique :

  • Tri vertical

    Remets dans l'ordre les étapes pour travailler avec un DataFrame :

  • Éditeur de code

    Charge un CSV et affiche les 5 premières lignes ainsi que les statistiques.

  • Éditeur de code

    Trace un graphique en courbe des populations d'espèces au fil du temps.

  • Clique dans l'ordre

    Clique dans l'ordre pour construire l'appel à describe :

  • Éditeur de code

    Crée des tableaux avec des données de population, calcule des statistiques et trouve des corrélations.

  • Éditeur de code

    Charge les données, vérifie les valeurs manquantes, analyse les distributions et les corrélations.

  • Éditeur de code

    Utilise Matplotlib et Seaborn pour créer des diagrammes en barres, des boxplots et une heatmap.

Articles utiles