5

I create an example GeoJSON:

import shapely.wkt
import geopandas as gpd

s0 = shapely.wkt.loads("POINT(0 0)")
s1 = shapely.wkt.loads("POINT(1 1)")
gdf = gpd.GeoDataFrame({'geometry':[s0, s1],'data':['a','b']})

gdf.to_file("example.geojson")

Check it: cat example.geojson:

{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": { "data": "a" }, "geometry": { "type": "Point", "coordinates": [ 0.0, 0.0 ] } },
{ "type": "Feature", "properties": { "data": "b" }, "geometry": { "type": "Point", "coordinates": [ 1.0, 1.0 ] } }
]
}

I would like each feature to have an id. I achieve that via ogr2ogr & the ID_GENERATE layer creation option (see docs):

ogr2ogr example_withIDs.geojson example.geojson -lco ID_GENERATE="YES"

Check the result via cat example_withIDs.geojson:

{
"type": "FeatureCollection",
"name": "example",
"features": [
{ "type": "Feature", "id": 0, "properties": { "data": "a" }, "geometry": { "type": "Point", "coordinates": [ 0.0, 0.0 ] } },
{ "type": "Feature", "id": 1, "properties": { "data": "b" }, "geometry": { "type": "Point", "coordinates": [ 1.0, 1.0 ] } }
]
}

as expected. However, I would need all my ids to be positive.

How can I generate unique positive integers as ids for each feature using ogr2ogr?


Below I present attempts/clarifications, but no need to read them if one understands the question above.


Attempt 1

I tried to use the ID_FIELD layer creation option too:

ogr2ogr -sql "SELECT *, 12345 as generated_id FROM example" -dialect sqlite example_withIDs.geojson example.geojson -lco ID_FIELD='generated_id'

Check the result via cat example_withIDs.geojson:

{
"type": "FeatureCollection",
"name": "SELECT",
"features": [
{ "type": "Feature", "id": 12345, "properties": { "data": "a" }, "geometry": { "type": "Point", "coordinates": [ 0.0, 0.0 ] } },
{ "type": "Feature", "id": 12345, "properties": { "data": "b" }, "geometry": { "type": "Point", "coordinates": [ 1.0, 1.0 ] } }
]
}

All ids now are 12345. If I could somehow enumerate rows starting from 1, instead of having 12345 as generated_id in the SQL statement, that would probably work.


A note on ids

Generating an id or ID, or similar field to be a member of properties is not what I am trying to achieve. A feature in a GeoJSON file looks like this:

   {
       "type": "Feature",
       "id": 12345, // <- I am talking about this id
       "geometry": {...},
       "properties": { "id": 12345, "ID": 12345 } // <- not about these
   }

I am talking about the id above which is on the same level as type, geometry and properties. Not about one of the properties elements. This is in line with section 3.2 of the GeoJSON specification:

If a Feature has a commonly used identifier, that identifier SHOULD be included as a member of the Feature object with the name "id", and the value of this member is either a JSON string or a number.

This is a separate thing from properties, which is:

A Feature object has a member with the name "properties". The value of the properties member is an object (any JSON object or a JSON null value).

2 Answers 2

6

Using this answer to the question How to enumerate returned rows in SQL?, this seems to work:

ogr2ogr -sql "SELECT *, ROW_NUMBER() OVER() AS generated_id FROM example" \
        -dialect sqlite \
        example_withIDs.geojson example.geojson \
        -lco ID_FIELD='generated_id'

example_withIDs.geojson:

{
"type": "FeatureCollection",
"name": "SELECT",
"features": [
{ "type": "Feature", "id": 1, "properties": { "data": "a" }, "geometry": { "type": "Point", "coordinates": [ 0.0, 0.0 ] } },
{ "type": "Feature", "id": 2, "properties": { "data": "b" }, "geometry": { "type": "Point", "coordinates": [ 1.0, 1.0 ] } }
]
}
1
4

You can also achieve it with GeoPandas using the index=None: bool parameter

If True, write index into one or more columns (for MultiIndex). Default None writes the index into one or more columns only if the index is named, is a MultiIndex, or has a non-integer data type. If False, no index is written.

gdf.index += 1 
gdf.to_file("example.geojson", index=True)

It will result in:

{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": { "index": 1, "data": "a" }, "geometry": { "type": "Point", "coordinates": [ 0.0, 0.0 ] } },
{ "type": "Feature", "properties": { "index": 2, "data": "b" }, "geometry": { "type": "Point", "coordinates": [ 1.0, 1.0 ] } }
]
}

If you prefer having "id" instead of "index", then execute the following code:

gdf["id"] = gdf.index + 1
gdf.to_file("example.geojson")

then you end up with:

{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": { "data": "a", "id": 1 }, "geometry": { "type": "Point", "coordinates": [ 0.0, 0.0 ] } },
{ "type": "Feature", "properties": { "data": "b", "id": 2 }, "geometry": { "type": "Point", "coordinates": [ 1.0, 1.0 ] } }
]
}

And then you can simply rewrite your GeoJSON for example with this code:

import json

with open("example.geojson", "r") as jsonFile:
    data = json.load(jsonFile)

for record in data['features']:
    record['id'] = record['properties']['index'] #or record['properties']['id']
    del record['properties']['index'] #or record['properties']['id']

with open("example.geojson", "w") as jsonFile:
    json.dump(data, jsonFile)

to get this result:

{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": {"data": "a"}, "geometry": {"type": "Point", "coordinates": [0.0, 0.0]}, "id": 1},
{ "type": "Feature", "properties": {"data": "b"}, "geometry": {"type": "Point", "coordinates": [1.0, 1.0]}, "id": 2}
]
}

References:

4
  • In my real world application, it would be better not having to read in the whole GeoJSON using GeoPandas, and then again with json.load. If there is a way which yields the same result using no other tools than ogr2ogr, it would make my life easier. Nevertheless, this works, so thank you!
    – zabop
    Dec 13, 2022 at 12:12
  • Sorry I am not good at ogr2ogr
    – Taras
    Dec 13, 2022 at 12:19
  • I realize the question in the body asked How can I generate unique positive integers as ids for each feature? while only the post title asked for ogr2ogr: How to generate unique positive integers as ids with ogr2ogr?. I fixed this, now the question body also says: How can I generate unique positive integers as ids for each feature using ogr2ogr?. Sorry for not making this more clear earlier.
    – zabop
    Dec 13, 2022 at 12:20
  • No worries. I think your post is useful for many future readers, even though it does not fully solve my problem in particular.
    – zabop
    Dec 13, 2022 at 12:21

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.