Spaces:
Sleeping
Sleeping
File size: 5,754 Bytes
ca8cf48 181c458 ca8cf48 181c458 ca8cf48 181c458 ca8cf48 181c458 ca8cf48 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
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("<h1 style='text-align: center; color: #2C3E50;'>📊 Tableau de Bord de l'Épidémie</h1>",
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("<hr>", 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("<hr>", unsafe_allow_html=True)
st.dataframe(filtered_df, use_container_width=True)
|