Simplifying MultiPolygon to Polygon (.geojson)

2 min read

Anyone who wants to map Choropleths, or color maps, need to have proper GIS shapefiles. They're simply collections of cooridnates of each boundary. Depending on the complexity of geography, they either contain MultiPolygon or Polygon.

MultiPolygon and Polygon geometry

As can be easily guessed, MultiPolygon is more complicated than its counterpart as it can encompass areas with holes inside into one name, while it's not allowed in Polygon type.

Then, we can just use MultiPolygon type geometry, right? Not really! Because of the added complexity, not every mapping tool can use MultiPolygon, notably, Pydeck (opens in a new tab). Therefore, it's imperative to have Polygon geomtry or convert into it.

Intuitions of effective conversions

As mentioned above, MultiPolyon geometry is a collection of multiple single Polygons. Intuitively, it seems that more important boundaries are made up of longer-length coordinates. Accordingly, if we limit the top largest-length Polygon coordinates, we can convert without increasing file size much (Because same header information are repeated for newly created Polygon geometries, file size should be larger). This filesize reduction process should be crucial as the mapping process depends on GIS shapefiles sizes.

Code for converting Multi to Single Polygon

import json
filename = 'data/cb_2018_us_cbsa_500k'
target_len = 15
 
js = open(filename+'.json', 'r').read()
gj = json.loads(js)
output = {"type":"FeatureCollection","features":[]}
 
def process_geojson(filename):
    js = open(filename+'.json', 'r').read()
    gj = json.loads(js)
    output = {"type":"FeatureCollection","features":[]}
 
    for feature in gj['features']:
        if feature['geometry'] is not None:
            if feature['geometry']['type'] == 'MultiPolygon':
                len_list = sorted([[idx, len(elem[0])] for idx, elem in enumerate(feature['geometry']['coordinates'])],key=lambda x: x[1],reverse=True)[:target_len]
                reg_len = [i[0] for i in len_list]
 
                for idx, poly in enumerate(feature['geometry']['coordinates']):
                    if len(feature['geometry']['coordinates'])<target_len or idx in reg_len:
                        xfeature = {"type":"Feature", "properties":feature["properties"], "geometry":{"type":"Polygon"}}
                        xfeature['geometry']['coordinates'] = poly
                        output['features'].append(xfeature)
            else:
                for idx, poly in enumerate(feature['geometry']['coordinates']):
                    xfeature = {"type":"Feature", "properties":feature["properties"], "geometry":feature["geometry"]}
                    output['features'].append(xfeature)
 
    open(filename+'.geojson', 'w').write(json.dumps(output,separators=(',',':'),ensure_ascii=False).replace('}},','}},\n'))
 
if __name__ == '__main__':
    process_geojson(filename)

Above is general-purpose MultiPolygon to Polygon conversion source made in Python. By general-purpose, I mean it doesn't manipulate any filesize reduction processes (e.g., removing unnecessary json tags) other than limiting the number of Polygon elements per MultiPolygon geometry.

Credits

Nick Doiron (opens in a new tab): Original tranformation source I came across via gis.stackexchange.com (opens in a new tab)

CC BY-NC 4.0 © min park.RSS