In the world of data-driven applications, presenting complex information clearly and interactively is paramount. While AG Grid excels at displaying and manipulating tabular data, combining its robust capabilities with powerful data visualization tools unlocks new levels of insight. This post delves into how to effectively leverage AG Charts alongside AG Grid in your React applications, transforming raw data into compelling visual stories.
AG Charts, developed by the same team behind AG Grid, offers a high-performance, enterprise-grade charting library designed for seamless integration. Whether you need integrated charts that pop up directly from your grid selections or standalone charts driven by grid data, AG Charts provides the flexibility and power you need.
Prerequisites & Setup
Before we dive into the code, ensure you have a basic React project set up. You'll need to install AG Grid React and AG Charts React packages.
npm install ag-grid-community ag-grid-react ag-charts-community ag-charts-react
# or yarn add ag-grid-community ag-grid-react ag-charts-community ag-charts-react
You'll also need to import the necessary styles for AG Grid:
// In your main App.js or component file
import 'ag-grid-community/styles/ag-grid.css';
import 'ag-grid-community/styles/ag-theme-alpine.css';
Integrated Charts: Visualizing Data Directly from AG Grid
One of the most powerful features of AG Charts is its deep integration with AG Grid, allowing users to create charts directly from selected data ranges within the grid. This capability is often referred to as "integrated charts" or "range charts."
Enabling Chart Creation
To enable chart creation, you need to set enableCharts: true in your grid options or individual column definitions. This allows users to select a range of cells and open a context menu to create a chart.
import React, { useState, useRef, useCallback } from 'react';
import { AgGridReact } from 'ag-grid-react';
const MyGridComponent = () => {
const gridRef = useRef();
const [rowData] = useState([
{ make: 'Toyota', model: 'Celica', price: 35000, fuelEfficiency: 12 },
{ make: 'Ford', model: 'Mondeo', price: 32000, fuelEfficiency: 10 },
{ make: 'Porsche', model: 'Boxster', price: 72000, fuelEfficiency: 8 },
{ make: 'BMW', model: 'M5', price: 60000, fuelEfficiency: 9 },
{ make: 'Volvo', model: 'V40', price: 28000, fuelEfficiency: 11 },
]);
const [columnDefs] = useState([
{ field: 'make', enableCharts: true },
{ field: 'model' },
{ field: 'price', enableCharts: true, type: 'numericColumn' },
{ field: 'fuelEfficiency', enableCharts: true, type: 'numericColumn' },
]);
const defaultColDef = {
flex: 1,
minWidth: 100,
resizable: true,
};
return (
<div className="ag-theme-alpine" style={{ height: 400, width: 600 }}>
<AgGridReact
ref={gridRef}
rowData={rowData}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
enableRangeSelection={true} // Essential for range charts
enableCharts={true} // Global setting to enable charts
></AgGridReact>
</div>
);
};
export default MyGridComponent;
With enableRangeSelection={true} and enableCharts={true}, your users can now select a range of cells (e.g., 'price' and 'fuelEfficiency') and right-click to open a context menu with "Chart Range" options.
Programmatically Creating Charts with createRangeChart
For more controlled or automated chart generation, you can use the createRangeChart method available via the AG Grid API. This is particularly useful for dashboards where you want to pre-define charts based on specific data.
import React, { useState, useRef, useCallback } from 'react';
import { AgGridReact } from 'ag-grid-react';
const MyGridChartComponent = () => {
const gridRef = useRef();
const [rowData] = useState([
{ make: 'Toyota', model: 'Celica', price: 35000, fuelEfficiency: 12 },
{ make: 'Ford', model: 'Mondeo', price: 32000, fuelEfficiency: 10 },
{ make: 'Porsche', model: 'Boxster', price: 72000, fuelEfficiency: 8 },
{ make: 'BMW', model: 'M5', price: 60000, fuelEfficiency: 9 },
{ make: 'Volvo', model: 'V40', price: 28000, fuelEfficiency: 11 },
]);
const [columnDefs] = useState([
{ field: 'make', enableCharts: true },
{ field: 'model' },
{ field: 'price', enableCharts: true, type: 'numericColumn' },
{ field: 'fuelEfficiency', enableCharts: true, type: 'numericColumn' },
]);
const defaultColDef = {
flex: 1,
minWidth: 100,
resizable: true,
};
const onGridReady = useCallback((params) => {
// You can programmatically create a chart once the grid is ready
// or trigger it from a button click.
// For demonstration, let's create a chart after a short delay.
setTimeout(() => {
const chartParams = {
chartType: 'groupedColumn', // e.g., 'bar', 'line', 'pie', 'scatter'
cellRange: {
rowStartIndex: 0,
rowEndIndex: rowData.length - 1,
columns: ['make', 'price', 'fuelEfficiency'],
},
// Optional: Customize the chart's initial state
chartContainer: document.querySelector('#myChartContainer'), // Or let AG Grid create a popup
aggFunc: 'sum', // How to aggregate data if multiple rows are selected for a category
suppressChartMenu: false, // Show the chart menu for user interaction
chartToolPanelsDef: { // Pre-select initial configurations
defaultCategorySelected: 'data',
defaultSeriesSelected: 'data',
panels: ['data', 'format']
}
};
// Calling createRangeChart opens the chart in a popup or a specified container
gridRef.current.api.createRangeChart(chartParams);
}, 1000);
}, [rowData]); // Depend on rowData to ensure it's available
return (
<div>
<div className="ag-theme-alpine" style={{ height: 400, width: 600 }}>
<AgGridReact
ref={gridRef}
rowData={rowData}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
enableRangeSelection={true}
enableCharts={true}
onGridReady={onGridReady}
></AgGridReact>
</div>
<div id="myChartContainer" style={{ height: 300, width: '100%', marginTop: '20px' }}></div>
</div>
);
};
export default MyGridChartComponent;
The chartToolPanelsDef property is incredibly powerful for configuring the default state of the chart tool panels (Data, Format, Customise) that appear with integrated charts. You can pre-select categories, series, or even hide panels entirely.
Standalone AG Charts with AG Grid Data
While integrated charts are excellent for ad-hoc analysis, sometimes you need a dedicated chart component in a specific part of your layout, populated with data from AG Grid. This is where using the AgChartsReact component directly comes into play.
Fetching Data from AG Grid for Standalone Charts
You can retrieve data from AG Grid using its API methods, such as api.getDataAsCsv() (and parse it), api.forEachNode(), or by maintaining a state variable for your row data that both the grid and the chart can access.
import React, { useState, useRef, useCallback, useEffect } from 'react';
import { AgGridReact } from 'ag-grid-react';
import { AgChartsReact } from 'ag-charts-react';
const MyStandaloneChartComponent = () => {
const gridRef = useRef();
const [gridData, setGridData] = useState([
{ make: 'Toyota', model: 'Celica', price: 35000, fuelEfficiency: 12 },
{ make: 'Ford', model: 'Mondeo', price: 32000, fuelEfficiency: 10 },
{ make: 'Porsche', model: 'Boxster', price: 72000, fuelEfficiency: 8 },
{ make: 'BMW', model: 'M5', price: 60000, fuelEfficiency: 9 },
{ make: 'Volvo', model: 'V40', price: 28000, fuelEfficiency: 11 },
]);
const [chartOptions, setChartOptions] = useState({});
const [columnDefs] = useState([
{ field: 'make' },
{ field: 'model' },
{ field: 'price', type: 'numericColumn' },
{ field: 'fuelEfficiency', type: 'numericColumn' },
]);
const defaultColDef = {
flex: 1,
minWidth: 100,
resizable: true,
};
// Update chart options when gridData changes
useEffect(() => {
if (gridData.length > 0) {
setChartOptions({
data: gridData,
title: { text: 'Car Price vs. Fuel Efficiency' },
series: [
{
type: 'scatter',
xKey: 'fuelEfficiency',
yKey: 'price',
xName: 'Fuel Efficiency (km/l)',
yName: 'Price ($)',
labelKey: 'make', // Show car make on hover
},
],
axes: [
{ type: 'number', position: 'bottom', title: { text: 'Fuel Efficiency' } },
{ type: 'number', position: 'left', title: { text: 'Price' } },
],
});
}
}, [gridData]);
// Example of retrieving data from the grid's model (e.g., after filtering/sorting)
const updateChartFromGrid = useCallback(() => {
if (gridRef.current && gridRef.current.api) {
const rowDataFromGrid = [];
gridRef.current.api.forEachNode(node => rowDataFromGrid.push(node.data));
setGridData(rowDataFromGrid); // Update the state, which will re-render the chart
}
}, []);
return (
<div>
<div className="ag-theme-alpine" style={{ height: 200, width: 600 }}>
<AgGridReact
ref={gridRef}
rowData={gridData} // Initial data for the grid
columnDefs={columnDefs}
defaultColDef={defaultColDef}
></AgGridReact>
</div>
<button onClick={updateChartFromGrid} style={{ marginTop: '10px', marginBottom: '20px' }}>
Update Chart from Grid Data
</button>
<div style={{ height: 400, width: 600 }}>
{gridData.length > 0 && <AgChartsReact options={chartOptions} />}
</div>
</div>
);
};
export default MyStandaloneChartComponent;
In this example, the gridData state is shared. Any changes to gridData (e.g., from an external API call that updates both grid and chart) will reflect in both components. The updateChartFromGrid function demonstrates how you could fetch the *current* data from the grid (after user interactions like filtering or sorting) and use it to update the standalone chart.
Customizing Your Charts
AG Charts offers extensive customization options, whether you're using integrated or standalone charts.
-
Chart Types: Easily switch between various chart types like Bar, Column, Line, Area, Pie, Doughnut, Scatter, Bubble, and more.
// Example for integrated chart (in createRangeChart options) chartType: 'pie', // Example for standalone chart (in chartOptions) series: [{ type: 'column', xKey: 'make', yKey: 'price' }], -
Themes: Apply different themes to match your application's aesthetic. AG Charts comes with several built-in themes, and you can create custom ones.
import { AgChartsReact } from 'ag-charts-react'; import { AgChartTheme } from 'ag-charts-community'; // For standalone chart <AgChartsReact options={{ ...myChartOptions, theme: AgChartTheme.AG_NIGHT }} /> // For integrated chart (in chartToolPanelsDef or chartOptions) chartTheme: 'ag-material', -
Series and Axis Customization: Fine-tune every aspect of your series (colors, markers, tooltips) and axes (titles, labels, ranges).
// Example chart options for detailed customization const chartOptions = { data: myData, title: { text: 'Sales Performance' }, subtitle: { text: 'By Quarter' }, series: [{ type: 'column', xKey: 'quarter', yKey: 'revenue', yName: 'Total Revenue', fill: 'rgba(0, 119, 204, 0.8)', stroke: 'rgba(0, 119, 204, 1)', tooltip: { renderer: ({ datum, xKey, yKey }) => { return { content: `Quarter ${datum[xKey]}: $${datum[yKey].toLocaleString()}` }; } } }], axes: [ { type: 'category', position: 'bottom', title: { text: 'Quarter' } }, { type: 'number', position: 'left', title: { text: 'Revenue ($)' }, label: { formatter: params => `$${params.value / 1000}k` } } ], // Other options like legend, background, etc. };
Key Benefits of Using AG Charts with AG Grid
- Seamless Integration: Both libraries are designed to work together, sharing common data models and configuration paradigms.
- Rich Interactivity: Integrated charts allow users to dynamically create and customize visualizations directly from grid data, enhancing self-service analytics.
- Performance: Built for enterprise-grade applications, AG Charts handles large datasets with high performance, just like AG Grid.
- Unified Look and Feel: Maintain a consistent design language across your data tables and charts, providing a cohesive user experience.
- Developer Efficiency: Leverage a single vendor for both grid and charting needs, simplifying development, support, and maintenance.
Conclusion
Integrating AG Charts with AG Grid in your React applications empowers you to deliver a comprehensive data experience. Whether through the dynamic, user-driven integrated charts or precisely controlled standalone visualizations, you can effectively present your data with clarity, interactivity, and performance. By mastering these techniques, you'll transform your data tables into powerful analytical tools, allowing users to gain deeper insights with ease.