Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import boto3 | |
| import pandas as pd | |
| import json | |
| import matplotlib.pyplot as plt | |
| # Titre de la page | |
| st.title("Predictions - ville de Rennes") | |
| # Paramètres S3 (à adapter ou utiliser variables d'environnement pour plus de sécurité) | |
| AWS_ACCESS_KEY_ID = "AKIAQJXL2QR4KZ2RZYW4" | |
| AWS_SECRET_ACCESS_KEY = "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" | |
| BUCKET_NAME = "jedha-quality-air" | |
| PREFIX = "datasets/output/" | |
| # FILE_KEY = "datasets/output/20250711-064810_prediction_data.json" | |
| # @st.cache_data(show_spinner=True) | |
| def load_data_from_s3(): | |
| s3 = boto3.client( | |
| "s3", | |
| aws_access_key_id=AWS_ACCESS_KEY_ID, | |
| aws_secret_access_key=AWS_SECRET_ACCESS_KEY, | |
| ) | |
| response = s3.list_objects_v2(Bucket=BUCKET_NAME, Prefix=PREFIX) | |
| # Vérifie s'il y a des objets | |
| if "Contents" in response: | |
| # Trie les objets par date de dernière modification (LastModified) | |
| latest_file = max(response["Contents"], key=lambda x: x["LastModified"]) | |
| latest_key = latest_file["Key"] | |
| # Récupère l'objet | |
| latest_object = s3.get_object(Bucket=BUCKET_NAME, Key=latest_key) | |
| content = latest_object["Body"].read().decode("utf-8") | |
| print("Latest file key:", latest_key) | |
| else: | |
| print("Aucun fichier trouvé dans ce dossier.") | |
| # response = s3.get_object(Bucket=BUCKET_NAME, Key=FILE_KEY) | |
| # content = response["Body"].read().decode("utf-8") | |
| data = json.loads(content) | |
| # Extraction date et heure du nom fichier | |
| filename = latest_key.split("/")[-1] | |
| datetime_str = filename.split("_")[0] # "20250711-064810" | |
| date_str = datetime_str[:8] | |
| time_str = datetime_str[9:] | |
| formatted_date = pd.to_datetime(date_str, format="%Y%m%d").date() | |
| formatted_time = pd.to_datetime(time_str, format="%H%M%S").time() | |
| df = pd.DataFrame([data]) | |
| df["date"] = formatted_date | |
| df["heure UTC"] = formatted_time | |
| return df, formatted_date, formatted_time | |
| # Chargement des données | |
| df, formatted_date, formatted_time = load_data_from_s3() | |
| pollution_seuils = { | |
| "PM25": [ | |
| (0, 10, "#4ee3dc", "Bon"), | |
| (10, 20, "#53c8b5", "Moyen"), | |
| (20, 25, "#f3dd57", "Dégradé"), | |
| (25, 50, "#f47d61", "Mauvais"), | |
| (50, 75, "#b22133", "Très mauvais"), | |
| (75, float("inf"), "#7d2e8e", "Extrêmement mauvais"), | |
| ], | |
| "PM10": [ | |
| (0, 20, "#4ee3dc", "Bon"), | |
| (20, 40, "#53c8b5", "Moyen"), | |
| (40, 50, "#f3dd57", "Dégradé"), | |
| (50, 100, "#f47d61", "Mauvais"), | |
| (100, 150, "#b22133", "Très mauvais"), | |
| (150, float("inf"), "#7d2e8e", "Extrêmement mauvais"), | |
| ], | |
| "NOX": [ | |
| (0, 40, "#4ee3dc", "Bon"), | |
| (40, 90, "#53c8b5", "Moyen"), | |
| (90, 120, "#f3dd57", "Dégradé"), | |
| (120, 230, "#f47d61", "Mauvais"), | |
| (230, 340, "#b22133", "Très mauvais"), | |
| (340, float("inf"), "#7d2e8e", "Extrêmement mauvais"), | |
| ], | |
| "O3": [ | |
| (0, 50, "#4ee3dc", "Bon"), | |
| (50, 100, "#53c8b5", "Moyen"), | |
| (100, 130, "#f3dd57", "Dégradé"), | |
| (130, 240, "#f47d61", "Mauvais"), | |
| (240, 380, "#b22133", "Très mauvais"), | |
| (380, float("inf"), "#7d2e8e", "Extrêmement mauvais"), | |
| ], | |
| } | |
| # Fonction pour récupérer la couleur selon les seuils | |
| def get_pollution_color(polluant, valeur): | |
| seuils = pollution_seuils.get(polluant) | |
| for bas, haut, couleur, libelle in seuils: | |
| if bas <= valeur < haut: | |
| return couleur, libelle | |
| return "#cccccc" # fallback gris | |
| # Affichage tableau | |
| st.subheader("Données de prédiction") | |
| st.dataframe(df) | |
| st.markdown("") | |
| st.markdown("") | |
| st.markdown("") | |
| # Création du plot | |
| polluants = ["O3", "NOX", "PM10", "PM25"] | |
| valeurs = [df[col].iloc[0] for col in polluants] | |
| couleurs = ["#8da0cb", "#fc8d62", "#66c2a5", "#a6d854"] # tons pastel et mats | |
| fig, ax = plt.subplots(figsize=(6, 3)) # taille plus compacte | |
| bars = ax.bar(polluants, valeurs, color=couleurs) | |
| # Titre avec date et heure | |
| titre = f"Pollution le {formatted_date} à {formatted_time.strftime('%H:%M:%S')}" | |
| ax.set_title(titre, fontsize=14) | |
| ax.set_xlabel("Polluants", fontsize=12) | |
| ax.set_ylabel("Valeurs", fontsize=12) | |
| # Valeurs sur barres | |
| max_val = max(valeurs) | |
| for bar, val in zip(bars, valeurs): | |
| height = bar.get_height() | |
| ax.text( | |
| bar.get_x() + bar.get_width() / 2, | |
| height + max_val * 0.02, | |
| f"{val:.1f}", | |
| ha="center", | |
| fontsize=8, | |
| ) | |
| # Centrage avec colonnes Streamlit | |
| left_co, cent_co, right_co = st.columns([1, 2, 1]) | |
| with cent_co: | |
| st.pyplot(fig) | |
| st.subheader("Qualité de l’air") | |
| for i, polluant in enumerate(polluants): | |
| val = valeurs[i] | |
| color, libelle = get_pollution_color(polluant, val) | |
| st.markdown( | |
| f""" | |
| <div style='background-color:{color};padding:10px 15px; | |
| margin:6px 0;border-radius:10px; | |
| color:black;font-weight:bold;font-size:16px;'> | |
| {polluant} : {val:.1f} µg/m³ - {libelle} | |
| </div> | |
| """, | |
| unsafe_allow_html=True | |
| ) |