1

I have a GeoDataFrame with some of its attributes that are geometries (only the position is the one which was interpreted as the active geometry when loading the data from PostGIS):

import psycopg2
import geopandas as gpd
import json
# define a conn object for database retrieval
sql = 'SELECT id, position, buffer1, buffer2, buffer3 FROM table WHERE id = 11;'
gdf = gpd.read_postgis(sql, conn, geom_col='position')

Which leads to this resulting gdf:

Resulting gdf

I dump it as follow before returning this object (it's a function return value):

return json.loads(gdf.to_json())

It looks like this:

{
  "type": "FeatureCollection",
  "features": [
    {
      "id": "0",
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [8.54, 47.36, 490.6]
      },
      "properties": {
        "id": 1,
        "buffer1": {
          "type": "Polygon",
          "coordinates": [
            [ [8.5, 47.3],
              (...)
              [ 8.4, 47.4]
            ]
          ]
        },
        "buffer2": {
          "type": "MultiPolygon",
          "coordinates": [
            [ [
                [8.5, 47.4],
                (...)
                [ 8.5, 47.6]
            ] ]
          ]
        },
        "buffer3": {
          "type": "MultiPolygon",
          "coordinates": [
            [ [
                [8.2, 47.2],
                (...)
                [8.3, 47.7]
            ] ]
          ]
        }
      }
    }
  ]
}

Several points drew my attention from here:

  • First; the CRS is not dumped. I don't know why?! It is definitely in the GeoDataFrame because when I ask for gdf.CRS it prints all the details of a pyproj.crs.crs.CRS object.

  • Second point; all the other geometries are stored in the 'properties' entry. It apparently "decided" to build a FeatureCollection (out of one record from the database, which is strange, but I'll live with it...). I would have preferred to have these extra 'bufferX' geometries as actual Features inside that FeatureCollection instead of just as properties. In such a structure for example; https://openlayers.org/en/latest/examples/geojson.html?q=geojson. So it's a mess to bring them back to standard single GeoJSON object (it's possible but not clean).

  • Last point; the FeatureCollection got the id 0, and my id (11) is also stored in the properties. My wanted output would be like this:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [8.54, 47.36, 490.6]
      },
      "properties": {
        "id": 11,
        "name": "position"
      }
    },
    {
      "type": "Feature",
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [ [8.5, 47.3],
            [ 8.4, 47.4]
          ]
        ]
      },
      "properties": {
        "id": 11,
        "name": "buffer1"
      }
    },
    {
      "type": "Feature",
      "geometry": {
        "type": "MultiPolygon",
        "coordinates": [
          [ [
              [8.5, 47.4],
              [ 8.5, 47.6]
          ] ]
        ]
      },
      "properties": {
        "id": 11,
        "name": "buffer2"
      }
    },
    {
      "type": "Feature",
      "geometry": {
        "type": "MultiPolygon",
        "coordinates": [
          [ [
              [8.2, 47.2],
              [8.3, 47.7]
          ] ]
        ]
      },
      "properties": {
        "id": 11,
        "name": "buffer3"
      }
    }
  ]
}

My question is: from an initial GeoDataFrame which has several geometry columns, is there a simple way to construct a valid GeoJSON object which has a single FeatureCollection containing each of these geometries as child Features (with a name attribute corresponding to its original column name and an id corresponding to the id used to get the data from the PostGIS database) and not as currently properties of a FeatureCollection containing only the active geometry column as a Feature and all other geometries as simple 'properties'?

There isn't much options yet to the .to_json() method. :(

Useful link: https://jsonformatter.org/

1 Answer 1

0

I end up with this "complicated" function to prepare a GeoJSON with a FeatureCollection containing multiple Features out of a GeoDataFrame with multiple geometry columns:

def gdf2geojson(gdf):
    import geojson
    from shapely.geometry import mapping
    columns = list(gdf.columns)
    features = []
    for col in columns:
        if col != 'id':
             # active geometry is a Shapely geometry instance and
             # has to be processed separately
            if col == gdf.geometry.name:
                geom = geojson.loads(
                    json.dumps(
                        mapping(
                            gdf.iloc[0][gdf.geometry.name]
                        )
                    )
                )
            else:
                geom = geojson.loads(gdf.iloc[0][col])
            
            properties = {
                "id": int(gdf.iloc[0]['id']),
                "name": col
            }
            feature = geojson.Feature(geometry=geom, properties=properties)
            features.append(feature)
    
    featCollection = geojson.FeatureCollection(features)

    return geojson.dumps(featCollection)

It works, but I hope I just missed a method somewhere that would have made my life a little easier.

Disclaimer; and it works because the gdf has only geometry columns (!), otherwise it becomes mandatory to implement a test somewhere to redirect non-geometry attributes into the property field of the GeoJSON object instead of the geometry field.

4
  • GeoJSON feature can have only one geometry tools.ietf.org/html/rfc7946#page-6. Definitions of GeoJSON Text and GeoJSON Objects sets that limitation.
    – user30184
    Jan 23, 2021 at 21:07
  • Thx. But I've got FeatureCollection, or, as its name suggests, it's a collection of Features, like the geojsonObject presented here. Jan 23, 2021 at 21:32
  • Yes, GeoJSON object can be a collection of features. Each of those features can have only one geometry. In your case you can present your data either with one geometry that is of geometry type GeometryCollection. Or like in the original example with one geometry and addional geometries as properties. If you want a feature with many geometries you must use some other format, like GML.
    – user30184
    Jan 24, 2021 at 11:35
  • The previous comment gives the two possible ways to present the original feature that has many geometries as one GeoJSON feature. Your way to split data into several features is OK as well.
    – user30184
    Jan 24, 2021 at 15:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.