Column and Line Mix
Income as columns and expenses as a line on one chart, so the gap between them shows year by year. The last year is a projection, drawn faint and dashed.
About this chart
When to mix columns and a line
Two measures on one chart read best when they look different: columns for the amounts, a line for what they are compared against. Here both share one axis, so the gap between income and expenses is the story, and the faint, dashed last year keeps the plan apart from the results.
Good for
- Income against expenses, sales against target
- Actual figures with a projection
- Amounts per period with a trend on top
Think twice when
- Two measures in different units: give each its own, clearly labeled axis
- Many years: two lines read more cleanly
- More than two measures: the mix gets hard to read
For developers
Get the code.
Built with amCharts 5, a JavaScript library. The JavaScript includes your theme and renderer (canvas or SVG); the JSON also follows the changes you make with the controls.
For projects that use npm:
How it reads:
npm install @amcharts/amcharts5. See Getting started.
The same chart as a JSON config. Chart Maker reads and writes this format, the library's JSON parser turns it into a chart, and the <am5-chart> element puts it on a page with no code.How it reads:
"type" is the class to create and "settings" what you would pass to its new() in code; "properties" fill in its parts, lists such as series and axes or templates such as columns.template; "refs" holds objects used in more than one place ("#series-0" stands for the one named series-0); a string starting with "@" takes a value from another object, such as "@series.get('fill')".
A complete page. Save it as an .html file and open it in a browser.
Paste this into an AI coding assistant to build the chart from scratch. More in amCharts & AI.
// Create root element
// https://docs.amcharts.com/v5/getting-started/#root-element
var root = am5.Root.new("chartdiv");
// Set themes
// https://docs.amcharts.com/v5/concepts/themes/
root.setThemes([am5themes_Animated.new(root), am5themes_Responsive.new(root)]);
// Create chart
// https://docs.amcharts.com/v5/charts/xy-chart/
var chart = root.container.children.push(
am5xy.XYChart.new(root, {
panX: false, // the plot doesn't pan when dragged
panY: false,
wheelX: "panX", // a horizontal wheel or trackpad swipe pans the years
wheelY: "zoomX", // the vertical wheel zooms in on them
paddingLeft: 0, // the value labels sit at the chart's left edge
layout: root.verticalLayout
})
);
var data = [
{
year: "2020",
income: 23.5,
expenses: 21.1
},
{
year: "2021",
income: 26.2,
expenses: 30.5
},
{
year: "2022",
income: 30.1,
expenses: 34.9
},
{
year: "2023",
income: 29.5,
expenses: 31.1
},
{
year: "2024",
income: 30.6,
expenses: 28.2,
// from this point on the line is dashed: the projected part
strokeSettings: {
stroke: chart.get("colors").getIndex(1),
strokeWidth: 3,
strokeDasharray: [5, 5]
}
},
{
year: "2025",
income: 34.1,
expenses: 32.9,
// the projected year's column: faint, with a dashed outline
columnSettings: {
strokeWidth: 1,
strokeDasharray: [5],
fillOpacity: 0.2
},
info: "(projection)" // shown after the value in the tooltips
}
];
// Create axes
// https://docs.amcharts.com/v5/charts/xy-chart/axes/
var xRenderer = am5xy.AxisRendererX.new(root, {
minorGridEnabled: true, // a grid line for every year, even one whose label is skipped
minGridDistance: 60 // at least 60px between labels; on narrow screens some are skipped
});
var xAxis = chart.xAxes.push(
am5xy.CategoryAxis.new(root, {
categoryField: "year",
renderer: xRenderer,
tooltip: am5.Tooltip.new(root, {}) // the cursor shows the year on the axis
})
);
xRenderer.grid.template.setAll({
// draw each grid line at the end of its year's cell instead of at its start
location: 1
})
xAxis.data.setAll(data);
var yAxis = chart.yAxes.push(
am5xy.ValueAxis.new(root, {
min: 0, // the columns start at zero
// 10% of room above the highest value
extraMax: 0.1,
renderer: am5xy.AxisRendererY.new(root, {
strokeOpacity: 0.1 // a faint axis line
})
})
);
// Add series
// https://docs.amcharts.com/v5/charts/xy-chart/series/
var series1 = chart.series.push(
am5xy.ColumnSeries.new(root, {
name: "Income",
xAxis: xAxis,
yAxis: yAxis,
valueYField: "income",
categoryXField: "year",
tooltip: am5.Tooltip.new(root, {
pointerOrientation: "horizontal", // the tooltip points sideways
labelText: "{name} in {categoryX}: {valueY} {info}" // {info} adds "(projection)" for the last year
})
})
);
series1.columns.template.setAll({
tooltipY: am5.percent(10), // the tooltip points near the top of the column
templateField: "columnSettings" // the projected year's look from its columnSettings
});
series1.data.setAll(data);
var series2 = chart.series.push(
am5xy.LineSeries.new(root, {
name: "Expenses",
xAxis: xAxis,
yAxis: yAxis,
valueYField: "expenses",
categoryXField: "year",
tooltip: am5.Tooltip.new(root, {
pointerOrientation: "horizontal", // the tooltip points sideways
labelText: "{name} in {categoryX}: {valueY} {info}"
})
})
);
series2.strokes.template.setAll({
strokeWidth: 3, // a 3px line
templateField: "strokeSettings" // dashed from the point that has strokeSettings
});
series2.data.setAll(data);
// a circle on each point, filled with the background color so it looks hollow
series2.bullets.push(function () {
return am5.Bullet.new(root, {
sprite: am5.Circle.new(root, {
strokeWidth: 3, // a 3px outline...
stroke: series2.get("stroke"), // ...in the line's color
radius: 5, // 5px
fill: root.interfaceColors.get("background")
})
});
});
chart.set("cursor", am5xy.XYCursor.new(root, {})); // both series' tooltips show for the hovered year
// Add legend, in the top left corner of the plot area
// https://docs.amcharts.com/v5/charts/xy-chart/legend-xy-series/
var legend = chart.plotContainer.children.push(
am5.Legend.new(root, {
x: 0, // the legend's top left corner...
y: 0, // ...at the plot's top left corner
paddingTop: 10, // 10px in from the corner
paddingLeft: 10
})
);
legend.data.setAll(chart.series.values);
// Make stuff animate on load
// https://docs.amcharts.com/v5/concepts/animations/
chart.appear(1000, 100);
series1.appear();
series2.appear();
{
"type": "XYChart",
"settings": {
"panX": false,
"panY": false,
"wheelX": "panX",
"wheelY": "zoomX",
"paddingLeft": 0,
"layout": {
"type": "VerticalLayout"
},
"cursor": {
"type": "XYCursor"
}
},
"properties": {
"series": [
"#series-0",
"#series-1"
],
"xAxes": [
"#axis-0"
],
"yAxes": [
"#axis-1"
],
"plotContainer": {
"children": [
{
"type": "Legend",
"settings": {
"x": 0,
"y": 0,
"paddingTop": 10,
"paddingLeft": 10
},
"properties": {
"data": [
"#series-0",
"#series-1"
]
},
"index": 5
}
]
}
},
"refs": [
{
"data-0": [
{
"year": "2020",
"income": 23.5,
"expenses": 21.1
},
{
"year": "2021",
"income": 26.2,
"expenses": 30.5
},
{
"year": "2022",
"income": 30.1,
"expenses": 34.9
},
{
"year": "2023",
"income": 29.5,
"expenses": 31.1
},
{
"year": "2024",
"income": 30.6,
"expenses": 28.2,
"strokeSettings": {
"stroke": "@colors.getIndex(1)",
"strokeWidth": 3,
"strokeDasharray": [5, 5],
"__parse": true
},
"__parse": true
},
{
"year": "2025",
"income": 34.1,
"expenses": 32.9,
"columnSettings": {
"strokeWidth": 1,
"strokeDasharray": [5],
"fillOpacity": 0.2,
"__parse": true
},
"info": "(projection)",
"__parse": true
}
]
},
{
"axis-0": {
"type": "CategoryAxis",
"settings": {
"categoryField": "year",
"renderer": {
"type": "AxisRendererX",
"settings": {
"minorGridEnabled": true,
"minGridDistance": 60
},
"properties": {
"grid": {
"properties": {
"template": {
"settings": {
"location": 1
}
}
}
}
}
},
"tooltip": {
"type": "Tooltip"
}
},
"properties": {
"data": "#data-0"
}
}
},
{
"axis-1": {
"type": "ValueAxis",
"settings": {
"min": 0,
"extraMax": 0.1,
"renderer": {
"type": "AxisRendererY",
"settings": {
"strokeOpacity": 0.1
}
}
}
}
},
{
"series-0": {
"type": "ColumnSeries",
"settings": {
"name": "Income",
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueYField": "income",
"categoryXField": "year",
"tooltip": {
"type": "Tooltip",
"settings": {
"pointerOrientation": "horizontal",
"labelText": "{name} in {categoryX}: {valueY} {info}"
}
}
},
"properties": {
"data": "#data-0",
"columns": {
"properties": {
"template": {
"settings": {
"tooltipY": {
"type": "Percent",
"value": 10
},
"templateField": "columnSettings"
}
}
}
}
}
}
},
{
"series-1": {
"type": "LineSeries",
"settings": {
"name": "Expenses",
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueYField": "expenses",
"categoryXField": "year",
"tooltip": {
"type": "Tooltip",
"settings": {
"pointerOrientation": "horizontal",
"labelText": "{name} in {categoryX}: {valueY} {info}"
}
}
},
"properties": {
"data": "#data-0",
"strokes": {
"properties": {
"template": {
"settings": {
"strokeWidth": 3,
"templateField": "strokeSettings"
}
}
}
},
"bullets": [
{
"type": "Bullet",
"settings": {
"sprite": {
"type": "Circle",
"settings": {
"strokeWidth": 3,
"stroke": "@series.get('stroke')",
"radius": 5,
"fill": "@root.interfaceColors.get('background')"
}
}
}
}
]
}
}
}
]
}



