Search code examples
pythonplotlymapbox

mapbox how can I add a label to a linestring in python?


This is a function that takes in coordinates and draw a circle and a line on a map. But I would like to add label to the line indicated the radius of the circle, like 1000m in this case.

Like this http://jsfiddle.net/brianssheldon/wm18a33d/27/ But this is javascript. Can I do this in python?

def func(lat, lon):

    df = pd.DataFrame(
        {'lat': [lat],
        'lon': [lon]})
    gdf = gpd.GeoDataFrame(
        df, geometry=gpd.points_from_xy(df.lon, df.lat))

    fig = px.scatter_mapbox(
        gdf, lat="lat", lon="lon"
    ).update_layout(mapbox={"style": "open-street-map"})

    gdf_ = gpd.GeoDataFrame(
        gdf, geometry=gpd.points_from_xy(gdf.lon, gdf.lat))
    gdf_.set_crs(epsg=4386, inplace=True)

    utm = gdf_.estimate_utm_crs()
    gdf_ = gdf_.to_crs(utm)
    b = 1000
    m = b // 10
    p = gdf_.centroid.values[0]
    arrow = LineString(
        [p, (p.x + b, p.y), (p.x + b - m, p.y - m), (p.x + b - m, p.y + m), (p.x + b, p.y)]
    )


    def geojson(shape, utm):
        return gpd.GeoSeries([shape], crs=utm).to_crs("epsg:4386").__geo_interface__

    # add circle geometry as layer to mapbox figure
    fig.update_layout(
        mapbox={
            "layers": [
                {
                    "source": geojson(p.buffer(b), utm),
                    "color": "PaleTurquoise",
                    "type": "fill",
                    "opacity": 0.5,
                },
                {
                    "source": geojson(p.buffer(m), utm),
                    "color": "red",
                    "type": "fill",
                    "opacity": 0.5,
                },
                {
                    "source": geojson(arrow, utm),
                    "color": "blue",
                    "type": "line",
                    "opacity": 0.5,
                    "title": 'aaa',
                },
            ]
        }
    )
    return fig

Solution

    • this is all documented here: layout mapbox
    • it suffers same issues as text parameter to px.scattermapbox(). Have to use a mapbox token and a mapbox style
    import plotly.express as px
    import geopandas as gpd
    import numpy as np
    import pandas as pd
    from shapely.geometry import LineString
    
    accessToken = "pk.eyJ1Ijoib2tpZWJ1YmJhIiwiYSI6ImNpdHZscGs3ajAwNXYyb284bW4ydWUzbGsifQ.1PoNrSP0F65WolWgqKhV4g"
    style = "mapbox://styles/mapbox/streets-v9"
    df = px.data.election()
    
    # prep geometry
    gdf = gpd.GeoDataFrame.from_features(px.data.election_geojson())
    gdf = gdf.join(
        gdf["geometry"].centroid.apply(lambda g: pd.Series({"lon": g.x, "lat": g.y}))
    )
    
    # plot circles at various lat / lon
    fig = px.scatter_mapbox(
        df.merge(gdf, on="district"), lat="lat", lon="lon", size="total"
    )
    fig.update_layout(mapbox={"style": style, "accesstoken": accessToken})
    # fig.update_layout(mapbox_style="carto-positron")
    
    gdf_ = gdf.set_crs("epsg:4326").sample(1)
    utm = gdf_.estimate_utm_crs()
    gdf_ = gdf_.to_crs(utm)
    b = 10000
    m = b // 10
    p = gdf_.centroid.values[0]
    arrow = LineString(
        [p, (p.x + b, p.y), (p.x + b - m, p.y - m), (p.x + b - m, p.y + m), (p.x + b, p.y)]
    )
    
    
    def geojson(shape, utm, label=None):
        gdf_ = gpd.GeoDataFrame(geometry=[shape], crs=utm).to_crs("epsg:4386")
        if label:
            gdf_ = gdf_.assign(label=label)
        return gdf_.__geo_interface__
    
    
    # add circle geometry as layer to mapbox figure
    fig.update_layout(
        mapbox={
            "layers": [
                {
                    "source": geojson(p.buffer(b), utm),
                    "color": "PaleTurquoise",
                    "type": "fill",
                    "opacity": 0.5,
                },
                {
                    "source": geojson(p.buffer(m), utm),
                    "color": "red",
                    "type": "fill",
                    "opacity": 0.5,
                },
                {
                    "source": geojson(arrow, utm),
                    "color": "blue",
                    "type": "line",
                    "opacity": 0.5,
                },
                {
                    "source": geojson(LineString([p, (p.x + b, p.y)]), utm, label="1000m"),
                    "type": "symbol",
                    "symbol": {
                        "text": "{label}",
                        "textfont": {"size": 12},
                        "placement": "line-center",
                    },
                },
            ]
        }
    )
    

    enter image description here