mirror of
https://forge.chapril.org/tykayn/osm-commerces
synced 2025-10-04 17:04:53 +02:00
add computing from osm history
This commit is contained in:
parent
da60f964ab
commit
66bbce5e85
13 changed files with 3921 additions and 0 deletions
309
counting_osm_objects/plotly_city.py
Executable file
309
counting_osm_objects/plotly_city.py
Executable file
|
@ -0,0 +1,309 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Script pour générer un graphique interactif avec plotly montrant l'évolution du nombre d'objets OSM
|
||||
à partir d'un fichier CSV thématique d'une ville (code INSEE 91111 par défaut).
|
||||
|
||||
Ce script utilise la bibliothèque plotly pour créer des graphiques interactifs à partir des données
|
||||
contenues dans des fichiers CSV thématiques. Par défaut, il utilise le code INSEE 91111.
|
||||
Le titre du graphique inclut le tag principal (thème) et le nom de la ville.
|
||||
|
||||
Utilisation:
|
||||
python plotly_city.py chemin/vers/fichier.csv [options]
|
||||
|
||||
Options:
|
||||
--output, -o : Chemin de sortie pour le graphique HTML (optionnel)
|
||||
--insee, -i : Code INSEE de la commune à analyser (par défaut: 91111)
|
||||
--city_name, -c : Nom de la ville (si non spécifié, sera généré à partir du code INSEE)
|
||||
|
||||
Exemple:
|
||||
python plotly_city.py test_results/commune_91111_borne-de-recharge.csv
|
||||
|
||||
Dépendances requises:
|
||||
- pandas
|
||||
- plotly
|
||||
|
||||
Installation des dépendances:
|
||||
pip install pandas plotly
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import pandas as pd
|
||||
import plotly.graph_objects as go
|
||||
from plotly.subplots import make_subplots
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def parse_args():
|
||||
"""Parse command line arguments."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Génère un graphique interactif avec plotly à partir des données CSV d'objets OSM."
|
||||
)
|
||||
parser.add_argument(
|
||||
"csv_file", help="Chemin vers le fichier CSV contenant les données"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output", "-o", help="Chemin de sortie pour le graphique (HTML)", default=None
|
||||
)
|
||||
parser.add_argument(
|
||||
"--insee", "-i", help="Code INSEE de la commune à analyser", default="91111"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--city_name",
|
||||
"-c",
|
||||
help="Nom de la ville (si non spécifié, sera extrait du CSV)",
|
||||
default=None,
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def get_city_name(insee_code):
|
||||
"""
|
||||
Récupère le nom de la ville à partir du code INSEE.
|
||||
Cette fonction pourrait être améliorée pour utiliser une API ou une base de données.
|
||||
|
||||
Args:
|
||||
insee_code: Code INSEE de la commune
|
||||
|
||||
Returns:
|
||||
Nom de la ville ou le code INSEE si le nom n'est pas trouvé
|
||||
"""
|
||||
# Pour l'instant, on retourne simplement le code INSEE
|
||||
# Dans une version future, on pourrait implémenter une recherche dans une base de données
|
||||
return f"Commune {insee_code}"
|
||||
|
||||
|
||||
def load_data(csv_file, insee_code="91111"):
|
||||
"""
|
||||
Charge les données depuis le fichier CSV.
|
||||
|
||||
Args:
|
||||
csv_file: Chemin vers le fichier CSV
|
||||
insee_code: Code INSEE de la commune à filtrer
|
||||
|
||||
Returns:
|
||||
DataFrame pandas contenant les données filtrées
|
||||
"""
|
||||
# Charger le CSV avec gestion des erreurs pour les lignes mal formatées
|
||||
try:
|
||||
df = pd.read_csv(csv_file, on_bad_lines="skip")
|
||||
except TypeError: # Pour les versions plus anciennes de pandas
|
||||
df = pd.read_csv(csv_file, error_bad_lines=False, warn_bad_lines=True)
|
||||
|
||||
# Vérifier si le CSV a la structure attendue
|
||||
if "date" in df.columns:
|
||||
# Format de CSV avec colonne 'date' directement
|
||||
df["date"] = pd.to_datetime(df["date"])
|
||||
else:
|
||||
# Si aucune colonne de date n'est trouvée, essayer d'utiliser la première colonne
|
||||
try:
|
||||
df["date"] = pd.to_datetime(df.iloc[:, 0])
|
||||
except:
|
||||
print("Erreur: Impossible de trouver ou convertir une colonne de date.")
|
||||
sys.exit(1)
|
||||
|
||||
# Filtrer par code INSEE si la colonne 'zone' contient des codes INSEE
|
||||
if "zone" in df.columns:
|
||||
# Vérifier si la zone contient le code INSEE
|
||||
if any(
|
||||
zone.endswith(insee_code) for zone in df["zone"] if isinstance(zone, str)
|
||||
):
|
||||
df = df[df["zone"].str.endswith(insee_code)]
|
||||
|
||||
# Trier par date
|
||||
df = df.sort_values("date")
|
||||
|
||||
return df
|
||||
|
||||
|
||||
def generate_plotly_graph(
|
||||
df, city_name=None, output_path=None, insee_code="91111", csv_file=None
|
||||
):
|
||||
"""
|
||||
Génère un graphique interactif avec plotly montrant l'évolution du nombre d'objets dans le temps.
|
||||
|
||||
Args:
|
||||
df: DataFrame pandas contenant les données
|
||||
city_name: Nom de la ville (optionnel)
|
||||
output_path: Chemin de sortie pour le graphique (optionnel)
|
||||
insee_code: Code INSEE de la commune
|
||||
csv_file: Chemin vers le fichier CSV source (pour générer un nom de fichier de sortie par défaut)
|
||||
"""
|
||||
# Si le nom de la ville n'est pas fourni, essayer de le récupérer
|
||||
if not city_name:
|
||||
city_name = get_city_name(insee_code)
|
||||
|
||||
# Déterminer la colonne pour les types d'objets (theme)
|
||||
theme_column = "theme"
|
||||
|
||||
# Créer une figure avec deux sous-graphiques (nombre total et taux de complétion)
|
||||
fig = make_subplots(
|
||||
rows=2,
|
||||
cols=1,
|
||||
subplot_titles=("Nombre d'objets OSM", "Taux de complétion des attributs (%)"),
|
||||
vertical_spacing=0.15,
|
||||
)
|
||||
|
||||
# Obtenir la liste des thèmes uniques
|
||||
if theme_column in df.columns:
|
||||
themes = df[theme_column].unique()
|
||||
|
||||
# Créer un graphique pour chaque thème
|
||||
for theme in themes:
|
||||
# Filtrer les données pour ce thème
|
||||
theme_data = df[df[theme_column] == theme]
|
||||
|
||||
# Tracer la ligne pour le nombre total d'objets
|
||||
fig.add_trace(
|
||||
go.Scatter(
|
||||
x=theme_data["date"],
|
||||
y=theme_data["nombre_total"],
|
||||
mode="lines+markers",
|
||||
name=f"{theme} - Total",
|
||||
hovertemplate="%{x}<br>Nombre: %{y}<extra></extra>",
|
||||
),
|
||||
row=1,
|
||||
col=1,
|
||||
)
|
||||
|
||||
# Tracer la ligne pour le taux de complétion si disponible
|
||||
if "pourcentage_completion" in theme_data.columns:
|
||||
fig.add_trace(
|
||||
go.Scatter(
|
||||
x=theme_data["date"],
|
||||
y=theme_data["pourcentage_completion"],
|
||||
mode="lines+markers",
|
||||
name=f"{theme} - Complétion (%)",
|
||||
hovertemplate="%{x}<br>Complétion: %{y}%<extra></extra>",
|
||||
),
|
||||
row=2,
|
||||
col=1,
|
||||
)
|
||||
else:
|
||||
# Si aucune colonne de thème n'est trouvée, tracer simplement le nombre total
|
||||
fig.add_trace(
|
||||
go.Scatter(
|
||||
x=df["date"],
|
||||
y=df["nombre_total"],
|
||||
mode="lines+markers",
|
||||
name="Total",
|
||||
hovertemplate="%{x}<br>Nombre: %{y}<extra></extra>",
|
||||
),
|
||||
row=1,
|
||||
col=1,
|
||||
)
|
||||
|
||||
# Tracer la ligne pour le taux de complétion si disponible
|
||||
if "pourcentage_completion" in df.columns:
|
||||
fig.add_trace(
|
||||
go.Scatter(
|
||||
x=df["date"],
|
||||
y=df["pourcentage_completion"],
|
||||
mode="lines+markers",
|
||||
name="Complétion (%)",
|
||||
hovertemplate="%{x}<br>Complétion: %{y}%<extra></extra>",
|
||||
),
|
||||
row=2,
|
||||
col=1,
|
||||
)
|
||||
|
||||
# Configurer les axes et les légendes
|
||||
fig.update_xaxes(title_text="Date", row=1, col=1)
|
||||
fig.update_xaxes(title_text="Date", row=2, col=1)
|
||||
fig.update_yaxes(title_text="Nombre d'objets", row=1, col=1)
|
||||
fig.update_yaxes(title_text="Taux de complétion (%)", range=[0, 100], row=2, col=1)
|
||||
|
||||
# Obtenir le thème principal (premier thème trouvé)
|
||||
main_tag = (
|
||||
themes[0] if theme_column in df.columns and len(themes) > 0 else "Objets OSM"
|
||||
)
|
||||
|
||||
# Mettre à jour le titre du graphique avec le tag principal et le nom de la ville
|
||||
fig.update_layout(
|
||||
title=f"{main_tag} - {city_name}",
|
||||
hovermode="x unified",
|
||||
legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1),
|
||||
height=800,
|
||||
width=1000,
|
||||
margin=dict(t=100, b=50, l=50, r=50),
|
||||
)
|
||||
|
||||
# Ajouter des annotations pour les informations supplémentaires
|
||||
fig.add_annotation(
|
||||
text=f"Code INSEE: {insee_code}",
|
||||
xref="paper",
|
||||
yref="paper",
|
||||
x=0.01,
|
||||
y=-0.15,
|
||||
showarrow=False,
|
||||
font=dict(size=10),
|
||||
)
|
||||
|
||||
# Ajouter la date de génération
|
||||
now = datetime.now().strftime("%Y-%m-%d %H:%M")
|
||||
fig.add_annotation(
|
||||
text=f"Généré le: {now}",
|
||||
xref="paper",
|
||||
yref="paper",
|
||||
x=0.99,
|
||||
y=-0.15,
|
||||
showarrow=False,
|
||||
font=dict(size=8),
|
||||
align="right",
|
||||
)
|
||||
|
||||
# Sauvegarder ou afficher le graphique
|
||||
if output_path:
|
||||
fig.write_html(output_path)
|
||||
print(f"Graphique interactif sauvegardé: {output_path}")
|
||||
elif csv_file:
|
||||
# Déterminer un chemin de sortie par défaut basé sur le fichier CSV
|
||||
base_name = os.path.splitext(csv_file)[0]
|
||||
default_output = f"{base_name}_plotly.html"
|
||||
fig.write_html(default_output)
|
||||
print(f"Graphique interactif sauvegardé: {default_output}")
|
||||
else:
|
||||
# Si aucun chemin de sortie n'est spécifié et aucun fichier CSV n'est fourni,
|
||||
# utiliser un nom par défaut basé sur le code INSEE et le thème
|
||||
default_output = f"commune_{insee_code}_{main_tag}_plotly.html"
|
||||
fig.write_html(default_output)
|
||||
print(f"Graphique interactif sauvegardé: {default_output}")
|
||||
|
||||
|
||||
def main():
|
||||
"""Fonction principale."""
|
||||
# Analyser les arguments de la ligne de commande
|
||||
args = parse_args()
|
||||
|
||||
# Vérifier que le fichier CSV existe
|
||||
if not os.path.isfile(args.csv_file):
|
||||
print(f"Erreur: Le fichier {args.csv_file} n'existe pas.")
|
||||
sys.exit(1)
|
||||
|
||||
# Charger les données
|
||||
df = load_data(args.csv_file, args.insee)
|
||||
|
||||
# Vérifier qu'il y a des données
|
||||
if df.empty:
|
||||
print(f"Aucune donnée trouvée pour le code INSEE {args.insee}.")
|
||||
sys.exit(1)
|
||||
|
||||
# Déterminer le chemin de sortie si non spécifié
|
||||
if not args.output:
|
||||
# Utiliser le même nom que le fichier CSV mais avec l'extension .html
|
||||
base_name = os.path.splitext(args.csv_file)[0]
|
||||
output_path = f"{base_name}_plotly.html"
|
||||
else:
|
||||
output_path = args.output
|
||||
|
||||
# Générer le graphique
|
||||
generate_plotly_graph(df, args.city_name, output_path, args.insee, args.csv_file)
|
||||
|
||||
print("Graphique interactif généré avec succès!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Add table
Add a link
Reference in a new issue