I am currently working on a Geography project, for which I have to do some research on migration flows.
I want to represent migration flows using Python and Mapbox, based on a worldwide GeoJSON I previously downloaded. However, I am having some issues regarding the quality of the work, and can't find a proper solution.
I first uploaded the world GeoJSON:
countries = json.load(open("countries_without_antartica.geojson"))
I then extracted the coordinates with a function and grouped them into a list named countries_coords, with countries_lons, countries_lats = zip(*countries_coords).
I then start creating the figure.
Firstly, I initiate it:
fig = go.Figure()
Then, I put the information I extracted before into a ScatterMapbox environment:
fig.add_trace(go.Scattermapbox(
mode='lines',
name='Countries',
fill='toself',
fillcolor='lightgray',
line=dict(color='black', width=1),
lat=countries_lats,
lon=countries_lons,
opacity=1,
showlegend=False,
hoverinfo='skip',
))
I then specify the Mapbox style with: fig.update_layout(mapbox=dict(style='white-bg'))
That leaves the map with the GeoJSON data alone, as seen in this image: 
The problem, however, starts right here: I then try to add a line to the map, indicating the first migration flow (in this case, from Spain to Australia). I do this with the following code:
fig.add_trace(
go.Scattermapbox(
name='flow1',
lon = [134.340916, -3.704239],
lat = [-25.039402, 40.415887],
mode = 'lines',
line = dict(width = 8,color = 'green')
)
)
However, the resulted figure is this:
I have several problems with that, as the migration flow line should be a somewhat curved line and not a straight one.
I realized the solution to THAT (and only THAT) problem was to use go.Scattergeo instead of go.Scattermapbox to represent the line, and so I did:
fig.add_trace(
go.Scattergeo(
name='flow1',
lon = [134.340916, -3.704239],
lat = [-25.039402, 40.415887],
mode = 'lines',
line = dict(width = 8,color = 'green')
)
)
BUT the line is now "behind" the map itself, so it is not visible (resulting in IMAGE 1 again).
The line with go.Scattergeo IS curved, and it DOES represent what I wanted it to represent, but it is not visible because it is "layered" behind the go.ScatterMapbox figure with the map.
How can I change the order of the traces? Is there a way to prevent the first trace from being "above" the second trace? I tried changing the order of appearance, but nothing worked.
EDIT 1
Following the solutions provided by @NikolasStevenson-Molnar and @BasvanderLinden, I rendered both the world and the migration flow by using go.Scattergeo. Code here:
fig.add_trace(go.Scattergeo(
mode='lines',
name='Countries',
fill='toself',
fillcolor='lightgray',
line=dict(color='black', width=1),
lat=countries_lats,
lon=countries_lons,
opacity=1,
showlegend=False,
hoverinfo='skip',
))
fig.add_trace(
go.Scattergeo(
name='flow1',
lon = [134.340916, -3.704239],
lat = [-25.039402, 40.415887],
mode = 'lines',
line = dict(width = 8,color = 'green')
)
)
As you can see, the map is not as "great" as it should be. Some issues regarding it's quality are:
- The countries are filled with the same colors as the background (i.e. the oceans). I cannot find a way to fill only de countries. While using
go.Scattermapboxthis was easily done by specifying the desired style (fig.update_layout(mapbox=dict(style='white-bg'))). However, 'go.Scattergeo' does not have that functionality. - The map seems to be outstretched horizontally (see how all the countries are way more wide in IMAGE 3 compared to IMAGE 1). This is particularly visible in the northern hemisphere.
It then occurred to me that issue 1 should be solved by "turning off" the filling atributes, so I coded:
fig.add_trace(go.Scattergeo(
mode='lines',
name='Countries',
line=dict(color='black', width=1),
lat=countries_lats,
lon=countries_lons,
opacity=1,
showlegend=False,
hoverinfo='skip',
))
Result is, again, not desirable, because the GeoJSON is plot above the default map that 'go.Scattergeo` provides. For example, when I zoom in into Spain, I get:
Clearly, the two traces (default and GeoJSON) are operating at the same time, making the final result not-so-tidy. On top of that, the default trace just shows "territory", but not "political division", so -for example- Portugal is not drawn in the default trace but it is in the GeoJSON.
Hope this extra information is valuable to reach a proper solution.
Thank you in advance, for any help, advice, or solution you might give me.

