Chart of the Week: Create a .NET MAUI Column Chart to Visualize which Milk Is the Most Sustainable

Jollen Moyani - Mar 8 - - Dev Community

Welcome to the Chart of the Week blog series!

Today, we will explore the statistics of the most sustainable kinds of milk using the Syncfusion .NET MAUI Column Chart.

The .NET MAUI Column Chart, a vertical bar chart, uses vertical bars (called columns) to display values for one or more items. The column chart is likely the most common chart type being used. Points from the series are drawn as columns next to each other. The chart supports zooming, scrolling, tooltips, and selection.

Exploring environmental impact

Plant-based milks like soy, rice, oat, and almond are increasingly popular due to concerns about animal welfare, dietary restrictions, and climate impact. So, determining their environmental friendliness compared to dairy milk is important. Generally, nondairy options surpass cow’s milk in carbon emissions, land use, and water consumption.

The processes involved in creating and shipping almond, oat, soy, and rice milk emit significantly less carbon than dairy milk. Almond milk is the lowest at 0.7kg per liter, followed by oat (0.9kg), soy (1kg), and rice (1.2kg). Plant-based options also require less land, ranging from 0.3 to 0.8 square meters per liter, compared to nine square meters for cow milk.

Contrary to popular belief, the production of almond milk uses less water than dairy, with 371 liters of water per liter of milk compared to 628 liters of water for dairy. Rice milk needs 270 liters of water, while soy and oats are even more efficient, needing only 28 and 48 liters, respectively.

Charting overall environmental impact

Notably, the production of alternative milks like soy and oat has minimal environmental impact compared to dairy, with factors like packaging and transportation becoming significant contributors to their ecological footprint. This comprehensive analysis underscores the importance of considering the entire life cycle of milk production.

The following chart visually presents the data discussed, providing a clear comparison of sustainability numbers between dairy and alternative milk.

Visualizing the most sustainable milk data using .NET MAUI Column ChartNow, let’s explore the steps involved in showcasing these details using the Syncfusion .NET MAUI Column Chart.

Step 1: Gather data for milk

Before proceeding, we need to gather data on the different kinds of milk from the BBC Report for our column chart.

Step 2: Populate the data for the chart

To illustrate the sustainability of different milk types based on distinct factors, we will create a class named MilkSourceModel. This class will encompass the following attributes:

  • Source : Signifying the various plant types utilized in milk production.
  • WaterQuantity : Storing data on the volume of water consumed in milk production.
  • CO2Emission : Storing data on carbon emissions produced during milk production.

Refer to the next code example for further clarification.

public class MilkSourceModel
{
       public string Source { get; set; }
       public double WaterQuantity { get; set; }
       public double CO2Emission { get; set; }

       public MilkSourceModel(string source, double waterQuantity, double cO2Emission)
       {
           Source = source;
           WaterQuantity = waterQuantity;
           CO2Emission = cO2Emission;
       }
}
Enter fullscreen mode Exit fullscreen mode

Next, we’ll generate the data collection illustrating the milk production details using the MilkSourceData class with the Data property.

Refer to the following code example.

public class MilkSourceData : INotifyPropertyChanged
{
     public List<MilkSourceModel> Data { get; set; }

     public MilkSourceData()
     {
          Data = new List<MilkSourceModel>
          {
                new MilkSourceModel("Cow", 628, 3.2),
                new MilkSourceModel("Almond", 371, 0.7),
                new MilkSourceModel("Rice", 270, 1.2),
                new MilkSourceModel("Oat", 48, 0.9),
                new MilkSourceModel("Soy", 28, 1.0),
          };

     }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Configure the Syncfusion .NET MAUI Cartesian Charts

Let’s configure the Syncfusion .NET MAUI Cartesian Charts control using this documentation.

Refer to the following code example.

<chart:SfCartesianChart>

