py_atmo_data_wrapper/demos/demo_atmo_functions.py
2025-07-14 17:56:57 +02:00

343 lines
No EOL
14 KiB
Python

#!/usr/bin/env python3
"""
Script de démonstration de toutes les fonctions du datamodel IndiceAtmo
Utilise les données réelles de l'API pour une ville française (aujourd'hui)
Idéal pour documentation et exemples
"""
from atmo_data_wrapper import AtmoDataClient, AtmoDataException
from atmo_data_wrapper import CODE_POLLUANT, INDICES_ATMO
from datetime import datetime
import sys
def demo_atmo_functions():
"""Démonstration complète des fonctions IndiceAtmo avec données réelles"""
# Configuration
AASQA_ILE_DE_FRANCE = "11" # Île-de-France pour avoir des données
today = datetime.now().strftime('%Y-%m-%d')
print("🌬️ DÉMONSTRATION DES FONCTIONS INDICEATMO")
print("=" * 55)
print(f"📍 Région: Île-de-France (AASQA: {AASQA_ILE_DE_FRANCE})")
print(f"🗓️ Date: {today}")
print(f"🏛️ Basé sur la notice officielle du 1er avril 2025")
print()
try:
# Connexion et récupération des données
print("🔐 Connexion à l'API...")
client = AtmoDataClient()
success = client.auto_login()
if not success:
print("❌ Échec de la connexion à l'API")
return False
print("✅ Connecté avec succès !")
# Récupération des données ATMO
print(f"🌬️ Récupération des indices ATMO pour {today}...")
indices = client.get_indices_atmo(
format="geojson",
date=today,
aasqa=AASQA_ILE_DE_FRANCE
)
if not indices or len(indices) == 0:
print("❌ Aucune donnée ATMO trouvée")
return False
print(f"{len(indices)} station(s) trouvée(s)")
# Utiliser la première station pour la démo
atmo = indices[0]
print(f"📍 Station sélectionnée: {atmo.lib_zone}")
print()
# === DÉMONSTRATION DES PROPRIÉTÉS DE BASE ===
print("📊 === PROPRIÉTÉS DE BASE (héritées d'AtmoDataBase) ===")
print()
print("🏛️ INFORMATIONS GÉNÉRALES:")
print(f" • AASQA: {atmo.aasqa}")
print(f" • Zone: {atmo.lib_zone}")
print(f" • Source: {atmo.source}")
print(f" • Type de zone: {atmo.type_zone}")
print(f" • Code zone: {atmo.code_zone}")
print()
print("📅 DONNÉES TEMPORELLES:")
print(f" • Date échéance: {atmo.date_ech}")
print(f" • Date diffusion: {atmo.date_dif}")
print()
print("🗺️ COORDONNÉES:")
if atmo.has_coordinates():
print(f" • Coordonnées disponibles: Oui")
if hasattr(atmo.coordinates, 'latitude'):
print(f" • Latitude: {atmo.coordinates.latitude:.6f}")
print(f" • Longitude: {atmo.coordinates.longitude:.6f}")
else:
print(" • Pas de coordonnées WGS84 disponibles")
print(f" • Coordonnées réglementaires: ({atmo.x_reg:.1f}, {atmo.y_reg:.1f})")
print(f" • Système de projection: EPSG:{atmo.epsg_reg}")
print()
print("🎨 FONCTIONS CENTRALISÉES:")
for level in [0, 1, 2, 3, 4, 5, 6, 7]:
emoji_round = atmo.get_emoji_by_level(level, "round")
emoji_square = atmo.get_emoji_by_level(level, "square")
color_hex, color_rgb = atmo.get_color_by_level(level)
qualif = INDICES_ATMO.get(level, "Inconnu")
print(f" • Niveau {level} ({qualif}): {emoji_round}{emoji_square} {color_hex} {color_rgb}")
print()
# === DÉMONSTRATION DES PROPRIÉTÉS SPÉCIFIQUES ATMO ===
print("🌬️ === PROPRIÉTÉS SPÉCIFIQUES ATMO ===")
print()
print("📈 INDICE GLOBAL:")
print(f" • Code qualificatif: {atmo.code_qual}")
print(f" • Libellé qualificatif: {atmo.lib_qual}")
print(f" • Couleur qualificatif: {atmo.coul_qual}")
print()
print("📊 CODES PAR POLLUANT:")
print(f" • Dioxyde d'azote (NO2): {atmo.code_no2}")
print(f" • Dioxyde de soufre (SO2): {atmo.code_so2}")
print(f" • Ozone (O3): {atmo.code_o3}")
print(f" • Particules PM10: {atmo.code_pm10}")
print(f" • Particules PM2.5: {atmo.code_pm25}")
print()
print("🔬 CONCENTRATIONS (μg/m³) - FACULTATIVES:")
print(f" • NO2: {atmo.conc_no2}")
print(f" • SO2: {atmo.conc_so2}")
print(f" • O3: {atmo.conc_o3}")
print(f" • PM10: {atmo.conc_pm10}")
print(f" • PM2.5: {atmo.conc_pm25}")
print()
# === DÉMONSTRATION DES MÉTHODES HELPER ===
print("🛠️ === MÉTHODES HELPER ===")
print()
# 1. get_qualificatif()
print("📋 1. QUALIFICATIF TEXTUEL:")
qualificatif = atmo.get_qualificatif()
print(f" • get_qualificatif(): '{qualificatif}'")
print(f" → Qualificatif de l'indice global")
print()
# 2. get_color()
print("🎨 2. COULEUR ASSOCIÉE:")
color_hex, color_rgb = atmo.get_color()
print(f" • get_color(): ('{color_hex}', {color_rgb})")
print(f" → Couleur hexadécimale et RGB de l'indice")
print()
# 3. get_emoji()
print("😀 3. ÉMOJIS:")
emoji_round = atmo.get_emoji("round")
emoji_square = atmo.get_emoji("square")
print(f" • get_emoji('round'): '{emoji_round}'")
print(f" • get_emoji('square'): '{emoji_square}'")
print(f" → Émojis rond et carré selon le niveau")
print()
# 4. Tests de qualité
print("✅ 4. TESTS DE QUALITÉ:")
is_good = atmo.is_good_quality()
is_poor = atmo.is_poor_quality()
print(f" • is_good_quality(): {is_good}")
print(f" → Qualité bonne (niveaux 1-2): {'Oui' if is_good else 'Non'}")
print(f" • is_poor_quality(): {is_poor}")
print(f" → Qualité dégradée (niveaux 4+): {'Oui' if is_poor else 'Non'}")
print()
# 5. get_worst_pollutant()
print("🔍 5. POLLUANT LE PLUS PROBLÉMATIQUE:")
worst_pollutant, worst_code = atmo.get_worst_pollutant()
worst_description = CODE_POLLUANT.get(worst_pollutant, worst_pollutant)
print(f" • get_worst_pollutant(): ('{worst_pollutant}', {worst_code})")
print(f" → Polluant: {worst_description}")
print(f" → Niveau: {worst_code} ({INDICES_ATMO.get(worst_code, 'Inconnu')})")
print()
# 6. get_pollutants_summary()
print("📋 6. RÉSUMÉ COMPLET DES POLLUANTS:")
summary = atmo.get_pollutants_summary()
print(f" • get_pollutants_summary():")
print(" → Structure complète par polluant:")
for polluant, info in summary.items():
if info['code'] > 0: # Afficher seulement les polluants avec des données
print(f" - {polluant} ({info['description']}):")
print(f" * Code: {info['code']}")
print(f" * Qualificatif: {info['qualificatif']}")
print()
# 7. get_concentrations() - NOUVELLE MÉTHODE
print("🔬 7. CONCENTRATIONS SELON NOTICE OFFICIELLE:")
concentrations = atmo.get_concentrations()
print(f" • get_concentrations(): {concentrations}")
print(" → Concentrations en μg/m³:")
for polluant, conc in concentrations.items():
description = CODE_POLLUANT.get(polluant, polluant)
print(f" - {description}: {conc} μg/m³")
print()
# 8. Nouvelles méthodes conformité notice
print("📋 8. MÉTHODES CONFORMITÉ NOTICE OFFICIELLE:")
is_commune = atmo.is_commune_level()
is_epci = atmo.is_epci_level()
responsible = atmo.get_responsible_pollutants()
print(f" • is_commune_level(): {is_commune}")
print(f" → Calculé au niveau commune: {'Oui' if is_commune else 'Non'}")
print(f" • is_epci_level(): {is_epci}")
print(f" → Calculé au niveau EPCI: {'Oui' if is_epci else 'Non'}")
print(f" • get_responsible_pollutants(): {responsible}")
if responsible:
resp_descriptions = [CODE_POLLUANT.get(p, p) for p in responsible]
print(f" → Polluants responsables: {', '.join(resp_descriptions)}")
print()
# === DÉMONSTRATION DES MÉTHODES STRING ===
print("📝 === REPRÉSENTATION STRING ===")
print()
print("🔤 MÉTHODE __str__():")
print(f" • str(atmo): '{str(atmo)}'")
print()
# === EXEMPLES D'UTILISATION PRATIQUE ===
print("💡 === EXEMPLES D'UTILISATION PRATIQUE ===")
print()
print("🎯 ANALYSE RAPIDE:")
print(f" • Qualité globale: {qualificatif} (niveau {atmo.code_qual})")
print(f" • Polluant problématique: {worst_description} (niveau {worst_code})")
print(f" • Couleur d'affichage: {color_hex} {emoji_round}")
if is_poor:
print(" • ⚠️ QUALITÉ DÉGRADÉE - Précautions recommandées")
elif is_good:
print(" • ✅ BONNE QUALITÉ DE L'AIR")
else:
print(" • 🔶 QUALITÉ MOYENNE")
print()
print("📈 ANALYSE PAR POLLUANT:")
# Analyse des polluants selon leurs niveaux
pollutants_analysis = {
'NO2': (atmo.code_no2, "Dioxyde d'azote"),
'SO2': (atmo.code_so2, "Dioxyde de soufre"),
'O3': (atmo.code_o3, "Ozone"),
'PM10': (atmo.code_pm10, "Particules PM10"),
'PM2.5': (atmo.code_pm25, "Particules PM2.5")
}
for code, (level, description) in pollutants_analysis.items():
if level > 0:
emoji = atmo.get_emoji_by_level(level)
qualif = INDICES_ATMO.get(level, "Inconnu")
print(f"{description}: {emoji} {qualif} (niveau {level})")
print()
print("🔍 FILTRAGE ET CLASSIFICATION:")
# Classification selon les seuils
critical_pollutants = [p for p, (l, _) in pollutants_analysis.items() if l >= 4]
moderate_pollutants = [p for p, (l, _) in pollutants_analysis.items() if 2 <= l <= 3]
good_pollutants = [p for p, (l, _) in pollutants_analysis.items() if l == 1]
if critical_pollutants:
print(f" • Polluants critiques (≥4): {', '.join(critical_pollutants)}")
if moderate_pollutants:
print(f" • Polluants modérés (2-3): {', '.join(moderate_pollutants)}")
if good_pollutants:
print(f" • Polluants bons (1): {', '.join(good_pollutants)}")
if not critical_pollutants and not moderate_pollutants:
print(" • ✅ Tous les polluants à des niveaux acceptables")
print()
# === INFORMATIONS TECHNIQUES ===
print("🔧 === INFORMATIONS TECHNIQUES ===")
print()
print("📦 STRUCTURE DE DONNÉES:")
print(f" • Type d'objet: {type(atmo).__name__}")
print(f" • Classe parente: {type(atmo).__bases__[0].__name__}")
print(f" • Propriétés disponibles: {len(atmo.properties)} champs")
print(f" • Géométrie: {'Oui' if atmo.has_coordinates() else 'Non'}")
print(f" • Zone géographique: {atmo.type_zone}")
print()
print("🎨 MÉTHODES HÉRITÉES:")
inherited_methods = [
'get_emoji_by_level()', 'get_color_by_level()', 'has_coordinates()',
'get_source()', 'get_aasqa_name()'
]
print(f" • Méthodes de AtmoDataBase: {', '.join(inherited_methods)}")
print()
specific_methods = [
'get_qualificatif()', 'get_color()', 'get_emoji()', 'is_good_quality()',
'is_poor_quality()', 'get_worst_pollutant()', 'get_pollutants_summary()',
'get_concentrations()', 'is_commune_level()', 'is_epci_level()', 'get_responsible_pollutants()'
]
print(f" • Méthodes spécifiques IndiceAtmo: {', '.join(specific_methods)}")
print()
print("🎨 NOUVEAUTÉS ÉMOJIS:")
print(" • get_emoji_by_level(level, style) - style='round'|'square'")
print(" • get_emoji(style) - avec choix de style d'émoji")
print(" • Support des émojis ronds (🟢) et carrés (🟩)")
print()
print("📋 CONFORMITÉ NOTICE OFFICIELLE (1er avril 2025):")
print(" • Tous les champs obligatoires et facultatifs supportés")
print(" • Propriétés conformes aux spécifications pages 12-14")
print(" • Méthodes basées sur les règles officielles de calcul")
print(" • Codes couleur conformes au tableau page 6")
print(" • Support des coordonnées réglementaires (Lambert 93)")
print(" • Concentrations facultatives selon format officiel")
print()
print("✅ === DÉMONSTRATION TERMINÉE ===")
print()
print("📚 Ce script illustre toutes les fonctionnalités de la classe IndiceAtmo")
print("🔧 Utilisez ces exemples pour votre documentation et vos développements")
print("📋 Conforme à l'arrêté du 10 juillet 2020 et à la notice du 1er avril 2025")
print()
return True
except AtmoDataException as e:
print(f"❌ Erreur API: {e}")
return False
except Exception as e:
print(f"❌ Erreur inattendue: {e}")
import traceback
traceback.print_exc()
return False
def main():
"""Point d'entrée principal"""
print("🌬️ Démonstration des fonctions IndiceAtmo")
print("=" * 55)
print()
success = demo_atmo_functions()
if not success:
print("\n❌ La démonstration s'est terminée avec des erreurs")
sys.exit(1)
else:
print("🎉 Démonstration terminée avec succès !")
sys.exit(0)
if __name__ == "__main__":
main()