Bubble Chart


The Blazor Bubble Chart component is used to display three dimensions of data at the same time. The location of the bubble is determined by the first two dimensions and the corresponding horizontal and vertical axes. The third dimension is represented by the size of the individual bubbles.

API Documentation

Chart setup #

Before using any chart demo: install BlazorExpress.ChartJS 1.2.2, load Chart.js 4.4.1, chartjs-plugin-datalabels 2.2.0, and _content/BlazorExpress.ChartJS/blazorexpress.chartjs.js, then add @using BlazorExpress.ChartJS to your chart page or chart folder.

Follow the shared chart setup guide, the .NET 8 WebAssembly guide, or the .NET 8 Web App Server guide. For full chart component guidance and examples, visit chartjs.blazorexpress.com.

How it works #

The Bubble Chart component visualizes three dimensions of data by displaying each data point as a bubble, where the X and Y coordinates determine the position and the bubble size represents a third value. This makes it ideal for comparing and analyzing relationships between multiple variables.

How to use:
  1. Add the BubbleChart component to your page and set its desired Width (e.g., Width="600").
  2. Prepare your ChartData with Labels for the X-axis and one or more BubbleChartDataset objects, each containing a list of BubbleChartDataPoint (with X, Y, and R values).
  3. Configure chart appearance and behavior using BubbleChartOptions (e.g., responsiveness, tooltips, axis settings).
  4. Initialize the chart by calling InitializeAsync with your data and options.
  5. Use built-in methods such as AddDatasetAsync, AddDataAsync, and UpdateAsync to dynamically update the chart as shown in the demo.
  6. Refer to the demo code below for practical examples, including adding datasets, randomizing data, and customizing chart styles.
This demo provides a hands-on example of setting up a Bubble Chart in Blazor, demonstrating how to bind and update your data for interactive visualizations.
<BubbleChart @ref="bubbleChart" Width="600" />

<div class="mt-5">
    <Button Color="ButtonColor.Primary" Size="ButtonSize.Small" @onclick="RandomizeAsync"> Randomize </Button>
    <Button Color="ButtonColor.Link" Size="ButtonSize.Small" @onclick="AddDatasetAsync"> Add Dataset </Button>
    <Button Color="ButtonColor.Info" Size="ButtonSize.Small" @onclick="AddDataAsync">Add Data</Button>
</div>

@code {
    private BubbleChart bubbleChart = default!;
    private BubbleChartOptions bubbleChartOptions = default!;
    private ChartData chartData = default!;

    private int datasetsCount = 0;
    private int labelsCount = 0;
    private string[] months = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
    private Random random = new();

    protected override void OnInitialized()
    {
        chartData = new ChartData { Labels = GetDefaultDataLabels(6), Datasets = GetDefaultDataSets(3) };
        bubbleChartOptions = new BubbleChartOptions { Responsive = true };
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await bubbleChart.InitializeAsync(chartData, bubbleChartOptions);
        }
        await base.OnAfterRenderAsync(firstRender);
    }

    private async Task RandomizeAsync()
    {
        if (chartData is null || chartData.Datasets is null || !chartData.Datasets.Any()) return;

        var newDatasets = new List<IChartDataset>();

        foreach (var dataset in chartData.Datasets)
        {
            if (dataset is BubbleChartDataset bubbleChartDataset
                && bubbleChartDataset is not null
                && bubbleChartDataset.Data is not null)
            {
                var count = bubbleChartDataset.Data.Count;

                var newData = new List<BubbleChartDataPoint>();
                for (var i = 0; i < count; i++)
                {
                    newData.Add(NewBubbleChartDataPoint);
                }

                bubbleChartDataset.Data = newData;
                newDatasets.Add(bubbleChartDataset);
            }
        }

        chartData.Datasets = newDatasets;

        await bubbleChart.UpdateAsync(chartData, bubbleChartOptions);
    }

    private async Task AddDatasetAsync()
    {
        if (chartData is null || chartData.Datasets is null) return;

        if (datasetsCount >= 12)
            return;

        var chartDataset = GetRandomBarChartDataset();
        chartData = await bubbleChart.AddDatasetAsync(chartData, chartDataset, bubbleChartOptions);
    }

    private async Task AddDataAsync()
    {
        if (chartData is null || chartData.Datasets is null)
            return;

        if (labelsCount >= 12)
            return;

        var data = new List<IChartDatasetData>();
        foreach (var dataset in chartData.Datasets)
        {
            if (dataset is BubbleChartDataset barChartDataset)
                data.Add(new BubbleChartDatasetData(barChartDataset.Label, NewBubbleChartDataPoint));
        }

        chartData = await bubbleChart.AddDataAsync(chartData, GetNextDataLabel(), data);
    }

    #region Data Preparation

    private List<IChartDataset> GetDefaultDataSets(int numberOfDatasets)
    {
        var datasets = new List<IChartDataset>();

        for (var index = 0; index < numberOfDatasets; index++)
        {
            datasets.Add(GetRandomBarChartDataset());
        }

        return datasets;
    }

    private BubbleChartDataset GetRandomBarChartDataset()
    {
        var c = ChartJsColorExtensions.ToColor(ChartJsColorUtility.CategoricalTwelveColors[datasetsCount]);

        datasetsCount += 1;

        return new BubbleChartDataset()
        {
            Label = $"Product {datasetsCount}",
            Data = GetRandomData(),
            BackgroundColor = new List<string> { ChartJsColorExtensions.ToRgbaString(c, 0.5) },
            BorderColor = new List<string> { ChartJsColorExtensions.ToRgbString(c) },
            BorderWidth = 1,
        };
    }

    private List<BubbleChartDataPoint> GetRandomData()
    {
        var data = new List<BubbleChartDataPoint>(labelsCount);
        for (var i = 0; i < labelsCount; i++)
        {
            data.Add(NewBubbleChartDataPoint);
        }
        return data;
    }

    private List<string> GetDefaultDataLabels(int numberOfLabels)
    {
        var labels = new List<string>();
        for (var index = 0; index < numberOfLabels; index++)
        {
            labels.Add(GetNextDataLabel());
        }

        return labels;
    }

    private string GetNextDataLabel()
    {
        labelsCount += 1;
        return months[labelsCount - 1];
    }

    private BubbleChartDataPoint NewBubbleChartDataPoint => new(X: random.Next(40), Y: random.Next(40), R: random.Next(10));

    #endregion Data Preparation
}
DO YOU KNOW?
This demo website is built using the BlazorExpress.Bulma library and published on the Azure Web App. See our source code on GitHub.