Visualizing Population Growth Data in WPF with LightningChart .NET

Tutorial

Building a WPF charting application for visualizing population growth data with LightningChart .NET (free ZIP project).
Roy Liu

Omar Urbano

Software Engineer

LinkedIn icon
Visualizing-Population-Growth-Data-Cover

Introduction

In this article, we will talk a little about population and the factors that influence its growth. As always, we will accompany the theory with a programming exercise. In this section, we will create a stacked bar chart, read a dataset from a JSON file, process the data, and graph it with LightningChart .NET. We will use the interactive examples application to create the WPF project.

If you do not have it installed yet, I recommend that you do so, as it can serve as a basis for multiple exercises. You can also download the project to experiment with it. Without further ado, let’s get started!

Factors influencing population growth

Talking about this topic can be somewhat controversial, as the results will vary depending on the culture, religion or geographic area. While one might assume that a stable or strong economy can result in a high population, the reality is that it is almost always the opposite.

  • Religion/Culture

In some societies, it is almost a moral obligation to have a large family. This behavior may be largely due to the predominant religion. Many religions have rules about marriage and family, and in some cases, it is a requirement to have many children.

For example, Catholicism and Islam have positions against contraception, or sexual practices without a reproductive purpose. This results in large families and a high birth rate. Another example, in many areas of India, large families are seen as a symbol of prosperity, and offspring are valued. In addition, in some rural communities, women have less access to education and family planning, which can lead to a larger number of children.

In many cultures, such as those in the East or even in Latin America, it is almost a moral obligation for women to marry at an early age and have children. This can be influenced by religion or simply by social status.

  • Government Policies

A country’s policy is another very important factor, whether it promotes the growth of the birth rate or decides to limit it, it will always be based on economic, military and territorial issues to establish rules that affect or benefit the growth of its population.

Some countries with a high GDP per capita offer multiple policies and support for family development, for example, Sweden, Norway, Iceland, Estonia and Portugal occupy the top positions. Despite these benefits, these countries maintain a much smaller population than other countries, which greatly influences the stability of their economy, and therefore allows them to offer these benefits.

On the other hand, countries such as China have established birth control policies, such as the one-child policy in China (1979-2015) or family planning programs. This is due to its enormous population growth since the 20th century, especially after the Chinese Revolution of 1949, where population expansion was encouraged to strengthen the nation.

In the case of countries on the American continent, although there are recommendations on family planning, it is not very common for people to carry them out. In Central and Latin American countries, where the Catholic religion is predominant, it has always been considered the main influence above any political recommendation.

Despite the above, the unstable economic situation in these countries has caused each new generation of people to decide to have small families or simply avoid having children.

  • Migration

Migratory events can significantly affect population growth, not necessarily in relation to birth rates. Whether for political reasons or quality of life reasons, it is more common for countries with better economic, environmental and social conditions to have increasingly constant migratory traffic.

  • Other Factors

With the advancement of technology, the quality of life of human beings has improved significantly, especially in the medical field, resulting in a longer life expectancy. As the mortality rate is reduced, the population size is not affected for a longer time and increases with the addition of new births and migratory events.

On the other hand, access to sexual education and family planning influences the reduction of the population. The economic impact can also affect the reduction of the birth rate because it is increasingly common to set aside cultural and religious aspects and avoid having children or large families.

Climate change, natural disasters, scarcity of resources, and environmental degradation can also influence population growth. These factors can generate population displacement or affect the capacity of a region to sustain its population.

What are the most populated countries in the world? 

The most populous countries in the world, according to the most recent estimates, are:

  1. China: About 1.425 billion people.
  2. India: About 1.43 billion people (India will surpass China in population in the next few years).
  3. United States: About 340 million people.
  4. Indonesia: About 280 million people.
  5. Pakistan: About 240 million people.
  6. Brazil: About 215 million people.
  7. Nigeria: About 220 million people.
  8. Bangladesh: About 175 million people.
  9. Russia: About 145 million people.
  10. Mexico: About 130 million people.

