Search code examples
pandasnumpyplotlymaps

How to display data over my map in plotly.express choropleth?


This is from my notebook:

from chart_studio import plotly
import plotly.graph_objs as go 
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
import plotly.express as px

init_notebook_mode(connected=True) 
df = pd.read_csv("D:\Documents\india_alcohol_stats.csv")
geojson="https://gist.githubusercontent.com/jbrobst/56c13bbbf9d97d187fea01ca62ea5112/raw/e388c4cae20aa53cb5090210a42ebb9b765c0a36/india_states.geojson",


fig = px.choropleth(
  df,
  geojson="https://gist.githubusercontent.com/jbrobst/56c13bbbf9d97d187fea01ca62ea5112/raw/e388c4cae20aa53cb5090210a42ebb9b765c0a36/india_states.geojson",
  featureidkey='properties.ST_NM',
  locations='state',

  color='consumption',
  color_continuous_scale='Reds'
)

fig.update_geos(fitbounds="locations", scope="asia", resolution=110, visible=False, showsubunits=True, subunitcolor="White", subunitwidth=0)

This is the result I get: Result

How do I get something like this? : Wanted


Solution

  • Since there is no data presented for the graph, it is taken from the Indian census data. Additional data processing has been added for this purpose. I cannot add annotations using geo-coordinates to px.choropleth(). See this for the rationale: adding annotations for percentage values in go.Scattertermapbox, adding color coding for population in go.Choroplethmapbox. The center coordinates of the state for annotations are calculated and created as dictionary data. Notes.

    1. The blanks on the map are blank because the census state name used differs from the geojson state name.
    2. The annotations for percentages are also exceptional because the state names are different. This is not necessary if the state name in your data matches the state name in the geojson data.
    3. A free API account is required to use mapbox.
    4. State name annotations are provided by mapbox and are not compatible.
    from urllib.request import urlopen
    import json
    import pandas as pd
    
    url = "https://gist.githubusercontent.com/jbrobst/56c13bbbf9d97d187fea01ca62ea5112/raw/e388c4cae20aa53cb5090210a42ebb9b765c0a36/india_states.geojson"
    with urlopen(url) as response:
        geo_json = json.load(response)
    
    # https://censusindia.gov.in/census.website/data/population-finder
    # POPULATION FINDER 2011
    df = pd.read_excel('./data/2011-IndiaState-0000.xlsx')
    dfs = df[(df['TRU'] == 'Total') & (df['Level'] == 'STATE')]
    dfs = dfs[['Level', 'Name', 'TRU', 'No_HH', 'TOT_P', 'TOT_M']]
    
    dfm = dfs.copy()
    
    dfm['Name'] = dfs['Name'].apply(lambda x: x.title())
    dfm['per'] = dfm['TOT_M'].apply(lambda x: x / sum(dfm['TOT_M']))
    dfm.head()
        Level   Name    TRU     No_HH   TOT_P   TOT_M   per
    3   STATE   Jammu & Kashmir     Total   2119718     12541302    6640662     0.010655
    6   STATE   Himachal Pradesh    Total   1483280     6864602     3481873     0.005586
    9   STATE   Punjab              Total   5513071     27743338    14639465    0.023488
    12  STATE   Chandigarh          Total   241173      1055450     580663  0.000932
    15  STATE   Uttarakhand         Total   2056975     10086292    5137773     0.008243
    
    # center coords of state
    from shapely.geometry import shape
    
    center_pos = {}
    features = geo_json['features']
    for feature in features:
        k = feature['properties']['ST_NM']
        s = shape(feature["geometry"])
        p = s.centroid
        center_pos[k] = list(p.coords)
    
    import plotly.graph_objects as go
    import plotly.express as px
    
    mapbox_access_token = open("mapbox_api_key.txt").read()
    
    fig = go.Figure()
    
    for k,v in center_pos.items():
        #print(k,v)
        val = dfm[dfm['Name'] == k]['per']
        try:
            val = '{:.2%}'.format(val.values[0])        
        except IndexError:
            val = '{:.2%}'.format(0.000001)
        fig.add_trace(go.Scattermapbox(
            lat=[center_pos[k][0][1]],
            lon=[center_pos[k][0][0]],
            mode='text',
            textfont=dict(
                color='red',
                size=18
            ),
            text=val,
            showlegend=False
    ))
    
    
    fig.add_trace(go.Choroplethmapbox(
        geojson=geo_json, 
        locations=dfm['Name'],
        featureidkey="properties.ST_NM",
        z=dfm['TOT_M'],
        colorscale="Viridis",
        marker_opacity=0.7,
        marker_line_width=0
    ))
    
    
    fig.update_layout(
        mapbox_accesstoken=mapbox_access_token,
        #mapbox_style="carto-positron",
        mapbox_zoom=4,
        mapbox_center = {"lat": 22.5, "lon": 81.0}
    )
    
    fig.update_layout(autosize=False,
                      height=600,
                      width=800,
                      margin={"r":0,"t":0,"l":0,"b":0},
                     )
    fig.show()
    

    enter image description here