Mapping the 2019 Novel Coronavirus Pandemic

According to WHO, 2019 Novel Corona Virus (COVID-19) is a virus (more specifically, a coronavirus) identified as the cause of an outbreak of respiratory illness, which was unknown before the outbreak began in Wuhan, China, in December 2019 [1]. Early on, the disease demonstrated an animal-to-person spread, then a person-to-person spread. Infections with COVID-19, were reported in a growing number of international locations, including the United States". The United States reported the first confirmed instance of person-to-person spread with this virus on January 30, 2020 [2].

This notebook shows how to use the ArcGIS API for Python to monitor the spread of COVID-19 as it became a pandemic (updated as of June 28th, 2021).

1. Import Data

Esri provides an open-to-public and free-to-share feature layer that contains the most up-to-date COVID-19 cases covering China, the United States, Canada, Australia (at province/state level), and the rest of the world (at country level, represented by either the country centroids or their capitals). Data sources are WHO, US CDC, China NHC, ECDC, and DXY. The China data is updated automatically at least once per hour, and non-China data is updating manually. The data source repo that this layer referenced from, is created and maintained by the Center for Systems Science and Engineering (CSSE) at the Johns Hopkins University, and can be viewed here. In this notebook, we will use the feature layer supported by Esri Living Atlas team and JHU Data Services, and provide a different perspective in viewing the global maps of COVID-19 via the use of ArcGIS API for Python.

NOTE: "Since COVID-19 is continuously evolving, the sample reflects data as of June 28th, 2021 (or if you are looking at a previously published version of this notebook, the data and maps were fetched/made as of July 4th, 2020). Running this notebook at a later date might reflect a different result, but the overall steps should hold good."

DISCLAIMER: "This notebook is for the purpose of illustrating an analytical process using Jupyter Notebooks and ArcGIS API for Python, and should not be used as medical or epidemiological advice."

Necessary Imports

from io import BytesIO
import requests
import pandas as pd
from arcgis.layers import Service
from arcgis.gis import GIS
from arcgis.map import Map
"""
# if you are using arcgis api for python with version 1.8.0 or above,
# make sure that the pandas version>=1.0,
# if not, use `pip install --upgrade pandas>=1` to upgrade.
"""
pd.__version__
'2.1.4'

Get data for the analysis

Query the source feature layer

The dashboard item contributed to the public by Esri and JHU CSSE, is accessible through here:

gis = GIS(profile="your_online_profile")
item = gis.content.search("Coronavirus_2019_nCoV_Cases owner:CSSE_covid19", outside_org=True)[0]
item
Coronavirus COVID-19 (2019-nCoV)
This ArcGIS Dashboard created by the CSSE Team at Johns Hopkins contains the most up-to-date coronavirus COVID-19 (2019-nCoV) cases and latest trend plot. On March 10, 2023, the Johns Hopkins Coronavirus Resource Center ceased collecting and reporting global COVID-19 data. For more information, visit the Johns Hopkins Coronavirus Resource Center. https://coronavirus.jhu.edu/
Dashboard by CSSE_covid19
Last Modified: March 10, 2023
0 comments, 559897620 views

Through the API Explorer provided along with the dashboard product, we can easily fetch the source URL for the Feature Service containing daily updated COVID-19 statistics, which can then be used to create a FeatureLayer object good for querying and visualizing.

src_url = "https://services1.arcgis.com/0MSEUqKaxRlEPj5g/arcgis/rest/services/Coronavirus_2019_nCoV_Cases/FeatureServer/1"
fl = Service(src_url)
df_global = fl.query(where="1=1",
                     return_geometry=True,
                     as_df=True)

As stated in the dashboard, the source data can be grouped into:

  • A. Countries or regions of which data are collected at province/state level, e.g. China, the United States, Canada, Australia;
  • B. Countries or regions for the rest of the world of which data collected at country level, and shape represented by either the country centroids or their capitals;
  • C. Cruise Ships with confirmed COVID-19 cases.
Group A

Let us first take a look at how many countries are within group A, that Country_Region and Province_State are not null or NAN.

