Friday, May 3, 2024
HomeC#Making a .NET MAUI Dynamic Bar Race Chart for the Prime 10...

Making a .NET MAUI Dynamic Bar Race Chart for the Prime 10 Populations within the World


Welcome to our Chart of the Week weblog collection!

As we speak, we’ll visualize the highest 10 international locations by way of world inhabitants from 1960 to 2021 utilizing a bar race chart, additionally known as an animated bar chart.

Bar race charts are efficient instruments for demonstrating adjustments in knowledge over time. The Syncfusion .NET MAUI Cartesian Charts management can be utilized to create a dynamic and interactive bar race chart that captivates viewers and conveys useful info by summarizing a big dataset in a reside visible bar graph, with bars racing to the tip primarily based on rankings.

Check with the next picture.

Visualize population data using .NET MAUI Bar Race Chart

Let’s get began!

Step 1: Collect knowledge for the world inhabitants

Earlier than creating the chart, we have to collect the world inhabitants knowledge. For this demo, we’re getting knowledge from 1960 to 2021.

Step 2: Put together the info for the bar race chart

Create the Mannequin class for holding the inhabitants knowledge with the assistance of the XValueYValueIndexXString, and different properties.

Check with the next code instance.

public Mannequin(int i, string xName, double x, double y)
{
    Index = i;
    XString = xName;
    XValue = x;
    YValue = y;
    ItemColor = brush[i % brush. Count];
}

Generate the info assortment with the assistance of the ViewModel class and Knowledge property. Then, convert the CSV knowledge to a set of inhabitants knowledge utilizing the ReadCSV methodology.

Public Ienumerable<Mannequin> ReadCSV()
{
    Meeting executingAssembly = typeof(App).GetTypeInfo().Meeting;
    Stream inputStream = executingAssembly.GetManifestResourceStream(“BarRaceChart.Assets.Uncooked.populationdata.csv”);

    if (inputStream == null)
    {
        return new Listing<Mannequin>();
    }

    string? Line;
    Listing<string> strains = new Listing<string>();

    utilizing StreamReader reader = new StreamReader(inputStream);
    whereas ((line = reader.ReadLine()) != null)
    {
        strains.Add(line);
    }
    int index = -1;
    double previousYear = 0;
    string previousString = string.Empty;

    return strains.Choose(line =>
    {
        string[] knowledge = line.Cut up(‘,’);
        string currentString = knowledge[0];
        double currentYear = Convert.ToDouble(knowledge[1]);
        if (currentString != previousString)
        {
            if (currentYear == previousYear)
            {
                index = -1;
            }
            index = index + 1;
            previousString = currentString;
        }

        return new Mannequin(index, knowledge[0], currentYear, Convert.ToDouble(knowledge[2]));
    });
}

Knowledge on the populations of all nations is split, filtered by 12 months, and saved within the dataCollection area. Check with the next code instance.

Public ViewModel()
{
    var fashions = new Listing<Mannequin>(ReadCSV());
    dataCollection = new Listing<Listing<Mannequin>>();
    StartYear = fashions.First().Xvalue;
    EndYear = fashions.Final().Xvalue;
    int depend = 0;
    var previousData = new Listing<Mannequin>();
    for (double I = StartYear; I <= EndYear; i++)
    {
        Ienumerable<Mannequin> knowledge = fashions.The place(x => x.Xvalue == i).OrderByDescending(x => x.Yvalue).Take(11);
        dataCollection.Insert(depend, UpdateDataIndex(I, previousData, knowledge));
        depend++;
        previousData = knowledge.ToList();
    }
            
    Knowledge = dataCollection[0];
    12 months = dataCollection[0].First().Xvalue;
}

Step 3: Configure Syncfusion .NET MAUI Cartesian Charts

Subsequent, configure the Syncfusion .NET MAUI Cartesian Charts management utilizing this documentation.

Check with the next code instance.

<chart:SfCartesianChart IsTransposed="True" >
 <chart:SfCartesianChart.Xaxes>
  <chart:NumericalAxis />        
 </chart:SfCartesianChart.Xaxes>

 <chart:SfCartesianChart.Yaxes>
  <chart:NumericalAxis />       
 </chart:SfCartesianChart.Yaxes>
</chart:SfCartesianChart>

Step 4: Create a bar race chart

Let’s create a BarRaceSegment class inherited from the ColumnSegment class of .NET MAUI Cartesian Charts, utilizing the section’s Draw methodology to animate the bar race chart.

public class BarRaceSegment : ColumnSegment
{

    protected override void Draw(ICanvas canvas)
    {
    
      // Do animating bar racing customization right here
      var collection = (Collection as BarRaceSeries);

      if (collection != null)
      {
        var index = collection.ChartSegments.IndexOf(this);

        if (index >= 0 && collection.PreviousSegments != null)
        {
            var previousSegment = collection.PreviousSegments[index] as BarRaceSegment;
            if (previousSegment != null)
            {
                float previousTop = previousSegment.Prime;
                float previousBottom = previousSegment.Backside;
                float previousLeft = previousSegment.Left;
                float previousRight = previousSegment.Proper;

                if (AnimatedValue > 0)
                {
                    float rectTop = GetColumnDynamicAnimationValue(AnimatedValue, previousTop, Prime == 0 ? previousTop : Prime);
                    float rectBottom = GetColumnDynamicAnimationValue(AnimatedValue, previousBottom, Backside);
                    float rectLeft = GetColumnDynamicAnimationValue(AnimatedValue, previousLeft, Left);
                    float rectRight = GetColumnDynamicAnimationValue(AnimatedValue, previousRight, Proper);

                    if (!float.IsNaN(rectLeft) && !float.IsNaN(rectTop) && !float.IsNaN(rectRight) && !float.IsNaN(rectBottom))
                    {

                        canvas.Alpha = Opacity;
                        CornerRadius cornerRadius = collection.CornerRadius;

                        var rect = new Rect() { Left = rectLeft, Prime = rectTop, Proper = rectRight, Backside = rectBottom };

                        canvas.SetFillPaint(AnimatedValue >= 0.5 ? Merchandise.ItemColor : previousSegment.Merchandise.itemColor, rect);

                        if (cornerRadius.TopLeft > 0 || cornerRadius.TopRight > 0 || cornerRadius.BottomLeft > 0 || cornerRadius.BottomRight > 0)
                        {
                            canvas.FillRoundedRectangle(rect, cornerRadius.TopLeft, cornerRadius.TopRight, cornerRadius.BottomLeft, cornerRadius.BottomRight);
                        }
                        else
                        {
                            canvas.FillRectangle(rect);
                        }

                        canvas.DrawString(xString, (float)rect.Left - 5, (float)Math.Spherical(rect.Middle.Y), HorizontalAlignment.Proper);

                        if (AnimatedValue == 1)
                            canvas.DrawString(Merchandise.YValue.ToString("#,###,###,###"), (float)rect.Proper + 2, (float)rect.Middle.Y + 2, HorizontalAlignment.Left);
                        else
                            canvas.DrawString(GetColumnDynamicAnimationValue(AnimatedValue, previousSegment.Merchandise.YValue, Merchandise.YValue).ToString("#,###,###,###"), (float)rect.Proper + 2, (float)rect.Middle.Y + 2, HorizontalAlignment.Left);

                   }
              }
           }
        }
} non-public float GetColumnDynamicAnimationValue(float animationValue, double oldValue, double currentValue) { if (!double.IsNaN(oldValue) && !double.IsNaN(currentValue)) { return (float)((currentValue > oldValue) ? oldValue + ((currentValue - oldValue) * animationValue) : oldValue - ((oldValue - currentValue) * animationValue)); } else { return double.IsNaN(oldValue) ? (float)currentValue * animationValue : (float)(oldValue - (oldValue * animationValue)); } } }

Then, create a BarRaceSeries class inherited from the ColumnSeries class of .NET MAUI Cartesian Charts to visualise the DemoGraphics statistic knowledge.

public class BarRaceSeries : ColumnSeries
{
    public Listing<ChartSegment> PreviousSegments { get; set; }

    public Listing<ChartSegment> ChartSegments { get; set; }

    public BarRaceSeries()
    {
        
    }

