From a0f810f6db67190287c11de5b5f725432eb86dc9 Mon Sep 17 00:00:00 2001 From: Tykayn Date: Mon, 31 Mar 2025 12:59:26 +0200 Subject: [PATCH] convert csv to geojson with panoramax speedlimit data --- csv_to_geojson.ts | 152 ++++++++++++++++++++++++++++++++++++++++++++++ unzip_csv.ts | 70 +++++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 csv_to_geojson.ts create mode 100644 unzip_csv.ts diff --git a/csv_to_geojson.ts b/csv_to_geojson.ts new file mode 100644 index 0000000..0976d36 --- /dev/null +++ b/csv_to_geojson.ts @@ -0,0 +1,152 @@ +/** + * csv_to_geojson.ts + * + * Convertir un fichier CSV en GeoJSON + * + * Utilisation: + * + * npx ts-node csv_to_geojson.ts -d etalab_data/panneaux -f panneaux_limite_de_vitesse_fr_panoramax_detections.csv --latColumn 'GPSLatitude' --lonColumn 'GPSLongitude' -h + * + */ +import fs from 'fs'; +import path from 'path'; +import csvParser from 'csv-parser'; +import minimist from 'minimist'; +import { Feature, FeatureCollection, Point } from 'geojson'; + +interface Options { + dir: string; + file: string; + latColumn: string; + lonColumn: string; + hasHeaders: boolean; +} +let counter = 0; +function csvToGeoJSON(options: Options): FeatureCollection { + const { dir, file, latColumn, lonColumn, hasHeaders } = options; + + console.log(`options latColumn: ${latColumn}`); + console.log(`options lonColumn: ${lonColumn}`); + + const filePath = path.join(dir, file); + const features: Feature[] = []; + let geoJSON: FeatureCollection = { + type: 'FeatureCollection', + features, + }; + + let headers: string[] = []; + let headersFound = false; + + let limitOffset = 100; + + console.log(`hasHeaders: ${hasHeaders}`); + fs.createReadStream(filePath) + .pipe(csvParser({ headers: hasHeaders })) + .on('data', (row) => { + counter++; + if (!headersFound && hasHeaders) { + let keys = Object.keys(row); + keys.forEach((key) => { + headers.push(row[key]); + }); + headersFound = true; + console.log(`headers: ${headers}`); + } + if (counter > limitOffset) { + return; + } + if (headers.indexOf(latColumn)) { + console.log(`latColumn: ${latColumn}`); + console.log(`headers latColumn: ${headers.indexOf(latColumn)}`); + console.log(`headers.indexOf(latColumn): `, headers.indexOf(latColumn)); + console.log('row', row); + const lat = parseFloat(row['_' + headers.indexOf(latColumn)]); + const lon = parseFloat(row['_' + headers.indexOf(lonColumn)]); + + // Si pas d'entêtes, utiliser des noms de colonnes génériques + if (!hasHeaders) { + const properties: { [key: string]: any } = {}; + Object.keys(row).forEach((key, index) => { + properties[headers[index]] = row[key]; + }); + row = properties; + } else { + let keys = Object.keys(row); + // Utiliser les entêtes comme noms de propriétés + const properties: { [key: string]: any } = {}; + headers.forEach((header, index) => { + + properties[header] = row['_' + index]; + }); + row = properties; + } + + // filtrer la ligne du header si présente + if (hasHeaders && counter > 1 || !hasHeaders || counter > limitOffset) { + features.push({ + type: 'Feature', + geometry: { + type: 'Point', + coordinates: [lon, lat], + }, + properties: row, + }); + } + } + else { + console.log('!!! no latColumn', row); + } + + }) + .on('end', () => { + geoJSON = { + type: 'FeatureCollection', + features, + }; + fs.writeFileSync(`${dir}/${file}.geojson`, JSON.stringify(geoJSON, null, 2)); + console.log(`GeoJSON créé avec succès : ${file}.geojson`); + }); + + console.log(`geoJSON lines: ${counter}`); + return geoJSON; +} + +const args = minimist(process.argv.slice(2), { + alias: { + dir: 'd', + file: 'f', + latColumn: 'lat', + lonColumn: 'lon', + hasHeaders: 'h', + }, + default: { + hasHeaders: true, + }, +}); + +function checkFile(args: Options) { + let filePath = path.join(args.dir, args.file); + let lineCount = 0; + + // Vérifier si le fichier existe + if (!fs.existsSync(filePath)) { + throw new Error(`Le fichier CSV ${filePath} n'existe pas`); + } else { + console.log(`Le fichier CSV ${filePath} existe`); + } + + fs.createReadStream(filePath) + .on('data', () => { + lineCount++; + }) + .on('end', () => { + console.log(`Nombre de lignes dans le fichier CSV : ${Math.floor(lineCount)}`); + }); + + +} + +console.log(`args: `, args); +checkFile(args); +csvToGeoJSON(args); \ No newline at end of file diff --git a/unzip_csv.ts b/unzip_csv.ts new file mode 100644 index 0000000..3832627 --- /dev/null +++ b/unzip_csv.ts @@ -0,0 +1,70 @@ +import axios from 'axios'; +import * as fs from 'fs'; +import * as zlib from 'zlib'; +import minimist from 'minimist'; + +interface Options { + url: string; + outputFile?: string; + category?: string; + gzip?: boolean; +} +/** + * @name downloadFile + * @description Télécharger un fichier d'open data csv gzippé et le mettre dans le dossier etalab_data dans une certaine catégorie + * + * Utilisation: + * + * npx ts-node unzip_csv.ts -u https://www.data.gouv.fr/fr/datasets/r/16a20f4e-0c06-40ff-adda-54f214099e5f -o panneaux_limite_de_vitesse_fr_panoramax_detections.csv -z + * + */ +async function downloadFile(options: Options): Promise { + try { + const response = await axios.get(options.url, { responseType: 'arraybuffer' }); + + if (!options.outputFile) { + throw new Error('Le nom du fichier de sortie est requis'); + } + + if (options.gzip) { + const gunzip = zlib.createGunzip(); + const output = fs.createWriteStream(options.outputFile); + gunzip.pipe(output); + gunzip.end(response.data); + } else { + fs.writeFileSync('etalab_data/' + options.category + '/' + options.outputFile, response.data); + } + + console.log(`Fichier téléchargé avec succès et enregistré en tant que ${options.outputFile}`); + } catch (error: any) { + console.error(`Erreur lors du téléchargement du fichier : ${error.message}`); + } +} + +const args = minimist(process.argv.slice(2), { + alias: { + url: 'u', + outputFile: 'o', + gzip: 'z', + category: 'c', + }, + default: { + category: 'panneaux', + outputFile: 'panneaux_limite_de_vitesse_fr.csv', + url: 'https://www.data.gouv.fr/fr/datasets/r/16a20f4e-0c06-40ff-adda-54f214099e5f' + }, +}); + +if (!args.url) { + console.error('L\'URL est requise. Utilisez -u ou --url'); + process.exit(1); +} + +const options: Options = { + url: args.url, + outputFile: args.outputFile, + category: args.category, + gzip: args.gzip === true +}; + +downloadFile(options); \ No newline at end of file