Search code examples
pythonjupytergeopandaskepler.gl

Kepler maps do not work when importing two geometry columns


I can extend this question to show a working example but I think it's a bug, not a coding error.

I've got two separate sources of data that are joined using sjoin. This returns points from df1 that are within a polygon outlined in df2.

I want to import the merged dataset using Kepler and display both the points and the polygon.

If I don't differentiate the geometry columns, the polygon coordinates get removed after the merge. On the other hand, if I rename the geometry column from df2 before the merge, it returns a type error.

For reference, I've plotted the polygon from df2 using Kepler (without df1) and it works fine.

Option 1 (removes polygon coordinates):

df1 = gpd.read_file('data1.shp')
df2 = gpd.read_file('data2.shp')

df1 = df1(epsg = 4326)
df2 = df1(epsg = 4326)

merge = gpd.sjoin(df1, df2, predicate = 'within', how = 'inner')

map1 = KeplerGl(height = 600)
map1.add_data(merge)
map1

Output: geometry column from df2 is lost. So cannot plot the polygon

Option 2 (TypeError):

df1 = gpd.read_file('data1.shp')
df2 = gpd.read_file('data2.shp')

df1 = df1(epsg = 4326)
df2 = df1(epsg = 4326)

df2['geomsaved'] = df2.geometry


merge = gpd.sjoin(df1, df2, predicate = 'within', how = 'inner')

map1 = KeplerGl(height = 600)
map1.add_data(merge)
map1

Solution

    • I'm finding kepplergl a painful library to work with...
    • your error is expected and is not a bug. Specifically geopandas only supports one geometry column
    • what does this mean? kepplergl will be using __geo_interface__ to generate geojson from the GeoDataFrame that is then serialised to a string to pass to JavaScript code of kepplergl. This fails as the second column is a Series of complex objects that is not converted to geojson. This I have replicated below, same error in a simple MWE
    • how to manage this?
      1. create two layers in kepplergl one is polygons other is points
      2. concatenate geometries to long GeoDataFrame and create one layer
    import pandas as pd
    import geopandas as gpd
    import json
    
    world = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres")).sample(10)
    cities = gpd.read_file(gpd.datasets.get_path("naturalearth_cities"))
    
    # does not fail
    json.dumps(cities.sjoin(world).__geo_interface__)
    # fails: TypeError: Object of type Polygon is not JSON serializable
    json.dumps(cities.sjoin(world.assign(poly=lambda d: d["geometry"])).__geo_interface__)