Project Overview

To create our chart, we will use the following Kaggle dataset.

Using the data set:

While the data set offers us many data columns, for this exercise, we will only use two columns:

  • growth Rate: This index will be positive or negative, and the values ​​correspond to data from the year 2023
  • cca3: Abbreviation of the country name to 3 characters
Visualizing Population Growth Data in WPF with LightningChart .NET screenshot

zip icon
Download the project to follow the tutorial

Local Setup

For this project, we need to consider the following requirements to compile the project.

  1. OS: 32-bit or 64-bit Windows Vista or later, Windows Server 2008 R2 or later.
  2. DirectX: 9.0c (Shader model 3 and higher) or 11.0 compatible graphics adapter.
  3. Visual Studio: 2022 for development, not required for deployment.
  4. Platform .NET Framework: installed version 8.0 or newer.

Now go to the next URL and download LightningChart .NET. You’ll then be redirected to a sign-in form where you’ll have to complete a simple sign-up process to get access to your LightningChart account.

Example-LightningChart-Account

After signing in to your account, you can download the SDK “free trial” version that allows you to use important features for this tutorial. When you download the SDK, you’ll have a .exe file like this:

LightningChart-exe-installation

The installation will be a typical Windows process, so please continue with it until it is finished. After the installation, you will see the following programs:

LightningChart-.NET-Installed-Programs

License Manager

In this application, you will see the purchase options. All the projects that you will create with this trial SDK will be available for future developments with all features enabled.

Purchase-Options-LightningChart-.NET

Code Behind

The code for our chart is quite simple, which is one of the strengths of LC .NET. We will begin with the CreateChart() method:

// Specify the path to your JSON file
string projectDirectory = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\"));
string relativePath = $"Data\\countries-table.json"; // Replace with your actual relative path
string filePath = Path.Combine(projectDirectory, relativePath);
// Read and parse the JSON file into a list of WindData objects
List<CountryData> countryData = ReadDataFromFile(filePath);

The first step is to obtain the data from the main dataset. To do this, we will retrieve the WindData.json file, which will be processed by the ReadDataFromFile method. The result will be a countryData list, which we can map later.

Our chart will be limited to 30 countries, to not visually saturate the chart. The series count variable refers to the number of bar series that will be stacked, in this case there will be 2 (negative and positive).

int countries = 30;
int seriesCount = 2;
double[,] yValues = new double[countries, seriesCount];

for (int i = 0; i < countries; i++)
{
    double max = 0;
    double min = 0;

    if (countryData[i].GrowthRate > 0)
    {
        max = countryData[i].GrowthRate;
    }
    else
    { 
        min = countryData[i].GrowthRate;
    }

    yValues[i, 0] = max;
    yValues[i, 1] = min;
}

For each country, we assign negative and positive values, validating whether they are greater than or less than zero.

Creating the chart

Before we start modifying or configuring properties, we must stop the continuous drawing of the chart, to avoid problems when processing data and high resource consumption:

// Create a new _chart.
_chart = new LightningChart
{
    ChartName = "Stacked bars with negative values _chart"
};
_chart.Title.Text = "Maximum and minimum growth rates by country";
_chart.BeginUpdate();

In the following code block, the series are created, and some conditions are executed, so I will explain step by step:

