Data points can be represented by vertical or horizontal bars in many series types, such as Bar, Range Bar, Waterfall and Box Plot.
Styling and customisation options such as fill, stroke and cornerRadius are configurable within each series. See API Reference for details.
Fixed Width Copy Link
Use the width option to set a fixed pixel width for each bar.
import {
AgCartesianChartOptions,
AgCharts,
BarSeriesModule,
CategoryAxisModule,
LegendModule,
ModuleRegistry,
NumberAxisModule,
ScrollbarModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
ModuleRegistry.registerModules([
BarSeriesModule,
CategoryAxisModule,
LegendModule,
NumberAxisModule,
ScrollbarModule,
]);
const options: AgCartesianChartOptions = {
data: getData(),
title: {
text: "Quarterly Revenue by Product Line",
},
scrollbar: { enabled: true },
series: [
{
type: "bar",
xKey: "quarter",
yKey: "software",
yName: "Software",
width: 30,
},
{
type: "bar",
xKey: "quarter",
yKey: "hardware",
yName: "Hardware",
width: 30,
},
{
type: "bar",
xKey: "quarter",
yKey: "services",
yName: "Services",
width: 30,
},
],
axes: {
x: {
type: "category",
},
y: {
type: "number",
label: {
formatter: ({ value }) => `$${(value / 1000).toFixed(1)}B`,
},
},
},
};
options.container = document.getElementById("myChart");
const chart = AgCharts.create(options);
function setWidthMode(event: Event) {
const fixedWidth = (event.target as HTMLInputElement).value === "fixed";
for (const series of options.series ?? []) {
if (!("width" in series)) continue;
series.width = fixedWidth
? Number(document.getElementById("fixedWidthSliderValue")!.innerHTML)
: undefined;
}
(document.getElementById("fixedWidthGroup") as HTMLFieldSetElement).disabled =
!fixedWidth;
chart.update(options);
}
function updateFixedWidth(event: any) {
const value = Number(event.target?.value);
for (const series of options.series ?? []) {
if (!("width" in series)) continue;
series.width = value;
}
document.getElementById("fixedWidthSliderValue")!.innerHTML = String(value);
chart.update(options);
}
if (typeof window !== "undefined") {
// Attach external event handlers to window so they can be called from index.html
(<any>window).setWidthMode = setWidthMode;
(<any>window).updateFixedWidth = updateFixedWidth;
}
export function getData() {
return [
{ quarter: "Q1 '23", software: 4200, hardware: 3100, services: 2800 },
{ quarter: "Q2 '23", software: 4500, hardware: 3300, services: 2900 },
{ quarter: "Q3 '23", software: 4100, hardware: 3500, services: 3100 },
{ quarter: "Q4 '23", software: 4800, hardware: 3200, services: 3300 },
{ quarter: "Q1 '24", software: 5100, hardware: 3400, services: 3500 },
{ quarter: "Q2 '24", software: 5400, hardware: 3600, services: 3200 },
{ quarter: "Q3 '24", software: 5000, hardware: 3800, services: 3600 },
{ quarter: "Q4 '24", software: 5700, hardware: 3500, services: 3800 },
];
}
{
series: [
{
type: 'bar',
width: 30,
},
],
}In this example:
- Each bar in the series has a fixed width of 30 pixels.
- Toggle the fixed width off to let bars automatically size to fit the series area.
- Use the slider to change the width in pixels.
When using fixed width bars:
- Resizing the chart does not affect the width of the bars.
- The bars will be clipped if the fixed width exceeds the available space in the series area.
- Clipped bars can be viewed using the Scrollbar, Navigator or Zoom controls.
Band Alignment Copy Link
Use the bandAlignment option on a Category, Unit Time or Ordinal Time axis to align fixed width bars.
import {
AgBandAlignment,
AgCartesianChartOptions,
AgCategoryAxisOptions,
AgCharts,
BarSeriesModule,
CategoryAxisModule,
ModuleRegistry,
NumberAxisModule,
} from "ag-charts-enterprise";
import { DataType, getData } from "./data";
ModuleRegistry.registerModules([
BarSeriesModule,
CategoryAxisModule,
NumberAxisModule,
]);
const options: AgCartesianChartOptions<DataType> = {
data: getData(),
title: {
text: "Total Visitors to Museums and Galleries",
},
footnote: {
text: "Source: Department for Digital, Culture, Media & Sport",
},
series: [
{
type: "bar",
xKey: "quarter",
yKey: "museums",
yName: "Museums",
width: 10,
},
{
type: "bar",
xKey: "quarter",
yKey: "galleries",
yName: "Galleries",
width: 10,
},
{
type: "bar",
xKey: "quarter",
yKey: "heritage",
yName: "Heritage Sites",
width: 10,
},
],
axes: {
x: {
type: "category",
bandAlignment: "start",
},
y: {
type: "number",
title: {
text: "Total Visitors (Millions)",
},
},
},
formatter: {
y(params) {
const value = params.value as number;
const millions = value / 1000000;
const accuracy = ["series-label", "axis-label"].includes(params.source)
? 0
: 1;
return `${millions.toFixed(accuracy)}M`;
},
},
};
options.container = document.getElementById("myChart");
const chart = AgCharts.create(options);
function bandAlignmentChange(event: Event) {
const alignment = (event.target as HTMLInputElement).value as AgBandAlignment;
(options.axes!.x! as AgCategoryAxisOptions).bandAlignment = alignment;
chart.update(options);
}
if (typeof window !== "undefined") {
// Attach external event handlers to window so they can be called from index.html
(<any>window).bandAlignmentChange = bandAlignmentChange;
}
export interface DataType {
quarter: string;
museums: number;
galleries: number;
heritage: number;
}
export function getData(): DataType[] {
return [
{ quarter: "Q1", museums: 12836720, galleries: 8472190, heritage: 5631280 },
{ quarter: "Q2", museums: 14272922, galleries: 9123450, heritage: 6284130 },
{ quarter: "Q3", museums: 13800193, galleries: 9842310, heritage: 7123540 },
{ quarter: "Q4", museums: 12458355, galleries: 8930240, heritage: 5429240 },
];
}
{
axes: {
x: {
type: 'category',
bandAlignment: 'start',
},
},
}In this example:
- The category axis has an initial band alignment of
start. - Use the buttons to compare other band alignment options.
justify- bands are sized to fill the chart width, with the bars centred within each band.start- bands are sized to fit the bar width and aligned to the start of the axis.center- bands are sized to fit the bar width and centred within the chart width.end- bands are sized to fit the bar width and aligned to the end of the axis.
Width Ratio Copy Link
Use the widthRatio option to set the bar width as a proportion of the default width.
import {
AgCartesianChartOptions,
AgCharts,
CrosshairModule,
LegendModule,
ModuleRegistry,
NumberAxisModule,
RangeBarSeriesModule,
UnitTimeAxisModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
const data = getData();
ModuleRegistry.registerModules([
CrosshairModule,
LegendModule,
NumberAxisModule,
RangeBarSeriesModule,
UnitTimeAxisModule,
]);
const options: AgCartesianChartOptions = {
title: {
text: "Australia vs Global Temperature Patterns",
},
subtitle: {
text: "Monthly temperature ranges (2020) showing seasonal variations across regions",
},
footnote: {
text: "Data: World Meteorological Organization. Ranges show typical monthly lows and highs.",
fontStyle: "italic",
},
series: [
{
data: data.World,
type: "range-bar",
xKey: "month",
yName: "World",
yLowKey: "lowTemperature",
yHighKey: "highTemperature",
yLowName: "Min Temp",
yHighName: "Max Temp",
cornerRadius: 5,
fill: "transparent",
strokeWidth: 2,
strokeOpacity: 0.6,
highlight: { enabled: false },
},
{
data: data.Australia,
type: "range-bar",
xKey: "month",
yName: "Australia",
grouped: false,
widthRatio: 0.4,
yLowKey: "lowTemperature",
yHighKey: "highTemperature",
yLowName: "Min Temp",
yHighName: "Max Temp",
cornerRadius: 5,
},
],
axes: {
x: {
type: "unit-time",
label: {
formatter: ({ value }) => {
const date = new Date(value);
return date.toLocaleDateString("en-US", { month: "short" });
},
},
},
y: {
label: {
formatter: ({ value }) => `${value}°C`,
},
},
},
};
options.container = document.getElementById("myChart");
const chart = AgCharts.create(options);
function updateWidthRatio(event: any) {
const value = Number(event.target?.value);
(options.series![1] as any).widthRatio = value;
document.getElementById("widthRatioSliderValue")!.innerHTML = String(value);
chart.update(options);
}
if (typeof window !== "undefined") {
// Attach external event handlers to window so they can be called from index.html
(<any>window).updateWidthRatio = updateWidthRatio;
}
export function getData() {
return {
World: [
{
month: new Date(2020, 0, 1),
lowTemperature: 5,
highTemperature: 30,
},
{
month: new Date(2020, 1, 1),
lowTemperature: 8,
highTemperature: 28,
},
{
month: new Date(2020, 2, 1),
lowTemperature: 10,
highTemperature: 30,
},
{
month: new Date(2020, 3, 1),
lowTemperature: 12,
highTemperature: 32,
},
{
month: new Date(2020, 4, 1),
lowTemperature: 12,
highTemperature: 35,
},
{
month: new Date(2020, 5, 1),
lowTemperature: 10,
highTemperature: 40,
},
{
month: new Date(2020, 6, 1),
lowTemperature: 8,
highTemperature: 42,
},
{
month: new Date(2020, 7, 1),
lowTemperature: 9,
highTemperature: 40,
},
{
month: new Date(2020, 8, 1),
lowTemperature: 12,
highTemperature: 35,
},
{
month: new Date(2020, 9, 1),
lowTemperature: 12,
highTemperature: 30,
},
{
month: new Date(2020, 10, 1),
lowTemperature: 8,
highTemperature: 30,
},
{
month: new Date(2020, 11, 1),
lowTemperature: 5,
highTemperature: 30,
},
],
Australia: [
{
month: new Date(2020, 0, 1),
lowTemperature: 19,
highTemperature: 26,
},
{
month: new Date(2020, 1, 1),
lowTemperature: 19,
highTemperature: 26,
},
{
month: new Date(2020, 2, 1),
lowTemperature: 15,
highTemperature: 25,
},
{
month: new Date(2020, 3, 1),
lowTemperature: 15,
highTemperature: 23,
},
{
month: new Date(2020, 4, 1),
lowTemperature: 12,
highTemperature: 20,
},
{
month: new Date(2020, 5, 1),
lowTemperature: 10,
highTemperature: 18,
},
{
month: new Date(2020, 6, 1),
lowTemperature: 8,
highTemperature: 17,
},
{
month: new Date(2020, 7, 1),
lowTemperature: 9,
highTemperature: 18,
},
{
month: new Date(2020, 8, 1),
lowTemperature: 12,
highTemperature: 20,
},
{
month: new Date(2020, 9, 1),
lowTemperature: 14,
highTemperature: 22,
},
{
month: new Date(2020, 10, 1),
lowTemperature: 16,
highTemperature: 24,
},
{
month: new Date(2020, 11, 1),
lowTemperature: 18,
highTemperature: 26,
},
],
};
}
{
series: [
{
type: 'range-bar',
grouped: false,
widthRatio: 0.4,
},
],
}In this example:
- The World series uses the default width ratio of 1.
- The Australia series has an initial width ratio of 0.4.
- Use the slider to change the width ratio.
- This gives an Actual vs Target style visualisation, with the "World" series as a background reference.
Actual vs Target Bars Copy Link
Bars can be layered to create actual vs target comparisons by using grouped: false to overlay series.
import {
AgCartesianChartOptions,
AgCharts,
BarSeriesModule,
CategoryAxisModule,
LegendModule,
ModuleRegistry,
NumberAxisModule,
} from "ag-charts-community";
import { getData } from "./data";
ModuleRegistry.registerModules([
BarSeriesModule,
CategoryAxisModule,
LegendModule,
NumberAxisModule,
]);
const options: AgCartesianChartOptions = {
data: getData(),
title: {
text: "Quarterly Sales vs Target",
},
series: [
{
type: "bar",
direction: "horizontal",
xKey: "quarter",
yKey: "target",
yName: "Target",
grouped: false,
fillOpacity: 0.3,
cornerRadius: 3,
highlight: {
enabled: false,
},
},
{
type: "bar",
direction: "horizontal",
xKey: "quarter",
yKey: "actual",
yName: "Actual",
grouped: false,
widthRatio: 0.5,
cornerRadius: 6,
},
],
};
options.container = document.getElementById("myChart");
const chart = AgCharts.create(options);
export function getData() {
return [
{ quarter: "Q1", target: 80, actual: 65 },
{ quarter: "Q2", target: 114, actual: 120 },
{ quarter: "Q3", target: 138, actual: 110 },
{ quarter: "Q4", target: 95, actual: 96 },
];
}
{
series: [
{
type: 'bar',
yKey: 'target',
grouped: false,
fillOpacity: 0.3,
},
{
type: 'bar',
yKey: 'actual',
grouped: false,
widthRatio: 0.5,
},
],
}In this example:
- The Target series uses
grouped: falseto span the full category width as a background bar. - The Actual series also uses
grouped: falsewith awidthRatioof 0.5 to appear narrower in front. - The Target series is specified first in the
seriesarray so that it appears behind the Actual series. - The target has reduced
fillOpacityand highlighting disabled.
Multiple Metrics Copy Link
Multiple grouped series can be displayed over a single ungrouped target bar.
import {
AgCartesianChartOptions,
AgCharts,
BarSeriesModule,
CategoryAxisModule,
LegendModule,
ModuleRegistry,
NumberAxisModule,
} from "ag-charts-community";
import { getData } from "./data";
ModuleRegistry.registerModules([
BarSeriesModule,
CategoryAxisModule,
LegendModule,
NumberAxisModule,
]);
const options: AgCartesianChartOptions = {
data: getData(),
title: {
text: "Regional Sales vs Target",
},
series: [
{
type: "bar",
xKey: "quarter",
yKey: "target",
yName: "Target",
grouped: false,
fillOpacity: 0.3,
highlight: {
enabled: false,
},
},
{
type: "bar",
xKey: "quarter",
yKey: "europe",
yName: "Europe",
widthRatio: 0.8,
},
{
type: "bar",
xKey: "quarter",
yKey: "asia",
yName: "Asia",
widthRatio: 0.8,
},
],
};
options.container = document.getElementById("myChart");
const chart = AgCharts.create(options);
export function getData() {
return [
{ quarter: "Q1 25", target: 80, europe: 35, asia: 42 },
{ quarter: "Q2 25", target: 114, europe: 52, asia: 58 },
{ quarter: "Q3 25", target: 138, europe: 72, asia: 68 },
{ quarter: "Q4 25", target: 200, europe: 98, asia: 96 },
{ quarter: "Q1 26", target: 95, europe: 38, asia: 32 },
];
}
In this example:
- The "Target" series is ungrouped and spans the full category width as a background reference.
- The "Europe" and "Asia" series are grouped by default, sharing their portion of the category width.
- When a series has
grouped: false, itswidthRatiois relative to the full category width. - When
grouped: true(the default),widthRatiois relative to the automatically calculated width allocated to each series within group.
Skip Null Bars Copy Link
Use the skipNullBars option on a Category, Unit Time or Ordinal Time axis to prevent bars with null, undefined or missing values from taking up space within each category band. This also closes the gap when a series supplies its own data array and a category is absent from it.
import {
AgCartesianChartOptions,
AgCategoryAxisOptions,
AgCharts,
BarSeriesModule,
CategoryAxisModule,
LegendModule,
ModuleRegistry,
NumberAxisModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
ModuleRegistry.registerModules([
BarSeriesModule,
CategoryAxisModule,
LegendModule,
NumberAxisModule,
]);
const options: AgCartesianChartOptions = {
data: getData(),
title: {
text: "Quarterly Revenue",
},
series: [
{
type: "bar",
xKey: "quarter",
yKey: "software",
yName: "Software",
},
{
type: "bar",
xKey: "quarter",
yKey: "hardware",
yName: "Hardware",
},
{
type: "bar",
xKey: "quarter",
yKey: "services",
yName: "Services",
},
{
type: "bar",
xKey: "quarter",
yKey: "investments",
yName: "Investments",
},
],
axes: {
x: {
type: "category",
skipNullBars: true,
},
y: {
type: "number",
label: {
formatter: ({ value }) => `$${(value / 1000).toFixed(1)}B`,
},
},
},
};
options.container = document.getElementById("myChart");
const chart = AgCharts.create(options);
function skipNullBarsChange(event: Event) {
(options.axes!.x as AgCategoryAxisOptions).skipNullBars =
(event.target as HTMLInputElement).value === "true";
chart.update(options);
}
if (typeof window !== "undefined") {
// Attach external event handlers to window so they can be called from index.html
(<any>window).skipNullBarsChange = skipNullBarsChange;
}
export function getData() {
return [
{
quarter: "Q1'24",
software: 5100,
hardware: 3400,
investments: undefined,
},
{
quarter: "Q2'24",
software: 5400,
hardware: null,
services: 3200,
investments: 3100,
},
{ quarter: "Q3'24", software: null, hardware: 3800, investments: 2500 },
{
quarter: "Q4'24",
software: 5700,
hardware: null,
services: undefined,
investments: null,
},
];
}
{
axes: {
x: {
type: 'category',
skipNullBars: true,
},
},
}In this example:
- Various values in the data are set to
null,undefinedor missing. - When an axis has
skipNullBars: true, bars withnull,undefinedor missing values are not represented on the chart. - Toggle between "Skip Null Bars" and "Show Null Bars" to compare the difference.
API Reference Copy Link
These properties are common to Bar, Range Bar, Waterfall and Box Plot series types.
- width
PixelSize - Fixed width of each bar in the series.
- widthRatio
Ratio - Ratio of the bandwidth (or specified width) to use for the width for each bar in the series.
- cornerRadius
PixelSize - Apply rounded corners to each bar.
- fill
AgColorType - The colour for filling shapes. A colour string, or an object for a gradient, pattern, or image fill.
- fillOpacity
Opacity - The opacity of the fill colour.
- stroke
AgCssColorOrRef - The colour for the stroke.
- strokeWidth
PixelSize - The width of the stroke in pixels.
- strokeOpacity
Opacity - The opacity of the stroke colour.
- lineDash
PixelSize[] - An array specifying the length in pixels of alternating dashes and gaps.
- lineDashOffset
PixelSize - The initial offset of the dashed line in pixels.
- width
PixelSize - Fixed width of each bar in the series.
- widthRatio
Ratio - Ratio of the bandwidth (or specified width) to use for the width for each bar in the series.
- cornerRadius
PixelSize - Apply rounded corners to each bar.
- fill
AgColorType - The colour for filling shapes. A colour string, or an object for a gradient, pattern, or image fill.
- fillOpacity
Opacity - The opacity of the fill colour.
- stroke
AgCssColorOrRef - The colour for the stroke.
- strokeWidth
PixelSize - The width of the stroke in pixels.
- strokeOpacity
Opacity - The opacity of the stroke colour.
- lineDash
PixelSize[] - An array specifying the length in pixels of alternating dashes and gaps.
- lineDashOffset
PixelSize - The initial offset of the dashed line in pixels.
This property is available on Category, Ordinal Time and Unit Time axes.
- bandAlignment
AgBandAlignmentdefault: 'justify' - The alignment of bands when used with bar-like series with fixed widths.
- bandAlignment
AgBandAlignmentdefault: 'justify' - The alignment of bands when used with bar-like series with fixed widths.
This property is available on Category, Ordinal Time and Unit Time axes.
- skipNullBars
booleandefault: false - Set to `true` to prevent bars with `null`, `undefined` or missing values from taking up space in each category.
- skipNullBars
booleandefault: false - Set to `true` to prevent bars with `null`, `undefined` or missing values from taking up space in each category.