Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any way to draw INDIA Map in plotly?

Tags:

python

plotly

I am trying to plot India map using plotly, but unable to find a way to do that. Below is the code which I tried for USA.

import pandas as pd

df_sample = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/laucnty16.csv')
df_sample['State FIPS Code'] = df_sample['State FIPS Code'].apply(lambda x: str(x).zfill(2))
df_sample['County FIPS Code'] = df_sample['County FIPS Code'].apply(lambda x: str(x).zfill(3))
df_sample['FIPS'] = df_sample['State FIPS Code'] + df_sample['County FIPS Code']

colorscale = ["#f7fbff","#ebf3fb","#deebf7","#d2e3f3","#c6dbef","#b3d2e9","#9ecae1",
              "#85bcdb","#6baed6","#57a0ce","#4292c6","#3082be","#2171b5","#1361a9",
              "#08519c","#0b4083","#08306b"]
endpts = list(np.linspace(1, 12, len(colorscale) - 1))
fips = df_sample['FIPS'].tolist()
values = df_sample['Unemployment Rate (%)'].tolist()

fig = ff.create_choropleth(
    fips=fips, values=values,
    binning_endpoints=endpts,
    colorscale=colorscale,
    show_state_data=False,
    show_hover=True, centroid_marker={'opacity': 0},
    asp=2.9, title='USA by Unemployment %',
    legend_title='% unemployed'
)

fig.layout.template = None
fig.show()

OUTPUT: enter image description here

In a similar way I just want to draw India's map with hovering values. and just want output like below... the output of INDIAN MAP: enter image description here

like image 884
Naveen Kumar Malineni Avatar asked Mar 29 '20 06:03

Naveen Kumar Malineni


People also ask

What is Locationmode in plotly?

locationmode (str) – One of 'ISO-3', 'USA-states', or 'country names' Determines the set of locations used to match entries in locations to regions on the map.

What is Scattergeo?

Scattergeo trace is a graph object in the figure's data list with any of the named arguments or attributes listed below. The data visualized as scatter point or lines on a geographic map is provided either by longitude/latitude pairs in `lon` and `lat` respectively or by geographic location IDs or names in `locations`.


3 Answers

The figure factory create_choropleth method that you're using is deprecated and deals with USA counties exclusively. For other maps, you need the GeoJSON for the features you're mapping. Plotly only comes with GeoJSON data for world countries and US states, so you'll have to provide the data for India's states yourself.

Like your example choropleth, let's plot the current number of active COVID-19 cases per state as of July 17 (this comes from indiacovid19.github.io, which is periodically archiving the data from India's Ministry of Health). As for the GeoJSON, a quick search yields a few GitHub repos but it seems the majority are too outdated for our cases data, as they don't include the merging of Dadra and Nagar Haveli and Daman and Diu. Luckily, datameet provides an up-to-date shapefile for India's states which I simplified a bit to reduce the size and converted to GeoJSON using mapshaper, then flipped the polygon winding using geojson-rewind.

Now, as detailed in the Plotly documentation, we can use plotly express to quickly make a choropleth map with our data:

import pandas as pd
import plotly.express as px

df = pd.read_csv("https://gist.githubusercontent.com/jbrobst/56c13bbbf9d97d187fea01ca62ea5112/raw/e388c4cae20aa53cb5090210a42ebb9b765c0a36/active_cases_2020-07-17_0800.csv")

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

fig.update_geos(fitbounds="locations", visible=False)

fig.show()

Active cases simple plotly express

For more fine control over the plot, we can use the graph objects directly:

import pandas as pd
import plotly.graph_objects as go

df = pd.read_csv("https://gist.githubusercontent.com/jbrobst/56c13bbbf9d97d187fea01ca62ea5112/raw/e388c4cae20aa53cb5090210a42ebb9b765c0a36/active_cases_2020-07-17_0800.csv")

