Graph COVID-19 cases per million in C#


[COVID-19]

The example Align graphs of COVID-19 case data in C# lets you load COVID-19 case data and display it, optionally aligning different countries’ graphs on the left so they start with roughly the same number of cases.

That makes it easier to compare countries that saw their first infections at different times. It’s still hard to compare countries of different sizes. For example, the response by the United States is often compared to that of Italy. The picture above shows their case data. The United States is the curve on top.

From this picture, it looks like Italy is starting to get things under control and the United States is doing much worse. However the United States is a much larger country so it’s reasonable to wonder if that’s true.

This example lets you graph COVID-19 case data normalized to show cases per million people.

Loading Population Data

I got the population data from Worldometer here. This brings up a common issue in programs: how to store and load data. You have a lot of choices and it’s not always obvious where you should put the data. Options include:

  • Database
  • XML/JSON file
  • Text file
  • System Registry
  • Config files
  • Hard-coded

Each of these has advantages and disadvantages. For example, databases provide searchability. Some make it easier to update the data if it changes. Others allow users to share data.

For this program, I decided to hard-code the data into the program. The advantage is that it is simple, easy to understand, I don’t have to write code to interact with an external data source, and I don’t need to include an external data source with the program. It has the disadvantage that it’s relatively hard to change the data because you need to recompile the program to do so. However, I don’t expect the data to change much during the lifetime of this program.

To make the code a little less cluttered, I placed the population data in a separate module. I created a class named Form1_part2, removed the class code, and inserted the following.

public partial class Form1
{
    private void LoadPopulationData()
    {
        Dictionary<string, int> population_dict =
            new Dictionary<string, int>();

        // Population data from
        // https://www.worldometers.info/world-population/population-by-country/.
        population_dict.Add("China", 1439323776);
        population_dict.Add("India", 1380004385);
        population_dict.Add("US", 331002651);    // United States
        population_dict.Add("Indonesia", 273523615);
        ...


        // Add the population data to the country data.
        Console.WriteLine("No population data for these countries:");
        foreach (CountryData country in CountryList)
        {
            if (population_dict.ContainsKey(country.Name))
                country.Population = population_dict[country.Name];
            else
                Console.WriteLine(country.Name);
        }

        // Calculate cases per million.
        // You could do this only when needed.
        // I'm using extra memory so we don't need
        // to do it later.
        foreach (CountryData country in CountryList)
        {
            country.CalculateCasesPerMillion();
        }
    }
}

The class declaration indicates that this is part of the class Form1. That makes it easy to use the Form1 code and it makes it easy for other Form1 code to use this code.

The LoadPopulationData method creates a dictionary and then loads it with country names and population values. I did make a few changes to make this data agree with the COVID-19 data.

After it has loaded the population dictionary, the program loops through the country data previously stored in the list named CountryList. It looks up each country in the population dictionary and saves its population in the new Population field. If it cannot find a country in the population data, the program displays the country’s name in the Console window.

After seeing the list of missing countries, I manually changed names or added data for them. For example, the population data uses the name United States but the COVID-19 data uses the name US, so I changed the population data to match.

The method finishes by looping through the country data again and calling each country’s CalculateCasesPerMillion method, which is described in the next section.

CountryData Code

After the program loads the case and population data, it calls each country’s CalculateCasesPerMillion method to calculate the number of cases per million of population.

// Calculate cases per million.
public void CalculateCasesPerMillion()
{
    // Create the CasesPerMillion array. (Initially all zeros.)
    CasesPerMillion = new float[Cases.Length];
    if (Population > 0)
    {
        Array.Copy(Cases, CasesPerMillion, Cases.Length);
        for (int i = 0; i < Cases.Length; i++)
        {
            CasesPerMillion[i] = CasesPerMillion[i] / Population * 1000000;
        }
    }
}

This method allocates a new CasesPerMillion array with the same number of entries as the Cases array. It then loops through the cases, divides each by the country’s population, multiples by 1 million, and saves the result in the corresponding CasesPerMillion entry.

