Graph COVID-19 cases per million in C#


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
        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];

        // 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)

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).


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.


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.)


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.


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.


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.


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.

4 Responses to Graph COVID-19 cases per million in C#

  1. Carlos Rum says:

    @RodStephens I am impressed with how you approach your Topics by doing each component yourself for the most part, from what I see you love programming (which is equivalent to inventing), that always takes you to a very high level in the quality of your work. I consider myself with a way of thinking similar to yours. Given this, I can only ask: Have you ever thought about using your skills to develop something unique, something that others consider not possible, something like chasing a dream? I am an employee but for a few years I have been chasing some small dreams so that they give me the resources and one day I can achieve the biggest dreams. In your case, that has not crossed your mind: For example, something that occurs to me (and that I have in the pending portfolio) would be an algorithm to generate predictive trading models in real time. I know that with mathematics and algorithms something very close could be achieved.

    But maybe at the end of the day we don’t all have the same way of seeing things. I don’t know, what do you think of what I said?

    • RodStephens says:

      I play around with minor ideas all the time. Unfortunately I don’t have the resources to do anything too big. I tried to get people interested in a C#-based object-oriented drawing program, but didn’t get must interest. It would be interesting to do something like that, which could be a lot better than MS Paint, but I’m not sure there’s enough market to try to compete as a product.

      You’d better believe there is a lot of work done on predictive trading models! The obvious place where you could find a niche is in smaller gains. For example, a big trading house won’t bother buying 100 shares of a smaller company to make a few hundred dollars, even if the return is a large percentage. It’s just not enough money to make it worth their while. But if someone small did that, it would add up.

  2. Carlos Rum says:

    @RodStephens You’ve heard this before: “Hardly anyone has done it, that’s why it will work” + “Think and get rich.” They are in themselves metaphors, but they hide a great truth. Several years ago I had the feeling that doing math and applying it to sports betting you could find models that the bookmaker has not found yet or that the bookmaker could not handle due to the combination required itself. Over the years of analyzing the situation and taking samples I discovered patterns that were surprising and gave me results enough to motivate even a turtle (For example from 2:40 or 2:60, 2:70, etc.), had managed to find the first traces of what I was looking for, nowadays, after eventually working hard on it and after several dawns I built a set of programs (Web + Win + Console + Triggers == Platform) that allow me to massively “Obtain”, analyze and classify “(according to my models)” the football events that are exposed in a certain betting house in real time. After 3 long years I can finally put my models at real profit and even discover other models or make some revisions with some ML. I’m sure the benefits will come to me. One day when I have more resources and some financial freedom I will dedicate myself to applying the same mechanism to trading (I have already traded and I know a good part of the business), I am confident that I will be able to achieve certain goals. You know, as Musk says, “if you think it’s worth it, you should give it a try”.

    That is why I asked, if having good skills you have not considered something like that before. Anyway I respect your way of thinking. Thanks for posting helpful topics.

Comments are closed.