    protected override ChartSegment CreateSegment()
    {
        return new BarRaceSegment();
    }

}

Step 5: Bind knowledge to the bar race chart

To visualise the highest 10 international locations on the planet by inhabitants statistics for a given 12 months, implement the BarRaceSeries occasion and bind the info to it.

Check with the next code instance.

<native:BarRaceSeries CornerRadius="0,100,0,100" EnableAnimation="True" ItemsSource="{Binding Knowledge}" XBindingPath="Rating" YBindingPath="YValue" >
</native:BarRaceSeries>

Within the earlier code instance, we’ve sure the Knowledge with the ItemsSource property. Then, the XBindingPath and YBindingPath are sure with the Rating and YValue properties, respectively.

Step 6: Customise the chart look

We are able to improve the looks of the chart by altering the axis parts and including a title.

Check with the next code instance to customise the chart title.

<chart:SfCartesianChart.Title>
 <HorizontalStackLayout Margin="10,10,0,10">
  <Border Margin="10,0,0,10" Stroke="Clear" BackgroundColor="DarkBlue" WidthRequest="20" HeightRequest="70"/>
  <VerticalStackLayout HeightRequest="70" Margin="10,0,0,10">
   <Label VerticalOptions="Begin" Textual content="Demographic Statistics | Prime 10 Populations within the World" Padding="10,5,5,0" FontSize="20" FontAttributes="Daring" />
   <Label VerticalOptions="Begin" Textual content="Since 1960 to 2021"  Padding="10,5,5,0" FontSize="15" FontAttributes="Daring" />
  </VerticalStackLayout>
 </HorizontalStackLayout>
</chart:SfCartesianChart.Title>

Then, configure the axis and modify the axis parts, as proven within the following code instance.

<chart:SfCartesianChart.XAxes>
 <chart:NumericalAxis IsInversed="True" IsVisible="False"  AutoScrollingDelta="10" AutoScrollingMode="Begin" Interval="1" ShowMajorGridLines="False"  />
</chart:SfCartesianChart.XAxes>
<chart:SfCartesianChart.YAxes>
 <chart:NumericalAxis  PlotOffsetStart="110" LabelCreated="NumericalAxis_LabelCreated"  RangePadding="AppendInterval"  >
  <chart:NumericalAxis.MajorTickStyle>
   <chart:ChartAxisTickStyle TickSize="0" />
  </chart:NumericalAxis.MajorTickStyle>
  <chart:NumericalAxis.AxisLineStyle>
   <chart:ChartLineStyle StrokeWidth="0" />
  </chart:NumericalAxis.AxisLineStyle>
 </chart:NumericalAxis>
</chart:SfCartesianChart.YAxes>

Step 7:  Configure the play/pause perform for animating the bar race chart

Render a pause (play/cease) button and an interactive progress bar utilizing the next code.

XAML

<Border Stroke="Clear"  Margin="20,0,0,10" Grid.Row="1" Padding="5">
 <Grid>
  <Grid.ColumnDefinitions>
   <ColumnDefinition Width="50" />
   <ColumnDefinition />
  </Grid.ColumnDefinitions>

  <Border Grid.Column="0" WidthRequest="45" HeightRequest="45" Stroke="Blue" BackgroundColor="White" >
   <Border.GestureRecognizers>
    <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"/>
   </Border.GestureRecognizers>
   <Border.StrokeShape>
    <RoundRectangle CornerRadius="10" />
   </Border.StrokeShape>
   <Label x:Identify="textual content" Textual content="{Binding ProgressString}" TextColor="Blue" HorizontalOptions="Middle" VerticalOptions="Middle" />
  </Border>
  <progress:SfLinearProgressBar Margin="10,20,0,0" Grid.Column="1" Minimal="{Binding StartYear}" Most="{Binding EndYear}" Progress="{Binding 12 months}" TrackHeight="10" TrackCornerRadius="5" ProgressHeight="10" ProgressCornerRadius="5" />
 </Grid>
</Border>

C#

public void Pause()
{
     canStopTimer = true;
     ProgressString = "Play";
}

public async void Play()
{
     ProgressString = "Pause";
     await Job.Delay(500);

     if (Utility.Present != null)
        Utility.Present.Dispatcher.StartTimer(new TimeSpan(0, 0, 0, 1, 500), UpdateData);

        canStopTimer = false;
}

Lastly, we will use the BarRaceSeriesItemsSource property to repeatedly replace the chart with inhabitants knowledge from the highest 10 international locations for annually.

non-public bool UpdateData()
{
    if(dataCollection.Depend < depend + 1)
    {
        ProgressString = "Play";
        depend = 0;
        return false;
    }

    if (canStopTimer) return false;

    MainThread.InvokeOnMainThreadAsync(() =>
    {
        Knowledge = dataCollection[count];
        12 months = dataCollection[count].First().XValue;
        depend++;
    });

    return true;
}

After executing the earlier code examples, the output will seem like the next picture.

Visualizing the top 10 populations in the world using .NET MAUI dynamic Bar Race Chart
Visualizing the highest 10 populations on the planet utilizing .NET MAUI dynamic Bar Race Chart

GitHub reference

For extra particulars, check with the full challenge on GitHub.

Conclusion

Thanks for studying! On this weblog, we’ve created a dynamic bar race chart to visualise the highest 10 populations on the planet utilizing Syncfusion .NET MAUI Cartesian Charts. We encourage you to comply with the steps outlined on this weblog and share your suggestions within the feedback part beneath.

In the event you require any help, please don’t hesitate to contact us through our help discussion boardhelp portal, or suggestions portal. We’re all the time keen that will help you!

Associated blogs

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments