9

I have a GeoDataFrame whose a column is list-type.

import geopandas as gpd

gdf = gpd.GeoDataFrame({'list': [[0,1]]}, geometry=[Point(0, 0)])
print(gdf)

# OUT:
#      list                 geometry
# 0  [0, 1]  POINT (0.00000 0.00000)

When I try to save it as GeoPackage/SQLite/GeoJSON using the following lines, it arises ValueError: Invalid field type <class 'list'>.

gdf.to_file("c:/path/to/output.gpkg", driver='GPKG')
gdf.to_file("c:/path/to/output.geojson", driver='GeoJSON')
gdf.to_file("c:/path/to/output.sqlite", driver='SQLite')

But interestingly, I can add a list-type fields to SQLite and GeoJSON files in QGIS.

How can I save a GeoDataFrame containing list-type column while keeping the list (without converting it to string)?

1

1 Answer 1

7

Indeed, I will encounter the same ValueError error after trying your code:

  ...
  File "fiona\\ogrext.pyx", line 1409, in fiona.ogrext.WritingSession.writerecs
  File "fiona\\ogrext.pyx", line 514, in fiona.ogrext.OGRFeatureBuilder.build
ValueError: Invalid field type <class 'list'>

It is happening because Fiona does not support fields with dict or list when exporting a GeoDataFrame in a geodata format. You can find more information in this thread: invalid field type <class 'list'> while writing a file.

Luckily, there are workarounds, that can protect your list field.

Approach 1 : the to_parquet() method

It will export GeoDataFrame to a GeoParquet file format. Since GeoPandas 0.8 version.

# imports
import geopandas as gpd
from shapely.geometry import Point

# creating a GeoDataFrame
gdf = gpd.GeoDataFrame({'list': [[0,1]]}, geometry=[Point(29.01054793, 41.05223318)])
gdf = gdf.set_crs(4326, allow_override=True)

# exporting GeoDataFrame to a GeoParquet
gdf.to_parquet("c:/path/to/output.parquet")

After one can properly import this 'output.parquet' into e.g. QGIS, see the image below:

result_1

If you check the types of the fields in QGIS, for the 'output.parquet' file:

# imports
from qgis.utils import iface
from qgis.core import QgsVariantUtils

# accessing the active layer
layer = iface.activeLayer()

# getting field's name and type in readable format
for field in layer.fields():
    print(field.name(), ':' , QgsVariantUtils.typeToDisplayString(field.type()))

you will see:

list : List

One will be convinced, that the field "list" possesses the QVariant.List type.

Approach 2 : the to_json() method

One can easily convert GeoDataFrame to a JSON, that can be later exported as a GeoJSON.

# imports
import geopandas as gpd
from shapely.geometry import Point

# creating a GeoDataFrame
gdf = gpd.GeoDataFrame({'list': [[0,1]]}, geometry=[Point(29.01054793, 41.05223318)])
gdf = gdf.set_crs(4326, allow_override=True)

# converting GeoDataFrame to a JSON
data = gdf.to_json()

# writing JSON data structure to a GeoJSON file
with open("c:/path/to/output.geojson", 'w', encoding='utf-8') as file:
    file.write(data)

If one does not need the automatically created "id" field, use the conversion like: data = gdf.to_json(drop_id=True)

Hereafter one can properly import this 'output.geojson' into e.g. QGIS, see the image below:

result_2

If you check the types of the fields in QGIS, for the 'output.geojson' file:

# imports
from qgis.utils import iface
from qgis.core import QgsVariantUtils

# accessing the active layer
layer = iface.activeLayer()

# getting fields names and types in readable format
for field in layer.fields():
    print(field.name(), ':' , QgsVariantUtils.typeToDisplayString(field.type()))

you will see:

id : Text (string)
list : List

One will be again convinced, that the field "list" possesses the QVariant.List type.


References:

0

This site is temporarily in read-only mode and not accepting new answers.

Not the answer you're looking for? Browse other questions tagged .