QGIS kullanarak 500 CSV dosyasını verimli ve kolay bir şekilde nasıl yeniden kopyalayabilirim?


11

Biliyorum, sorum bu sitedeki bazı eski sorulara benziyor.

Ben qgis (ve daha sonra onları dönüştürmek için) almak için CSV dosyaları (coğrafi koordinatlar) bir sürü var , ve her zamanki gibi bunu yapmak için en iyi yolu değil (çok uzun).

Neredeyse 500 CSV dosyam var (wgs84 koordinatları) ve bunu yapmak istiyorum:

  1. Tüm CSV dosyalarını aynı anda QGIS'e aktarın
  2. Onları projelendirin
  3. Bunları CSV dosyalarına (tekrar) ancak farklı koordinatlarla (UTM33N'ye dönüştürme) dışa aktarın

Python konsolunu nasıl kullanacağımı anlamaya çalışıyorum ama devam etmiyorum :(

Biri bana nasıl adım adım başarılacağını açıklayabilir mi?


aşağıdaki cevabımı gör. sorun zaten çözüldü ve açıklandı
Generic Wevers

2
Ve bu neden işaretlenmiş olanla yineleniyor? Belki OP cesur olduğunu düşünürseniz pyqgis ve python kullanmayı öğrenir.
nickves

Lütfen sorunuzu belirtin. Bunları manuel olarak QGIS'e yüklemek istemez misiniz? Bunları başka bir formata dönüştürmek istiyor musunuz? Sorunuz tam olarak nedir?
bugmenot123

1. Tüm dosyaları tek bir işlemde qgis'e aktarın 2. onları projelendirin 3. hepsini tekrar csv olarak ama utm koordinatlarında verin
Raquel Ribeiro

cat * .csv> one_file.csv (veya windows eşdeğeri ne olursa olsun) tüm csv dosyalarınızı tek bir dosyada birleştirir. 500 gerçekten çok büyük bir sayı değil :-)
John Powell

Yanıtlar:


15

QGIS'deki Python Konsolu'ndan csv dosyalarını yeniden oluşturmak istiyorsanız, aşağıdaki komut dosyasını kullanabilirsiniz. Değiştirmeniz gereken tek şey yorumlarda belirtilen üç yoldur.

Esasen, script shapefiles (sizin geometrik alanlar adlandırılır varsayarak olarak QGIS içine csv dosyalarını alır Xve Y). Ardından ve alanlarını yeni koordinatlarla yeniden yansıtmak ve güncellemek için İşleme Araç Kutusu'ndakiqgis:reprojectlayer ve qgis:fieldcalculatoralgoritmalarını kullanır . Daha sonra bunları bir klasöre kaydeder ve belirttiğiniz bir yolda csv dosyalarına dönüştürür. Sonunda, ayrı klasörlerde şekil dosyaları ve csv dosyalarını güncellediniz.XY

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

Bu yardımcı olur umarım!


2
Harika cevap - her şeye sahipsin !. Sakıncası yoksa bir soru: Python konsolundan bir şeyler yapsanız bile QgsMapLayerRegistry'de katman eklemeniz / kaldırmanız gerekiyor mu?
nickves

1
@nickves - Haha çok teşekkürler dostum! Hmm Katman eklemek / kaldırmak zorunda kalmayabilirim (betiğin önemli ölçüde azaltılabileceğinden eminim). Uzman değilim ama daha sonra test edip size döneceğim. Çok daha temiz bir senaryo sağlayamazsanız, bu durumda bir cevap olarak göndermelisiniz, ben onu değerlendiririm :)
Joseph

@nickves - Öneri arkadaşınız için tekrar teşekkürler! Katmanları ikinci kez eklemeyi / kaldırmayı önlemek için kod düzenlendi :)
Joseph

@RaquelRibeiro - En hoş geldiniz! Sevindim yardımcı oldu :)
Joseph

@Joseph sana tekrar bir şey sorabilir miyim? 14 ve 15. satırlarda, 0, 10, 10 sayıları tam olarak neyi tanımlar? (çıkış koordinatlarının sağda çok fazla sıfır var ve bunları en aza indirmek istiyorum)
Raquel Ribeiro

8

WGS84'te "lon lat" içeren boşlukla ayrılmış bir dosyayı UTM33N'ye dönüştürmek için hızlı bir çözümdür, ancak başka veri almazsınız:

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

Çalışır ve verilerin sırasını korur, böylece açıklayıcı verileri koordinatlarla birleştirmek için örneğin awk kullanan başka bir döngü olabilir mi?

Düzenle. Aşağıda yaptığım dağınık yorumlar nedeniyle cevabı burada düzenleyeceğim.

Aşağıdaki komut dosyası, her dosyaya yeni koordinat sütunları ekleyerek birden çok csv dosyasını okuma işini yapmalıdır.

#!/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'te sed'in en son (2009) sürümünü kurmanız ve döngüdeki ilk, uncommented satırı kullanmanız gerekir. Linux için ilki yorumlayın ve ikincisini kullanın. -F " "Örneğin -F ","virgülle ayrılmış gibi csv dosyalarınızdaki ayırıcı biçimine göre ayarlayın . Ayrıca, yükseklik dönüşümünün jeoide değil elipsoide olduğunu unutmayın , bu nedenle yükseklikleri buna göre dönüştürdüğünüzden emin olun.


