Logo

dev-resources.site

for different kinds of informations.

Chart of the Week: Creating a WPF Stacked Area Chart to Visualize Wealth Distribution in the U.S.

Published at
4/19/2024
Categories
wpf
chart
desktop
ui
Author
gayathrigithub7
Categories
4 categories in total
wpf
open
chart
open
desktop
open
ui
open
Author
15 person written this
gayathrigithub7
open
Chart of the Week: Creating a WPF Stacked Area Chart to Visualize Wealth Distribution in the U.S.

TL;DR: Learn to visualize wealth distribution in the U.S. from 1990 to 2023 using Syncfusion WPF Stacked Area Chart. Explore a step-by-step guide on data preparation, chart layout design, customization, and more. Dive into insightful analysis with this powerful tool!

Welcome to our Chart of the Week blog series!

Today, we will visualize the U.S. wealth distribution data based on income groups using the Syncfusion WPF Stacked Area Chart.

The WPF Stacked Area Chart is a data visualization tool used to represent the cumulative values of different categories over time. It comprises multiple data series stacked on each other, with the area below the lines filled with colors to differentiate between the categories.

The following image shows the chart we’re going to create. Visualizing the U.S. wealth distribution using WPF Stacked Area Chart

Let’s get started!

Step 1: Gathering the data

Before creating the chart, we should collect the data from the wealth distribution report. We can also download the data in CSV format.

Step 2: Prepare the data for the chart

Let’s design the WealthData class with the Date and Value properties to encapsulate the details of wealth distribution.

Refer to the following code example.

public class WealthData
{
     public string Date { get; set; }
     public double Value { get; set; }
     public WealthData(string date, double value)
     {
         Date = date;
         Value = value;
     }
}
Enter fullscreen mode Exit fullscreen mode

Now, design the LabelItem class with the Content and Position properties to encapsulate the details of custom axis labels.

Refer to the following code example.

