Search code examples
pythonplotlygeospatialplotly-dashopenstreetmap

Plotly mapbox layer not displaying image


I am trying to create a plotly scatter mapbox using open-street-map as well as an image which I want to overlay as a layer when a user zooms into the map.

Currently my code looks like the following:

import pandas as pd
import plotly.express as px
import os

dir_path = os.path.dirname(os.path.realpath(__file__))

map_file = dir_path + "\\map.png"

df_event = pd.Dataframe()#dataframe containing long and lattitude coordinates

fig = px.scatter_mapbox(df_event, lat="Latitude", lon="Longitude", zoom=10)
fig.update_layout(mapbox_style="open-street-map",
                    mapbox_layers=[
                        {
                            "sourcetype": "image",
                            "source": "file://"+map_file,
                            "coordinates": [[10.0025794227684, 53.6280250042934] [10.0016447071323, 53.6280250042934] [10.0016447071323, 53.6281356890004] [10.0025794227684, 53.6281356890004]]
                        }
                    ])
fig.show()

The plot displays all the observations fine on the map. But the png file i’m trying to overlay does not appear on the map despite this.


Solution

  • If you want to add local images to the map, you will need to encode them with base64, I have used the example answers from the plotly community and adapted the code from the reference to fit your question. Since it is unclear what kind of map you want to overlay, I used the locally saved Montreal traffic congestion map from here to match the reference. I used a graph object and used the free API key for the map box. For more information on the Mapbox API, see here. The bottom layer is the openstreetmap and the second layer is the congestion information image. The top level is a scatterplot. The order of the layers is controlled by the below="traces" parameter. The display range of the layers is manually adjusted based on the maximum and minimum latitude and longitude of the data frame. This is not exact. If you know the latitude and longitude of the map you want to overlay, replace it with it.

    import plotly.graph_objects as go
    import plotly.express as px
    
    mapbox_access_token = open("mapbox_api_key.txt").read()
    df = px.data.carshare()
    
    # add map layer
    map_filename = './data/montreal_road_map.png'
    montreal_road_map = base64.b64encode(open(map_filename, 'rb').read())
    
    fig = go.Figure()#go.Scattermapbox()
    
    fig.add_trace(go.Scattermapbox(
        lat=df['centroid_lat'],
        lon=df['centroid_lon'],
        mode='markers',
        marker=go.scattermapbox.Marker(
            size=10,
            color=df['peak_hour'],
        ),
    ))
    
    fig.update_layout(mapbox_style="open-street-map",
                      mapbox_accesstoken=mapbox_access_token,
                      mapbox_center=dict(lat=df.centroid_lat.mean(), lon=df.centroid_lon.mean()),
                      mapbox_zoom=10,
                      mapbox_layers=[{
                          "sourcetype": "image",
                          "opacity": 1.0,
                          "below": "traces", 
                          "source": 'data:image/png;base64,{}'.format(montreal_road_map.decode('utf-8')),
                          "coordinates": 
                          [[-73.73894559925054-0.03, 45.61087892678886+0.015],
                           [-73.5124596370787+0.075, 45.61087892678886+0.015],
                           [-73.5124596370787+0.075, 45.448903185047335-0.025],
                           [-73.73894559925054-0.03, 45.448903185047335-0.025],
                           ]
                            }])
    
    fig.update_layout(height=600)
    
    fig.show()
    

    enter image description here