mirror of
https://forge.chapril.org/tykayn/wololo
synced 2025-10-04 17:04:53 +02:00
update propose mapping from open data for Rouen métropole trees
This commit is contained in:
parent
f309db257d
commit
d7c622bf71
6 changed files with 276 additions and 33 deletions
|
@ -61,6 +61,11 @@ Résultat: `output/my_converted_data_set__mappingIssy2Roues.json`[makefile](make
|
||||||
## Examen des jeux de données Osmose
|
## Examen des jeux de données Osmose
|
||||||
Osmose permet la détection et suggestion de corrections de données dans OSM. On peut utiliser un export de ces données à la conversion d'un Mapper.
|
Osmose permet la détection et suggestion de corrections de données dans OSM. On peut utiliser un export de ces données à la conversion d'un Mapper.
|
||||||
Pour cela, récupérez un jeu de données et utilisez le convertisseur Osmose de votre choix sur ces données afin d'en faire un nouveau jeu de données.
|
Pour cela, récupérez un jeu de données et utilisez le convertisseur Osmose de votre choix sur ces données afin d'en faire un nouveau jeu de données.
|
||||||
|
|
||||||
|
## Création d'une configuration de conversion
|
||||||
|
Utilisez le script `create_mapping.ts`, celui-ci vous posera quelques questions et se chargera d'ajouter la nouvelle classe dans le fichier principal de conversion.
|
||||||
|
`ts-node create_mapping.ts`
|
||||||
|
|
||||||
[doc sur l'ajout d'un jeu de données](ajout_jeu_de_données.md)
|
[doc sur l'ajout d'un jeu de données](ajout_jeu_de_données.md)
|
||||||
|
|
||||||
## Bornes de recharge - IRVE
|
## Bornes de recharge - IRVE
|
||||||
|
|
|
@ -53,9 +53,11 @@ import MappingAskAngela from "./mappings/converters/configAskAngela";
|
||||||
import MappingPlanningFamlial from "./mappings/converters/configPlanningFamilial";
|
import MappingPlanningFamlial from "./mappings/converters/configPlanningFamilial";
|
||||||
import MappingSurveillanceRouen from "./mappings/converters/configSurveillance";
|
import MappingSurveillanceRouen from "./mappings/converters/configSurveillance";
|
||||||
import MappingRnb from "./mappings/converters/configRnb";
|
import MappingRnb from "./mappings/converters/configRnb";
|
||||||
|
import MappingArbresRemarquablesRouen from './mappings/converters/configArbresRemarquablesRouen'
|
||||||
const limitWarningPercentageChangeInPoints = 5; // show a warning when more than N percent of the number of points changed
|
const limitWarningPercentageChangeInPoints = 5; // show a warning when more than N percent of the number of points changed
|
||||||
|
|
||||||
const allowed_configs: any = {
|
const allowed_configs: any = {
|
||||||
|
MappingArbresRemarquablesRouen,
|
||||||
MappingRnb,
|
MappingRnb,
|
||||||
mappingIssy2Roues,
|
mappingIssy2Roues,
|
||||||
mappingConfigIRVE,
|
mappingConfigIRVE,
|
||||||
|
|
74
mappings/converters/configArbresRemarquablesRouen.ts
Normal file
74
mappings/converters/configArbresRemarquablesRouen.ts
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
/**
|
||||||
|
* arbres monumentaux de Rouen
|
||||||
|
*/
|
||||||
|
import MappingConfigType from "../mapping-config.type";
|
||||||
|
|
||||||
|
const MappingArbresRemarquablesRouen: MappingConfigType = {
|
||||||
|
config_name: "MappingArbresRemarquablesRouen",
|
||||||
|
config_author: "tykayn contact@cipherbliss.com",
|
||||||
|
default_properties_of_point: {
|
||||||
|
natural: 'tree',
|
||||||
|
source: 'Métropole de Rouen',
|
||||||
|
historic: 'monument'
|
||||||
|
},
|
||||||
|
source: {
|
||||||
|
geojson_path: 'https://data.metropole-rouen-normandie.fr/api/explore/v2.1/catalog/datasets/arbres-remarquables-metropole-rouen-normandie-2019/exports/geojson?lang=fr&timezone=Europe%2FBerlin',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
filters: {
|
||||||
|
// exclude_point_if_tag_not_empty: ['id_osm'], // exclure les points ayant déjà un id_osm pour éviter les doublons
|
||||||
|
// offset: 1
|
||||||
|
},
|
||||||
|
add_not_mapped_tags_too: false,
|
||||||
|
boolean_keys: [],
|
||||||
|
tags_to_ignore_if_value_is: ['Non renseigne'],
|
||||||
|
tags: {
|
||||||
|
// Mapping des champs du fichier source vers les tags OSM
|
||||||
|
// 'champ_source': 'tag_osm_cible',
|
||||||
|
// 'champ_source_id': 'ref:FR:votre_id',
|
||||||
|
|
||||||
|
// Exemple de transformation plus complexe
|
||||||
|
// nom: {
|
||||||
|
// key_converted: 'name',
|
||||||
|
// convert_to_name: true,
|
||||||
|
// },
|
||||||
|
|
||||||
|
// "geo_point_2d": "",
|
||||||
|
"gml_id": {
|
||||||
|
key_converted: 'ref:FR:rouen:gml_id',
|
||||||
|
convert_to_name: true,
|
||||||
|
},
|
||||||
|
// "objectid": "",
|
||||||
|
"nom": "name",
|
||||||
|
// "foret": "",
|
||||||
|
// "variete": "",
|
||||||
|
// "diametre_pied": "",
|
||||||
|
// "hauteur": "",
|
||||||
|
// "age": "",
|
||||||
|
// "parcelle": "",
|
||||||
|
// "photo": "",
|
||||||
|
// "pdf": "",
|
||||||
|
// "gps": "",
|
||||||
|
// "x": "",
|
||||||
|
// "y": "",
|
||||||
|
|
||||||
|
"description": "description",
|
||||||
|
"essence_forestiere": {
|
||||||
|
conditional_values: {
|
||||||
|
"Feuillu ": {
|
||||||
|
'tags_to_add': {
|
||||||
|
"leaf_type": "broadleaved",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Résineux": {
|
||||||
|
'tags_to_add': {
|
||||||
|
"leaf_type": "needleleaved",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MappingArbresRemarquablesRouen;
|
0
osm_output/my_converted_data_set__irve-latest-osmose.osm
Normal file
0
osm_output/my_converted_data_set__irve-latest-osmose.osm
Normal file
|
@ -1,33 +0,0 @@
|
||||||
import json
|
|
||||||
import sys
|
|
||||||
import json
|
|
||||||
# examiner un jeu de données geojson, et proposer des tags à mettre dans une config
|
|
||||||
# comme celle ci mappings/converters/configIRVE.ts
|
|
||||||
#
|
|
||||||
# exemple de lancement de commande:
|
|
||||||
# python propose_mapping_from_data.py mon_fichier.geojson
|
|
||||||
|
|
||||||
|
|
||||||
# Vérifie si un argument est fourni
|
|
||||||
if len(sys.argv) < 2:
|
|
||||||
print("Usage: python propose_mapping_from_data.py <geojson_file>")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Ouvre le fichier GeoJSON donné
|
|
||||||
with open(sys.argv[1]) as f:
|
|
||||||
data = json.load(f)
|
|
||||||
|
|
||||||
# Extraire les propriétés de tous les points de la FeatureCollection
|
|
||||||
properties = []
|
|
||||||
for feature in data['features']:
|
|
||||||
props = feature['properties']
|
|
||||||
properties.extend(props.keys())
|
|
||||||
|
|
||||||
# Créer un dictionnaire avec toutes les clés comme clés et des valeurs par défaut vides
|
|
||||||
defaults = {prop: '' for prop in properties}
|
|
||||||
|
|
||||||
# Remplacer les clés contenant "web" ou "téléphone" par "contact:website" ou "contact:phone"
|
|
||||||
defaults.update({prop: 'contact:website' if 'web' in prop else 'contact:phone' if 'téléphone' in prop else '' for prop in properties})
|
|
||||||
|
|
||||||
# Convertir le dictionnaire en JSON et l'afficher
|
|
||||||
print(json.dumps(defaults, indent=2))
|
|
195
propose_mapping_from_geojson.ts
Normal file
195
propose_mapping_from_geojson.ts
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
/**
|
||||||
|
* propose_mapping_from_data.ts
|
||||||
|
* Examine un jeu de données GeoJSON et propose des tags à mettre dans une config
|
||||||
|
* comme celle dans mappings/converters/configIRVE.ts
|
||||||
|
*
|
||||||
|
* Exemple de lancement:
|
||||||
|
* npx ts-node propose_mapping_from_data.ts mon_fichier.geojson
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
interface GeoJSONFeature {
|
||||||
|
type: string;
|
||||||
|
geometry: any;
|
||||||
|
properties: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GeoJSONData {
|
||||||
|
type: string;
|
||||||
|
features: GeoJSONFeature[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie les arguments de la ligne de commande
|
||||||
|
*/
|
||||||
|
function checkArguments(): string {
|
||||||
|
if (process.argv.length < 3) {
|
||||||
|
console.error("Usage: npx ts-node propose_mapping_from_data.ts <geojson_file>");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
return process.argv[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Charge et parse le fichier GeoJSON
|
||||||
|
*/
|
||||||
|
function loadGeoJSONFile(filePath: string): GeoJSONData {
|
||||||
|
try {
|
||||||
|
const fileContent = fs.readFileSync(filePath, 'utf8');
|
||||||
|
const data = JSON.parse(fileContent);
|
||||||
|
|
||||||
|
// Vérifie que le fichier est bien un GeoJSON avec des features
|
||||||
|
if (!data.features || !Array.isArray(data.features)) {
|
||||||
|
console.error("Le fichier ne semble pas être un GeoJSON valide avec des features");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Erreur lors du chargement du fichier: ${error}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extrait toutes les propriétés uniques des features
|
||||||
|
*/
|
||||||
|
function extractProperties(data: GeoJSONData): Set<string> {
|
||||||
|
const properties: Set<string> = new Set();
|
||||||
|
|
||||||
|
for (const feature of data.features) {
|
||||||
|
if (feature.properties) {
|
||||||
|
Object.keys(feature.properties).forEach(key => properties.add(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compte les occurrences des différentes valeurs pour chaque propriété
|
||||||
|
*/
|
||||||
|
function countPropertyValues(data: GeoJSONData): Record<string, Record<string, number>> {
|
||||||
|
const valuesCounts: Record<string, Record<string, number>> = {};
|
||||||
|
|
||||||
|
// Initialiser le comptage pour chaque propriété
|
||||||
|
for (const feature of data.features) {
|
||||||
|
if (feature.properties) {
|
||||||
|
Object.entries(feature.properties).forEach(([key, value]) => {
|
||||||
|
// Convertir la valeur en chaîne pour pouvoir la compter
|
||||||
|
const stringValue = String(value);
|
||||||
|
|
||||||
|
// Initialiser le compteur pour cette propriété si nécessaire
|
||||||
|
if (!valuesCounts[key]) {
|
||||||
|
valuesCounts[key] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Incrémenter le compteur pour cette valeur
|
||||||
|
valuesCounts[key][stringValue] = (valuesCounts[key][stringValue] || 0) + 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return valuesCounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée les mappings suggérés pour les propriétés
|
||||||
|
*/
|
||||||
|
function createMappingSuggestions(properties: Set<string>): Record<string, string> {
|
||||||
|
const defaults: Record<string, string> = {};
|
||||||
|
|
||||||
|
properties.forEach(prop => {
|
||||||
|
// Cherche les propriétés liées au web ou au téléphone
|
||||||
|
if (prop.toLowerCase().includes('web') || prop.toLowerCase().includes('site') || prop.toLowerCase().includes('url')) {
|
||||||
|
defaults[prop] = 'contact:website';
|
||||||
|
}
|
||||||
|
else if (prop.toLowerCase().includes('telephone') || prop.toLowerCase().includes('téléphone') || prop.toLowerCase().includes('phone')) {
|
||||||
|
defaults[prop] = 'contact:phone';
|
||||||
|
}
|
||||||
|
else if (prop.toLowerCase().includes('nom') || prop.toLowerCase().includes('name')) {
|
||||||
|
defaults[prop] = 'name';
|
||||||
|
}
|
||||||
|
else if (prop.toLowerCase().includes('adresse') || prop.toLowerCase().includes('address')) {
|
||||||
|
defaults[prop] = 'addr:full';
|
||||||
|
}
|
||||||
|
else if (prop.toLowerCase().includes('id') || prop.toLowerCase().includes('ref')) {
|
||||||
|
defaults[prop] = 'ref';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
defaults[prop] = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return defaults;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Affiche les statistiques des valeurs pour chaque propriété
|
||||||
|
*/
|
||||||
|
function displayPropertyValueStats(valuesCounts: Record<string, Record<string, number>>): void {
|
||||||
|
console.log('\n=== Statistiques des valeurs par propriété ===');
|
||||||
|
|
||||||
|
Object.entries(valuesCounts).forEach(([prop, values]) => {
|
||||||
|
const totalValues = Object.values(values).reduce((sum, count) => sum + count, 0);
|
||||||
|
const uniqueValues = Object.keys(values).length;
|
||||||
|
|
||||||
|
console.log(`\nPropriété: ${prop}`);
|
||||||
|
console.log(`- Total d'occurrences: ${totalValues}`);
|
||||||
|
console.log(`- Valeurs uniques: ${uniqueValues}`);
|
||||||
|
|
||||||
|
// Si trop de valeurs uniques, n'afficher que les plus fréquentes
|
||||||
|
if (uniqueValues > 10) {
|
||||||
|
console.log('- Top 5 des valeurs les plus fréquentes:');
|
||||||
|
const sortedValues = Object.entries(values)
|
||||||
|
.sort((a, b) => b[1] - a[1])
|
||||||
|
.slice(0, 5);
|
||||||
|
|
||||||
|
sortedValues.forEach(([value, count]) => {
|
||||||
|
// Tronquer les valeurs très longues
|
||||||
|
const displayValue = value.length > 50 ? value.substring(0, 47) + '...' : value;
|
||||||
|
console.log(` "${displayValue}": ${count} occurrences (${Math.round(count / totalValues * 100)}%)`);
|
||||||
|
});
|
||||||
|
console.log(` ... et ${uniqueValues - 5} autres valeurs`);
|
||||||
|
} else {
|
||||||
|
console.log('- Toutes les valeurs:');
|
||||||
|
Object.entries(values)
|
||||||
|
.sort((a, b) => b[1] - a[1])
|
||||||
|
.forEach(([value, count]) => {
|
||||||
|
// Tronquer les valeurs très longues
|
||||||
|
const displayValue = value.length > 50 ? value.substring(0, 47) + '...' : value;
|
||||||
|
console.log(` "${displayValue}": ${count} occurrences (${Math.round(count / totalValues * 100)}%)`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('\n=== Fin des statistiques ===\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fonction principale
|
||||||
|
*/
|
||||||
|
function main(): void {
|
||||||
|
const filePath = checkArguments();
|
||||||
|
const data = loadGeoJSONFile(filePath);
|
||||||
|
|
||||||
|
console.log(`\nFichier GeoJSON chargé: ${filePath}`);
|
||||||
|
console.log(`Nombre de features: ${data.features.length}`);
|
||||||
|
|
||||||
|
const properties = extractProperties(data);
|
||||||
|
|
||||||
|
const valuesCounts = countPropertyValues(data);
|
||||||
|
displayPropertyValueStats(valuesCounts);
|
||||||
|
|
||||||
|
const mappingSuggestions = createMappingSuggestions(properties);
|
||||||
|
|
||||||
|
console.log('Suggestions de mapping OSM:');
|
||||||
|
console.log(JSON.stringify(mappingSuggestions, null, 2));
|
||||||
|
|
||||||
|
console.log(`Nombre de propriétés uniques: ${properties.size}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exécution du programme
|
||||||
|
main();
|
Loading…
Add table
Add a link
Reference in a new issue