Kısa bir süre önce benzer bir şey yaptığımı ve bloguma bir çözüm gönderdiğimi hatırladım. Mac için yazılmıştır, ancak bash tabanlıdır. En büyük fark, yazı sonunda ele aldığım OS X'deki sed ile ilgili sorun: mercergeoinfo.blogspot.se/2014/01/…
mercergeoinfo

Son yorum biraz dağınıktı. Tüm dosyalar arasında geçiş yapmak için yukarıdaki bash betiğindeki bu satırı kullanın. 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}OSX'de değilseniz / usr / local / sed komutunu sadece sed ile değiştirin. Yukarıdaki satırda varsayıldığı gibi, csv dosyalarınız boşlukla ayrılmışsa bu ideal değildir, ancak çalışır. Eğer virgül ardından değişikliği ayrılmış varsa -F " "için-F ","
mercergeoinfo

Yorumlarda güncellenen kodun neden olduğunu merak ediyorum ve yukarıdaki cevabınızı güncellemediniz. Yorumdaki kodu okumak gerçekten zor. Cevabınızın altında düzenleme bağlantısını görüyor musunuz?
Miro

Evet, ama aslında bir güncelleme değildi, daha çok bir ek gibi. Oldukça dağınık, katılıyorum. Orijinal cevabı güncellemeliyim sanırım. Teşekkürler
mercergeoinfo

7

Bunun için qgis ve hatta OGR kullanmak aşırıya kaçıyor.
Kullanım pyproj( https://pypi.python.org/pypi/pyproj ) piton csv yazar ve birkaç standart kütüphane püf noktaları ile birlikte. Bunun dışında bir şey kurmanıza gerek yok 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

Posterin python ile oldukça deneyimsiz olduğunu anlıyorum. Düzenli olarak QGIS kullanmıyorum, bu yüzden bu platformla daha fazla deneyime sahip biri python'un nereye kurulduğunu açıklayabilir mi? Poster bunu bağımsız bir komut dosyası yapmalı ve muhtemelen IDLE'den çalıştırmalıdır. Geçerli bir kurulumum yok, bu yüzden pyprojposter için ayrı olarak yüklenmesi gerekip gerekmediğini bilmiyorum .
blord-castillo

1
daha önce hiç kısmi işlev kullanmamış. Bundan böyle yapacağım. +1
nickves

4

Python'a ihtiyacınız yok. Komut satırını ve ogr2ogr komutunu kullanın. Sizin durumunuzda en önemlisi -t_srs srs_def parametresidir.

Bu zaten açıklanmıştır Bu yanıt için bir shape için x ile bir excel dosyası, y sütunlar dönüştürebilir nasıl?

GÜNCELLEME Size tam kodunuzu yazacak vaktim yok. Ancak sorun python'da düşündüğünüzden biraz daha fazla koda ihtiyaç duyması olacaktır.

Asıl sorun, csv dosyalarıyla çalışmanın şekil dosyaları kullanmak kadar rahat olmamasıdır. Bu yüzden önce csv'yi VRT dosyasına ihtiyaç duyan şekle dönüştürmeniz gerekir. Bu ilk bağlantıda açıklanmıştır. Burada, otomatik olarak vrt dosyalarını oluşturan dosyalarınız arasında bir python betiği yazmanız gerekecektir.

Bu kendimi kullandığım bir senaryo. Sizin için işe yarayıp yaramadığını test etmeniz gerekir. WGS 84'ten UTM 33N'ye dönüşümü zaten ekledim

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)

Alan adı , src , x ve y parametrelerini csv dosyanıza göre ayarlamanız gerekir.

Update2

Biraz düşündükten sonra kendime neden QGIS kullanmak istediğinizi soruyorum. Sen gibi bir piton komut dosyası kullanabilirsiniz bu doğrudan UTM WGS adresinin koordinatları dönüştürmek için. Bu durumda basit bir açık csv, okuma koordinatı, koordinatı dönüştürme ve yeni bir dosyaya kaydetme.


i aradığım şey bu değil ... Neredeyse 500 csv dosyaları (wgs84 koordinatları) var ve bunu yapmak istiyorum: 1. q gis bir kez tüm csv dosyalarını içe aktarın 2. onları proje 3. bunları csv dosyalarına aktarın (tekrar) ancak farklı koordinatlarla (utm33N'ye dönüştürme)
Raquel Ribeiro

Ben bir toplu işlem veya bunu yapmak için böyle bir şey gerekir düşünüyorum ...
Raquel Ribeiro

4
ama bunu neden yapmak istiyorsun? 1. qgis olmadan komut satırından aynı şeyi (tarif ettiğiniz) yapabilirsiniz. 2. bunu toplu modda yapabilirsiniz. 3. python neredeyse aynıdır. ayrıca ogr2ogr
Generic

2
"Sadece" komut satırını kullanmak gerçekten bir cevap değildir. Nasıl yapılacağına dair bir fikriniz yoksa komut satırını kullanmak hiç kolay değildir. Ve bağlantılı cevabı gerçekten bulamıyorum. Neden sadece zavallı adama ogr2ogr ile örnek bir parti vermiyorsunuz ve her şey yolunda?
Bernd V.

1
tamam, 1. gis.stackexchange.com/help/how-to-ask adresini okuyabilirsiniz . Bundan ve 5 dakikalık googleing'den sonra, sorunun çok zayıf bir şekilde araştırıldığını ve zaten verilen cevaplarla çözülebileceğini kabul edeceksiniz. 2. Eğer hala çözülemezse, sanırım herkes yardım etmekten mutluluk duyacaktır. ama iyi bir insan olduğum için daha fazla ipucu vereceğim.
Generic Wevers
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.