Copied RSS Feed

.NET MAUI

Visualizing Skyscraper Data with .NET MAUI Doughnut Chart and Maps

TL;DR: Let’s see how to visualize skyscraper data with Syncfusion .NET MAUI Semi-Doughnut Chart and Maps controls. We’ll gather data, create a semi-doughnut chart with a center view by adding Maps control, and customize visuals like angles, colors, and interactive features. Enhance your app with geographic context and dynamic data visualization for a richer user experience.

Welcome to the Chart of the Week blog series!

Data visualization is an essential part of modern applications, and combining charts with maps can elevate the user experience by providing geographic context to your data.

In this blog, we’ll explore how to create a Semi-Doughnut Chart with integrated Maps using the Syncfusion .NET MAUI Circular Charts and Maps controls.

Understanding Doughnut Charts and Maps

The Circular Chart is a versatile control representing data in a circular format. A semi-doughnut chart presents data in a semi-circle, ideal for scenarios where screen space is limited or when combining charts with other visual elements.

The Maps control allows us to integrate rich geographic data visualizations into your .NET MAUI apps. You can add layers, markers, and shapes to create dynamic maps that perfectly complement your chart data.

Visualizing skyscraper data in urban landscapes

In today’s urban landscape, skyscrapers symbolize innovation, architectural prowess, and economic strength. To highlight cities with the most skyscrapers, we use .NET MAUI to create an interactive doughnut chart paired with maps. This integration not only emphasizes statistical data but also provides geographic context, grasping insights immediately.

The following image shows the semi-doughnut chart that we intend to create.

Let’s explore the steps involved in analyzing the details of the top 10 cities with the most skyscrapers!

Step 1: Gathering data for the chart

To begin, we need to gather data for the chart. We’ll refer to Wikipedia, which offers comprehensive information on cities with the most skyscrapers.

Step 2: Prepare the data for the chart

Next, define a SkyscrapersModel class to encapsulate information about each country, city, and the number of skyscrapers. This model ensures that the information is well-organized and easily accessible for visualization.

By representing each record with a dedicated class, you can seamlessly bind data to both the Doughnut Chart and Maps.

Refer to the following code example:

public class SkysCrapersModel
{
    public string? City { get; set; }
    public string? Country { get; set; }
    public int Count { get; set; }
}

Now, create a SkysCrapersData class to manage the collection of skyscraper details. This SkysCrapersData will serve as the intermediary between your data and the user interface, facilitating data binding.

Refer to the following code example:

public class SkysCrapersData : INotifyPropertyChanged
{
    public ObservableCollection<SkysCrapersModel> Data { get; set; }

    public SkysCrapersData()
    {
        Data = new ObservableCollection<SkysCrapersModel>
        {
            new SkysCrapersModel { City = "Hong-Kong", Country = "Hong Kong", Count = 558 },
            new SkysCrapersModel { City = "Shenzhen", Country = "China", Count = 415 },
            new SkysCrapersModel { City = "New York", Country = "US", Count = 318 },
            new SkysCrapersModel { City = "Dubai", Country = "UAE", Count = 263 },
            new SkysCrapersModel { City = "Guangzhou", Country = "China", Count = 194 },
            new SkysCrapersModel { City = "Shanghai", Country = "China", Count = 194 },
            new SkysCrapersModel { City = "Kuala Lumpur", Country = "Malaysia", Count = 179 },
            new SkysCrapersModel { City = "Tokyo", Country = "Japan", Count = 176 },
            new SkysCrapersModel { City = "Wuhan", Country = "China", Count = 169 },
            new SkysCrapersModel { City = "Chongqing", Country = "China", Count = 145 },
        };
    }
}

Step 3: Configure the Syncfusion .NET MAUI Circular Charts

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

 Refer to the following code example.

<Grid>
    <chart:SfCircularChart>
    </chart:SfCircularChart>
</Grid>

Step 4: Bind the data to the .NET MAUI Doughnut Chart

Let’s bind the data to the .NET MAUI DoughnutSeries to visualize the top 10 cities for skyscrapers.

<chart:SfCircularChart>
  <chart:DoughnutSeries 
        x:Name="series" 
        ItemsSource="{Binding Data}" 
        XBindingPath="City" 
        YBindingPath="Count">
  </chart:DoughnutSeries>
</chart:SfCircularChart>

Step 5: Customizing the chart appearance

Let’s enhance the aesthetics and readability of the .NET MAUI Semi-Doughnut Chart by customizing its elements, like title, series, interaction features, and center view.

Adding the chart title

Adding a title is simple and intuitive. It helps users understand the content of the chart more effectively. Refer to the following code example to customize the chart title.

<chart:SfCircularChart.Title>

    <StackLayout HorizontalOptions="Center" Orientation="Horizontal" Margin="0,10,0,20">

        <Path Data="{StaticResource PathData}" 
              Stroke="#666666" 
              VerticalOptions="Center" 
              HorizontalOptions="Start" />

        <Label Text="Top 10 Cities with the Most Skyscrapers" 
               FontSize="{OnPlatform Android=16, iOS=16, Default=20}"
               VerticalTextAlignment="Center" 
               Margin="5,0,0,0" 
               FontAttributes="Bold" 
               TextColor="#666666" 
               LineBreakMode="WordWrap"/>
               
    </StackLayout>

