first commit
This commit is contained in:
commit
a233e18c0b
48 changed files with 55300 additions and 0 deletions
3
demos/__init__.py
Normal file
3
demos/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
"""
|
||||
Demos package for Atmo Data Wrapper
|
||||
"""
|
343
demos/demo_atmo_functions.py
Normal file
343
demos/demo_atmo_functions.py
Normal file
|
@ -0,0 +1,343 @@
|
|||
#!/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()
|
165
demos/demo_complete.py
Normal file
165
demos/demo_complete.py
Normal file
|
@ -0,0 +1,165 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Démonstration complète du wrapper Atmo Data API
|
||||
avec connexion réelle et toutes les fonctionnalités
|
||||
"""
|
||||
|
||||
from atmo_data_wrapper import AtmoDataClient, AtmoDataException
|
||||
from datetime import datetime, timedelta
|
||||
import os
|
||||
|
||||
def main():
|
||||
"""Démonstration complète de toutes les fonctionnalités"""
|
||||
print("🌍 === DÉMONSTRATION ATMO DATA API ===\n")
|
||||
|
||||
try:
|
||||
# 1. Connexion automatique
|
||||
print("1. 🔐 Connexion à l'API...")
|
||||
client = AtmoDataClient()
|
||||
success = client.auto_login()
|
||||
|
||||
if not success:
|
||||
print("❌ Échec de connexion")
|
||||
return
|
||||
|
||||
print(f"✅ Connecté à {client.base_url}")
|
||||
print(f" Token: {client.token[:20]}...")
|
||||
print()
|
||||
|
||||
# 2. Indices ATMO avec objets typés
|
||||
print("2. 🏭 Récupération des indices de qualité de l'air...")
|
||||
today = datetime.now().strftime('%Y-%m-%d')
|
||||
indices = client.get_indices_atmo(date=today, aasqa='11') # Île-de-France
|
||||
|
||||
print(f"✅ {len(indices)} indices récupérés")
|
||||
print(f" Résumé: {indices.to_summary()}")
|
||||
|
||||
# Examiner quelques indices
|
||||
print("\n 📊 Exemples d'indices:")
|
||||
for i, indice in enumerate(indices[:3]):
|
||||
print(f" • {indice.lib_zone}: {indice.get_qualificatif()}")
|
||||
if indice.is_poor_quality():
|
||||
worst_pol, code = indice.get_worst_pollutant()
|
||||
print(f" ⚠️ Attention: {worst_pol} élevé ({code})")
|
||||
print()
|
||||
|
||||
# 3. Épisodes de pollution
|
||||
print("3. 🚨 Vérification des épisodes de pollution...")
|
||||
episodes = client.get_episodes_3jours(aasqa='11')
|
||||
print(f"✅ {len(episodes)} épisodes trouvés")
|
||||
|
||||
alerts_actives = [ep for ep in episodes if ep.is_alert_active()]
|
||||
if alerts_actives:
|
||||
print(f" ⚠️ {len(alerts_actives)} alertes actives:")
|
||||
for ep in alerts_actives[:3]:
|
||||
print(f" • {ep.lib_zone}: {ep.get_alert_level()} - {ep.lib_pol}")
|
||||
else:
|
||||
print(" ✅ Aucune alerte active")
|
||||
print()
|
||||
|
||||
# 4. Données d'émissions
|
||||
print("4. 🏭 Analyse des émissions...")
|
||||
emissions = client.get_emissions(aasqa='11', echelle='region')
|
||||
print(f"✅ {len(emissions)} territoires analysés")
|
||||
|
||||
if len(emissions) > 0:
|
||||
em = emissions[0]
|
||||
print(f" 📍 {em.name}:")
|
||||
print(f" • Population: {em.population:,.0f} habitants")
|
||||
total_em = em.get_total_emissions()
|
||||
print(f" • Émissions NOx: {total_em['NOx']:,.1f} t/an")
|
||||
print(f" • Émissions PM10: {total_em['PM10']:,.1f} t/an")
|
||||
|
||||
# Calculs par habitant
|
||||
nox_per_capita = em.get_emission_per_capita('nox') * 1000 # kg/hab
|
||||
print(f" • NOx par habitant: {nox_per_capita:.2f} kg/hab/an")
|
||||
print()
|
||||
|
||||
# 5. Indices pollen
|
||||
print("5. 🌸 Vérification des indices pollen...")
|
||||
try:
|
||||
pollens = client.get_indices_pollens(aasqa='11')
|
||||
print(f"✅ {len(pollens)} stations pollen")
|
||||
|
||||
alerts_pollen = [p for p in pollens if p.is_alert_active()]
|
||||
if alerts_pollen:
|
||||
print(f" ⚠️ {len(alerts_pollen)} alertes pollen actives")
|
||||
for pol in alerts_pollen[:3]:
|
||||
dangerous = pol.get_dangerous_pollens()
|
||||
if dangerous:
|
||||
print(f" • Pollens à risque: {', '.join(dangerous)}")
|
||||
else:
|
||||
print(" ✅ Pas d'alerte pollen majeure")
|
||||
|
||||
except Exception as e:
|
||||
print(f" ⚠️ Indices pollen indisponibles: {e}")
|
||||
print()
|
||||
|
||||
# 6. Sauvegarde des données
|
||||
print("6. 💾 Sauvegarde des données...")
|
||||
try:
|
||||
# Créer le dossier de sauvegarde
|
||||
save_dir = f"export_{today}"
|
||||
|
||||
# Sauvegarder en différents formats
|
||||
json_file = client.save_to_file(indices.raw_data, f"{save_dir}/indices_idf", "json")
|
||||
csv_file = client.save_to_file(indices.raw_data, f"{save_dir}/indices_idf", "csv")
|
||||
|
||||
print(f"✅ Données sauvegardées:")
|
||||
print(f" • JSON: {json_file} ({os.path.getsize(json_file):,} bytes)")
|
||||
print(f" • CSV: {csv_file} ({os.path.getsize(csv_file):,} bytes)")
|
||||
|
||||
except Exception as e:
|
||||
print(f" ❌ Erreur sauvegarde: {e}")
|
||||
print()
|
||||
|
||||
# 7. Analyse statistique
|
||||
print("7. 📈 Analyse statistique...")
|
||||
stats = indices.get_statistics()
|
||||
qs = stats['quality_stats']
|
||||
|
||||
print(f"✅ Statistiques de qualité de l'air:")
|
||||
print(f" • Qualité moyenne: {qs['moyenne']:.1f}/7")
|
||||
print(f" • Bonne qualité: {qs['bon_pourcentage']:.1f}% des zones")
|
||||
print(f" • Meilleur indice: {qs['min']}")
|
||||
print(f" • Pire indice: {qs['max']}")
|
||||
|
||||
# Classification des zones
|
||||
bonnes = [i for i in indices if i.is_good_quality()]
|
||||
mauvaises = [i for i in indices if i.is_poor_quality()]
|
||||
|
||||
print(f" • Zones de bonne qualité: {len(bonnes)}")
|
||||
print(f" • Zones de qualité dégradée: {len(mauvaises)}")
|
||||
|
||||
if mauvaises:
|
||||
print(" ⚠️ Zones à surveiller:")
|
||||
for zone in mauvaises[:5]:
|
||||
print(f" - {zone.lib_zone}: {zone.get_qualificatif()}")
|
||||
print()
|
||||
|
||||
# 8. Recommandations
|
||||
print("8. 💡 Recommandations...")
|
||||
|
||||
if qs['moyenne'] <= 2:
|
||||
print("✅ Qualité de l'air globalement bonne en Île-de-France")
|
||||
elif qs['moyenne'] <= 3:
|
||||
print("⚠️ Qualité de l'air modérée - Surveillance recommandée")
|
||||
else:
|
||||
print("🚨 Qualité de l'air dégradée - Précautions recommandées")
|
||||
|
||||
if alerts_actives:
|
||||
print("🚨 Épisodes de pollution en cours - Limitez les activités extérieures")
|
||||
|
||||
print("\n🎉 === DÉMONSTRATION TERMINÉE ===")
|
||||
print(f"📊 Données analysées: {len(indices)} indices, {len(episodes)} épisodes, {len(emissions)} territoires")
|
||||
print("💾 Fichiers exportés dans le dossier export_*")
|
||||
|
||||
except AtmoDataException as e:
|
||||
print(f"❌ Erreur API: {e}")
|
||||
except Exception as e:
|
||||
print(f"❌ Erreur inattendue: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
472
demos/demo_emission_functions.py
Normal file
472
demos/demo_emission_functions.py
Normal file
|
@ -0,0 +1,472 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Script de démonstration des fonctionnalités de la classe EmissionData
|
||||
================================================================
|
||||
|
||||
Ce script illustre l'utilisation de toutes les méthodes disponibles
|
||||
dans la classe EmissionData pour analyser les données d'émissions.
|
||||
|
||||
Fonctionnalités testées:
|
||||
- Analyse des émissions par polluant
|
||||
- Calcul de densités d'émission par km²
|
||||
- Calcul d'émissions par habitant
|
||||
- Analyse des secteurs d'émission
|
||||
- Gestion des coordonnées géographiques
|
||||
- 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 EmissionData, AtmoDataCollection, Coordinates
|
||||
from atmo_data_wrapper import SECTEURS_EMISSIONS
|
||||
|
||||
def demo_basic_properties():
|
||||
"""Démonstration des propriétés de base d'un objet EmissionData"""
|
||||
print("=" * 60)
|
||||
print("DÉMONSTRATION DES PROPRIÉTÉS DE BASE")
|
||||
print("=" * 60)
|
||||
|
||||
# Exemple de données d'émission simulées
|
||||
sample_emission = {
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [6.1667, 49.1333] # Nancy
|
||||
},
|
||||
"properties": {
|
||||
"aasqa": "90",
|
||||
"source": "ATMO Grand Est",
|
||||
"date_maj": "2024-01-15",
|
||||
"lib_zone": "Nancy Métropole",
|
||||
"code": "54395",
|
||||
"name": "Nancy",
|
||||
"population": 104885,
|
||||
"superficie": 15.01,
|
||||
"nox": 125.5,
|
||||
"pm10": 45.2,
|
||||
"pm25": 28.7,
|
||||
"ges": 850.3,
|
||||
"code_pcaet": "01"
|
||||
}
|
||||
}
|
||||
|
||||
emission = EmissionData(sample_emission)
|
||||
|
||||
print(f"Code zone: {emission.code}")
|
||||
print(f"Nom: {emission.name}")
|
||||
print(f"Population: {emission.population:,} habitants")
|
||||
print(f"Superficie: {emission.superficie} km²")
|
||||
print(f"AASQA: {emission.get_aasqa_name()}")
|
||||
print(f"Source: {emission.get_source()}")
|
||||
print(f"Date de mise à jour: {emission.date_maj}")
|
||||
print(f"Zone: {emission.lib_zone}")
|
||||
print(f"Secteur: {emission.get_secteur_name()}")
|
||||
|
||||
if emission.has_coordinates():
|
||||
print(f"Coordonnées: {emission.coordinates}")
|
||||
else:
|
||||
print("Pas de coordonnées disponibles")
|
||||
|
||||
print(f"Représentation: {emission}")
|
||||
print()
|
||||
|
||||
def demo_emission_analysis():
|
||||
"""Démonstration de l'analyse des émissions"""
|
||||
print("=" * 60)
|
||||
print("ANALYSE DES ÉMISSIONS PAR POLLUANT")
|
||||
print("=" * 60)
|
||||
|
||||
# Exemple avec plusieurs zones d'émission
|
||||
emission_samples = [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {"type": "Point", "coordinates": [6.1667, 49.1333]},
|
||||
"properties": {
|
||||
"aasqa": "90", "name": "Nancy", "population": 104885, "superficie": 15.01,
|
||||
"nox": 125.5, "pm10": 45.2, "pm25": 28.7, "ges": 850.3, "code_pcaet": "01"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {"type": "Point", "coordinates": [7.7500, 48.5833]},
|
||||
"properties": {
|
||||
"aasqa": "90", "name": "Strasbourg", "population": 280966, "superficie": 78.26,
|
||||
"nox": 285.7, "pm10": 92.1, "pm25": 58.4, "ges": 1850.9, "code_pcaet": "02"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {"type": "Point", "coordinates": [6.2000, 49.2500]},
|
||||
"properties": {
|
||||
"aasqa": "90", "name": "Metz", "population": 116429, "superficie": 41.94,
|
||||
"nox": 155.8, "pm10": 52.3, "pm25": 35.1, "ges": 950.7, "code_pcaet": "03"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
for i, emission_data in enumerate(emission_samples, 1):
|
||||
emission = EmissionData(emission_data)
|
||||
print(f"{i}. {emission.name}")
|
||||
print(f" Population: {emission.population:,} hab, Superficie: {emission.superficie} km²")
|
||||
|
||||
# Émissions totales
|
||||
total_emissions = emission.get_total_emissions()
|
||||
print(f" Émissions totales:")
|
||||
for polluant, valeur in total_emissions.items():
|
||||
print(f" - {polluant}: {valeur:.1f} tonnes/an")
|
||||
|
||||
print()
|
||||
|
||||
def demo_density_calculations():
|
||||
"""Démonstration des calculs de densité d'émission"""
|
||||
print("=" * 60)
|
||||
print("CALCULS DE DENSITÉ D'ÉMISSION (tonnes/km²)")
|
||||
print("=" * 60)
|
||||
|
||||
emission_data = {
|
||||
"type": "Feature",
|
||||
"geometry": {"type": "Point", "coordinates": [2.3522, 48.8566]},
|
||||
"properties": {
|
||||
"aasqa": "18", "name": "Paris", "population": 2161000, "superficie": 105.4,
|
||||
"nox": 1250.5, "pm10": 425.2, "pm25": 280.7, "ges": 8500.3, "code_pcaet": "01"
|
||||
}
|
||||
}
|
||||
|
||||
emission = EmissionData(emission_data)
|
||||
|
||||
print(f"Zone: {emission.name}")
|
||||
print(f"Superficie: {emission.superficie} km²")
|
||||
print()
|
||||
print("Densités d'émission par km²:")
|
||||
|
||||
pollutants = ['nox', 'pm10', 'pm25', 'ges']
|
||||
for pollutant in pollutants:
|
||||
density = emission.get_emission_density(pollutant)
|
||||
polluant_name = pollutant.upper().replace('GES', 'GES (CO2 eq)')
|
||||
print(f" - {polluant_name}: {density:.2f} tonnes/km²")
|
||||
|
||||
print()
|
||||
|
||||
def demo_per_capita_calculations():
|
||||
"""Démonstration des calculs d'émission par habitant"""
|
||||
print("=" * 60)
|
||||
print("CALCULS D'ÉMISSION PAR HABITANT (tonnes/hab/an)")
|
||||
print("=" * 60)
|
||||
|
||||
emission_data = {
|
||||
"type": "Feature",
|
||||
"geometry": {"type": "Point", "coordinates": [3.0573, 50.6292]},
|
||||
"properties": {
|
||||
"aasqa": "59", "name": "Lille Métropole", "population": 1182127, "superficie": 611.0,
|
||||
"nox": 1580.3, "pm10": 520.7, "pm25": 315.8, "ges": 11250.5, "code_pcaet": "02"
|
||||
}
|
||||
}
|
||||
|
||||
emission = EmissionData(emission_data)
|
||||
|
||||
print(f"Zone: {emission.name}")
|
||||
print(f"Population: {emission.population:,} habitants")
|
||||
print()
|
||||
print("Émissions par habitant (en tonnes/habitant/an):")
|
||||
|
||||
pollutants = ['nox', 'pm10', 'pm25', 'ges']
|
||||
for pollutant in pollutants:
|
||||
per_capita = emission.get_emission_per_capita(pollutant)
|
||||
polluant_name = pollutant.upper().replace('GES', 'GES (CO2 eq)')
|
||||
# Convertir en kg/hab/an pour plus de lisibilité
|
||||
per_capita_kg = per_capita * 1000
|
||||
print(f" - {polluant_name}: {per_capita:.6f} t/hab/an ({per_capita_kg:.2f} kg/hab/an)")
|
||||
|
||||
print()
|
||||
|
||||
def demo_secteur_analysis():
|
||||
"""Démonstration de l'analyse par secteur d'émission"""
|
||||
print("=" * 60)
|
||||
print("ANALYSE PAR SECTEUR D'ÉMISSION")
|
||||
print("=" * 60)
|
||||
|
||||
# Simulation de différents secteurs d'émission
|
||||
secteurs_samples = [
|
||||
{"code_pcaet": "01", "name": "Transport routier", "nox": 850.5, "pm10": 45.2},
|
||||
{"code_pcaet": "02", "name": "Industrie manufacturière", "nox": 320.8, "pm10": 85.7},
|
||||
{"code_pcaet": "03", "name": "Résidentiel", "nox": 125.3, "pm10": 95.4},
|
||||
{"code_pcaet": "04", "name": "Agriculture", "nox": 85.2, "pm10": 125.8},
|
||||
{"code_pcaet": "05", "name": "Tertiaire", "nox": 65.7, "pm10": 25.3}
|
||||
]
|
||||
|
||||
print("Émissions par secteur:")
|
||||
print()
|
||||
|
||||
for i, secteur_data in enumerate(secteurs_samples, 1):
|
||||
emission_data = {
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"aasqa": "25", "name": f"Zone {i}", "population": 50000, "superficie": 25.0,
|
||||
"nox": secteur_data["nox"], "pm10": secteur_data["pm10"], "pm25": 15.0, "ges": 500.0,
|
||||
"code_pcaet": secteur_data["code_pcaet"]
|
||||
}
|
||||
}
|
||||
|
||||
emission = EmissionData(emission_data)
|
||||
print(f"{i}. Secteur: {emission.get_secteur_name()}")
|
||||
print(f" Code PCAET: {emission.code_pcaet}")
|
||||
print(f" Émissions NOx: {emission.nox:.1f} t/an")
|
||||
print(f" Émissions PM10: {emission.pm10:.1f} t/an")
|
||||
print()
|
||||
|
||||
def demo_coordinate_functions():
|
||||
"""Démonstration des fonctions de coordonnées géographiques"""
|
||||
print("=" * 60)
|
||||
print("FONCTIONS DE COORDONNÉES GÉOGRAPHIQUES")
|
||||
print("=" * 60)
|
||||
|
||||
# Créer des émissions avec coordonnées
|
||||
emission_lille = EmissionData({
|
||||
"type": "Feature",
|
||||
"geometry": {"type": "Point", "coordinates": [3.0573, 50.6292]},
|
||||
"properties": {
|
||||
"aasqa": "59", "name": "Lille", "population": 233897, "superficie": 34.8,
|
||||
"nox": 285.5, "pm10": 85.2, "pm25": 55.7, "ges": 1250.3, "code_pcaet": "01"
|
||||
}
|
||||
})
|
||||
|
||||
emission_nancy = EmissionData({
|
||||
"type": "Feature",
|
||||
"geometry": {"type": "Point", "coordinates": [6.1667, 49.1333]},
|
||||
"properties": {
|
||||
"aasqa": "90", "name": "Nancy", "population": 104885, "superficie": 15.01,
|
||||
"nox": 125.5, "pm10": 45.2, "pm25": 28.7, "ges": 850.3, "code_pcaet": "01"
|
||||
}
|
||||
})
|
||||
|
||||
print(f"Émission 1: {emission_lille.name}")
|
||||
print(f" Coordonnées: {emission_lille.coordinates}")
|
||||
print(f" A des coordonnées: {emission_lille.has_coordinates()}")
|
||||
print()
|
||||
|
||||
print(f"Émission 2: {emission_nancy.name}")
|
||||
print(f" Coordonnées: {emission_nancy.coordinates}")
|
||||
print(f" A des coordonnées: {emission_nancy.has_coordinates()}")
|
||||
print()
|
||||
|
||||
# Calcul de distance
|
||||
if emission_lille.has_coordinates() and emission_nancy.has_coordinates():
|
||||
distance = emission_lille.coordinates.distance_to(emission_nancy.coordinates)
|
||||
print(f"Distance entre {emission_lille.name} et {emission_nancy.name}: {distance:.1f} km")
|
||||
|
||||
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)
|
||||
|
||||
emission_data = {
|
||||
"type": "Feature",
|
||||
"geometry": {"type": "Point", "coordinates": [4.8357, 45.7640]},
|
||||
"properties": {
|
||||
"aasqa": "84", "name": "Lyon Métropole", "population": 1398892, "superficie": 533.68,
|
||||
"nox": 1850.7, "pm10": 625.4, "pm25": 385.2, "ges": 13250.8, "code_pcaet": "02",
|
||||
"source": "ATMO Auvergne-Rhône-Alpes", "date_maj": "2024-01-15"
|
||||
}
|
||||
}
|
||||
|
||||
emission = EmissionData(emission_data)
|
||||
|
||||
print(f"Zone: {emission.name}")
|
||||
print(f"AASQA: {emission.get_aasqa_name()}")
|
||||
print(f"Source: {emission.get_source()}")
|
||||
print()
|
||||
|
||||
# Test des fonctions de couleur et emoji (niveau fictif pour démonstration)
|
||||
print("Fonctions de couleur et emoji (exemple avec niveau 3):")
|
||||
test_level = 3
|
||||
couleur_hex, couleur_rgb = emission.get_color_by_level(test_level)
|
||||
emoji_round = emission.get_emoji_by_level(test_level, "round")
|
||||
emoji_square = emission.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 plusieurs zones"""
|
||||
print("=" * 60)
|
||||
print("ANALYSE COMPARATIVE ENTRE ZONES")
|
||||
print("=" * 60)
|
||||
|
||||
zones_data = [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {"type": "Point", "coordinates": [2.3522, 48.8566]},
|
||||
"properties": {
|
||||
"aasqa": "18", "name": "Paris", "population": 2161000, "superficie": 105.4,
|
||||
"nox": 1250.5, "pm10": 425.2, "pm25": 280.7, "ges": 8500.3, "code_pcaet": "01"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {"type": "Point", "coordinates": [4.8357, 45.7640]},
|
||||
"properties": {
|
||||
"aasqa": "84", "name": "Lyon", "population": 1398892, "superficie": 533.68,
|
||||
"nox": 1850.7, "pm10": 625.4, "pm25": 385.2, "ges": 13250.8, "code_pcaet": "02"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {"type": "Point", "coordinates": [5.3698, 43.2965]},
|
||||
"properties": {
|
||||
"aasqa": "13", "name": "Marseille", "population": 868277, "superficie": 240.62,
|
||||
"nox": 980.3, "pm10": 385.7, "pm25": 245.8, "ges": 7250.5, "code_pcaet": "01"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
emissions = [EmissionData(zone) for zone in zones_data]
|
||||
|
||||
print("Comparaison des émissions par habitant (kg/hab/an):")
|
||||
print("-" * 55)
|
||||
print(f"{'Zone':<15} {'NOx':<8} {'PM10':<8} {'PM2.5':<8} {'GES':<10}")
|
||||
print("-" * 55)
|
||||
|
||||
for emission in emissions:
|
||||
nox_per_cap = emission.get_emission_per_capita('nox') * 1000 # Conversion en kg
|
||||
pm10_per_cap = emission.get_emission_per_capita('pm10') * 1000
|
||||
pm25_per_cap = emission.get_emission_per_capita('pm25') * 1000
|
||||
ges_per_cap = emission.get_emission_per_capita('ges') * 1000
|
||||
|
||||
print(f"{emission.name:<15} {nox_per_cap:<8.1f} {pm10_per_cap:<8.1f} {pm25_per_cap:<8.1f} {ges_per_cap:<10.1f}")
|
||||
|
||||
print()
|
||||
print("Comparaison des densités d'émission (tonnes/km²):")
|
||||
print("-" * 55)
|
||||
print(f"{'Zone':<15} {'NOx':<8} {'PM10':<8} {'PM2.5':<8} {'GES':<10}")
|
||||
print("-" * 55)
|
||||
|
||||
for emission in emissions:
|
||||
nox_density = emission.get_emission_density('nox')
|
||||
pm10_density = emission.get_emission_density('pm10')
|
||||
pm25_density = emission.get_emission_density('pm25')
|
||||
ges_density = emission.get_emission_density('ges')
|
||||
|
||||
print(f"{emission.name:<15} {nox_density:<8.1f} {pm10_density:<8.1f} {pm25_density:<8.1f} {ges_density:<10.1f}")
|
||||
|
||||
print()
|
||||
|
||||
def demo_edge_cases():
|
||||
"""Démonstration de la gestion des cas particuliers"""
|
||||
print("=" * 60)
|
||||
print("GESTION DES CAS PARTICULIERS")
|
||||
print("=" * 60)
|
||||
|
||||
# Cas 1: Données manquantes
|
||||
print("1. Zone sans coordonnées:")
|
||||
emission_no_coords = EmissionData({
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"aasqa": "99", "name": "Zone sans coordonnées", "population": 10000, "superficie": 20.0,
|
||||
"nox": 50.0, "pm10": 20.0, "pm25": 15.0, "ges": 300.0, "code_pcaet": "01"
|
||||
}
|
||||
})
|
||||
|
||||
print(f" A des coordonnées: {emission_no_coords.has_coordinates()}")
|
||||
print(f" Coordonnées: {emission_no_coords.coordinates}")
|
||||
print()
|
||||
|
||||
# Cas 2: Population nulle (division par zéro)
|
||||
print("2. Zone sans population:")
|
||||
emission_no_pop = EmissionData({
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"aasqa": "99", "name": "Zone industrielle", "population": 0, "superficie": 5.0,
|
||||
"nox": 150.0, "pm10": 25.0, "pm25": 18.0, "ges": 800.0, "code_pcaet": "02"
|
||||
}
|
||||
})
|
||||
|
||||
nox_per_cap = emission_no_pop.get_emission_per_capita('nox')
|
||||
print(f" Émission NOx par habitant: {nox_per_cap} (population = 0)")
|
||||
print()
|
||||
|
||||
# Cas 3: Superficie nulle
|
||||
print("3. Zone sans superficie:")
|
||||
emission_no_area = EmissionData({
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"aasqa": "99", "name": "Point source", "population": 100, "superficie": 0,
|
||||
"nox": 25.0, "pm10": 8.0, "pm25": 5.0, "ges": 150.0, "code_pcaet": "02"
|
||||
}
|
||||
})
|
||||
|
||||
nox_density = emission_no_area.get_emission_density('nox')
|
||||
print(f" Densité NOx: {nox_density} (superficie = 0)")
|
||||
print()
|
||||
|
||||
# Cas 4: Secteur inconnu
|
||||
print("4. Secteur d'émission non référencé:")
|
||||
emission_unknown_sector = EmissionData({
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"aasqa": "99", "name": "Zone test", "population": 5000, "superficie": 10.0,
|
||||
"nox": 35.0, "pm10": 12.0, "pm25": 8.0, "ges": 200.0, "code_pcaet": "99"
|
||||
}
|
||||
})
|
||||
|
||||
print(f" Code secteur: {emission_unknown_sector.code_pcaet}")
|
||||
print(f" Nom secteur: {emission_unknown_sector.get_secteur_name()}")
|
||||
print()
|
||||
|
||||
def main():
|
||||
"""Fonction principale de démonstration"""
|
||||
print("SCRIPT DE DÉMONSTRATION - CLASSE EMISSIONDATA")
|
||||
print("=" * 60)
|
||||
print("Ce script teste toutes les fonctionnalités de la classe EmissionData")
|
||||
print("pour l'analyse des données d'émissions atmosphériques.")
|
||||
print()
|
||||
|
||||
try:
|
||||
# Exécution de toutes les démonstrations
|
||||
demo_basic_properties()
|
||||
demo_emission_analysis()
|
||||
demo_density_calculations()
|
||||
demo_per_capita_calculations()
|
||||
demo_secteur_analysis()
|
||||
demo_coordinate_functions()
|
||||
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 à EmissionData:")
|
||||
print("✓ get_emission_density(pollutant)")
|
||||
print("✓ get_emission_per_capita(pollutant)")
|
||||
print("✓ get_total_emissions()")
|
||||
print("✓ get_secteur_name()")
|
||||
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("✓ Coordonnées géographiques et distance")
|
||||
print("✓ Émissions par polluant (nox, pm10, pm25, ges)")
|
||||
print("✓ Données démographiques (population, superficie)")
|
||||
print("✓ Secteurs d'émission (code_pcaet)")
|
||||
print("✓ Gestion des cas particuliers (données manquantes)")
|
||||
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()
|
536
demos/demo_episode_functions.py
Normal file
536
demos/demo_episode_functions.py
Normal file
|
@ -0,0 +1,536 @@
|
|||
#!/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()
|
213
demos/demo_licence_atmo.py
Normal file
213
demos/demo_licence_atmo.py
Normal file
|
@ -0,0 +1,213 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Démonstration des fonctions de licence Atmo France
|
||||
=================================================
|
||||
|
||||
Ce script montre comment utiliser les fonctions utilitaires pour afficher
|
||||
la mention légale requise par Atmo France selon leur licence d'utilisation
|
||||
des données en open data sous licence ODbL.
|
||||
|
||||
Conformément aux exigences d'Atmo France:
|
||||
"Chacun peut donc bénéficier gratuitement de ces données mises en open data
|
||||
sous licence ODbL, en indiquant la source "Atmo France et les Associations
|
||||
agréées de surveillance de la qualité de l'air" ou "Atmo France / AASQA"
|
||||
dans sa version courte."
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Ajouter le répertoire parent au PYTHONPATH pour importer le package local
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from atmo_data_wrapper import (
|
||||
get_atmo_licence,
|
||||
print_atmo_licence,
|
||||
ATMO_LICENCE_COURTE,
|
||||
ATMO_LICENCE_LONGUE,
|
||||
ATMO_LICENCE_COMPLETE
|
||||
)
|
||||
|
||||
|
||||
def demo_licence_formats():
|
||||
"""Démonstration des différents formats de licence"""
|
||||
print("📋 FORMATS DE LICENCE ATMO FRANCE")
|
||||
print("=" * 50)
|
||||
print()
|
||||
|
||||
print("1️⃣ Version courte (recommandée pour citations):")
|
||||
print(f" → {get_atmo_licence('courte')}")
|
||||
print()
|
||||
|
||||
print("2️⃣ Version longue (nom officiel complet):")
|
||||
print(f" → {get_atmo_licence('longue')}")
|
||||
print()
|
||||
|
||||
print("3️⃣ Version complète (avec détails de licence):")
|
||||
print(get_atmo_licence('complete'))
|
||||
print()
|
||||
|
||||
|
||||
def demo_usage_examples():
|
||||
"""Exemples d'utilisation pratique"""
|
||||
print("💡 EXEMPLES D'UTILISATION PRATIQUE")
|
||||
print("=" * 50)
|
||||
print()
|
||||
|
||||
print("1️⃣ Dans un script de données:")
|
||||
print("```python")
|
||||
print("from atmo_data_wrapper import get_atmo_licence")
|
||||
print()
|
||||
print("# Récupérer des données")
|
||||
print("indices = client.get_indices_atmo()")
|
||||
print()
|
||||
print("# Afficher la source")
|
||||
print('print(f"Source: {get_atmo_licence(\'courte\')}")')
|
||||
print("```")
|
||||
print()
|
||||
print("Résultat:")
|
||||
print(f"Source: {get_atmo_licence('courte')}")
|
||||
print()
|
||||
|
||||
print("2️⃣ Dans un rapport ou documentation:")
|
||||
print("```python")
|
||||
print("print_atmo_licence('complete')")
|
||||
print("```")
|
||||
print()
|
||||
print("Résultat:")
|
||||
print_atmo_licence('complete')
|
||||
print()
|
||||
|
||||
print("3️⃣ Accès direct aux constantes:")
|
||||
print("```python")
|
||||
print("from atmo_data_wrapper import ATMO_LICENCE_COURTE")
|
||||
print("print(ATMO_LICENCE_COURTE)")
|
||||
print("```")
|
||||
print()
|
||||
print("Résultat:")
|
||||
print(ATMO_LICENCE_COURTE)
|
||||
print()
|
||||
|
||||
|
||||
def demo_integration_examples():
|
||||
"""Exemples d'intégration dans différents contextes"""
|
||||
print("🔧 EXEMPLES D'INTÉGRATION")
|
||||
print("=" * 50)
|
||||
print()
|
||||
|
||||
print("1️⃣ Dans un fichier CSV:")
|
||||
print("# Commentaire en en-tête de fichier CSV")
|
||||
print(f"# Source: {get_atmo_licence('longue')}")
|
||||
print("# Licence: ODbL")
|
||||
print("commune,indice_atmo,date")
|
||||
print("Nancy,2,2024-01-15")
|
||||
print("...")
|
||||
print()
|
||||
|
||||
print("2️⃣ Dans un graphique matplotlib:")
|
||||
print("```python")
|
||||
print("import matplotlib.pyplot as plt")
|
||||
print("from atmo_data_wrapper import get_atmo_licence")
|
||||
print()
|
||||
print("# Créer le graphique")
|
||||
print("plt.plot(dates, indices)")
|
||||
print("plt.title('Évolution de la qualité de l\\'air')")
|
||||
print()
|
||||
print("# Ajouter la source")
|
||||
print("plt.figtext(0.02, 0.02, f'Source: {get_atmo_licence(\'courte\')}', fontsize=8)")
|
||||
print("plt.show()")
|
||||
print("```")
|
||||
print()
|
||||
|
||||
print("3️⃣ Dans une API REST:")
|
||||
print("```python")
|
||||
print("from flask import Flask, jsonify")
|
||||
print("from atmo_data_wrapper import get_atmo_licence")
|
||||
print()
|
||||
print("@app.route('/api/air-quality')")
|
||||
print("def get_air_quality():")
|
||||
print(" data = get_air_quality_data()")
|
||||
print(" return jsonify({")
|
||||
print(" 'data': data,")
|
||||
print(" 'source': get_atmo_licence('courte'),")
|
||||
print(" 'licence': 'ODbL'")
|
||||
print(" })")
|
||||
print("```")
|
||||
print()
|
||||
|
||||
print("4️⃣ Dans un footer HTML:")
|
||||
print("```html")
|
||||
print("<footer>")
|
||||
print(f" <p>Source des données: {get_atmo_licence('longue')}</p>")
|
||||
print(" <p>Licence: <a href='https://opendatacommons.org/licenses/odbl/'>ODbL</a></p>")
|
||||
print("</footer>")
|
||||
print("```")
|
||||
print()
|
||||
|
||||
|
||||
def demo_licence_compliance():
|
||||
"""Vérification de conformité avec les exigences"""
|
||||
print("✅ CONFORMITÉ AVEC LES EXIGENCES ATMO FRANCE")
|
||||
print("=" * 55)
|
||||
print()
|
||||
|
||||
print("📋 Exigences officielles:")
|
||||
print('• Indiquer la source "Atmo France et les Associations agréées"')
|
||||
print('• Ou version courte "Atmo France / AASQA"')
|
||||
print('• Respecter la licence ODbL')
|
||||
print()
|
||||
|
||||
print("✅ Notre implémentation:")
|
||||
print(f"• Version courte: '{get_atmo_licence('courte')}'")
|
||||
print(f"• Version longue: '{get_atmo_licence('longue')}'")
|
||||
print("• Mention de la licence ODbL incluse")
|
||||
print("• URLs officielles fournies")
|
||||
print()
|
||||
|
||||
print("🎯 Recommandations d'usage:")
|
||||
print("• Utiliser la version courte pour les citations courtes")
|
||||
print("• Utiliser la version longue pour les documents officiels")
|
||||
print("• Utiliser la version complète pour les mentions légales détaillées")
|
||||
print("• Toujours mentionner la licence ODbL")
|
||||
print()
|
||||
|
||||
|
||||
def main():
|
||||
"""Fonction principale"""
|
||||
print("DÉMONSTRATION DES FONCTIONS DE LICENCE ATMO FRANCE")
|
||||
print("=" * 60)
|
||||
print("Conformité avec les exigences de licence ODbL d'Atmo France")
|
||||
print()
|
||||
|
||||
try:
|
||||
demo_licence_formats()
|
||||
demo_usage_examples()
|
||||
demo_integration_examples()
|
||||
demo_licence_compliance()
|
||||
|
||||
print("=" * 60)
|
||||
print("✅ DÉMONSTRATION TERMINÉE AVEC SUCCÈS")
|
||||
print()
|
||||
print("🔑 Fonctions disponibles:")
|
||||
print(" • get_atmo_licence(format): Retourne la licence selon le format")
|
||||
print(" • print_atmo_licence(format): Affiche la licence")
|
||||
print()
|
||||
print("📋 Formats supportés:")
|
||||
print(" • 'courte': Version abrégée")
|
||||
print(" • 'longue': Version officielle complète")
|
||||
print(" • 'complete': Avec détails de licence")
|
||||
print()
|
||||
print("📁 Constantes disponibles:")
|
||||
print(" • ATMO_LICENCE_COURTE")
|
||||
print(" • ATMO_LICENCE_LONGUE")
|
||||
print(" • ATMO_LICENCE_COMPLETE")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Erreur lors de l'exécution: {e}")
|
||||
import traceback
|
||||
print("\nDétails de l'erreur:")
|
||||
print(traceback.format_exc())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
333
demos/demo_pollen_functions.py
Normal file
333
demos/demo_pollen_functions.py
Normal file
|
@ -0,0 +1,333 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Script de démonstration de toutes les fonctions du datamodel IndicePollen
|
||||
Utilise les données réelles de l'API pour Tomblaine (aujourd'hui)
|
||||
Idéal pour documentation et exemples
|
||||
"""
|
||||
|
||||
from atmo_data_wrapper import AtmoDataClient, AtmoDataException
|
||||
from atmo_data_wrapper import CODE_TAXON
|
||||
from datetime import datetime
|
||||
import sys
|
||||
|
||||
def demo_pollen_functions():
|
||||
"""Démonstration complète des fonctions IndicePollen avec données réelles"""
|
||||
|
||||
# Configuration
|
||||
CODE_INSEE_TOMBLAINE = "54526"
|
||||
AASQA_GRAND_EST = "44"
|
||||
today = datetime.now().strftime('%Y-%m-%d')
|
||||
|
||||
print("🌸 DÉMONSTRATION DES FONCTIONS INDICEPOLLEN")
|
||||
print("=" * 55)
|
||||
print(f"📍 Ville: Tomblaine (INSEE: {CODE_INSEE_TOMBLAINE})")
|
||||
print(f"🗓️ Date: {today}")
|
||||
print(f"🏛️ AASQA: {AASQA_GRAND_EST} (Grand Est)")
|
||||
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 pollen
|
||||
print(f"🌸 Récupération des indices pollen pour {today}...")
|
||||
pollens = client.get_indices_pollens(
|
||||
format="geojson",
|
||||
date=today,
|
||||
aasqa=AASQA_GRAND_EST,
|
||||
code_zone=CODE_INSEE_TOMBLAINE,
|
||||
with_geom=False
|
||||
)
|
||||
|
||||
if not pollens or len(pollens) == 0:
|
||||
print("❌ Aucune donnée pollen trouvée")
|
||||
return False
|
||||
|
||||
print(f"✅ {len(pollens)} station(s) trouvée(s)")
|
||||
|
||||
# Utiliser la première station pour la démo
|
||||
pollen = pollens[0]
|
||||
print(f"📍 Station sélectionnée: {pollen.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: {pollen.aasqa}")
|
||||
print(f" • Zone: {pollen.lib_zone}")
|
||||
print(f" • Source: {pollen.source}")
|
||||
print(f" • Alerte active: {pollen.alerte}")
|
||||
print()
|
||||
|
||||
print("🗺️ COORDONNÉES:")
|
||||
if pollen.has_coordinates():
|
||||
coords = pollen.get_coordinates()
|
||||
print(f" • Latitude: {coords.latitude:.6f}")
|
||||
print(f" • Longitude: {coords.longitude:.6f}")
|
||||
else:
|
||||
print(" • Pas de coordonnées disponibles")
|
||||
print()
|
||||
|
||||
print("🎨 FONCTIONS CENTRALISÉES:")
|
||||
for level in [0, 1, 2, 3, 4]:
|
||||
emoji_round = pollen.get_emoji_by_level(level, "round")
|
||||
emoji_square = pollen.get_emoji_by_level(level, "square")
|
||||
color_hex, color_rgb = pollen.get_color_by_level(level)
|
||||
print(f" • Niveau {level}: {emoji_round}{emoji_square} {color_hex} {color_rgb}")
|
||||
print()
|
||||
|
||||
# === DÉMONSTRATION DES PROPRIÉTÉS SPÉCIFIQUES POLLEN ===
|
||||
print("🌿 === PROPRIÉTÉS SPÉCIFIQUES POLLEN ===")
|
||||
print()
|
||||
|
||||
print("📈 CODES PAR TAXON:")
|
||||
print(f" • Ambroisie (ambr): {pollen.code_ambr}")
|
||||
print(f" • Armoise (arm): {pollen.code_arm}")
|
||||
print(f" • Aulne (aul): {pollen.code_aul}")
|
||||
print(f" • Bouleau (boul): {pollen.code_boul}")
|
||||
print(f" • Graminées (gram): {pollen.code_gram}")
|
||||
print(f" • Olivier (oliv): {pollen.code_oliv}")
|
||||
print()
|
||||
|
||||
print("🔬 CONCENTRATIONS (grains/m³):")
|
||||
print(f" • Ambroisie: {pollen.conc_ambr:.1f}")
|
||||
print(f" • Armoise: {pollen.conc_arm:.1f}")
|
||||
print(f" • Aulne: {pollen.conc_aul:.1f}")
|
||||
print(f" • Bouleau: {pollen.conc_boul:.1f}")
|
||||
print(f" • Graminées: {pollen.conc_gram:.1f}")
|
||||
print(f" • Olivier: {pollen.conc_oliv:.1f}")
|
||||
print()
|
||||
|
||||
print("🎯 TAXONS RESPONSABLES DE L'INDICE:")
|
||||
print(f" • pollen_resp (raw): '{pollen.pollen_resp}'")
|
||||
print()
|
||||
|
||||
# === DÉMONSTRATION DES MÉTHODES HELPER ===
|
||||
print("🛠️ === MÉTHODES HELPER ===")
|
||||
print()
|
||||
|
||||
# 1. is_alert_active()
|
||||
print("🚨 1. DÉTECTION D'ALERTE:")
|
||||
alert_active = pollen.is_alert_active()
|
||||
print(f" • is_alert_active(): {alert_active}")
|
||||
if alert_active:
|
||||
print(" → Alerte pollen active !")
|
||||
else:
|
||||
print(" → Pas d'alerte pollen")
|
||||
print()
|
||||
|
||||
# 2. get_highest_pollen()
|
||||
print("🏆 2. POLLEN LE PLUS ÉLEVÉ:")
|
||||
highest_taxon, highest_code = pollen.get_highest_pollen()
|
||||
highest_name = CODE_TAXON.get(highest_taxon, highest_taxon.title())
|
||||
print(f" • get_highest_pollen(): ('{highest_taxon}', {highest_code})")
|
||||
print(f" → Espèce: {highest_name}")
|
||||
print(f" → Niveau: {highest_code}")
|
||||
print()
|
||||
|
||||
# 3. get_highest_concentration()
|
||||
print("🔬 3. CONCENTRATION LA PLUS ÉLEVÉE:")
|
||||
highest_conc_taxon, highest_conc_value = pollen.get_highest_concentration()
|
||||
highest_conc_name = CODE_TAXON.get(highest_conc_taxon, highest_conc_taxon.title())
|
||||
print(f" • get_highest_concentration(): ('{highest_conc_taxon}', {highest_conc_value})")
|
||||
print(f" → Espèce: {highest_conc_name}")
|
||||
print(f" → Concentration: {highest_conc_value:.1f} grains/m³")
|
||||
print()
|
||||
|
||||
# 4. get_dangerous_pollens()
|
||||
print("⚠️ 4. POLLENS DANGEREUX (niveau ≥ 4):")
|
||||
dangerous = pollen.get_dangerous_pollens()
|
||||
print(f" • get_dangerous_pollens(): {dangerous}")
|
||||
if dangerous:
|
||||
dangerous_names = [CODE_TAXON.get(p, p.title()) for p in dangerous]
|
||||
print(f" → Espèces à risque: {', '.join(dangerous_names)}")
|
||||
else:
|
||||
print(" → Aucun pollen à risque élevé")
|
||||
print()
|
||||
|
||||
# 5. get_responsible_pollens() - NOUVELLE MÉTHODE
|
||||
print("🎯 5. TAXONS RESPONSABLES DE L'INDICE (API):")
|
||||
responsible = pollen.get_responsible_pollens()
|
||||
print(f" • get_responsible_pollens(): {responsible}")
|
||||
if responsible:
|
||||
print(f" → Espèces responsables selon l'API: {', '.join(responsible)}")
|
||||
else:
|
||||
print(" → Aucun taxon responsable spécifié par l'API")
|
||||
print()
|
||||
|
||||
# 6. get_concentrations()
|
||||
print("📊 6. TOUTES LES CONCENTRATIONS:")
|
||||
concentrations = pollen.get_concentrations()
|
||||
print(f" • get_concentrations(): {concentrations}")
|
||||
print(" → Détail:")
|
||||
for taxon, conc in concentrations.items():
|
||||
taxon_name = CODE_TAXON.get(taxon, taxon.title())
|
||||
print(f" - {taxon_name}: {conc:.1f} grains/m³")
|
||||
print()
|
||||
|
||||
# 7. get_pollens_summary()
|
||||
print("📋 7. RÉSUMÉ COMPLET:")
|
||||
summary = pollen.get_pollens_summary()
|
||||
print(f" • get_pollens_summary():")
|
||||
print(" → Structure complète par taxon:")
|
||||
|
||||
for code_taxon, info in summary.items():
|
||||
if info['code'] > 0: # Afficher seulement les pollens détectés
|
||||
print(f" - {code_taxon}:")
|
||||
print(f" * Code: {info['code']}")
|
||||
print(f" * Espèce: {info['espece']}")
|
||||
print(f" * Qualificatif: {info['qualificatif']}")
|
||||
print(f" * Concentration: {info['concentration']:.1f} gr/m³")
|
||||
print(f" * Couleur: {info['couleur']}")
|
||||
print(f" * Émoji rond: {info['emoji_round']}")
|
||||
print(f" * Émoji carré: {info['emoji_square']}")
|
||||
print()
|
||||
|
||||
# 8. Test des styles d'émojis
|
||||
print("🎨 8. TEST DES STYLES D'ÉMOJIS:")
|
||||
summary_round = pollen.get_pollens_summary("round")
|
||||
summary_square = pollen.get_pollens_summary("square")
|
||||
print(" • Comparaison des styles par défaut:")
|
||||
for code_taxon in ['arm', 'gram']: # Tester avec les pollens détectés
|
||||
if summary_round[code_taxon]['code'] > 0:
|
||||
round_emoji = summary_round[code_taxon]['emoji']
|
||||
square_emoji = summary_square[code_taxon]['emoji']
|
||||
espece = summary_round[code_taxon]['espece']
|
||||
print(f" - {espece}: Rond={round_emoji} | Carré={square_emoji}")
|
||||
print()
|
||||
|
||||
# === DÉMONSTRATION DES MÉTHODES STRING ===
|
||||
print("📝 === REPRÉSENTATION STRING ===")
|
||||
print()
|
||||
|
||||
print("🔤 MÉTHODE __str__():")
|
||||
print(f" • str(pollen): '{str(pollen)}'")
|
||||
print()
|
||||
|
||||
# === EXEMPLES D'UTILISATION PRATIQUE ===
|
||||
print("💡 === EXEMPLES D'UTILISATION PRATIQUE ===")
|
||||
print()
|
||||
|
||||
print("🎯 ANALYSE RAPIDE:")
|
||||
print(f" • Niveau global le plus élevé: {highest_name} (niveau {highest_code})")
|
||||
print(f" • Concentration maximale: {highest_conc_name} ({highest_conc_value:.1f} gr/m³)")
|
||||
|
||||
if alert_active:
|
||||
print(" • ⚠️ ALERTE ACTIVE - Précautions recommandées")
|
||||
|
||||
if dangerous:
|
||||
print(f" • 🚨 POLLENS À RISQUE: {', '.join([CODE_TAXON.get(p, p) for p in dangerous])}")
|
||||
else:
|
||||
print(" • ✅ Aucun pollen à risque élevé")
|
||||
print()
|
||||
|
||||
print("📈 DÉTECTION DE TENDANCES:")
|
||||
detected_pollens = [taxon for taxon, info in summary.items() if info['code'] > 0]
|
||||
significant_pollens = [taxon for taxon, info in summary.items() if info['code'] >= 2]
|
||||
|
||||
print(f" • Pollens détectés: {len(detected_pollens)} espèces")
|
||||
print(f" • Pollens significatifs (≥2): {len(significant_pollens)} espèces")
|
||||
|
||||
if significant_pollens:
|
||||
sig_names = [CODE_TAXON.get(p, p) for p in significant_pollens]
|
||||
print(f" → {', '.join(sig_names)}")
|
||||
print()
|
||||
|
||||
print("🔍 FILTRAGE AVANCÉ:")
|
||||
# Exemple de filtrage par concentration
|
||||
high_conc = {t: c for t, c in concentrations.items() if c > 5.0}
|
||||
if high_conc:
|
||||
print(" • Concentrations élevées (>5 gr/m³):")
|
||||
for taxon, conc in high_conc.items():
|
||||
taxon_name = CODE_TAXON.get(taxon, taxon.title())
|
||||
print(f" → {taxon_name}: {conc:.1f} gr/m³")
|
||||
else:
|
||||
print(" • Aucune concentration élevée (>5 gr/m³)")
|
||||
print()
|
||||
|
||||
# === INFORMATIONS TECHNIQUES ===
|
||||
print("🔧 === INFORMATIONS TECHNIQUES ===")
|
||||
print()
|
||||
|
||||
print("📦 STRUCTURE DE DONNÉES:")
|
||||
print(f" • Type d'objet: {type(pollen).__name__}")
|
||||
print(f" • Classe parente: {type(pollen).__bases__[0].__name__}")
|
||||
print(f" • Propriétés disponibles: {len(pollen.properties)} champs")
|
||||
print(f" • Géométrie: {'Oui' if pollen.has_coordinates() else 'Non'}")
|
||||
print()
|
||||
|
||||
print("🎨 MÉTHODES HÉRITÉES:")
|
||||
inherited_methods = [
|
||||
'get_emoji_by_level()', 'get_color_by_level()', 'has_coordinates()',
|
||||
'get_coordinates()', 'get_source()'
|
||||
]
|
||||
print(f" • Méthodes de AtmoDataBase: {', '.join(inherited_methods)}")
|
||||
print()
|
||||
|
||||
specific_methods = [
|
||||
'is_alert_active()', 'get_highest_pollen()', 'get_highest_concentration()',
|
||||
'get_dangerous_pollens()', 'get_responsible_pollens()', 'get_concentrations()', 'get_pollens_summary()'
|
||||
]
|
||||
print(f" • Méthodes spécifiques IndicePollen: {', '.join(specific_methods)}")
|
||||
print()
|
||||
|
||||
print("🎨 NOUVEAUTÉS ÉMOJIS:")
|
||||
print(" • get_emoji_by_level(level, style) - style='round'|'square'")
|
||||
print(" • get_emoji(style) - pour IndiceAtmo avec choix de style")
|
||||
print(" • get_pollens_summary(emoji_style) - résumé avec style d'émoji")
|
||||
print(" • Chaque résumé inclut emoji_round ET emoji_square")
|
||||
print()
|
||||
|
||||
print("📋 CONFORMITÉ NOTICE OFFICIELLE (1er avril 2025):")
|
||||
print(" • Tous les champs de la notice officielle sont supportés")
|
||||
print(" • Classes IndiceAtmo et IndicePollen conformes aux spécifications")
|
||||
print(" • Nouvelles propriétés pour IndiceAtmo : type_zone, coordonnées réglementaires")
|
||||
print(" • Concentrations facultatives ajoutées selon la notice")
|
||||
print(" • Méthodes basées sur les règles officielles de calcul")
|
||||
print(" • Codes couleur et qualificatifs conformes au tableau page 6")
|
||||
print()
|
||||
|
||||
print("✅ === DÉMONSTRATION TERMINÉE ===")
|
||||
print()
|
||||
print("📚 Ce script illustre toutes les fonctionnalités de la classe IndicePollen")
|
||||
print("🔧 Utilisez ces exemples pour votre documentation et vos développements")
|
||||
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 IndicePollen")
|
||||
print("=" * 55)
|
||||
print()
|
||||
|
||||
success = demo_pollen_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()
|
Loading…
Add table
Add a link
Reference in a new issue