Does scatter_geo needs an internet access to display the map?

Hi there,
I’m a bit puzzled; I use Dash and Plotly at work, but the examples provided in the doc do not display any map; when executed as-is, I get the legends, but no map. They work on a private machine, though, even without Wifi, which is in contradiction with the question asked in the title of this topic…

For instance, the below code

import plotly.express as px
df = px.data.gapminder().query("year == 2007")
fig = px.scatter_geo(df, locations="iso_alpha",
                     size="pop", # size of markers, "pop" is one of the columns of gapminder
                     )
fig.show()

Shows a blank page with an empty figure in the browser;

The next one

import plotly.express as px
df = px.data.gapminder().query("year == 2007")
fig = px.scatter_geo(df, locations="iso_alpha",
                     color="continent", # which column to use to set the color of markers
                     hover_name="country", # column added to hover information
                     size="pop", # size of markers
                     projection="natural earth")
fig.show()

Only shows legends items, no map.

I tried with other data:

    import io
    import pandas as pd
    import numpy as np
    import plotly.express as px
    df_1 = pd.read_csv(io.StringIO("""Paesi_principali,Value,iso_alpha
    US, 20, USA
    Italia, 11, ITA
    Germania, 6, DEU
    Messico, 5, MEX
    India, 6, IND
    Francia, 8, FRA
    """))
    fig = px.scatter_geo(df_1, locations="iso_alpha",locationmode ="ISO-3", 
color="iso_alpha", size="Value", projection="natural earth")
    fig.show()

But again, no map.

I also tried without px.express:

    import plotly.graph_objects as go
    fig30 = go.Figure()
    fig30.add_trace(go.Scattergeo(lon=[21.0936], lat=[7.1881], text=['Africa'], mode='text', geo='geo2'))
    fig30.update_layout(geo2=go.layout.Geo(scope='africa', domain=dict(x=[0, 0.6], y=[0, 0.6])))
    fig30.show(
)

And again, no map.

I tried to plot a scatter_mapbox, but once again,

df = px.data.carshare()
fig = px.scatter_mapbox(df, lat="centroid_lat", lon="centroid_lon", color="peak_hour", size="car_hours",
                  color_continuous_scale=px.colors.cyclical.IceFire, size_max=15, zoom=10,
                  mapbox_style="carto-positron")
fig.show()

the above does not show any map. I get the marker on the map, though. (Maybe both a token and internet access issue, here?)

One more:

df = px.data.election()
geojson = px.data.election_geojson()

fig = px.choropleth_mapbox(df, geojson=geojson, color="Bergeron",
                           locations="district", featureidkey="properties.district",
                           center={"lat": 45.5517, "lon": -73.7073},
                           mapbox_style="carto-positron", zoom=9)
fig.show()

gives:

But no map :frowning:

This topic seems to be related: Px scatter_geo does not show map ERROR

I use plotly 5.13. Any clue regarding the possible cause of the problem?

Plotly actually tries to retrieve data from https://cdn.plot.ly/world_110m.json to plot the map. I found discussions about this on python - Displaying Plotly maps on disconnected system - Stack Overflow, (Kevin Daly’s answer), and here Cannot draw a map offline · Issue #514 · plotly/plotly.py · GitHub (carlosvega’s answer)
Hammy27 suggested that installing plotly-geo would fix the issue, but it didnt work; maps are still missing.

The root of the issue is that the machine on which the dash app run does not have any access to the internet.

Edit:
While looking for a reference to “topojson” somewhere in the doc, in the modules files and on this forum, I found this previous post:

which pointed to the doc:

and helped a lot in fixing the problem. Thanks, @zoohair

In a nutshell, the solution consists in:

  1. in the DashApp assets folder, make a new folder in which will be stored the topjson files. In this example, I named it “topojson_local”

  2. copy-paste the content of https://cdn.plot.ly/world_110m.json, https://cdn.plot.ly/world_110m.json in a json file, which is then saved into the assets/topojson folder. Proceed similarly with https://cdn.plot.ly/world_50m.json, and the other ones.

  3. at the top of the dash app, add the following:

    isOffline = True
    plotlyConfig = {'topojsonURL':'assets/topojson_local/'} if isOffline else {}
    

    (as suggested by @zoohair )

  4. the dcc.Graph component containing the map must set the config arg as below:

      dcc.Graph(
          id='map-xyz',
          config=plotlyConfig,
          figure=fig,
          style={"height": "100%"}
      )
    