</chart:SfCircularChart.Title>

Customize the Doughnut Chart angle, color, and size

Refer to the following example code to customize the chart’s size, angle, and color using the Radius, InnerRadius, StartAngle, EndAngle, and PaletteBrushes properties.

XAML

<chart:DoughnutSeries 
    StartAngle="150" 
    EndAngle="390" 
    PaletteBrushes="{Binding CustomBrushes}" 
    Radius="0.9" 
    InnerRadius="0.75" 
    ExplodeRadius="15">
</chart:DoughnutSeries>

C#

public class SkysCrapersData : INotifyPropertyChanged
{
    public ObservableCollection<Brush> CustomBrushes { get; set; }

    public SkysCrapersData()
    {
        CustomBrushes = new ObservableCollection<Brush>()
        {
            new SolidColorBrush(Color.FromArgb("#9e0142")),
            new SolidColorBrush(Color.FromArgb("#d53e4f")),
            new SolidColorBrush(Color.FromArgb("#f46d43")),
            new SolidColorBrush(Color.FromArgb("#fdae61")),
            new SolidColorBrush(Color.FromArgb("#fee08b")),
            new SolidColorBrush(Color.FromArgb("#e6f598")),
            new SolidColorBrush(Color.FromArgb("#abdda4")),
            new SolidColorBrush(Color.FromArgb("#66c2a5")),
            new SolidColorBrush(Color.FromArgb("#3288bd")),
            new SolidColorBrush(Color.FromArgb("#5e4fa2")),
        };
    }
}

Adding a center view and interactivity support to the chart

Now, configure the CenterView property of the DoughnutSeries to add any view to the center of the chart. This feature helps us to provide additional information about the data represented.

In this example, we’ll add the SfMaps control at the center of the chart and enable the explode interactivity feature to make it more engaging and visually appealing.

The .NET MAUI Maps control is a powerful data visualization control for displaying statistical information over a geographical area. It offers highly interactive and customizable features like selection, tooltips, legends, markers, bubbles, and color mapping. With Maps control, you can visualize population density, sales, political boundaries, weather patterns, election results, routes, and more.

Refer to the following code example. Here, we’ll highlight the major cities with the most skyscrapers by placing a custom marker on the map when a chart segment explodes. Additionally, we’ll display the corresponding country name and the skyscraper count in the bottom area of the chart.

<Grid>

    <chart:SfCircularChart>

        <chart:DoughnutSeries 
            ExplodeOnTouch="True" 
            ExplodeIndex="{Binding SelectedIndex, Mode=TwoWay}">

            <chart:DoughnutSeries.CenterView>

                <Border 
                    x:Name="border" 
                    HeightRequest="{Binding CenterHoleSize}" 
                    WidthRequest="{Binding CenterHoleSize}"
                    BackgroundColor="Transparent" 
                    Stroke="Transparent" 
                    Padding="20,0,20,0">

                    <Border.StrokeShape>
                        <RoundRectangle 
                            CornerRadius="{Binding CenterHoleSize, Converter={StaticResource innerRadiusConverter}, Source={x:Reference series}}" />
                    </Border.StrokeShape>

                    <maps:SfMaps>

                        <maps:SfMaps.Layer>

                            <maps:MapShapeLayer 
                                ShapesSource="https://cdn.syncfusion.com/maps/map-data/world-map.json" 
                                ShapeStroke="#888888" 
                                ShapeFill="#e7e7e7"
                                Markers="{Binding MapMarkerCollection, Source={x:Reference viewModel}}">

                                <maps:MapShapeLayer.MarkerTemplate>
                                    <DataTemplate>
                                        <StackLayout HorizontalOptions="Center">
                                            <Image Source="map_pin.png" HeightRequest="30" WidthRequest="30" />
                                            <Label 
                                                Text="{Binding SelectedCityName, Source={x:Reference viewModel}}"
                                                HorizontalTextAlignment="Center" 
                                                FontSize="10" 
                                                FontAttributes="Bold" />
                                        </StackLayout>
                                    </DataTemplate>
                                </maps:MapShapeLayer.MarkerTemplate>

                            </maps:MapShapeLayer>

                        </maps:SfMaps.Layer>

                    </maps:SfMaps>

                </Border>

            </chart:DoughnutSeries.CenterView>

        </chart:DoughnutSeries>

    </chart:SfCircularChart>

    <Border 
        HorizontalOptions="Center" 
        Padding="10" 
        VerticalOptions="End" 
        Margin="{OnPlatform WinUI='0,-20,0,20', MacCatalyst='0,-20,0,40', Default='0,-40,0,40'}"
        Stroke="Black" 
        WidthRequest="150" 
        StrokeShape="RoundRectangle 10">

        <StackLayout HorizontalOptions="Center">
            <StackLayout Grid.Row="0" Orientation="Horizontal" Spacing="10">
                <Image Source="{Binding SelectedCityImage}" WidthRequest="25" HeightRequest="25" />
                <Label Text="{Binding SelectedCountryName}" FontSize="16" TextColor="Black" />
            </StackLayout>

            <Label 
                Text="{Binding SelectedCityCount}" 
                Margin="40,0,0,0" 
                FontSize="15" 
                FontAttributes="Bold" 
                TextColor="Black" />
        </StackLayout>

    </Border>

