Tuesday, 31 October 2017

python - Get field names of shapefiles using GDAL


I use GDAL in Python for importing shapefile. I want to know the field names for the file, my current way is:


fields = []
for i in range(1, layer.GetFeature(0).GetFieldCount()):
field = layer.GetFeature(0).GetDefnRef().GetFieldDefn(i).GetName()

fields.append(field)

But this way, I am getting the feature for the first layer. Does it mean it is possible that different layers can have different features?


If not, is it possible to get the field names at once, instead of getting into this deep? If yes, is there any easier way of getting the field names?



Answer



1) individual shapefile: as in the comment, a shapefile has only one layer. If you want only the names of the fields


from osgeo import ogr
source = ogr.Open("a_shapefile.shp")
layer = source.GetLayer()
schema = []

ldefn = layer.GetLayerDefn()
for n in range(ldefn.GetFieldCount()):
fdefn = ldefn.GetFieldDefn(n)
schema.append(fdefn.name)
print schema
['dip_dir', 'dip', 'cosa', 'sina']

You can use the GeoJSON format with a Python generator (ogr_geointerface.py)


def records(layer):  
# generator

for i in range(layer.GetFeatureCount()):
feature = layer.GetFeature(i)
yield json.loads(feature.ExportToJson())
features = record(layer)
first_feat = features.next()
print first_feat
{u'geometry': {u'type': u'Point', u'coordinates': [272070.600041, 155389.38792]}, u'type': u'Feature', u'properties': {u'dip_dir': 130, u'dip': 30, u'cosa': -0.6428, u'sina': -0.6428}, u'id': 0}
print first_feat['properties'].keys()
[u'dip', u'dip_dir', u'cosa', u'sina']


This introduces Fiona (another Python wrapper of OGR, Python 2.7.x and 3.x). All results are Python dictionaries (GeoJSON format).


import fiona
shapes = fiona.open("a_shapefile.shp")
shapes.schema
{'geometry': 'Point', 'properties': OrderedDict([(u'dip_dir', 'int:3'), (u'dip', 'int:2'), (u'cosa', 'float:11.4'), (u'sina', 'float:11.4')])}
shapes.schema['properties'].keys()
[u'dip', u'dip_dir', u'cosa', u'sina']
# first feature
shapes.next()
{'geometry': {'type': 'Point', 'coordinates': (272070.600041, 155389.38792)}, 'type': 'Feature', 'id': '0', 'properties': OrderedDict([(u'dip_dir', 130), (u'dip', 30), (u'cosa', -0.6428), (u'sina', -0.6428)])}


And GeoPandas (Fiona + pandas, Python 2.7.x and 3.x). The result is a Pandas DataFrame (= GeoDataFrame).


import geopandas as gpd
shapes = gpd.read_file("a_shapefile.shp")
list(shapes.columns.values)
[u'dip', u'dip_dir', u'cosa', u'sina', 'geometry']
# first features
shapes.head(3)

enter image description here



2) Multiple shapefiles: if you want to iterate through multiple shapefiles in a folder


With osgeo.ogr


for subdir, dirs, files in os.walk(rootdir):
for file in files:
if file.endswith(".shp"):
source = ogr.Open(os.path.join(rootdir, file))
layer = source.GetLayer()
ldefn = layer.GetLayerDefn()
schema = [ldefn.GetFieldDefn(n).name for n in range(ldefn.GetFieldCount())]
print schema


or with a generator


def records(shapefile):  
# generator
reader = ogr.Open(shapefile)
layer = reader.GetLayer(0)
for i in range(layer.GetFeatureCount()):
feature = layer.GetFeature(i)
yield json.loads(feature.ExportToJson())


for subdir, dirs, files in os.walk(rootdir):
for file in files:
if file.endswith(".shp"):
layer = records(os.path.join(rootdir, file))
print layer.next()['properties'].keys()

With Fiona


import fiona
for subdir, dirs, files in os.walk(rootdir):
for file in files:

if file.endswith(".shp"):
layer = fiona.open(os.path.join(rootdir, file))
print layer.schema['properties'].keys()

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...