Note that this uses some extra memory unnecessarily. You could calculate the cases per million values on the fly when they were needed instead of storing them in a separate array. I’m doing it this way for two reasons. First, this is easy to understand. It takes a bit more memory but not all that much and it simplifies the later code.

The second reason for creating a separate CasesdPerMillion array is so the program can easily graph it. Pre-calculating the array allows the program to graph it in the same way that it treats the Cases array. That lets us reuse the previous graphing code with minimal changes.

To reuse the graphing code, I basically renamed the Cases array to SelectedData within the graphing code. Now the program has three references to data arrays: Cases, SelectedData and CasesPerMillion. The following snippet shows those declarations in the CountryData class.

public float[] SelectedData = null;
public float[] Cases = null;
public float[] CasesPerMillion = null;

Now when you select a data set (cases or cases per million), the program sets SelectedData equal to the corresponding array. The graph-drawing code then works as before, drawing whichever data set is pointed to by SelectedData.

That’s the general idea. There are a few other details but they’re not spectacularly interesting so I won’t cover them in detail. For example, I needed to change the graph slightly so it can allow very small values. Some countries have cases per million that are very small or even zero. (Note: In many of those instances, I suspect that the country has COVID-19 cases but they are either unknown or not reported.)

The US and Italy

Let’s look again at the picture at the top of this post showing the graphs for the US (top) and Italy (bottom).


[COVID-19]

It looks like Italy is doing much better than the US, but now look at the following picture, which shows the data in cases per million.


[COVID-19]

Now the two graphs match so closely it’s spooky. In fact, it’s terrifying.

The US graph ends on April 11 with 1,590.31 cases per million. Between March 28 and 29, Italy passed that level going to 1,529.43 cases per million on March 28.

On April 11 Italy had 2,518.47 cases per million. If the US graph continues to follow Italy’s, the US will have around 2,500 cases per million on around April 26. Because the US is a bigger country, that translates into around 827,500 cases. (Versus Italy’s 152,271 cases.)

Scandinavia

Another interesting case is Scandinavia, in particular Sweden. Sweden has implemented a “use your own judgement” strategy for having people stay at home. They are trying to protect those who are most vulnerable but allowing others to decide how much they should stay away from others. The following graph shows the data for the Scandinavian countries.


[COVID-19]

You can see that Sweden did very well until the point where the Norway, Denmark, and Iceland graphs end. Then it started to shoot upwards, quickly passing all of the others.

Furthermore it looks like the graphs for Norway, Denmark, and Iceland are starting to show decreasing slopes but it’s not clear that Sweden and Finland’s curves are flattening.

The following picture shows the graphs per million.


[COVID-19]

This picture shows that Sweden’s cases per million is fairly close to that of Norway, Denmark, and Finland. However, it also shows Sweden’s curve continuing to rise. Unless something changes, Sweden is likely to pass the other countries in cases per million in the next few days.

The unexpected story is Iceland. The earlier picture showed it had far fewer cases in total, but the new graph shows that it has a much higher number of cases per million. In fact, Iceland has one of the highest infection rates in the world, along with several other very small countries.

Iceland has around 341,000 people, but some of the other small countries are so tiny that they fall into areas of statistical uncertainty. For example, the Holy See has an infection rate of almost 10,000 per million, but that’s because they have 8 cases and a population of only 801 people. One infected bus or plane could give these tiny countries huge infection rates.

Iceland is huge compared to the tiny countries, so it seems like it wouldn’t be a single small event that set their rates. Looking into why Iceland sticks out among the Scandinavian countries would probably make an interesting research project. If you have time and figure it out, post a note in the comments below.

Conclusion

Download the example and experiment with it. If you find anything interesting, please post a note in the comments.


Download Example   Follow me on Twitter   RSS feed   Donate




About RodStephens

Rod Stephens is a software consultant and author who has written more than 30 books and 250 magazine articles covering C#, Visual Basic, Visual Basic for Applications, Delphi, and Java.
This entry was posted in drawing, graphics and tagged , , , , , , , , , , , . Bookmark the permalink.

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.