TL;DR: Create a WPF FastLine Chart with plot bands to analyze global population trends by age group, covering both historical data and future projections. This guide includes data preparation, chart configuration, and customization techniques for effective data visualization.
Welcome to the Chart of the Week blog series!
Today, we’ll explore how to analyze global population trends by age group, covering both historical data and future projections. To visualize the data, we’ll create a WPF FastLine Chart with plot bands using the Syncfusion WPF Charts control. We’ll also discuss various customization techniques, such as axis customization, series palette adjustments, and adding plot bands for enhanced data visualization.
Plot bands are useful features that allow us to highlight specific regions within the chart, aiding in analyzing population trends across different age groups. In this example, we’ll look at the global population from 1950 to 2100. The population will be categorized into various age groups, and we’ll use plot bands to shade key periods (future trends), making the data easier to interpret.
Refer to the following image.
Let’s get started!
First, we’ll gather data on the global population categorized by age groups, including historical and projected figures. This data is sourced from the Our World in Data, covering the period from 1950 to 2100. The extracted data is available as a CSV file on GitHub.
Create a Model to represent the global population based on age groups. Refer to the following code example.
public class Model { public double Year { get; set; } public double TotalPopulation { get; set; } public double Under25 { get; set; } public double Between25to64 { get; set; } public double Under15 { get; set; } public double Under4 { get; set; } public double Above65 { get; set; } public Model(double year, double totalPopulation, double under25, double between25to64, double under15, double under4, double above65) { Year = year; TotalPopulation = totalPopulation; Under25 = under25; Between25to64 = between25to64; Under15 = under15; Under4 = under4; Above65 = above65; } }
Then, create a ViewModel to hold two data collections: one for historical population analysis and another for forecasted population analysis. The data is generated from a CSV file.
Refer to the following code example.
public class ViewModel { public ObservableCollection<Model> HistoricalPopulationData { get; set; } public ObservableCollection<Model> ForecastPopulationData { get; set; } public ViewModel() { HistoricalPopulationData = new ObservableCollection<Model>(); ForecastPopulationData = new ObservableCollection<Model>(); ReadCSV("ForecastFastLineChartWithPlotBand.data.csv"); } private void ReadCSV(string fileName) { Assembly executingAssembly = typeof(App).GetTypeInfo().Assembly; Stream inputStream = executingAssembly.GetManifestResourceStream(fileName); if (inputStream != null) { string line; List<String> lines = new List<String>(); StreamReader reader = new StreamReader(inputStream); while ((line = reader.ReadLine()) != null) { lines.Add(line); } lines.RemoveAt(0); for (int i = 0; i < lines.Count; i++) { string input = lines[i]; string[] data = input.Split(','); var year = Convert.ToDouble(data); if (year <= 2023) { var model = new Model( year, Convert.ToDouble(data[3]), Convert.ToDouble(data[10]), Convert.ToDouble(data[7]), Convert.ToDouble(data[11]), Convert.ToDouble(data[13]), Convert.ToDouble(data[5]) ); HistoricalPopulationData.Add(model); } else { var model = new Model( year, Convert.ToDouble(data[4]), Convert.ToDouble(data[9]), Convert.ToDouble(data[8]), Convert.ToDouble(data[12]), Convert.ToDouble(data[14]), Convert.ToDouble(data[6]) ); ForecastPopulationData.Add(model); } } } } }
Now, configure the Syncfusion WPF Charts control using this documentation. The PrimaryAxis and SecondaryAxis will be set as Numerical axis axes to represent the years and population count for each age group.
Refer to the following code example.
<Window x:Class="ForecastFastLineChartWithPlotBand.MainWindow" … xmlns:sync="clr-namespace:Syncfusion.UI.Xaml.Charts;assembly=Syncfusion.SfChart.WPF"> <sync:SfChart x:Name="chart"> <sync:SfChart.PrimaryAxis> <sync:NumericalAxis/> </sync:SfChart.PrimaryAxis> <sync:SfChart.SecondaryAxis> <sync:NumericalAxis/> </sync:SfChart.SecondaryAxis> </Window>
To design multiple FastLine charts, we’ll use Syncfusion WPF FastLineSeries instances. Ensure the ViewModel class is properly configured to bind its properties to the chart’s BindingContext.
Refer to the following code example, where the FastLineSeries is updated with the respective ItemsSource, XBindingPath, and YBindingPath properties.
<Window x:Class="ForecastFastLineChartWithPlotBand.MainWindow" … xmlns:local="clr-namespace:ForecastFastLineChartWithPlotBand" xmlns:sync="clr-namespace:Syncfusion.UI.Xaml.Charts;assembly=Syncfusion.SfChart.WPF"> <sync:SfChart x:Name="chart" HorizontalHeaderAlignment="Left"> <sync:SfChart.DataContext> <local:ViewModel x:Name="viewModel"/> </sync:SfChart.DataContext> …. <sync:FastLineSeries x:Name="series" ItemsSource="{Binding HistoricalPopulationData}" XBindingPath="Year" YBindingPath="TotalPopulation"/> <sync:FastLineSeries x:Name="series1" ItemsSource="{Binding HistoricalPopulationData}" XBindingPath="Year" YBindingPath="Under25"/> <sync:FastLineSeries x:Name="series2" ItemsSource="{Binding HistoricalPopulationData}" XBindingPath="Year" YBindingPath="Between25to64"/> <sync:FastLineSeries x:Name="series3" ItemsSource="{Binding HistoricalPopulationData}" XBindingPath="Year" YBindingPath="Under15"/> <sync:FastLineSeries x:Name="series4" ItemsSource="{Binding HistoricalPopulationData}" XBindingPath="Year" YBindingPath="Under4"/> <sync:FastLineSeries x:Name="series5" ItemsSource="{Binding HistoricalPopulationData}" XBindingPath="Year" YBindingPath="Above65"/> <sync:FastLineSeries x:Name="series6" ItemsSource="{Binding ForecastPopulationData }" StrokeDashArray="2, 2" XBindingPath="Year" YBindingPath="TotalPopulation"/> <sync:FastLineSeries x:Name="series7" ItemsSource="{Binding ForecastPopulationData }" StrokeDashArray="2, 2" XBindingPath="Year" YBindingPath="Under25"/> <sync:FastLineSeries x:Name="series8" ItemsSource="{Binding ForecastPopulationData }" StrokeDashArray="2, 2" XBindingPath="Year" YBindingPath="Between25to64"/> <sync:FastLineSeries x:Name="series9" ItemsSource="{Binding ForecastPopulationData }" StrokeDashArray="2, 2" XBindingPath="Year" YBindingPath="Under15"/> <sync:FastLineSeries x:Name="series10" ItemsSource="{Binding ForecastPopulationData }" StrokeDashArray="2, 2" XBindingPath="Year" YBindingPath="Under4"/> <sync:FastLineSeries x:Name="series11" ItemsSource="{Binding ForecastPopulationData }" StrokeDashArray="2, 2" XBindingPath="Year" YBindingPath="Above65"/> </sync:SfChart> </Window>
Now, let’s improve the readability of the Syncfusion WPF FastLine Chart by customizing its elements.
In the Syncfusion WPF Charts control, the Header property is used to define the chart’s title. You can further adjust the alignment of the header using the HorizontalHeaderAlignment property.
<sync:SfChart x:Name="chart" HorizontalHeaderAlignment="Left"> <sync:SfChart.Header> <Border BorderBrush="White" Margin="0, 0, 0, 10"> <StackPanel Orientation="Horizontal" Margin="-20, 0, 0, 0"> <Grid> <Ellipse Width="5" Height="5" Fill="Gray" Margin="0.5, 15, 0, 0"/> <Path Margin="0,35,0,0" Data="{Binding PathData}" Stretch="Uniform" Stroke="Gray" StrokeThickness="1" Fill="Gray" Width="40" Height="18" RenderTransformOrigin="0.5,0.5"/> </Grid> <Path Margin="-19,-8,0,0" Data="{Binding PathData1}" Stretch="Uniform" Fill="Gray" Width="60" Height="60" RenderTransformOrigin="0.5,0.5"/> <StackPanel> <TextBlock FontSize="22" Margin="5, 0, 0, 0" Text="Global Population by Age Group" FontWeight="Bold"/> <TextBlock FontSize="13" Margin="5, 0, 0, 0" Text="Exploring Population Trends from 1950 to 2023 and Future Projections to 2100." FontWeight="Medium" Foreground="Gray"/> </StackPanel> </StackPanel> </Border> </sync:SfChart.Header> … </sync:SfChart>
Let’s customize the chart axis intervals, gridlines, and labels, as shown in the following code example.
<sync:SfChart.PrimaryAxis> <sync:NumericalAxis ShowGridLines="False" PlotOffsetEnd="5"> </sync:NumericalAxis> </sync:SfChart.PrimaryAxis> <sync:SfChart.SecondaryAxis> <sync:NumericalAxis Interval="2000000000" LabelCreated="NumericalAxis_LabelCreated_1"/> </sync:SfChart.SecondaryAxis>
Refer to the following code example to format the axis labels in billions.
private void NumericalAxis_LabelCreated_1(object sender, LabelCreatedEventArgs e) { if (e.AxisLabel is ChartAxisLabel label && label.LabelContent is string content && content != "0") { var value = double.Parse(content) / 1000000000; label.LabelContent = value.ToString() + "B"; } }
Syncfusion WPF Charts control allows us to add striplines (plotbands) to shade specific regions of the plot area for better data visualization. In this example, the stripline starts from 2024 and extends with a width of 100 units. The background color of the stripline has been customized to represent future population trends.
<sync:SfChart.PrimaryAxis> <sync:NumericalAxis> <sync:NumericalAxis.StripLines> <sync:ChartStripLine Start="2024" Width="100" Background="#dbd9d9" Opacity="0.2"/> </sync:NumericalAxis.StripLines> </sync:NumericalAxis> </sync:SfChart.PrimaryAxis>
The WPF FastLine Chart allows us to customize the series’ fill colors. Additionally, the forecasted FastLine series can be customized with a dotted line using the StrokeDashArray property.
public class Model { public Brush Brush1 = new SolidColorBrush(Colors.BlueViolet); public Brush Brush2 = new SolidColorBrush(Colors.Green); public Brush Brush3 = new SolidColorBrush(Colors.Brown); public Brush Brush4 = new SolidColorBrush(Colors.DeepPink); public Brush Brush5 = new SolidColorBrush(Colors.DarkBlue); public Brush Brush6 = new SolidColorBrush(Colors.Orange); }
var model = viewModel.HistoricalPopulationData; series.Interior = series6.Interior = model.Brush1; series7.Interior = series1.Interior = model.Brush2; series8.Interior = series2.Interior = model.Brush3; series9.Interior = series3.Interior = model.Brush4; series10.Interior = series4.Interior = model.Brush5; series11.Interior = series5.Interior = model.Brush6; series6.StrokeDashArray = new System.Windows.Media.DoubleCollection { 10, 3, 2, 3 }; series7.StrokeDashArray = series8.StrokeDashArray = series9.StrokeDashArray = series10.StrokeDashArray = series11.StrokeDashArray = series6.StrokeDashArray;
The ChartTrackBallBehavior allows tracking of data points closest to the cursor position. The visibility of the trackballcan be controlled using the ShowTrackballInfo property. Additionally, you can customize the appearance of the trackball label using the TrackBallLabelTemplate property.
<sync:SfChart x:Name="chart"> <sync:SfChart.Resources> <local:TooltipValueConverter x:Key="converter"/> <DataTemplate x:Key="labelTemplate"> <Border CornerRadius="5" BorderThickness="1" BorderBrush="Black" Background="White" Padding="10" Margin="8"> <StackPanel Orientation="Vertical"> <TextBlock Foreground="Black" Background="LightGray" FontSize="15" Text="{Binding Item, Converter={StaticResource converter}, ConverterParameter=0}"/> <Grid Margin="0, 5, 0, 0"> <Grid.RowDefinitions> <RowDefinition Height="20"/> <RowDefinition Height="20"/> <RowDefinition Height="20"/> <RowDefinition Height="20"/> <RowDefinition Height="20"/> <RowDefinition Height="20"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="15"/> <ColumnDefinition Width="80"/> <ColumnDefinition Width="50"/> </Grid.ColumnDefinitions> <StackPanel Background="{Binding Item, .Converter={StaticResource converter}, ConverterParameter=7}" Height="10" Width="10" Margin="0, -2, 0, 0" Grid.Column="0" Grid.Row="0"/> <StackPanel Background="{Binding Item, Converter={StaticResource converter}, ConverterParameter=8}" Height="10" Width="10" Margin="0, -2, 0, 0" Grid.Column="0" Grid.Row="1"/> <StackPanel Background="{Binding Item, Converter={StaticResource converter}, ConverterParameter=9}" Height="10" Width="10" Margin="0, -2, 0, 0" Grid.Column="0" Grid.Row="2"/> <StackPanel Background="{Binding Item, Converter={StaticResource converter}, ConverterParameter=10}" Height="10" Width="10" Margin="0, -2, 0, 0" Grid.Column="0" Grid.Row="3"/> <StackPanel Background="{Binding Item, Converter={StaticResource converter}, ConverterParameter=11}" Height="10" Width="10" Margin="0, -2, 0, 0" Grid.Column="0" Grid.Row="4"/> <StackPanel Background="{Binding Item, Converter={StaticResource converter}, ConverterParameter=12}" Height="10" Width="10" Margin="0, -2, 0, 0" Grid.Column="0" Grid.Row="5"/> <TextBlock Foreground="Black" Text="Total" Grid.Row="0" Grid.Column="1"/> <TextBlock Foreground="Black" Text="Under 25" Grid.Row="1" Grid.Column="1"/> <TextBlock Foreground="Black" Text="Ages 25-64" Grid.Row="2" Grid.Column="1"/> <TextBlock Foreground="Black" Text="Under 15" Grid.Row="3" Grid.Column="1"/> <TextBlock Foreground="Black" Text="Under 4" Grid.Row="4" Grid.Column="1"/> <TextBlock Foreground="Black" Text="Above 65" Grid.Row="5" Grid.Column="1"/> <TextBlock Foreground="Black" Text="{Binding Item, Converter={StaticResource converter}, ConverterParameter=1}" Grid.Column="2" Grid.Row="0" HorizontalAlignment="Center"/> <TextBlock Foreground="Black" Text="{Binding Item, Converter={StaticResource converter}, ConverterParameter=2}" Grid.Column="2" Grid.Row="1" HorizontalAlignment="Center"/> <TextBlock Foreground="Black" Text="{Binding Item, Converter={StaticResource converter}, ConverterParameter=3}" Grid.Column="2" Grid.Row="2" HorizontalAlignment="Center"/> <TextBlock Foreground="Black" Text="{Binding Item, Converter={StaticResource converter}, ConverterParameter=4}" Grid.Column="2" Grid.Row="3" HorizontalAlignment="Center"/> <TextBlock Foreground="Black" Text="{Binding Item, Converter={StaticResource converter}, ConverterParameter=5}" Grid.Column="2" Grid.Row="4" HorizontalAlignment="Center"/> <TextBlock Foreground="Black" Text="{Binding Item, Converter={StaticResource converter}, ConverterParameter=6}" Grid.Column="2" Grid.Row="5" HorizontalAlignment="Center"/> </Grid> </StackPanel> </Border> </DataTemplate> </sync:SfChart.Resources> <sync:SfChart.Behaviors> <sync:ChartTrackBallBehavior/> </sync:SfChart.Behaviors> <sync:FastLineSeries x:Name="series" ShowTrackballInfo="False"/> <sync:FastLineSeries x:Name="series1" ShowTrackballInfo="True" TrackBallLabelTemplate="{StaticResource labelTemplate}"/> <sync:FastLineSeries x:Name="series2" ShowTrackballInfo="False" /> <sync:FastLineSeries x:Name="series3" ShowTrackballInfo="False" /> <sync:FastLineSeries x:Name="series4" ShowTrackballInfo="False" /> <sync:FastLineSeries x:Name="series5" ShowTrackballInfo="False" /> <sync:FastLineSeries x:Name="series6" ShowTrackballInfo="False" /> <sync:FastLineSeries x:Name="series7" ShowTrackballInfo="True" TrackBallLabelTemplate="{StaticResource labelTemplate}"/> <sync:FastLineSeries x:Name="series8" ShowTrackballInfo="False" /> <sync:FastLineSeries x:Name="series9" ShowTrackballInfo="False" /> <sync:FastLineSeries x:Name="series10" ShowTrackballInfo="False" /> <sync:FastLineSeries x:Name="series11" ShowTrackballInfo="False" /> </sync:SfChart>
After executing the previous code examples, the output will look like the following image.
For more details, refer to Visualizing the global population trends by age groups using the WPF FastLine Chart GitHub demo.
Thank you for reading! In this blog, we’ve seen how to analyze and forecast global population trends using the Syncfusion WPF FastLine Chart. We strongly encourage you to follow the steps outlined in this blog and share your feedback in the comments section below.
Existing customers can download the new version of Essential Studio® on the License and Downloads page. If you are not a Syncfusion customer, try our 30-day free trial to check out our incredible features.
If you require any assistance, please don’t hesitate to contact us via our support forums, support portal, or feedback portal. We are always eager to help you!