3

I have an example GeoDataFrame:

import geopandas as gpd
import shapely.geometry

s = gpd.GeoSeries([shapely.geometry.Point([10,60])])
gdf = gpd.GeoDataFrame.from_dict(dict(geometry=s, col0=['val0']))

I would like to write the GeoDataFrame into a GeoJSON file with integer feature ids. Preferably, without leaving Python. Below I outline a few ways of achieving this, but none of them are ideal.

Pure GeoPandas

I can use to_file() to write it to a GeoJSON file.

gdf.to_file("example.geojson")

Leads to:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "col0": "val0"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [
          10.0,
          60.0
        ]
      }
    }
  ]
}

There is no feature id. To get feature id, I do:

with open("with_featureid.geojson","w") as f:
    f.write(gdf.to_json())

Result:

{
  "type": "FeatureCollection",
  "features": [
    {
      "id": "0",
      "type": "Feature",
      "properties": {
        "col0": "val0"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [
          10.0,
          60.0
        ]
      }
    }
  ]
}

There is a feature id, but it is not integer.

ogr2ogr

I can convert with_featureid.geojson to integer using ogr2ogr:

ogr2ogr ids_are_ints.geojson example.geojson -lco ID_TYPE="Integer"

Result:

{
  "type": "FeatureCollection",
  "name": "example",
  "features": [
    {
      "type": "Feature",
      "id": 0,
      "properties": {
        "col0": "val0"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [
          10.0,
          60.0
        ]
      }
    }
  ]
}

The feature id is nicely an integer. Disadvantage of this method: writing to a GeoJSON file and then processing that with ogr2ogr takes a lot of time when the files are big. Besides, sometimes it is not convenient to call ogr2ogr from within a Python script.

Manual modification of each feature

Alternatively, I can get to almost the same result using Python only:

import json

jsondict = gdf.__geo_interface__
for each in jsondict['features']:
    each['id'] = int(each['id'])
    del each['bbox']
    
del jsondict['bbox']
    
with open("ids_are_ints2.geojson","w") as f:
    json.dump(jsondict,f)

Result:

{
  "type": "FeatureCollection",
  "features": [
    {
      "id": 0,
      "type": "Feature",
      "properties": {
        "col0": "val0"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [
          10.0,
          60.0
        ]
      }
    }
  ]
}

Feature id is integer again. Disadvantage: I had to loop through all of the features before I can even begin writing the file.

Question

How can I write a GeoDataFrame to a GeoJSON file with integer feature ids, without encountering the disadvantages outlined above?

1

1 Answer 1

5

It is a bit of a search in the documentation to find it, but you can pass GDAL layer creation options as parameters in to_file. From the geopandas documentation:

**kwargs: 
    Keyword args to be passed to the engine, and can be used to 
    write to multi-layer data, store data within archives (zip files), 
    etc. In case of the “fiona” engine, the keyword arguments are 
    passed to fiona.open`. For more information on possible keywords, 
    type: import fiona; help(fiona.open). In case of the “pyogrio” 
    engine, the keyword arguments are passed to pyogrio.write_dataframe

Next, e.g. in the pyogrio.write_dataframe documentation, you can read on:

**kwargs
    Additional driver-specific dataset or layer creation options 
    passed to OGR. pyogrio will attempt to automatically pass those 
    keywords either as dataset or as layer creation option based on the 
    known options for the specific driver. Alternatively, you can use 
    the explicit dataset_options or layer_options keywords to manually 
    do this (for example if an option exists as both dataset and layer 
    option).

So e.g. this will do the trick (will work without engine="pyogrio" as well, but pyogrio is a lot faster):

import geopandas as gpd
import shapely.geometry

s = gpd.GeoSeries([shapely.geometry.Point([10, 60])])
gdf = gpd.GeoDataFrame.from_dict(dict(geometry=s, col0=["val0"]))
gdf.to_file("example.geojson", engine="pyogrio", id_generate=True)
1
  • 1
    Just for information as you mentioned it in the question. You can call ogr2ogr directly in python as well using gdal.VectorTranslate
    – Pieter
    Nov 30, 2023 at 13:57

Your Answer

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

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