343 lines
No EOL
14 KiB
Python
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() |