trouver une ville par son nom avec nominatim, génération de carte html

This commit is contained in:
Tykayn 2025-03-16 16:13:45 +01:00 committed by tykayn
parent 8cb321a9c8
commit eb8fafdd49
13 changed files with 84740 additions and 109757 deletions

314
GUIDE_UTILISATION.md Normal file
View file

@ -0,0 +1,314 @@
# Guide d'Utilisation Détaillé - Analyse Urbaine
Ce guide détaille l'utilisation des différents scripts disponibles dans ce projet d'analyse urbaine.
## Table des matières
1. [Génération de rapports HTML](#génération-de-rapports-html)
2. [Génération de cartes](#génération-de-cartes)
3. [Conversion HTML vers JPG](#conversion-html-vers-jpg)
4. [Workflow recommandé](#workflow-recommandé)
5. [Dépannage](#dépannage)
## Génération de rapports HTML
Le script `present.py` permet de générer des rapports HTML à partir de données JSON.
### Syntaxe
```bash
python present.py <fichier_json> [fichier_html_sortie] [fichier_template]
```
### Arguments
- `<fichier_json>` : Chemin vers le fichier JSON contenant les données (obligatoire)
- `[fichier_html_sortie]` : Chemin où sauvegarder le fichier HTML (par défaut: resultat.html)
- `[fichier_template]` : Nom du fichier template à utiliser (par défaut: template.html)
### Exemples
```bash
# Utilisation basique
python present.py summary_results.json
# Spécifier le fichier de sortie
python present.py summary_results.json rapport_ville.html
# Utiliser un template personnalisé
python present.py summary_results.json rapport_ville.html template_ameliore.html
```
## Génération de cartes
Plusieurs scripts sont disponibles pour générer des cartes de villes à partir de leur ID OpenStreetMap.
### Script principal : generate_city_map.py
Ce script est un wrapper qui utilise soit OSMnx, soit Folium selon les options.
#### Syntaxe
```bash
python generate_city_map.py <osm_id> [options]
```
#### Arguments
- `<osm_id>` : ID OpenStreetMap de la ville (obligatoire)
- `-o, --output` : Chemin où sauvegarder l'image (par défaut: city_map.jpg)
- `--folium` : Utiliser Folium au lieu d'OSMnx (plus léger mais moins détaillé)
- `-v, --verbose` : Afficher les messages de débogage
#### Exemples
```bash
# Générer une carte avec OSMnx (haute qualité)
python generate_city_map.py 1209165 -o carte_ville.jpg
# Générer une carte avec Folium (plus léger, recommandé)
python generate_city_map.py 1209165 -o carte_ville.html --folium
```
### Script alternatif : map_simple.py
Ce script utilise Folium pour générer des cartes interactives en HTML.
#### Syntaxe
```bash
python map_simple.py <osm_id> [options]
```
#### Arguments
- `<osm_id>` : ID OpenStreetMap de la ville (obligatoire)
- `-o, --output` : Chemin où sauvegarder la carte HTML (par défaut: city_map.html)
- `-v, --verbose` : Afficher les messages de débogage
#### Exemples
```bash
python map_simple.py 1209165 -o carte_ville.html
```
### Script simplifié : simple_map.py
Version simplifiée qui utilise directement l'API Overpass pour récupérer les données.
#### Syntaxe
```bash
python simple_map.py <osm_id> [options]
```
#### Arguments
- `<osm_id>` : ID OpenStreetMap de la ville (obligatoire)
- `-o, --output` : Chemin où sauvegarder la carte HTML (par défaut: city_map.html)
#### Exemples
```bash
python simple_map.py 1209165 -o carte_ville.html
```
### Fonds de carte disponibles
Les cartes générées utilisent par défaut le fond de carte **Stamen Terrain** qui offre une meilleure lisibilité et un rendu plus esthétique que le fond OpenStreetMap standard. Les cartes interactives incluent également un sélecteur de fonds de carte permettant de basculer entre :
- **Stamen Terrain** : fond topographique détaillé avec relief (par défaut)
- **Stamen Toner** : fond noir et blanc minimaliste, idéal pour l'impression
- **Stamen Watercolor** : fond artistique style aquarelle
- **OpenStreetMap** : fond standard d'OpenStreetMap
Pour changer de fond de carte, utilisez le contrôle de couches situé en haut à droite de la carte interactive.
### Filtrage précis des éléments
Les scripts de génération de cartes utilisent désormais une méthode avancée pour récupérer uniquement les éléments (routes, bâtiments, parkings) qui se trouvent à l'intérieur du polygone de la ville, et non plus simplement dans une boîte englobante rectangulaire. Cela permet d'obtenir des cartes plus précises qui ne contiennent que les éléments appartenant réellement à la ville.
Cette fonctionnalité utilise l'opérateur `area` de l'API Overpass pour filtrer les éléments par leur appartenance géographique au polygone de la ville, ce qui donne des résultats beaucoup plus précis qu'un simple filtrage par coordonnées.
**Note :** Pour les points d'intérêt (nodes), un filtrage par boîte englobante est toujours utilisé, mais avec un rayon réduit.
## Conversion HTML vers JPG
Deux scripts sont disponibles pour convertir les cartes HTML en images JPG.
### Script recommandé : html2jpg.py
Ce script utilise Playwright pour rendre la page web et la capturer en image.
#### Prérequis
```bash
pip install playwright
playwright install
```
#### Syntaxe
```bash
python html2jpg.py <fichier_html> [-o output.jpg]
```
#### Arguments
- `<fichier_html>` : Chemin vers le fichier HTML à convertir (obligatoire)
- `-o, --output` : Chemin où sauvegarder l'image JPG (par défaut: nom_du_fichier.jpg)
#### Exemples
```bash
python html2jpg.py carte_ville.html -o carte_ville.jpg
```
### Script alternatif : html_to_jpg.py
Ce script propose plusieurs méthodes de conversion.
#### Syntaxe
```bash
python html_to_jpg.py <fichier_html> [-o output.jpg] [-m méthode]
```
#### Arguments
- `<fichier_html>` : Chemin vers le fichier HTML à convertir (obligatoire)
- `-o, --output` : Chemin où sauvegarder l'image JPG (par défaut: nom_du_fichier.jpg)
- `-m, --method` : Méthode de conversion à utiliser (wkhtmltoimage, imgkit, cutycapt, selenium)
#### Exemples
```bash
python html_to_jpg.py carte_ville.html -o carte_ville.jpg -m selenium
```
## Workflow recommandé
Pour obtenir les meilleurs résultats, suivez ce workflow en deux étapes :
1. **Générer une carte HTML avec Folium** :
```bash
python generate_city_map.py 1209165 -o carte_ville.html --folium
```
2. **Convertir la carte HTML en image JPG** :
```bash
python html2jpg.py carte_ville.html -o carte_ville.jpg
```
Cette approche en deux étapes est plus robuste que la génération directe en JPG.
## Dépannage
### Problèmes avec OSMnx
Si vous rencontrez des erreurs avec OSMnx, utilisez l'option `--folium` :
```bash
python generate_city_map.py <osm_id> -o carte_ville.html --folium
```
### Problèmes avec la conversion HTML vers JPG
1. **Vérifiez que Playwright est installé** :
```bash
pip install playwright
playwright install
```
2. **Utilisez le script html2jpg.py** qui est plus robuste :
```bash
python html2jpg.py carte_ville.html -o carte_ville.jpg
```
3. **Alternative manuelle** : Ouvrez le fichier HTML dans un navigateur et prenez une capture d'écran.
### ID OpenStreetMap invalide
Si l'ID OpenStreetMap ne fonctionne pas, vérifiez qu'il s'agit bien d'une relation, d'un way ou d'un node valide sur [OpenStreetMap](https://www.openstreetmap.org/).
### Trouver l'ID OpenStreetMap d'une ville
1. Allez sur [OpenStreetMap](https://www.openstreetmap.org/)
2. Recherchez la ville souhaitée
3. Cliquez sur la ville dans les résultats
4. L'URL contiendra l'ID, par exemple : `https://www.openstreetmap.org/relation/123456`
5. L'ID est le nombre après "relation/" (ici, 123456)
### Recherche automatique d'ID OpenStreetMap
Le script `find_city_osm_id.py` permet de rechercher automatiquement l'identifiant OpenStreetMap d'une ville à partir de son nom.
#### Syntaxe
```bash
python find_city_osm_id.py <nom_ville> [options]
```
#### Arguments
- `<nom_ville>` : Nom de la ville à rechercher (obligatoire)
- `-c, --country` : Code pays pour filtrer les résultats (ex: fr, be, ch)
- `-l, --limit` : Nombre maximum de résultats à afficher (défaut: 5)
- `-r, --relation-only` : Afficher uniquement les IDs de relation
- `-j, --json` : Afficher les résultats au format JSON
- `-g, --generate-map` : Générer automatiquement une carte pour le premier résultat (actif par défaut)
- `-ng, --no-generate-map` : Ne pas générer automatiquement de carte
- `-o, --output` : Chemin où sauvegarder la carte générée (défaut: carte_ville.html)
- `--no-folium` : Utiliser OSMnx au lieu de Folium pour la génération de carte
- `-v, --verbose` : Afficher les messages de débogage
#### Exemples
```bash
# Recherche simple avec génération automatique de carte
python find_city_osm_id.py "Briis-sous-Forges"
# Filtrer par pays (France) sans génération de carte
python find_city_osm_id.py "Paris" -c fr -ng
# Recherche avec génération de carte et spécification du fichier de sortie
python find_city_osm_id.py "Lyon" -c fr -o lyon_carte.html
# Recherche avec génération de carte en utilisant OSMnx au lieu de Folium
python find_city_osm_id.py "Marseille" -c fr --no-folium -o marseille_carte.jpg
```
#### Fonctionnement
Le script utilise l'API Nominatim d'OpenStreetMap pour rechercher les villes correspondant au nom fourni. Pour chaque résultat, il affiche :
1. Le nom de la ville et son type (city, town, village, etc.)
2. Sa localisation (département, région, pays)
3. Son identifiant OpenStreetMap et son type (node, way, relation)
4. L'URL pour accéder à la ville sur OpenStreetMap
Si le résultat n'est pas déjà une relation, le script recherche automatiquement l'identifiant de relation associé en utilisant l'API Overpass.
#### Génération automatique de carte
Par défaut, le script génère automatiquement une carte HTML avec Folium pour le premier résultat trouvé. Cette fonctionnalité peut être désactivée avec l'option `-ng` ou `--no-generate-map`.
Le processus de génération de carte est le suivant :
1. Le script trouve l'ID OpenStreetMap de la ville
2. Si l'élément n'est pas une relation, il recherche l'ID de relation associé
3. Il exécute automatiquement `generate_city_map.py` avec l'ID trouvé
4. La carte est générée au format HTML (par défaut) ou JPG (si `--no-folium` est spécifié)
5. Le chemin vers la carte générée est affiché
Si la carte est générée au format HTML, le script suggère également la commande pour la convertir en JPG avec `html2jpg.py`.
#### Workflow tout-en-un
Ce script simplifie considérablement le workflow en permettant de passer directement du nom d'une ville à une carte générée en une seule commande :
```bash
# Rechercher une ville, générer sa carte HTML et la convertir en JPG
python find_city_osm_id.py "Briis-sous-Forges" -c fr -o briis.html && python html2jpg.py briis.html -o briis.jpg
```
Cette approche est beaucoup plus simple que de rechercher manuellement l'ID OpenStreetMap de la ville, puis d'exécuter séparément les scripts de génération de carte.

View file

@ -2,11 +2,15 @@
Ce projet permet de générer des rapports HTML et des cartes visuelles présentant les résultats d'analyse urbaine pour une ville donnée, à partir de données JSON et OpenStreetMap.
> **Note :** Pour des instructions détaillées, consultez le [Guide d'Utilisation Détaillé](GUIDE_UTILISATION.md).
## Fonctionnalités
- Génération de rapports HTML à partir de données JSON
- Visualisation des statistiques urbaines (routes, pistes cyclables, parkings, bâtiments, etc.)
- Génération de cartes visuelles des villes à partir de leur ID OpenStreetMap
- Utilisation du fond de carte Stamen Terrain pour une meilleure lisibilité
- Sélecteur de fonds de carte (Stamen Terrain, Stamen Toner, Stamen Watercolor, OpenStreetMap)
- Calcul automatique de ratios et d'indicateurs
- Templates personnalisables
- Interface responsive adaptée aux mobiles et ordinateurs
@ -33,6 +37,11 @@ Ce projet permet de générer des rapports HTML et des cartes visuelles présent
3. Pour la conversion HTML vers JPG, installez l'un des outils suivants :
- wkhtmltopdf/wkhtmltoimage : https://wkhtmltopdf.org/downloads.html
- CutyCapt (pour Linux) : `sudo apt-get install cutycapt`
- Playwright (recommandé) :
```bash
pip install playwright
playwright install
```
## Utilisation
@ -89,6 +98,11 @@ Pour plus de contrôle, vous pouvez utiliser les scripts individuels :
```bash
python html_to_jpg.py <fichier_html> [-o output.jpg] [-m méthode]
```
Ou avec le nouveau script simplifié (recommandé) :
```bash
python html2jpg.py <fichier_html> [-o output.jpg]
```
### Test de la solution
@ -137,12 +151,94 @@ Vous pouvez créer vos propres templates en vous basant sur les templates exista
## Trouver l'ID OpenStreetMap d'une ville
### Méthode manuelle
1. Allez sur [OpenStreetMap](https://www.openstreetmap.org/)
2. Recherchez la ville souhaitée
3. Cliquez sur la ville dans les résultats
4. L'URL contiendra l'ID de la relation, par exemple : `https://www.openstreetmap.org/relation/123456`
5. L'ID est le nombre après "relation/" (ici, 123456)
### Méthode automatique (recommandée)
Utilisez le script `find_city_osm_id.py` pour rechercher une ville par son nom et obtenir son ID de relation :
```bash
python find_city_osm_id.py "Nom de la ville"
```
Options disponibles :
- `-c, --country` : Filtrer par code pays (ex: fr, be, ch)
- `-l, --limit` : Nombre maximum de résultats (défaut: 5)
- `-r, --relation-only` : Afficher uniquement les IDs de relation
- `-j, --json` : Afficher les résultats au format JSON
Exemple :
```bash
python find_city_osm_id.py "Paris"
```
## Licence
Ce projet est sous licence MIT.
Ce projet est sous licence AGPLv3+.
## Workflow recommandé pour générer une carte
### Méthode simplifiée (recommandée)
Utilisez le script `find_city_osm_id.py` qui recherche et génère automatiquement la carte en une seule commande :
```bash
python find_city_osm_id.py "Nom de la ville" -c fr -o carte_ville.html
```
Pour convertir ensuite la carte HTML en image JPG :
```bash
python html2jpg.py carte_ville.html -o carte_ville.jpg
```
Cette méthode est la plus simple car elle :
- Recherche automatiquement l'ID OpenStreetMap de la ville
- Génère directement la carte HTML avec Folium
- Suggère la commande pour convertir en JPG
### Méthode manuelle (étape par étape)
Si vous préférez contrôler chaque étape du processus :
#### Étape 1 : Trouver l'ID OpenStreetMap de la ville
Utilisez le script `find_city_osm_id.py` pour trouver l'ID de la ville par son nom, mais désactivez la génération automatique de carte :
```bash
python find_city_osm_id.py "Nom de la ville" -c fr -ng
```
Ou en ligne de commande pour obtenir directement l'ID :
```bash
ID=$(python find_city_osm_id.py "Nom de la ville" -c fr -r | head -n 1)
```
#### Étape 2 : Générer la carte HTML avec Folium
```bash
python generate_city_map.py <osm_id> -o carte_ville.html --folium
```
#### Étape 3 : Convertir la carte HTML en image JPG
```bash
python html2jpg.py carte_ville.html -o carte_ville.jpg
```
### Workflow complet en une seule commande
Pour les utilisateurs avancés, voici comment combiner toutes les étapes en une seule commande :
```bash
python find_city_osm_id.py "Briis-sous-Forges" -c fr -o carte_ville.html && python html2jpg.py carte_ville.html -o carte_ville.jpg
```
Cette approche en une ou deux étapes est robuste et permet de générer des cartes pour n'importe quelle ville en connaissant simplement son nom.

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 663 KiB

Before After
Before After

BIN
carte_ville.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 KiB

View file

@ -16,7 +16,10 @@ args = parser.parse_args()
CITY_NAME = args.city
# limours: 3601176343
city_overpass_id = "3601209165"
# briis-sous-forges: 3601209165
parser.add_argument("--osm-id", type=str, default="3601209165", help="Identifiant OpenStreetMap de la ville (défaut: 3601209165 pour Briis-sous-Forges)")
city_overpass_id = args.osm_id
COUNTRY_NAME = "France"
# estimations des tailles de parking en m carré selon le placement

View file

@ -3,7 +3,17 @@ import json
# Configuration
OVERPASS_API = "https://overpass-api.de/api/interpreter"
city_overpass_id = "3601209165" # ID de la ville
import argparse
def parse_arguments():
parser = argparse.ArgumentParser(description="Récupère les données OpenStreetMap pour une ville")
parser.add_argument("city_id", help="Identifiant OpenStreetMap de la ville")
return parser.parse_args()
args = parse_arguments()
city_overpass_id = args.city_id # ID de la ville
def fetch_overpass_data():
# Requête Overpass pour obtenir les routes et bâtiments de la ville

341
find_city_osm_id.py Executable file
View file

@ -0,0 +1,341 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Script pour trouver l'identifiant OpenStreetMap d'une ville à partir de son nom.
Utilise l'API Nominatim pour effectuer la recherche.
"""
import sys
import argparse
import requests
import json
import time
import os
import subprocess
from urllib.parse import quote
def search_city(city_name, country=None, limit=5):
"""
Recherche une ville par son nom en utilisant l'API Nominatim d'OpenStreetMap.
Args:
city_name (str): Nom de la ville à rechercher
country (str, optional): Code pays pour filtrer les résultats (ex: 'fr', 'be', 'ch')
limit (int, optional): Nombre maximum de résultats à retourner
Returns:
list: Liste des correspondances trouvées
"""
# Construire l'URL de recherche
base_url = "https://nominatim.openstreetmap.org/search"
# Paramètres de recherche
params = {
'q': city_name,
'format': 'json',
'addressdetails': 1,
'limit': limit,
'polygon_geojson': 0,
}
# Ajouter le filtre de pays si spécifié
if country:
params['countrycodes'] = country
# Ajouter des paramètres pour filtrer les résultats par type
params['featuretype'] = 'city'
# En-têtes pour respecter les conditions d'utilisation de Nominatim
headers = {
'User-Agent': 'CityOSMIDFinder/1.0',
'Accept-Language': 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7',
}
try:
# Effectuer la requête
response = requests.get(base_url, params=params, headers=headers)
# Vérifier si la requête a réussi
if response.status_code != 200:
print(f"Erreur lors de la requête: {response.status_code}")
return []
# Analyser les résultats
results = response.json()
# Filtrer pour ne garder que les villes/villages
filtered_results = []
for result in results:
# Vérifier si c'est une ville ou un village
if 'address' in result:
place_type = None
for key in ['city', 'town', 'village', 'municipality', 'hamlet']:
if key in result['address']:
place_type = key
break
if place_type:
# Ajouter des informations supplémentaires
result['place_type'] = place_type
# Rechercher l'ID de relation
osm_id = result.get('osm_id')
osm_type = result.get('osm_type')
if osm_id and osm_type:
# Convertir le type en majuscule pour la première lettre
osm_type = osm_type.capitalize()
# Ajouter à la liste filtrée
filtered_results.append(result)
return filtered_results
except Exception as e:
print(f"Erreur lors de la recherche: {str(e)}")
return []
def get_relation_id(osm_type, osm_id):
"""
Récupère l'ID de relation pour un élément OSM.
Si l'élément est déjà une relation, retourne simplement son ID.
Sinon, essaie de trouver une relation associée.
Args:
osm_type (str): Type d'élément OSM ('Node', 'Way', 'Relation')
osm_id (int): ID de l'élément OSM
Returns:
int: ID de la relation ou None si aucune relation n'est trouvée
"""
if osm_type == 'Relation':
return osm_id
# Pour les nodes et ways, on doit chercher la relation associée
# Construire la requête Overpass
if osm_type == 'Node':
query = f"""
[out:json];
node({osm_id});
is_in->.a;
relation.a["admin_level"="8"];
out ids;
"""
elif osm_type == 'Way':
query = f"""
[out:json];
way({osm_id});
is_in->.a;
relation.a["admin_level"="8"];
out ids;
"""
else:
return None
# Envoyer la requête à l'API Overpass
try:
overpass_url = "https://overpass-api.de/api/interpreter"
response = requests.post(overpass_url, data={"data": query})
if response.status_code != 200:
print(f"Erreur lors de la requête Overpass: {response.status_code}")
return None
data = response.json()
# Extraire l'ID de relation
if 'elements' in data and data['elements']:
for element in data['elements']:
if element.get('type') == 'relation':
return element.get('id')
return None
except Exception as e:
print(f"Erreur lors de la récupération de l'ID de relation: {str(e)}")
return None
def display_results(results):
"""
Affiche les résultats de recherche de manière formatée.
Args:
results (list): Liste des résultats de recherche
"""
if not results:
print("Aucun résultat trouvé.")
return
print(f"\n{len(results)} résultat(s) trouvé(s):\n")
for i, result in enumerate(results, 1):
# Extraire les informations
name = result.get('display_name', 'Nom inconnu')
osm_type = result.get('osm_type', '').capitalize()
osm_id = result.get('osm_id', 'ID inconnu')
place_type = result.get('place_type', 'Type inconnu')
# Extraire les informations d'adresse
address = result.get('address', {})
city = address.get('city', address.get('town', address.get('village', address.get('municipality', address.get('hamlet', '')))))
county = address.get('county', '')
state = address.get('state', '')
country = address.get('country', '')
# Afficher les informations
print(f"{i}. {city} ({place_type})")
print(f" Localisation: {county}, {state}, {country}")
print(f" OSM ID: {osm_id} (Type: {osm_type})")
print(f" URL: https://www.openstreetmap.org/{osm_type.lower()}/{osm_id}")
# Rechercher l'ID de relation si ce n'est pas déjà une relation
if osm_type != 'Relation':
print(" Recherche de l'ID de relation associé...")
relation_id = get_relation_id(osm_type, osm_id)
if relation_id:
print(f" ID de relation: {relation_id}")
print(f" URL de relation: https://www.openstreetmap.org/relation/{relation_id}")
else:
print(" Aucune relation trouvée.")
print()
def generate_map(osm_id, output_path=None, use_folium=True, verbose=False):
"""
Génère une carte pour la ville avec l'ID OpenStreetMap spécifié.
Args:
osm_id (int): ID OpenStreetMap de la ville
output_path (str, optional): Chemin sauvegarder la carte
use_folium (bool, optional): Utiliser Folium au lieu d'OSMnx
verbose (bool, optional): Afficher les messages de débogage
Returns:
str: Chemin vers la carte générée ou None en cas d'erreur
"""
try:
# Vérifier si le script generate_city_map.py existe
if not os.path.exists("generate_city_map.py"):
print("Erreur: Le script generate_city_map.py n'a pas été trouvé.")
return None
# Construire la commande
cmd = ["python", "generate_city_map.py", str(osm_id)]
# Ajouter les options
if output_path:
cmd.extend(["-o", output_path])
if use_folium:
cmd.append("--folium")
if verbose:
cmd.append("-v")
# Exécuter la commande
print(f"Génération de la carte pour l'ID OSM {osm_id}...")
print(f"Commande: {' '.join(cmd)}")
result = subprocess.run(cmd, capture_output=True, text=True)
# Vérifier si la commande a réussi
if result.returncode == 0:
output_file = output_path if output_path else "city_map.html" if use_folium else "city_map.jpg"
print(f"Carte générée avec succès: {output_file}")
# Afficher les messages de sortie si verbose
if verbose:
print("\nSortie de la commande:")
print(result.stdout)
return output_file
else:
print(f"Erreur lors de la génération de la carte (code {result.returncode}):")
print(result.stderr)
return None
except Exception as e:
print(f"Erreur lors de la génération de la carte: {str(e)}")
return None
def main():
"""
Fonction principale qui traite les arguments de ligne de commande
et effectue la recherche.
"""
parser = argparse.ArgumentParser(description='Recherche l\'identifiant OpenStreetMap d\'une ville à partir de son nom.')
parser.add_argument('city_name', type=str, help='Nom de la ville à rechercher')
parser.add_argument('-c', '--country', type=str, help='Code pays pour filtrer les résultats (ex: fr, be, ch)', default='fr')
parser.add_argument('-l', '--limit', type=int, default=5, help='Nombre maximum de résultats à afficher (défaut: 5)')
parser.add_argument('-j', '--json', action='store_true', help='Afficher les résultats au format JSON', default=False)
parser.add_argument('-r', '--relation-only', action='store_true', help='Afficher uniquement les IDs de relation', default=False)
# Nouvelles options pour la génération de carte
parser.add_argument('-g', '--generate-map', action='store_true', default=True,
help='Générer automatiquement une carte pour le premier résultat (actif par défaut)')
parser.add_argument('-ng', '--no-generate-map', action='store_false', dest='generate_map',
help='Ne pas générer automatiquement de carte')
parser.add_argument('-o', '--output', type=str, default='carte_ville.html',
help='Chemin où sauvegarder la carte générée (défaut: carte_ville.html)')
parser.add_argument('--no-folium', action='store_false', dest='use_folium',
help='Utiliser OSMnx au lieu de Folium pour la génération de carte', default=True)
parser.add_argument('-v', '--verbose', action='store_true',
help='Afficher les messages de débogage')
args = parser.parse_args()
# Effectuer la recherche
print(f"Recherche de la ville: {args.city_name}")
if args.country:
print(f"Filtrage par pays: {args.country}")
results = search_city(args.city_name, args.country, args.limit)
# Afficher les résultats
if args.json:
print(json.dumps(results, indent=2))
elif args.relation_only:
for result in results:
osm_type = result.get('osm_type', '').capitalize()
osm_id = result.get('osm_id', '')
if osm_type == 'Relation':
print(f"{osm_id}")
else:
relation_id = get_relation_id(osm_type, osm_id)
if relation_id:
print(f"{relation_id}")
else:
display_results(results)
# Générer une carte si demandé et si des résultats ont été trouvés
if args.generate_map and results:
# Prendre le premier résultat
first_result = results[0]
osm_type = first_result.get('osm_type', '').capitalize()
osm_id = first_result.get('osm_id', '')
# Obtenir l'ID de relation si nécessaire
if osm_type != 'Relation':
relation_id = get_relation_id(osm_type, osm_id)
if relation_id:
osm_id = relation_id
else:
print("Aucune relation trouvée pour ce résultat. Utilisation de l'ID original.")
# Générer la carte
if osm_id:
print("\n--- Génération automatique de la carte ---")
map_path = generate_map(osm_id, args.output, args.use_folium, args.verbose)
if map_path:
print(f"\nCarte générée avec succès: {map_path}")
# Si c'est un fichier HTML, suggérer de le convertir en JPG
if map_path.endswith('.html'):
print("\nPour convertir cette carte HTML en image JPG, utilisez la commande:")
print(f"python html2jpg.py {map_path} -o {os.path.splitext(map_path)[0]}.jpg")
else:
print("\nÉchec de la génération de la carte.")
if __name__ == "__main__":
main()

6
map.py
View file

@ -95,9 +95,9 @@ def generate_city_map(city_data, output_path=None):
# Définir les couleurs
background_color = '#8CDD81' # Vert clair pour le fond
road_color = '#555555' # Gris pour les routes
building_color = '#777777' # Gris pour les bâtiments
parking_color = '#999999' # Gris clair pour les parkings
road_color = '#222' # Gris pour les routes
building_color = '#CCC' # Gris pour les bâtiments
parking_color = '#555' # Gris clair pour les parkings
# Dessiner le fond (limite de la ville)
city_data['boundary'].plot(ax=ax, facecolor=background_color, edgecolor='none', alpha=0.8)

View file

@ -156,18 +156,54 @@ def _try_get_osm_data(osm_id, element_type):
bbox = (min_lat, min_lon, max_lat, max_lon)
# Récupérer les éléments dans la zone (routes, bâtiments, parkings)
# Utiliser la boîte englobante pour la requête
area_query = f"""
[out:json];
(
way[highway]({bbox[0]},{bbox[1]},{bbox[2]},{bbox[3]});
way[building]({bbox[0]},{bbox[1]},{bbox[2]},{bbox[3]});
way[amenity=parking]({bbox[0]},{bbox[1]},{bbox[2]},{bbox[3]});
);
out body;
>;
out skel qt;
"""
# Utiliser l'ID de la relation/way pour limiter aux éléments à l'intérieur de la ville
if element_type == "relation":
# Pour les relations (villes), il faut d'abord obtenir l'ID d'area correspondant
# L'ID d'area est calculé comme 3600000000 + ID de la relation
area_id = 3600000000 + osm_id
area_query = f"""
[out:json];
area({area_id})->.searchArea;
(
way[highway](area.searchArea);
way[building](area.searchArea);
way[amenity=parking](area.searchArea);
);
out body;
>;
out skel qt;
"""
elif element_type == "way":
# Pour les ways (contours), il faut d'abord obtenir l'ID d'area correspondant
# L'ID d'area est calculé comme 2400000000 + ID du way
area_id = 2400000000 + osm_id
area_query = f"""
[out:json];
area({area_id})->.searchArea;
(
way[highway](area.searchArea);
way[building](area.searchArea);
way[amenity=parking](area.searchArea);
);
out body;
>;
out skel qt;
"""
else:
# Pour les nodes ou si les méthodes précédentes échouent, utiliser la boîte englobante
# mais avec un rayon plus petit autour du point
area_query = f"""
[out:json];
(
way[highway]({bbox[0]},{bbox[1]},{bbox[2]},{bbox[3]});
way[building]({bbox[0]},{bbox[1]},{bbox[2]},{bbox[3]});
way[amenity=parking]({bbox[0]},{bbox[1]},{bbox[2]},{bbox[3]});
);
out body;
>;
out skel qt;
"""
logger.warning(f"Utilisation d'une boîte englobante pour {element_type} {osm_id} (moins précis)")
logger.info(f"Récupération des routes, bâtiments et parkings pour {name}...")
response = requests.post(overpass_url, data={"data": area_query})
@ -212,8 +248,31 @@ def create_folium_map(city_data, output_path=None):
elements_data = city_data['elements_data']
element_type = city_data.get('element_type', 'unknown')
# Créer une carte centrée sur la ville
m = folium.Map(location=center, zoom_start=14, tiles='OpenStreetMap')
# Créer une carte centrée sur la ville avec fond Stamen Terrain
m = folium.Map(
location=center,
zoom_start=14,
tiles='Stamen Terrain',
attr='Map tiles by <a href="http://stamen.com">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under <a href="http://www.openstreetmap.org/copyright">ODbL</a>.'
)
# Ajouter d'autres options de fonds de carte
folium.TileLayer(
'Stamen Toner',
attr='Map tiles by <a href="http://stamen.com">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under <a href="http://www.openstreetmap.org/copyright">ODbL</a>.'
).add_to(m)
folium.TileLayer(
'Stamen Watercolor',
attr='Map tiles by <a href="http://stamen.com">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under <a href="http://www.openstreetmap.org/copyright">ODbL</a>.'
).add_to(m)
folium.TileLayer(
'OpenStreetMap',
attr='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
).add_to(m)
folium.LayerControl().add_to(m)
# Ajouter un titre
title_html = f'''

View file

@ -181,7 +181,7 @@
<body>
<header>
<div class="container">
<h1>Analyse urbaine de Ville Test</h1>
<h1>Analyse urbaine de {{ city_name }}</h1>
<p class="subtitle">Données d'infrastructure et d'aménagement urbain</p>
</div>
</header>
@ -226,9 +226,7 @@
</div>
<p>Ratio cyclable/routier:</p>
<div class="progress-container">
<div
class="progress-bar ratio-medium"
style='width: 5.47 %'></div>
<div class="progress-bar ratio-medium" style='width: 5.47 %'></div>
</div>
<p>5.47% du réseau routier</p>
</div>

View file

@ -107,12 +107,14 @@ def get_bbox_from_data(data):
print(f"Erreur lors du calcul de la boîte englobante: {str(e)}")
return None
def get_elements_in_bbox(bbox):
def get_elements_in_area(osm_id, element_type, bbox=None):
"""
Récupère les routes, bâtiments et parkings dans une boîte englobante.
Récupère les routes, bâtiments et parkings dans une zone définie par un élément OSM.
Args:
bbox (tuple): (min_lat, min_lon, max_lat, max_lon)
osm_id (int): L'identifiant OpenStreetMap
element_type (str): Le type d'élément ('relation', 'way', 'node')
bbox (tuple, optional): (min_lat, min_lon, max_lat, max_lon) à utiliser si l'area ne fonctionne pas
Returns:
dict: Les données récupérées ou None en cas d'erreur
@ -120,17 +122,56 @@ def get_elements_in_bbox(bbox):
print(f"Récupération des éléments dans la zone...")
# Construire la requête Overpass
query = f"""
[out:json];
(
way[highway]({bbox[0]},{bbox[1]},{bbox[2]},{bbox[3]});
way[building]({bbox[0]},{bbox[1]},{bbox[2]},{bbox[3]});
way[amenity=parking]({bbox[0]},{bbox[1]},{bbox[2]},{bbox[3]});
);
out body;
>;
out skel qt;
"""
if element_type == "relation":
# Pour les relations (villes), il faut d'abord obtenir l'ID d'area correspondant
# L'ID d'area est calculé comme 3600000000 + ID de la relation
area_id = 3600000000 + osm_id
query = f"""
[out:json];
area({area_id})->.searchArea;
(
way[highway](area.searchArea);
way[building](area.searchArea);
way[amenity=parking](area.searchArea);
);
out body;
>;
out skel qt;
"""
elif element_type == "way":
# Pour les ways (contours), il faut d'abord obtenir l'ID d'area correspondant
# L'ID d'area est calculé comme 2400000000 + ID du way
area_id = 2400000000 + osm_id
query = f"""
[out:json];
area({area_id})->.searchArea;
(
way[highway](area.searchArea);
way[building](area.searchArea);
way[amenity=parking](area.searchArea);
);
out body;
>;
out skel qt;
"""
else:
# Pour les nodes ou si les méthodes précédentes échouent, utiliser la boîte englobante
if not bbox:
print("Erreur: bbox requis pour les nodes")
return None
query = f"""
[out:json];
(
way[highway]({bbox[0]},{bbox[1]},{bbox[2]},{bbox[3]});
way[building]({bbox[0]},{bbox[1]},{bbox[2]},{bbox[3]});
way[amenity=parking]({bbox[0]},{bbox[1]},{bbox[2]},{bbox[3]});
);
out body;
>;
out skel qt;
"""
print(f"Utilisation d'une boîte englobante pour {element_type} {osm_id} (moins précis)")
# Envoyer la requête à l'API Overpass
try:
@ -195,14 +236,14 @@ def create_map(osm_id, output_path=None):
name = element_info.get('tags', {}).get('name', f"Lieu_{osm_id}")
print(f"Lieu identifié: {name}")
# Calculer la boîte englobante
# Calculer la boîte englobante pour l'affichage et comme fallback
bbox = get_bbox_from_data(data)
if not bbox:
print("Impossible de calculer la boîte englobante")
return None
# Récupérer les éléments dans la zone
elements_data = get_elements_in_bbox(bbox)
# Récupérer les éléments dans la zone définie par l'élément OSM
elements_data = get_elements_in_area(osm_id, element_type, bbox)
if not elements_data:
print("Impossible de récupérer les éléments dans la zone")
return None
@ -212,9 +253,32 @@ def create_map(osm_id, output_path=None):
center_lon = (bbox[1] + bbox[3]) / 2
center = (center_lat, center_lon)
# Créer la carte
# Créer la carte avec fond Stamen Terrain
print("Création de la carte...")
m = folium.Map(location=center, zoom_start=14, tiles='OpenStreetMap')
m = folium.Map(
location=center,
zoom_start=14,
tiles='Stamen Terrain',
attr='Map tiles by <a href="http://stamen.com">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under <a href="http://www.openstreetmap.org/copyright">ODbL</a>.'
)
# Ajouter d'autres options de fonds de carte
folium.TileLayer(
'Stamen Toner',
attr='Map tiles by <a href="http://stamen.com">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under <a href="http://www.openstreetmap.org/copyright">ODbL</a>.'
).add_to(m)
folium.TileLayer(
'Stamen Watercolor',
attr='Map tiles by <a href="http://stamen.com">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under <a href="http://www.openstreetmap.org/copyright">ODbL</a>.'
).add_to(m)
folium.TileLayer(
'OpenStreetMap',
attr='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
).add_to(m)
folium.LayerControl().add_to(m)
# Ajouter un titre
title_html = f'''