pythondeck.glpydeck

Proper syntax for a pydeck PathLayer from a shapely geometry


I see the example of a PathLayer and it shows the input data is a list of lists within a regular pandas df, as opposed to a geopandas df.

Let's say I'm coming from a GeoPandas df (let's say called consline) that has a shapely MULTILINESTRING geometry column. What's the proper/best syntax to use that? I tried different combinations between calling it a PathLayer and a GeoJsonLayer with using the get_path parameter and nothing seemed to work except for doing json.loads(consline.geometry.to_json())['features'][0]['geometry']['coordinates']

The consline can be loaded as

consline=gpd.read_file("https://github.com/deanm0000/SOexamples/raw/main/consline.gpkg")

For instance, this doesn't work:

mylayers=[
    pdk.Layer(
        'PathLayer',
        data=consline,
        get_path="geometry",
        pickable=True,
        get_fill_color=[0,255,0],
        width_scale=20,
        width_min_pixels=2,   
    )
]
view_state = pdk.ViewState(
    longitude=-98.99,
    latitude=31.79,
    zoom=5,
    min_zoom=1,
    max_zoom=15)
r = pdk.Deck(layers=mylayers, initial_view_state=view_state, map_style='light')
r.to_html("example.html")

but this does:

mylayers=[
    pdk.Layer(
    'PathLayer',
    data=json.loads(consline.geometry.to_json())['features'][0]['geometry']['coordinates'],
    get_path="-",
    pickable=True,
    get_fill_color=[0,255,0],
    width_scale=20,
    width_min_pixels=2,
)
]
view_state = pdk.ViewState(
    longitude=-98.99,
    latitude=31.79,
    zoom=5,
    min_zoom=1,
    max_zoom=15)
r = pdk.Deck(layers=mylayers, initial_view_state=view_state, map_style='light')
r.to_html("example.html")

I can't imagine having shapely convert it to json and then python to convert it to a dict and then have pydeck convert it back to json for deck.gl is the best way to do this but I can't get it to work any other way.


Solution

  • You can set data to an object having the shape described for the deck.gl PathLayer.

    Using shapely, you can merge the MULTILINESTRING to a LINESTRING. Then pass along its coordinates.

    With default get_path option set to d => d.path

    import shapely as shp
    
    consline_geoseries = consline.geometry.iloc[0]
    consline_linestring = shp.ops.linemerge(consline_geoseries)
    data = [{'path': list(consline_linestring.coords)}]
    
    mylayers=[
        pdk.Layer(
            'PathLayer',
            data=data,
            pickable=True,
            get_fill_color=[0,255,0],
            width_scale=20,
            width_min_pixels=2,   
        )
    ]
    

    With default get_path set to -

    import shapely as shp
    
    consline_multilinestring = consline.geometry.iloc[0]
    consline_linestring = shp.ops.linemerge(consline_multilinestring)
    data = [list(consline_linestring.coords)]
    
    mylayers=[
        pdk.Layer(
            'PathLayer',
            data=data,
            get_path='-',
            pickable=True,
            get_fill_color=[0,255,0],
            width_scale=20,
            width_min_pixels=2,   
        )
    ]
    

    If you don't want to use shapely, you can pass the MULTILINESTRING as a data list of LINESTRING.

    consline_multilinestring = consline.geometry[0]
    mylayers=[
        pdk.Layer(
            'PathLayer',
            data=[list(geom.coords) for geom in consline_multilinestring.geoms],
            get_path="-",
            pickable=True,
            get_fill_color=[0,255,0],
            width_scale=20,
            width_min_pixels=2,   
        )
    ]