   <chart:SfCartesianChart.XAxes>
       <chart:CategoryAxis>
       </chart:CategoryAxis>
   </chart:SfCartesianChart.XAxes>

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

</chart:SfCartesianChart>
Enter fullscreen mode Exit fullscreen mode

Step 4: Data binding for column chart visualization

Next, we create a column chart to represent the various types of milk. For this purpose, initialize the column chart in the code-behind and segment it as necessary.

Refer to the following code example.

public class ColumnSeriesExt : ColumnSeries
{

}

public class ColumnSegmentExt : ColumnSegment
{

}
Enter fullscreen mode Exit fullscreen mode

To bind the data to the chart, use a customized column instance. Bind the Data collection to the ItemSource property. The XBindingPath and YBindingPath properties should be associated with the Source and WaterQuantity properties, respectively.

<model:ColumnSeriesExt ItemsSource="{Binding Data}" XBindingPath="Source" YBindingPath="WaterQuantity">

</model:ColumnSeriesExt>
Enter fullscreen mode Exit fullscreen mode

Step 5: Customize the column chart

Create an extension of the standard ColumnSeries with the ColumnSeriesExt class. Within this class, override the CreateSegment method. This is a crucial step that enables the creation of a distinct ColumnSegmentExt instance, allowing the chart to display specialized segments.

public class ColumnSeriesExt : ColumnSeries
{
     protected override ChartSegment CreateSegment()
     {
         return new ColumnSegmentExt();
     }
}
Enter fullscreen mode Exit fullscreen mode

Next, implement the ColumnSegmentExt class as a derivative of ColumnSegment. This class contains the drawing logic for the custom column shape, resulting in a visually appealing and personalized column chart.

For a detailed example, please refer to the following code example.

public class ColumnSegmentExt : ColumnSegment
{
    protected override void Draw(ICanvas canvas)
    {
        if (Series is CartesianSeries series && series.ActualYAxis is NumericalAxis yAxis)
        {
            var top = yAxis.ValueToPoint(Convert.ToDouble(yAxis.Maximum ?? double.NaN));
            var trackRect = new RectF() { Left = Left, Top = (float)top, Right = Right, Bottom = Bottom };
            DrawTrackPath(canvas, trackRect);
            canvas.SaveState();
            DrawColumn(canvas);
            canvas.RestoreState();
        }
    }

    private void DrawColumn(ICanvas canvas)
    {
        var path = new PathF();

        #if ANDROID || IOS
        path.MoveTo(Left + 20, Bottom);
        path.LineTo(Right - 20, Bottom);
        path.LineTo(Right - 20, Top);
        path.LineTo(Left + 20, Top);
        path.Close();

        #elif WINDOWS || MACCATALYST
        path.MoveTo(Left + 10, Bottom);
        path.LineTo(Right - 10, Bottom);
        path.LineTo(Right - 10, Top);
        path.LineTo(Left + 10, Top);
        path.Close();

        #endif
        var color = (Fill is SolidColorBrush brush) ? brush.Color : Colors.Transparent;
        canvas.FillColor = color;
        canvas.FillPath(path);
    }