fig = go.Figure(data=go.Choropleth(
    geojson="https://gist.githubusercontent.com/jbrobst/56c13bbbf9d97d187fea01ca62ea5112/raw/e388c4cae20aa53cb5090210a42ebb9b765c0a36/india_states.geojson",
    featureidkey='properties.ST_NM',
    locationmode='geojson-id',
    locations=df['state'],
    z=df['active cases'],

    autocolorscale=False,
    colorscale='Reds',
    marker_line_color='peachpuff',

    colorbar=dict(
        title={'text': "Active Cases"},

        thickness=15,
        len=0.35,
        bgcolor='rgba(255,255,255,0.6)',

        tick0=0,
        dtick=20000,

        xanchor='left',
        x=0.01,
        yanchor='bottom',
        y=0.05
    )
))

fig.update_geos(
    visible=False,
    projection=dict(
        type='conic conformal',
        parallels=[12.472944444, 35.172805555556],
        rotation={'lat': 24, 'lon': 80}
    ),
    lonaxis={'range': [68, 98]},
    lataxis={'range': [6, 38]}
)

fig.update_layout(
    title=dict(
        text="Active COVID-19 Cases in India by State as of July 17, 2020",
        xanchor='center',
        x=0.5,
        yref='paper',
        yanchor='bottom',
        y=1,
        pad={'b': 10}
    ),
    margin={'r': 0, 't': 30, 'l': 0, 'b': 0},
    height=550,
    width=550
)

fig.show()

Active cases full plotly graph objects

like image 172
Josh Brobst Avatar answered Oct 12 '22 23:10

Josh Brobst


Note : I could not manage to do it in plotly, but I can do it easily in Bokeh. The OP asked specifically for plotly but still I am posting this answer to show how can be done someother way.

  1. GeoJson of India states is distributed by https://gadm.org/
  2. Load it into GeoJSONDataSource Data Model of Bokeh
  3. Setup the figure and fead in th Data Model
  4. Custom colors can be achived by added the information per germoery/state inside the Datamodel.

Working Code

from bokeh.models import GeoJSONDataSource
from urllib.request import urlopen
import json

from bokeh.models import GeoJSONDataSource, HoverTool, LinearColorMapper
from bokeh.palettes import Viridis256
from bokeh.plotting import figure
from bokeh.io import output_file, show
import matplotlib.pyplot as plt
from bokeh.io import show, output_notebook

%matplotlib 
output_notebook()

# Geojson of India
with urlopen("https://raw.githubusercontent.com/geohacker/india/master/state/india_state.geojson") as response:
    geojson = json.load(response)

# Round robin over over 3 colors
# You can set the colors here based on the case count you have per state
for i in range(len(geojson['features'])):
  geojson['features'][i]['properties']['Color'] = ['blue', 'red', 'green'][i%3]


# Set the hover to state information and finally plot it
cmap = LinearColorMapper(palette=Viridis256)

TOOLS = "pan,wheel_zoom,box_zoom,reset,hover,save"

geo_source = GeoJSONDataSource(geojson=json.dumps(geojson))

p = figure(title='India', tools=TOOLS, x_axis_location=None, y_axis_location=None, width=800, height=800)
p.grid.grid_line_color = None

p.patches('xs', 'ys', fill_alpha=0.7, line_color='black', fill_color='Color', line_width=0.1, source=geo_source)

hover = p.select_one(HoverTool)
hover.point_policy = 'follow_mouse'
hover.tooltips = [('State:', '@NAME_1')]

show(p)

Output: enter image description here

As mentioned in the code comments above, you can add the case information to the states in the datamodel and set it to hovertool. This way when you hover over sates you will see the case count. In fact you can just add what ever info you want to the states inside the datamodel and use the datamodel to render them.

like image 38
mujjiga Avatar answered Oct 13 '22 00:10

mujjiga


Sorry but you cannot do that as the location mode has only 3 values: “ISO-3” , “USA-states” , “country names”

and the geo of layout can only have the 7 values for scope -“world” | “usa” | “europe” | “asia” | “frica” | “north america” | “south america”.

so in order to get a plot of India you need to get a plot of asia in which india would be marked but there is no option for a separate plot of India and states.

data = dict(type = 'choropleth',
           locations = ['india'],
           locationmode = 'country names',
           colorscale= 'Portland',
           text= ['t1'],
           z=[1.0],
           colorbar = {'title' : 'Colorbar Title'})

layout = dict(geo = {'scope': 'asia'})

this colud give you asia map with India marked.

like image 36
Divyessh Avatar answered Oct 13 '22 01:10

Divyessh