Làm cách nào để phân phối lại 500 tệp CSV một cách hiệu quả và dễ dàng bằng cách sử dụng QGIS?


11

Tôi biết, câu hỏi của tôi tương tự như một số câu hỏi cũ trên trang web này.

Tôi đã nhập rất nhiều tệp CSV (tọa độ địa lý) để nhập vào qgis (và sau đó để chuyển đổi chúng) và cách thông thường không phải là cách tốt nhất để làm điều đó (quá lâu).

Tôi có gần 500 tệp CSV (tọa độ wss84) và đây là điều tôi muốn làm:

  1. Nhập tất cả các tệp CSV cùng một lúc vào QGIS
  2. Chiếu chúng
  3. Xuất chúng thành tệp CSV (một lần nữa) nhưng với các tọa độ khác nhau (hội tụ đến UTM33N)

Tôi đang cố gắng hiểu cách sử dụng bảng điều khiển python nhưng tôi không di chuyển :(

Bất cứ ai có thể giải thích cho tôi làm thế nào để đạt được nó từng bước?


xem câu trả lời của tôi dưới đây vấn đề đã được giải quyết và giải thích
Chung Wevers

2
Và tại sao nó lại trùng lặp với cái được đánh dấu? Có thể OP cố gắng học pyqgis và cách sử dụng python nếu bạn xem xét sự táo bạo của anh ấy / cô ấy.
biệt danh

Vui lòng ghi rõ câu hỏi của bạn. Bạn có muốn không tải chúng thủ công vào QGIS không? Bạn có muốn chuyển đổi chúng sang định dạng khác? Chính xác câu hỏi của bạn là gì?
bugmenot123

1. Nhập tất cả các tệp trong một quy trình vào qgis 2. chiếu chúng 3. xuất lại tất cả chúng dưới dạng csv nhưng theo tọa độ utm
Raquel Ribeiro

cat * .csv> one_file.csv (hoặc bất cứ thứ gì tương đương với windows) sẽ kết hợp tất cả các tệp csv của bạn thành một. 500 thực sự không phải là một con số lớn như vậy :-)
John Powell

Câu trả lời:


15

Nếu bạn đang tìm cách từ chối các tệp csv từ Bảng điều khiển Python trong QGIS thì bạn có thể sử dụng tập lệnh sau. Tất cả những gì bạn cần thay đổi là ba con đường được đề cập trong các bình luận.

Về cơ bản, tập lệnh nhập các tệp csv của bạn vào QGIS dưới dạng shapefiles (giả sử các trường hình học của bạn được đặt tên XY). Sau đó, nó sử dụng các thuật toán qgis:reprojectlayerqgis:fieldcalculatortừ Hộp công cụ xử lý để định hướng lại và cập nhật XYcác trường với tọa độ mới. Sau đó, nó lưu chúng trong một thư mục và chuyển đổi chúng thành các tệp csv theo đường dẫn bạn chỉ định. Vì vậy, cuối cùng, bạn đã cập nhật các tệp shapefiles và csv trong các thư mục riêng biệt.

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

Hi vọng điêu nay co ich!


2
Câu trả lời tuyệt vời - bạn có tất cả ở đó!. Một câu hỏi nếu bạn không phiền: Bạn vẫn phải thêm / xóa các lớp tại QssMapLayerRegistry ngay cả khi bạn làm mọi thứ từ bảng điều khiển python?
biệt danh

1
@nickves - Haha cảm ơn nhiều bạn! Hmm Tôi có thể không phải thêm / xóa các lớp (Tôi chắc chắn kịch bản có thể được giảm đáng kể). Tôi không phải là chuyên gia nhưng tôi sẽ kiểm tra nó sau và lấy lại cho bạn. Trừ khi bạn có thể cung cấp một kịch bản gọn gàng hơn trong trường hợp bạn nên đăng nó dưới dạng câu trả lời, tôi sẽ nâng cao nó :)
Joseph

@nickves - Cảm ơn một lần nữa cho bạn bè gợi ý của bạn! Mã đã được chỉnh sửa để tránh thêm / xóa các lớp lần thứ hai :)
Joseph

