JavaScript/jQuery Chart - Data Aggregation
If the Chart contains many series points, displaying all of them may slow down its performance. In this case, it is better to aggregate the series points or replace a group of them with a single point. This aggregated series point conveys a summary of several points, which also facilitates analysis of large datasets. This article discusses steps to configure data aggregation in the Chart.
Enable Data Aggregation
You can enable data aggregation for individual series, all series of a specific type, or for all series in the Chart. The following code demonstrates all the three cases:
jQuery
$(function() { $("#chartContainer").dxChart({ // ... commonSeriesSettings: { // Enables data aggregation for all series in the Chart aggregation: { enabled: true }, fullstackedbar: { // Enables data aggregation for all Full-Stacked Bar series aggregation: { enabled: true } } }, series: [{ // Enables data aggregation for an individual series aggregation: { enabled: true } }, { // ... }] }); });
Angular
<dx-chart ... > <dxo-common-series-settings> <!-- Enables data aggregation for all series in the Chart --> <dxo-aggregation [enabled]="true"> </dxo-aggregation> <dxo-fullstackedbar> <!-- Enables data aggregation for all Full-Stacked Bar series --> <dxo-aggregation [enabled]="true"> </dxo-aggregation> </dxo-fullstackedbar> </dxo-common-series-settings> <dxi-series> <!-- Enables data aggregation for an individual series --> <dxo-aggregation [enabled]="true"> </dxo-aggregation> </dxi-series> </dx-chart>
import { DxChartModule } from "devextreme-angular"; // ... export class AppComponent { // ... } @NgModule({ imports: [ // ... DxChartModule ], // ... })
Vue
<template> <DxChart ... > <DxCommonSeriesSettings ... :fullstackedbar="fullStackedBarSettings"> <!-- Enables data aggregation for all Full-Stacked Bar series --> <DxAggregation :enabled="true"/> <!-- Enables data aggregation for all series in the Chart --> </DxCommonSeriesSettings> <DxSeries> <DxAggregation :enabled="true"/> <!-- Enables data aggregation for an individual series --> </DxSeries> </DxChart> </template> <script> import DxChart, { DxCommonSeriesSettings, DxSeries, DxAggregation } from 'devextreme-vue/chart'; export default { components: { DxChart, DxCommonSeriesSettings, DxSeries, DxAggregation }, data() { return { fullStackedBarSettings: { aggregation: { enabled: true } } }; } } </script>
React
import React from 'react'; import Chart, { CommonSeriesSettings, Series, Aggregation } from 'devextreme-react/chart'; const fullStackedBarSettings = { aggregation: { enabled: true } }; class App extends React.Component { render() { return ( <Chart ... > <CommonSeriesSettings ... fullstackedbar={fullStackedBarSettings}> {/* Enables data aggregation for all Full-Stacked Bar series */} <Aggregation enabled={true} /> {/* Enables data aggregation for all series in the Chart */} </CommonSeriesSettings> <Series> <Aggregation enabled={true} /> {/* Enables data aggregation for an individual series */} </Series> </Chart> ); } } export default App;
Specify the Aggregation Interval
Series points are grouped for aggregation using intervals: those points that fall within the same interval on the argument axis get aggregated together. You can specify the length of the intervals in axis units (numbers or dates), in pixels, or aggregate points by categories:
Axis units (for continuous and logarithmic axes only)
Use the argumentAxis.aggregationInterval property.jQuery
JavaScript$(function() { $("#chartContainer").dxChart({ // ... argumentAxis: { // A new interval every 100 units aggregationInterval: 100, // A new interval every day aggregationInterval: "day", // A new interval every five days aggregationInterval: { days: 5 } } }); });
Angular
HTMLTypeScript<dx-chart ... > <dxo-argument-axis [aggregationInterval]="100" <!-- A new interval every 100 units --> aggregationInterval="day"> <!-- A new interval every day --> <dxo-aggregation-interval [days]="5"> <!-- A new interval every five days --> </dxo-aggregation-interval> </dxo-argument-axis> </dx-chart>
import { DxChartModule } from "devextreme-angular"; // ... export class AppComponent { // ... } @NgModule({ imports: [ // ... DxChartModule ], // ... })
Vue
App.vue<template> <DxChart ... > <DxArgumentAxis :aggregation-interval="100" <!-- A new interval every 100 units --> aggregation-interval="day"> <!-- A new interval every day --> <DxAggregationInterval :days="5"/> <!-- A new interval every five days --> </DxArgumentAxis> </DxChart> </template> <script> import DxChart, { DxArgumentAxis, DxAggregationInterval } from 'devextreme-vue/chart'; export default { components: { DxChart, DxArgumentAxis, DxAggregationInterval } } </script>
React
App.jsimport React from 'react'; import Chart, { ArgumentAxis, AggregationInterval } from 'devextreme-react/chart'; class App extends React.Component { render() { return ( <Chart ... > <ArgumentAxis aggregationInterval={100} {/* A new interval every 100 units */} aggregationInterval="day"> {/* A new interval every day */} <AggregationInterval days={5} /> {/* A new interval every five days */} </ArgumentAxis> </Chart> ); } } export default App;
Pixels
Use the argumentAxis.aggregationGroupWidth property.jQuery
JavaScript$(function() { $("#chartContainer").dxChart({ // ... argumentAxis: { // A new interval every 100 pixels aggregationGroupWidth: 100 } }); });
Angular
HTMLTypeScript<dx-chart ... > <dxo-argument-axis [aggregationGroupWidth]="100"> <!-- A new interval every 100 pixels --> </dxo-argument-axis> </dx-chart>
import { DxChartModule } from "devextreme-angular"; // ... export class AppComponent { // ... } @NgModule({ imports: [ // ... DxChartModule ], // ... })
Vue
App.vue<template> <DxChart ... > <DxArgumentAxis :aggregation-group-width="100"/> <!-- A new interval every 100 pixels --> </DxChart> </template> <script> import DxChart, { DxArgumentAxis } from 'devextreme-vue/chart'; export default { components: { DxChart, DxArgumentAxis } } </script>
React
App.jsimport React from 'react'; import Chart, { ArgumentAxis } from 'devextreme-react/chart'; class App extends React.Component { render() { return ( <Chart ... > <ArgumentAxis aggregationGroupWidth={100} /> {/* A new interval every 100 pixels */} </Chart> ); } } export default App;
Categories
Aggregation by categories can be applied only when the axis displays categories, and each category contains two or more points. To apply it, set argumentAxis.aggregateByCategory to true:jQuery
JavaScript$(function() { $("#chartContainer").dxChart({ // ... argumentAxis: { aggregateByCategory: true } }); });
Angular
HTMLTypeScript<dx-chart ... > <dxo-argument-axis [aggregateByCategory]="true"> </dxo-argument-axis> </dx-chart>
import { DxChartModule } from "devextreme-angular"; // ... export class AppComponent { // ... } @NgModule({ imports: [ // ... DxChartModule ], // ... })
Vue
App.vue<template> <DxChart ... > <DxArgumentAxis :aggregate-by-category="true"/> </DxChart> </template> <script> import DxChart, { DxArgumentAxis } from 'devextreme-vue/chart'; export default { components: { DxChart, DxArgumentAxis } } </script>
React
App.jsimport React from 'react'; import Chart, { ArgumentAxis } from 'devextreme-react/chart'; class App extends React.Component { render() { return ( <Chart ... > <ArgumentAxis aggregateByCategory={true} /> </Chart> ); } } export default App;
Choose the Aggregation Method
Aggregation methods specify how series points should be aggregated. DevExtreme provides the most commonly used aggregation methods out of the box. To use one, specify a series' aggregation.method property. In its description, you will find the full list of provided aggregation methods. Note that different series types have different aggregation methods available.
The following code shows how to specify aggregation methods for each series individually. Data aggregation is enabled for all series in the commonSeriesSettings object.
jQuery
$(function() { $("#chartContainer").dxChart({ // ... commonSeriesSettings: { aggregation: { enabled: true } }, series: [{ // ... type: "line", aggregation: { method: "min" } }, { // ... type: "bar", aggregation: { method: "max" } }] }); });
Angular
<dx-chart ... > <dxo-common-series-settings ... > <dxo-aggregation [enabled]="true"> </dxo-aggregation> </dxo-common-series-settings> <dxi-series type="line" ... > <dxo-aggregation method="min"> </dxo-aggregation> </dxi-series> <dxi-series type="bar" ... > <dxo-aggregation method="max"> </dxo-aggregation> </dxi-series> </dx-chart>
import { DxChartModule } from "devextreme-angular"; // ... export class AppComponent { // ... } @NgModule({ imports: [ // ... DxChartModule ], // ... })
Vue
<template> <DxChart ... > <DxCommonSeriesSettings ... > <DxAggregation :enabled="true"/> </DxCommonSeriesSettings> <DxSeries ... type="line"> <DxAggregation method="min"/> </DxSeries> <DxSeries ... type="bar"> <DxAggregation method="max"/> </DxSeries> </DxChart> </template> <script> import DxChart, { DxCommonSeriesSettings, DxSeries, DxAggregation } from 'devextreme-vue/chart'; export default { components: { DxChart, DxCommonSeriesSettings, DxSeries, DxAggregation } } </script>
React
import React from 'react'; import Chart, { CommonSeriesSettings, Series, Aggregation } from 'devextreme-react/chart'; class App extends React.Component { render() { return ( <Chart ... > <CommonSeriesSettings ... > <Aggregation enabled={true} /> </CommonSeriesSettings> <Series ... type="line"> <Aggregation method="min" /> </Series> <Series ... type="bar"> <Aggregation method="max" /> </Series> </Chart> ); } } export default App;
You can implement a custom aggregate function instead of using an out-of-the-box aggregation method.
Implement a Custom Aggregate Function
When implementing a custom aggregate function, use the aggregationInfo object that is passed to it as the first argument. This object contains information on the aggregation interval for which the function is called and the data objects that fall within this interval. In addition, you can access the Series object, which is passed to the function as the second argument.
To apply the function, assign it to the series' aggregation.calculate property and set the aggregation.method property to "custom".
In the following code, a custom aggregation function implements the median filter algorithm:
jQuery
$(function() { $("#chartContainer").dxChart({ dataSource: [ { argument: 1, value: 10 }, // ... ], series: [{ argumentField: "argument", valueField: "value", aggregation: { enabled: true, method: "custom", calculate: function (aggregationInfo) { if (aggregationInfo.data.length) { return { argument: aggregationInfo.intervalStart, value: aggregationInfo.data[Math.floor(aggregationInfo.data.length / 2)].value }; } } } }] }); });
Angular
<dx-chart [dataSource]="data"> <dxi-series argumentField="argument" valueField="value"> <dxo-aggregation [enabled]="true" method="custom" [calculate]="calcMedianFilter"> </dxo-aggregation> </dxi-series> </dx-chart>
import { DxChartModule } from "devextreme-angular"; // ... export class AppComponent { data = [ { argument: 1, value: 10 }, // ... ]; calcMedianFilter (aggregationInfo) { if (aggregationInfo.data.length) { return { argument: aggregationInfo.intervalStart, value: aggregationInfo.data[Math.floor(aggregationInfo.data.length / 2)].value }; } }; } @NgModule({ imports: [ // ... DxChartModule ], // ... })
Vue
<template> <DxChart ... :data-source="data"> <DxSeries argument-field="argument" value-field="value"> <DxAggregation :enabled="true" :calculate="calcMedianFilter" method="custom" /> </DxSeries> </DxChart> </template> <script> import DxChart, { DxSeries, DxAggregation } from 'devextreme-vue/chart'; export default { components: { DxChart, DxSeries, DxAggregation }, data() { return { data: [ { argument: 1, value: 10 }, // ... ] }; }, methods: { calcMedianFilter(aggregationInfo) { if(aggregationInfo.data.length) { return { argument: aggregationInfo.intervalStart, value: aggregationInfo.data[Math.floor(aggregationInfo.data.length / 2)].value }; } } } } </script>
React
import React from 'react'; import Chart, { Series, Aggregation } from 'devextreme-react/chart'; const data = [ { argument: 1, value: 10 }, // ... ]; class App extends React.Component { render() { return ( <Chart ... dataSource={data}> <Series argumentField="argument" valueField="value"> <Aggregation enabled={true} calculate={calcMedianFilter} method="custom" /> </Series> </Chart> ); } } function calcMedianFilter(aggregationInfo) { if(aggregationInfo.data.length) { return { argument: aggregationInfo.intervalStart, value: aggregationInfo.data[Math.floor(aggregationInfo.data.length / 2)].value }; } } export default App;