13 votos

¿Cómo reproyectar 500 archivos CSV de forma eficaz y sencilla con QGIS?

Lo sé, mi pregunta es similar a algunas antiguas en este sitio.

Tengo un montón de archivos CSV (coordenadas geográficas) para importar a qgis (y luego convertirlos), y la forma habitual no es la mejor manera de hacerlo (demasiado tiempo).

Tengo casi 500 archivos CSV (coordenadas wgs84) y esto es lo que quiero hacer:

  1. Importar todos los archivos CSV a la vez en QGIS
  2. Proyéctelos
  3. Exportarlos a archivos CSV (de nuevo) pero con coordenadas diferentes (conversión a UTM33N)

Estoy tratando de entender cómo utilizar el consola de python pero no voy a seguir adelante :(

¿Alguien puede explicarme cómo conseguirlo paso a paso?

0 votos

Ver mi respuesta más abajo. el problema ya fue resuelto y explicado

2 votos

¿Y por qué está duplicado con el marcado? Tal vez el OP trata de aprender pyqgis y cómo utilizar python si se considera su negrita.

0 votos

Por favor, especifique su pregunta. ¿Quiere no cargarlos manualmente en QGIS? ¿Quiere convertirlos a otro formato? ¿Cuál es exactamente su pregunta?

16voto

Mue Puntos 2469

Si quieres reproyectar archivos csv del Consola Python en QGIS, entonces podría utilizar el siguiente script. Todo lo que tendría que cambiar son las tres rutas que se mencionan en los comentarios.

Esencialmente, el script importa sus archivos csv a QGIS como shapefiles (asumiendo que sus campos geométricos se denominan X y Y ). A continuación, utiliza el qgis:reprojectlayer y qgis:fieldcalculator algoritmos del Caja de herramientas de procesamiento para reproyectar y actualizar el X y Y con las nuevas coordenadas. A continuación, los guarda en una carpeta y los convierte en archivos csv en una ruta que usted especifica. Así que al final, tienes archivos shapefiles actualizados y archivos csv en carpetas separadas.

import glob, os, processing

path_to_csv = "C:/Users/You/Desktop/Testing//"  # Change path to the directory of your csv files
shape_result = "C:/Users/You/Desktop/Testing/Shapefile results//"  # Change path to where you want the shapefiles saved

os.chdir(path_to_csv)  # Sets current directory to path of csv files
for fname in glob.glob("*.csv"):  # Finds each .csv file and applies following actions
        uri = "file:///" + path_to_csv + fname + "?delimiter=%s&crs=epsg:4326&xField=%s&yField=%s" % (",", "x", "y")
        name = fname.replace('.csv', '')
        lyr = QgsVectorLayer(uri, name, 'delimitedtext')
        QgsMapLayerRegistry.instance().addMapLayer(lyr)  # Imports csv files to QGIS canvas (assuming 'X' and 'Y' fields exist)

crs = 'EPSG:32633'  # Set crs
shapefiles = QgsMapLayerRegistry.instance().mapLayers().values()  # Identifies loaded layers before transforming and updating 'X' and 'Y' fields
for shapes in shapefiles:
        outputs_0 = processing.runalg("qgis:reprojectlayer", shapes, crs, None)
        outputs_1 = processing.runalg("qgis:fieldcalculator", outputs_0['OUTPUT'], 'X', 0, 10, 10, False, '$x', None)
        outputs_2 = processing.runalg("qgis:fieldcalculator", outputs_1['OUTPUT_LAYER'], 'Y', 0, 10, 10, False, '$y', shape_result + shapes.name())

os.chdir(shape_result)  # Sets current directory to path of new shapefiles
for layer in glob.glob("*.shp"):  # Finds each .shp file and applies following actions
        new_layer = QgsVectorLayer(layer, os.path.basename(layer), "ogr")
        new_name = layer.replace('.shp', '')
        csvpath = "C:/Users/You/Desktop/Testing/CSV results/" + new_name + ".csv"  # Change path to where you want the csv(s) saved
        QgsVectorFileWriter.writeAsVectorFormat(new_layer, csvpath, 'utf-8', None, "CSV")   

Espero que esto ayude.

2 votos

Gran respuesta - ¡lo tienes todo ahí!. Una pregunta si no te importa: ¿Todavía tienes que añadir/quitar capas en QgsMapLayerRegistry incluso si haces las cosas desde la consola de python?

1 votos

@nickves - ¡Ja, ja, muchas gracias, amigo! Hmm puede que no tenga que añadir/quitar capas (estoy seguro que el script se puede reducir drásticamente). No soy un experto pero lo probaré más tarde y te comentaré. A menos que puedas proporcionar un script mucho más ordenado, en cuyo caso deberías publicarlo como respuesta, yo lo votaría :)

