JavaScript Object Notation (JSON) is rapidly becoming the number one data exchange format across a lot of fields. The lightweight syntax and the similarity to existing data structures in both the JavaScript from which Python borrows some data structures makes it a perfect match for Python.
The following GeoJSON sample document contains a single point:
{ "type": "Feature", "id": "OpenLayers.Feature.Vector_314", "properties": {}, "geometry": { "type": "Point", "coordinates": [ 97.03125, 39.7265625 ] }, "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } } }
This sample is just a simple point with new attributes, which would be stored in the properties
data structure of the geometry. First, we'll compact the sample document into a single string to make it easier to handle:
>>> jsdata = """{ "type": "Feature", "id": "OpenLayers.Feature.Vector_314", "pro perties": {}, "geometry": { "type": "Point", "coordinates": [ 97.03125, 39.72656 25 ] }, "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1. 3:CRS84" } } }"""
GeoJSON looks very similar to a nested set of Python's dictionaries and lists. Just for fun, let's just try and use Python's eval()
function to parse it as Python code:
>>> point = eval(jsdata) >>> point["geometry"] {'type': 'Point', 'coordinates': [97.03125, 39.7265625]}
Wow! That just worked! We turned that random GeoJSON string into native Python data in one easy step. Keep in mind that the JSON data format is based on JavaScript syntax which happens to be similar to Python. Also, as you get deeper into GeoJSON data and work with larger data, you'll find that JSON allows characters that Python does not. Using Python's eval()
function is considered very insecure as well. But as far as keeping things simple is concerned, note that it doesn't get any simpler than that!
Thanks to Python's drive towards simplicity, the more advanced method doesn't get much more complicated. Let's use Python's json
module, which is part of the standard library, to turn the same string into Python the right way:
>>> import json >>> json.loads(jsdata) {u'geometry': {u'type': u'Point', u'coordinates': [97.03125, 39.7265625]}, u'crs ': {u'type': u'name', u'properties': {u'name': u'urn:ogc:def:crs:OGC:1.3:CRS84'} }, u'type': u'Feature', u'id': u'OpenLayers.Feature.Vector_314', u'properties': {}}
As a side note, in the previous example the CRS84
property is a synonym for the common WGS84 coordinate system. The json
module adds some nice features such as safer parsing and conversion of strings to Unicode. We can export Python data structures to JSON in almost the same way:
>>> pydata = json.loads(jsdata) >>> json.dumps(pydata) '{"geometry": {"type": "Point", "coordinates": [97.03125, 39.7265625]}, "crs": { "type": "name", "properties": {"name": "urn:ogc:def:crs:OGC:1.3:CRS84"}}, "type" : "Feature", "id": "OpenLayers.Feature.Vector_314", "properties": {}}'
We could happily go on reading and writing GeoJSON data using the json
module forever, but there's an even better way. The geojson
module available on PyPI offers some distinct advantages. For starters, it knows the requirements of the GeoJSON specification, which can save a lot of typing. Let's create a simple point using this module and export it to GeoJSON:
>>> import geojson >>> p = geojson.Point([-92, 37]) >>> geojs = geojson.dumps(p) >>> geojs '{"type": "Point", "coordinates": [-92, 37]}'
Notice that the geojson
module has an interface for different data types and saves us from setting the type
and coordinates
attributes manually. Now imagine if you had a geographic object with hundreds of features. You could programmatically build this data structure instead of building a very large string. The geojson
module is also the reference implementation for the Python __geo_interface__
convention. This interface allows cooperating programs to exchange data seamlessly and in a Pythonic way without the programmer explicitly exporting and importing GeoJSON strings. So, if we wanted to feed the point we created with the geojson
module to the Shapely module, we could perform the following command, which reads the geojson
module's point
object straight into Shapely after which we'll export it as WKT:
>>> from shapely.geometry import asShape >>> point = asShape(p) >>> point.wkt 'POINT (-92.0000000000000000 37.0000000000000000)'
More and more geospatial Python libraries are implementing both the geojson
and __geo_interface__
functionality including PyShp, Fiona, Karta, and ArcGIS. Third-party implementations exist for QGIS.