0

I'm working on a function to perform operations on folders of vector files.

These files might have differing attribute fields but there will be a common field between them. I'm using fiona in python to do the work.

A section of code is attached below and I'm using meta = input.meta to gather all the information about the input file to write to the output file.

This is being designed to work on different vector files. So the common field may be different in each run. For example, it might be a string field in one instance or an integer in another.

Despite not knowing beforehand what type of field the input field would be, is it possible to only include the specified field in the output file?

Whilst keeping the other information, such as projection and geometry type, the same as the input.

for file in veclist:
    with fiona.open(file) as input:
        meta = input.meta
        outfilename = os.path.join(outdir, os.path.basename(file).replace('.shp', "_d.shp"))
        with fiona.open(outfilename, 'w', **meta) as output:

I've tried to edit the dictionary of the schema and I've had some success

for file in veclist:
    with fiona.open(file) as input:

        fieldvalue = input.schema['properties'][target_field]

        input.schema['properties'].clear()

        input.schema['properties'][target_field] = fieldvalue

        meta = input.meta
        outfilename = os.path.join(outdir, os.path.basename(file).replace('.shp', "_d.shp"))
        with fiona.open(outfilename, 'w', **meta) as output:

As print(input.schema) listed this:

{'geometry': 'Polygon', 'properties': OrderedDict([('Field_Name', 'str:254')])}

And print(input.meta) listed this:

{'crs': {u'lon_0': -2, u'k': 0.9996012717, u'datum': u'OSGB36', u'y_0': -100000, u'no_defs': True, u'proj': u'tmerc', u'x_0': 400000, u'units': u'm', u'lat_0': 49}, 'driver': u'ESRI Shapefile', 'crs_wkt': u'PROJCS["OSGB_1936_British_National_Grid",GEOGCS["GCS_OSGB 1936",DATUM["OSGB_1936",SPHEROID["Airy_1830",6377563.396,299.3249646]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",49],PARAMETER["central_meridian",-2],PARAMETER["scale_factor",0.9996012717],PARAMETER["false_easting",400000],PARAMETER["false_northing",-100000],UNIT["Meter",1]]', 'schema': {'geometry': 'Polygon', 'properties': OrderedDict([('Field_Name', 'str:254')])}}

But I get this error on trying to write the shapefile:

  File "/.local/lib/python2.7/site-packages/fiona/collection.py", line 355, in write
    self.writerecords([record])
  File "/.local/lib/python2.7/site-packages/fiona/collection.py", line 349, in writerecords
    self.session.writerecs(records, self)
  File "fiona/ogrext.pyx", line 1168, in fiona.ogrext.WritingSession.writerecs
ValueError: Record does not match collection schema: [u'Field_Name', u'pH', u'P_PPM', u'P_Index', u'K_PPM', u'K_Index', u'Mg_PPM', u'Mg_Index', u'2018_y_t_h', u'Grid_ID'] != ['Field_Name']

I thought I had successfully changed my schema and meta when I printed out the results. But it still seems to have picked up the original.

Ok I have gotten slightly further. The issue seem to be due to the next step.

I'm using the dissolve solution from Dissolving polygons based on attributes with Python (shapely, fiona)?

for file in veclist:
    with fiona.open(file) as input:

        fieldvalue = input.schema['properties'][target_field]

        input.schema['properties'].clear()

        input.schema['properties'][target_field] = fieldvalue

        meta = input.meta
        outfilename = os.path.join(outdir, os.path.basename(file).replace('.shp', "_d.shp"))
        with fiona.open(outfilename, 'w', **meta) as output:
            e = sorted(input, key=lambda k: k['properties'][target_field])
            for key, group in itertools.groupby(e, key=lambda x:x['properties'][target_field]):
                properties, geom = zip(*[(feature['properties'], shape(feature['geometry'])) for feature in group])
                print("printing properties")
                print(properties)
                store.append({'geometry': mapping(unary_union(geom)), 'properties': properties[0]})
            print(store)

It's storing all the values of the original fields and attempting to write them to a schema where now only one of the fields exists.

printing properties
(OrderedDict([(u'Grower_ID', 1), (u'Field_Name', u'Black Shed'), (u'pH', 6.0), (u'P_PPM', None), (u'P_Index', u'L+'), (u'K_PPM', None), (u'K_Index', u'M-'), (u'Mg_PPM', None), (u'Mg_Index', u'M'), (u'2018_y_t_h', 7.7), (u'Grid_ID', 291)])

Is it possible to only keep the target_field at this step?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.