marker icon on plotly scattermapbox not updating

Solution 1:

  • reference this answer How to create a symbol/button on a Plotly choropleth map for some of the explanation. Simply maki icons do not work as markers in plotly mapbox
  • have taken approach of sourcing SVG for marker from maki or font-awesome then convert it to geojson
  • for purpose of this have sourced UK hospitals and used a black marker
  • IMHO it's worth still using circle markers if you want hover info. You won't get any from layout / layers
import geopandas as gpd
import pandas as pd
import requests, io
import plotly.graph_objects as go
import shapely.geometry
import svgpath2mpl
import numpy as np

# create shapely multi-polygon from maki or font-awesome SVG path
def marker(name="star", source="fa"):
    def to_shapely(mpl, simplify=0):
        p = shapely.geometry.MultiPolygon(
            [shapely.geometry.Polygon(a).simplify(simplify) for a in mpl]
        )
        p = shapely.affinity.affine_transform(
            p,
            [1, 0, 0, -1, 0, 0],
        )
        scale = 1 if source == "maki" else 10 ** -2
        p = shapely.affinity.affine_transform(
            p,
            [1, 0, 0, 1, -p.centroid.x, -p.centroid.y],
        )
        return shapely.affinity.affine_transform(
            p,
            [scale, 0, 0, scale, -p.centroid.x, -p.centroid.y],
        )

    if source == "maki":
        url = f"https://raw.githubusercontent.com/mapbox/maki/main/icons/{name}.svg"
    elif source == "fa":
        url = f"https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/svgs/{name}.svg"
    svgpath = pd.read_xml(requests.get(url).text).loc[0, "d"]
    return to_shapely(svgpath2mpl.parse_path(svgpath).to_polygons())


# create mapbox layers for markers.  icon defines layer and color
def marker_mapbox(
    df,
    size=0.01,
    color="blue",
    lat="lat",
    lon="lon",
):
    layers = []
    m = marker("marker", "maki")
    geoms = [
        shapely.affinity.affine_transform(m, [size, 0, 0, size, r[lon], r[lat]])
        for _, r in df.iterrows()
    ]
    layers.append(
        {
            "source": gpd.GeoSeries(geoms).__geo_interface__,
            "type": "fill",
            "color": color,
        }
    )

    return layers


df = pd.read_csv(
    io.StringIO(requests.get("https://assets.nhs.uk/data/foi/Hospital.csv").text),
    sep="Č",
    engine="python",
).rename(columns={"Latitude": "Lat", "Longitude": "Long"})
df = df.sample(50)
cd_cols = ["SubType", "Sector"]


data = []
data.append(
    {
        "type": "scattermapbox",
        "lat": df["Lat"],
        "lon": df["Long"],
        "name": "Location",
        # "hovertext": rent,
        "showlegend": False,
        "hoverinfo": "text",
        "mode": "markers",
        "customdata": df.loc[:, cd_cols].values,
        # "marker": {
        #     "symbol": "marker",
        #     # "size": 18,
        #     "opacity": 0.8,
        #     # "color": "black"
        # },
    }
)

fig = go.Figure(data).update_layout(
    mapbox={
        "style": "carto-positron",
        "center": df.sample(1)
        .loc[:, ["Lat", "Long"]]
        .rename(columns={"Lat": "lat", "Long": "lon"})
        .to_dict("records")[0],
        "zoom": 4,
    },
    margin={"t": 0, "b": 0, "l": 0, "r": 0},
)

# add the markers as geojson layer...
fig.update_layout(
    mapbox={
        "layers": marker_mapbox(df, size=0.05, lat="Lat", lon="Long", color="black")
    }
)

enter image description here