All Components

Data Binding

The Chart supports the binding of its data series and category axis to arrays and Observables.

Binding Series

This section provides information on the binding methods for the Chart series in general. For more information on how to configure each Chart series, refer to the articles on the Chart series types.

Arrays of Values

The simplest form of data binding involves the supplying of each series with an array of values.

@Component({
    selector: 'my-app',
    template: `
        <kendo-chart>
          <kendo-chart-series>
            <kendo-chart-series-item [data]="seriesData">
            </kendo-chart-series-item>
          </kendo-chart-series>
        </kendo-chart>
    `
})
export class AppComponent {
    public seriesData: number[] = [1, 2, 3, 5];
}

Arrays of Arrays

Some series require more than one value per point—for example, the Scatter (x and y) and Bubble (x, y, and size) series.

The following example demonstrates how to bind a Bubble series to an array of arrays.

@Component({
    selector: 'my-app',
    template: `
        <kendo-chart>
          <kendo-chart-series>
            <kendo-chart-series-item type="bubble" [data]="seriesData">
            </kendo-chart-series-item>
          </kendo-chart-series>
        </kendo-chart>
    `
})
export class AppComponent {
    public seriesData: number[] = [[1, 1, 10], [2, 2, 20], [3, 3, 30]];
}

Objects

The Chart allows you to bind it to objects by specifying the fields you want to use—for the value, category, X value, Y value, and so on. This is the most commonly used type of binding as it allows you to use your model with little or no modification.

The following example demonstrates how to configure a Column series with bound category text and a value.

interface Model {
    product: string;
    sales: number;
}

@Component({
    selector: 'my-app',
    template: `
        <kendo-chart>
          <kendo-chart-series>
            <kendo-chart-series-item
                type="column" [data]="seriesData"
                field="sales" categoryField="product">
            </kendo-chart-series-item>
          </kendo-chart-series>
        </kendo-chart>
    `
})
export class AppComponent {
    public seriesData: Model[] = [{
        product: "Chai",
        sales: 200
    }, {
        product: "Others",
        sales: 250
    }];
}

Groups of Objects

It is often convenient to plot a separate series for each unique category in a data set. For example, a Line Chart for each product in a sales report. Typically, the exact number of categories is not known in advance.

The Data Query package offers a convenient groupBy method that you can use to split the records into groups. It takes the data and a GroupDescriptor. The output is a GroupResult that contains the groups and their items.

The following example demonstrates how to plot a Line Chart for each service.

import { groupBy, GroupResult } from '@progress/kendo-data-query';

interface Sample {
    interval: number;
    service: string;
    value: number;
}

@Component({
    selector: 'my-app',
    template: `
        <kendo-chart>
          <kendo-chart-series>
            <kendo-chart-series-item
                *ngFor="let item of series"
                [data]="item.items" [name]="item.value"
                field="value" categoryField="interval"
                type="line">
            </kendo-chart-series-item>
          </kendo-chart-series>
        </kendo-chart>
    `
})
export class AppComponent {
    public data: Sample[] = [{
        interval: 1, service: 'Service 1', value: 5
    }, {
        interval: 2, service: 'Service 1', value: 15
    }, {
        interval: 3, service: 'Service 1', value: 10
    }, {
        interval: 1, service: 'Service 2', value: 10
    }, {
        interval: 2, service: 'Service 2', value: 5
    }, {
        interval: 3, service: 'Service 2', value: 15
    }];

    public series: Sample[] | GroupResult[];

    constructor() {
        this.series = groupBy(this.data, [{ field: "service" }]);

        // Inspect the resulting data structure in the console
        console.log(JSON.stringify(this.series, null, 2));
    }
}

Binding Categories

The category axis of Categorical Charts is a data-bound component just like the series.

It supports the following basic approaches for providing the category list:

When the Chart is bound to dates, the category axis provides dedicated functions. For more information, refer to the section on displaying time series.

Arrays of Labels

The simplest form of data binding involves the supplying of an array of labels for the categories to the axis. The list will be displayed as is, without any modifications. Series data points are positioned in sequence along the axis.

  • The order of the categories has no relation to the order of the series data points.
  • The number of the categories has to be equal to the number of the data points in the series.
  • To preserve the order, the missing values in the series have to be represented by null.
@Component({
    selector: 'my-app',
    template: `
        <kendo-chart>
          <kendo-chart-category-axis>
            <kendo-chart-category-axis-item [categories]="categories">
            </kendo-chart-category-axis-item>
          </kendo-chart-category-axis>
          <kendo-chart-series>
            <kendo-chart-series-item [data]="seriesData">
            </kendo-chart-series-item>
          </kendo-chart-series>
        </kendo-chart>
    `
})
export class AppComponent {
    public seriesData: number[] = [20, 40, 45, 30, 50];
    public categories: string[] = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'];
}

Category Fields

The previous approach is error-prone because of the necessity for you to maintain a category and a particular data order. To avoid this requirement, bind the categories to the same model object as the series. In this way, the series points and categories will always be matched automatically.

