#!/usr/bin/env python3 """ Script de démonstration des fonctionnalités de la classe EpisodePollution ===================================================================== Ce script illustre l'utilisation de toutes les méthodes disponibles dans la classe EpisodePollution pour analyser les épisodes de pollution. Fonctionnalités testées: - Analyse des alertes de pollution - Identification des polluants responsables - Analyse des niveaux d'alerte (Information/Alerte) - Gestion des géométries complexes - Analyse des zones géographiques affectées - Utilisation des méthodes héritées de la classe de base """ import json from pathlib import Path from atmo_wrapper import AtmoDataWrapper from atmo_data_wrapper import EpisodePollution, AtmoDataCollection, Coordinates from atmo_data_wrapper import CODE_POLLUANT def demo_basic_properties(): """Démonstration des propriétés de base d'un objet EpisodePollution""" print("=" * 60) print("DÉMONSTRATION DES PROPRIÉTÉS DE BASE") print("=" * 60) # Exemple d'épisode de pollution aux particules fines sample_episode = { "type": "Feature", "geometry": { "type": "MultiPolygon", "coordinates": [[[ [6.0, 49.0], [6.5, 49.0], [6.5, 49.5], [6.0, 49.5], [6.0, 49.0] ]]] }, "properties": { "aasqa": "90", "source": "ATMO Grand Est", "date_maj": "2024-01-15T10:00:00", "lib_zone": "Agglomération de Nancy", "code_pol": "5", "lib_pol": "PM10", "code_zone": "54395", "date_dif": "2024-01-15", "date_ech": "2024-01-16", "etat": "PROCEDURE D'INFORMATION ET DE RECOMMANDATION" } } episode = EpisodePollution(sample_episode) print(f"Zone affectée: {episode.lib_zone}") print(f"Code polluant: {episode.code_pol}") print(f"Polluant: {episode.lib_pol}") print(f"Code polluant normalisé: {episode.get_polluant_code()}") print(f"État: {episode.etat}") print(f"AASQA: {episode.get_aasqa_name()}") print(f"Source: {episode.get_source()}") print(f"Date de diffusion: {episode.date_dif}") print(f"Date d'échéance: {episode.date_ech}") print(f"Date de mise à jour: {episode.date_maj}") print(f"Géométrie complexe: {episode.is_geometry_complex()}") if episode.has_coordinates(): print(f"Coordonnées: {episode.coordinates}") else: print("Pas de coordonnées ponctuelles (géométrie de zone)") print(f"Représentation: {episode}") print() def demo_alert_analysis(): """Démonstration de l'analyse des alertes""" print("=" * 60) print("ANALYSE DES ALERTES DE POLLUTION") print("=" * 60) # Exemples d'épisodes avec différents niveaux d'alerte episodes_samples = [ { "properties": { "aasqa": "18", "lib_zone": "Île-de-France", "code_pol": "5", "lib_pol": "PM10", "etat": "PROCEDURE D'INFORMATION ET DE RECOMMANDATION", "date_dif": "2024-01-15" } }, { "properties": { "aasqa": "18", "lib_zone": "Paris", "code_pol": "3", "lib_pol": "O3", "etat": "PROCEDURE D'ALERTE", "date_dif": "2024-07-20" } }, { "properties": { "aasqa": "90", "lib_zone": "Strasbourg", "code_pol": "1", "lib_pol": "NO2", "etat": "PAS DE DEPASSEMENT", "date_dif": "2024-01-15" } }, { "properties": { "aasqa": "13", "lib_zone": "Marseille", "code_pol": "6", "lib_pol": "PM2.5", "etat": "PROCEDURE D'INFORMATION", "date_dif": "2024-03-10" } }, { "properties": { "aasqa": "84", "lib_zone": "Lyon", "code_pol": "3", "lib_pol": "O3", "etat": "ALERTE NIVEAU 1", "date_dif": "2024-08-15" } } ] print("Analyse des différents types d'alertes:") print() for i, episode_data in enumerate(episodes_samples, 1): episode_data["type"] = "Feature" episode = EpisodePollution(episode_data) print(f"{i}. {episode.lib_zone} - {episode.lib_pol}") print(f" État: {episode.etat}") print(f" Alerte active: {'✓' if episode.is_alert_active() else '✗'}") print(f" Niveau d'alerte: {episode.get_alert_level()}") print(f" Code polluant: {episode.get_polluant_code()}") print(f" Date: {episode.date_dif}") print() def demo_pollutant_analysis(): """Démonstration de l'analyse par polluant""" print("=" * 60) print("ANALYSE PAR POLLUANT") print("=" * 60) # Exemples avec différents polluants pollutants_samples = [ {"code_pol": "1", "lib_pol": "NO2", "zone": "Zone urbaine dense"}, {"code_pol": "2", "lib_pol": "SO2", "zone": "Zone industrielle"}, {"code_pol": "3", "lib_pol": "O3", "zone": "Zone péri-urbaine"}, {"code_pol": "5", "lib_pol": "PM10", "zone": "Centre-ville"}, {"code_pol": "6", "lib_pol": "PM2.5", "zone": "Zone trafic"} ] print("Polluants détectés dans les épisodes:") print() for i, poll_data in enumerate(pollutants_samples, 1): episode_data = { "type": "Feature", "properties": { "aasqa": "99", "lib_zone": poll_data["zone"], "code_pol": poll_data["code_pol"], "lib_pol": poll_data["lib_pol"], "etat": "PROCEDURE D'INFORMATION", "date_dif": "2024-01-15" } } episode = EpisodePollution(episode_data) polluant_description = CODE_POLLUANT.get(episode.get_polluant_code(), "Description non disponible") print(f"{i}. Polluant: {episode.lib_pol} (Code: {episode.code_pol})") print(f" Code normalisé: {episode.get_polluant_code()}") print(f" Zone: {episode.lib_zone}") print(f" Description: {polluant_description}") print() def demo_geometry_analysis(): """Démonstration de l'analyse des géométries""" print("=" * 60) print("ANALYSE DES GÉOMÉTRIES") print("=" * 60) # Épisode avec géométrie simple (Point) episode_point = EpisodePollution({ "type": "Feature", "geometry": { "type": "Point", "coordinates": [2.3522, 48.8566] }, "properties": { "aasqa": "18", "lib_zone": "Paris Centre", "code_pol": "3", "lib_pol": "O3", "etat": "PROCEDURE D'INFORMATION", "date_dif": "2024-07-15" } }) # Épisode avec géométrie complexe (MultiPolygon) episode_multipolygon = EpisodePollution({ "type": "Feature", "geometry": { "type": "MultiPolygon", "coordinates": [ [[[2.0, 48.5], [2.5, 48.5], [2.5, 49.0], [2.0, 49.0], [2.0, 48.5]]], [[[2.8, 48.7], [3.2, 48.7], [3.2, 49.1], [2.8, 49.1], [2.8, 48.7]]] ] }, "properties": { "aasqa": "18", "lib_zone": "Île-de-France", "code_pol": "5", "lib_pol": "PM10", "etat": "PROCEDURE D'ALERTE", "date_dif": "2024-01-20" } }) # Épisode sans géométrie episode_no_geom = EpisodePollution({ "type": "Feature", "properties": { "aasqa": "90", "lib_zone": "Grand Est", "code_pol": "1", "lib_pol": "NO2", "etat": "PAS DE DEPASSEMENT", "date_dif": "2024-01-15" } }) episodes = [ ("Point", episode_point), ("MultiPolygon", episode_multipolygon), ("Sans géométrie", episode_no_geom) ] print("Types de géométries dans les épisodes:") print() for i, (type_geom, episode) in enumerate(episodes, 1): print(f"{i}. {type_geom} - {episode.lib_zone}") print(f" Type géométrie: {episode.geometry.get('type', 'Non défini')}") print(f" Géométrie complexe: {'✓' if episode.is_geometry_complex() else '✗'}") print(f" A des coordonnées: {'✓' if episode.has_coordinates() else '✗'}") if episode.has_coordinates(): print(f" Coordonnées: {episode.coordinates}") print(f" État: {episode.etat}") print() def demo_temporal_analysis(): """Démonstration de l'analyse temporelle des épisodes""" print("=" * 60) print("ANALYSE TEMPORELLE DES ÉPISODES") print("=" * 60) # Simulation d'épisodes à différentes dates temporal_episodes = [ { "date_dif": "2024-01-15", "date_ech": "2024-01-16", "lib_zone": "Lyon", "lib_pol": "PM10", "etat": "PROCEDURE D'INFORMATION", "aasqa": "84", "code_pol": "5" }, { "date_dif": "2024-07-20", "date_ech": "2024-07-21", "lib_zone": "Marseille", "lib_pol": "O3", "etat": "PROCEDURE D'ALERTE", "aasqa": "13", "code_pol": "3" }, { "date_dif": "2024-12-05", "date_ech": "2024-12-07", "lib_zone": "Strasbourg", "lib_pol": "NO2", "etat": "PROCEDURE D'INFORMATION", "aasqa": "90", "code_pol": "1" } ] print("Épisodes chronologiques:") print() for i, episode_data in enumerate(temporal_episodes, 1): episode_data["type"] = "Feature" episode = EpisodePollution(episode_data) # Calcul de la durée (simplifié) try: from datetime import datetime date_debut = datetime.strptime(episode.date_dif, "%Y-%m-%d") date_fin = datetime.strptime(episode.date_ech, "%Y-%m-%d") duree = (date_fin - date_debut).days except: duree = "Non calculable" print(f"{i}. {episode.lib_zone} - {episode.lib_pol}") print(f" Période: du {episode.date_dif} au {episode.date_ech}") print(f" Durée: {duree} jour(s)" if duree != "Non calculable" else f" Durée: {duree}") print(f" État: {episode.etat}") print(f" Niveau: {episode.get_alert_level()}") print() def demo_regional_analysis(): """Démonstration de l'analyse régionale des épisodes""" print("=" * 60) print("ANALYSE RÉGIONALE DES ÉPISODES") print("=" * 60) # Simulation d'épisodes dans différentes régions regional_episodes = [ {"aasqa": "18", "region": "Île-de-France", "lib_zone": "Paris", "lib_pol": "PM10"}, {"aasqa": "84", "region": "Auvergne-Rhône-Alpes", "lib_zone": "Lyon", "lib_pol": "O3"}, {"aasqa": "13", "region": "Provence-Alpes-Côte d'Azur", "lib_zone": "Marseille", "lib_pol": "PM2.5"}, {"aasqa": "90", "region": "Grand Est", "lib_zone": "Strasbourg", "lib_pol": "NO2"}, {"aasqa": "59", "region": "Hauts-de-France", "lib_zone": "Lille", "lib_pol": "O3"} ] print("Épisodes par région AASQA:") print() for i, episode_data in enumerate(regional_episodes, 1): episode_data.update({ "type": "Feature", "code_pol": "5", "etat": "PROCEDURE D'INFORMATION", "date_dif": "2024-01-15" }) episode = EpisodePollution(episode_data) print(f"{i}. Région: {episode_data['region']}") print(f" AASQA: {episode.get_aasqa_name()}") print(f" Zone: {episode.lib_zone}") print(f" Polluant: {episode.lib_pol}") print(f" Code AASQA: {episode.aasqa}") print() def demo_inherited_methods(): """Démonstration des méthodes héritées de la classe de base""" print("=" * 60) print("MÉTHODES HÉRITÉES DE LA CLASSE DE BASE") print("=" * 60) episode_data = { "type": "Feature", "geometry": { "type": "Point", "coordinates": [4.8357, 45.7640] }, "properties": { "aasqa": "84", "source": "ATMO Auvergne-Rhône-Alpes", "date_maj": "2024-07-15T14:30:00", "lib_zone": "Lyon Métropole", "code_pol": "3", "lib_pol": "O3", "etat": "PROCEDURE D'ALERTE", "date_dif": "2024-07-15", "date_ech": "2024-07-16" } } episode = EpisodePollution(episode_data) print(f"Zone affectée: {episode.lib_zone}") print(f"AASQA: {episode.get_aasqa_name()}") print(f"Source: {episode.get_source()}") print(f"A des coordonnées: {'✓' if episode.has_coordinates() else '✗'}") if episode.has_coordinates(): print(f"Coordonnées: {episode.coordinates}") print() # Test des fonctions de couleur et emoji (niveau fictif pour démonstration) print("Fonctions de couleur et emoji (exemple avec niveau 4 - Alerte):") test_level = 4 # Niveau d'alerte couleur_hex, couleur_rgb = episode.get_color_by_level(test_level) emoji_round = episode.get_emoji_by_level(test_level, "round") emoji_square = episode.get_emoji_by_level(test_level, "square") print(f" - Couleur hex: {couleur_hex}") print(f" - Couleur RGB: {couleur_rgb}") print(f" - Emoji rond: {emoji_round}") print(f" - Emoji carré: {emoji_square}") print() def demo_comparative_analysis(): """Démonstration d'une analyse comparative entre épisodes""" print("=" * 60) print("ANALYSE COMPARATIVE DES ÉPISODES") print("=" * 60) episodes_data = [ { "type": "Feature", "properties": { "aasqa": "18", "lib_zone": "Paris", "code_pol": "5", "lib_pol": "PM10", "etat": "PROCEDURE D'INFORMATION ET DE RECOMMANDATION", "date_dif": "2024-01-15" } }, { "type": "Feature", "properties": { "aasqa": "84", "lib_zone": "Lyon", "code_pol": "3", "lib_pol": "O3", "etat": "PROCEDURE D'ALERTE", "date_dif": "2024-07-20" } }, { "type": "Feature", "properties": { "aasqa": "13", "lib_zone": "Marseille", "code_pol": "6", "lib_pol": "PM2.5", "etat": "ALERTE NIVEAU 1", "date_dif": "2024-03-10" } }, { "type": "Feature", "properties": { "aasqa": "90", "lib_zone": "Strasbourg", "code_pol": "1", "lib_pol": "NO2", "etat": "PAS DE DEPASSEMENT", "date_dif": "2024-05-05" } } ] episodes = [EpisodePollution(ep) for ep in episodes_data] print("Comparaison des épisodes de pollution:") print("-" * 70) print(f"{'Zone':<15} {'Polluant':<8} {'Niveau':<12} {'Alerte':<8} {'État'}") print("-" * 70) for episode in episodes: alerte_status = "✓" if episode.is_alert_active() else "✗" niveau = episode.get_alert_level() print(f"{episode.lib_zone:<15} {episode.lib_pol:<8} {niveau:<12} {alerte_status:<8} {episode.etat}") print() # Statistiques total_episodes = len(episodes) alertes_actives = sum(1 for ep in episodes if ep.is_alert_active()) print(f"Statistiques:") print(f" - Total d'épisodes: {total_episodes}") print(f" - Alertes actives: {alertes_actives}") print(f" - Pourcentage d'alertes: {(alertes_actives/total_episodes)*100:.1f}%") # Répartition par polluant polluants = {} for episode in episodes: polluant = episode.get_polluant_code() polluants[polluant] = polluants.get(polluant, 0) + 1 print(f" - Répartition par polluant:") for polluant, count in polluants.items(): print(f" * {polluant}: {count} épisode(s)") print() def demo_edge_cases(): """Démonstration de la gestion des cas particuliers""" print("=" * 60) print("GESTION DES CAS PARTICULIERS") print("=" * 60) # Cas 1: Épisode sans état défini print("1. Épisode sans état défini:") episode_no_state = EpisodePollution({ "type": "Feature", "properties": { "aasqa": "99", "lib_zone": "Zone test", "code_pol": "5", "lib_pol": "PM10", "etat": "", "date_dif": "2024-01-15" } }) print(f" État: '{episode_no_state.etat}'") print(f" Alerte active: {'✓' if episode_no_state.is_alert_active() else '✗'}") print(f" Niveau d'alerte: {episode_no_state.get_alert_level()}") print() # Cas 2: Code polluant non standard print("2. Code polluant non référencé:") episode_unknown_pollutant = EpisodePollution({ "type": "Feature", "properties": { "aasqa": "99", "lib_zone": "Zone test", "code_pol": "99", "lib_pol": "Polluant inconnu", "etat": "PROCEDURE D'INFORMATION", "date_dif": "2024-01-15" } }) print(f" Code polluant original: {episode_unknown_pollutant.code_pol}") print(f" Code polluant normalisé: {episode_unknown_pollutant.get_polluant_code()}") print(f" Nom polluant: {episode_unknown_pollutant.lib_pol}") print() # Cas 3: Géométrie malformée print("3. Géométrie non standard:") episode_no_geometry = EpisodePollution({ "type": "Feature", "geometry": None, "properties": { "aasqa": "99", "lib_zone": "Zone sans géométrie", "code_pol": "3", "lib_pol": "O3", "etat": "PROCEDURE D'ALERTE", "date_dif": "2024-01-15" } }) print(f" Géométrie: {episode_no_geometry.geometry}") print(f" Type géométrie: {episode_no_geometry.geometry.get('type', 'Non défini') if episode_no_geometry.geometry else 'None'}") print(f" Géométrie complexe: {'✓' if episode_no_geometry.is_geometry_complex() else '✗'}") print(f" A des coordonnées: {'✓' if episode_no_geometry.has_coordinates() else '✗'}") print() def main(): """Fonction principale de démonstration""" print("SCRIPT DE DÉMONSTRATION - CLASSE EPISODEPOLLUTION") print("=" * 60) print("Ce script teste toutes les fonctionnalités de la classe EpisodePollution") print("pour l'analyse des épisodes de pollution atmosphérique.") print() try: # Exécution de toutes les démonstrations demo_basic_properties() demo_alert_analysis() demo_pollutant_analysis() demo_geometry_analysis() demo_temporal_analysis() demo_regional_analysis() demo_inherited_methods() demo_comparative_analysis() demo_edge_cases() print("=" * 60) print("RÉCAPITULATIF DES MÉTHODES TESTÉES") print("=" * 60) print("Méthodes spécifiques à EpisodePollution:") print("✓ get_polluant_code()") print("✓ is_alert_active()") print("✓ get_alert_level()") print("✓ is_geometry_complex()") print() print("Méthodes héritées de AtmoDataBase:") print("✓ get_aasqa_name()") print("✓ get_source()") print("✓ has_coordinates()") print("✓ get_emoji_by_level(level, style)") print("✓ get_color_by_level(level)") print() print("Propriétés testées:") print("✓ Codes et noms des polluants") print("✓ États et niveaux d'alerte") print("✓ Zones géographiques affectées") print("✓ Géométries (Point, MultiPolygon)") print("✓ Informations temporelles (dates)") print("✓ Gestion des cas particuliers") print() print("✅ TOUTES LES FONCTIONNALITÉS ONT ÉTÉ TESTÉES AVEC SUCCÈS") except Exception as e: print(f"❌ ERREUR lors de l'exécution: {e}") raise if __name__ == "__main__": main()