// Create and configure each BarSeries object.
for (int i = 0; i < seriesCount; i++)
{
    // Create BarSeriesValue array to store temperature values.
    BarSeriesValue[] data = new BarSeriesValue[countries];
    for (int j = 0; j < countries; j++)
    {
        data[j].Value = yValues[j, i];
        data[j].Location = j + 1;
        data[j].Text = yValues[j, i] == 0 ? string.Empty : yValues[j, i].ToString();

        if (i == 0)
        {
            // Let's use custom axis ticks to display cca3 name.
            CustomAxisTick tick = new CustomAxisTick(_chart.ViewXY.XAxes[0])
            {
                AxisValue = j + 1,
                LabelText = countryData[j].Cca3
            };

            _chart.ViewXY.XAxes[0].CustomTicks.Add(tick);
        }
    }

Main loop (for (int i = 0; i < seriesCount; i++)):

This loop goes through several series in the chart (indicated by seriesCount), so each time the loop goes around, it works with a different data series.

Creating the data array:

Inside the loop, an array of BarSeriesValue objects called data is created, with a size equal to countries (30). Each BarSeriesValue object will represent the growth data for one country.

Internal loop (for (int j = 0; j < countries; j++)):

This second loop iterates through each country (according to the number of countries, countries). For each country, it assigns values ​​to the BarSeriesValue objects stored in the data array. For each country (j):

  • Growth value (data[j]. Value): The value of the country in that series is assigned from the yValues ​​array.
  • Location (data[j]. Location): A location number is assigned based on the country index (j + 1).
  • Text (data[j]. Text): A text is assigned to be displayed in the graph bar, which is the temperature value, but if the value is zero, no text is displayed.

Special condition for the first series (if (i == 0)):

If we are on the first data series (when i == 0), the code creates custom marks on the X-axis to show the country name (cca3). A CustomAxisTick object is created, which represents a custom tick mark on the X-axis of the chart. This tick mark has:

  • Axis Value (AxisValue): The country index plus 1 (j + 1).
  • Label Text (LabelText): The country code (in Cca3 format, it is probably a three-letter code representing the country).
  • That custom tick is then added to the X-axis of the chart, in the custom ticks collection:(_chart.ViewXY.XAxes[0].CustomTicks).
// Create BarSeries object.
BarSeries bs = new BarSeries(_chart.ViewXY, _chart.ViewXY.XAxes[0], _chart.ViewXY.YAxes[0]);
bs.Title.Text = i > 0 ? "Min Growth Rate" : "Max Growth Rate";
bs.Fill.Color = i > 0 ? Color.FromArgb(255, 238, 76, 57) : Color.FromArgb(255, 57, 76, 238);
bs.Fill.GradientFill = GradientFill.Solid;
bs.LabelStyle.Angle = 0;
bs.LabelStyle.VerticalAlign = BarsTitleVerticalAlign.BarTop;
bs.Values = data;

_chart.ViewXY.BarSeries.Add(bs);

We assign the color and title of the series, depending on whether it is positive or negative. The data array is added to the “values” property of the bar series, and finally, the series is added to the chart.

Configuring bars grouping

// Configure bar view layout.
_chart.ViewXY.BarViewOptions.Grouping = BarsGrouping.ByLocation;
_chart.ViewXY.BarViewOptions.Stacking = BarsStacking.Stack;

BarViewOptions.Grouping allows grouping the bars by value indices, by indices using width fitting or by location values. It brings values from different bar series visually together.

If no grouping is wanted, use BarViewOptions.Grouping.ByLocation and set different Location fields for every BarSeriesValue object.

Use width fitting properties to adjust the spaces between columns and aside them. When no width fitting is used, BarThickness property of the bar series determines the bar width.

The groups can be stacked by setting BarViewOptions.Stacking to Stack or to StackStretchToSumWhen using StackStretchToSum, define the target sum by setting StackSum property. It is 100 by default to represent 100 %.

Configuring Legend Box Position & Orientation

// Configure legend.
_chart.ViewXY.LegendBoxes[0].Layout = LegendBoxLayout.Vertical;
_chart.ViewXY.LegendBoxes[0].Position = LegendBoxPositionXY.SegmentBottomRight;

These lines are configuring various properties of the X-axis on the chart:

_chart.ViewXY.XAxes[0].AutoFormatLabels = false;
_chart.ViewXY.XAxes[0].CustomTicksEnabled = true;
_chart.ViewXY.XAxes[0].MinorDivTickStyle.Visible = false;
_chart.ViewXY.XAxes[0].MajorGrid.Pattern = LinePattern.Dash;
_chart.ViewXY.XAxes[0].AllowUserInteraction = false;
_chart.ViewXY.XAxes[0].Title.Text = "Countries";
_chart.ViewXY.XAxes[0].ValueType = AxisValueType.Number;
_chart.ViewXY.XAxes[0].ScrollMode = XAxisScrollMode.None;
_chart.ViewXY.XAxes[0].SetRange(0.0, countries + 1);
  • Disabling automatic label formatting and minor ticks.
  • Enabling custom tick positions and setting a dashed pattern for the major grid lines.
  • Disabling user interaction with the axis and setting a title and range for the axis.
  • Ensuring that the axis uses numeric values and prevents scrolling along the axis.

This setup is aimed at customizing the appearance and behavior of the X-axis for a chart, likely showing data related to countries. For the Y-axis, we just need to add the title label and set the range:

_chart.ViewXY.YAxes[0].Title.Text = "Growth Rate";
_chart.ViewXY.YAxes[0].SetRange(countryData.Select(x => x.GrowthRate).Take(30).Min(), countryData.Select(x => x.GrowthRate).Take(30).Max());

The range will be specified by getting the minimum and maximum values from the countryData object. These three settings are configuring how zooming and panning interact with the user’s device:

_chart.ViewXY.ZoomPanOptions.DevicePrimaryButtonAction = UserInteractiveDeviceButtonAction.None;
_chart.ViewXY.ZoomPanOptions.WheelZooming = WheelZooming.Vertical;
_chart.ViewXY.ZoomPanOptions.PanDirection = PanDirection.Vertical;
  • The primary mouse button (left click) does not trigger any zoom or pan actions.
  • Zooming can only be done using the vertical scroll wheel (up or down).
  • Panning is restricted to the vertical direction (moving the chart up or down).

This setup is useful when you want to limit user interactions to specific directions (vertical) and prevent unintended actions like zooming or panning with the mouse button or horizontal wheel scrolling. To finish, we need to end the update process and add the new chart object to the XAML grid object:

_chart.EndUpdate();

gridChart.Children.Add(_chart);

Conclusion

Thank you for getting this far. Much of the article focused on the theoretical framework, partly because the topic is both interesting and highly relevant today.

I am originally from Mexico, and I know very well how religious and cultural factors can create strong pressure to start a family. This has influenced my country’s population growth, impacting the economy, environment, education, and more. For that reason, I have always been interested in learning about different cultural ideologies and their repercussions.

While overpopulation affects many countries, others struggle with having too few young people capable of sustaining their communities. These case studies often rely on visual data representations to better understand the trends and their effects.

I chose the stacked bar chart because it is one of the best ways to clearly represent these values. LightningChart .NET makes it easy to create these charts while leveraging the power of the .NET framework.

For this type of study, other charts—such as pie charts or scatter plots—can also be useful. I recommend exploring the interactive examples application, where you can find both 2D and 3D versions of these charts. I hope this article has been helpful and that the example provided serves as a simple starting point for practicing with LC .NET. Bye!

Continue learning with LightningChart

How to Create a Strip Chart

How to Create a Strip Chart

Written by a human | Updated on April 9th, 2025What is a Strip chart application and what are the modern equivalents to it?  Before computers exist or were taking their first steps, a Strip chart was a way to visualize an analog electrical signal. Voltage was...

Data Visualization Template for Electron JS | LightningChart®

Updated on April 4th, 2025 | Written by humanAre you already building cross-platform applications with Electron JS?  In some of our previous articles, we’ve worked on TypeScript projects where we created pie charts and vibration chart applications. And as we...

Bar chart race JavaScript

Bar chart race JavaScript

Updated on April 14th, 2025 | Written by humanBar chart race JavaScript  When I wrote this article, the COVID-19 pandemic was at its peak point. Today, things are much better thanks to vaccinations that continued their steady positive global effect. With this bar...