จะปฏิเสธไฟล์ CSV 500 ไฟล์อย่างมีประสิทธิภาพและง่ายดายโดยใช้ QGIS อย่างไร


11

ฉันรู้ว่าคำถามของฉันคล้ายกับคำถามเก่า ๆ ในเว็บไซต์นี้

ฉันมีไฟล์ CSV (พิกัดทางภูมิศาสตร์) จำนวนมากที่จะนำเข้าสู่ qgis (แล้วแปลงเป็นไฟล์) และวิธีปกติไม่ใช่วิธีที่ดีที่สุดในการทำ (ยาวเกินไป)

ฉันมีไฟล์ CSV เกือบ 500 ไฟล์ (พิกัด wgs84) และนี่คือสิ่งที่ฉันต้องการทำ:

  1. นำเข้าไฟล์ CSV ทั้งหมดในครั้งเดียวไปยัง QGIS
  2. ฉายภาพเหล่านั้น
  3. ส่งออกเป็นไฟล์ CSV (อีกครั้ง) แต่มีพิกัดต่างกัน (แปลงเป็น UTM33N)

ฉันพยายามเข้าใจวิธีการใช้งานpython consoleแต่ฉันไม่ได้ไปที่ :(

ทุกคนสามารถอธิบายให้ฉันทราบถึงวิธีการบรรลุเป้าหมายทีละขั้นตอนได้หรือไม่


ดูคำตอบของฉันด้านล่าง ปัญหาได้รับการแก้ไขแล้วและอธิบาย
Generic Wevers

2
และทำไมจึงมีความซ้ำซ้อนกับสิ่งที่ทำเครื่องหมายไว้? บางที OP พยายามเรียนรู้ pyqgis และวิธีการใช้ python ถ้าคุณพิจารณาตัวหนาของเขา / เธอ
nickves

โปรดระบุคำถามของคุณ คุณต้องการที่จะไม่โหลดมันด้วยตนเองลงใน QGIS หรือไม่? คุณต้องการแปลงเป็นรูปแบบอื่นหรือไม่? คำถามของคุณคืออะไร
bugmenot123

1. นำเข้าไฟล์ทั้งหมดในขั้นตอนเดียวไปยัง qgis 2. ฉายภาพเหล่านั้น 3. ส่งออกทั้งหมดอีกครั้งเป็น csv แต่ในพิกัด utm
Raquel Ribeiro

cat * .csv> one_file.csv (หรืออะไรก็ตามที่เทียบเท่ากับ windows) จะรวมไฟล์ csv ทั้งหมดของคุณเข้าด้วยกัน 500 จริงๆไม่ใช่จำนวนมาก :-)
John Powell

คำตอบ:


15

หากคุณต้องการที่จะปฏิเสธไฟล์ csv จากPython Consoleใน QGIS คุณสามารถใช้สคริปต์ต่อไปนี้ สิ่งที่คุณต้องเปลี่ยนคือสามเส้นทางที่กล่าวถึงในความคิดเห็น

โดยพื้นฐานแล้วสคริปต์จะอิมพอร์ตไฟล์ csv ของคุณไปยัง QGIS เป็นรูปร่างไฟล์ (สมมติว่าฟิลด์เรขาคณิตของคุณมีชื่อXและY) จากนั้นใช้qgis:reprojectlayerและqgis:fieldcalculatorอัลกอริทึมจากกล่องเครื่องมือการประมวลผลเพื่อปฏิเสธและอัปเดตฟิลด์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 แม้ว่าคุณจะทำสิ่งต่าง ๆ จากคอนโซลหลาม?
nickves

1
@nickves - ฮ่าฮ่าขอบคุณมากเพื่อน ๆ ! อืมฉันอาจไม่ต้องเพิ่ม / ลบเลเยอร์ (ฉันแน่ใจว่าสคริปต์จะลดลงอย่างมาก) ฉันไม่มีความเชี่ยวชาญ แต่ฉันจะทดสอบในภายหลังและกลับไปหาคุณ ถ้าคุณสามารถให้สคริปต์ neater มากซึ่งในกรณีนี้คุณควรจะโพสต์เป็นคำตอบผมจะ upvote มัน :)
โจเซฟ

