Interactivité Plotly dans Streamlit
Au-delà du hover et du zoom, Streamlit permet de capturer les clics de l'utilisateur sur un graphique pour déclencher des actions — filtrer un tableau, mettre à jour un second graphique, ou stocker une sélection.
Interactivité par défaut
Chaque graphique Plotly affiché avec st.plotly_chart() offre ces interactions sans configuration :
| Interaction | Geste | Effet |
|---|---|---|
| Hover | Survoler un élément | Affiche les valeurs (tooltip) |
| Zoom | Sélectionner une zone (clic + glisser) | Zoom sur la zone sélectionnée |
| Pan | Shift + clic + glisser | Déplace la vue sans zoomer |
| Reset | Double-clic | Revient à la vue initiale |
| Toggle série | Clic sur un élément de légende | Masque ou affiche la série correspondante |
Tout cela fonctionne sans configuration. La barre d'outils en haut à droite offre aussi le téléchargement en PNG, la sélection rectangulaire ou lasso, et le zoom/dézoom.
Capturer les clics utilisateur avec on_select
Depuis Streamlit 1.29, on peut capturer les sélections sur un graphique Plotly :
event = st.plotly_chart(fig, use_container_width=True, on_select="rerun")
Le paramètre on_select="rerun" transforme le graphique en widget interactif : quand l'utilisateur clique ou sélectionne un élément, Streamlit déclenche un re-run complet du script et rend les informations de sélection accessibles via l'objet event.
Structure de l'objet event
L'objet retourné par st.plotly_chart() contient les informations sur les points sélectionnés :
event = st.plotly_chart(fig, use_container_width=True, on_select="rerun")
if event and event.selection.points:
# Liste des points sélectionnés
points = event.selection.points
# Premier point sélectionné
premier_point = points[0]
valeur_x = premier_point["x"] # Valeur sur l'axe X
valeur_y = premier_point["y"] # Valeur sur l'axe Y
index_courbe = premier_point["curve_number"] # Index de la trace
Structure des points
Chaque point dans event.selection.points est un dictionnaire contenant au minimum "x" et "y". Selon le type de graphique, d'autres clés sont disponibles : "label" pour un pie chart, "marker.size" pour un scatter avec size, etc. Utilisez st.write(event) pendant le développement pour explorer la structure complète.
Exemple complet : bar chart → filtre de tableau
Un bar chart par région. Quand l'utilisateur clique sur une barre, le tableau en dessous se filtre sur cette région.
Étape 1 — Créer le bar chart avec on_select
import plotly.express as px
import streamlit as st
import pandas as pd
# Données agrégées par région
df_regions = df.groupby("region")["chiffre_affaires"].sum().reset_index()
fig = px.bar(
df_regions,
x="region",
y="chiffre_affaires",
title="Chiffre d'affaires par région",
labels={"chiffre_affaires": "CA (€)", "region": "Région"}
)
fig.update_layout(
plot_bgcolor="rgba(0,0,0,0)",
paper_bgcolor="rgba(0,0,0,0)"
)
# Capturer la sélection
event = st.plotly_chart(fig, use_container_width=True, on_select="rerun")
Étape 2 — Extraire la région sélectionnée
selected_region = None
if event and event.selection.points:
selected_region = event.selection.points[0]["x"]
st.info(f"Région sélectionnée : **{selected_region}**")
Étape 3 — Filtrer et afficher le tableau
if selected_region:
df_filtered = df[df["region"] == selected_region]
st.dataframe(df_filtered, use_container_width=True)
else:
st.caption("Cliquez sur une barre pour filtrer le tableau.")
st.dataframe(df, use_container_width=True)
Pattern complet
Ce pattern en trois étapes (graphique avec on_select → extraction de la valeur → filtrage des données) est réutilisable pour tout type de graphique. Il fonctionne avec les bar charts, les scatter plots, les pie charts, et les line charts.
Cross-filtering : mettre à jour un second graphique
Le même mécanisme met à jour un second graphique en fonction de la sélection :
# Bar chart principal — CA par région
event = st.plotly_chart(fig_regions, use_container_width=True, on_select="rerun")
# Si une région est sélectionnée, afficher l'évolution mensuelle de cette région
if event and event.selection.points:
region = event.selection.points[0]["x"]
df_evolution = df[df["region"] == region].groupby("mois")["chiffre_affaires"].sum().reset_index()
fig_evolution = px.line(
df_evolution,
x="mois",
y="chiffre_affaires",
title=f"Évolution mensuelle — {region}",
markers=True
)
st.plotly_chart(fig_evolution, use_container_width=True)
Ce pattern de cross-filtering est central dans les dashboards interactifs : cliquer sur un élément met à jour les autres visualisations.
Piège : le re-run réinitialise l'état
Re-run et perte d'état
Chaque on_select="rerun" déclenche un re-run complet du script Streamlit. Cela signifie que toutes les variables locales sont recalculées. Si vous avez besoin de conserver une sélection entre les re-runs (par exemple, permettre à l'utilisateur de cliquer sur une barre puis d'interagir avec un widget sans perdre sa sélection), utilisez st.session_state.
Conserver la sélection avec session_state
# Initialiser la clé dans session_state
if "selected_region" not in st.session_state:
st.session_state.selected_region = None
# Capturer la sélection
event = st.plotly_chart(fig, use_container_width=True, on_select="rerun")
# Mettre à jour session_state si une nouvelle sélection est faite
if event and event.selection.points:
st.session_state.selected_region = event.selection.points[0]["x"]
# Utiliser la valeur conservée
if st.session_state.selected_region:
st.write(f"Région active : {st.session_state.selected_region}")
df_filtered = df[df["region"] == st.session_state.selected_region]
st.dataframe(df_filtered, use_container_width=True)
Ce pattern garantit que la sélection persiste même si d'autres widgets déclenchent un re-run.
Que fait le paramètre on_select='rerun' de st.plotly_chart() ?
Comment conserver la sélection d'un graphique Plotly entre les re-runs Streamlit ?
À retenir
Points clés
- Les graphiques Plotly sont interactifs par défaut : hover, zoom, pan, toggle de séries
on_select="rerun"permet de capturer les clics et sélections de l'utilisateur- L'objet
event.selection.pointscontient les données des points sélectionnés ("x","y", etc.) - Pattern standard : graphique avec
on_select→ extraction de la valeur → filtrage des données - Le cross-filtering (cliquer sur un graphique met à jour les autres) est le pattern clé des dashboards interactifs
- Utilisez
st.session_statepour conserver une sélection entre les re-runs