df_global[~pd.isnull(df_global['Province_State'])].groupby('Country_Region').sum(numeric_only=True)[['Confirmed', 'Recovered', 'Deaths']]
ConfirmedRecoveredDeaths
Country_Region
Australia10114810014426
Belgium4497199032575
Brazil345167390684813
Canada4225396044607
Chile4559801060749
China2615637015020
Colombia63043170141708
Denmark46629049
France118054004517
Germany324522500148299
India444953590528150
Italy220352910176204
Japan20074857042554
Malaysia4803624036277
Mexico70562690329736
Netherlands8507272023253
New Zealand638601
Pakistan1570796030598
Peru41252080216086
Russia197225560377462
Spain133676470113130
Sweden2573548020006
US9524275001050318
Ukraine53637580116685
United Kingdom237715720206751

Each country/region in Group A, has more than 1 feature, as what we have seen below from the query() results.

fset_usa = fl.query(where="Country_Region='US'")
fset_usa
<FeatureSet> 60 features
fset_china = fl.query(where="Country_Region='China'")
fset_china
<FeatureSet> 34 features
fl.query(where="Country_Region='Denmark'")
<FeatureSet> 3 features
Group C

Group C contains cruise ships across the globe with reported cases:

df_cruise_ships = fl.query(where="Province_State='Diamond Princess' or \
                                  Province_State='Grand Princess' or \
                                  Country_Region='MS Zaandam' or \
                                  Country_Region='Diamond Princess'",
                           as_df=True)
df_cruise_ships[["Province_State", "Country_Region", "Last_Update", "Confirmed", "Recovered", "Deaths"]]
Province_StateCountry_RegionLast_UpdateConfirmedRecoveredDeaths
0Diamond PrincessCanada2020-12-21 13:27:30001
1Grand PrincessCanada2020-12-21 13:27:301300
2<NA>Diamond Princess2022-09-11 05:20:45712013
3<NA>MS Zaandam2022-09-11 05:20:45902
4Grand PrincessUS2020-08-04 02:27:5610303
5Diamond PrincessUS2020-08-04 02:27:564900
Group B

In the df_global, other than the 22 countries (Australia, Canada, China, etc.) in Group A, and those cruise ships in Group C, all other countries/regions fall into Group B, e.g. Thailand. The major difference between Group A and Group B is that the latter contains one and only feature per country.

fl.query(where="Country_Region='Thailand'")
<FeatureSet> 1 features

Query the reference feature layers

Because the geo-information provided by the dashboard contains only the coordinates representing the centroid of each country/region, the feature layer can only be rendered as points on Map. If this is what you want, you can now skip the rest of section 1, and jump right onto section 2.

On the other hand, if you want to visualize the confirmed/death/recovered cases per country/region as polygons, in other words as a choropleth map, please read along:

First, we need to access the feature service that contains geometry/shape info for all provinces in Mainland China, and merge with the COVID-19 DataFrame.

Access the reference feature layer of China
provinces_item = gis.content.get("0f57da7f853c4a1aa5b2e048ff8655d2")
provinces_item
Merged_China_Province_Boundaries_2018
Feature layer generated from Merge Layers
Feature Layer Collection by api_data_owner
Last Modified: July 05, 2020
0 comments, 0 views
provinces_flayer = provinces_item.layers[0]
provinces_df = provinces_flayer.query(as_df=True)
provinces_df.columns
Index(['OBJECTID', 'ID', 'NAME', 'AREA', 'TOTPOP_CY', 'ISO_CODE', 'ISO_SUB',
       'ISO2_CC', 'ISO3_CC', 'Shape__Area', 'Shape__Length', 'ID_1',
       'sourceCountry', 'ENRICH_FID', 'aggregationMethod',
       'populationToPolygonSizeRating', 'apportionmentConfidence', 'HasData',
       'TOTPOP_CY_1', 'YEAR2018', 'SHAPE'],
      dtype='object')
tmp = provinces_df.sort_values('NAME', ascending=True)
provinces_df = tmp.drop_duplicates(subset='NAME', keep='last')
provinces_df.shape
(31, 21)
DataFrame Merging for China Dataset