@nickves - ขอบคุณอีกครั้งสำหรับเพื่อนแนะนำของคุณ! รหัสได้รับการแก้ไขเพื่อหลีกเลี่ยงการเพิ่ม / ลบชั้นเป็นครั้งที่สอง :)
โจเซฟ

@RaquelRibeiro - ยินดีต้อนรับมากที่สุด! ดีใจที่มันเป็นประโยชน์ :)
โจเซฟ

@Joseph ฉันขอถามคุณอีกครั้งได้ไหม? ที่บรรทัดที่ 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 คุณจะต้องติดตั้ง sed รุ่นล่าสุด (2009) และใช้บรรทัดแรกที่ไม่ใส่เครื่องหมายคอมเม้นต์ในลูป สำหรับ Linux ให้คอมเม้นต์ก่อนและใช้อันที่สอง ปรับ-F " "ตามรูปแบบของตัวแยกในไฟล์ csv ของคุณเช่น-F ","คั่นด้วยเครื่องหมายจุลภาค โปรดทราบว่าการเปลี่ยนระดับความสูงเป็นรูปวงรีไม่ใช่รูปทรงเรขาคณิตดังนั้นโปรดตรวจสอบให้แน่ใจว่าได้แปลงความสูงตามนั้น


ฉันจำได้ว่าเพิ่งทำสิ่งที่คล้ายกันเมื่อไม่นานมานี้และโพสต์โซลูชันในบล็อกของฉัน มันเขียนขึ้นสำหรับ Mac แต่ใช้ทุบตี ความแตกต่างที่ใหญ่ที่สุดคือปัญหากับ sed บน OS X ซึ่งผมจัดการกับในตอนท้ายของการโพสต์: mercergeoinfo.blogspot.se/2014/01/...
mercergeoinfo

ความคิดเห็นล่าสุดค่อนข้างยุ่ง ใช้บรรทัดนี้ในสคริปต์ทุบตีด้านบนเพื่อวนไฟล์ทั้งหมด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 ","
mercerge ซั

ฉันสงสัยว่าทำไมรหัสปรับปรุงในความคิดเห็นและคุณไม่ได้อัปเดตคำตอบของคุณด้านบน รหัสในความคิดเห็นยากต่อการอ่าน คุณเห็นลิงค์แก้ไขใต้คำตอบของคุณหรือไม่
Miro

ใช่แล้ว แต่มันก็ไม่ได้เป็นการปรับปรุงจริง ๆ เช่นเพิ่มเติม สวยยุ่งฉันเห็นด้วย ฉันเดาว่าฉันควรจะปรับปรุงคำตอบเดิม ขอบคุณ
mercergeMp3

7