public class LabelItem
{
    public string? Content { get; set; }
    public double Position { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Then, configure the HouseHoldWealthData class to organize the assortment of data regarding wealth distribution across income groups over different periods. Subsequently, this data will be stored in an observable collection utilizing the different properties based on income groups.

Refer to the following code example.

public class HouseHoldWealthData
{
     public ObservableCollection<WealthData> Bottom50Data { get; set; }
     public ObservableCollection<WealthData> Next40 { get; set; }
     public ObservableCollection<WealthData> Top9 { get; set; }
     public ObservableCollection<WealthData> Top1 { get; set; }
     public ObservableCollection<WealthData> TopPoint1 { get; set; }

     public List<LabelItem> Labels { get; set; }

     public HouseHoldWealthData()
     {
         Bottom50Data = new ObservableCollection<WealthData>();
         Next40 = new ObservableCollection<WealthData>();
         Top9 = new ObservableCollection<WealthData>();
         Top1 = new ObservableCollection<WealthData>();
         TopPoint1 = new ObservableCollection<WealthData>();
         Labels = new List<LabelItem>();

         ReadCSV();
     }
}
Enter fullscreen mode Exit fullscreen mode

Then, the CSV data will be converted to a data collection using the ReadCSV method. Each collection’s maximum values will be collected to update the custom label position.

Refer to the following code example.

public void ReadCSV()
{
    Assembly executingAssembly = typeof(App).GetTypeInfo().Assembly;
    Stream inputStream = executingAssembly.GetManifestResourceStream("WhealthDistributionSample.dfanetworthlevels.csv");
    List<string> lines = new List<string>();
    if (inputStream != null)
    {
        string line;
        StreamReader reader = new StreamReader(inputStream);
        while ((line = reader.ReadLine()) != null)
        {
            lines.Add(line);
        }
        lines.RemoveAt(0);

        double _bottom50 = 0, _next40 = 0, _top9 = 0, _top1 = 0, _topPoint1 = 0;

        foreach (var dataPoint in lines)
        {
            string[] data = dataPoint.Split(',');
            string[] date = data[0].Split(':');                  

            switch (data[1])
            {
                case "Bottom50":
                    var bottom50value = Convert.ToDouble(data[2]);
                    Bottom50Data.Add(new WealthData(date[0], bottom50value));
                    _bottom50 = Math.Max(bottom50value, _bottom50);
                    break;
                case "Next40":
                    var next40Value = Convert.ToDouble(data[2]);
                    Next40.Add(new WealthData(date[0], next40Value));
                    _next40 = Math.Max(next40Value, _next40);
                    break;
                case "Next9":
                    var next9Value = Convert.ToDouble(data[2]);
                    Top9.Add(new WealthData(date[0], next9Value));
                    _top9 = Math.Max(next9Value, _top9);
                    break;
                case "RemainingTop1":
                    var remainingTop1Value = Convert.ToDouble(data[2]);
                    Top1.Add(new WealthData(date[0], remainingTop1Value));
                    _top1 = Math.Max(remainingTop1Value, _top1);
                    break;
                default:
                    var topPoint1Value = Convert.ToDouble(data[2]);
                    TopPoint1.Add(new WealthData(date[0], topPoint1Value));
                    _topPoint1 = Math.Max(topPoint1Value, _topPoint1);
                    break;
            }

        }
        AddCustomLabels(_bottom50, _next40, _top9, _top1, _topPoint1);               

    }
}
Enter fullscreen mode Exit fullscreen mode

Let’s add the custom labels and position them using the Content and Position properties, respectively, in the Labels collection. Here, we will position the custom labels for each series at their maximum value data point.

Refer to the following code example.

private void AddCustomLabels(double bottom50, double next40, double top9, double top1, double topPoint1)
{
    next40 += bottom50;
    top9 += next40;
    top1 += top9;
    topPoint1 += top1;

    Labels.Add(new LabelItem() { Position = bottom50, Content = "Bottom 50%" });
    Labels.Add(new LabelItem() { Position = next40, Content = "50 - 90%" });
    Labels.Add(new LabelItem() { Position = top9, Content = "90 - 99%" });
    Labels.Add(new LabelItem() { Position = top1, Content = "Top 0.9%" });
    Labels.Add(new LabelItem() { Position = topPoint1, Content = "Top 0.1%" });
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Adding a border to the chart

Before creating the chart, let’s add a border. This helps us organize and visualize the data efficiently.

Refer to the following code example.

<Window x:Class="WealthDistributionSample.MainWindow"
        xmlns:local="clr-namespace:WealthDistributionSample"
        Title="MainWindow" Height="650" Width="879" Background="Black">

  <!—Set border for the chart-->
  <Border Margin="20" 
          BorderThickness="2" 
          BorderBrush="White"  
          CornerRadius="10">
     <!—Create the chart inside the border-->        
  </Border>   

</Window>
Enter fullscreen mode Exit fullscreen mode

Step 4: Configure the Syncfusion WPF Charts control

Now, configure the Syncfusion WPF Charts control utilizing this documentation.

Refer to the following code example.

<charts:SfChart x:Name="chart">                

  <charts:SfChart.PrimaryAxis>
   <charts:CategoryAxis/>
  </charts:SfChart.PrimaryAxis>

  <charts:SfChart.SecondaryAxis>
   <charts:NumericalAxis/>
  </charts:SfChart.SecondaryAxis>

</charts:SfChart>
Enter fullscreen mode Exit fullscreen mode

Step 5: Bind the data to the WPF Stacked Area Chart

We will utilize the Syncfusion WPF StackingAreaSeries to visualize the wealth distribution data. Ensure that the HouseHoldWealthData class is configured to establish a binding between its properties and the Chart’s DataContext.

Refer to the following code example.

<charts:SfChart>

 <charts:SfChart.DataContext>
  <local:HouseHoldWealthData x:Name="viewModel"/>
 </charts:SfChart.DataContext>                

 <charts:StackingAreaSeries ItemsSource="{Binding Bottom50Data}"
                            XBindingPath="Date" 
                            YBindingPath="Value" />

 <charts:StackingAreaSeries ItemsSource="{Binding Next40}"
                            XBindingPath="Date" 
                            YBindingPath="Value"/>

 <charts:StackingAreaSeries ItemsSource="{Binding Top9}" 
                            XBindingPath="Date" 
                            YBindingPath="Value"/>

 <charts:StackingAreaSeries ItemsSource="{Binding Top1}" 
                            XBindingPath="Date" 
                            YBindingPath="Value”/>

 <charts:StackingAreaSeries ItemsSource="{Binding TopPoint1}"
                            XBindingPath="Date" 
                            YBindingPath="Value"/>

</charts:SfChart>
Enter fullscreen mode Exit fullscreen mode

In the above code example, each series’ XBindingPath and YBindingPath properties are bound with the respective series’ Date and Value properties, respectively.

Step 6: Create the duplicate axis to customize the chart

Let’s showcase the income group details in each series for better visualization. To achieve this, we will use the duplicate Y-axis to display custom labels.

First, we will create the NumericalAxis (Y-axis positioned at the left) in the chart’s Resources property and assign the axis to each series’ YAxis property. This will act as the major Y-axis for the chart’s series.

Then, we will create a secondary Y-axis as a duplicate one (Positioned at the right) to showcase the custom labels. Next, bind the Labels collection to the LabelsSource property and set the PositionPath and ContentPath properties.

Refer to the following code example.

<charts:SfChart>

 <charts:SfChart.Resources>
  <charts:NumericalAxis x:Key="yAxis" 
                        ActualRangeChanged="NumericalAxis_ActualRangeChanged" />
 </charts:SfChart.Resources>
      . . . 

 <charts:SfChart.SecondaryAxis>
  <charts:NumericalAxis x:Name="customAxis 
                        OpposedPosition="True"  
                        ShowGridLines="False" 
                        Interval="0.25" 
                        LabelsSource="{Binding Labels}" 
                        ContentPath="Content" 
                        PositionPath="Position">

   <charts:NumericalAxis.LabelTemplate>
    <DataTemplate>
     <!—using a color converter for returning the border background color based on the label content -->
      <Border Width="70" Background="{Binding LabelContent, Converter= {StaticResource ColorCoverter}}">
       <Label Content="{Binding LabelContent}" FontWeight="Bold" Foreground="Black" HorizontalContentAlignment="Center"/>
      </Border>
    </DataTemplate>
   </charts:NumericalAxis.LabelTemplate>

  </charts:NumericalAxis>
 </charts:SfChart.SecondaryAxis>

 <charts:StackingAreaSeries YAxis="{StaticResource yAxis}" />
 <charts:StackingAreaSeries YAxis="{StaticResource yAxis}" />
 <charts:StackingAreaSeries YAxis="{StaticResource yAxis}" />
 <charts:StackingAreaSeries YAxis="{StaticResource yAxis}" />
 <charts:StackingAreaSeries YAxis="{StaticResource yAxis}" />

</charts:SfChart>
Enter fullscreen mode Exit fullscreen mode

The custom labels will be positioned based on the axis values (EX: 50- 90% ). To achieve this, we will add the values for the Maximum and Minimum properties of the duplicate axis based on the major YAxis’ ActualMaximum and ActualMinimum values.

private void NumericalAxis_ActualRangeChanged(object sender, ActualRangeChangedEventArgs e)
{
    customAxis.Maximum = (double?)e.ActualMaximum;
    customAxis.Minimum = (double?)e.ActualMinimum;
}
Enter fullscreen mode Exit fullscreen mode

Step 7: Customize the chart appearance

Let’s customize the appearance of the Syncfusion WPF Stacked Area Chart to enhance its readability.

Customize the chart header

Refer to the following example to customize the chart header.

. . . 

<charts:SfChart.Header>

 <Border>
  <Grid x:Name="header">

   <Grid.ColumnDefinitions>
    <ColumnDefinition />
    <ColumnDefinition Width="5*"/>
   </Grid.ColumnDefinitions>

   <Image Source="Wealth.png" Grid.Column="0" Margin="0,5,0,5" Width="70" Height="60"/>

   <StackPanel Grid.Column="1"  
               Margin="5,2,0,0" 
               HorizontalAlignment="Left" 
               Orientation="Vertical">
    <Label Content="A Comprehensive Analysis of Household Wealth Distribution" 
           FontSize="22"  
           FontFamily="AntaRegular" 
           Foreground="White"/>

    <Label Content="in the U.S. by Exploring Income Groups."    
           FontSize="22"  
           Margin="0,2,0,0" 
           FontFamily="AntaRegular" 
           Foreground="White"/>
   </StackPanel>
  </Grid>

 </Border>

</charts:SfChart.Header>

. . . 
Enter fullscreen mode Exit fullscreen mode

Customize the axis

Refer to the following code example. Here, we are going to customize the Y-axis in the chart.

<charts:SfChart.Resources>

 <charts:NumericalAxis Interval="50000000"      
                       LabelCreated="NumericalAxis_LabelCreated"      
                       Maximum="146000000” >

  <charts:NumericalAxis.LabelStyle>
   <charts:LabelStyle Foreground="White"/>
  </charts:NumericalAxis.LabelStyle>

  <charts:NumericalAxis.AxisLineStyle>
   <Style TargetType="Line">
    <Setter Property="StrokeThickness" Value="0"/>
   </Style>
  </charts:NumericalAxis.AxisLineStyle>

 </charts:NumericalAxis>

</charts:SfChart.Resources>
Enter fullscreen mode Exit fullscreen mode

Let’s modify the content of the axis labels using the LabelCreated event.

private void NumericalAxis_LabelCreated(object sender, LabelCreatedEventArgs e)
{
     double value = Convert.ToDouble(e.AxisLabel.LabelContent);
     double trillionValue = value / 1000000;
     if(trillionValue <= 100)
     {
         e.AxisLabel.LabelContent = $"${trillionValue}T";
     }
     else
     {
         e.AxisLabel.LabelContent = string.Empty;
         e.AxisLabel.Position = 0;
     }
}
Enter fullscreen mode Exit fullscreen mode

Then, customize the X-axis by referring to the following code example.

<charts:SfChart.PrimaryAxis>

 <charts:CategoryAxis Interval="25" 
                      ShowGridLines="False">
  <charts:CategoryAxis.LabelStyle>
   <charts:LabelStyle Foreground="White"/>
  </charts:CategoryAxis.LabelStyle>
 </charts:CategoryAxis>

</charts:SfChart.PrimaryAxis>
Enter fullscreen mode Exit fullscreen mode

Customize the chart series

Now, customize each stacked area series’ color using the Interior property.

.. . 
<charts:StackingAreaSeries Interior="#A94438" />
<charts:StackingAreaSeries Interior="#CD5C08" />
<charts:StackingAreaSeries Interior="#E8C872" />
<charts:StackingAreaSeries Interior="#BBE2EC" />
<charts:StackingAreaSeries Interior="#DFF5FF" />
 . . . 
Enter fullscreen mode Exit fullscreen mode

Adding annotations to the chart

Next, we’ll enhance the chart’s readability with the Text Annotation to provide contextual insights.

<charts:SfChart.Annotations>

 <charts:TextAnnotation CoordinateUnit="Axis" Y1="100000000" X1="70.60" >

  <charts:TextAnnotation.ContentTemplate>
   <DataTemplate>
    <StackPanel>
     <TextBlock Text="The share of wealth held by the top 0.1% has reached its highest point to date."  
                Foreground="White" 
                FontSize="10" 
                FontWeight="Medium" Width="105" Height="60"  
                TextAlignment="Justify" 
                TextWrapping="Wrap"/>
    </StackPanel>
   </DataTemplate>
  </charts:TextAnnotation.ContentTemplate>

 </charts:TextAnnotation>

 <charts:TextAnnotation CoordinateUnit="Axis" Y1="18000000" X1="75.60" >

  <charts:TextAnnotation.ContentTemplate>
   <DataTemplate>
    <StackPanel>
     <TextBlock Text="In 2011, the bottom 50% reached a historically low share of wealth, at just 0.4%."  
                Foreground="Black"
                FontSize="9" 
                FontWeight="Medium" Width="120" Height="50"  
                TextAlignment="Justify" 
                TextWrapping="Wrap"/>
    </StackPanel>
   </DataTemplate>
  </charts:TextAnnotation.ContentTemplate>

 </charts:TextAnnotation>

</charts:SfChart.Annotations>
Enter fullscreen mode Exit fullscreen mode

After executing these code examples, we will get the output that resembles the following image.

Visualizing the U.S. wealth distribution using WPF Stacked Area Chart

Visualizing the U.S. wealth distribution using WPF Stacked Area Chart

GitHub reference

For more details, refer to visualizing the U.S. wealth distribution data using the WPF Stacked Area Chart GitHub demo.

Conclusion

Thanks for reading! In this blog, we’ve seen how to visualize data on wealth distribution in the U.S. based on income groups using the Syncfusion WPF Stacked Area Chart. We strongly encourage you to follow the steps outlined in this blog and share your thoughts in the comments below.

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

You can also contact us through our support forums, support portal, or feedback portal. We are always happy to assist you!

Related blogs

wpf Article's
30 articles in total
Favicon
[WPF] Draw Tree Topology
Favicon
What’s New in WPF Diagram: 2024 Volume 4
Favicon
Implementing Full Transparency No Frame and Acrylic Effects in Avalonia UI
Favicon
𝗚𝗲𝘁 𝗗𝗲𝘃𝗘𝘅𝗽𝗿𝗲𝘀𝘀 .𝗡𝗘𝗧 𝗠𝗔𝗨𝗜 𝗖𝗼𝗻𝘁𝗿𝗼𝗹𝘀 𝗳𝗼𝗿 𝗙𝗿𝗲𝗲 𝗕𝗲𝗳𝗼𝗿𝗲 𝗗𝗲𝗰𝗲𝗺𝗯𝗲𝗿 𝟯𝟭, 𝟮𝟬𝟮𝟰!
Favicon
Por onde anda o WPF?
Favicon
Streamlining .NET Development with Practical Aspects
Favicon
Creating a Dynamic WPF Chart Dashboard to Showcase 2024 Women’s T20 World Cup Statistics
Favicon
In-Depth Technical Analysis of XAML-Based Frameworks and Cross-Platform Project Architecture Design
Favicon
Semantic Searching using Embedding in WPF DataGrid
Favicon
Integrating AI-Powered Smart Location Search in WPF Maps
Favicon
Create a WPF Multi-Bar Chart to Visualize U.S. vs. China Superpower Status
Favicon
AI-Powered Smart Paste in WPF Text Input Layout for Effortless Data Entry
Favicon
Latest LightningChart .NET Release: v.12.1.1 is out now!
Favicon
Create a WPF FastLine Chart to Analyze Global Population Trends by Age Group
Favicon
Introducing AI-Powered Smart Components & Features in Syncfusion Desktop Platforms
Favicon
Chart of the Week: Clean and Preprocess E-Commerce Website Traffic Data Using an AI-Powered Smart WPF Chart
Favicon
Everything You Need to Know About WPF Gantt Control
Favicon
Chart of the Week: Creating a WPF Chart Dashboard to Analyze 2024 T20 World Cup Statistics
Favicon
What’s New in WPF Gantt Chart: 2024 Volume 2
Favicon
Chart of the Week: Creating a WPF Doughnut Chart to Visualize the New European Parliament’s Composition in 2024
Favicon
Chart of the Week: Creating a WPF Pie Chart to Visualize the Percentage of Global Forest Area for Each Country
Favicon
Chart of the Week: Creating a WPF Range Bar Chart to Visualize the Hearing Range of Living Beings
Favicon
Chart of the Week: Creating a WPF Sunburst Chart to Visualize the Syncfusion Chart of the Week Blog Series
Favicon
Chart of the Week: Creating a WPF Stacked Area Chart to Visualize Wealth Distribution in the U.S.
Favicon
Elevating Automation: Mastering PowerShell and C# Integration with Dynamic Paths and Parameters
Favicon
Navigate PDF Annotations in a TreeView Using WPF PDF Viewer
Favicon
Chart of the week: Creating a WPF 3D Column Chart to Visualize the Panama Canal’s Shipment Transit Data
Favicon
Improve Real-Time WPF Visualization of ECG Signals With SciChart
Favicon
Race Strategy Analysis using SciChart WPF
Favicon
Chart of the Week: Creating a WPF Chart Dashboard to Visualize the 2023 World Billionaires List

Featured ones: