FlexChart | ComponentOne
Chart Types / Statistical Charts / WinForms Pareto Chart
In This Topic
    WinForms Pareto Chart
    In This Topic

    Pareto charts graphically summarize the process problems in ranking order from the most frequent to the least one. These charts comprise of both a bar and a line chart where bar chart values are plotted in decreasing order of relative frequency while the line chart plots the cumulative total percentage of frequencies. Pareto chart is essentially used in scenarios where the data is broken into different categories, and when the developer needs to highlight the most important factors from a given set of factors. For example, quality control, inventory control, and customer grievance handling are some areas where Pareto chart analysis can be frequently used.

    WinForms Pareto Chart

    With FlexChart, Pareto chart can be easily created by combining ranged histogram chart with any of line, spline, line symbol, or spline symbol chart. First, plot the relative frequency on a ranged histogram in descending order. Then, calculate the cumulative relative frequency in percentage using original data to create another series which is plotted using any of the line, spline, line symbol, or spline symbol chart. This forms Pareto line of the chart which helps in identifying the added contribution of each category.

    private void Form1_Load(object sender, EventArgs e)
    {
        this.flexChart1.ChartType = ChartType.RangedHistogram;
        var histogram = new C1.Win.Chart.RangedHistogram()
        {
            Binding = "Value",
            BindingX = "Name",
            Name = "Count",
            SortDescending = true,
            DataSource = GetPurchaseFactorsData(),
            DataLabel = new DataLabel { Content = "{y:N0}", Position = LabelPosition.Top },
        };
        this.flexChart1.Series.Add((Series)histogram);
        //calculate data for Pareto line
        var histoYs = histogram.GetValues(0);
        var sum = histoYs.Sum();
        var paretoData = new List<PointF>();
        double cumulativeSum = 0;
        for (int i = 0; i < histoYs.Length; i++)
        {
            cumulativeSum += histoYs[i];
            paretoData.Add(new PointF
            {
                X = i,
                Y = (float)(cumulativeSum / sum),
            });
        }
        var paretoLine = new Series
        {
            Name = "Cumulative %",
            ChartType = ChartType.LineSymbols,
            DataSource = paretoData,
            Binding = "Y",
            BindingX = "X",
            AxisY = new Axis
            {
                Position = Position.Right,
                Min = 0,
                Max = 1,
                Format = "P0",
                Title = "Cumulative Percentage",
            },
        };
        this.flexChart1.Series.Add(paretoLine);
    }
    
    Private Sub Form1_Load(sender As Object, e As EventArgs)
        Me.flexChart1.ChartType = ChartType.RangedHistogram
        Dim histogram As RangedHistogram = New C1.Win.Chart.RangedHistogram() With {
              .Binding = "Value",
              .BindingX = "Name",
              .Name = "Count",
              .SortDescending = True,
              .DataSource = GetPurchaseFactorsData(),
              .DataLabel = New DataLabel() With {
                  .Content = "{y:N0}",
                  .Position = LabelPosition.Top
            }
        }
        Me.flexChart1.Series.Add(DirectCast(histogram, Series))
        'calculate data for Pareto line
        Dim histoYs As Double() = histogram.GetValues(0)
        Dim sum As Double = histoYs.Sum()
        Dim paretoData As List(Of PointF) = New List(Of PointF)()
        Dim cumulativeSum As Double = 0
        For i As Integer = 0 To (histoYs.Length - 1)
            cumulativeSum += histoYs(i)
            paretoData.Add(New PointF() With {
                  .X = i,
                  .Y = CSng(cumulativeSum / sum)
            })
        Next
        Dim paretoLine As Series = New Series() With {
              .Name = "Cumulative %",
              .ChartType = ChartType.LineSymbols,
              .DataSource = paretoData,
              .Binding = "Y",
              .BindingX = "X",
              .AxisY = New Axis() With {
                  .Position = Position.Right,
                  .Min = 0,
                  .Max = 1,
                  .Format = "P0",
                  .Title = "Cumulative Percentage"
            }
        }
        Me.flexChart1.Series.Add(paretoLine)
    End Sub
    

    Note that the above sample code uses a custom method named GetPurchaseFactorsData to supply data to the chart. You can set up the data source as per your requirements.

    Random rnd = new Random();
    public List<CategoricalPoint> GetPurchaseFactorsData()
    {
        var data = new List<CategoricalPoint>();
        for (int i = 1; i <= 7; i++)
        {
            int fact = 1;
            foreach (string factor in PurchaseFactors)
            {
                data.Add(new CategoricalPoint
                {
                    Name = factor,
                    Value = (22 - (fact * 3)) * rnd.Next(9, 15),
                });
                fact++;
            }
        }
        return data;
    }
    
    Private rnd As New Random()
    Public Function GetPurchaseFactorsData() As List(Of CategoricalPoint)
        Dim data As List(Of CategoricalPoint) = New List(Of CategoricalPoint)()
        For i As Integer = 1 To 7
            Dim fact As Integer = 1
            For Each factor As String In PurchaseFactors
                data.Add(New CategoricalPoint() With {
                      .Name = factor,
                      .Value = (22 - (fact * 3)) * rnd.[Next](9, 15)
                })
                fact += 1
            Next
        Next
        Return data
    End Function
    Private _purchaseFactors As String()
    Public ReadOnly Property PurchaseFactors() As String()
        Get
            If _purchaseFactors Is Nothing Then
                _purchaseFactors = GetObject("PurchaseFactors").ToString().Split("|"C)
            End If
            Return _purchaseFactors
        End Get
    End Property
    Private _dict As Dictionary(Of String, Object)
    Private Function GetObject(key As String) As Object
        If _dict Is Nothing Then
            Dim json As String = File.ReadAllText("../../Data.json")
            Dim javaScriptSerializer As New JavaScriptSerializer()
            _dict = javaScriptSerializer.Deserialize(Of Dictionary(Of String, Object))(json)
        End If
        Return _dict(key)
    End Function