---
title: "Time Series"
enterprise: true
framework: react
version: "36.1.0"
---

# Time Series

This section covers how to chart time series data using Integrated Charts.

Integrated Charts supports the charting of time series data using line and area charts when a time axis is chosen instead of a category or numeric axis.

## Time vs Category Axis

A [Time Axis](https://www.ag-grid.com/charts/react/axes-types/#time) is used to plot continuous date / time values, whereas a [Category Axis](https://www.ag-grid.com/charts/react/axes-types/#category) is used to plot discrete values or categories.

The example below highlights the differences between time and category axes. Notice that the time axis contains all days for the range of values provided, whereas the category axis only shows axis labels for the discrete values provide.

#### Time vs Category Axis

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  useEffect,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import "./style.css";
import { AgChartsEnterpriseModule } from "ag-charts-enterprise";
import {
  AgChartThemeOverrides,
  CellSelectionOptions,
  ChartToolPanelsDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  ColumnApiModule,
  FirstDataRenderedEvent,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  ValueFormatterParams,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ContextMenuModule,
  IntegratedChartsModule,
  RowGroupingModule,
} from "ag-grid-enterprise";
import { getData } from "./data";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [
  ColumnApiModule,
  ClientSideRowModelModule,
  IntegratedChartsModule.with(AgChartsEnterpriseModule),
  ColumnMenuModule,
  ContextMenuModule,
  RowGroupingModule,
];

let currentChartRef: any;

function getColumnDefs() {
  return [
    { field: "date", valueFormatter: dateFormatter },
    { field: "avgTemp" },
  ];
}

function dateFormatter(params: ValueFormatterParams) {
  return params.value
    ? params.value.toISOString().substring(0, 10)
    : params.value;
}

function formatDate(date: Date | number) {
  return Intl.DateTimeFormat("en-GB", {
    day: "2-digit",
    month: "short",
    year: undefined,
  }).format(new Date(date));
}

const GridExample = () => {
  const gridRef = useRef<AgGridReact>(null);
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>();
  const [columnDefs, setColumnDefs] = useState<ColDef[]>(getColumnDefs());
  const defaultColDef = useMemo<ColDef>(() => {
    return { flex: 1 };
  }, []);
  const popupParent = useMemo<HTMLElement | null>(() => {
    return document.body;
  }, []);
  const chartThemeOverrides = useMemo<AgChartThemeOverrides>(() => {
    return {
      line: {
        title: {
          enabled: true,
          text: "Average Daily Temperatures",
        },
        navigator: {
          enabled: true,
          height: 20,
          spacing: 25,
        },
        axes: {
          time: {
            label: {
              rotation: 0,
              format: "%d %b",
            },
          },
          category: {
            label: {
              rotation: 0,
              formatter: (params: any) => {
                // charts typings
                return formatDate(params.value);
              },
            },
          },
          number: {
            label: {
              formatter: (params: any) => {
                // charts typings
                return params.value + "°C";
              },
            },
          },
        },
      },
    };
  }, []);
  const chartToolPanelsDef = useMemo<ChartToolPanelsDef>(() => {
    return {
      panels: ["data", "format"],
    };
  }, []);

  const onGridReady = useCallback((params: GridReadyEvent) => {
    getData().then((rowData) => setRowData(rowData));
  }, []);

  const onFirstDataRendered = useCallback(
    (params: FirstDataRenderedEvent) => {
      if (currentChartRef) {
        currentChartRef.destroyChart();
      }
      currentChartRef = params.api.createRangeChart({
        chartContainer: document.querySelector("#myChart") as HTMLElement,
        cellRange: {
          columns: ["date", "avgTemp"],
        },
        suppressChartRanges: true,
        chartType: "line",
      });
    },
    [currentChartRef],
  );

  const toggleAxis = useCallback(() => {
    const axisBtn = document.querySelector("#axisBtn") as any;
    axisBtn.textContent = axisBtn.value;
    axisBtn.value = axisBtn.value === "time" ? "category" : "time";
    const columnDefs: ColDef[] = getColumnDefs();
    columnDefs.forEach((colDef) => {
      if (colDef.field === "date") {
        colDef.chartDataType = axisBtn.value;
      }
    });
    gridRef.current!.api.setGridOption("columnDefs", columnDefs);
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div className="wrapper">
          <div id="buttonRow">
            <label>Switch Axis to: </label>
            <button id="axisBtn" onClick={toggleAxis} value="time">
              Category
            </button>
          </div>

          <div style={gridStyle} className="my-grid">
            <AgGridReact
              ref={gridRef}
              rowData={rowData}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              cellSelection={true}
              popupParent={popupParent}
              enableCharts={true}
              chartThemeOverrides={chartThemeOverrides}
              chartToolPanelsDef={chartToolPanelsDef}
              onGridReady={onGridReady}
              onFirstDataRendered={onFirstDataRendered}
            />
          </div>
          <div id="myChart" className="my-chart"></div>
        </div>
      </div>
    </AgGridProvider>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <GridExample />
  </StrictMode>,
);
```

[Live example: Time vs Category Axis](https://www.ag-grid.com/examples/integrated-charts-time-series/time-vs-category/reactFunctionalTs/)

## Time Axis Configuration

A [Time Axis](https://www.ag-grid.com/charts/react/axes-types/#time) can be configured by setting `chartDataType = 'time'` on the column definition.

For the time axis to work correctly, the column must contain values in one of the following formats:

- `Date`
- `string` in ISO 8601 format
- `number` representing the numeric timestamp

Additionally, if `chartDataType` is not specified and the column contains `Date` values, it will automatically use a time axis.

The following snippet shows how different time series values can be configured to enable a time axis:

```jsx
const [columnDefs, setColumnDefs] = useState([
    // date objects are treated as time by default
    { field: 'someDate' },
    { field: 'someIsoString', chartDataType: 'time' },
    { field: 'someTimestamp', chartDataType: 'time' },
]);
const [rowData, setRowData] = useState([
    {
        someDate: new Date('Mon Apr 17 2023 12:43:17'), // date object
        someIsoString: '2023-04-17T11:43:17.000Z', // ISO 8601 string
        someTimestamp: 1681735397000, // numeric timestamp (JavaScript format)
    },
    // ... more rows
]);

<AgGridReact
    columnDefs={columnDefs}
    rowData={rowData}
/>
```

The following example demonstrates configuring numeric timestamps to use a time axis:

#### Time Axis Configuration

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  useEffect,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import "./style.css";
import { AgChartsEnterpriseModule } from "ag-charts-enterprise";
import {
  AgChartThemeOverrides,
  CellSelectionOptions,
  ChartToolPanelsDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  FirstDataRenderedEvent,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ContextMenuModule,
  IntegratedChartsModule,
  RowGroupingModule,
} from "ag-grid-enterprise";
import { getData } from "./data";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [
  ClientSideRowModelModule,
  IntegratedChartsModule.with(AgChartsEnterpriseModule),
  ColumnMenuModule,
  ContextMenuModule,
  RowGroupingModule,
];

function formatTime(date: Date | number) {
  return Intl.DateTimeFormat("en-GB", {
    hour: "2-digit",
    minute: "2-digit",
    second: "2-digit",
  }).format(new Date(date));
}

const GridExample = () => {
  const gridRef = useRef<AgGridReact>(null);
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>();
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "timestamp", chartDataType: "time" },
    { field: "cpuUsage" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return { flex: 1 };
  }, []);
  const popupParent = useMemo<HTMLElement | null>(() => {
    return document.body;
  }, []);
  const chartThemeOverrides = useMemo<AgChartThemeOverrides>(() => {
    return {
      area: {
        title: {
          enabled: true,
          text: "CPU Usage",
        },
        navigator: {
          enabled: true,
          height: 20,
          spacing: 25,
        },
        axes: {
          time: {
            label: {
              rotation: 315,
              format: "%H:%M",
            },
          },
          number: {
            label: {
              formatter: (params: any) => {
                // charts typings
                return params.value + "%";
              },
            },
          },
        },
      },
    };
  }, []);
  const chartToolPanelsDef = useMemo<ChartToolPanelsDef>(() => {
    return {
      panels: ["data", "format"],
    };
  }, []);

  const onGridReady = useCallback((params: GridReadyEvent) => {
    getData().then((rowData) => setRowData(rowData));
  }, []);

  const onFirstDataRendered = useCallback((params: FirstDataRenderedEvent) => {
    params.api.createRangeChart({
      chartContainer: document.querySelector("#myChart") as HTMLElement,
      cellRange: {
        columns: ["timestamp", "cpuUsage"],
      },
      suppressChartRanges: true,
      chartType: "area",
    });
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div className="wrapper">
          <div style={gridStyle} className="my-grid">
            <AgGridReact
              ref={gridRef}
              rowData={rowData}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              cellSelection={true}
              popupParent={popupParent}
              enableCharts={true}
              chartThemeOverrides={chartThemeOverrides}
              chartToolPanelsDef={chartToolPanelsDef}
              onGridReady={onGridReady}
              onFirstDataRendered={onFirstDataRendered}
            />
          </div>
          <div id="myChart" className="my-chart"></div>
        </div>
      </div>
    </AgGridProvider>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <GridExample />
  </StrictMode>,
);
```

[Live example: Time Axis Configuration](https://www.ag-grid.com/examples/integrated-charts-time-series/time-axis-config/reactFunctionalTs/)

## Time Axis Combination Chart

A time axis can also be used in combination charts as shown in the following example.

For more details on how to configure a combination chart, see the [Range Chart API example](https://www.ag-grid.com/react-data-grid/integrated-charts-api-range-chart/#combination-charts).

#### Time Axis Combination Chart

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  useEffect,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import "./style.css";
import { AgChartsEnterpriseModule } from "ag-charts-enterprise";
import {
  AgAxisCaptionFormatterParams,
  AgCartesianSeriesTooltipRendererParams,
  AgCrosshairLabelRendererParams,
} from "ag-charts-types";
import {
  AgChartThemeOverrides,
  CellSelectionOptions,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  FirstDataRenderedEvent,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  ValueParserParams,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ContextMenuModule,
  IntegratedChartsModule,
  RowGroupingModule,
} from "ag-grid-enterprise";
import { getData } from "./data";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [
  ClientSideRowModelModule,
  IntegratedChartsModule.with(AgChartsEnterpriseModule),
  ColumnMenuModule,
  ContextMenuModule,
  RowGroupingModule,
];

function numberParser(params: ValueParserParams) {
  const value = params.newValue;
  if (value === null || value === undefined || value === "") {
    return null;
  }
  return parseFloat(value);
}

function formatDate(date: Date | number) {
  return Intl.DateTimeFormat("en-GB", {
    day: "2-digit",
    month: "short",
    year: undefined,
  }).format(new Date(date));
}

const GridExample = () => {
  const gridRef = useRef<AgGridReact>(null);
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>();
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    {
      field: "date",
      chartDataType: "time",
      valueFormatter: (params) => params.value.toISOString().substring(0, 10),
    },
    { field: "rain", chartDataType: "series", valueParser: numberParser },
    { field: "pressure", chartDataType: "series", valueParser: numberParser },
    { field: "temp", chartDataType: "series", valueParser: numberParser },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return { flex: 1 };
  }, []);
  const popupParent = useMemo<HTMLElement | null>(() => {
    return document.body;
  }, []);
  const chartThemeOverrides = useMemo<AgChartThemeOverrides>(() => {
    return {
      common: {
        padding: {
          top: 45,
        },
        axes: {
          number: {
            title: {
              enabled: true,
              formatter: (params: AgAxisCaptionFormatterParams) => {
                return params.boundSeries.map((s) => s.name).join(" / ");
              },
            },
          },
          time: {
            crosshair: {
              label: {
                renderer: (params: AgCrosshairLabelRendererParams) => ({
                  text: formatDate(params.value),
                }),
              },
            },
          },
        },
      },
      bar: {
        series: {
          strokeWidth: 2,
          fillOpacity: 0.8,
        },
      },
      line: {
        series: {
          strokeWidth: 5,
          strokeOpacity: 0.8,
        },
      },
    };
  }, []);

  const onGridReady = useCallback((params: GridReadyEvent) => {
    getData().then((rowData) => setRowData(rowData));
  }, []);

  const onFirstDataRendered = useCallback((params: FirstDataRenderedEvent) => {
    params.api.createRangeChart({
      chartContainer: document.querySelector("#myChart") as HTMLElement,
      cellRange: {
        columns: ["date", "rain", "pressure", "temp"],
      },
      suppressChartRanges: true,
      seriesChartTypes: [
        { colId: "rain", chartType: "groupedColumn", secondaryAxis: false },
        { colId: "pressure", chartType: "line", secondaryAxis: true },
        { colId: "temp", chartType: "line", secondaryAxis: true },
      ],
      chartType: "customCombo",
      aggFunc: "sum",
    });
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div className="wrapper">
          <div style={gridStyle}>
            <AgGridReact
              ref={gridRef}
              rowData={rowData}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              cellSelection={true}
              popupParent={popupParent}
              enableCharts={true}
              chartThemeOverrides={chartThemeOverrides}
              onGridReady={onGridReady}
              onFirstDataRendered={onFirstDataRendered}
            />
          </div>
          <div id="myChart"></div>
        </div>
      </div>
    </AgGridProvider>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <GridExample />
  </StrictMode>,
);
```

[Live example: Time Axis Combination Chart](https://www.ag-grid.com/examples/integrated-charts-time-series/time-combination-chart/reactFunctionalTs/)
