Thursday, 29 November 2018

python - Fiona - Preffered method for defining a schema


I'm fairly new to the world of python and GIS - so this is definitely a beginner question.


I am following Tom Macwrights small guide to Shapely and Fiona, and I noticed that even when opening the previously created shapefile, it doesn't contain the schema I defined using:



schema = { 
'geometry': 'Point',
'properties': { 'name': 'str' } }

This is evident because when I try to call it using schema = input.schema.copy(), it spits out AttributeError: 'function' object has no attribute 'schema'


Reading the Fiona documentation, it states that:



the schema of its record type (a vector file has a single type of record, remember) is accessed via a read-only schema attribute.



Does that mean that it is not possible to store a schema in the shapefile,a nd therefore I'm always required set up the variables in the beginning, rather than reading from the file using input.schema.copy()? Or do I setup the schema using Records?



If so, how do you read from a csv file (as in Tom's example) and place the data into the records to be read from input.schema.copy()? is it helpful to do this, or am I just complicating things and should define the schema every time i open the shapefile?


Thanks for the help - I'm really interested in developing my understanding of the processes occurring.



Answer



I don't really understand your problem. Some explanations: for example, we want to



  1. create a new shapefile


  2. modify the original schema: for that, it's easier to just copy things to a new shapefile and make the changes as you copy



    • Create a new Polyline shapefile:





import fiona
# schema: it is a simple dictionary with geometry and properties as keys
schema = {'geometry': 'LineString','properties': {'test': 'int'}}
# for defining the geometry, you need Shapely
from shapely.geometry import LineString, mapping
# two simples geometries
lines = [LineString([(272830.63,155125.73),(273770.32,155467.75)]),LineString([(273536.47,155914.07),(272033.12,152265.71)])]

with fiona.open('myshp.shp', 'w', 'ESRI Shapefile', schema) as layer:
for line in lines:
# filling schema
elem = {}
# geometry with mapping function of shapely
elem['geometry'] = mapping(line)
# attribute value (the same here)
elem['properties'] = {'test': 145}
# writing element in the file
layer.write(elem)



  • Now we want to modify the schema of the original shapefile in a new shapefile:


1) Open the original shapefile:


shapefile =fiona.open('myshp.shp')
#read the schema
schema2 = shapefile.schema
print schema2
{'geometry': 'LineString', 'properties': OrderedDict([(u'test', 'int:10')])}


2) As it is a dictionary, it is easy to add new fields/keys in the properties:


schema2['properties']['string']='str'

3) Now we create a new shapefile copying myshp.shp with the new schema :


with fiona.open('myshp.shp', 'r') as input:
schema = schema2
# writing the new shapefile
with fiona.open('myshp_copy.shp', 'w', 'ESRI Shapefile', schema) as output:
for elem in input:

# add the new attribute value
elem['properties']['string']="hello"
output.write({'properties': elem['properties'],'geometry': mapping(shape(elem['geometry']))})


  • verification


c = fiona.open('myshp_copy.shp')
c.schema
{'geometry': 'LineString', 'properties': OrderedDict([(u'test', 'int:10'), (u'string', 'str')])}

# first element of the shapefile
c.next()
{'geometry': {'type': 'LineString', 'coordinates': [(272830.63, 155125.73000000001), (273770.32000000001, 155467.75)]}, 'type': 'Feature', 'id': '0', 'properties': OrderedDict([(u'test', 145), (u'string', u'hello')])}


  • Conclusion


If you don't want to modify the shapefile, it is easier with schema.copy() that is only used to get a copy of the original schema (no definition here)


with fiona.open('myshp.shp', 'r') as input:
schema = input.schema.copy()

with fiona.open('myshp_copy2.shp', 'w', 'ESRI Shapefile', schema) as output:
for elem in input:
output.write({'properties': elem['properties'],'geometry': mapping(shape(elem['geometry']))})

No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...