├── .gitignore ├── ogr_geointerface.py ├── PyQGIS_geointerface.py ├── spatialite_geointerface.py ├── PyShp_geointerface.py ├── Pyshp_mapping.py ├── PostGIS_geointerface.py ├── PyShp_schema.py ├── mapnik_geointerface.py ├── QGIS_add_geo_interface.py ├── pyshp_geojson.py ├── ogr_gml_to_geojson.py └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | 21 | # Installer logs 22 | pip-log.txt 23 | 24 | # Unit test / coverage reports 25 | .coverage 26 | .tox 27 | nosetests.xml 28 | 29 | # Translations 30 | *.mo 31 | 32 | # Mr Developer 33 | .mr.developer.cfg 34 | .project 35 | .pydevproject 36 | -------------------------------------------------------------------------------- /ogr_geointerface.py: -------------------------------------------------------------------------------- 1 | def records(shapefile): 2 | # generator 3 | reader = ogr.Open(shapefile) 4 | layer = reader.GetLayer(0) 5 | for i in range(layer.GetFeatureCount()): 6 | feature = layer.GetFeature(i) 7 | yield json.loads(feature.ExportToJson()) 8 | 9 | >>> from osgeo import ogr 10 | >>> a = records('point.shp') 11 | >>> a.next() 12 | {'geometry': {'type': 'Point', 'coordinates': (161821.09375, 79076.0703125)}, 'properties': {'DIP_DIR': 120, 'STRATI_TYP': 1, 'DIP': 30}} 13 | -------------------------------------------------------------------------------- /PyQGIS_geointerface.py: -------------------------------------------------------------------------------- 1 | layer = qgis.utils.iface.activeLayer() 2 | 3 | def records(layer): 4 | fields = layer.pendingFields() 5 | field_names = [field.name() for field in fields] 6 | for elem in layer.getFeatures(): 7 | geom= elem.geometry() 8 | atr = dict(zip(field_names, elem.attributes())) 9 | yield dict(geometry=geom.exportToGeoJSON(),properties=atr) 10 | 11 | c = records(layer) 12 | c.next() 13 | {'geometry': {'type': 'Point', 'coordinates': (161821.09375, 79076.0703125)}, 'id': '0', 'properties': {u'DIP_DIR': 120, u'STRATI_TYP': 1, u'DIP': 30}} 14 | -------------------------------------------------------------------------------- /spatialite_geointerface.py: -------------------------------------------------------------------------------- 1 | from pyspatialite import dbapi2 as db 2 | conn = db.connect('test_db.sqlite') 3 | conn.row_factory = db.Row 4 | cur = conn.cursor() 5 | 6 | def records(result): 7 | for i in result: 8 | atr=dict(zip(i.keys()[:-1],list(i)[:-1])) 9 | yield dict(geometry=list(i)[-1],properties=atr) 10 | 11 | 12 | sql = "SELECT dip_dir,strati,dip, AsGeoJSON(geom) from point" 13 | rs = cur.execute(sql) 14 | c = records(rs) 15 | c.next() 16 | {'geometry': u{'type': 'Point', 'coordinates': (161821.09375, 79076.0703125)}, 'id': '0', 'properties': {'dip_dir': 120, 'strati_typ': 1, 'dip': 30}} 17 | -------------------------------------------------------------------------------- /PyShp_geointerface.py: -------------------------------------------------------------------------------- 1 | def records(filename): 2 | # generator 3 | reader = shapefile.Reader(filename) 4 | fields = reader.fields[1:] 5 | field_names = [field[0] for field in fields] 6 | for sr in reader.shapeRecords(): 7 | geom = sr.shape.__geo_interface__ 8 | atr = dict(zip(field_names, sr.record)) 9 | yield dict(geometry=geom,properties=atr) 10 | 11 | 12 | >>> import shapefile 13 | >>> a = records('point.shp') 14 | >>> a.next() 15 | {'geometry': {'type': 'Point', 'coordinates': (161821.09375, 79076.0703125)}, 'properties': {'DIP_DIR': 120, 'STRATI_TYP': 1, 'DIP': 30}} 16 | -------------------------------------------------------------------------------- /Pyshp_mapping.py: -------------------------------------------------------------------------------- 1 | import shapefile 2 | reader= shapefile.Reader("/Users/Shared/Dropbox/coupe_profile/strati2.shp") 3 | elem = reader.shapeRecords()[0] 4 | 5 | 6 | def mapping_feature(reader,feature): 7 | properties = {} 8 | geom = feature.shape.__geo_interface__ 9 | fields = reader.fields[1:] 10 | fields = [field[0] for field in fields] 11 | atr = dict(zip(fields, feature.record)) 12 | return dict(geometry=geom,properties=atr) 13 | 14 | mapping_feature(reader,elem) 15 | {'geometry': {'type': 'Point', 'coordinates': (272070.600041, 155389.38792000001)}, 'properties': {'DIRECTION': 130, 'PENDAGE': 30, 'TYPE': 'incl'}} 16 | 17 | -------------------------------------------------------------------------------- /PostGIS_geointerface.py: -------------------------------------------------------------------------------- 1 | # for PostGIS version < 9 2 | import psycopg2 3 | import psycopg2.extras 4 | from json import loads 5 | def records(result): 6 | for i in result: 7 | atr=dict(zip(i.keys()[:-1],list(i)[:-1])) 8 | yield dict(geometry=loads(list(i)[-1]),properties=atr) 9 | 10 | conn = psycopg2.connect("dbname='testpostgis'host='localhost' user='me'",cursor_factory=psycopg2.extras.DictCursor) 11 | cur = conn.cursor() 12 | sql = """SELECT "dip_dir","strati","dip", ST_AsGeoJSON(the_geom) from from point;""" 13 | cur.execute(sql) 14 | c = records(cur.fetchall()) 15 | c.next() 16 | {'geometry': {u'type': u'Point', u'coordinates': [161821.09375, 79076.0703125]}, 'properties': {'dip_dir': 120, 'strati_typ': 1, 'dip': 30}} 17 | 18 | # convert to shapely geometry 19 | from shapely.geometry import shape 20 | print shape(c.next()['geometry']) 21 | POINT (161821.09375, 79076.0703125) 22 | -------------------------------------------------------------------------------- /PyShp_schema.py: -------------------------------------------------------------------------------- 1 | # shema comme Fiona 2 | 3 | import fiona 4 | c = fiona.open('strati2.shp') 5 | c.schema 6 | {'geometry': 'Point', 'properties': {u'DIRECTION': 'int', u'PENDAGE': 'int', u'TYPE': 'str:10'}} 7 | 8 | 9 | import shapefile 10 | c = shapefile.Reader('strati2.shp') 11 | 12 | def schema(reader): 13 | properties = dict((d[0],d[1:]) for d in reader.fields[1:]) 14 | return { 'type' : 'Feature', 15 | 'properties' : properties, 16 | 'geometry' : reader.shapes()[1].__geo_interface__['type']} 17 | 18 | # add a property to a class dynamically 19 | 20 | shapefile.Reader.schema = property(lambda self: schema(self)) 21 | c.schema 22 | {'geometry': 'Point', 'type': 'Feature', 'properties': {'DIRECTION': ['N', 3, 0], 'PENDAGE': ['N', 2, 0], 'TYPE': ['C 23 | ', 10, 0]}} 24 | 25 | def schema2(reader): 26 | properties = dict((d[0],d[1:]) for d in reader.fields[1:]) 27 | return {'properties' : properties, 28 | 'geometry' : reader.shapes()[1].__geo_interface__['type']} 29 | 30 | shapefile.Reader.schema2 = property(lambda self: schema2(self)) 31 | c.schema2 32 | {'geometry': 'Point', 'properties': {'DIRECTION': ['N', 3, 0], 'PENDAGE': ['N', 2, 0], 'TYPE': ['C', 10, 0]}} 33 | 34 | 35 | -------------------------------------------------------------------------------- /mapnik_geointerface.py: -------------------------------------------------------------------------------- 1 | import mapnik 2 | 3 | # NOTE: works with >= Mapnik 2.3.x 4 | # Geo interface added in 2.3.0: https://github.com/mapnik/mapnik/issues/2009 5 | 6 | # Example 1: access the geometry from a feature 7 | context = mapnik.Context() 8 | feature = mapnik.Feature(context,1) 9 | feature.add_geometries_from_wkt('POINT (0 0)') 10 | print feature.__geo_interface__['geometry'] 11 | 12 | # Example 2: access the geometry directly from the mapnik.Path container 13 | # first, lets make a multipoint geometry by adding another WKT 14 | feature.add_geometries_from_wkt('POINT (1 1)') 15 | paths = feature.geometries() 16 | print paths.__geo_interface__ 17 | 18 | def print_featureset(fs): 19 | feat = fs.next() 20 | while (feat): 21 | print feat.__geo_interface__ 22 | try: 23 | feat = fs.next() 24 | except StopIteration: 25 | feat = None 26 | 27 | # Example 3: access via an inline Geo-CSV 28 | csv = ''' 29 | id,wkt 30 | 1,"POINT(0 0)" 31 | 2,"POINT(1 1)" 32 | ''' 33 | datasource = mapnik.Datasource(**{'type':'csv','inline':csv}) 34 | query = mapnik.Query(datasource.envelope()) 35 | fs = datasource.features(query) 36 | print_featureset(fs) 37 | 38 | 39 | # Example 3: access via a shapefile 40 | # uncomment and fix the path to point to a valid shapefile 41 | #datasource = mapnik.Datasource(**{'type':'shape','file':'some/path/to/shapefile.shp'}) 42 | #query = mapnik.Query(datasource.envelope()) 43 | #print_featureset(datasource.features(query)) 44 | -------------------------------------------------------------------------------- /QGIS_add_geo_interface.py: -------------------------------------------------------------------------------- 1 | # modified from Nathan Woodrow's [Adding __geo_interface__ to QGIS geometry and feature ](http://nathanw.net/2013/06/25/qgis-geo-interface/) 2 | # avoid the usage of eval. It is better to use json.loads() to parse JSON Data into dictionary. 3 | 4 | 5 | import json 6 | 7 | def mapping_feature(feature): 8 | geom = feature.geometry() 9 | properties = {} 10 | fields = [field.name() for field in feature.fields()] 11 | properties = dict(zip(fields, feature.attributes())) 12 | return { 'type' : 'Feature', 13 | 'properties' : properties, 14 | 'geometry' : geom.__geo_interface__} 15 | 16 | def mapping_geometry(geometry): 17 | geo = geometry.exportToGeoJSON() 18 | # not eval as Nathan Woodrow but json.loads() 19 | return json.loads(geo) 20 | 21 | QgsFeature.__geo_interface__ = property(lambda self: mapping_feature(self)) 22 | QgsGeometry.__geo_interface__ = property(lambda self: mapping_geometry(self)) 23 | 24 | layer = iface.activeLayer() 25 | f = layer.selectedFeatures()[0] 26 | f 27 | 28 | f.__geo_interface__ 29 | {'geometry': {u'type': u'Point', u'coordinates': [271066.032148, 154475.631377]}, 'type': 'Feature', 'properties': {u'DIRECTION': 145, u'PENDAGE': 55, u'TYPE': u'incl'}} 30 | 31 | dict((field.name(),{field.typeName():field.length()}) for field in layer.pendingFields() ) 32 | {u'DIRECTION': {u'Integer': 3}, u'PENDAGE': {u'Integer': 2}, u'TYPE': {u'String': 10}} 33 | # problème avec les real (10:2) exemple 34 | layer.type() 35 | 0 # = point 36 | -------------------------------------------------------------------------------- /pyshp_geojson.py: -------------------------------------------------------------------------------- 1 | # simple 2 | 3 | import shapefile 4 | 5 | # read the shapefile 6 | reader = shapefile.Reader("strati.shp") 7 | fields = reader.fields[1:] 8 | field_names = [field[0] for field in fields] 9 | buffer = [] 10 | for sr in reader.shapeRecords(): 11 | atr = dict(zip(field_names, sr.record)) 12 | geom = sr.shape.__geo_interface__ 13 | buffer.append(dict(type="Feature", geometry=geom, properties=atr)) 14 | 15 | # write the GeoJSON file 16 | from json import dumps 17 | geojson = open("pyshp-demo.json", "w") 18 | geojson.write(dumps({"type": "FeatureCollection","features": buffer}, indent=2) + "\n") 19 | geojson.close() 20 | 21 | 22 | # with coroutines 23 | 24 | from json import dumps 25 | 26 | def coroutine(func): 27 | def start(*args,**kwargs): 28 | cr = func(*args,**kwargs) 29 | cr.next() 30 | return cr 31 | return start 32 | 33 | def pipe(source, following): 34 | for elem in source: 35 | following.send(elem) 36 | following.close() 37 | 38 | @coroutine 39 | def writer(fileobj): 40 | buffer = [] 41 | try: 42 | while True: 43 | result = (yield) 44 | buffer.append(result) 45 | except GeneratorExit: 46 | fileobj.write(dumps({"type": "FeatureCollection","features": buffer}, indent=2) + "\n") 47 | fileobj.close() 48 | 49 | def records(filename): 50 | # generator 51 | reader = shapefile.Reader(filename) 52 | fields = reader.fields[1:] 53 | field_names = [field[0] for field in fields] 54 | for sr in reader.shapeRecords(): 55 | atr = dict(zip(field_names, sr.record)) 56 | geom = sr.shape.__geo_interface__ 57 | yield dict(type="Feature", geometry=geom, properties=atr) 58 | 59 | import shapefile 60 | a = records("strati.shp") 61 | pipe(a,writer(open("pyshp-demo.json", "w"))) 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /ogr_gml_to_geojson.py: -------------------------------------------------------------------------------- 1 | # my response to http://gis.stackexchange.com/questions/77974/how-to-convert-gml-to-geojson-using-python-and-ogr-with-geometry-transformation/77999#77999 2 | 3 | # geo_interface 4 | def records(file): 5 | # generator 6 | reader = ogr.Open(file) 7 | layer = reader.GetLayer() 8 | for i in range(layer.GetFeatureCount()): 9 | feature = layer.GetFeature(i) 10 | yield json.loads(feature.ExportToJson()) 11 | 12 | from osgeo import ogr 13 | elem = records('test.gml') 14 | features = [feat for feat in records("test.gml')] 15 | # creation of the dictionary 16 | my_layer = { 17 | "type": "FeatureCollection", 18 | "features": features} 19 | print my_layer 20 | {'type': 'FeatureCollection', 'features': [{u'geometry': {u'type': u'LineString', u'coordinates': [[-0.95694033573220805, -0.290284677254464], [-0.28378378378378399, 0.33648648648648599], [0.39729729729729701, -0.064864864864864993], [0.99324324324324298, 0.48648648648648701]]}, u'type': u'Feature', u'properties': {u'id': None, u'fid': u'essai.0'}, u'id': 0}, {u'geometry': {u'type': u'LineString', u'coordinates': [[0.51422274119435496, 0.55873852866636098], [0.41724639928901802, 0.392759789636073], [0.32586484633975898, 0.39648964894012401], [0.21583399687024199, 0.366650774507713], [0.219563856174294, 0.30324316633883902]]}, u'type': u'Feature', u'properties': {u'id': None, u'fid': u'essai.1'}, u'id': 1}, {u'geometry': {u'type': u'LineString', u'coordinates': [[-0.37907856212595797, -0.028714311721736999], [-0.22428940100782399, -0.19842291005607601], [-0.10679883293020501, -0.32523812639382399], [-0.034066576501201998, -0.19469305075202401], [0.018151453755517001, -0.142475020495305], [0.083423991576417, -0.20215276936012699]]}, u'type': u'Feature', u'properties': {u'id': None, u'fid': u'essai.2'}, u'id': 2}, {u'geometry': {u'type': u'LineString', u'coordinates': [[-0.58235589419676004, 0.37597542276784202], [-0.37534870282190602, 0.52143993562584701], [-0.23361404926795301, 0.467356975717101], [-0.047121084065381999, 0.40021950824417601], [0.075964272968313998, 0.493465990845461]]}, u'type': u'Feature', u'properties': {u'id': None, u'fid': u'essai.3'}, u'id': 3}]} 21 | 22 | import json 23 | # json features 24 | print json.dumps(my_layer) 25 | '{"type": "FeatureCollection",..... 26 | 27 | # write the GeoJSON file 28 | with open("test.geojson", "w") as outfile: 29 | json.dump(my_layer,outfile) 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Python Geo_interface applications 2 | ================================= 3 | 4 | The __geo_interface__ (GeoJSON-like) protocol was proposed by [Sean Gillies](https://gist.github.com/2217756) and can be used in Python with: 5 | 6 | * [**Shapely**](https://github.com/Toblerity/Shapely) 7 | * [**Fiona**](https://github.com/Toblerity/Fiona) 8 | * [**descartes**](https://bitbucket.org/sgillies/descartes/) 9 | * [**geojson**](https://github.com/sgillies/geojson) 10 | * [**osgeo.ogr**](http://www.gdal.org/ogr/classOGRGeometry.html#a28609fce6bd422b16182eab58ff4e812) 11 | * [**pygeoif**](https://github.com/cleder/pygeoif) 12 | * [**PySAL**](http://pythonhosted.org/PySAL/users/tutorials/shapely.html?highlight=geojson) 13 | * [**ArcPy**](http://gis.stackexchange.com/questions/10201/arcpy-geometry-geo-interface-and-asshape-function-loss) 14 | * [**Papyrus**](https://papyrus.readthedocs.org/en/master/creating_mapfish_views.html) 15 | * [**PyShp**](https://pypi.python.org/pypi/pyshp/1.1.7), implemented since version 1.1.7 by Christian Lederman (https://github.com/cleder/pyshp) 16 | * Karim Bahgat has created a tempory fork of PyShp that can write new shapes based on geoJSON: 17 | [**Pyshp-fork-speedup-and-geojson-write**](https://github.com/karimbahgat/Pyshp-fork-speedup-and-geojson-write) 18 | * [**QGIS**](http://www.qgis.org/) with the new API with [monkey patching]( http://nathanw.net/2013/06/25/qgis-geo-interface/) by Nathan Woodrow or with generators in [GeoJSON, nouveau lingua franca en géomatique ?](https://portailsig.org/content/geojson-nouveau-lingua-franca-en-geomatique.html) by Martin Laloux 19 | * [**mapnik**](http://mapnik.org/) implemented by Dane Springmeyer 20 | * [**rasterstats**](https://github.com/perrygeo/python-raster-stats) 21 | * [**SpatiaLite**](http://www.gaia-gis.it/gaia-sins/) implemented here 22 | * [**PostGIS**](http://postgis.net/) implemented here 23 | * [**GeoDjango**](https://docs.djangoproject.com/en/dev/ref/contrib/gis/geos/) 24 | * [**pygml**](https://pypi.org/project/pygml/) 25 | * [**geodaisy**](https://pypi.org/project/geodaisy/) 26 | 27 | 28 | 29 | Applications 30 | ------------- 31 | 32 | One big advantage of the protocol is its ability to quickly examine the contents of a shapefile as dictionaries: 33 | 34 | ### with Fiona: 35 | 36 | ```python 37 | 38 | >>> import fiona 39 | >>> f = fiona.open('point.shp') 40 | >>> f.next() 41 | {'geometry': {'type': 'Point', 'coordinates': (161821.09375, 79076.0703125)}, 'id': '0', 'properties': {u'DIP_DIR': 120, u'STRATI_TYP': 1, u'DIP': 30}} 42 | >>> f.next()['geometry']['coordinates'] 43 | (161485.09375, 79272.34375) 44 | >>> f.next()['properties']['DIP'] 45 | 55 46 | ``` 47 | 48 | ### with PyShp: 49 | 50 | ```python 51 | 52 | def records(filename): 53 | # generator 54 | reader = shapefile.Reader(filename) 55 | fields = reader.fields[1:] 56 | field_names = [field[0] for field in fields] 57 | for sr in reader.shapeRecords(): 58 | geom = sr.shape.__geo_interface__ 59 | atr = dict(zip(field_names, sr.record)) 60 | yield dict(geometry=geom,properties=atr) 61 | 62 | 63 | >>> import shapefile 64 | >>> a = records('point.shp') 65 | >>> a.next() 66 | {'geometry': {'type': 'Point', 'coordinates': (161821.09375, 79076.0703125)}, 'properties': {'DIP_DIR': 120, 'STRATI_TYP': 1, 'DIP': 30}} 67 | >>> a.next()['geometry']['coordinates'] 68 | (161485.09375, 79272.34375) 69 | >>> a.next()['properties']['DIP'] 70 | 55 71 | 72 | ``` 73 | 74 | ### with osgeo.ogr 75 | 76 | ```python 77 | 78 | def records(file): 79 | # generator 80 | reader = ogr.Open(file) 81 | layer = reader.GetLayer(0) 82 | for i in range(layer.GetFeatureCount()): 83 | feature = layer.GetFeature(i) 84 | yield json.loads(feature.ExportToJson()) 85 | 86 | >>> from osgeo import ogr 87 | >>> a = records('point.shp') 88 | >>> a.next() 89 | {'geometry': {'type': 'Point', 'coordinates': (161821.09375, 79076.0703125)}, 'properties': {'DIP_DIR': 120, 'STRATI_TYP': 1, 'DIP': 30}} 90 | ``` 91 | 92 | ### with PyQGIS API2: 93 | 94 | ```python 95 | 96 | layer = qgis.utils.iface.activeLayer() 97 | def records(layer): 98 | fields = layer.pendingFields() 99 | field_names = [field.name() for field in fields] 100 | for elem in layer.getFeatures(): 101 | geom= elem.geometry() 102 | atr = dict(zip(field_names, elem.attributes())) 103 | yield dict(geometry=geom.exportToGeoJSON(),properties=atr) 104 | 105 | c = records(layer) 106 | c.next() 107 | {'geometry': {'type': 'Point', 'coordinates': (161821.09375, 79076.0703125)}, 'id': '0', 'properties': {u'DIP_DIR': 120, u'STRATI_TYP': 1, u'DIP': 30}} 108 | ``` 109 | 110 | ### conversion to shapely or pygeoif geometry 111 | 112 | with **shapely** (Sean Gillies, as with **pygeoif** of Christian Lederman): 113 | 114 | ```python 115 | 116 | >>> from shapely.geometry import shape 117 | >>> a = records('point.shp') 118 | >>> print shape( a.next()['geometry']) 119 | POINT (161821.09375 79076.0703125) 120 | ``` 121 | --------------------------------------------------------------------------------