interface Model {
    product: string;
    sales: number;
}

@Component({
    selector: 'my-app',
    template: `
        <kendo-chart>
          <kendo-chart-series>
            <kendo-chart-series-item
                type="column" [data]="seriesData"
                field="sales" categoryField="product">
            </kendo-chart-series-item>
          </kendo-chart-series>
        </kendo-chart>
    `
})
export class AppComponent {
    public seriesData: Model[] = [{
        product: "Chai",
        sales: 200
    }, {
        product: "Others",
        sales: 250
    }];
}

Handling Duplicate Categories

Binding to a category field makes it possible for two data points to have the same category—the following example demonstrates two values that are declared for 'Chai'.

interface Model {
    product: string;
    sales: number;
}

@Component({
    selector: 'my-app',
    template: `
        <kendo-chart>
          <kendo-chart-series>
            <kendo-chart-series-item
                type="column" [data]="seriesData"
                field="sales" categoryField="product">
            </kendo-chart-series-item>
          </kendo-chart-series>
        </kendo-chart>
    `
})
export class AppComponent {
    public seriesData: Model[] = [{
        product: "Chai",
        sales: 200
    }, {
        product: "Chai",
        sales: 100
    }, {
        product: "Others",
        sales: 250
    }];
}

In this case, the Chart takes the data points from the source data set and produces a new point by using an aggregate function.

By default, the aggregate function returns the maximum value of the value fields. If the category contains only one point, it returns it without modification. Other aggregates, such as count and sum, produce their own value even if the category contains just one data point.

interface Model {
    product: string;
    sales: number;
}

@Component({
    selector: 'my-app',
    template: `
        <kendo-chart>
          <kendo-chart-series>
            <kendo-chart-series-item
                aggregate="count"
                type="column" [data]="seriesData"
                field="sales" categoryField="product">
            </kendo-chart-series-item>
          </kendo-chart-series>
        </kendo-chart>
    `
})
export class AppComponent {
    public seriesData: Model[] = [{
        product: "Chai",
        sales: 200
    }, {
        product: "Chai",
        sales: 100
    }, {
        product: "Others",
        sales: 250
    }];
}

It is also possible to define your own aggregate functions, as demonstrated in the following example.

When the category binding is in use, the aggregate function is executed for all unique categories.

interface Model {
    product: string;
    sales: number;
}

@Component({
    selector: 'my-app',
    template: `
        <kendo-chart>
          <kendo-chart-series>
            <kendo-chart-series-item
                [aggregate]="myAggregate"
                type="column" [data]="seriesData"
                field="sales" categoryField="product">
            </kendo-chart-series-item>
          </kendo-chart-series>
        </kendo-chart>
    `
})
export class AppComponent {
    public seriesData: Model[] = [{
        product: "Chai",
        sales: 200
    }, {
        product: "Chai",
        sales: 100
    }, {
        product: "Others",
        sales: 250
    }];

    public myAggregate(values: number[], series: any, dataItems: Model[], category: string) {
        /* Return a sum of the values */
        return values.reduce((n, acc) => acc + n, 0);
    }
}

Updating Data

You can update the data of the Chart either by:

Replacing the Array Instance

To improve its browser performance, the Chart uses the OnPush change-detection strategy. This means that the component does not detect changes to the array instance—for example, when an element is added. To trigger the change detection, create a new array instance for the collection—for example, instead of the this.data.push({new item}) array, set a this.data = [...this.data, {new item}] one.

@Component({
    selector: 'my-app',
    template: `
        <kendo-chart [transitions]="false">
          <kendo-chart-series>
            <kendo-chart-series-item [data]="seriesData">
            </kendo-chart-series-item>
          </kendo-chart-series>
        </kendo-chart>
    `
})
export class AppComponent {
    public seriesData: number[] = [];

    constructor() {
        setInterval(() => {
            // Clone the array
            const data = this.seriesData.slice(0);

            // Produce one random value each 100ms
            data.push(Math.random());

            if (data.length > 10) {
                // Keep only 10 items in the array
                data.shift();
            }

            // Replace with the new array instance
            this.seriesData = data;
        }, 100);
    }
}

Binding to Observables

When you bind the Chart to an observable, the component automatically updates the information it renders every time new data comes from the observable. To bind the Chart to an observable, use an async pipe.

import { Component } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/interval';
import 'rxjs/add/observable/from';
import 'rxjs/add/operator/bufferCount';
import 'rxjs/add/operator/map';

@Component({
    selector: 'my-app',
    template: `
        <kendo-chart [transitions]="false">
          <kendo-chart-series>
            <kendo-chart-series-item
                type="column" [data]="seriesData | async">
            </kendo-chart-series-item>
          </kendo-chart-series>
        </kendo-chart>
    `
})
export class AppComponent {
    /* Start with an empty observable */
    public seriesData: Observable<number[]>;

    constructor() {
        /* Produce 1 random value each 100ms
           and emit it in batches of 10. */
        this.seriesData = Observable.interval(100)
            .map(i => Math.random())
            .bufferCount(10);
    }
}
In this article