Pyshp会将新字段附加到现有shapefile中,但不会记录值

时间:2017-09-12 11:45:08

标签: python csv shapefile

问题在于将.csv文件中显示的列附加为现有shapefile的新字段。所以,我使用了Python和模块pyshp和csv,首先复制原始shapefile的内容(几何和记录),然后在此副本中创建新字段并迭代各自的.csv行以便插入:

import os, sys
import shapefile, csv

from os.path import basename

filename_full = sys.argv[1]
output_full = sys.argv[2]

name, file_extension = os.path.splitext(filename_full)
output_name, file_extension = os.path.splitext(output_full)

filename_dbf =  name + ".dbf"
filename_classified =  name + "_classified.csv"
output_dbf =  output_name + ".dbf"

# reader
myshp = open(filename_full, "rb")
mydbf = open(filename_dbf, "rb")
r = shapefile.Reader(shp=myshp, dbf=mydbf)

# writer
w = shapefile.Writer(r.shapeType)

# copy shapefiles content
w._shapes.extend(r.shapes())
w.records.extend(r.records())
w.fields = list(r.fields)
w.save(output_full)

# add new records from the csv
with open(filename_classified, 'rt', encoding='utf-8') as csvfile:
     reader = csv.DictReader(csvfile, delimiter=',')    
     headers = reader.fieldnames
     [w.field(field) for field in headers]     
     for row in reader:            
        w.record(*tuple([row[f] for f in headers])) # <-- insertion in specific fields

w.save(output_full)

pyshp page中,有几个例子。其中一个特定于将行插入特定字段。如下:

>>> w = shapefile.Writer()
>>> w.field('FIRST_FLD','C','40')
>>> w.field('SECOND_FLD','C','40')
>>> w.record('First', 'Line')
>>> w.record(FIRST_FLD='First', SECOND_FLD='Line')

但是,即使指示字段,我也会得到:

Traceback (most recent call last):
  File "assigning-shapefile.py", line 68, in <module>
    w.record(*tuple([row[f] for f in headers]))
  File "/usr/local/lib/python3.5/dist-packages/shapefile.py", line 1040, in record
    record = [recordList[i] for i in range(fieldCount)]
  File "/usr/local/lib/python3.5/dist-packages/shapefile.py", line 1040, in <listcomp>
    record = [recordList[i] for i in range(fieldCount)]
IndexError: tuple index out of range 

并且,如果我们查看shapefile,我们有类似的东西:

QGIS attribute table before and after the code execution

我得出结论,字段成功添加,但行(w.record与指定的字段名称)不是。

1 个答案:

答案 0 :(得分:0)

使用osgeo库的一个非常简单的方法解决了这个问题:

# --
# USAGE: 
#       python3 assinging-shapefile.py [input-shapefile] [output-shapefile]
# --
# REQUISITE: 
#   The classification csv file should be edited as a header of classifiers and its labels. The file name is mandatory to be IMAGE_NAME-classified.csv
#   Ex: 
#       Filename: IMAGE_NAME-classified.csv
#       Content: 
#               Random forest, Multilayer-Perc, CRF, SVM
#               vegetation, vegetation, building, vegetation
#               wall, window, window, window 
#               ...
# --

import os, sys
import shapefile, csv

from os.path import basename
from osgeo import ogr

filename_full = sys.argv[1]
output_full = sys.argv[2]

name, file_extension = os.path.splitext(filename_full)
output_name, file_extension = os.path.splitext(output_full)

filename_dbf =  name + ".dbf"
filename_classified =  name + "_classified.csv"
output_dbf =  output_name + ".dbf"

myshp = open(filename_full, "rb")
mydbf = open(filename_dbf, "rb")
r = shapefile.Reader(shp=myshp, dbf=mydbf)
w = shapefile.Writer(r.shapeType)

# copy shapefile
w._shapes.extend(r.shapes())
w.records.extend(r.records())
w.fields = list(r.fields)
w.save(output_full)

# read the csv records
csvRecords = []
csvHeaders = []
with open(filename_classified, 'rt', encoding='utf-8') as csvfile:
    reader = csv.DictReader(csvfile, delimiter=',')
    csvHeaders = reader.fieldnames  
    for line in reader:
        csvRecords.append(line)

driver = ogr.GetDriverByName('ESRI Shapefile')
infile = driver.Open(output_full, 1)

for classifier in csvHeaders:
    field = ogr.FieldDefn(classifier, ogr.OFTString)
    field.SetWidth(16)

    layer = infile.GetLayer()
    layer.CreateField(field)

cont = 0
for feature in layer:   
    for classifier in csvHeaders:       
        if(feature.GetField(0)!=cont):
            cont += 1

        feature.SetField(classifier, csvRecords[cont][classifier]) 
        layer.SetFeature(feature)           
infile=None

能够(i)读取csv文件(带有要添加的列),(ii)读取shapefile并复制它,(iii)通过使用对应的csv记录编辑每一行来修改.shp副本