การใช้ qgis หรือแม้แต่ OGR นั้นเกินความเป็นจริง
ใช้pyproj( https://pypi.python.org/pypi/pyproj ) รวมกับ python csv writer และกลวิธีไลบรารีมาตรฐานสองสามข้อ คุณไม่จำเป็นต้องติดตั้งอะไรนอกจาก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 เป็นประจำดังนั้นบางคนที่มีประสบการณ์มากขึ้นกับแพลตฟอร์มนั้นจะอธิบายว่าติดตั้งไพ ธ อนไว้ที่ใด โปสเตอร์ควรทำให้เป็นสคริปต์แบบสแตนด์อโลนและอาจเรียกใช้จาก IDLE ฉันไม่มีการติดตั้งปัจจุบันดังนั้นฉันไม่รู้ว่าpyprojจะต้องติดตั้งแยกต่างหากสำหรับโปสเตอร์หรือมีอยู่แล้ว
blord-castillo

1
ไม่เคยใช้ฟังก์ชั่นบางส่วนมาก่อน จะทำจากนี้ไป +1
nickves

4

คุณไม่ต้องการหลาม เพียงใช้บรรทัดคำสั่งและ ogr2ogr ในกรณีของคุณสิ่งสำคัญที่สุดคือพารามิเตอร์ -t_srs srs_def

นี่มีคำอธิบายอยู่แล้วในคำตอบนี้เป็นฉันจะแปลงไฟล์ excel ด้วยคอลัมน์ x, y เป็นรูปร่างไฟล์ได้อย่างไร

อัปเดต ฉันไม่มีเวลาที่จะเขียนโค้ดให้คุณ แต่ปัญหาคือมันต้องการรหัสเพิ่มเติมเล็กน้อยในงูหลามกว่าที่คุณคิด

ปัญหาหลักของคุณคือการทำงานกับไฟล์ csv ไม่สะดวกเท่ากับการใช้ shapefiles ดังนั้นก่อนอื่นคุณจะต้องแปลง csv เป็นรูปร่างที่ต้องการไฟล์ VRT นี่คือคำอธิบายในลิงค์แรก ที่นี่คุณจะต้องเขียนสคริปต์ไพ ธ อนที่วนไฟล์ของคุณซึ่งสร้างไฟล์ 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 ของคุณ

UPDATE2

หลังจากคิดแล้วฉันถามตัวเองว่าทำไมคุณถึงต้องการใช้ QGIS เลย? คุณสามารถใช้สคริปต์ python เช่นนี้เพื่อแปลงพิกัดของคุณโดยตรงจาก WGS เป็น UTM ในกรณีนี้มันเป็น csv แบบเปิดง่าย ๆ อ่านค่าพิกัดเปลี่ยนพิกัดและบันทึกเป็นไฟล์ใหม่


ฉันคิดว่านี่ไม่ใช่สิ่งที่ฉันกำลังมองหา ... ฉันมีไฟล์ csv เกือบ 500 ไฟล์ (พิกัด wgs84) และนี่คือสิ่งที่ฉันต้องการทำ: 1. นำเข้าไฟล์ csv ทั้งหมดในครั้งเดียวเพื่อ q gis 2. ฉายภาพเหล่านั้น 3 ส่งออกไปยังไฟล์ csv (อีกครั้ง) แต่ด้วยพิกัดที่ต่างกัน (แปลงเป็น utm33N)
Raquel Ribeiro

ฉันคิดว่าฉันต้องการกระบวนการแบทช์หรือ somethig เช่นนั้นที่จะทำ ...
Raquel Ribeiro

4
แต่ทำไมคุณถึงต้องการทำเช่นนั้น? 1. คุณสามารถทำสิ่งเดียวกัน (สิ่งที่คุณอธิบาย) จากบรรทัดคำสั่งโดยไม่ต้อง qgis 2. คุณสามารถทำได้ในโหมดแบทช์ 3. ในไพ ธ อนมันใกล้เคียงกัน คุณอาจจะใช้ ogr2ogr
Generic Wevers

2
"เพียงแค่" การใช้บรรทัดคำสั่งไม่ใช่คำตอบจริงๆ บรรทัดคำสั่งไม่เคยใช้งานง่ายถ้าคุณไม่รู้ว่าจะทำอย่างไร และฉันไม่สามารถหาคำตอบได้ในคำตอบที่เชื่อมโยงกันจริงๆ ทำไมไม่ลองยกตัวอย่างคนจนกับชุด ogr2ogr แล้วทุกอย่างก็โอเค
Bernd V.

1
ตกลง 1. คุณอาจจะอ่านgis.stackexchange.com/help/how-to-ask หลังจากนั้นและใช้ googleing 5 นาทีคุณจะยอมรับว่าคำถามนั้นได้รับการวิจัยต่ำมากและสามารถแก้ไขได้ด้วยคำตอบที่ได้รับไปแล้ว 2. หากยังไม่สามารถแก้ไขได้ฉันคิดว่าทุกคนยินดีที่จะช่วยเหลือ แต่ในฐานะที่ฉันเป็นคนดีฉันจะให้คำแนะนำเพิ่มเติม
Wevers ทั่วไป
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.