#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Script pour analyser les polygones de villes et générer des fichiers JSON d'analyse. Ce script: 1. Parcourt tous les fichiers de polygones dans le dossier "polygons" 2. Pour chaque polygone, vérifie si un fichier d'analyse JSON existe déjà 3. Si non, utilise loop_thematics_history_in_zone_to_counts.py pour extraire les données 4. Sauvegarde les résultats dans un fichier JSON avec une analyse de complétion 5. Ajoute une date de création à chaque analyse Usage: python analyze_city_polygons.py """ import os import sys import json import glob import subprocess import argparse from datetime import datetime from pathlib import Path # Import des thèmes depuis loop_thematics_history_in_zone_to_counts.py from loop_thematics_history_in_zone_to_counts import THEMES # Chemins des répertoires SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) POLYGONS_DIR = os.path.join(SCRIPT_DIR, "polygons") OSM_DATA_FILE = os.path.join(SCRIPT_DIR, "osm_data", "france-latest.osm.pbf") ANALYSIS_DIR = os.path.join(SCRIPT_DIR, "city_analysis") TEMP_DIR = os.path.join(SCRIPT_DIR, "temp") OUTPUT_DIR = os.path.join(SCRIPT_DIR, "resultats") def ensure_directories_exist(): """ Vérifie que les répertoires nécessaires existent, sinon les crée. """ os.makedirs(POLYGONS_DIR, exist_ok=True) os.makedirs(ANALYSIS_DIR, exist_ok=True) os.makedirs(TEMP_DIR, exist_ok=True) os.makedirs(OUTPUT_DIR, exist_ok=True) print(f"Dossier d'analyses: {ANALYSIS_DIR}") def analysis_exists(insee_code): """ Vérifie si l'analyse pour le code INSEE donné existe déjà. Args: insee_code (str): Le code INSEE de la commune Returns: bool: True si l'analyse existe, False sinon """ analysis_file = os.path.join(ANALYSIS_DIR, f"analyse_commune_{insee_code}.json") return os.path.isfile(analysis_file) def run_command(command): """ Exécute une commande shell et retourne la sortie. Args: command (str): La commande à exécuter Returns: str: La sortie de la commande ou None en cas d'erreur """ print(f"Exécution: {command}") try: result = subprocess.run( command, shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, ) return result.stdout except subprocess.CalledProcessError as e: print(f"Erreur lors de l'exécution de la commande: {e}") print(f"Sortie de la commande: {e.stdout}") print(f"Erreur de la commande: {e.stderr}") return None def extract_data_for_polygon(poly_file, insee_code): """ Extrait les données pour un polygone donné en utilisant loop_thematics_history_in_zone_to_counts.py. Args: poly_file (str): Chemin vers le fichier de polygone insee_code (str): Code INSEE de la commune Returns: dict: Dictionnaire contenant les données extraites ou None en cas d'erreur """ try: # Vérifier que le fichier OSM existe if not os.path.isfile(OSM_DATA_FILE): print(f"Erreur: Le fichier OSM {OSM_DATA_FILE} n'existe pas.") return None # Exécuter loop_thematics_history_in_zone_to_counts.py pour extraire les données # Nous utilisons --max-dates=1 pour obtenir uniquement les données les plus récentes command = f"python3 {os.path.join(SCRIPT_DIR, 'loop_thematics_history_in_zone_to_counts.py')} --input {OSM_DATA_FILE} --poly {poly_file} --output-dir {OUTPUT_DIR} --temp-dir {TEMP_DIR} --max-dates=1" run_command(command) # Récupérer les résultats depuis les fichiers CSV générés zone_name = Path(poly_file).stem data = {"themes": {}} for theme_name in THEMES.keys(): csv_file = os.path.join(OUTPUT_DIR, f"{zone_name}_{theme_name}.csv") if os.path.exists(csv_file): # Lire le fichier CSV et extraire les données les plus récentes with open(csv_file, "r") as f: lines = f.readlines() if len(lines) > 1: # S'assurer qu'il y a des données (en-tête + au moins une ligne) headers = lines[0].strip().split(",") latest_data = lines[-1].strip().split(",") # Créer un dictionnaire pour ce thème theme_data = {} for i, header in enumerate(headers): if i < len(latest_data): # Convertir en nombre si possible try: value = latest_data[i] if value and value != "": theme_data[header] = float(value) if "." in value else int(value) else: theme_data[header] = 0 except ValueError: theme_data[header] = latest_data[i] data["themes"][theme_name] = theme_data return data except Exception as e: print(f"Erreur lors de l'extraction des données pour {insee_code}: {e}") return None def create_analysis(poly_file): """ Crée une analyse pour un fichier de polygone donné. Args: poly_file (str): Chemin vers le fichier de polygone Returns: str: Chemin vers le fichier d'analyse créé ou None en cas d'erreur """ try: # Extraire le code INSEE du nom du fichier (format: commune_XXXXX.poly) poly_filename = os.path.basename(poly_file) if poly_filename.startswith("commune_") and poly_filename.endswith(".poly"): insee_code = poly_filename[8:-5] # Enlever "commune_" et ".poly" else: print(f"Format de nom de fichier non reconnu: {poly_filename}") return None print(f"Création de l'analyse pour la commune {insee_code}...") # Extraire les données pour ce polygone data = extract_data_for_polygon(poly_file, insee_code) if not data: return None # Ajouter des métadonnées à l'analyse data["metadata"] = { "insee_code": insee_code, "creation_date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "polygon_file": poly_filename, "osm_data_file": os.path.basename(OSM_DATA_FILE) } # Calculer les statistiques de complétion globales total_objects = 0 total_completion = 0 theme_count = 0 for theme_name, theme_data in data["themes"].items(): if "nombre_total" in theme_data and theme_data["nombre_total"] > 0: total_objects += theme_data["nombre_total"] if "pourcentage_completion" in theme_data: total_completion += theme_data["pourcentage_completion"] * theme_data["nombre_total"] theme_count += 1 if total_objects > 0: data["metadata"]["total_objects"] = total_objects data["metadata"]["average_completion"] = total_completion / total_objects if total_objects > 0 else 0 data["metadata"]["theme_count"] = theme_count # Sauvegarder l'analyse dans un fichier JSON analysis_file = os.path.join(ANALYSIS_DIR, f"analyse_commune_{insee_code}.json") with open(analysis_file, "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) print(f"Analyse pour la commune {insee_code} sauvegardée dans {analysis_file}") return analysis_file except Exception as e: print(f"Erreur lors de la création de l'analyse: {e}") return None def main(): """ Fonction principale du script. """ parser = argparse.ArgumentParser( description="Analyse les polygones de villes et génère des fichiers JSON d'analyse." ) parser.add_argument( "--force", "-f", action="store_true", help="Force la recréation des analyses existantes" ) parser.add_argument( "--single", "-s", help="Traite uniquement le polygone spécifié (code INSEE)" ) args = parser.parse_args() try: # S'assurer que les répertoires nécessaires existent ensure_directories_exist() # Récupérer les fichiers de polygones à traiter if args.single: # Traiter uniquement le polygone spécifié single_poly_file = os.path.join(POLYGONS_DIR, f"commune_{args.single}.poly") if not os.path.isfile(single_poly_file): print(f"Erreur: Le fichier de polygone pour la commune {args.single} n'existe pas.") return 1 poly_files = [single_poly_file] print(f"Mode test: traitement uniquement du polygone {args.single}") else: # Traiter tous les polygones poly_files = glob.glob(os.path.join(POLYGONS_DIR, "commune_*.poly")) if not poly_files: print("Aucun fichier de polygone trouvé dans le dossier 'polygons'.") return 1 # Pour le test, limiter à 3 polygones test_mode = False # Mettre à True pour limiter le traitement à quelques polygones if test_mode: # Trier les polygones par taille et prendre les 3 plus petits poly_files = sorted(poly_files, key=os.path.getsize)[:3] print(f"Mode test: traitement limité à {len(poly_files)} polygones") for poly_file in poly_files: print(f" - {os.path.basename(poly_file)}") # Compteurs pour les statistiques total = len(poly_files) existing = 0 created = 0 failed = 0 # Pour chaque fichier de polygone, créer une analyse si elle n'existe pas déjà for i, poly_file in enumerate(poly_files, 1): # Extraire le code INSEE du nom du fichier poly_filename = os.path.basename(poly_file) insee_code = poly_filename[8:-5] # Enlever "commune_" et ".poly" print(f"\nTraitement du polygone {i}/{total}: {poly_filename}") if analysis_exists(insee_code) and not args.force: print(f"L'analyse pour la commune {insee_code} existe déjà.") existing += 1 continue # Créer l'analyse result = create_analysis(poly_file) if result: created += 1 else: failed += 1 # Afficher les statistiques print("\nRésumé:") print(f"Total des polygones traités: {total}") print(f"Analyses déjà existantes: {existing}") print(f"Analyses créées avec succès: {created}") print(f"Échecs: {failed}") return 0 # Succès except KeyboardInterrupt: print("\nOpération annulée par l'utilisateur.") return 1 # Erreur except Exception as e: print(f"Erreur inattendue: {e}") return 1 # Erreur if __name__ == "__main__": sys.exit(main())