The subsets of dataframe being created in the previous section now needs to be merged with feature services which have geographic information (e.g. geometries, shape, or longitude/latitude) in order to provide location and geometries required for geographic mapping. First, let's acquire the geometries from feature services existing on living atlas or arcgis online organization to represent the geographic information needed of overlap_rows_china.

df_china = fset_china.sdf[['Province_State', 'Confirmed', 'Recovered', 'Deaths']]
df_china = df_china.assign(NAME = df_china["Province_State"])
df_china.head()
Province_StateConfirmedRecoveredDeathsNAME
0Anhui150606Anhui
1Beijing408809Beijing
2Chongqing101206Chongqing
3Fujian417601Fujian
4Gansu134802Gansu

Because the names are inconsistent between the two data sources (e.g. provinces represented differently in df_china['Province_State'] and provinces_df['NAME"]), the replace_value_in_column method is declared below to edit the records and unify the column names.

def replace_value_in_column(data_frame, l_value, r_value, column_name = 'NAME'):
    data_frame.loc[data_frame[column_name] == l_value, column_name] = r_value

replace_value_in_column(df_china, 'Guangxi', 'Guangxi Zhuang Autonomous Region')
replace_value_in_column(df_china, 'Inner Mongolia', 'Inner Mongolia Autonomous Region')
replace_value_in_column(df_china, 'Ningxia', 'Ningxia Hui Autonomous Region')
replace_value_in_column(df_china, 'Tibet', 'Tibet Autonomous Region')

Now the two DataFrame objects have got unified column names, we can go ahead to use a single function in Pandas called merge as an entry point to perform in-memory standard database join operations (similar to that of relational databases such as SQL), and its syntax is shown here -

pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,
         left_index=False, right_index=False, sort=True)

Note that, the how argument specifies how to merge (a.k.a. how to determine which keys are to be included in the resulting table). If a key combination does not appear in either the left or the right tables, the values in the joined table will be NA. The table below then shows a summary of the how options and their SQL equivalent names −

Merge MethodSQL EquivalentDescription
leftLEFT OUTER JOINUse keys from left object
rightRIGHT OUTER JOINUse keys from right object
outerFULL OUTER JOINUse union of keys
innerINNER JOINUse intersection of keys

In this case, we will be calling merge() with how='inner' to perform the inner join of the two DataFrame objects on the index field "NAME" and only to keep the intersection of keys.

cols_2 = ['NAME', 'AREA', 'TOTPOP_CY','SHAPE']
overlap_rows_china = pd.merge(left = provinces_df[cols_2], right = df_china, 
                              how='inner', on = 'NAME')
overlap_rows_china.head()
NAMEAREATOTPOP_CYSHAPEProvince_StateConfirmedRecoveredDeaths
0Anhui140139.79598761795934{"rings": [[[116.36710167, 34.643320083], [116...Anhui150606
1Beijing16535.63027622237467{"rings": [[[116.647890001, 41.0513740000001],...Beijing408809
2Chongqing82390.60069130365055{"rings": [[[108.50186348, 32.20025444], [108....Chongqing101206
3Fujian121789.66683338659398{"rings": [[[118.426801682, 28.2953205110001],...Fujian417601
4Gansu401138.39458126268236{"rings": [[[97.1721363070001, 42.793840408000...Gansu134802
cols_2 = ['NAME', 'AREA', 'TOTPOP_CY','SHAPE','Shape__Area', 'Shape__Length']
overlap_rows_china = pd.merge(left = provinces_df[cols_2], right = df_china, how='inner',
                        on = 'NAME')
overlap_rows_china.head()
NAMEAREATOTPOP_CYSHAPEShape__AreaShape__LengthProvince_StateConfirmedRecoveredDeaths
0Anhui140139.79598761795934{"rings": [[[116.36710167, 34.643320083], [116...13.35290432.965496Anhui150606
1Beijing16535.63027622237467{"rings": [[[116.647890001, 41.0513740000001],...<NA><NA>Beijing408809
2Chongqing82390.60069130365055{"rings": [[[108.50186348, 32.20025444], [108....7.70849230.308633Chongqing101206
3Fujian121789.66683338659398{"rings": [[[118.426801682, 28.2953205110001],...10.98910554.634113Fujian417601
4Gansu401138.39458126268236{"rings": [[[97.1721363070001, 42.793840408000...41.08570380.438096Gansu134802

As shown in overlap_rows_china, each province/state in China is now merged while retaining the SHAPE column, and is ready to be rendered as polygons.

Access the reference feature layer of the United States

Next, we need to access the feature service that contains geometry/shape info for all states in the U. S., and merge with the DataFrame depicting COVID-19 statistics.

us_states_item = gis.content.get('99fd67933e754a1181cc755146be21ca')
us_states_item
USA States (Generalized)
USA States (Generalized) provides boundaries for the States of the United States in the 50 states and the District of Columbia.
Feature Layer Collection by esri_dm
Last Modified: August 11, 2022
0 comments, 526939643 views
us_states_flayer = us_states_item.layers[0]
us_states_df = us_states_flayer.query(as_df=True)
us_states_df.columns
Index(['FID', 'STATE_NAME', 'STATE_FIPS', 'SUB_REGION', 'STATE_ABBR',
       'POPULATION', 'POP_SQMI', 'POP2010', 'POP10_SQMI', 'WHITE', 'BLACK',
       'AMERI_ES', 'ASIAN', 'HAWN_PI', 'HISPANIC', 'OTHER', 'MULT_RACE',
       'MALES', 'FEMALES', 'AGE_UNDER5', 'AGE_5_9', 'AGE_10_14', 'AGE_15_19',
       'AGE_20_24', 'AGE_25_34', 'AGE_35_44', 'AGE_45_54', 'AGE_55_64',
       'AGE_65_74', 'AGE_75_84', 'AGE_85_UP', 'MED_AGE', 'MED_AGE_M',
       'MED_AGE_F', 'HOUSEHOLDS', 'AVE_HH_SZ', 'HSEHLD_1_M', 'HSEHLD_1_F',
       'MARHH_CHD', 'MARHH_NO_C', 'MHH_CHILD', 'FHH_CHILD', 'FAMILIES',
       'AVE_FAM_SZ', 'HSE_UNITS', 'VACANT', 'OWNER_OCC', 'RENTER_OCC',
       'NO_FARMS12', 'AVE_SIZE12', 'CROP_ACR12', 'AVE_SALE12', 'SQMI',
       'Shape__Area', 'Shape__Length', 'GlobalID', 'SHAPE'],
      dtype='object')
DataFrame Merging for U.S. Dataset
df_usa = fset_usa.sdf[['Province_State', 'Confirmed', 'Recovered', 'Deaths']]
df_usa = df_usa.assign(STATE_NAME = df_usa["Province_State"])
df_usa.head()
Province_StateConfirmedRecoveredDeathsSTATE_NAME
0Mississippi918874012821Mississippi
1Grand Princess10303Grand Princess
2Oklahoma1182071016759Oklahoma
3Delaware30439303080Delaware
4Minnesota1645653013509Minnesota
cols_4 = ['STATE_NAME','SHAPE']
overlap_rows_usa = pd.merge(left = us_states_df[cols_4], right = df_usa, 
                            how='inner', on = 'STATE_NAME')
overlap_rows_usa.head()
STATE_NAMESHAPEProvince_StateConfirmedRecoveredDeaths
0Alaska{"rings": [[[-17959594.8053098, 8122953.575198...Alaska29559601338
1California{"rings": [[[-13543710.3257494, 4603367.827345...California11166567095311
2Hawaii{"rings": [[[-17819334.303422, 2512026.7784964...Hawaii34072901655
3Idaho{"rings": [[[-13027307.5891034, 5415905.134774...Idaho49156405131
4Nevada{"rings": [[[-13263990.1054907, 4637763.931898...Nevada835618011417
Access the reference feature layer of world countries
countries_item = gis.content.get('2b93b06dc0dc4e809d3c8db5cb96ba69')
countries_item
World Countries Generalized
World Countries Generalized represents generalized boundaries for the countries of the world.
Feature Layer Collection by esri_dm
Last Modified: June 08, 2023
3 comments, 49892730 views
countries_flayer = countries_item.layers[0]
countries_df = countries_flayer.query(as_df=True)
countries_df.columns
Index(['FID', 'COUNTRY', 'ISO', 'COUNTRYAFF', 'AFF_ISO', 'Shape__Area',
       'Shape__Length', 'SHAPE'],
      dtype='object')
DataFrame Merging for global Dataset

The df_global has listed its Country_Region column with their current best-known names in English, while the countries_df uses their currently best-known equivalents, and this difference in naming countries has created a problem for the merge() operation to understand if the two countries listed in two DataFrame objects are the same. We need to hence run the following cell in order to make country names consistent between the two DataFrames to be merged.

df_global.loc[df_global['Country_Region']=='US', 'Country_Region'] = 'United States'
df_global.loc[df_global['Country_Region']=='Korea, South', 'Country_Region'] = 'South Korea'
df_global.loc[df_global['Country_Region']=='Korea, North', 'Country_Region'] = 'North Korea'
df_global.loc[df_global['Country_Region']=='Russia', 'Country_Region'] = 'Russian Federation'
df_global.loc[df_global['Country_Region']=='Czechia', 'Country_Region'] = 'Czech Republic'
List the top 10 countries with largest numbers

With df_global ready, we can now sort countries or regions by their numbers of confirmed/recovered/death cases, through usage of groupby(), and sort_values().

# sorted by # of confirmed cases
df_global_sum = df_global.groupby('Country_Region').sum(numeric_only=True)[['Confirmed', 'Recovered', 'Deaths']]
df_global_sum_c = df_global_sum.sort_values(by = ['Confirmed'], ascending = False)
df_global_sum_c.head(10)
ConfirmedRecoveredDeaths
Country_Region
United States9524275001050318
India444953590528150
France348989090155508
Brazil345167390684813
Germany324522500148299
South Korea24004887027476
United Kingdom237715720206751
Italy220352910176204
Japan20074857042554
Russian Federation197225560377462
# sorted by death tolls
df_global_sum_d = df_global_sum.sort_values(by = ['Deaths'], ascending = False)
df_global_sum_d.head(10)
ConfirmedRecoveredDeaths
Country_Region
United States9524275001050318
Brazil345167390684813
India444953590528150
Russian Federation197225560377462
Mexico70562690329736
Peru41252080216086
United Kingdom237715720206751
Italy220352910176204
Indonesia63905530157757
France348989090155508
Joining the COVID-19 stats and world countries DataFrames
world_merged1 = pd.merge(df_global_sum_c, countries_df[['COUNTRY', 'SHAPE']], 
                         left_index=True, right_on='COUNTRY',
                         how="left")
world_merged1[['COUNTRY', 'Confirmed','Deaths', 'Recovered']].head(10)
COUNTRYConfirmedDeathsRecovered
238.0United States9524275010503180
104.0India444953595281500
78.0France348989091555080
31.0Brazil345167396848130
85.0Germany324522501482990
211.0South Korea24004887274760
237.0United Kingdom237715722067510
111.0Italy220352911762040
113.0Japan20074857425540
184.0Russian Federation197225563774620

Now, each country/region in world_merged1 is now merged with the SHAPE column, and is ready to be rendered as polygons.

2. Map the COVID-19 cases in China

Next, let us start visualizing the following scenarios targeting at China:

  • Confirmed cases rendered as points, and polygons
  • Death cases rendered as points, and polygons
  • Recovered cases rendered as points, and polygons

Map the confirmed COVID-19 cases in China

We can call the map.content.add method or the data frame's spatial.plot() method to add the specified layer or item (i.e. the FeatureLayer object created as fl) to the map widget. Once we do that, we can use that layer's RendererManager to access the smart_mapping() method to use class breaks rendering to visualize the data, distinguishing by size or color.

Display confirmed cases in China as points

map1 = gis.map('China')
map1
map1.content.add(fl)
render_1 = map1.content.renderer(0)
render_1.smart_mapping().class_breaks_renderer(break_type="size", field="Confirmed", num_classes=5)
map1.zoom = 3
map1.legend.enabled = True

Display confirmed cases in China as polygons

map1b = gis.map('China')
map1b

Screenshot

map1b.basemap.basemap = "topo-vector"
overlap_rows_china.spatial.plot(map1b)
True
render_1 = map1b.content.renderer(0)
render_1.smart_mapping().class_breaks_renderer(break_type="color", field="Confirmed", num_classes=4)
map1b.zoom = 4
map1b.legend.enabled=True

The Map view above (map1b) displays the number of confirmed cases per province in Mainland China. Dark blue polygons refer to provinces with number of confirmed cases in the range of 51,350 - 68,427, and light-blue polygons represent those in the range of 122 - 17,198.

Also, we can save the MapView object into a Web Map item for the purpose of future references and modifications.

map1b.save({'title':'Confirmed COVID-19 Cases in China',
            'snippet':'Map created using Python API showing confirmed COVID-19 cases in China',
            'tags':['automation', 'COVID19', 'world health', 'python']})
Confirmed COVID-19 Cases in China
Map created using Python API showing confirmed COVID-19 cases in ChinaWeb Map by arcgis_python
Last Modified: July 04, 2020
0 comments, 0 views

Map the deaths caused by COVID-19 in China

Display death cases in China as points

map2 = gis.map('China')
map2.basemap.basemap = "topo-vector"
map2

Screenshot

map2.content.add(fl)
render_1 = map2.content.renderer(0)
render_1.smart_mapping().class_breaks_renderer(break_type="size", field="Deaths", num_classes=4)
map2.legend.enabled = True

Display death cases in China as polygons

map2b = gis.map('China')
map2b.basemap.basemap = "topo-vector"
map2b

Screenshot

overlap_rows_china.spatial.plot(map2b)
True
render_1 = map2b.content.renderer(0)
render_1.smart_mapping().class_breaks_renderer(break_type="color", field="Deaths", num_classes=4)

Using the same approach, we can then map the number of death cases per province in Mainland China. With legend displayed, map2b shows us light blue polygons refer to provinces with number of death cases in the range of 0 - 1,128, while dark blue polygons represent those in the range of 3,384 - 4512.

Similarly, we can create an additional deliverable - the Web Map Item created on the active GIS - and then browse the web map in the browser, change its symbology to different color maps in the configuration pane, and/or visualize it again with different looks here.

map2b.zoom = 4
map2b.legend.enabled = True
map2b_item = map2b.save({'title':'COVID-19 Death Cases in China',
                         'snippet':'Map created using Python API showing COVID-19 death cases in China',
                         'tags':['automation', 'COVID19', 'world health', 'python']})

Map the recovered COVID-19 cases in China

Display the recovered cases in China as points

map3 = gis.map("China")
map3
map3.content.add(fl)
render_1 = map3.content.renderer(0)
render_1.smart_mapping().class_breaks_renderer(break_type="size", field="Recovered", num_classes=6)
map3.legend.enabled = True

Display the recovered cases in China as polygons

map3b = gis.map('China')
map3b
overlap_rows_china.spatial.plot(map3b)
True
render_1 = map3b.content.renderer(0)
render_1.smart_mapping().class_breaks_renderer(break_type="size", field="Recovered", num_classes=4)
map3b.zoom = 4
map3b.legend.enabled = True

Same here in map3b, with legend displayed, we can tell orange polygons refer to provinces with number of recovered cases in the range of 42,411 - 63,616, and black polygons represent those in the range of 1 - 21206.

Based on the sets of maps plotted above, the Hubei province has topped all provinces in China no matter when we are looking at the confirmed cases, or the recovered/death tolls.

Again as how we create an additional deliverable - the Web Map Item - on the active GIS in previous two sections, we can then browse the web map in the browser, change its symbology to different color maps in the configuration pane, and/or visualize it again with different looks.

map3b_item = map3b.save({'title':'COVID-19 Recovered Cases in China',
                         'snippet':'Map created using Python API showing COVID-19 recovered cases in China',
                         'tags':['automation', 'COVID19', 'world health', 'python']})

3. Map the COVID-19 cases in the U.S.

Similar to how we map the scenarios in China, visualizing these scenarios targeting at the United States can be divided into these sub-sections:

  • Confirmed cases rendered as points, and polygons
  • Death cases rendered as points, and polygons

Map the confirmed COVID-19 cases in the U. S.

We'll add data to the map in two different ways:

  • calling the add() method of the MapContent (content property) class to add the specified layer or item (i.e. the FeatureLayer object created as fl) to the map widget
  • plot the derived SeDF on the map view directly.

We'll then use the layer's RendererManager to call the smart_mapping() manager and set visualization options to use the ClassedBreaksRenderer differentiating values by size and then by color.

Map the confirmed cases in the U.S. as points

map4 = gis.map("US")
map4
map4.zoom = 3
map4.center = [40.24195886889022, -95.9833441926828]
map4.content.add(fl)
render_1 = map4.content.renderer(0)
render_1.smart_mapping().class_breaks_renderer(break_type="size", field="Confirmed", num_classes=4)
map4.legend.enabled = True

Map the confirmed cases in the U.S. as polygons

map4a = gis.map("US")
map4a

Screenshot

map4a.zoom = 4
map4a.center = [40.24195886889022, -95.9833441926828]
overlap_rows_usa.spatial.plot(map4a)
True
render_1 = map4a.content.renderer(0)
render_1.smart_mapping().class_breaks_renderer(break_type="color", field="Confirmed", num_classes=4, classification_method='equal-interval')
map4a.legend.enabled = True

Map the COVID-19 deaths in the U. S.

Map the death cases in the U.S. as points

map4b = gis.map("US")
map4b
map4b.content.add(fl)
render_1 = map4b.content.renderer(0)
render_1.smart_mapping().class_breaks_renderer(break_type="size", field="Deaths", num_classes=5, classification_method='equal-interval')
map4b.zoom=4
map4b.legend.enabled=True

Map the death cases in the U.S. as polygons

map4c = gis.map("US")
map4c

Screenshot

map4c.zoom = 4
map4c.center = [40.24195886889022, -95.9833441926828]
overlap_rows_usa.spatial.plot(map4c)
True
render_1 = map4c.content.renderer(0)
render_1.smart_mapping().class_breaks_renderer(break_type="color", field="Deaths", num_classes=5, classification_method='equal-interval')
map4c.legend.enabled = True

4. Map the COVID-19 cases globally

Now we have learned how to map COVID-19 cases in China, and the United States, let's take a look at how to map across the globe. For illustration purpose, the rest of this section will only talk about mapping the confirmed cases globally, yet the workflow is almost the same to map deaths and recovered cases globally.

Map the confirmed COVID-19 cases globally

We are going to walk through how the confirmed cases across the globe can be mapped in the Map widget:

  • call the add() method off the content property to add the specified layer or item (i.e. the FeatureLayer object created as fl) to the map widget
  • plot the derived SeDF on the map view directly

Once the layer is added to the map, we can access the RendererManager using the renderer property, and subsequently call the smart_mapping() to render the data and visualize using size and color to differentiateranges of values.

Map the global confirmed cases as points

map5a = gis.map("Italy")
map5a

Screenshot

map5a.content.add(fl)
render_1 = map5a.content.renderer(0)
render_1.smart_mapping().class_breaks_renderer(break_type="size", field="Confirmed", num_classes=5)
map5a.legend.enabled=True
map5a.zoom = 4

Map the global confirmed cases as polygons

map5b = gis.map("Italy")
map5b

Screenshot

world_merged1.spatial.plot(map5b)
True
render_1 = map5b.content.renderer(0)
render_1.smart_mapping().class_breaks_renderer(break_type="color", field="Confirmed", num_classes=7, classification_method='quantile')
map5b.zoom = 4
map5b.legend.enabled = True

When map5b is created centering Brazil, the legend added along shows that yellow polygons (the 2nd class in the colormap) indicate that the countries are of number of confirmed cases ranging within (28026277, 33631532], and purple polygons represent those ranging between (5605255, 11210511].

5. What's next?

This notebook demonstrates accessing the corona viruses statistics, tabularizing them in DataFrames, and finally mapping the outbreak in different regions or counties. Next step, you can refer to Part 2 notebook for analyzing and charting time-series of the 2019 Novel Coronavirus.

References

[1] https://www.cdc.gov/coronavirus/2019-ncov/about/index.html

[2] https://www.cdc.gov/coronavirus/2019-nCoV/

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.