Bubble Chart in Angular Charts

Bubble

A bubble series renders data as bubbles whose size is proportional to a third value (the z-value), with the position determined by the x and y values.

Bubble chart displaying data points with varying sizes representing three-dimensional data

Configure a bubble series as follows:

  1. Set the series type: Set the series type to Bubble.
  2. Register the service: Register BubbleSeriesService in the module providers array, or in ApplicationConfig.providers for standalone applications. Confirm that ChartModule is imported.
  3. Map the data fields: Bind the data with dataSource, and map the x, y, and bubble-size fields with xName, yName, and size.
import { ChartModule, BubbleSeriesService } from '@syncfusion/ej2-angular-charts';
import { Component, OnInit } from '@angular/core';
import { bubbleData } from './datasource';

@Component({
    imports: [ChartModule],
    providers: [BubbleSeriesService],
    standalone: true,
    selector: 'app-container',
    template: `<ejs-chart id="chart-container" [primaryXAxis]='primaryXAxis' [primaryYAxis]='primaryYAxis' [title]='title'>
        <e-series-collection>
            <e-series [dataSource]='data' type='Bubble' xName='x' yName='y' size='size' name='pound'></e-series>
        </e-series-collection>
    </ejs-chart>`
})
export class AppComponent implements OnInit {
    public title?: string;
    public data?: Object[];
    public primaryXAxis?: Object;
    public primaryYAxis?: Object;

