Dynamic Data Update in React Charts
The React Charts component provides methods to dynamically modify data without requiring a full chart refresh. This enables real-time data visualization, interactive features, and responsive user experiences. Common scenarios include adding sensor readings, removing outdated data points, replacing entire datasets, and enabling click-based data manipulation.
These methods (addPoint, removePoint, and setData) are called on a Series instance — not on the chart itself — and are accessible via chart.series[seriesIndex]. The chart instance is typically obtained by assigning a ref to the <ChartComponent> element.
Adding a new data point
Use the addPoint method to dynamically append a new data point to a series. This is useful for real-time data streams, user interactions, or incremental data loading. The method accepts the following parameters:
- Data point (required): The new data object to append to the series (must match the datasource structure)
- Animation duration (optional): Duration in milliseconds for the entry animation
The method returns void and mutates the series in place. For the complete signature (including the optional isNew flag and overloads), see the addPoint API reference.
import * as React from "react";
import * as ReactDOM from "react-dom";
import {
ChartComponent, SeriesCollectionDirective, SeriesDirective, Inject,
Legend, Category, DataLabel, SplineSeries
} from '@syncfusion/ej2-react-charts';
import { data } from './datasource';
function App() {
const primaryXAxis = { valueType: 'Category', enableTrim: false, majorTickLines: { width: 0 }, majorGridLines: { width: 0 } };
const primaryYAxis = { minimum: 0, maximum: 800, labelFormat: '{value}M', edgeLabelPlacement: 'Shift' };
const marker = {
visible: true,
dataLabel: {
visible: true,
position: 'Top',
font: {
fontWeight: '600'
}
}
};
const legendSettings = { visible: false };
let chartInstance;
function clickHandler() {
chartInstance.series[0].addPoint({ x: 'Japan', y: 118.2 });
}
return (<div>
<button value='add' onClick={clickHandler.bind(this)}>Add Point</button>
<ChartComponent id='charts' ref={chart => chartInstance = chart} primaryXAxis={primaryXAxis} primaryYAxis={primaryYAxis} legendSettings={legendSettings} title='Internet Users - 2016' chartArea={{ border: { width: 1 } }}>
<Inject services={[SplineSeries, Legend, DataLabel, Category]} />
<SeriesCollectionDirective>
<SeriesDirective dataSource={data} xName='x' yName='y' width={2} name='Users' type='Spline' marker={marker}>
</SeriesDirective>
</SeriesCollectionDirective>
</ChartComponent></div>);
}
;
export default App;
ReactDOM.render(<App />, document.getElementById("charts"));import * as React from "react";
import * as ReactDOM from "react-dom";
import {
AxisModel, ChartComponent, SeriesCollectionDirective, SeriesDirective, Inject,
Legend, Category, DataLabel, SplineSeries, MarkerSettingsModel, LegendSettingsModel
} from '@syncfusion/ej2-react-charts';
import { data } from './datasource';
function App() {
const primaryXAxis: AxisModel = { valueType: 'Category', enableTrim: false, majorTickLines: { width: 0 }, majorGridLines: { width: 0 } };
const primaryYAxis: AxisModel = { minimum: 0, maximum: 800, labelFormat: '{value}M', edgeLabelPlacement: 'Shift' };
const marker: MarkerSettingsModel = {
visible: true,
dataLabel: {
visible: true,
position: 'Top',
font: {
fontWeight: '600'
}
}
};
const legendSettings: LegendSettingsModel = { visible: false };
let chartInstance: ChartComponent;
function clickHandler() {
chartInstance.series[0].addPoint({ x: 'Japan', y: 118.2 });
}
return (<div>
<button value='add' onClick={clickHandler.bind(this)}>Add Point</button>
<ChartComponent id='charts' ref={chart => chartInstance = chart} primaryXAxis={primaryXAxis} primaryYAxis={primaryYAxis} legendSettings={legendSettings} title='Internet Users - 2016' chartArea={{ border: { width: 1 } }}>
<Inject services={[SplineSeries, Legend, DataLabel, Category]} />
<SeriesCollectionDirective>
<SeriesDirective dataSource={data} xName='x' yName='y' width={2} name='Users' type='Spline' marker={marker}>
</SeriesDirective>
</SeriesCollectionDirective>
</ChartComponent></div>)
};
export default App;
ReactDOM.render(<App />, document.getElementById("charts"));export let data = [
{ x: "Germany", y: 72 },
{ x: "Russia", y: 103.1 },
{ x: "Brazil", y: 139.1 },
{ x: "India", y: 462.1 },
{ x: "China", y: 721.4 },
{ x: "USA", y: 286.9 },
{ x: "Great Britain", y: 115.1 },
{ x: "Nigeria", y: 97.2 }
];export let data: Object[] = [
{ x: "Germany", y: 72 },
{ x: "Russia", y: 103.1 },
{ x: "Brazil", y: 139.1 },
{ x: "India", y: 462.1 },
{ x: "China", y: 721.4 },
{ x: "USA", y: 286.9 },
{ x: "Great Britain", y: 115.1 },
{ x: "Nigeria", y: 97.2 }
];Removing an existing data point
Use the removePoint method to dynamically delete a data point from a series by its index. This is useful for filtering data, removing outliers, or responding to user actions. The method accepts the following parameters:
- Point index (required): The zero-based index of the data point to remove. The index refers to the data point’s position in the series — not its data value. To remove a point by a specific value, find its index first.
- Animation duration (optional): Duration in milliseconds for the exit animation
The method returns void and mutates the series in place. See the removePoint API reference for the full signature.
import * as React from "react";
import * as ReactDOM from "react-dom";
import {
ChartComponent, SeriesCollectionDirective, SeriesDirective, Inject,
Legend, Category, DataLabel, SplineSeries
} from '@syncfusion/ej2-react-charts';
import { data } from './datasource';
function App() {
const primaryXAxis = { valueType: 'Category', enableTrim: false, majorTickLines: { width: 0 }, majorGridLines: { width: 0 } };
const primaryYAxis = { minimum: 0, maximum: 800, labelFormat: '{value}M', edgeLabelPlacement: 'Shift' };
const marker = {
visible: true,
dataLabel: {
visible: true,
position: 'Top',
font: {
fontWeight: '600'
}
}
};
const legendSettings = { visible: false };
let chartInstance;
function clickHandler() {
chartInstance.series[0].removePoint(0);
}
return (<div>
<button value='remove' onClick={clickHandler.bind(this)}>Remove Point</button>
<ChartComponent id='charts' ref={chart => chartInstance = chart} primaryXAxis={primaryXAxis} primaryYAxis={primaryYAxis} legendSettings={legendSettings} title='Internet Users - 2016' chartArea={{ border: { width: 1 } }}>
<Inject services={[SplineSeries, Legend, DataLabel, Category]} />
<SeriesCollectionDirective>
<SeriesDirective dataSource={data} xName='x' yName='y' width={2} name='Users' type='Spline' marker={marker}>
</SeriesDirective>
</SeriesCollectionDirective>
</ChartComponent></div>);
}
;
export default App;
ReactDOM.render(<App />, document.getElementById("charts"));import * as React from "react";
import * as ReactDOM from "react-dom";
import {
AxisModel, ChartComponent, SeriesCollectionDirective, SeriesDirective, Inject,
Legend, Category, DataLabel, SplineSeries, MarkerSettingsModel, LegendSettingsModel
} from '@syncfusion/ej2-react-charts';
import { data } from './datasource';
function App() {
const primaryXAxis: AxisModel = { valueType: 'Category', enableTrim: false, majorTickLines: { width: 0 }, majorGridLines: { width: 0 } };
const primaryYAxis: AxisModel = { minimum: 0, maximum: 800, labelFormat: '{value}M', edgeLabelPlacement: 'Shift' };
const marker: MarkerSettingsModel = {
visible: true,
dataLabel: {
visible: true,
position: 'Top',
font: {
fontWeight: '600'
}
}
};
const legendSettings: LegendSettingsModel = { visible: false };
let chartInstance: ChartComponent;
function clickHandler() {
chartInstance.series[0].removePoint(0);
}
return (<div>
<button value='remove' onClick={clickHandler.bind(this)}>Remove Point</button>
<ChartComponent id='charts' ref={chart => chartInstance = chart} primaryXAxis={primaryXAxis} primaryYAxis={primaryYAxis} legendSettings={legendSettings} title='Internet Users - 2016' chartArea={{ border: { width: 1 } }}>
<Inject services={[SplineSeries, Legend, DataLabel, Category]} />
<SeriesCollectionDirective>
<SeriesDirective dataSource={data} xName='x' yName='y' width={2} name='Users' type='Spline' marker={marker}>
</SeriesDirective>
</SeriesCollectionDirective>
</ChartComponent></div>)
};
export default App;
ReactDOM.render(<App />, document.getElementById("charts"));export let data = [
{ x: "Germany", y: 72 },
{ x: "Russia", y: 103.1 },
{ x: "Brazil", y: 139.1 },
{ x: "India", y: 462.1 },
{ x: "China", y: 721.4 },
{ x: "USA", y: 286.9 },
{ x: "Great Britain", y: 115.1 },
{ x: "Nigeria", y: 97.2 }
];export let data: Object[] = [
{ x: "Germany", y: 72 },
{ x: "Russia", y: 103.1 },
{ x: "Brazil", y: 139.1 },
{ x: "India", y: 462.1 },
{ x: "China", y: 721.4 },
{ x: "USA", y: 286.9 },
{ x: "Great Britain", y: 115.1 },
{ x: "Nigeria", y: 97.2 }
];Replacing the dataset of a series
Use the setData method to replace all data points in a series with a new dataset. This is useful for category switching, time range changes, or complete data refreshes. The method accepts the following parameters:
-
New data source (required): The complete new dataset array to display (must match the existing datasource structure — same
xNameandyNamefields) - Animation duration (optional): Duration in milliseconds for the transition animation
The method returns void and mutates the series in place. See the setData API reference for the full signature.
import * as React from "react";
import * as ReactDOM from "react-dom";
import { ChartComponent, SeriesCollectionDirective, SeriesDirective, Inject, ColumnSeries, Category } from '@syncfusion/ej2-react-charts';
import { data } from './datasource';
function App() {
const primaryXAxis = { valueType: 'Category', majorGridLines: { width: 0 }, labelStyle: { size: '12px' }, labelIntersectAction: 'Rotate90' };
const primaryYAxis = { title: 'Sales (in percentage)', labelFormat: '{value}%', lineStyle: { width: 0 }, majorTickLines: { width: 0 }, interval: 5, minimum: 0, maximum: 100 };
let chartInstance;
function clickHandler() {
const newData = data.map((item) => {
const value = getRandomInt(10, 90);
return { x: item.x, y: value };
});
if (chartInstance.series.length > 0) {
chartInstance.series[0].setData(newData, 500);
}
}
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
let axisRangeCalculated = (args) => {
if (args.axis.name === 'primaryYAxis') {
args.maximum = args.maximum > 100 ? 100 : args.maximum;
if (args.maximum > 80) {
args.interval = 20;
}
else if (args.maximum > 40) {
args.interval = 10;
}
}
}
return (<div>
<button value='update' onClick={clickHandler.bind(this)}>Update Data</button>
<ChartComponent id='charts' ref={chart => chartInstance = chart} primaryXAxis={primaryXAxis} primaryYAxis={primaryYAxis} title='Sales by product' chartArea={{ border: { width: 0 } }} axisRangeCalculated={axisRangeCalculated.bind(this)}>
<Inject services={[ColumnSeries, Category]} />
<SeriesCollectionDirective>
<SeriesDirective dataSource={data} xName='x' yName='y' cornerRadius={{ topLeft: 15, topRight: 15 }} columnWidth={0.5} type='Column'>
</SeriesDirective>
</SeriesCollectionDirective>
</ChartComponent></div>);
}
;
export default App;
ReactDOM.render(<App />, document.getElementById("charts"));import * as React from "react";
import * as ReactDOM from "react-dom";
import {
AxisModel, ChartComponent, SeriesCollectionDirective, SeriesDirective, Inject,
ColumnSeries, Category, IAxisRangeCalculatedEventArgs
} from '@syncfusion/ej2-react-charts';
import { data } from './datasource';
function App() {
const primaryXAxis: AxisModel = { valueType: 'Category', majorGridLines: { width: 0 }, labelStyle: { size: '12px' }, labelIntersectAction: 'Rotate90' };
const primaryYAxis: AxisModel = { title: 'Sales (in percentage)', labelFormat: '{value}%', lineStyle: { width: 0 }, majorTickLines: { width: 0 }, interval: 5, minimum: 0, maximum: 100 };
let chartInstance: ChartComponent;
function clickHandler() {
const newData = data.map((item: { x: string, y: number }) => {
const value: number = getRandomInt(10, 90);
return { x: item.x, y: value };
});
if (chartInstance.series.length > 0) {
chartInstance.series[0].setData(newData, 500);
}
}
function getRandomInt(min: number, max: number) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
let axisRangeCalculated = (args: IAxisRangeCalculatedEventArgs): void => {
if (args.axis.name === 'primaryYAxis') {
args.maximum = args.maximum as number > 100 ? 100 : args.maximum;
if (args.maximum > 80) {
args.interval = 20;
}
else if (args.maximum > 40) {
args.interval = 10;
}
}
}
return (<div>
<button value='update' onClick={clickHandler.bind(this)}>Update Data</button>
<ChartComponent id='charts' ref={chart => chartInstance = chart} primaryXAxis={primaryXAxis} primaryYAxis={primaryYAxis} title='Sales by product' chartArea={{ border: { width: 0 } }} axisRangeCalculated={axisRangeCalculated.bind(this)}>
<Inject services={[ColumnSeries, Category]} />
<SeriesCollectionDirective>
<SeriesDirective dataSource={data} xName='x' yName='y' cornerRadius={{ topLeft: 15, topRight: 15 }} columnWidth={0.5} type='Column'>
</SeriesDirective>
</SeriesCollectionDirective>
</ChartComponent></div>)
};
export default App;
ReactDOM.render(<App />, document.getElementById("charts"));export let data = [
{ x: 'Jewellery', y: 75 },
{ x: 'Shoes', y: 45 },
{ x: 'Footwear', y: 73 },
{ x: 'Pet Services', y: 53 },
{ x: 'Business Clothing', y: 85 },
{ x: 'Office Supplies', y: 68 },
{ x: 'Food', y: 45 }
];export let data: any[] = [
{ x: 'Jewellery', y: 75 },
{ x: 'Shoes', y: 45 },
{ x: 'Footwear', y: 73 },
{ x: 'Pet Services', y: 53 },
{ x: 'Business Clothing', y: 85 },
{ x: 'Office Supplies', y: 68 },
{ x: 'Food', y: 45 }
];Click to add or remove a data point
Enable users to add or remove data points by clicking on the chart. Listen to the chartMouseClick event to capture click coordinates and point information. When a user clicks within the chart area, the event arguments expose args.axisData (the x and y axis values) which you can use to determine what was clicked.
The example below implements click-to-add and click-to-remove with a pixel-tolerance match against existing data points. Because the click coordinates are pixel values but the data points are in axis units, the sample iterates the series’ points and compares them with a tolerance equal to half the marker’s width. If a match is found, removePoint is called with that index; otherwise addPoint is called with the rounded axis values. This creates an intuitive interface for data exploration and editing.
Note: The point-matching algorithm in the sample is intentionally simple. For production use, you may need to adjust the tolerance, account for axis scale (linear vs. logarithmic), and handle edge cases such as overlapping points.
import * as React from "react";
import * as ReactDOM from "react-dom";
import { ChartComponent, SeriesCollectionDirective, SeriesDirective, Inject, LineSeries, DataLabel, Tooltip } from '@syncfusion/ej2-react-charts';
import { data } from './datasource';
function App() {
const primaryXAxis = { edgeLabelPlacement: 'Shift', rangePadding: 'Additional', majorGridLines: { width: 0 } };
const primaryYAxis = { title: 'Value', interval: 20, lineStyle: { width: 0 }, majorTickLines: { width: 0 } };
const marker = {
visible: true,
isFilled: true,
border: {
width: 2,
color: 'White'
},
width: 13,
height: 13
};
const tooltip = { enable: true };
let chartInstance;
const axisRangeCalculated = (args) => {
if (args.axis.name === 'primaryXAxis') {
if (args.interval < 10) {
args.maximum = args.maximum + 10;
args.minimum = args.minimum - 10;
args.interval = 10;
}
}
if (args.axis.name === 'primaryYAxis') {
if (args.maximum <= 60) {
args.interval = 10;
}
}
}
const chartMouseClick = (args) => {
let isRemoved = false;
if (args.axisData) {
for (let i = 0; i < (chartInstance.series[0]).points.length; i++) {
const markerWidth = (chartInstance.series[0]).marker.width / 2;
let roundedX = Math.round(args.axisData['primaryXAxis']) + markerWidth;
let roundedY = Math.round(args.axisData['primaryYAxis']) + markerWidth;
let pointX = Math.round((chartInstance.series[0]).points[i].x) + markerWidth;
let pointY = Math.round((chartInstance.series[0]).points[i].y) + markerWidth;
if ((roundedX === pointX || roundedX + 1 === pointX || roundedX - 1 === pointX) &&
(roundedY === pointY || roundedY + 1 === pointY || roundedY - 1 === pointY)) {
if ((chartInstance.series[0]).points.length > 1) {
const points = (chartInstance.series[0]).points;
const duration = i === 0 || i === points[points.length - 1].index ? 500 : 0;
chartInstance.series[0].removePoint(i, duration);
}
isRemoved = true;
}
}
if (!isRemoved) {
chartInstance.series[0].addPoint({ x: Math.round(args.axisData['primaryXAxis']), y: Math.round(args.axisData['primaryYAxis']) });
}
}
};
return (<div>
<ChartComponent id='charts' ref={chart => chartInstance = chart} primaryXAxis={primaryXAxis} primaryYAxis={primaryYAxis} tooltip={tooltip} title='User supplied data' chartArea={{ border: { width: 0 } }} axisRangeCalculated={axisRangeCalculated.bind(this)} chartMouseClick={chartMouseClick.bind(this)}>
<Inject services={[LineSeries, DataLabel, Tooltip]} />
<SeriesCollectionDirective>
<SeriesDirective dataSource={data} xName='x' yName='y' marker={marker} width={3} type='Line'>
</SeriesDirective>
</SeriesCollectionDirective>
</ChartComponent></div>);
}
;
export default App;
ReactDOM.render(<App />, document.getElementById("charts"));import * as React from "react";
import * as ReactDOM from "react-dom";
import {
AxisModel, ChartComponent, SeriesCollectionDirective, SeriesDirective, Inject,
LineSeries, DataLabel, Tooltip, MarkerSettingsModel, IAxisRangeCalculatedEventArgs, Series, TooltipSettingsModel, IMouseEventArgs
} from '@syncfusion/ej2-react-charts';
import { data } from './datasource';
function App() {
const primaryXAxis: AxisModel = { edgeLabelPlacement: 'Shift', rangePadding: 'Additional', majorGridLines: { width: 0 } };
const primaryYAxis: AxisModel = { title: 'Value', interval: 20, lineStyle: { width: 0 }, majorTickLines: { width: 0 } };
const marker: MarkerSettingsModel = {
visible: true,
isFilled: true,
border: {
width: 2,
color: 'White'
},
width: 13,
height: 13
};
const tooltip: TooltipSettingsModel = { enable: true };
let chartInstance: ChartComponent;
const axisRangeCalculated = (args: IAxisRangeCalculatedEventArgs): void => {
if (args.axis.name === 'primaryXAxis') {
if (args.interval < 10) {
args.maximum = args.maximum + 10;
args.minimum = args.minimum - 10;
args.interval = 10;
}
}
if (args.axis.name === 'primaryYAxis') {
if (args.maximum <= 60) {
args.interval = 10;
}
}
}
const chartMouseClick = (args: IMouseEventArgs): void => {
let isRemoved: boolean = false;
if (args.axisData) {
for (let i: number = 0; i < (chartInstance.series[0] as Series).points.length; i++) {
const markerWidth: number = (chartInstance.series[0] as Series).marker.width / 2;
let roundedX: number = Math.round(args.axisData['primaryXAxis']) + markerWidth;
let roundedY: number = Math.round(args.axisData['primaryYAxis']) + markerWidth;
let pointX: number = Math.round((chartInstance.series[0] as Series).points[i].x as number) + markerWidth;
let pointY: number = Math.round((chartInstance.series[0] as Series).points[i].y as number) + markerWidth;
if ((roundedX === pointX || roundedX + 1 === pointX || roundedX - 1 === pointX) &&
(roundedY === pointY || roundedY + 1 === pointY || roundedY - 1 === pointY)) {
if ((chartInstance.series[0] as Series).points.length > 1) {
const points = (chartInstance.series[0] as Series).points;
const duration: number = i === 0 || i === points[points.length - 1].index ? 500 : 0;
chartInstance.series[0].removePoint(i, duration);
}
isRemoved = true;
}
}
if (!isRemoved) {
chartInstance.series[0].addPoint({ x: Math.round(args.axisData['primaryXAxis']), y: Math.round(args.axisData['primaryYAxis']) });
}
}
};
return (<div>
<ChartComponent id='charts' ref={chart => chartInstance = chart} primaryXAxis={primaryXAxis} primaryYAxis={primaryYAxis} tooltip={tooltip} title='User supplied data' chartArea={{ border: { width: 0 } }} axisRangeCalculated={axisRangeCalculated.bind(this)} chartMouseClick={chartMouseClick.bind(this)}>
<Inject services={[LineSeries, DataLabel, Tooltip]} />
<SeriesCollectionDirective>
<SeriesDirective dataSource={data} xName='x' yName='y' marker={marker} width={3} type='Line'>
</SeriesDirective>
</SeriesCollectionDirective>
</ChartComponent></div>)
};
export default App;
ReactDOM.render(<App />, document.getElementById("charts"));export let data = [
{ x: 20, y: 20 },
{ x: 80, y: 80 }
];export let data: Object[] = [
{ x: 20, y: 20 },
{ x: 80, y: 80 }
];