Welcome to our dashboard!

Reasoning, methodology, and more.

Table of Contents


Our goal in this endeavor was to build a refined, statistically sound, and easy-to-use dashboard for the Maryland public.

We consider the Maryland Department of Health (MDH) official dashboard difficult to use and focused on the wrong indicators. It is far more important, for example, to examine the change in new cases than the number of cumulative cases; additionally, MDH doesn’t adjust any of its data for population, which is crucial in a state as diverse as Maryland.

Our dashboard focuses on the correct indicators, standardized where necessary, to accurately relay the current landscape.

All of our code and scripts are open-source and are located in our GitHub repository.


We composed the dashboard with the JavaScript library D3.js. This offered us the flexibility that we needed in order to design a tool that would effectively adapt to changing data. We made use of Observable, a live code website for D3, to create and host the elements for the dashboard. We could then easily embed the maps and charts from our Observable notebooks into our HTML dashboard. View our Observable notebooks here.

We gathered our data from MDH’s APIs. We wrote the vast majority of our data wrangling methods in R, which is far more straightforward than D3. Some of our data massaging included:

We use cron to automate running the R script and pushing the results to GitHub. If MDH doesn’t update their APIs by 11:00 AM Eastern, however, we must manually run the script and push the results. The Observable notebooks update automatically.


These are the building blocks of the dashboard.


One of D3’s most attractive advantages is the ability to create high quality, lightweight, interactive maps.

Change in cases maps

The most notable difference between our dashboard and the MDH dashboard is our focus on a “change in cases” map. At this point in the pandemic, that Baltimore has recorded 13,000 cases is practically meaningless. Outbreaks and increases in cases are far more important to track. Our map would clearly show, for example, an outbreak at a crab-packing plant in Fishing Creek, a town in the sparsely populated Dorchester County; or a steep increase in cases in the Baltimore region. A map of cumulative cases would be unable to reflect the former and unlikely to show the latter.

To account for variation in daily case counts, our map compares today’s seven-day rolling average in cases with the average from two weeks prior. We then display a color based on the magnitude of the difference.

The map’s scale is diverging, meaning that it displays two colors. Red represents an increase in cases and blue represents a decrease. The darker the color, the larger the difference. The scale will extend as far as necessary and as little as 20 cases for counties or ten for zip codes.

Total cases maps

We have also included the total cases maps present in the MDH dashboard. While these maps do not offer a useful picture of the pandemic right now, they still provide necessary context about the areas disproportionately affected over the course of the pandemic.

Testing map

Similar to the MDH dashboard, we have included a map of tests administered. However, we have adjusted this map by population. We believe this metric is much more effective at quantifying the state’s testing response.

Montgomery County, the most populated jurisdiction in the state, has of course conducted the most tests—but ranks only thirteenth in tests per capita. Kent County, located in the Eastern Shore and the least populated county in Maryland, has administered a volume of tests equivalent to roughly one-third of its population.

Exploring ratios

One experimental feature we’ve implemented on the “total cases by county” and “testing by county” maps, is expressing counts as ratios. While these fractions are simplifications, they do well at contextualizing daunting numbers like case counts. We expect that some viewers may better understand a small ratio—one in four, three in 11, etc.—than a big number.

Topline numbers

We find the MDH topline numbers helpful, so we implemented our own version.

Line charts

Few graphs are better at visualizing change over time than line charts. No other element on our dashboard better represents a holistic view of the pandemic in its entirety.


A chart showing hospitalizations is one of the few true metrics of the pandemic. Early in the crisis, testing was limited to symptomatic individuals with a doctor’s order; now, almost anyone can walk into a testing clinic for free. When we saw a July increase in cases, the following increase in hospitalizations suggested that not all of the cases were of healthy asymptomatic individuals, as some politicians have suggested.

Cases, deaths, and positivity rate

In addition to hospitalizations, we examine cases, deaths, and positivity rate over time. The bars represent the reported number for that day, while the line is a seven-day rolling average. MDH includes a chart with both positivity rate and the number of tests administered, but we strongly believe that charts with two y axes are misleading; we’ll explain further in an upcoming post.

There is no real limit to the number of charts we can include, so we took the position that additional, simple charts are preferable to fewer, more complex graphs. MDH, for example, puts cumulative cases on the same chart as daily increases; it is virtually impossible to discern a pattern in new daily increases when the y axis reaches 100,000 cumulative cases.

Bar charts

Our bar charts display the demographic breakdown of COVID-19 cases, by age, race, and sex. We do not include probable deaths in the visualizations because those bars are small and unnecessarily complicate the overall graphic. We have suspicions about the accuracy of these data, which we’ll address in another blog post.


We felt that it was important to allow the user to easily view the data for themselves. These tables make true on our promise to provide population-adjusted data, allowing for easy comparisons of the counties.

We created the tables using the R package DT.

Cases and deaths

For the cases and deaths tables, we included a 14-day trendline. We made use of the R package sparklines to create the trend lines.

These trend lines were also included on the maps, but we thought it was important to include them once again to underscore their importance.


For the testing table, we decided to include the seven-day average positivity rate instead of a trendline, all of which remained practically flat.