    ngOnInit(): void {
        this.primaryXAxis = {
            title: 'Literacy Rate',
            minimum: 60,
            maximum: 100,
            interval: 5
        };
        this.primaryYAxis = {
            title: 'GDP Growth Rate',
            minimum: 0,
            maximum: 16,
            interval: 2
        };
        this.data = bubbleData;
        this.title = 'GDP vs Literacy Rate';
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
export let bubbleData: Object[] =  [
        { x: 92.2, y: 7.8, size: 1.347, text: 'China' },
        { x: 74, y: 6.5, size: 1.241, text: 'India' },
        { x: 90.4, y: 6.0, size: 0.238, text: 'Indonesia' },
        { x: 99.4, y: 2.2, size: 0.312, text: 'US' },
        { x: 88.6, y: 1.3, size: 0.197, text: 'Brazil' },
        { x: 99, y: 0.7, size: 0.0818, text: 'Germany' },
        { x: 72, y: 2.0, size: 0.0826, text: 'Egypt' },
        { x: 99.6, y: 3.4, size: 0.143, text: 'Russia' },
        { x: 99, y: 0.2, size: 0.128, text: 'Japan' },
        { x: 86.1, y: 4.0, size: 0.115, text: 'Mexico' },
        { x: 92.6, y: 6.6, size: 0.096, text: 'Philippines' },
        { x: 61.3, y: 14.5, size: 0.162, text: 'Nigeria' }];

Series customization

Customize a bubble series using the following properties.

Fill

Use the fill property to set a single solid bubble color. Accepted values are CSS color names (for example, blue), hexadecimal strings (for example, #1A75FF), and rgba(...) strings.

import { ChartModule, BubbleSeriesService } from '@syncfusion/ej2-angular-charts';
import { Component, OnInit } from '@angular/core';
import { bubbleData } from './datasource';

@Component({
    imports: [ChartModule],
    providers: [BubbleSeriesService],
    standalone: true,
    selector: 'app-container',
    template: `<ejs-chart id="chart-container" [primaryXAxis]='primaryXAxis' [primaryYAxis]='primaryYAxis' [title]='title'>
        <e-series-collection>
            <e-series [dataSource]='data' type='Bubble' xName='x' yName='y' size='size' name='pound' fill='blue'></e-series>
        </e-series-collection>
    </ejs-chart>`
})
export class AppComponent implements OnInit {
    public title?: string;
    public data?: Object[];
    public primaryXAxis?: Object;
    public primaryYAxis?: Object;

    ngOnInit(): void {
        this.primaryXAxis = {
            title: 'Literacy Rate',
            minimum: 60,
            maximum: 100,
            interval: 5
        };
        this.primaryYAxis = {
            title: 'GDP Growth Rate',
            minimum: 0,
            maximum: 16,
            interval: 2
        };
        this.data = bubbleData;
        this.title = 'GDP vs Literacy Rate';
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
export let bubbleData: Object[] =  [
        { x: 92.2, y: 7.8, size: 1.347, text: 'China' },
        { x: 74, y: 6.5, size: 1.241, text: 'India' },
        { x: 90.4, y: 6.0, size: 0.238, text: 'Indonesia' },
        { x: 99.4, y: 2.2, size: 0.312, text: 'US' },
        { x: 88.6, y: 1.3, size: 0.197, text: 'Brazil' },
        { x: 99, y: 0.7, size: 0.0818, text: 'Germany' },
        { x: 72, y: 2.0, size: 0.0826, text: 'Egypt' },
        { x: 99.6, y: 3.4, size: 0.143, text: 'Russia' },
        { x: 99, y: 0.2, size: 0.128, text: 'Japan' },
        { x: 86.1, y: 4.0, size: 0.115, text: 'Mexico' },
        { x: 92.6, y: 6.6, size: 0.096, text: 'Philippines' },
        { x: 61.3, y: 14.5, size: 0.162, text: 'Nigeria' }];

Opacity

Use the opacity property to control bubble transparency. Set a value from 0 (fully transparent) to 1 (fully opaque).

import { ChartModule, BubbleSeriesService } from '@syncfusion/ej2-angular-charts';
import { Component, OnInit } from '@angular/core';
import { bubbleData } from './datasource';

@Component({
    imports: [ChartModule],
    providers: [BubbleSeriesService],
    standalone: true,
    selector: 'app-container',
    template: `<ejs-chart id="chart-container" [primaryXAxis]='primaryXAxis' [primaryYAxis]='primaryYAxis' [title]='title'>
        <e-series-collection>
            <e-series [dataSource]='data' type='Bubble' xName='x' yName='y' size='size' name='pound' opacity='0.5'></e-series>
        </e-series-collection>
    </ejs-chart>`
})
export class AppComponent implements OnInit {
    public title?: string;
    public data?: Object[];
    public primaryXAxis?: Object;
    public primaryYAxis?: Object;

    ngOnInit(): void {
        this.primaryXAxis = {
            title: 'Literacy Rate',
            minimum: 60,
            maximum: 100,
            interval: 5
        };
        this.primaryYAxis = {
            title: 'GDP Growth Rate',
            minimum: 0,
            maximum: 16,
            interval: 2
        };
        this.data = bubbleData;
        this.title = 'GDP vs Literacy Rate';
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
export let bubbleData: Object[] =  [
        { x: 92.2, y: 7.8, size: 1.347, text: 'China' },
        { x: 74, y: 6.5, size: 1.241, text: 'India' },
        { x: 90.4, y: 6.0, size: 0.238, text: 'Indonesia' },
        { x: 99.4, y: 2.2, size: 0.312, text: 'US' },
        { x: 88.6, y: 1.3, size: 0.197, text: 'Brazil' },
        { x: 99, y: 0.7, size: 0.0818, text: 'Germany' },
        { x: 72, y: 2.0, size: 0.0826, text: 'Egypt' },
        { x: 99.6, y: 3.4, size: 0.143, text: 'Russia' },
        { x: 99, y: 0.2, size: 0.128, text: 'Japan' },
        { x: 86.1, y: 4.0, size: 0.115, text: 'Mexico' },
        { x: 92.6, y: 6.6, size: 0.096, text: 'Philippines' },
        { x: 61.3, y: 14.5, size: 0.162, text: 'Nigeria' }];

Size mapping

Use the size property to map each bubble radius to a numeric value from the data source.

import { ChartModule, BubbleSeriesService } from '@syncfusion/ej2-angular-charts';
import { Component, OnInit } from '@angular/core';
import { bubbleData } from './datasource';

@Component({
    imports: [ChartModule],
    providers: [BubbleSeriesService],
    standalone: true,
    selector: 'app-container',
    template: `<ejs-chart id="chart-container" [primaryXAxis]='primaryXAxis' [primaryYAxis]='primaryYAxis' [title]='title'>
        <e-series-collection>
            <e-series [dataSource]='data' type='Bubble' xName='x' yName='y' size='size' name='pound'></e-series>
        </e-series-collection>
    </ejs-chart>`
})
export class AppComponent implements OnInit {
    public title?: string;
    public data?: Object[];
    public primaryXAxis?: Object;
    public primaryYAxis?: Object;

    ngOnInit(): void {
        this.primaryXAxis = {
            title: 'Literacy Rate',
            minimum: 60,
            maximum: 100,
            interval: 5
        };
        this.primaryYAxis = {
            title: 'GDP Growth Rate',
            minimum: 0,
            maximum: 16,
            interval: 2
        };
        this.data = bubbleData;
        this.title = 'GDP vs Literacy Rate';
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
export let bubbleData: Object[] =  [
        { x: 92.2, y: 7.8, size: 1.347, text: 'China' },
        { x: 74, y: 6.5, size: 1.241, text: 'India' },
        { x: 90.4, y: 6.0, size: 0.238, text: 'Indonesia' },
        { x: 99.4, y: 2.2, size: 0.312, text: 'US' },
        { x: 88.6, y: 1.3, size: 0.197, text: 'Brazil' },
        { x: 99, y: 0.7, size: 0.0818, text: 'Germany' },
        { x: 72, y: 2.0, size: 0.0826, text: 'Egypt' },
        { x: 99.6, y: 3.4, size: 0.143, text: 'Russia' },
        { x: 99, y: 0.2, size: 0.128, text: 'Japan' },
        { x: 86.1, y: 4.0, size: 0.115, text: 'Mexico' },
        { x: 92.6, y: 6.6, size: 0.096, text: 'Philippines' },
        { x: 61.3, y: 14.5, size: 0.162, text: 'Nigeria' }];

Empty points

A data point whose mapped value is null or undefined is empty. Configure its behavior with emptyPointSettings.mode.

Mode

Use mode to control empty-point rendering. The default is Gap.

Mode Visual behavior
Gap Skip the empty point; subsequent bubbles are still rendered.
Zero Treat the empty point as 0 and render the bubble at the origin.
Drop Drop the empty bubble; subsequent points are still rendered.
Average Replace the empty value with the average of the surrounding points.
import { ChartModule, BubbleSeriesService } from '@syncfusion/ej2-angular-charts';
import { Component, OnInit } from '@angular/core';
import { bubbleData } from './datasource';

@Component({
    imports: [ChartModule],
    providers: [BubbleSeriesService],
    standalone: true,
    selector: 'app-container',
    template: `<ejs-chart id="chart-container" [primaryXAxis]='primaryXAxis' [primaryYAxis]='primaryYAxis' [title]='title'>
        <e-series-collection>
            <e-series [dataSource]='data' type='Bubble' xName='x' yName='y' size='size' name='pound' [emptyPointSettings]='emptyPointSettings'></e-series>
        </e-series-collection>
    </ejs-chart>`
})
export class AppComponent implements OnInit {
    public title?: string;
    public data?: Object[];
    public emptyPointSettings?: Object;
    public primaryXAxis?: Object;
    public primaryYAxis?: Object;

    ngOnInit(): void {
        this.primaryXAxis = {
            title: 'Literacy Rate',
            minimum: 60,
            maximum: 100,
            interval: 5
        };
        this.primaryYAxis = {
            title: 'GDP Growth Rate',
            minimum: 0,
            maximum: 16,
            interval: 2
        };
        this.data = bubbleData;
        this.emptyPointSettings = {
            mode: 'Zero'
        };
        this.title = 'GDP vs Literacy Rate';
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
export let bubbleData: Object[] = [
        { x: 92.2, y: 7.8,  size: 1.347 },
        { x: 74,   y: 6.5,  size: 1.241 },
        { x: 90.4, y: null,  size: 0.238 },
        { x: 99.4, y: 2.2,  size: 0.312 },
        { x: 88.6, y: 1.3,  size: 0.197 },
        { x: 99,   y: 0.7,  size: 0.0818 },
        { x: 72,   y: 2.0,  size: 0.0826 },
        { x: 99.6, y: 3.4,  size: 0.143 },
        { x: 99,   y: undefined,  size: 0.128 },
        { x: 86.1, y: 4.0,  size: 0.115 },
        { x: 92.6, y: 6.6,  size: 0.096 },
        { x: 61.3, y: 14.5, size: 0.162 }
    ];

Empty-point fill

Use the emptyPointSettings.fill property to customize the fill color of empty-point bubbles.

import { ChartModule, BubbleSeriesService } from '@syncfusion/ej2-angular-charts';
import { Component, OnInit } from '@angular/core';
import { bubbleData } from './datasource';

@Component({
    imports: [ChartModule],
    providers: [BubbleSeriesService],
    standalone: true,
    selector: 'app-container',
    template: `<ejs-chart id="chart-container" [primaryXAxis]='primaryXAxis' [primaryYAxis]='primaryYAxis' [title]='title'>
        <e-series-collection>
            <e-series [dataSource]='data' type='Bubble' xName='x' yName='y' size='size' name='pound' [emptyPointSettings]='emptyPointSettings'></e-series>
        </e-series-collection>
    </ejs-chart>`
})
export class AppComponent implements OnInit {
    public title?: string;
    public data?: Object[];
    public emptyPointSettings?: Object;
    public primaryXAxis?: Object;
    public primaryYAxis?: Object;

    ngOnInit(): void {
        this.primaryXAxis = {
            title: 'Literacy Rate',
            minimum: 60,
            maximum: 100,
            interval: 5
        };
        this.primaryYAxis = {
            title: 'GDP Growth Rate',
            minimum: 0,
            maximum: 16,
            interval: 2
        };
        this.data = bubbleData;
        this.emptyPointSettings = {
            mode: 'Average',
            fill: 'red'
        };
        this.title = 'GDP vs Literacy Rate';
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
export let bubbleData: Object[] = [
        { x: 92.2, y: 7.8,  size: 1.347 },
        { x: 74,   y: 6.5,  size: 1.241 },
        { x: 90.4, y: null,  size: 0.238 },
        { x: 99.4, y: 2.2,  size: 0.312 },
        { x: 88.6, y: 1.3,  size: 0.197 },
        { x: 99,   y: 0.7,  size: 0.0818 },
        { x: 72,   y: 2.0,  size: 0.0826 },
        { x: 99.6, y: 3.4,  size: 0.143 },
        { x: 99,   y: undefined,  size: 0.128 },
        { x: 86.1, y: 4.0,  size: 0.115 },
        { x: 92.6, y: 6.6,  size: 0.096 },
        { x: 61.3, y: 14.5, size: 0.162 }
    ];

Empty-point border

Use the emptyPointSettings.border property to customize the width and color of an empty-point bubble’s stroke.

import { ChartModule, BubbleSeriesService } from '@syncfusion/ej2-angular-charts';
import { Component, OnInit } from '@angular/core';
import { bubbleData } from './datasource';

@Component({
    imports: [ChartModule],
    providers: [BubbleSeriesService],
    standalone: true,
    selector: 'app-container',
    template: `<ejs-chart id="chart-container" [primaryXAxis]='primaryXAxis' [primaryYAxis]='primaryYAxis' [title]='title'>
        <e-series-collection>
            <e-series [dataSource]='data' type='Bubble' xName='x' yName='y' size='size' name='pound' [emptyPointSettings]='emptyPointSettings'></e-series>
        </e-series-collection>
    </ejs-chart>`
})
export class AppComponent implements OnInit {
    public title?: string;
    public data?: Object[];
    public emptyPointSettings?: Object;
    public primaryXAxis?: Object;
    public primaryYAxis?: Object;

    ngOnInit(): void {
        this.primaryXAxis = {
            title: 'Literacy Rate',
            minimum: 60,
            maximum: 100,
            interval: 5
        };
        this.primaryYAxis = {
            title: 'GDP Growth Rate',
            minimum: 0,
            maximum: 16,
            interval: 2
        };
        this.data = bubbleData;
        this.emptyPointSettings = {
            mode: 'Zero',
            fill: 'red',
            border: { width: 2, color: 'green' }
        };
        this.title = 'GDP vs Literacy Rate';
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
export let bubbleData: Object[] = [
        { x: 92.2, y: 7.8,  size: 1.347 },
        { x: 74,   y: 6.5,  size: 1.241 },
        { x: 90.4, y: null,  size: 0.238 },
        { x: 99.4, y: 2.2,  size: 0.312 },
        { x: 88.6, y: 1.3,  size: 0.197 },
        { x: 99,   y: 0.7,  size: 0.0818 },
        { x: 72,   y: 2.0,  size: 0.0826 },
        { x: 99.6, y: 3.4,  size: 0.143 },
        { x: 99,   y: undefined,  size: 0.128 },
        { x: 86.1, y: 4.0,  size: 0.115 },
        { x: 92.6, y: 6.6,  size: 0.096 },
        { x: 61.3, y: 14.5, size: 0.162 }
    ];

Events

Series render

The seriesRender event allows you to customize series properties, such as data, fill, and name, before they are rendered on the chart. The callback receives an ISeriesRenderEventArgs argument that exposes mutable series and data properties.

<ejs-chart (seriesRender)="onSeriesRender($event)"></ejs-chart>
import { ChartModule, BubbleSeriesService } from '@syncfusion/ej2-angular-charts';
import { ISeriesRenderEventArgs } from '@syncfusion/ej2-charts';
import { Component, OnInit } from '@angular/core';
import { bubbleData } from './datasource';

@Component({
    imports: [ChartModule],
    providers: [BubbleSeriesService],
    standalone: true,
    selector: 'app-container',
    template: `<ejs-chart id="chart-container" (seriesRender)='seriesRender($event)' [primaryXAxis]='primaryXAxis' [primaryYAxis]='primaryYAxis' [title]='title'>
        <e-series-collection>
            <e-series [dataSource]='data' type='Bubble' xName='x' yName='y' size='size' name='pound'></e-series>
        </e-series-collection>
    </ejs-chart>`
})
export class AppComponent implements OnInit {
    public title?: string;
    public data?: Object[];
    public primaryXAxis?: Object;
    public primaryYAxis?: Object;

    ngOnInit(): void {
        this.primaryXAxis = {
            title: 'Literacy Rate',
            minimum: 60,
            maximum: 100,
            interval: 5
        };
        this.primaryYAxis = {
            title: 'GDP Growth Rate',
            minimum: 0,
            maximum: 16,
            interval: 2
        };
        this.data = bubbleData;
        this.title = 'GDP vs Literacy Rate';
    }

    public seriesRender(args: ISeriesRenderEventArgs): void {
        args.fill = '#ff6347';
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
export let bubbleData: Object[] =  [
        { x: 92.2, y: 7.8, size: 1.347, text: 'China' },
        { x: 74, y: 6.5, size: 1.241, text: 'India' },
        { x: 90.4, y: 6.0, size: 0.238, text: 'Indonesia' },
        { x: 99.4, y: 2.2, size: 0.312, text: 'US' },
        { x: 88.6, y: 1.3, size: 0.197, text: 'Brazil' },
        { x: 99, y: 0.7, size: 0.0818, text: 'Germany' },
        { x: 72, y: 2.0, size: 0.0826, text: 'Egypt' },
        { x: 99.6, y: 3.4, size: 0.143, text: 'Russia' },
        { x: 99, y: 0.2, size: 0.128, text: 'Japan' },
        { x: 86.1, y: 4.0, size: 0.115, text: 'Mexico' },
        { x: 92.6, y: 6.6, size: 0.096, text: 'Philippines' },
        { x: 61.3, y: 14.5, size: 0.162, text: 'Nigeria' }];

Point render

The pointRender event allows you to customize each data point before it is rendered on the chart. The callback receives an IPointRenderEventArgs argument that exposes the current point, series, fill, and border, plus a cancel flag.

<ejs-chart (pointRender)="onPointRender($event)"></ejs-chart>
import { ChartModule, BubbleSeriesService } from '@syncfusion/ej2-angular-charts';
import { IPointRenderEventArgs } from '@syncfusion/ej2-charts';
import { Component, OnInit } from '@angular/core';
import { bubbleData } from './datasource';

@Component({
    imports: [ChartModule],
    providers: [BubbleSeriesService],
    standalone: true,
    selector: 'app-container',
    template: `<ejs-chart id="chart-container" (pointRender)='pointRender($event)' [primaryXAxis]='primaryXAxis' [primaryYAxis]='primaryYAxis' [title]='title'>
        <e-series-collection>
            <e-series [dataSource]='data' type='Bubble' xName='x' yName='y' size='size' name='pound'></e-series>
        </e-series-collection>
    </ejs-chart>`
})
export class AppComponent implements OnInit {
    public title?: string;
    public data?: Object[];
    public primaryXAxis?: Object;
    public primaryYAxis?: Object;

    ngOnInit(): void {
        this.primaryXAxis = {
            title: 'Literacy Rate',
            minimum: 60,
            maximum: 100,
            interval: 5
        };
        this.primaryYAxis = {
            title: 'GDP Growth Rate',
            minimum: 0,
            maximum: 16,
            interval: 2
        };
        this.data = bubbleData;
        this.title = 'GDP vs Literacy Rate';
    }

    public pointRender(args: IPointRenderEventArgs): void {
        if (args.point.maximum < 38) {
            args.fill = '#ff6347';
        } else {
            args.fill = '#009cb8';
        }
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
export let bubbleData: Object[] =  [
        { x: 92.2, y: 7.8, size: 1.347, text: 'China' },
        { x: 74, y: 6.5, size: 1.241, text: 'India' },
        { x: 90.4, y: 6.0, size: 0.238, text: 'Indonesia' },
        { x: 99.4, y: 2.2, size: 0.312, text: 'US' },
        { x: 88.6, y: 1.3, size: 0.197, text: 'Brazil' },
        { x: 99, y: 0.7, size: 0.0818, text: 'Germany' },
        { x: 72, y: 2.0, size: 0.0826, text: 'Egypt' },
        { x: 99.6, y: 3.4, size: 0.143, text: 'Russia' },
        { x: 99, y: 0.2, size: 0.128, text: 'Japan' },
        { x: 86.1, y: 4.0, size: 0.115, text: 'Mexico' },
        { x: 92.6, y: 6.6, size: 0.096, text: 'Philippines' },
        { x: 61.3, y: 14.5, size: 0.162, text: 'Nigeria' }];

Troubleshooting

The following symptoms map to the most common configuration issues.

  • Bubbles are not rendered: Confirm that BubbleSeriesService is registered, the series type is Bubble, and that xName, yName, and size map to numeric fields in the data source.
  • All bubbles are the same size: The size field is missing or non-numeric. Verify the data type and clamp values.
  • An empty point renders as a zero-radius bubble: Review emptyPointSettings.mode. Use Gap to skip rendering or Drop to keep subsequent bubbles.
  • pointRender does not fire: Confirm you bind the event on the <ejs-chart> element with (pointRender)="...", not on the series.

See also