Search code examples
pythonplotlymapsgischoropleth

Display map labels over choropleth data plotly.py


Right now I have the following code in Python to generate a choropleth map which highlights various U.S. counties by FIPS code:

import plotly.graph_objects as go

fig = go.Figure(go.Choroplethmapbox(
    geojson=counties, 
    locations=df.fips, 
    z=df.data,
    zmin=0, zmax=1,
    marker_opacity=1,
))
fig.update_layout(
    mapbox_style='open-street-map',
    mapbox_zoom=3,
    mapbox_center = {'lat': 37.0902, 'lon': -95.7129},
)
fig.update_layout(
    margin={ 'r': 0, 't': 0, 'l': 0, 'b': 0 }
)

My problem is that because I have marker_opacity=1, all of the place names and other geographic data that is normally displayed on the map is hidden and only the colors from each choropleth region can be seen. I realize I can lower marker_opacity to still be able to see the labels on the map, but it is still quite hard to see the place names. I need a way to tell plotly to display the map labels over the choropleth graph that I have created.


Solution

  • Since there is no data presented, the data for the graph is created from references. First we get the state code, county code, county name, and geometory from geojson, then we combine the state code and county code into one column to combine with the fip code of the user data in a new data frame. We also add the county name. We also get the latitude and longitude of the center from the geomerty and add them in a list. The first map is a choropleth map, which is color-coded based on user data. The second is a scatter map with the latitude and longitude set in text mode and the county names as annotation text.

    from urllib.request import urlopen
    import json
    with urlopen('https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json') as response:
        counties = json.load(response)
    
    import pandas as pd
    df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/fips-unemp-16.csv",
                       dtype={"fips": str})
    
    from shapely.geometry import shape
    
    features = counties['features']
    df2 = pd.DataFrame()
    fips2, county_name, center_pos = [], [], []
    
    for feature in features:
        state_county = feature['properties']['STATE'] + feature['properties']['COUNTY']
        countyname = feature['properties']['NAME']
        center = shape(feature['geometry'])
        fips2.append(state_county)
        county_name.append(countyname)
        center_pos.append([center.centroid.x, center.centroid.y])
        
    df2 = pd.DataFrame({'fips':fips2, 'countyname':county_name, 'center_pos': center_pos})
    dfm = df.merge(df2, left_on='fips', right_on='fips', how='inner')
    
    dfm.head()
    
    fips    unemp   countyname  center_pos
    0   01001   5.3     Autauga     [-86.64119616803883, 32.536152921436546]
    1   01003   5.4     Baldwin     [-87.72395376445844, 30.72586230172138]
    2   01005   8.6     Barbour     [-85.38924517387589, 31.867888656342394]
    3   01007   6.6     Bibb    [-87.12496297519768, 32.996456285921184]
    4   01009   5.5     Blount  [-86.56975624844863, 33.98524765933215]
    
    import plotly.graph_objects as go
    
    mapbox_access_token = open("./mapbox_api_key.txt").read()
    
    fig = go.Figure(
        go.Choroplethmapbox(
            geojson=counties,
            locations=df.fips,
            z=df.unemp,
            colorscale="Viridis",
            zmin=0,
            zmax=12,
            marker_opacity=0.8,
            marker_line_width=0
    ))
    
    fig.add_trace(go.Scattermapbox(
            lat=[x[1] for x in dfm['center_pos']],
            lon=[x[0] for x in dfm['center_pos']],
            mode='text',
            text=dfm['countyname'].tolist(),
            textposition='middle center',
            textfont=dict(
                color='white',
                size=10,
            )
    ))
    
    fig.update_layout(title_text ='County name',
                      title_x =0.5,
                      autosize=True,
                      height=600,
                      mapbox = dict(
                          center=dict(lat=37.0902, lon=-95.7129),
                          accesstoken=mapbox_access_token,
                          zoom=6,
                          style="light"
                      ))
    
    fig.show()
    

    enter image description here