0 votos

@nickves - ¡Gracias de nuevo por tu sugerencia amigo! El código ha sido editado para evitar añadir/quitar las capas por segunda vez :)

8voto

Sork Puntos 26

Usar qgis o incluso OGR es una exageración para esto.
Utilice pyproj ( https://pypi.python.org/pypi/pyproj ) combinado con el escritor csv de python y algunos trucos de la biblioteca estándar. No es necesario instalar nada más que pyproj ¡por esto!

import csv
import pyproj
from functools import partial
from os import listdir, path

#Define some constants at the top
#Obviously this could be rewritten as a class with these as parameters

lon = 'lon' #name of longitude field in original files
lat = 'lat' #name of latitude field in original files
f_x = 'x' #name of new x value field in new projected files
f_y = 'y' #name of new y value field in new projected files
in_path = u'D:\\Scripts\\csvtest\\input' #input directory
out_path = u'D:\\Scripts\\csvtest\\output' #output directory
input_projection = 'epsg:4326' #WGS84
output_projecton = 'epsg:32633' #UTM33N

#Get CSVs to reproject from input path
files= [f for f in listdir(in_path) if f.endswith('.csv')]

#Define partial function for use later when reprojecting
project = partial(
    pyproj.transform,
    pyproj.Proj(init=input_projection),
    pyproj.Proj(init=output_projecton))

for csvfile in files:
    #open a writer, appending '_project' onto the base name
    with open(path.join(out_path, csvfile.replace('.csv','_project.csv')), 'wb') as w:
        #open the reader
        with open(path.join( in_path, csvfile), 'rb') as r:
            reader = csv.DictReader(r)
            #Create new fieldnames list from reader
            # replacing lon and lat fields with x and y fields
            fn = [x for x in reader.fieldnames]
            fn[fn.index(lon)] = f_x
            fn[fn.index(lat)] = f_y
            writer = csv.DictWriter(w, fieldnames=fn)
            #Write the output
            writer.writeheader()
            for row in reader:
                x,y = (float(row[lon]), float(row[lat]))
                try:
                    #Add x,y keys and remove lon, lat keys
                    row[f_x], row[f_y] = project(x, y)
                    row.pop(lon, None)
                    row.pop(lat, None)
                    writer.writerow(row)
                except Exception as e:
                    #If coordinates are out of bounds, skip row and print the error
                    print e

0 votos

Me doy cuenta de que el cartel es bastante inexperto con python. No uso regularmente QGIS, así que ¿podría alguien con más experiencia con esa plataforma explicar dónde se instala python? El cartel debe hacer esto un script independiente y probablemente ejecutarlo desde IDLE. No tengo una instalación actual, así que no sé si pyproj debe instalarse por separado para el cartel, o ya está ahí.

1 votos

Nunca había utilizado la función parcial. Lo haré a partir de ahora. +1

8voto

ccxvii Puntos 566

Una solución rápida para transformar un archivo separado por espacios que contiene "lon lat" en WGS84 a UTM33N, pero no se obtiene ningún otro dato:

#!/bin/bash
#
for i in $( ls *.csv ); do
    gdaltransform -s_srs EPSG:4326 -t_srs EPSG:32633 < ${i} > utm${i}
done

Eso funciona y preserva el orden de los datos, así que tal vez otro bucle usando, por ejemplo, awk para combinar los datos descriptivos con las coordenadas?

Editar. Debido a los comentarios desordenados que hice abajo, editaré la respuesta aquí en su lugar.

El siguiente script debería hacer el trabajo de leer múltiples archivos csv, añadiendo nuevas columnas de coordenadas a cada archivo.

#!/bin/bash
#
for i in $( ls *.csv ); do
 paste -d',' ${i} <(awk -v OFS="," -F " " 'NR>1 {print $1 " " $2}' ${i} | gdaltransform -s_srs EPSG:4326 -t_srs EPSG:32633 | awk '{gsub(" ",",",$0); print $0}' | /usr/local/bin/sed "1i\X,Y,Z") > utm${i}
#
 #paste -d',' ${i} <(awk -v OFS="," -F " " 'NR>1 {print $1 " " $2}' ${i} | gdaltransform -s_srs EPSG:4326 -t_srs EPSG:32633 | awk '{gsub(" ",",",$0); print $0}' |sed "1i\X,Y,Z") > utm${i}
#
done

En OSX tendrá que instalar la última versión (2009) de sed y utilizar la primera línea no comentada en el bucle. En Linux, comenta la primera y utiliza la segunda. Ajuste el -F " " según el formato del separador en sus archivos csv, por ejemplo -F "," para separar las comas. También hay que tener en cuenta que la transformación de la elevación es al elipsoide, no el geoide, así que asegúrate de transformar las alturas en consecuencia.

0 votos

Acabo de recordar haber hecho algo similar hace un tiempo y publicar una solución en mi blog. Está escrito para Mac pero está basado en bash. La mayor diferencia es el problema con sed en OS X, que trato al final del post: mercergeoinfo.blogspot.se/2014/01/

0 votos

El último comentario ha sido un poco desordenado. Utiliza esta línea en el bash script anterior para recorrer todos los archivos paste -d',' ${i} <(awk -v OFS="," -F " " 'NR>1 {print $1 " " $2}' ${i} | gdaltransform -s_srs EPSG:4326 -t_srs EPSG:32633 | awk '{gsub(" ",",",$0); print $0}' | /usr/local/bin/sed "1i\X,Y,Z") > utm${i} Reemplace el /usr/local/sed con sólo sed si no está en OSX. Esto no es ideal si sus archivos csv están separados por espacios, como la línea anterior supone, pero funciona. Si tiene archivos separados por comas, cambie -F " " a -F ","

0 votos

Me pregunto por qué está el código actualizado en los comentarios y usted no actualizó su respuesta anterior. El código en el comentario es realmente difícil de leer. ¿Ves el enlace de edición debajo de tu respuesta?

4voto

epic9x Puntos 1020

No necesitas python. Simplemente usa la línea de comandos y ogr2ogr. En su caso lo más importante es el parámetro -t_srs srs_def.

Esto ya se explica en esta respuesta a ¿Cómo puedo convertir un archivo excel con columnas x, y en un shapefile?

ACTUALIZACIÓN No tengo tiempo para escribirte el código completo. Pero el problema será que se necesita un poco más de código en python de lo que se puede pensar.

Su principal problema será que trabajar con archivos csv no es tan cómodo como usar shapefiles. Por lo tanto, primero tendrá que convertir el csv en shape, lo que requiere un archivo VRT. Esto se explica en el primer enlace. Aquí tendrás que escribir un python script que recorra tus archivos y genere automáticamente los archivos vrt.

Este es un script que he utilizado yo mismo. Tienes que probar si te funciona. Ya incluí la conversión de WGS 84 a UTM 33N

from os import listdir, stat, mkdir, system
path = "your path here"
out_path = "your output path here"
files = filter(listdir(path), '*.csv') #for Python 3.x
# files= [f for f in listdir(path) if f.endswith('.csv')] #for Python 2.7

for x in range(len(files)):
    name = files[x].replace('.csv', '')
    # 2. create vrt file for reading csv
    outfile_path1 = out_path + name + '.vrt'
    text_file = open(outfile_path1, "w")
    text_file.write('<OGRVRTDataSource> \n')
    text_file.write('    <OGRVRTLayer name="' + str(name) + '"> \n')
    text_file.write('        <SrcDataSource relativeToVRT="1">' + name + '.csv</SrcDataSource> \n')
    text_file.write('        <GeometryType>wkbPoint</GeometryType> \n')
    text_file.write('        <LayerSRS>WGS84</LayerSRS> \n')
    text_file.write('        <GeometryField encoding="PointFromColumns" x="Lon" y="Lat"/> \n')
    text_file.write('        <Field name="Name" src="Name" type="String" /> \n')
    text_file.write('    </OGRVRTLayer> \n')
    text_file.write('</OGRVRTDataSource> \n')
    # 3. convert csv/vrt to point shapefile
    outfile_path2 = out_path + name + '.shp'
    command = ('ogr2ogr -f "ESRI Shapefile" -t_srs EPSG:32633' + outfile_path2 + ' ' +  outfile_path1)
    system(command)

Es necesario ajustar los parámetros para Nombre del campo , src , x y y según su archivo csv.

ACTUALIZACIÓN2

Después de pensarlo un poco, me pregunto por qué quieres usar QGIS. Podrías usar un python script como este para convertir directamente sus coordenadas de WGS a UTM. En este caso es un simple abrir csv, leer coordenadas, transformar coordenadas y guardarlas en un nuevo archivo.

0 votos

Creo que esto no es lo que busco... Tengo casi 500 archivos csv (coordenadas wgs84) y esto es lo que quiero hacer: 1. Importar todos los archivos csv de una vez a q gis 2. proyectarlos 3. exportarlos a archivos csv (de nuevo) pero con coordenadas diferentes (conversión a utm33N)

0 votos

Creo que necesito un proceso por lotes o algo así para hacerlo...

4 votos

¿pero por qué quieres hacer eso? 1. puedes hacer lo mismo (lo que has descrito) desde la línea de comandos sin qgis. 2. puedes hacerlo en modo batch. 3. en python es casi lo mismo. también usarías ogr2ogr

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X