    private void DrawTrackPath(ICanvas canvas, RectF trackRect)
    {
        var path = new PathF();

        #if ANDROID || IOS
        path.MoveTo(Left + 20, Bottom);
        path.LineTo(Right - 20, Bottom);
        path.LineTo(Right - 20, trackRect.Top + 10);
        path.LineTo(Right - 40, trackRect.Top + 5);
        path.LineTo(Right - 40, trackRect.Top);
        path.LineTo(Left + 40, trackRect.Top);
        path.LineTo(Left + 40, trackRect.Top + 5);
        path.LineTo(Left + 20, trackRect.Top + 10);
        path.Close();

        #elif WINDOWS || MACCATALYST
        path.MoveTo(Left + 10, Bottom);
        path.LineTo(Right - 10, Bottom);
        path.LineTo(Right - 10, trackRect.Top + 30);
        path.LineTo(Right - 30, trackRect.Top + 15);
        path.LineTo(Right - 30, trackRect.Top);
        path.LineTo(Left + 30, trackRect.Top);
        path.LineTo(Left + 30, trackRect.Top + 15);
        path.LineTo(Left + 10, trackRect.Top + 30);
        path.Close();

        #endif
        canvas.FillColor = Color.FromRgb(243, 241, 255);
        canvas.FillPath(path);
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 6: Customize the chart appearance

Let’s enhance the .NET MAUI column chart by customizing its properties and style to improve the data readability.

Customizing the chart title

You can customize the chart title to make the chart more visually appealing and informative like in the following code example.

<chart:SfCartesianChart.Title>
 <Grid>
  <Grid.ColumnDefinitions>
   <ColumnDefinition Width="2*" />
   <ColumnDefinition Width="*" />
  </Grid.ColumnDefinitions>
  <Grid Margin="0,0,0,50" Grid.Column="0">
   <Grid.ColumnDefinitions>
    <ColumnDefinition Width="13"/>
    <ColumnDefinition Width="*"/>
   </Grid.ColumnDefinitions>
   <StackLayout Grid.RowSpan="2" Margin="0,5,0,0" Orientation="Vertical" BackgroundColor="#9BD241" />
   <StackLayout Grid.Column="1" Margin="5,0,0,0" HorizontalOptions="Start" Orientation="Vertical">
    <Label Text="Which Milk Is the Most Sustainable?" FontSize="Large" FontAttributes="Bold" TextColor="#666666" FontFamily="AntaRegular"/>
    <Label Text="Based on quantity of water used and CO₂ emitted per liter of milk" FontSize="17" TextColor="Gray" Margin="0,2,0,0" FontFamily="AntaRegular"/>
   </StackLayout>
  </Grid>

  <VerticalStackLayout HorizontalOptions="End" Margin="40,0,0,0" Grid.Column="1">
   <Label Text="CO₂ Emission (in kg)" FontSize="16" FontFamily="AntaRegular" HorizontalOptions="Center" Margin="0,0,0,5"/>

   <Frame BorderColor="#031257" CornerRadius="5" Background="#0DC3ECB2" WidthRequest="{OnPlatform Android=165,iOS=165,Default=180}" Padding="5">
    <Grid>
     <Grid.ColumnDefinitions>
      <ColumnDefinition/>
      <ColumnDefinition/>
      <ColumnDefinition/>
     </Grid.ColumnDefinitions>
     <Image Grid.Row="1" Grid.Column="0" Source="{Binding SourceImage}" Margin="10,0,0,0" HeightRequest="{OnPlatform Android=50,iOS=50, Default=50}"
WidthRequest="{OnPlatform Android=50,iOS=50, Default=50}"/>
     <Image Grid.Row="1" Grid.Column="1" Source="right.png" Margin="15,0,0,0" HeightRequest="50" WidthRequest="40" VerticalOptions="Center"/>
     <Label Grid.Row="1" Grid.Column="2" Text="{Binding EmissionText}" FontFamily="AntaRegular" FontSize="18" Margin="-20,0,-25,0" HorizontalTextAlignment="Center" VerticalTextAlignment="Center"/>
     </Grid>
    </Frame>
  </VerticalStackLayout>
 </Grid>
</chart:SfCartesianChart.Title>
Enter fullscreen mode Exit fullscreen mode

Customizing the chart axis

You can customize the chart axis using the following properties:

  • ShowMajorGridLines : Adjusts the visibility of the major grid lines.
  • LabelStyle : Modifies the style of the axis labels.
  • AxisLineStyle : Alters the style of the axis line.
  • MajorTickStyle : Changes the style of the major tick lines.
  • Title : Customizes the appearance of the axis title.

Refer to the following code example.

<chart:SfCartesianChart.XAxes>
 <chart:CategoryAxis ShowMajorGridLines="False">
 <chart:CategoryAxis.LabelStyle>
   <chart:ChartAxisLabelStyle FontFamily="AntaRegular" TextColor="Black" FontSize="14"/>
 </chart:CategoryAxis.LabelStyle>

 <chart:CategoryAxis.AxisLineStyle>
   <chart:ChartLineStyle StrokeWidth ="0"/>
 </chart:CategoryAxis.AxisLineStyle>

  <chart:CategoryAxis.MajorTickStyle>
   <chart:ChartAxisTickStyle StrokeWidth ="0"/>
  </chart:CategoryAxis.MajorTickStyle>
 </chart:CategoryAxis>
</chart:SfCartesianChart.XAxes>

<chart:SfCartesianChart.YAxes>
 <chart:NumericalAxis ShowMajorGridLines="False" Maximum="800">
  <chart:NumericalAxis.Title>
   <chart:ChartAxisTitle Text="Water use (liters)" FontSize="20" TextColor="Black" FontFamily="AntaRegular" Margin="0,-50,0,0"/>
  </chart:NumericalAxis.Title>

  <chart:NumericalAxis.LabelStyle>
   <chart:ChartAxisLabelStyle TextColor="Transparent"/>
  </chart:NumericalAxis.LabelStyle>

  <chart:NumericalAxis.AxisLineStyle>
   <chart:ChartLineStyle StrokeWidth ="0"/>
  </chart:NumericalAxis.AxisLineStyle>

  <chart:NumericalAxis.MajorTickStyle>
   <chart:ChartAxisTickStyle StrokeWidth ="0"/>
  </chart:NumericalAxis.MajorTickStyle>
 </chart:NumericalAxis>
</chart:SfCartesianChart.YAxes>
Enter fullscreen mode Exit fullscreen mode

Customizing the series appearance

Next, customize the series appearance by specifying the column color.

<model:ColumnSeriesExt Fill="#B8D86D">

</model:ColumnSeriesExt>
Enter fullscreen mode Exit fullscreen mode

Customize the data label appearance

To improve readability, we can activate the chart data labels using the ShowDataLabels property.

<model:ColumnSeriesExt ShowDataLabels="True">

 <chart:ColumnSeries.DataLabelSettings>
  <chart:CartesianDataLabelSettings LabelPlacement="Outer" UseSeriesPalette="False">
   <chart:CartesianDataLabelSettings.LabelStyle>
    <chart:ChartDataLabelStyle FontSize="{OnPlatform Android=11,iOS=11, Default=14}"
 FontFamily="AntaRegular" TextColor="Black"/>
   </chart:CartesianDataLabelSettings.LabelStyle>
  </chart:CartesianDataLabelSettings>
 </chart:ColumnSeries.DataLabelSettings>

</model:ColumnSeriesExt>
Enter fullscreen mode Exit fullscreen mode

In the previous code example, the data labels display information about the water used during the production of the milk.

Enhancing chart interactivity

To augment the informativeness of our column chart, we will integrate selection features and relevant information into the title view. The selection features allow us to highlight a specific data point when it is selected.

In this instance, we include images of a cow and the plants from which milk is made and their carbon emissions values in the title view and enable segment selection. Consequently, the view will show information about the selected segment.

<model:ColumnSeriesExt>

  <chart:ColumnSeries.SelectionBehavior>
    <chart:DataPointSelectionBehavior SelectionBrush="#9BD241" Type="SingleDeselect" SelectedIndex="{Binding SelectedIndex, Mode=TwoWay}"/>
  </chart:ColumnSeries.SelectionBehavior>

</model:ColumnSeriesExt>
Enter fullscreen mode Exit fullscreen mode

In the following code example, we have created the SourceImage , EmissionText , and SelectedIndex properties to store the carbon emissions data.

public class MilkSourceData : INotifyPropertyChanged
{

      private string sourceImage = "";
      public string SourceImage
      {
          get { return sourceImage; }
          set
          {
              if (sourceImage != value)
              {
                  sourceImage = value;
                  OnPropertyChanged(nameof(SourceImage));
              }
          }
      }

      private string emissionText = "";
      public string EmissionText
      {
          get { return emissionText; }
          set
          {
              if (emissionText != value)
              {
                  emissionText = value;
                  OnPropertyChanged(nameof(EmissionText));
              }
          }
      }

      private int selectedIndex;
      public int SelectedIndex
      {
          get { return selectedIndex; }
          set
          {
              selectedIndex = value;
              UpdateCountryAndCount();
              OnPropertyChanged(nameof(SelectedIndex));
          }
      }

      public MilkSourceData()
      {
          SelectedIndex = 1;
      }

      public event PropertyChangedEventHandler? PropertyChanged;
      protected virtual void OnPropertyChanged(string propertyName)
      {
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      }

      private void UpdateCountryAndCount()
      {
          if (SelectedIndex >= 0 && SelectedIndex < Data?.Count)
          {
              SourceImage = Data[SelectedIndex].Source.ToLower() + ".png";
              EmissionText = Data[SelectedIndex].CO2Emission.ToString();
          }
      }
 }
Enter fullscreen mode Exit fullscreen mode

After executing the previous code examples, the output will resemble the following GIF image. Visualizing the most sustainable milk data using .NET MAUI Column Chart

GitHub reference

For more details, refer to Visualizing the most sustainable types of milk using the .NET MAUI Column Chart GitHub demo.

Conclusion

Thank you for reading! In this blog, we have explored how to visualize the data on which milk is most sustainable based on various factors using the Syncfusion .NET MAUI Column Chart. We encourage you to follow the steps outlined in this blog and share your feedback in the comments section below.

Current customers can download the newest version of Essential Studio from the License and Downloads page. If you are not a Syncfusion customer, try our 30-day free trial to check out our features.

If you require assistance, please don’t hesitate to contact us via our support forum, support portal, or feedback portal. We are always eager to help you!

Related blogs

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .