Як ефективно і легко відтворити 500 файлів CSV за допомогою QGIS?


11

Я знаю, моє запитання схоже на деякі старі на цьому сайті.

У мене дуже багато файлів CSV ( геокоординати ) для імпорту в qgis (а потім для їх перетворення), і звичайний спосіб - це не найкращий спосіб зробити це (занадто довго).

У мене майже 500 файлів CSV (координати wgs84), і ось що я хочу зробити:

  1. Імпортуйте всі файли CSV одразу в QGIS
  2. Проектуйте їх
  3. Експортуйте їх у файли CSV (знову), але з різними координатами (перетворення в UTM33N)

Я намагаюся зрозуміти, як використовувати консоль python, але я не рухаюся далі :(

Хтось може мені пояснити, як досягти цього крок за кроком?


дивіться мою відповідь нижче. проблема вже була вирішена і пояснена
Generic Wevers

2
І чому той дублікат із позначеним? Можливо, ОП намагається навчитися pyqgis та як використовувати python, якщо врахувати його / її сміливості.
прізвиська

Будь ласка, вкажіть своє запитання. Ви хочете не завантажувати їх вручну в QGIS? Ви хочете конвертувати їх в інший формат? Яке саме ваше запитання?
bugmenot123

1. Імпортуйте всі файли за один процес у qgis 2. спроектуйте їх 3. експортуйте їх знову у вигляді CSV, але у utm координатах
Raquel Ribeiro

cat * .csv> one_file.csv (або будь-який еквівалент Windows) об'єднає всі ваші файли csv в один. 500 справді не така велика кількість :-)
Джон Пауелл

Відповіді:


15

Якщо ви хочете перепроектувати CSV-файли з консолі Python в QGIS, ви можете використовувати наступний скрипт. Все, що вам потрібно буде змінити, - це три шляхи, про які йдеться в коментарях.

По суті, сценарій імпортує ваші файли csv у QGIS у вигляді форм-файлів (якщо припустити, що ваші геометричні поля названі Xта Y). Потім він використовує qgis:reprojectlayerі qgis:fieldcalculatorалгоритми з Processing Toolbox для перепроеціровать і поновлення Xі Yполя з новими координатами. Потім вони зберігають їх у папці та перетворюють їх у файли csv у вказаному вами шляху. Отже, зрештою, ви оновили файли форм і файли csv в окремих папках.

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")   

Сподіваюся, це допомагає!


2
Чудова відповідь - у вас це все є !. Одне запитання, якщо ви не заперечуєте: вам все одно доведеться додавати / видаляти шари в QgsMapLayerRegistry, навіть якщо ви робите речі з консолі python?
ніки

1
@nickves - Ха-ха, дякую приятелю! Гм, можливо, мені не доведеться додавати / видаляти шари (я впевнений, що сценарій можна значно зменшити). Я не експерт, але я перевіряю це пізніше і повернусь до вас. Якщо ви не зможете надати набагато акуратніший сценарій, і в такому випадку ви можете опублікувати його як відповідь, я б схвалив це :)
Йосип

@nickves - ще раз дякую за ваш приятель! Код відредаговано, щоб уникнути додавання / видалення шарів вдруге :)
Йосип

@RaquelRibeiro - Вітаємо! Радий, що це було корисно :)
Йосип

@ Джозеф, я можу знову попросити щось у вас? У рядках 14 і 15 цифри: 0, 10, 10 визначають, що саме? (Вихідні координати мають занадто багато нулів праворуч, і я хочу їх звести до мінімуму)
Raquel Ribeiro

8

Швидке рішення для перетворення файлу, розділеного пробілом, що містить "lon lat" в WGS84 в UTM33N, але інших даних ви не отримуєте:

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

Це працює, і він зберігає порядок даних, тож можливо інший цикл, наприклад, наприклад, awk для поєднання описових даних з координатами?

Редагувати. Через брудні коментарі, які я виклав нижче, я замість цього зміню відповідь.

Наступний скрипт повинен виконати роботу з читанням декількох файлів csv, додаючи нові колонки координат до кожного файлу.

#!/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

На OSX вам потрібно буде встановити останню (2009) версію sed і використати першу, некомментовану лінію в циклі. Для Linux прокоментуйте перший, а використовуйте другий. Налаштуйте -F " "відповідно до формату роздільника у файлах csv, наприклад -F ","для розділених комами. Також зауважте, що перетворення висоти відбувається в еліпсоїд, а не в геоїд, тому обов'язково перетворіть висоти відповідно.


Я просто згадав, що робив щось подібне деякий час тому і розміщував рішення у своєму блозі. Він написаний для Mac, але на базі. Найбільша різниця - проблема з sed на OS X, якою я займаюся в кінці посту: mercergeoinfo.blogspot.se/2014/01/…
mercergeoinfo

Останній коментар був трохи безладним. Використовуйте цей рядок у вищезгаданому скрипті bash, щоб переглядати всі файли 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}Замініть / usr / local / sed на просто sed, якщо ви не на OSX. Це не ідеально, якщо у файлах CSV розділено простір, як передбачається вище, але це працює. Якщо у вас розділена кома, перейдіть -F " "на-F ","
mercergeoinfo

Цікаво, чому оновлений код у коментарях, і ви не оновили свою відповідь вище. Код у коментарі дійсно важко читати. Ви бачите посилання для редагування під своєю відповіддю?
Миро

Так, але тоді це насправді не було оновленням, скоріше як додатковим. Досить безладний, я згоден. Я думаю, я повинен оновити оригінальну відповідь. Спасибі
mercergeoinfo

7

Використання qgis або навіть OGR є надмірним для цього.
Використовуйте pyproj( https://pypi.python.org/pypi/pyproj ) у поєднанні з письменником-письменником csv і кількома стандартними бібліотечними трюками. Вам не потрібно встановлювати нічого, крім pyprojцього!

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

Я розумію, що плакат досить недосвідчений з пітона. Я регулярно не використовую QGIS, тому хтось із більшим досвідом роботи на цій платформі може пояснити, де встановлений python? Плакат повинен зробити цей окремий сценарій і, ймовірно, запустити його з IDLE. У мене немає поточної установки, тому я не знаю, чи pyprojпотрібно її встановлювати окремо для плаката, або вона вже є.
blord-castillo

1
ніколи раніше не використовував часткову функцію. Зроблять з цього моменту. +1
ники

4

Вам не потрібен пітон. Просто використовуйте командний рядок і ogr2ogr. У вашому випадку найважливішим є параметр -t_srs srs_def.

Це вже пояснено у цій відповіді на тему Як я можу конвертувати файл excel із стовпцями x, y у файл форми?

ОНОВЛЕННЯ У мене немає часу, щоб написати вам ваш повний код. Але проблема буде в тому, що йому потрібно трохи більше коду в python, ніж ви можете подумати.

Вашою основною проблемою буде те, що робота з CSV-файлами не така зручна, як використання форм-файлів. Таким чином, спочатку вам потрібно буде перетворити CSV у форму, для якої потрібен файл VRT. Це пояснено у першому посиланні. Тут вам потрібно буде написати скрипт python, який прокручує ваші файли, що автоматично генерує файли vrt.

Це сценарій, яким я користувався сам. Ви повинні перевірити, чи працює він для вас. Я вже включив перетворення з WGS 84 в 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)

Вам потрібно налаштувати параметри для імені поля , src , x та y відповідно до вашого файлу csv.

ОНОВЛЕННЯ2

Подумавши, я запитую себе, чому ти взагалі хочеш використовувати QGIS? Ви можете використовувати пітон скрипт , як це безпосередньо конвертувати ваші координати з WGS в UTM. У цьому випадку це простий відкритий csv, зчитування координати, перетворення координати та збереження у новий файл.


Я думаю, що це не те, що я шукаю ... У мене майже 500 файлів CSV (координати wgs84), і це те, що я хочу зробити: 1. Імпортувати всі файли CSV відразу до q gis 2. спроектувати їх 3. експортуйте їх у файли CSV (знову), але з різними координатами (перетворення у utm33N)
Ракель Рібейро,

я думаю, що мені потрібен пакетний процес чи щось подібне, щоб це зробити ...
Ракель Рібейро,

4
але чому ти хочеш це робити? 1. ви можете зробити те саме (що ви описали) з командного рядка без qgis. 2. це можна зробити в пакетному режимі. 3. у python він майже однаковий. ви також використовуєте ogr2ogr
Generic Wevers

2
"Просто" за допомогою командного рядка насправді не є відповіддю. Командний рядок ніколи не є простим у використанні, якщо ви не знаєте, як це зробити. І я дійсно не можу знайти рішення у зв’язаній відповіді. Чому б просто не надати бідолаху приклад партії з ogr2ogr, і все було б добре?
Бернд В.

1
добре, 1. ви можете прочитати gis.stackexchange.com/help/how-to-ask . після цього і 5 хвилин гуглення ви визнаєте, що питання дуже погано досліджене і його можна вирішити за допомогою вже даних відповідей. 2. Якщо це все-таки неможливо вирішити, я думаю, всі будуть раді допомогти. але так як я хороша людина, я дам ще кілька підказок.
Generic Wevers
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.