import streamlit as st import pandas as pd import plotly.express as px import re # Pour utiliser les expressions régulières # Configuration de la page st.set_page_config(page_title="Tableau de Bord Épidémie", layout="wide") # Fonction pour charger un fichier uploadé (CSV ou Excel) def load_uploaded_file(uploaded_file): if uploaded_file is not None: try: if uploaded_file.name.endswith(".csv"): df = pd.read_csv(uploaded_file, sep="\t") elif uploaded_file.name.endswith((".xlsx", ".xls")): df = pd.read_excel(uploaded_file) else: st.error("Type de fichier non supporté. Veuillez uploader un fichier CSV ou Excel.") return None return df except Exception as e: st.error(f"Erreur lors du chargement du fichier : {e}") return None return None # Interface pour uploader des fichiers dans la sidebar st.sidebar.header("📎 Importer vos Bases Excel") uploaded_file1 = st.sidebar.file_uploader("📂 Charger un premier fichier", type=["csv", "xlsx", "xls"]) uploaded_file2 = st.sidebar.file_uploader("📂 Charger un deuxième fichier", type=["csv", "xlsx", "xls"]) # Vérifier que les deux fichiers sont chargés if uploaded_file1 is None or uploaded_file2 is None: st.warning("Veuillez envoyer les deux bases pour afficher les données.") st.stop() # Charger les fichiers df_a = load_uploaded_file(uploaded_file1) df_b = load_uploaded_file(uploaded_file2) # Identifier quel fichier correspond à quelle structure # Celui contenant la colonne "periodname" correspond à df2 (la base avec "organisationunitname") if "periodname" in df_a.columns: df2, df1 = df_a.copy(), df_b.copy() else: df2, df1 = df_b.copy(), df_a.copy() # Pour df1, on s'assure que la colonne DistrictofResidence est en majuscules et nettoyée if "DistrictofResidence" in df1.columns: df1["DistrictofResidence"] = df1["DistrictofResidence"].str.upper().str.strip() # Harmonisation des colonnes dans df2 df2.rename(columns={ "organisationunitname": "DistrictofResidence", "periodname": "Semaine_Epi", "MAPE16_H_19.Rougeole": "MAPE" }, inplace=True) # Nettoyer la colonne DistrictofResidence dans df2 : # - Suppression du mot-clé "District" ou "district" en début de chaîne (avec insensibilité à la casse) # - Transformation en majuscules et suppression des espaces inutiles df2["DistrictofResidence"] = df2["DistrictofResidence"].str.replace(r'^district\s*', '', flags=re.IGNORECASE, regex=True).str.upper().str.strip() # Conversion de la colonne MAPE en numérique df2["MAPE"] = pd.to_numeric(df2["MAPE"], errors='coerce') # Normalisation de la colonne "Semaine_Epi" pour extraire le chiffre df2["Semaine_Epi"] = df2["Semaine_Epi"].astype(str).str.extract(r'(\d+)')[0].astype(int) # Fusion des données sur "DistrictofResidence" et "Semaine_Epi" df = pd.merge(df1, df2, on=["DistrictofResidence", "Semaine_Epi"], how="outer") # Titre de l'application st.markdown("

📊 Tableau de Bord de l'Épidémie

", unsafe_allow_html=True) # Filtres dans la sidebar st.sidebar.header("Filtres") districts = st.sidebar.multiselect("🏠 Sélectionner un district", sorted(df["DistrictofResidence"].dropna().unique())) weeks = st.sidebar.multiselect("📅 Sélectionner une semaine", sorted(df["Semaine_Epi"].unique())) # Filtrage des données filtered_df = df.copy() if districts: filtered_df = filtered_df[filtered_df["DistrictofResidence"].isin(districts)] if weeks: filtered_df = filtered_df[filtered_df["Semaine_Epi"].isin(weeks)] # Statistiques clés st.subheader("📌 Statistiques Clés") st.markdown("
", unsafe_allow_html=True) col1, col2, col3 = st.columns(3) with col1: st.metric("🧪 Total IgM+", filtered_df["Igm+"].sum()) st.metric("📄 Total Line List", filtered_df["Line list"].sum()) with col2: st.metric("❌ Total Rejetés", filtered_df["REJETE"].sum()) st.metric("🔵 Total MAPE", filtered_df["MAPE"].sum()) with col3: st.metric("🟠 Total Compatibles", filtered_df["Compatible"].sum()) # Assurer que les semaines sont de 1 à 10 all_weeks = pd.DataFrame({"Semaine_Epi": range(1, 11)}) time_series = filtered_df.groupby("Semaine_Epi")[ ["Igm+", "REJETE", "Compatible", "Line list", "MAPE"]].sum().reset_index() time_series = all_weeks.merge(time_series, on="Semaine_Epi", how="left").fillna(0) # Création du graphique avec affichage des valeurs sur chaque segment fig = px.bar( time_series, x="Semaine_Epi", y=["Igm+", "REJETE", "Compatible", "Line list", "MAPE"], title="📊 Évolution des différents cas", color_discrete_map={ "Igm+": "red", "REJETE": "green", "Compatible": "orange", "Line list": "yellow", "MAPE": "blue" }, barmode="stack", text_auto=True # Affiche les valeurs sur chaque bande ) fig.update_layout( xaxis=dict(tickmode='array', tickvals=list(range(1, 11)), ticktext=[str(i) for i in range(1, 11)]) ) # Affichage du graphique st.plotly_chart(fig, use_container_width=True) # Possibilité de télécharger le graphique sous forme d'image PNG # Pour cela, Plotly nécessite l'installation de kaleido : pip install -U kaleido img_bytes = fig.to_image(format="png") st.download_button( label="Télécharger le graphique", data=img_bytes, file_name="graphique.png", mime="image/png" ) # Affichage des données filtrées dans un tableau st.subheader("📋 Données Filtrées") st.markdown("
", unsafe_allow_html=True) st.dataframe(filtered_df, use_container_width=True)