4

I currently have the following code to write a multipolygon Shapely feature to a GeoPackage:

import fiona

myschema = {'geometry': 'MultiPolygon', 'properties': {'id': 'int'}}

with fiona.open(
    '/path/to/file.gpkg',
    mode='w',
    driver='GPKG',
    schema=myschema,
    crs='EPSG:2056') as m:
 m.write({
    'geometry': geometry.mapping(shapely_multipolygon_instance),
    'properties': {'id': 12},# I can specify properties here time of writing
})

When I open this file in QGIS for example, I can see 2 fields in the attribute table: fid, which is 1 and id which is the value I specified, i.e. 12 in that case.

As fiona seems now embedded in the to_file() method of a GeoDataFrame, I try to directly write my file as follow, but I don't know how could I pass the properties:

import geopandas as gpd

G = gpd.GeoDataFrame(
    shapely_multipolyong_instance,
    columns=['geometry']).dissolve() # to a unique multipoly

G.set_geometry('geometry', inplace=True, crs='EPSG:2056')

# I removed the 'geometry' from 'myschema' as we're now dealing with a gdf:
myschema = {'properties': {'id': 'int'}} 

G.to_file(
    '/path/to/file.gpkg',
    driver="GPKG",
    schema=myschema # when I remove that the file is correctly written but...
)

I get this error message:

Traceback (most recent call last):

  File "<ipython-input-142-8bd51132bd01>", line 10, in <module>
    schema=myschema

  File "/usr/local/lib/python3.6/dist-packages/geopandas/geodataframe.py", line 1086, in to_file
    _to_file(self, filename, driver, schema, index, **kwargs)

  File "/usr/local/lib/python3.6/dist-packages/geopandas/io/file.py", line 330, in _to_file
    colxn.writerecords(df.iterfeatures())

  File "/usr/local/lib/python3.6/dist-packages/fiona/collection.py", line 361, in writerecords
    self.session.writerecs(records, self)

  File "fiona/ogrext.pyx", line 1280, in fiona.ogrext.WritingSession.writerecs

ValueError: Record does not match collection schema: dict_keys([]) != ['id']

And if I simply remove the last schema=myschema line, the file is correctly written, but it has only one field in the attribute table, namely the fid which is 1. The exact same thing happens when I remove the schema=myschema line but add instead properties={'id': 12}. And if I put both, I end up on the same error as before.

So...
I probably don't understand correctly how to interpret this sentence in the doc:

The extra keyword arguments **kwargs are passed to fiona.open and can be used to write to multi-layer data, store data within archives (zip files), etc.

Therefore, how could I also set my id and its value in the attribute table of the written GeoPackage file?

This is the help of the method (if he could include an example using a schema, it would be helpful I think):

$ help(G.to_file)

Help on method to_file in module geopandas.geodataframe:

to_file(filename, driver='ESRI Shapefile', schema=None, index=None, **kwargs)
    method of geopandas.geodataframe.GeoDataFrame instance
    Write the ``GeoDataFrame`` to a file.
    
    By default, an ESRI shapefile is written, but any OGR data source
    supported by Fiona can be written. A dictionary of supported OGR
    providers is available via:
    
import fiona
fiona.supported_drivers  # doctest: +SKIP
    
    Parameters
    ----------
    filename : string
        File path or file handle to write to.
    driver : string, default: 'ESRI Shapefile'
        The OGR format driver used to write the vector file.
    schema : dict, default: None
        If specified, the schema dictionary is passed to Fiona to
        better control how the file is written.
    index : bool, default None
        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.
    
        .. versionadded:: 0.7
            Previously the index was not written.
    
    Notes
    -----
    The extra keyword arguments ``**kwargs`` are passed to fiona.open and
    can be used to write to multi-layer data, store data within archives
    (zip files), etc.
    
    The format drivers will attempt to detect the encoding of your data, but
    may fail. In this case, the proper encoding can be specified explicitly
    by using the encoding keyword parameter, e.g. ``encoding='utf-8'``.
    
    See Also
    --------
    GeoSeries.to_file
    GeoDataFrame.to_postgis : write GeoDataFrame to PostGIS database
    GeoDataFrame.to_parquet : write GeoDataFrame to parquet
    GeoDataFrame.to_feather : write GeoDataFrame to feather
    
    Examples
    --------
    
gdf.to_file('dataframe.shp')  # doctest: +SKIP
    
gdf.to_file('dataframe.gpkg', driver='GPKG', layer='name')  # doctest: +SKIP
    
gdf.to_file('dataframe.geojson', driver='GeoJSON')  # doctest: +SKIP
    
    With selected drivers you can also append to a file with `mode="a"`:
    
gdf.to_file('dataframe.shp', mode="a")  # doctest: +SKIP

1 Answer 1

1

You need to pass the attribute data to the geodataframe instead of the schema:

from shapely.geometry import Polygon, MultiPolygon
import geopandas as gpd

polygon1 = Polygon([(0, 0), (0, 1), (1, 1), (1, 0)])
polygon2 = Polygon([(1, 1), (1, 2), (2, 2), (2, 1)])
multipolygon = MultiPolygon([polygon1, polygon2])

G = gpd.GeoDataFrame([[12, multipolygon]], columns=['id', 'geometry'])

myschema = {'geometry': 'MultiPolygon', 'properties': {'id': 'int'}}
G.to_file('/path/to/file.gpkg', schema=myschema)

You can also construct a GeoDataFrame like this:

G = gpd.GeoDataFrame({'id': [12], 'geometry': [multipolygon]})

.dissolve() makes sense when you like to merge single polygons having the same id to a multipolygon:

G = gpd.GeoDataFrame({'id': [12, 12], 'geometry': [polygon1, polygon2]}).dissolve()

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.