And then, the dash app will render the map, even if it is executed on some intranet without any access to the web.

Hi David,

Can you post an example for this? I tried to use your solution but it still blank.

Hi,
The above solution must work; dash/plotly is designed to allow this. Note that it expects to find a file named “world_110m.json” in the folder of your choice. If you need another map, then you have to get the relevant file. (e.g world_50m.json, etc) I don’t have the full list of them.

By copy pasting the below code:

from dash import Dash, dcc, html, Input, Output
import plotly.express as px
import pandas as pd

isOffline = False
plotlyConfig = {'topojsonURL':'assets/topojson_local/'} if isOffline else {}

app = Dash(__name__)

app.layout = html.Div(children=[
    dcc.Dropdown(
        options=[{'label': '2002', 'value': '2002'},
                 {'label': '2007', 'value': '2007'}],
        value='2007',
        id="demo-dropdown"
    ),
    dcc.Graph(id='example-graph', config=plotlyConfig),
    dcc.Graph(id='example-graph-2', config=plotlyConfig)
])

@app.callback(
    Output(component_id='example-graph', component_property='figure'),
    Output(component_id='example-graph-2', component_property='figure'),
    Input(component_id='demo-dropdown', component_property='value')
)
def update_output_div(input_value):
    querystring = "year == {}".format(input_value)
    df = px.data.gapminder().query(querystring)
    fig = px.scatter_geo(df, locations="iso_alpha", size="pop")
    fig2 = px.scatter_geo(df, locations="iso_alpha", color="continent", 
hover_name="country", size="pop", projection="natural earth")
    return fig, fig2

if __name__ == '__main__':
    app.run_server(debug=True)

On a machine without any access to internet, you will get this:

Then, if you set isOffline to True:

isOffline = True
plotlyConfig = {'topojsonURL':'assets/topojson_local/'} if isOffline else {}

You’ll get this:

If, of course, you have the world_110m.json in topojson_local folder in the assets folder of your dash app

Note: if you remove

    config=plotlyConfig

from

    dcc.Graph(id='example-graph-2', config=...) 

kill the app, clear the cache, close the tab in your browser, restart the app by setting isOffline=False, you’ll have 2 empty figures.
Then, if you set isOffline=True, and just refresh the app, you will get a map in the first figure, but nothing in the second one (because the topojsonURL is not set anymore, we removed the config=… arg).
Eventually, if you put the config arg into the 2nd dcc.Graph again (by adding the config=plotlyConfig), and refresh, you will get a map in each figures.

And if you set the isOffline back to “False”, and refresh without restarting the app, the figure keeps showing a map. Here, I guess it’s because it’s cached.

1 Like

Thank David, I’m still stuck. Already add world_110m.json to assets folder, try to change isOffline=True and run your code but it’s still a white page. Below is my console. Maybe I still missing something.

what do your config and topjsonUrl look like ?

1 Like

Thank you, I found out the reason. I need to add normalize.min.css.map to assets folder to make it work.

Why?. I dont need it here to make it work :face_with_monocle:

1 Like

I’m not sure why, but I checked console and saw that it was missing so I tried to add it to assets folder then it worked.

Im adding more details to this thread since 1/ I ran into a new issue, and 2/ I found the full list of maps in the meantime.

Regarding 2/, the list of map can be found, thanks to @etienne’s post, here:

direct link: https://github.com/etpinard/sane-topojson/tree/master/dist

Regarding 1/, the console is now complaining that

It doesn’t seem to be related to the same-origin policy mentioned there Scattergeo loading map offline from local topojson (with Python) [Solved] - #2 by jmmease

No clue how to fix this. I’m trying to display a scatter geo on a page of a multi page App