Serialize GeoJSON in Python with rounded coordinates

Viewed 421

I'd like to serialize GeoJSON FeatureCollections in Python with limited precision for their coordinates.

For example, here's a FeatureCollection (represented as dicts and lists in Python):

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "name": "Liberty Island",
        "area_sqm": 24950.40123456,
        "established": 1875,
        "height_ft": 305
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [ -74.04715418815613, 40.690994683044906 ],
            [ -74.04499769210815, 40.68873311507798 ],
            [ -74.04354929924011, 40.689676800252016 ],
            [ -74.04715418815613, 40.690994683044906 ]
          ]
        ]
      }
    }
  ]
}

I can serialize it using json.dumps:

print(json.dumps(fc))

This prints out the JSON:

{"type": "FeatureCollection", "features": [{"type": "Feature", "properties": {"name": "Liberty Island", "area_sqm": 24950.40123456, "established": 1875, "height_ft": 305}, "geometry": {"type": "Polygon", "coordinates": [[[-74.04715418815613, 40.690994683044906], [-74.04499769210815, 40.68873311507798], [-74.04354929924011, 40.689676800252016], [-74.04715418815613, 40.690994683044906]]]}}]}

Those coordinates are far too precise. According to Wikipedia, 7 digits is ~cm precision, which ought to be good enough. What I'm getting is ~nanometer precision.

I'd like to serialize the GeoJSON FeatureCollection with only seven digits of precision for coordinates. Note that I'd like to use Python's default serialization for everything in properties: since the values there could be anything, I can't make any universal claims about how much precision is enough.

My desired output is something like:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "name": "Liberty Island",
        "area_sqm": 24950.40123456,
        "established": 1875,
        "height_ft": 305
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [ -74.0471541, 40.6909946 ],
            [ -74.0449976, 40.6887331 ],
            [ -74.0435492, 40.6896768 ],
            [ -74.0471541, 40.6909946 ]
          ]
        ]
      }
    }
  ]
}
1 Answers

I'm not sure what exact serialization you're after but when it comes to FeatureCollection simplification, this should get you started:

import json
from copy import copy


def simplify_geometries(feat_collection):
    new_coll = copy(feat_collection)
    old_features = new_coll['features']
    new_features = []

    for feature in old_features:
        geometry = feature['geometry']
        coords = shorten_arr(geometry['coordinates'])
        geometry['coordinates'] = coords

        new_features.append(feature)

    new_coll['features'] = new_features
    return json.dumps(new_coll)


print(simplify_geometries(
    json.loads('{"type": "FeatureCollection",...')
))

where shorten_arr is a trivial recursion:

def shorten_arr(arr, dec_places=7):
    if not isinstance(arr, list):
        return round(arr, dec_places)

    to_ret = []
    for n in arr:
        if isinstance(n, list):
            n = shorten_arr(n, dec_places)
        to_ret.append(shorten_arr(n, dec_places))
    return to_ret
Related