</Grid>

To achieve this, we’ve defined the following properties in the SkysCrapersData class:

  • SelectedIndex: Stores the index of the exploded chart segment.
  • SelectedCityImage: Displays the image of the selected city.
  • SelectedCityName: Represents the name of the selected city.
  • SelectedCityCount: Shows the skyscraper count for the selected city.
  • SelectedCountryName: Displays the name of the country.
  • MapMarkerCollection: Holds the markers to display on the map, highlighting the cities with the most skyscrapers.

Refer to the following code example.

public class SkysCrapersData : INotifyPropertyChanged
{
    private int _selectedIndex;

    public int SelectedIndex
    {
        get => _selectedIndex;
        set
        {
            if (_selectedIndex != value)
            {
                _selectedIndex = value;
                UpdateIndex();
                OnPropertyChanged(nameof(SelectedIndex));
            }
        }
    }

    private string? _selectedCityImage;

    public string? SelectedCityImage
    {
        get => _selectedCityImage;
        set
        {
            _selectedCityImage = value;
            OnPropertyChanged(nameof(SelectedCityImage));
        }
    }

    private string? _selectedCityName;

    public string? SelectedCityName
    {
        get => _selectedCityName;
        set
        {
            _selectedCityName = value;
            OnPropertyChanged(nameof(SelectedCityName));
        }
    }

    private string? _selectedCountryName;

    public string? SelectedCountryName
    {
        get => _selectedCountryName;
        set
        {
            _selectedCountryName = value;
            OnPropertyChanged(nameof(SelectedCountryName));
        }
    }

    private int _selectedCityCount;

    public int SelectedCityCount
    {
        get => _selectedCityCount;
        set
        {
            _selectedCityCount = value;
            OnPropertyChanged(nameof(SelectedCityCount));
        }
    }

    private MapMarkerCollection? _mapMarkerCollection;

    public MapMarkerCollection? MapMarkerCollection
    {
        get => _mapMarkerCollection;
        set
        {
            _mapMarkerCollection = value;
            OnPropertyChanged(nameof(MapMarkerCollection));
        }
    }

    public SkysCrapersData()
    {
        MapMarkerCollection = new MapMarkerCollection();
        SelectedIndex = 1;
    }

    private void UpdateIndex()
    {
        var selectedCity = Data.ElementAtOrDefault(SelectedIndex);
        if (selectedCity != null)
        {
            SelectedCityName = selectedCity.City;
            SelectedCountryName = selectedCity.Country;
            SelectedCityCount = selectedCity.Count;
            SelectedCityImage = $"{selectedCity.Country?.ToLower().Replace(" ", "_")}.png";

            MapMarkerCollection?.Clear();

            var marker = selectedCity.City switch
            {
                "Hong-Kong"    => new MapMarker { Latitude = 22.3193, Longitude = 114.1694 },
                "Shenzhen"     => new MapMarker { Latitude = 22.5429, Longitude = 114.0596 },
                "New York"     => new MapMarker { Latitude = 40.7128, Longitude = 74.0060 },
                "Dubai"        => new MapMarker { Latitude = 25.2048, Longitude = 55.2708 },
                "Guangzhou"    => new MapMarker { Latitude = 23.1291, Longitude = 113.2644 },
                "Shanghai"     => new MapMarker { Latitude = 31.2304, Longitude = 121.4737 },
                "Kuala Lumpur" => new MapMarker { Latitude = 3.1499,  Longitude = 101.6945 },
                "Tokyo"        => new MapMarker { Latitude = 35.6764, Longitude = 139.6500 },
                "Wuhan"        => new MapMarker { Latitude = 30.5928, Longitude = 114.3052 },
                "Chongqing"    => new MapMarker { Latitude = 29.5657, Longitude = 106.5512 },
                _              => null
            };

            if (marker != null)
            {
                MapMarkerCollection?.Add(marker);
            }
        }
    }

    public event PropertyChangedEventHandler? PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

After executing the above code examples, we’ll get the output that resembles the following image.

GitHub reference

For more details, refer to the project on GitHub.

Supercharge your cross-platform apps with Syncfusion's robust .NET MAUI controls.

Conclusion

Thank you for reading! In this blog, we’ve explored how to visualize the top 10 cities with the most skyscrapers data using the Syncfusion .NET MAUI Doughnut Chart and Maps control. This integration offers a powerful example of combining geographic data with statistical representations to convey insights effectively. We encourage you to follow the steps outlined and share your feedback in the comments section 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 forumssupport portal, or feedback portal. We are always happy to assist you!

Meet the Author

Saiyath Ali Fathima M

Saiyath Ali Fathima M has been a software developer at Syncfusion, specializing in custom control development for Microsoft technologies since 2022.