Loading geo assets offline [Solved]

I am running a Dash server offline and maps do not load.

I can confirm that any map Graph runs if I have an internet connection but it doesn’t render if there is no internet connection (assuming this hasn’t been cached).

Specifically, Plotly is looking for assets like https://cdn.plot.ly/usa_110m.json to render with.

Is there a method to render this locally and offline?

I have a solution and it involves copying the JSON files stored on the Plotly CDN and attaching to your web server in your offline environment (in my case IIS).

The CDN files I downloaded were:
https://cdn.plot.ly/usa_110m.json
https://cdn.plot.ly/world_110m.jso

Once the web server is hosting its own address for the Plotly geo files, you then need to change a line of code in the plotly.min.js file that Plotly uses to call the Plotly cdn.
If you search for “topojsonURL” then you can change the URL used by the webs server accordingly.

This is confirmed to work but if you are having issues with setting this up on IIS feel free to message.

I know this is marked as solved, but since I had a similar issue with trying to do this with Dash, and this is the first link that shows up, I thought I’d share my solution

after trying to figure out how to host the files locally, having some iptables or /etc/hosts
change that forwarded to my local machine, I eventually tried the “hack” of modifiying the topojsonURL config in my local plotly.min.js file suggest here. However that still didn’t work. I kept getting the same error about not being able to load the file from https://cdn.plot.ly/ even though I overwrote topojsonURL in plotly.min.js, and debugging the minified file was crashing my Chrome instance.

My hunch was that it was being set by something else, and sure enough, after searching a bit in
the dash files there was another reference to topojsonURL in dcc.Graph

I checked the documentation, and there was a mention of:
- topojsonURL (string; optional): URL to topojson files used in geo charts
So I passed that to the config of dcc.Graph and it worked well!

The following is a simple working example for anyone who is trying to get the ‘native’ maps to work offline (mapbox of course requires an online connection or a local instance, but since a lot of the features that make it powerful in my opinion - layers with heatmaps for example- are not yet supported, it’s not clear if it’s worth using mapbox vs. the native maps for my application.)

import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html

app = dash.Dash(meta_tags = 
                [{'name':"viewport", 'content':"width=device-width, initial-scale=1"}])

portnumber=5500

# Can be passed as argument to application, automatically determined, etc.
offline = True

app.css.config.serve_locally = offline
app.scripts.config.serve_locally = offline

#Here we assume that the appropriate topoJson files (world_110m.json, world_50m.json, etc.)
#normally hosted on https://cdn.plot.ly/ are available under ./assets
plotlyConfig = {'topojsonURL':'http://127.0.0.1:%i/assets/'%portnumber} if offline else {}


data  = [ dict(
        type = 'scattergeo',
        text=['A', 'B', 'C'],
        lon=['-122', '35', '170'],
        lat=['37', '-24', '-37'], 
        mode='markers+text+lines',
        marker=dict(size=5),
        textfont=dict(size=12),
        hoverinfo='none',
) ]

layout = dict(
            width=800, height=400,
            geo = dict(
                projection=dict( type='natural earth' , scale=1),
                framewidth = 1,
                showland = True, showlakes = True, showocean=True, showcountries=True,
                landcolor = 'rgb(204, 204, 204)',
                oceancolor= 'rgb(145, 191, 219)',
                countrycolor = 'rgb(128, 128, 128)',
                lakecolor = 'rgb(145, 191, 219)',
                countrywidth = 0.5,
                subunitwidth = 0.5,
                coastlinewidth = 1,
                resolution = 75,
                center = dict(lat=0,lon=0)
            ),
            showlegend=False,
            margin = dict(l = 0, r = 0, t = 0, b = 0),
        )

fig = dict(data=data, layout=layout)

gr = dcc.Graph(id='inputMap', config=plotlyConfig, figure = fig)

app.layout = html.Div(gr)

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

1 Like

Zoohair, this is a better solution thankyou.

Another note is that it is a possibility that you weren’t editing the correct plotly.min.js If youre using python environments. changing the topojson url definitely changes the cdn location!

Thanks @eddy_oj

I was changing the plotly.min.js served by dash, and I’m sure it was the right one because when debugging in chrome I could see my change in there. It is possible that there is another file being served from plotly itself (as opposed to from Dash?)

I haven’t managed to get this working for a notebook though: not sure if iplot() has a similar config to allow for setting topojsonURL

Thanks @Zoohair. I had to deal with similar constraints (workstation without access to the web). Based on your solution I updated my initial question in the plotly section.

Thanks for having shared your solution here!

Perhaps the debugger could be a bit more “verbose” when the default cdn queried by plotly to plot a scatter_geo or any other map cannot be reached. I had to open the brower’s console to figure out what resource was missing.