import streamlit as st import pandas as pd import plotly.express as px # ------------------------------------------------------------------ # Configuration de la page # ------------------------------------------------------------------ st.set_page_config( page_title="Mon Tracker COVID perso", page_icon="📊", layout="wide", ) # Image locale en haut du dashboard #st.image("Covid.png", use_column_width=True) # Titre et intro st.title("Covid Tracker 🦠") st.markdown( "Dashboard de suivi des vagues de COVID-19 à travers le monde, " "basé sur les données de l'European Centre for Disease Prevention and Control (ECDC)." ) # ------------------------------------------------------------------ # Chargement des données (mis en cache pour la rapidité) # ------------------------------------------------------------------ @st.cache_data def load_data(): df = pd.read_csv("covid_data.csv") df["dateRep"] = pd.to_datetime(df["dateRep"], format="%d/%m/%Y") return df df = load_data() # ------------------------------------------------------------------ # Barre latérale : tous les filtres ensemble # ------------------------------------------------------------------ st.sidebar.header("Filtres") # Filtre par continent continents = sorted(df["continentExp"].unique()) selected_continent = st.sidebar.selectbox("Continent", continents) # Filtre par pays countries = sorted(df[df["continentExp"] == selected_continent]["countriesAndTerritories"].unique()) selected_countries = st.sidebar.multiselect( "Pays à afficher", options=countries, default=countries[:4] if len(countries) >= 4 else countries, ) # Filtre par plage de dates min_date = df["dateRep"].min().date() max_date = df["dateRep"].max().date() date_range = st.sidebar.date_input( "Plage de dates", value=(min_date, max_date), min_value=min_date, max_value=max_date, ) # Slider pour le top N pays top_n = st.sidebar.slider("Afficher le top N pays", min_value=3, max_value=20, value=10) # Échelle logarithmique log_scale = st.sidebar.checkbox("Échelle logarithmique") # ------------------------------------------------------------------ # Filtrage du dataframe selon les choix utilisateur # ------------------------------------------------------------------ filtered = df[df["continentExp"] == selected_continent] filtered = filtered[filtered["countriesAndTerritories"].isin(selected_countries)] if len(date_range) == 2: start, end = date_range filtered = filtered[ (filtered["dateRep"] >= pd.to_datetime(start)) & (filtered["dateRep"] <= pd.to_datetime(end)) ] # ------------------------------------------------------------------ # Onglets pour organiser le dashboard # ------------------------------------------------------------------ tab1, tab2, tab3 = st.tabs(["Vue d'ensemble", "Par pays", "Comparaisons"]) # ----- ONGLET 1 : Vue d'ensemble ----- with tab1: st.subheader("Indicateurs globaux") col1, col2, col3 = st.columns(3) total_cases = int(filtered["cases"].sum()) total_deaths = int(filtered["deaths"].sum()) mortality_rate = (total_deaths / total_cases * 100) if total_cases > 0 else 0 col1.metric("Cas totaux", f"{total_cases:,}".replace(",", " ")) col2.metric("Décès totaux", f"{total_deaths:,}".replace(",", " ")) col3.metric("Taux de mortalité", f"{mortality_rate:.2f} %") # Courbe des cas dans le temps st.subheader("Évolution des cas dans le temps") fig_cases = px.line( filtered, x="dateRep", y="cases", color="countriesAndTerritories", labels={"dateRep": "Date", "cases": "Cas quotidiens", "countriesAndTerritories": "Pays"}, log_y=log_scale, ) st.plotly_chart(fig_cases, use_container_width=True) # Courbe des décès dans le temps st.subheader("Évolution des décès dans le temps") fig_deaths = px.line( filtered, x="dateRep", y="deaths", color="countriesAndTerritories", labels={"dateRep": "Date", "deaths": "Décès quotidiens", "countriesAndTerritories": "Pays"}, log_y=log_scale, ) st.plotly_chart(fig_deaths, use_container_width=True) # ----- ONGLET 2 : Par pays ----- with tab2: st.subheader("Récapitulatif par pays") summary = ( filtered.groupby("countriesAndTerritories") .agg( cas_totaux=("cases", "sum"), deces_totaux=("deaths", "sum"), cas_moyens_par_jour=("cases", "mean"), ) .round(0) .sort_values("cas_totaux", ascending=False) ) st.dataframe(summary, use_container_width=True) # Bouton pour télécharger le résumé en CSV csv = summary.to_csv().encode("utf-8") st.download_button( label="📥 Télécharger le résumé en CSV", data=csv, file_name="covid_summary.csv", mime="text/csv", ) # Données brutes (déplié sur demande) with st.expander("Voir les données brutes filtrées"): st.dataframe(filtered) # ----- ONGLET 3 : Comparaisons ----- with tab3: # Carte mondiale colorée par cas totaux st.subheader("Carte mondiale des cas") map_data = ( filtered.groupby(["countryterritoryCode", "countriesAndTerritories"]) .agg(total_cases=("cases", "sum")) .reset_index() ) fig_map = px.choropleth( map_data, locations="countryterritoryCode", color="total_cases", hover_name="countriesAndTerritories", color_continuous_scale="Reds", ) st.plotly_chart(fig_map, use_container_width=True) # Cas cumulés par pays en aires empilées st.subheader("Cas cumulés par pays") fig_area = px.area( filtered, x="dateRep", y="cases", color="countriesAndTerritories", labels={"dateRep": "Date", "cases": "Cas"}, ) st.plotly_chart(fig_area, use_container_width=True) # Cas par jour de la semaine st.subheader("Cas par jour de la semaine") filtered_copy = filtered.copy() filtered_copy["weekday"] = filtered_copy["dateRep"].dt.day_name() weekday_avg = filtered_copy.groupby("weekday")["cases"].mean().reindex( ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] ) st.bar_chart(weekday_avg) # Moyenne mobile 7 jours st.subheader("Tendance lissée (moyenne mobile 7 jours)") filtered_sorted = filtered.sort_values(["countriesAndTerritories", "dateRep"]) filtered_sorted["cases_7day_avg"] = ( filtered_sorted.groupby("countriesAndTerritories")["cases"] .transform(lambda x: x.rolling(7, min_periods=1).mean()) ) fig_smooth = px.line( filtered_sorted, x="dateRep", y="cases_7day_avg", color="countriesAndTerritories", ) st.plotly_chart(fig_smooth, use_container_width=True) # Taux d'incidence pour 100 000 habitants st.subheader("Taux d'incidence (cas pour 100 000 habitants)") filtered_copy["incidence_per_100k"] = ( filtered_copy["cases"] / filtered_copy["popData2020"] * 100_000 ) fig_incidence = px.line( filtered_copy, x="dateRep", y="incidence_per_100k", color="countriesAndTerritories", ) st.plotly_chart(fig_incidence, use_container_width=True)