Skip to content

Creating Interactive Corona Virus(COVID-19) Tracking Dashboard using Python

Learn how to build an interactive dashboard to track live status of Corona pandemic across the world using public APIs and Python.

A good visualization conveys the true meaning hidden behind numbers in a data-set analysis. Python, as it always does, has quite a few options to visualize geospatial data. As the world is grappling with COVID-19 outbreak, let us try to visualize the impact of the virus across different countries in the world.

I will be using the dataset published by John Hopkins University. I will be using geoviews, pandas, numpy, bokeh python libraries. You can download the entire notebook here.

Let’s start with reading and preprocessing the dataset. I am going to use pandas to read the csv. The dataset contains the following columns: Province/State, Country/Region, Last Update, Confirmed, Deaths, Recovered, Latitude, Longitude.

For this dashboard, let’s ignore the Last Update column value. We read the remaining columns. The State value is left empty for most of the countries. So we fill the empty cells with the value “-“. We also rename the lengthy column names to shorter names.

import pandas as pd
#read the dataset and replace NaN state values with '-'
df_new= pd.read_csv("03-17-2020.csv")[['Province/State', 'Country/Region', 'Confirmed', 'Deaths', 'Recovered', 'Latitude', 'Longitude']]
df_new = df_new.fillna('-')

#rename columns
df_new.columns = ['state', 'country', 'confirmed', 'deaths', 'recovered', 'lat', 'lon']

Now let’s plot the countries in a world map. We will be using GeoViews and bokeh extension to achieve this. We are going to use one of the available tile_sources, CartoDark, from the GeoViews tile_sources list to create a basemap. To plot points in our basemap, we create GeoViews Points by supplying co-ordinate information along with the data, in our case — country names and the case counts, to be associated with the point. To plot the points on our basemap we use *.

import geoviews as gv
import geoviews.tile_sources as gvts
gv.extension('bokeh')

gv_points = gv.Points(df, ['lon', 'lat'], ['state', 'country', 'cases'])
gvts.CartoDark * gv_points

Alright, we got the data points on a map. Now let’s make the points tell us the story about the data. First let’s make the map bigger. We can do this by supplying height and width parameters to GeoViews opts. Let us also get rid of the x-axis and y-axis values. To visualize the impact in different countries, let’s change the size and color of the geoview points based on the number of confirmed cases. We set the size parameter to ‘np.sqrt(dim(‘confirmed’))*0.7‘ and we set color, line_color, alpha parameters to set the color and transparency of the points.

gvts.CartoDark * points.opts(
    opts.Points(width=1200, height=700, alpha=0.4,  
                line_color='red', color='red', xaxis=None, yaxis=None,size=np.sqrt(dim('confirmed'))*0.7))

That looks pretty neat. For the final part, let us add an interactive element to the map. We are going to use bokeh HoverTool to get tooltips for all the data points in the map. We do this supplying the HoverTool with the required data to be displayed. The variable is then passed to the tool option. We can also highlight the hovered point by supplying values for a lower value for alpha value than the hover_fill_alpha value. We can make the points more distinct by supplying value line_color, hover_line_color options.

points = gv.Points(df_new, ['lon', 'lat'], ['state', 'country', 'confirmed', 'deaths', 'recovered'])
gvts.CartoDark * points.opts(
    opts.Points(width=1200, height=700, alpha=0.4,  hover_fill_alpha=0.6, tools=[hover], color='red', xaxis=None, yaxis=None, size=np.sqrt(dim('confirmed'))*0.7, hover_line_color='red',  
                line_color='red',))

That gives you a nice interactive dashboard that is almost similar to that of John Hopkins Corona dashboard. We can extend this dashboard to also indicate the number of recovered, death cases as data points in the map. I have color encoded these three values and the tooltip using pretty much the same logic we have used thus far in our little project to do this.

#define custom tooltip with color code
hover = HoverTool(
        tooltips="""
        <div>
            <span>State:</span>
            <span>@state</span>
        </div>
        <div>
            <span>Country:</span>
            <span>@country</span>
        </div>
        <div>
            <span>Confirmed:</span>
            <span style="background-color: red; color:white;">&nbsp;@confirmed&nbsp;</span>
        </div>
        <div>
            <span>Recovered:</span>
            <span style="background-color: springgreen;">&nbsp;@recovered&nbsp;</span>
        </div>
        <div>
            <span>Deaths:</span>
            <span style="background-color: black; color:white;">&nbsp;@deaths&nbsp;</span>
        </div>
        """
    )


confirmed_points = gv.Points(df_new, ['lon', 'lat'], ['state', 'country', 'confirmed', 'deaths', 'recovered'])
recovered_points = gv.Points(df_new, ['lon', 'lat'], ['state', 'country', 'confirmed', 'deaths', 'recovered'])
death_points = gv.Points(df_new, ['lon', 'lat'], ['state', 'country', 'confirmed', 'deaths', 'recovered'])

confirmed_opts = opts.Points(width=1200, height=700, alpha=0.4, hover_line_color='red',  
                line_color='red', color='red', xaxis=None, yaxis=None,
                tools=[hover],size=np.sqrt(dim('confirmed'))*0.7, hover_fill_alpha=0.6)

recovered_opts = opts.Points(width=1200, height=700, alpha=0.6, hover_line_color='green',  
                line_color='springgreen', color='springgreen', xaxis=None, yaxis=None,
                tools=[hover],size=np.sqrt(dim('recovered'))*0.7, hover_fill_alpha=0.8)

death_opts = opts.Points(width=1200, height=700, alpha=0.7, hover_line_color='black',  
                line_color='black', color='black', xaxis=None, yaxis=None,
                tools=[hover],size=np.sqrt(dim('deaths'))*0.7, hover_fill_alpha=0.9)

gvts.CartoDark * confirmed_points.opts(confirmed_opts)* recovered_points.opts(recovered_opts)* death_points.opts(death_opts)

That’s all folks. Fin.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.