A line chart where every day gets a number on the axis: small day numbers along the bottom, week labels under them, so each point’s date is easy to read.
With only main dates on the axis, readers count grid lines to find a day. Numbering the minor grid lines saves them the counting. It suits short ranges, a month or a few weeks, where each day matters.
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.
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."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://www.amcharts.com/docs/v5/getting-started/#Root_element
var root = am5.Root.new("chartdiv");
const myTheme = am5.Theme.new(root);
// Put the main date labels in a second row, under the day numbers,
// starting at their grid line, so the two rows never overlap
myTheme.rule("AxisLabel", ["x"]).setAll({
paddingTop: 20,
centerX: 0,
location: 0
});
// Day numbers (minor labels) stay in the first row, centered under each day
myTheme.rule("AxisLabel", ["x", "minor"]).setAll({
paddingTop: 3,
centerX: am5.p50,
location: 0.5
});
// Tweak minor grid opacity
myTheme.rule("Grid", ["minor"]).setAll({
strokeOpacity: 0.08
});
// Set themes
// https://www.amcharts.com/docs/v5/concepts/themes/
root.setThemes([
am5themes_Animated.new(root),
myTheme,
am5themes_Responsive.new(root)
]);
// Create chart
// https://www.amcharts.com/docs/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 days
wheelY: "zoomX", // the vertical wheel zooms in on them
paddingLeft: 0 // the value labels sit at the chart's left edge
}));
// Add cursor
// https://www.amcharts.com/docs/v5/charts/xy-chart/cursor/
var cursor = chart.set("cursor", am5xy.XYCursor.new(root, {
// drag across the plot to zoom into those days
behavior: "zoomX"
}));
cursor.lineY.set("visible", false); // no horizontal cursor line, only the vertical one
var date = new Date(); // today at midnight; the data starts the day after
date.setHours(0, 0, 0, 0);
var value = 100;
// the next day's point: a random step of up to 5 from the last value
function generateData() {
value = Math.round((Math.random() * 10 - 5) + value);
am5.time.add(date, "day", 1);
return {
date: date.getTime(),
value: value
};
}
// that many days in a row
function generateDatas(count) {
var data = [];
for (var i = 0; i < count; ++i) {
data.push(generateData());
}
return data;
}
// Create axes
// https://www.amcharts.com/docs/v5/charts/xy-chart/axes/
var xAxis = chart.xAxes.push(am5xy.DateAxis.new(root, {
maxDeviation: 0, // no panning past the first and last day
baseInterval: { // one point per day
timeUnit: "day",
count: 1
},
// Number every day, including the first day of each week
skipFirstMinor: false,
renderer: am5xy.AxisRendererX.new(root, {
minorGridEnabled: true, // grid lines for the days between the main labels
// main labels at least 200px apart; the days between them get minor grid lines and labels
minGridDistance: 200,
minorLabelsEnabled: true // and labels for them too
}),
tooltip: am5.Tooltip.new(root, {}) // the cursor shows the date on the axis
}));
xAxis.set("minorDateFormats", {
day: "dd", // minor labels show two-digit day numbers...
month: "MM" // ...or month numbers, when the minor steps are months
});
var yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, {
renderer: am5xy.AxisRendererY.new(root, {})
}));
// Add series
// https://www.amcharts.com/docs/v5/charts/xy-chart/series/
var series = chart.series.push(am5xy.LineSeries.new(root, {
name: "Series",
xAxis: xAxis,
yAxis: yAxis,
valueYField: "value",
valueXField: "date",
tooltip: am5.Tooltip.new(root, {
labelText: "{valueY}" // the hovered day's value
})
}));
// All bullets share one template, so setting its radius resizes them at once
var bulletTemplate = am5.Template.new({
radius: 5 // 5px dots
});
series.bullets.push(function () {
var bulletCircle = am5.Circle.new(root, {
fill: series.get("fill") // in the series color
}, bulletTemplate);
return am5.Bullet.new(root, {
sprite: bulletCircle
})
})
// Add scrollbar
// https://www.amcharts.com/docs/v5/charts/xy-chart/scrollbars/
chart.set("scrollbarX", am5.Scrollbar.new(root, {
orientation: "horizontal" // drag its grips to zoom in on a range of days
}));
var data = generateDatas(30); // 30 days of data
series.data.setAll(data);
// Make stuff animate on load
// https://www.amcharts.com/docs/v5/concepts/animations/
series.appear(1000);
chart.appear(1000, 100);
{
"type": "XYChart",
"settings": {
"panX": false,
"panY": false,
"wheelX": "panX",
"wheelY": "zoomX",
"paddingLeft": 0,
"cursor": {
"type": "XYCursor",
"settings": {
"behavior": "zoomX"
},
"properties": {
"lineY": {
"settings": {
"visible": false
}
}
}
},
"scrollbarX": {
"type": "Scrollbar",
"settings": {
"orientation": "horizontal"
}
}
},
"properties": {
"series": [
"#series-0"
],
"xAxes": [
"#axis-0"
],
"yAxes": [
"#axis-1"
]
},
"refs": [
{
"data-0": [
{
"date": 1791320400000,
"value": 96
},
{
"date": 1791406800000,
"value": 98
},
{
"date": 1791493200000,
"value": 94
},
{
"date": 1791579600000,
"value": 92
},
{
"date": 1791666000000,
"value": 88
},
{
"date": 1791752400000,
"value": 93
},
{
"date": 1791838800000,
"value": 95
},
{
"date": 1791925200000,
"value": 96
},
{
"date": 1792011600000,
"value": 98
},
{
"date": 1792098000000,
"value": 100
},
{
"date": 1792184400000,
"value": 99
},
{
"date": 1792270800000,
"value": 99
},
{
"date": 1792357200000,
"value": 101
},
{
"date": 1792443600000,
"value": 100
},
{
"date": 1792530000000,
"value": 102
},
{
"date": 1792616400000,
"value": 103
},
{
"date": 1792702800000,
"value": 106
},
{
"date": 1792789200000,
"value": 110
},
{
"date": 1792875600000,
"value": 115
},
{
"date": 1792965600000,
"value": 120
},
{
"date": 1793052000000,
"value": 117
},
{
"date": 1793138400000,
"value": 119
},
{
"date": 1793224800000,
"value": 124
},
{
"date": 1793311200000,
"value": 127
},
{
"date": 1793397600000,
"value": 127
},
{
"date": 1793484000000,
"value": 126
},
{
"date": 1793570400000,
"value": 125
},
{
"date": 1793656800000,
"value": 125
},
{
"date": 1793743200000,
"value": 128
},
{
"date": 1793829600000,
"value": 129
}
]
},
{
"template-0": {
"type": "Template",
"settings": {
"radius": 5
}
}
},
{
"axis-0": {
"type": "DateAxis",
"settings": {
"maxDeviation": 0,
"baseInterval": {
"timeUnit": "day",
"count": 1
},
"skipFirstMinor": false,
"renderer": {
"type": "AxisRendererX",
"settings": {
"minorGridEnabled": true,
"minGridDistance": 200,
"minorLabelsEnabled": true
}
},
"tooltip": {
"type": "Tooltip"
},
"minorDateFormats": {
"day": "dd",
"month": "MM"
}
}
}
},
{
"axis-1": {
"type": "ValueAxis",
"settings": {
"renderer": {
"type": "AxisRendererY"
}
}
}
},
{
"series-0": {
"type": "LineSeries",
"settings": {
"name": "Series",
"xAxis": "#axis-0",
"yAxis": "#axis-1",
"valueYField": "value",
"valueXField": "date",
"tooltip": {
"type": "Tooltip",
"settings": {
"labelText": "{valueY}"
}
}
},
"properties": {
"data": "#data-0",
"bullets": [
{
"type": "Bullet",
"settings": {
"sprite": {
"type": "Circle",
"settings": {
"fill": "@series.get('fill')"
},
"properties": {
"template": "#template-0"
}
}
}
}
]
}
}
}
]
}