我知道,我的问题类似于该网站上的一些旧问题。
我有很多CSV文件(地理坐标)要导入到qgis(然后进行转换),通常的方法不是最好的方法(太长)。
我有将近500个CSV文件(wgs84坐标),这就是我想要做的:
- 一次将所有CSV文件导入QGIS
- 投射他们
- 再次将它们导出到CSV文件中,但坐标不同(转换为UTM33N)
我试图了解如何使用python控制台,但我没有继续:(
谁能向我解释如何逐步实现它?
我知道,我的问题类似于该网站上的一些旧问题。
我有很多CSV文件(地理坐标)要导入到qgis(然后进行转换),通常的方法不是最好的方法(太长)。
我有将近500个CSV文件(wgs84坐标),这就是我想要做的:
我试图了解如何使用python控制台,但我没有继续:(
谁能向我解释如何逐步实现它?
Answers:
如果要从QGIS中的Python控制台重新投影csv文件,则可以使用以下脚本。您只需要更改注释中提到的三个路径即可。
本质上,该脚本将您的csv文件作为shapefile导入QGIS(假设您的几何字段命名为X
和Y
)。然后,它使用“ 处理工具箱”中的qgis:reprojectlayer
和qgis:fieldcalculator
算法重新投影并使用新坐标更新和字段。然后,将它们保存在文件夹中,并在您指定的路径中将它们转换为csv文件。因此,最后,您在单独的文件夹中更新了shapefile和csv文件。X
Y
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")
希望这可以帮助!
一种将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上,您将需要安装sed的最新版本(2009),并在循环中使用第一行(未注释)。对于Linux,请注释掉第一个,然后使用第二个。-F " "
根据csv文件中分隔符的格式调整,例如,-F ","
以逗号分隔。还要注意,高程变换是针对椭圆体而不是大地水准面,因此请确保相应地变换高度。
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上,请在上面的bash脚本中使用此行来循环浏览所有文件,将/ usr / local / sed替换为sed。如果您的csv文件以空格分隔(如上一行所假设的那样),则不是理想选择,但它可以工作。如果您用逗号分隔-F " "
,-F ","
为此,使用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
pyproj
需要为海报单独安装,或者已经安装了。
您不需要python。只需使用命令行和ogr2ogr。对于您而言,最重要的是-t_srs srs_def参数。
这已在“ 如何将带有x,y列的excel文件转换为shapefile”的答案中进行了解释。
更新 我没有时间为您编写完整的代码。但是问题是,它在python中需要的代码比您想象的要多。
您的主要问题是使用csv文件不如使用shapefile舒适。因此,您首先需要将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)
您需要根据csv文件调整Field name,src,x和y的参数。
更新2
经过一番思考,我问自己为什么要使用QGIS?您可以使用像这样的python脚本直接将坐标从WGS转换为UTM。在这种情况下,它是一个简单的打开的csv,可以读取坐标,转换坐标并将其保存到新文件中。