{"id":305,"date":"2020-06-08T19:37:59","date_gmt":"2020-06-08T19:37:59","guid":{"rendered":"https:\/\/rejupillai.com\/?p=305"},"modified":"2026-04-13T00:09:22","modified_gmt":"2026-04-13T00:09:22","slug":"how-to-build-a-covid-dashboard","status":"publish","type":"post","link":"https:\/\/rejupillai.com\/index.php\/2020\/06\/08\/how-to-build-a-covid-dashboard\/","title":{"rendered":"How to build a Covid Dashboard?"},"content":{"rendered":"\n<p style=\"text-align:center\">Slide and Touch\/Click inside<\/p>\n\n\n\n<style>\n       .errordiv { padding:10px; margin:10px; border: 1px solid #555555;color: #000000;background-color: #f8f8f8; width:500px; }#advanced_iframe {visibility:visible;opacity:1;vertical-align:top;}.ai-info-bottom-iframe { position: fixed; z-index: 10000; bottom:0; left: 0; margin: 0px; text-align: center; width: 100%; background-color: #ff9999; padding-left: 5px;padding-bottom: 5px; border-top: 1px solid #aaa } a.ai-bold {font-weight: bold;}#ai-layer-div-advanced_iframe p {height:100%;margin:0;padding:0}<\/style><script type=\"text\/javascript\">var ai_iframe_width_advanced_iframe = 0;var ai_iframe_height_advanced_iframe = 0;var aiOnloadScrollTop=\"true\";var aiShowDebug=false;\n\t\tif (typeof aiReadyCallbacks === 'undefined') {\n\t\t\tvar aiReadyCallbacks = [];\n\t\t} else if (!(aiReadyCallbacks instanceof Array)) {\n\t\t\tvar aiReadyCallbacks = [];\n\t\t}    function aiShowIframeId(id_iframe) { jQuery(\"#\"+id_iframe).css(\"visibility\", \"visible\");    }    function aiResizeIframeHeight(height) { aiResizeIframeHeight(height,advanced_iframe); }    function aiResizeIframeHeightId(height,width,id) {aiResizeIframeHeightById(id,height);}<\/script><iframe id=\"advanced_iframe\"  name=\"advanced_iframe\"  src=\"\/\/rejupillai.github.io\/covid19-dva\/\"  width=\"100%\"  height=\"400\"  frameborder=\"0\"  border=\"0\"  allowtransparency=\"true\"  loading=\"lazy\"  style=\";border-width: 0px;;border: none;;width:100%;;height:400px;\" ><\/iframe><script type=\"text\/javascript\">var ifrm_advanced_iframe = document.getElementById(\"advanced_iframe\");var hiddenTabsDoneadvanced_iframe = false;\nfunction resizeCallbackadvanced_iframe() {}<\/script><script type=\"text\/javascript\"><\/script><p style=\"display:block !important; visibility:visible !important;margin: -18px 14px 0 0;padding-left: 3px;padding-top:3px;background: white; overflow: hidden; position: relative; line-height:15px;width: fit-content;\"><small style=\"display:block !important;visibility:visible !important\">powered by Advanced iFrame<\/small><\/p>\n\n\n\n<p>It is an interesting challenge every data-science enthusiast has today &#8211; to create meaningful insights. There is a surge in the number of COVID-19 dashboards, developers are creating across the globe. The last article focused more on the&nbsp;<strong><em>Data and ML<\/em><\/strong>&nbsp;part, and this one will focus on the&nbsp;<strong><em>Visualization<\/em><\/strong><em>.<\/em>&nbsp;Afterall a picture says a thousand words! So I created a simple dashboard on&nbsp;<em>Corona Stats by Country;&nbsp;<\/em>the one seen in the banner image. The data is updated 3 times a day. There are many DVA tools in the market both commercial and opensource, some are also combined with business intelligence. The popular commercial ones are &#8211;<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Tableau<\/li><li>Microsoft PowerBI<\/li><li>Sisense<\/li><li>Qlik<\/li><li>Oracle, SAP, TIBCO, Salesforce all have solutions around it.<\/li><\/ul>\n\n\n\n<p>On the OpenSource side, most of the data science frameworks and languages support it, for example, Python has Matplotlib, Pandas, Seaborn, Plotty, etc. And one of the popular&nbsp;<em>(I wouldn&#8217;t say easy, but certainly very comprehensive)&nbsp;<\/em>isD3.js. D3 is the short form for&nbsp;<strong>Data-Driven Documents.<\/strong>&nbsp;So in this article, we will explore, How to create a simple, yet awesome WorldMap with live Corona cases by using nothing, but plain HTML and JS.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img decoding=\"async\" src=\"https:\/\/media-exp1.licdn.com\/dms\/image\/C5112AQFig91cRP-Eiw\/article-inline_image-shrink_1000_1488\/0?e=1597276800&amp;v=beta&amp;t=xxpxPt0aK5Q-lt4HUJJAsYWZPAU7ozFdajCYig96Ecg\" alt=\"\"\/><\/figure><\/div>\n\n\n\n<p>Let&#8217;s do it stepwise :<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: Find a trusted and reliable data source (API) for statistics.<\/h2>\n\n\n\n<p>It is imperative that the data shown on your website is trustable and accurate from the last refresh. There are many organizations tracking the current situation such as Governments, HealthCare agencies, and Universities, specifically the John&nbsp;<a href=\"https:\/\/coronavirus.jhu.edu\/map.html\" target=\"_blank\" rel=\"noreferrer noopener\">Hopkins Center for System Science and Engineering<\/a><\/p>\n\n\n\n<p>There are also independent groups who are building APIs on top of these reliable sources to make it easily consumable for upstream development. I liked below for its comprehensiveness.<\/p>\n\n\n\n<p><a href=\"https:\/\/rapidapi.com\/collection\/coronavirus-covid-19\" target=\"_blank\" rel=\"noreferrer noopener\">RapidAPI<\/a>:<\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/postmanlabs\/covid-19-apis\" target=\"_blank\" rel=\"noreferrer noopener\">PostMan API<\/a>:<\/p>\n\n\n\n<p><a href=\"https:\/\/covidtracking.com\/api\" target=\"_blank\" rel=\"noreferrer noopener\">CovidTracking<\/a><\/p>\n\n\n\n<p>And additionally this&nbsp;<a href=\"https:\/\/blogs.mulesoft.com\/dev\/api-dev\/track-covid-19\/\" target=\"_blank\" rel=\"noreferrer noopener\">blogpost<\/a>&nbsp;from MuleSoft.<\/p>\n\n\n\n<p>I have used CovidTracking&nbsp;<a href=\"https:\/\/covidapi.info\/api\/v1\/global\/latest\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/covidapi.info\/api\/v1\/global\/latest<\/a>&nbsp;for this article.<\/p>\n\n\n\n<p>A sample cURL response looks like this<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"count\": 184,\n  \"date\": \"2020-04-08\",\n  \"result\": [\n    {\n      \"MOZ\": {\n        \"confirmed\": 17,\n        \"deaths\": 0,\n        \"recovered\": 1\n      }\n    },\n    {\n      \"TLS\": {\n        \"confirmed\": 1,\n        \"deaths\": 0,\n        \"recovered\": 0\n      }\n    },\n    {\n      \"GRD\": {\n        \"confirmed\": 12,\n        \"deaths\": 0,\n        \"recovered\": 0\n      }\n    }, ....]<\/code><\/pre>\n\n\n\n<p>The request doesn&#8217;t require any input, the response has countrywide data for today.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: Conceptualize the dashboard.<\/h2>\n\n\n\n<p>This step is where we conceptualize how the dashboard should like, A single dashboard can have multiple viewpoints. For simplicity, here I have chosen only a WorldMap with overlayed statistics when cursor points on the country. The darkness level in the blue color indicates the country with more infected cases. Black ones do not have data; for example Greenland.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/media-exp1.licdn.com\/dms\/image\/C5112AQFJ_FsX55rYJg\/article-inline_image-shrink_1500_2232\/0?e=1597276800&amp;v=beta&amp;t=bMlIp49wcRRElp3s8zIXVY2zawZxPrhwR7PNbeIG6zs\" alt=\"\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3: Transform \/ Clean the data to suit your dashboard requirements.<\/h2>\n\n\n\n<p>The loading of the live CovidTracking data is simple. A JQuery function&nbsp;<strong>$.getJSON&nbsp;<\/strong>makes a GET call to the server identified by the URL. The response is a JSON object stored in the variable&nbsp;<strong><em>items.<\/em><\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>function loadCovid19Data() {\n\n      var url = \"https:\/\/covidapi.info\/api\/v1\/global\/latest\";\n      var items;\n      $.getJSON(url, function (items) {\n        popData = ConvertToTSV(items);\n      });\n      console.log(popData)\n      return popData\n\n    }<\/code><\/pre>\n\n\n\n<p>The unmodified JSON object is then passed to a transformation function&nbsp;<strong>ConvertToTSV()<\/strong>. I needed to fit the response into a specific format required by&nbsp;<strong>D3&#8217;s data loading API<\/strong>. This is the JS transformation code, basically, create an array of Countries, extract Corona statistics and push it to the array. This was required because each country is the &#8216;key&#8217; and the value is of datatype Object&nbsp;<strong>&#8220;MOZ&#8221;: { &#8220;confirmed&#8221;: 17, &#8220;deaths&#8221;: 0, &#8220;recovered&#8221;: 1 },<\/strong>&nbsp;like a dictionary of Objects identified by Country as Key.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>function ConvertToTSV(objArray) {\n      const data = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;\n      var aList = data['result'];\n      var confirmed = [];\n\n      for (i = 0; i &lt; aList.length; i++) {\n        var item = aList[i];\n        for (key in item) {\n            value = item[key];\n            var pop = new Object();\n            pop.id = key;\n            pop.confirmed = value.confirmed;\n            pop.deaths = value.deaths;\n            pop.recovered = value.recovered;\n            confirmed.push(pop);\n\n        }\n      }<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Step 4: JavaScript \/ D3 code<\/strong><\/h2>\n\n\n\n<p>There are lots of sample D3 code available for WorldMap. I have used this&nbsp;<a href=\"http:\/\/bl.ocks.org\/jeremycflin\/b43ab253f3ae02dced07\" target=\"_blank\" rel=\"noreferrer noopener\">variant<\/a>. Note that the WorldMap is an SVG object, with the attribute class equals &#8216;map&#8217;.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code> var svg = d3.select(\"body\")\n      .append(\"svg\")\n      .attr(\"width\", width)\n      .attr(\"height\", height)\n      .append('g')\n      .attr('class', 'map');\n<\/code><\/pre>\n\n\n\n<p>The D3 data loading needs 2 information (either as a file or as a JSON object)<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>world_countries.json, for drawing the WorldMap.<\/li><li>Covid19Tracking JSON response, for our data of interest to be shown.<\/li><\/ol>\n\n\n\n<p>This means we need to &#8220;join&#8221; these 2 data. In this case, the Country Code (also referred to as id here) is the Key used to marry both.<\/p>\n\n\n\n<p>When D3 loads multiple data sources, it is advisable to use a blocking queue() function. If the data is static, it can be loaded as CSV\/TSV file. In my case, since I want to monitor the latest statistics, it needs to be pulled per request using $.getJSON function as described above, unless you are some sort of cache.<\/p>\n\n\n\n<p>Note here that world_countries.json is static information because it simply has the coordinate information to draw the WorldMap.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code> queue()\n                 .defer(d3.json, \"world_countries.json\")\n \/\/Commented     .defer(d3.tsv , \"covid19sats.tsv)\n                 .await(ready);\n\n\n    function ready(error, data) {\n      var confirmedById = {};\n      var deathsById = {};\n      var recoveredById = {};\n      \/\/ process your data ...\n <\/code><\/pre>\n\n\n\n<p>The overlayed statistics is again a simple HTML snippet<br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code> \/\/ Set tooltips\n    var tip = d3.tip()\n      .attr('class', 'd3-tip')\n      .offset([-10, 0])\n      .html(function (d) {\n        return \"&lt;strong>Country: &lt;\/strong>&lt;span class='details'>\" + d.properties.name + \"&lt;br>&lt;\/span>\" + \"&lt;strong>Confirmed: &lt;\/strong>&lt;span class='details'>\" + format(d.confirmed) + \"&lt;\/span>\" + \" &lt;BR> &lt;strong>Deaths: &lt;\/strong>&lt;span class='details'>\" + format(d.deaths) + \"&lt;\/span>\" + \"&lt;strong> &lt;BR> Recovered: &lt;\/strong>&lt;span class='details'>\" + format(d.recovered) + \"&lt;\/span>\";;\n      })\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 5: Test and Host It!<\/h2>\n\n\n\n<p>The best part of D3.js is that it doesn&#8217;t need any special installation. For development and local testing, you just need a browser, but it is advisable to run it under any HTTP webserver. The easiest is way to do it is<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm install http-server\nhttp-server<\/code><\/pre>\n\n\n\n<p>this will run a web server at port 8080, and you can access the page using http:\/\/localhost:8080\/index.html<\/p>\n\n\n\n<p>For hosting it on the internet there are again multiple simple ways &#8211;<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/www.process.st\/how-to-host-a-website-on-google-drive-for-free\/\" target=\"_blank\" rel=\"noreferrer noopener\">Free Webhosting with Gdrive<\/a><\/li><li><a href=\"https:\/\/medium.com\/@kyle.galbraith\/how-to-host-a-website-on-s3-without-getting-lost-in-the-sea-e2b82aa6cd38\" target=\"_blank\" rel=\"noreferrer noopener\">On a public cloud like AWS<\/a>&nbsp;(or Azure \/ GCP )<\/li><li>And easiest of all is the&nbsp;<a href=\"https:\/\/pages.github.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">GitHub Pages<\/a>, which I have used.<\/li><\/ul>\n\n\n\n<p>All source files can be found here in my&nbsp;<a href=\"https:\/\/github.com\/rejupillai\/covid19-dva\" target=\"_blank\" rel=\"noreferrer noopener\">Github<\/a>&nbsp;Repo<\/p>\n\n\n\n<p>That&#8217;s all for now, thanks for reading.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Stay safe, follow social distancing, and take care of your loved ones!<\/h3>\n","protected":false},"excerpt":{"rendered":"<p>Slide and Touch\/Click inside It is an interesting challenge every data-science enthusiast has today &#8211; to create meaningful insights. There is a surge in the number of COVID-19 dashboards, developers are creating across the globe. The last article focused more on the&nbsp;Data and ML&nbsp;part, and this one will focus on<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-305","post","type-post","status-publish","format-standard","hentry","category-techblogs","ct-col-2"],"_links":{"self":[{"href":"https:\/\/rejupillai.com\/index.php\/wp-json\/wp\/v2\/posts\/305","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rejupillai.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rejupillai.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rejupillai.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rejupillai.com\/index.php\/wp-json\/wp\/v2\/comments?post=305"}],"version-history":[{"count":10,"href":"https:\/\/rejupillai.com\/index.php\/wp-json\/wp\/v2\/posts\/305\/revisions"}],"predecessor-version":[{"id":338,"href":"https:\/\/rejupillai.com\/index.php\/wp-json\/wp\/v2\/posts\/305\/revisions\/338"}],"wp:attachment":[{"href":"https:\/\/rejupillai.com\/index.php\/wp-json\/wp\/v2\/media?parent=305"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rejupillai.com\/index.php\/wp-json\/wp\/v2\/categories?post=305"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rejupillai.com\/index.php\/wp-json\/wp\/v2\/tags?post=305"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}