@RaquelRibeiro - Chào mừng bạn nhất! Rất vui vì nó hữu ích :)
Joseph

@Joseph tôi có thể hỏi bạn điều gì nữa không? Ở dòng 14 & 15, các số: 0, 10, 10 đang xác định chính xác là gì? (tọa độ đầu ra có quá nhiều số 0 ở bên phải và tôi muốn giảm thiểu chúng)
Raquel Ribeiro

8

Một giải pháp nhanh chóng để chuyển đổi một tệp được phân tách bằng dấu cách chứa "lon lat" trong WGS84 thành UTM33N nhưng bạn không nhận được bất kỳ dữ liệu nào khác:

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

Điều đó hoạt động và nó bảo toàn thứ tự của dữ liệu để có thể một vòng lặp khác sử dụng ví dụ awk để kết hợp dữ liệu mô tả với tọa độ?

Biên tập. Do những bình luận lộn xộn mà tôi đưa ra dưới đây, tôi sẽ chỉnh sửa câu trả lời ở đây.

Kịch bản sau đây sẽ thực hiện công việc đọc nhiều tệp csv, thêm các cột tọa độ mới vào mỗi tệp.

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

Trên OSX, bạn sẽ cần cài đặt phiên bản sed mới nhất (2009) và sử dụng dòng đầu tiên, không bị lỗi trong vòng lặp. Đối với Linux nhận xét đầu tiên và sử dụng thứ hai. Điều chỉnh -F " "theo định dạng của dấu phân cách trong các tệp csv của bạn, ví dụ như được -F ","phân tách bằng dấu phẩy. Cũng lưu ý rằng việc chuyển đổi độ cao là theo hình elip, không phải là Geoid, vì vậy hãy chắc chắn chuyển đổi độ cao tương ứng.


Tôi chỉ nhớ làm một cái gì đó tương tự một lúc trước và đăng một giải pháp lên blog của tôi. Nó được viết cho Mac nhưng dựa trên bash. Sự khác biệt lớn nhất là vấn đề với sed trên OS X, mà tôi đối phó với ở phần cuối của bài: mercergeoinfo.blogspot.se/2014/01/...
mercergeoinfo

Nhận xét cuối cùng là một chút lộn xộn. Sử dụng dòng này trong tập lệnh bash ở trên để lặp qua tất cả các tệp 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}Thay thế / usr / local / sed bằng sed nếu bạn không dùng OSX. Điều này không lý tưởng nếu các tệp csv của bạn được phân tách bằng dấu cách, như dòng trên giả định, nhưng nó hoạt động. Nếu bạn đã phân tách dấu phẩy thì hãy đổi -F " "thành-F ","
mercergeoinfo

Tôi tự hỏi tại sao mã được cập nhật trong các bình luận và bạn đã không cập nhật câu trả lời của bạn ở trên. Mã trong bình luận thực sự khó đọc. Bạn có thấy liên kết chỉnh sửa bên dưới câu trả lời của bạn?
Miro

Yup, nhưng sau đó nó không thực sự là một bản cập nhật, giống như một bổ sung. Khá lộn xộn, tôi đồng ý. Tôi đoán tôi nên cập nhật câu trả lời ban đầu. Cảm ơn
mercergeoinfo 04/11/2015

7

