Search code examples
pythonmatplotlibplotly.graph-objects

How to draw bounderies between countries and countries' states on pyplot.go.Figure with go.Scattergeo


So, I am doing a map that shows the flow of people among some cities in Brazil by drawing lines on the map, representing the path, and setting its opacity according to the count of occurrences. To do so, I am following this code (third map, the one about flights on US).

My question is, can I draw the borders between countries? And, if possible, also between Brazilian states?

In the documentation, there is an argument of the function called "geojson", but I'am not sure on how to use it, or if it is even useful for me.

Note that I have GeoJSON data for both countries and states.

Here's the code to generate the my map:

import pandas as pd
import plotly.graph_objects as go

fig = go.Figure()

for i in range(len(my_df)):
    fig.add_trace(
        go.Scattergeo(
            lon = [my_df['res_longitude'][i], my_df['nasc_longitude'][i]],
            lat = [my_df['res_latitude'][i], my_df['nasc_latitude'][i]],
            mode = 'lines',
            line = dict(width = 1,color = 'red'),
            opacity = min(1, float(my_df['flow'][i]) / float(my_df['flow'].quantile(.95))),
        )
    )

fig.update_layout(
    showlegend = False,
    margin ={'l':0,'t':0,'b':0,'r':0},
    mapbox = {
    'center': {'lon': -50.3206, 'lat': -16.4984},
    'style': "stamen-terrain",
    'zoom': 3}
)

and here's the result:

Flow Map on Brazil


Solution

  • Since I don't have the geojson data and the latitude and longitude information to draw the line, I'll use the official reference you referenced to answer your question.

    • Using the choropleth map, add a sum column with 0 to the data used in this sample.
    • Specify the geojson you obtained to geojson=usa_geo.
    • We associate the geojson state name with the state in the data.
    • I set the map fill to a light gray.
    • Note: The center setting of the map is automatically calculated since we are using fitbounds for the location.
    from urllib import request
    import json
    import pandas as pd
    import plotly.graph_objects as go
    import plotly.express as px
    
    # usa geojson data
    # https://eric.clst.org/tech/usgeojson/
    usa_json = open('./data/gz_2010_us_040_00_500k.json', 'r')
    usa_geo = json.load(usa_json)
    
    # Choropleth Maps with go.Choropleth
    # https://plotly.com/python/choropleth-maps/
    df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/2011_us_ag_exports.csv')
    
    # https://plotly.com/python/lines-on-maps/
    df_flight_paths = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/2011_february_aa_flight_paths.csv')
    
    # dummy data column
    dfs = pd.concat([df, pd.Series([0]*len(df),name='count')], axis=1)
    
    fig = go.Figure()
    fig.add_trace(go.Choropleth(
        geojson=usa_geo,
        locations=df['state'],
        z = dfs['count'].astype(float), 
        featureidkey='properties.NAME',
        colorscale = [[0,'rgb(200, 200, 200)']],
        showlegend=False,
        coloraxis=None,
        colorbar=None
    ))
    
    fig.update_traces(showscale=False)
    
    flight_paths = []
    for i in range(len(df_flight_paths)):
        fig.add_trace(
            go.Scattergeo(
                #locationmode = 'USA-states',
                lon = [df_flight_paths['start_lon'][i], df_flight_paths['end_lon'][i]],
                lat = [df_flight_paths['start_lat'][i], df_flight_paths['end_lat'][i]],
                mode = 'lines',
                line = dict(width = 1,color = 'red'),
                opacity = float(df_flight_paths['cnt'][i]) / float(df_flight_paths['cnt'].max()),
                showlegend=False
            )
        )
    
    fig.update_layout(
        autosize=False,
        width=1000,
        height=600,
        margin={"r":0,"t":0,"l":0,"b":0},
        geo=dict(
            scope='north america', # you chenge 'south america'
            fitbounds="locations", # It is associated width 'px.Choropleth'
            visible=True,
            showland=True,
            #center=dict(lon=34.05795, lat=-179.25450), 
            # The center designation of the map has no effect as this is automatically calculated
        )
    )
    
    fig.show()
    

    enter image description here