QGISを使用して500個のCSVファイルを効率的かつ簡単に再投影する方法は?


11

私の質問は、このサイトの古い質問と似ています。

私はqgisにインポートする(そして変換する)多くのCSVファイル(geo座標)を持っていますが、それを行うには通常の方法は最適ではありません(長すぎます)。

私はほぼ500のCSVファイル(wgs84座標)を持っていますが、これは私がやりたいことです:

  1. すべてのCSVファイルを一度にQGISにインポートする
  2. それらを投影する
  3. それらをCSVファイルに(再び)エクスポートしますが、座標が異なります(UTM33Nへの変換)

私はPythonコンソールの使用方法を理解しようとしていますが、先に進みません:(

誰も私にステップバイステップでそれを達成する方法を説明できますか?


以下の私の答えをご覧ください。この問題は既に解決され、説明されています
ジェネリックWevers

2
そして、なぜそれがマークされたものと重複していますか?たぶん、OPはpyqgisと、ボールドを考慮するとpythonを使用する方法を学習しようとします。
ニック

質問を指定してください。それらを手動でQGISにロードしませんか?別の形式に変換しますか?ご質問は何ですか?
bugmenot123

QGIS 2.プロジェクトへの1つのプロセス1.インポートしたすべてのファイルにそれらをCSVとしてではなく、UTM座標に再びすべて書き出す3.
ラクエル・リベイロ

cat * .csv> one_file.csv(またはWindowsの同等のもの)は、すべてのcsvファイルを1つに結合します。500はそれほど大きな数字ではありません:
ジョンパウエル

回答:


15

QGIS のPythonコンソールからcsvファイルを再投影する場合は、次のスクリプトを使用できます。変更する必要があるのは、コメントに記載されている3つのパスのみです。

基本的に、スクリプトはcsvファイルをシェープファイルとしてQGISにインポートします(ジオメトリフィールドの名前がXandであると仮定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
素晴らしい答え-あなたはそれをすべて持っています!気にしない場合の質問:pythonコンソールから操作を行っても、QgsMapLayerRegistryでレイヤーを追加/削除する必要がありますか?
ニックス

1
@nickves-ハハ、どうもありがとう!うーん、レイヤーを追加/削除する必要はないかもしれません(スクリプトを劇的に減らすことができると確信しています)。私は専門家ではありませんが、後でテストし、ご連絡いたします。あなたが答えとしてそれを投稿する必要があります非常にきれいなスクリプトを提供できない限り、私はそれを賛成します:)
ジョセフ

@nickves-提案バディをありがとう!コードを編集して、2回目のレイヤーの追加/削除を回避しました:)
ジョセフ

@RaquelRibeiro-大歓迎です!
ジョセフ

@Josephもう一度質問してもいいですか?14行目と15行目では、0、10、10の数字が正確に何を定義していますか?(出力座標の右側にゼロが多すぎるため、それらを最小化したい)
ラクエルリベイロ

8

WGS84の「lon lat」を含むスペース区切りファイルを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の場合、最初のものをコメントアウトし、2番目のものを使用します。-F " "CSVファイルの区切り記号の形式に応じて、-F ","コンマ区切りなどを調整します。また、高度変換はジオイドではなく楕円体に変換されるため、それに応じて高さも変換するようにしてください。


少し前に似たようなことをして、自分のブログに解決策を投稿したことを思い出しました。Mac用に書かれていますが、bashベースです。最大の違いは、私は記事の最後に対処OS X、上のsedで問題です: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}。OSXを使用していない場合は、/ usr / local / sedをsedに置き換えます。上記の行が想定しているように、csvファイルがスペースで区切られている場合、これは理想的ではありませんが、動作します。カンマで区切られている場合は、次のように変更-F " "します-F ","
mercergeoinfo

なぜ更新されたコードがコメントにあり、上記の回答を更新しなかったのでしょうか。コメント内のコードは本当に読みにくいです。回答の下に編集リンクが表示されていますか?
ミロ

うん、でもそれは実際にはアップデートではなく、追加のようなものだった。かなり面倒です、私は同意します。元の回答を更新する必要があると思います。ありがとう
-mercergeoinfo

7

これにはqgisまたはOGRを使用するのはやり過ぎです。(https://pypi.python.org/pypi/pyproj)をpython csvライターといくつかの標準ライブラリトリックと組み合わせて
使用します。これ以外のものをインストールする必要はありません! pyprojpyproj

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

ポスターはpythonにはかなり慣れていないことがわかります。私はQGISを定期的に使用していませんが、そのプラットフォームの経験が豊富な人がPythonのインストール場所を説明できますか?ポスターは、これをスタンドアロンスクリプトにし、おそらくIDLEから実行する必要があります。現在インストールpyprojされていないので、ポスター用に個別にインストールする必要があるのか​​、それとも既にインストールされているのかわかりません。
blord-castillo

1
以前に部分関数を使用したことはありません。これからします。+1
ニックス

4

pythonは必要ありません。コマンドラインとogr2ogrを使用するだけです。あなたの場合、最も重要なのは-t_srs srs_defパラメーターです。

これは、すでに説明されているこの答え、私はシェープファイルにXとExcelファイル、yの列を変換するにはどうすればよいですか?

更新 完全なコードを作成する時間はありません。しかし、問題は、あなたが思っているよりもPythonで少し多くのコードを必要とすることです。

主な問題は、csvファイルの操作がシェープファイルの使用ほど快適ではないことです。したがって、最初にcsvをVRTファイルを必要とする形状に変換する必要があります。これは最初のリンクで説明されています。ここで、vrtファイルを自動的に生成するファイルをループするPythonスクリプトを作成する必要があります。

これは私が自分で使用したスクリプトです。動作するかどうかをテストする必要があります。すでに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)

csvファイルに応じて、フィールド名srcxyのパラメーターを調整する必要があります。

更新2

少し考えてから、なぜQGISを使用したいのでしょうか?このようなPythonスクリプトを使用して、座標をWGSからUTMに直接変換できます。この場合、それは単純なオープンCSVであり、座標を読み取り、座標を変換し、新しいファイルに保存します。


私はこれが私が探しているものではないと思います...私はほぼ500のcsvファイル(wgs84座標)を持っています、これは私がやりたいことです:1.すべてのcsvファイルをq gisに1回インポートしますそれらをcsvファイルに(再び)エクスポートしますが、座標は異なります(utm33Nへの変換)
ラケルリベイロ

私は...私はそれを行うにはそのようなバッチ処理やsomethigが必要だと思う
ラクエル・リベイロ

4
しかし、なぜあなたはそれをしたいのですか?1. qgisを使用せずにコマンドラインから同じこと(説明したこと)を実行できます。2.これはバッチモードで実行できます。3. pythonでもほぼ同じです。また、ogr2ogr
Generic Wevers

2
コマンドラインを使用する「単純に」は、実際には答えではありません。コマンドラインは、使い方が分からない場合は決して使いやすいものではありません。そして、私は本当にリンクされた答えで解決策を見つけることができません。貧しい仲間にogr2ogrのサンプルバッチを与えるだけで、すべてがうまくいくのはなぜですか。
ベルントV.

1
OK、1。gis.stackexchange.com/help/how-to-askを読むことができます。その後、5分間のグーグル検索を行うと、質問の調査が非常に不十分であり、既に与えられた回答で解決できることを認めます。2.それでも解決できない場合、誰もが喜んで助けてくれると思います。しかし、私はいい人なので、もう少しヒントをあげます。
ジェネリックWevers
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.