Sử dụng qgis hoặc thậm chí OGR là quá mức cần thiết cho việc này.
Sử dụng pyproj( https://pypi.python.org/pypi/pyproj ) kết hợp với trình soạn thảo csv python và một vài thủ thuật thư viện tiêu chuẩn. Bạn không cần phải cài đặt bất cứ thứ gì khác ngoài pyprojviệc này!

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

Tôi nhận ra rằng poster khá thiếu kinh nghiệm với python. Tôi không thường xuyên sử dụng QGIS, vì vậy ai đó có nhiều kinh nghiệm hơn với nền tảng đó có thể giải thích nơi python được cài đặt không? Người đăng phải biến nó thành một tập lệnh độc lập và có thể chạy nó từ IDLE. Tôi không có bản cài đặt hiện tại, vì vậy tôi không biết có pyprojcần phải cài đặt riêng cho người đăng hay đã ở đó.
blord-castillo

1
không bao giờ sử dụng chức năng một phần trước đây. Sẽ làm từ bây giờ. +1
biệt danh

4

Bạn không cần trăn. Đơn giản chỉ cần sử dụng dòng lệnh và ogr2ogr. Trong trường hợp của bạn, quan trọng nhất là tham số -t_srs srs_def.

Điều này đã được giải thích trong câu trả lời này cho Làm cách nào tôi có thể chuyển đổi một tệp excel với các cột x, y thành một shapefile?

CẬP NHẬT Tôi không có thời gian để viết cho bạn mã hoàn chỉnh của bạn. Nhưng vấn đề sẽ là nó cần một ít mã trong python hơn bạn nghĩ.

Vấn đề chính của bạn sẽ là làm việc với các tệp csv không thoải mái như sử dụng shapefiles. Do đó, trước tiên bạn sẽ cần chuyển đổi csv thành hình dạng cần tệp VRT. Điều này được giải thích trong liên kết đầu tiên. Ở đây bạn sẽ cần phải viết một kịch bản python lặp qua các tệp của bạn để tự động tạo các tệp vrt.

Đây là một kịch bản tôi đã sử dụng bản thân mình. Bạn phải kiểm tra nếu nó làm việc cho bạn. Tôi đã bao gồm chuyển đổi từ WGS 84 sang 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)

Bạn cần điều chỉnh các tham số cho Tên trường , src , xy theo tệp csv của bạn.

CẬP NHẬT2

Sau khi suy nghĩ, tôi tự hỏi tại sao bạn muốn sử dụng QGIS? Bạn có thể sử dụng tập lệnh python như thế này để chuyển đổi trực tiếp tọa độ của mình từ WGS sang UTM. Trong trường hợp này, nó là một csv mở đơn giản, đọc tọa độ, chuyển đổi tọa độ và lưu nó vào một tệp mới.


Tôi nghĩ rằng đây không phải là thứ tôi đang tìm kiếm ... Tôi có gần 500 tệp csv (tọa độ wss84) và đây là điều tôi muốn làm: 1. Nhập tất cả các tệp csv vào một lần để q gis 2. chiếu chúng 3. xuất chúng thành các tệp csv (một lần nữa) nhưng với tọa độ khác (hội tụ đến utm33N)
Raquel Ribeiro

tôi nghĩ rằng tôi cần một quy trình hàng loạt hoặc đôi khi như thế để làm điều đó ...
Raquel Ribeiro

4
nhưng tại sao bạn muốn làm điều đó? 1. bạn có thể làm tương tự (những gì bạn mô tả) từ dòng lệnh mà không cần qgis. 2. bạn có thể làm điều này trong chế độ hàng loạt. 3. trong python nó gần giống nhau. bạn cũng sẽ sử dụng ogr2ogr
Generic Wevers

2
"Đơn giản" sử dụng dòng lệnh thực sự không phải là một câu trả lời. Dòng lệnh không bao giờ dễ sử dụng nếu bạn không biết làm thế nào để làm điều đó. Và tôi thực sự không thể tìm thấy giải pháp trong câu trả lời được liên kết. Tại sao không chỉ cung cấp cho người nghèo một lô ví dụ với ogr2ogr, và mọi thứ sẽ ổn?
Bernd V.

1
ok, 1. bạn có thể đọc gis.stackexchange.com/help/how-to-ask . sau đó và 5 phút google bạn sẽ thừa nhận rằng câu hỏi được nghiên cứu rất kém và có thể được giải quyết với câu trả lời đã được đưa ra. 2. Nếu vẫn không thể giải quyết được, tôi đoán mọi người sẽ vui lòng giúp đỡ. nhưng vì tôi là một người tốt, tôi sẽ đưa ra một số gợi ý nữa.
Wevers Chung
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.