Axes

Axes are vital part of most XY and some other chart types, providing a measure of scale or grouping to the otherwise arbitrary visual data.

This article will look at different kinds of axes, how they can be used and configured to suit your needs.

Instantiating axes

In amCharts 4, most of the chart types that require axes need two of those. In most cases the chart will have two properties: xAxes and yAxes.

Both of those are lists, since charts support any number of axes, of any type and combination.

Creating an axis

Like with most list-based properties, we create an axis by using create() method, specifying the type of axis we want to create.

For example, to create a vertical Value axis, and horizontal Category axis, we'd do something like this:

let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
let categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
{
  // ...
  "yAxes": [{
    "type": "ValueAxis"
  }],
  "xAxes": [{
    "type": "CategoryAxis"
  }]
}

Orientation and position

The orientation (vertical or horizontal) is determined in which list it is assigned/created. Axes assigned to xAxes list, will be horizontal (or will start off horizontally then will curve in case of circular charts like Radar). Axes in yAxes will be vertical.

Horizontal axes are drawn at the bottom, and vertical ones on the left by default. To move the axis to the opposite side (top and right respectively), use axis' renderer's setting opposite.

let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.renderer.opposite = true;
let categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.renderer.opposite = true;
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.renderer.opposite = true;
var categoryAxis = chart.xAxes.push(new am4charts.charts.CategoryAxis());
categoryAxis.renderer.opposite = true;
{
  // ...
  "yAxes": [{
    "type": "ValueAxis",
    "opposite": true
  }],
  "xAxes": [{
    "type": "CategoryAxis",
    "opposite": true
  }]
}

The above will move our Value axis to the right, and Category axis to the top of the chart.

Axis renderers

In amCharts 4, actual axis type is separated from its rendering. This allows us to retain uniform, consistent axis types across, seemingly different chart types.

For example an XY chart can have a straight horizontal Category axis, while Radar chart can have a circular Category axis.

That's where axis renderers come in.

When you create a horizontal Category axis in an XY chart, it will automatically use AxisRenderX. For a circular Radar axis, it will automatically use AxisRendererCircular.

Axis' renderer is always accessible via axis' renderer property.

Depending on renderer, it may have different settings that will affect behavior and appearance of the actual drawn axis. This is why most of the appearance settings are usually set not directly via axis' properties, but rather via its renderer's properties, as you already saw in previous chapter about axis' positions. (yes the opposite setting)

Types of axes

There are three main types of axes in amCharts 4: Value, Date, and Category. Let's examine each one in detail.

Value axis

Value axis (ValueAxis) is used to depict a simple numeric value.

Numeric scale

In the most common serial chart scenario, you would have a vertical Value axis, and either a Category or Date axis, for horizontal dimension. In such chart each point (an elbow on a line series, or a column in a column series) is represented by a numeric value, and an some other value, either category or a date.

Some chart types, like Scatter/Bubble, will have data points represented by two numeric values: X (horizontal) and Y (vertical) value. In such charts we will have two Value axes: horizontal and vertical.

Normally, a Value axis will automatically choose its scale (minimum and maximum value, as well as intermediate grid/value positions) based on the actual range of numeric values in currently displayed data. Furthermore, it will automatically try to intelligently adjust its scale so that its scale is represented by "pretty" numbers, while maintaining the best possible appearance of related series.

For example, if we have a line series with three values: 3.5, 6, and 6.5. The actual range of values is from 3.5 to 6.5.

Naturally, a value axis starting with 3.5 and ending with 6.5, with intermediate numbers at some odd fractional increments would look awkward to say the least.

That's why the algorithm behind Value axis will intelligently try to adjust its scale to start at 3 and end at 7, with intermediate grid/label every 1, resulting in grid lines/labels at 3, 4, 5, 6, and 7.

See the Pen amCharts V4: Value axis (1) by amCharts (@amcharts) on CodePen.24419

Adjusting scale

Now that we know how Value axis' scales work, let's look at how we can adjust it to our needs.

Default behavior for the Value axis is designed to provide best results "out-of-the-box". However, in some cases you might need to adjust it for better results for your specific requirements, or usage scenario.

Normally, Value axis will not start at zero, but will start at a value just before the smallest value in currently displayed data. This helps make the difference in values as prominent as possible. For example, if we had some very large numbers with only a little fluctuation between them (i.e. 900, 920, 915). Starting the scale at zero would make the columns for all three look almost identical, which would provide false impression to the user viewing the chart. Here's a demo how it would look like, just to illustrate the point:

See the Pen amCharts V4: Value axis (2) by amCharts (@amcharts) on CodePen.24419

Not particularly useful, is it?

Here's how the same chart looks like with default settings: (letting Value axis determine best possible starting value by itself)

See the Pen amCharts V4: Value axis (3) by amCharts (@amcharts) on CodePen.24419

Much better.

However, if you know what's best for your users, and how to best depict your data, you can adjust the scale using Value axis' min property (to set the starting value) and max (to set the ending value).

So, if I'd want my value axis scale to go from, say, 500 to 1500, I'd go with something like this:

let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.min = 500;
valueAxis.max = 1500;
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.min = 500;
valueAxis.max = 1500;
{
  // ...
  "yAxes": [{
    "type": "ValueAxis",
    "min": 500,
    "max": 1500
  }]
}

NOTE Even though you explicitly specify min and/or max, Value axis might "disobey" and adjust these settings to result in better intermediate value increments for the available space. Here's how our chart looks like with the above setting:

See the Pen amCharts V4: Value axis (4) by amCharts (@amcharts) on CodePen.24419

Notice, how the chart adjusted the values, because it thought it would result in better looking scale.

To "force" the start/end values for the scale to literally follow your min/max settings, use strictMinMax setting.

So, if I'd want my value axis scale to go from, say, 500 to 1500, I'd go with something like this:

let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.min = 500;
valueAxis.max = 1500;
valueAxis.strictMinMax = true;
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.min = 500;
valueAxis.max = 1500;
valueAxis.strictMinMax = true;
{
  // ...
  "yAxes": [{
    "type": "ValueAxis",
    "min": 500,
    "max": 1500,
    "strictMinMax": true
  }]
}

Let's see how we do now:

See the Pen amCharts V4: Value axis (5) by amCharts (@amcharts) on CodePen.24419

Notice, how the scale is now precisely follows our settings, albeit does not look too good, because the first label and last are not there. This is because Value axis has determined that for this specific value range, the most optimal step size is 200, hence labels 500 and 1500 are not present. That brings us to the next mini-section on Value axis.

Relatively expanding the scale

Setting minimum and maximum values explicitly might work but it's not very universal.

What if my values change?

What if I want the scale to always go a bit further than the bare minimum required to fit all of the data points in it?

That's where Value axis' extraMin and extraMax properties come in.

These settings are used to relatively "expand" current minimum or maximum value range of the axis.

This is useful in the situations where we might want to "pad" actual series in the chart from getting too close to the edge.

The values for these settings are relative to the current unmodified range of the axis values.

E.g. setting extraMin = 0.2 on an axis that is currently displaying values from 100 to 200 will force the range to 80 to 200.

// Pad values by 20%
valueAxis.extraMin = 0.2;
valueAxis.extraMax = 0.2;
// Pad values by 20%
valueAxis.extraMin = 0.2;
valueAxis.extraMax = 0.2;
{
  // ...
  "yAxes": [{
    // ...
    // Pad values by 20%
    "extraMin": 0.2,
    "extraMax": 0.2
  }]
}

Adjusting value steps

Like with the actual scale, Value axis will do its best to determine the most optimal step size for the value range it needs to encompass. It depends on a number of criteria, like value range, available space, etc.

The single most important setting, determining number of grid/labels, and thus the actual step is the minimum allowed distance between two grid lines. It is determined by axis' renderer's property: minGridDistance.

It ensures that chart maintains a minimum distance (in pixels) between each grid line, so that they do not become too crammed or too spread out.

Reducing the minGridDistance will result in more grid lines / labels and thus a more granular value axis step. Let's try using it to trick a chart to use increments in 100s, rather than 200s.

valueAxis.renderer.minGridDistance = 20;
valueAxis.renderer.minGridDistance = 20;
{
  // ...
  "yAxes": [{
    // ...
    "renderer": {
      "minGridDistance": 20
    }
  }]
}

Yup, that did it:

See the Pen amCharts V4: Value axis (6) by amCharts (@amcharts) on CodePen.24419

Multiple value axes

We already mentioned that amCharts 4 supports any number of axes. This might come really useful when you have to plot, say, two series with very distinctive values, or even units.

In such case, you can create to separate Value axes, then bind each respective series to them.

MORE INFO We're not going to get into multiple value axes here. This particular topic is described in great detail, with examples to code with it in the article "Anatomy of XY Chart".

Logarithmic scale

Multiple value axes work well when you have distinctive series with different scales of data.

But what about if data varies greatly within single series? Say you have several data points in the 100s, with one data point sticking out at 1000. Naturally, the scale of the value axis will be in 1000 so that it can accommodate all values.

This will make one column stick out, while all others will look like equally sized gnomes next to it:

See the Pen amCharts V4: Value axis (7) by amCharts (@amcharts) on CodePen.24419

In this case, using Value axis with a logarithmic scale might help. Such value axis will not use value scale with equal increments. Instead, each increment will be orders of magnitude larger than the previous one, making the series with large gap between values, usable.

To turn this feature on, simply set logarithmic = true on your Value axis:

valueAxis.logarithmic = true;
valueAxis.logarithmic = true;
{
  // ...
  "yAxes": [{
    // ...
    "logarithmic": true
  }]
}

See the Pen amCharts V4: Value axis (8) by amCharts (@amcharts) on CodePen.24419

Category axis

Category axis is the simplest of the axes trio. It does not do any calculations, or scales. All it does is list text-based items, or as charting community calls them - categories.

A category can be anything - a name, a year, a person. The Category axis allot equal space for each category and will display data items that go into that category.

For line series, each data item will be laid over each other. For multiple column series, each column will be arranged into clusters.

The examples in this article so far had a Category axis, with proverbial company department names as categories: Research & Development; Marketing; Distribution.

Binding categories to data

This brings us to important setting, which is needed and used by only Category axis.

A Category axis needs to know which particular field in data holds category names.

Just to remind, here's how our sample data looks like:

[{
  "category": "Research & Development",
  "value": 3.5
}, {
  "category": "Marketing",
  "value": 6
}, {
  "category": "Distribution",
  "value": 6.5
}]

While it may be obvious to us, that field "category" holds the category, it's not for the chart.

In most places in amCharts 4, where object needs to bind its properties to actual data, we use dataFields. It's an object which holds key / value pair, with key being some object's internal property, and value being the name of the field in data, to get data from.

Category axis has a data field, predictably called "category", so we can use it to bind Category axis to data:

let categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "category";
var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "category";
{
  // ...
  "xAxes": [{
    "type": "CategoryAxis",
    "dataFields": {
      "category": "category"
    }
  }]
}

Now, our Category axis will know, that for each object in data, it needs to look for "category" property to get it's list of categories from.

Date axis

Date axis (DateAxis) is quite similar to the Value axis, except instead of numeric scale, it uses date and time scale.

Basically, if you have a series that is bound to a date/time values in data (via its own dataFields), you will need a Date axis to plot it on.

Just like Value axis, a Date axis will automatically select its scale based on the actual scope of date/time values in data.

It will also ensure that each data point is placed at exactly the position it has its date/time set on.

To demonstrate it all, let's refactor our demo from before to use days plotted on a Date axis, instead of categories.

let dateAxis = chart.xAxes.push(new am4charts.DateAxis());
var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
{
  // ...
  "xAxes": [{
    "type": "DateAxis"
  }]
}

IMPORTANT In order for series to be correctly plotted on a Date axis, it needs to set up proper dataFields, such as dateX or dateY.

MORE INFO Please refer to our "Series" article for more information about series' data fields.

Let's take a look at the updated example:

See the Pen amCharts V4: Date axis (1) by amCharts (@amcharts) on CodePen.24419

Natural time scale

As we briefly mentioned before, a Date axis will try to maintain a natural scale, even if data points come at irregular intervals.

Let's try to move one of our data points a few days away from the other ones, to create a gap:

See the Pen amCharts V4: Date axis (2) by amCharts (@amcharts) on CodePen.24419

As you can see, the last column moved away, creating "empty" entries in the Date axis, for the days the there is no data points for.

Data granularity

A date/time-based data can come at different intervals. For example, we could have just one entry per year, or we can have a data point every millisecond.

Date axis will do turn on its wits to determine the granularity by examining your actual data. So, if you have data points with a minute between them, the axis will determine the best granularity to use is a minute.

Data granularity affects how axis grid is drawn, and how labels are formatted. E.g. if you have a data point each day, it makes sense to display a grid line and a date label for each data point.

MORE INFO We will have a more detailed look at formatting of axis labels further down this article, in section "Label formatting".

Manually specifying data granularity

In some rare cases, when you have data coming in at irregular intervals, or where precise timestamp is important, even if your data points are logged only occasionally, you might need to explicitly specify the granularity of data for your Date axis to use.

In those cases you will use Date axis' setting baseInterval.

NOTE In fact, if you know the granularity of your data beforehand, it is encouraged to set baseInterval so that Date axis does not have to waste precious resources in trying to figure it our from your data.

It comes in a form of an object like this:

{
  "timeUnit": "minute",
  "count": 5
}

A "timeUnit" identifies base time unit (second, minute, hour, day, etc.).

A "count" specifies how many "timeUnit" each data item comes at. Count parameter can be skipped, in which case Date axis will assume 1.

The above snippet actually serves as a hint to Date axis: "my data has a data point every 5 minutes".

Let's see what happens to our chart if we revert to data point per minute, rather than data point per day.

See the Pen amCharts V4: Date axis (3) by amCharts (@amcharts) on CodePen.24419

As you can see the chart automatically adjusted to our new minute-based data.

Let's say we need to emphasize that we have a second-based data, even though we just have one data point per minute.

dateAxis.baseInterval = {
  "timeUnit": "second",
  "count": 1
}
dateAxis.baseInterval = {
 "timeUnit": "second",
 "count": 1
}
{
  // ...
  "xAxes": [{
    "type": "DateAxis",
    "baseInterval": {
      "timeUnit": "second",
      "count": 1
    }
  }]
}

See the Pen amCharts V4: Date axis (4) by amCharts (@amcharts) on CodePen.24419

As you can see, we still have the same 3 columns, however they're now much smaller. This happens because we have instructed our Date axis that we need second-grade granularity. This means that every minute is now divvied up into 60 seconds, so our column now takes 1/60th of the width, allotted for the whole minute.

Notice, how labels are changed to accommodate seconds as well.

Removing empty time units

Sometimes you won't want to display seconds, minutes, hours, days, or whatever your baseInterval is without data. For example in a stock option, you won't have any data over the weekends, because, well, there's no trading going on.

In that case you can go ahead and remove empty time units using axis' skipEmptyPeriods setting.

dateAxis.skipEmptyPeriods= true;
dateAxis.skipEmptyPeriods= true;
{
  // ...
  "xAxes": [{
    "type": "DateAxis",
    // ...
    "skipEmptyPeriods": true
  }]
}

See the Pen amCharts V4: Date axis (5) by amCharts (@amcharts) on CodePen.24419

Duration axis

What is a Duration axis

In its nature, Duration axis is very similar to a Value axis. Both axis types use absolute numeric values for its scale.

The difference is that on Duration axis, numbers are treated like time units and the increments (intermediate grid lines and labels) are placed at time units, not at ones, tens, hundreds, etc.

For example we have a data, that illustrates how many seconds of a process each stage took:

[{
  "stage": "I",
  "duration": 780
}, {
  "stage": "II",
  "duration": 600
}, {
  "stage": "III",
  "duration": 1800
}, {
  "stage": "IV",
  "duration": 1250
}, {
  "stage": "V",
  "duration": 500
}]

We could display this on a value axis, which would show how seconds, treating those as numbers:

See the Pen amCharts 4: Duration axis (1) by amCharts (@amcharts) on CodePen.24419

That's all fine and dandy - the columns represent visual representation of the duration of each stage.

However from the user's standpoint it's not very useful: quick, what's a 2000 seconds?

That's where Duration axis comes in.

We replace ValueAxis with a DurationAxis, tell our numbers are seconds and watch the magic happen:

let yAxis = chart.yAxes.push(new am4charts.DurationAxis());
yAxis.baseUnit = "second";
yAxis.title.text = "Duration";
var yAxis = chart.yAxes.push(new am4charts.DurationAxis());
yAxis.baseUnit = "second";
yAxis.title.text = "Duration";
{
  // ...
  "yAxes": [{
    "type": "DurationAxis",
    "baseUnit": "second",
    "title": {
      "text": "Duration"
    }
  }]
}

See the Pen amCharts 4: Duration axis (2) by amCharts (@amcharts) on CodePen.24419

As you can see, now our seconds are being resolved to minutes. It's now much easier for our users to understand how long each process took, not just how much longer it was in comparison to other processes.

Granularity and format of duration labels

Duration axis, knowing what time unit your numbers mean (baseUnit), is clever enough to automatically choose format for the labels.

In our above example, none of the numbers were above an hour, so it was showing labels, formatted as minutes.

Would our numbers be higher, spanning, more than an hour, axis would automatically switch to hourly format.

Let's see what happens when we bump our number of seconds up:

See the Pen amCharts 4: Duration axis (3) by amCharts (@amcharts) on CodePen.24419

Yup. Now the format was adjusted to incorporate hours.

The increments are now placed at each hour, which represents scale nicely.

Forcing duration format

What if you don't want Duration axis going all clever on us, because we know better?

We can force Duration axis to use particular format by setting formatDuration explicitly on the chart's or axis' durationFormatter.

chart.durationFormatter.durationFormat = "hh 'hours' mm 'minutes' ss 'seconds'";
chart.durationFormatter.durationFormat = "hh 'hours' mm 'minutes' ss 'seconds'";
{
  // ...
  "durationFormatter": {
    "durationFormat": "hh 'hours' mm 'minutes' ss 'seconds'"
  }
}

See the Pen amCharts 4: Duration axis (5) by amCharts (@amcharts) on CodePen.24419

MORE INFO Make sure you visit our article about "Formatting Duration" for all the codes and guidance on duration formats.

Setting duration format in tooltips

It's not related to axis, but we want to touch this topic here anyway.

Our axis knows that it is a Duration axis, and knows it needs to format its labels as durations.

Our series, on the other hand, does not know that. It treats our time units as regular numbers, so it will display them in its tooltip formatted as such:

Duration formatted as number

That's not exactly what we wanted, is it?

This is why we'll need to explicitly force duration dormatter on our placeholders in tooltipText:

series.columns.template.tooltipText = "{categoryX}: {valueY.formatDuration()}";
series.columns.template.tooltipText = "{categoryX}: {valueY.formatDuration()}";
{
  // ...
  "series": [{
    // ...
    "columns": {
      "tooltipText": "{categoryX}: {valueY.formatDuration()}"
    }
  }]
}

See the Pen amCharts 4: Duration axis (4) by amCharts (@amcharts) on CodePen.24419

Alright, now our 18000 seconds are formatted as 5 hours:

Value formatted as duration

Configuring Axes

As we already mentioned at the beginning of this article, most of the "logic-related" settings are set directly on the axis (axis.*), while most of the settings that affect appearance are set on axis' renderer. (axis.renderer.*)

Generic settings

Since most of the settings are related to appearance, there are not that many generic settings we can set directly on axis itself.

Some of those are relative to specific axis types (like for instance baseInterval from Date axis).

Some are universal. Like for instance title. A title is an instance of Label which you can use to set text and also format it like any other label. Using it will enable a title drawn alongside the axis.

valueAxis.title.text = "Turnover ($M)";
valueAxis.title.fontWeight = "bold";
valueAxis.title.text = "Turnover ($M)";
valueAxis.title.fontWeight = "bold";
{
  // ...
  "yAxes": [{
    "type": "ValueAxis",
    "title": {
      "text": "Turnover ($M)",
      "fontWeight": "bold"
    }
  }]
}
Value axis with title

MORE INFO Look up each individual axis class in our Class Reference for a complete list of available settings.

Appearance

As you already know, most appearance-related settings are set through axis' renderer.

You can look up specific renderer in our Class Reference for available settings.

For example vertical axis on an XY chart uses AxisRendererX.

Grid, labels, and ticks

Grid are lines perpendicular to the axis. They are usually are placed at certain value intervals, determined by the axis itself, based on a lot of criteria.

Grid lines are usually accompanied with ticks and labels.

As you correctly have already guessed, we'll use axis renderer to change the appearance of any of those three.

Grid

Grid items (lines) are located in a list in renderer's property grid.

As with any list you can modify it's "template" to set how grid elements look like. (more on list templates)

As an exercise let's change Value axis' grid color and thickness:

valueAxis.renderer.grid.template.strokeOpacity = 1;
valueAxis.renderer.grid.template.stroke = am4core.color("#A0CA92");
valueAxis.renderer.grid.template.strokeWidth = 2;
valueAxis.renderer.grid.template.strokeOpacity = 1;
valueAxis.renderer.grid.template.stroke = am4core.color("#A0CA92");
valueAxis.renderer.grid.template.strokeWidth = 2;
{
  // ...
  "yAxes": [{
    "type": "ValueAxis",
    "renderer": {
      "grid": {
        "strokeOpacity": 1,
        "stroke": "#A0CA92",
        "strokeWidth": 2
      }
    }
  }]
}

See the Pen amCharts V4: Value axis (10) by amCharts (@amcharts) on CodePen.24419

MORE INFO Since grid consists of Grid elements, refer to its class reference for all available settings.

Zero line

If you have a Value axis that spans range of values from negative to positive, the chart will display a special grid line that goes at zero (a zero line).

It's not affected by renderer.grid settings, but it can be configured separately, using renderer.baseGrid property.

Since it's a single line, there are not template - you set properties to it directly.

E.g. to disable zero-line you'd do something like this:

valueAxis.renderer.baseGrid.disabled = true;
valueAxis.renderer.baseGrid.disabled = true;
{
  // ...
  "yAxes": [{
    "type": "ValueAxis",
    "renderer": {
      "baseGrid": {
        "disabled": true
      }
    }
  }]
}

Labels

Just like grid, labels are configured via a list property in axis' renderer. In this case it's labels.

Let's change the color to labels as well, as well as make them bigger.

valueAxis.renderer.labels.template.fill = am4core.color("#A0CA92");
valueAxis.renderer.labels.template.fontSize = 20;
valueAxis.renderer.labels.template.fill = am4core.color("#A0CA92");
valueAxis.renderer.labels.template.fontSize = 20;
{
  // ...
  "yAxes": [{
    "type": "ValueAxis",
    "renderer": {
      // ...
      "labels": {
        "fill": "#A0CA92",
        "fontSize": 20
      }
    }
  }]
}

See the Pen amCharts V4: Value axis (11) by amCharts (@amcharts) on CodePen.24419

MORE INFO Again, labels are objects of type AxisLabel. Refer to relative class reference for available configuration options.

Ticks

Ticks are tiny "spikes" that go between label and axis, and generally look like the extension of the grid lines.

Configure ticks by accessing template of the renderer's ticks property. (more on list templates)

By default, ticks are disabled. Let's enable them, and make them same thickness as grid line, but darker in color:

valueAxis.renderer.ticks.template.strokeOpacity = 1;
valueAxis.renderer.ticks.template.stroke = am4core.color("#495C43");
valueAxis.renderer.ticks.template.strokeWidth = 2;
valueAxis.renderer.ticks.template.length = 10;
valueAxis.renderer.ticks.template.strokeOpacity = 1;
valueAxis.renderer.ticks.template.stroke = am4core.color("#495C43");
valueAxis.renderer.ticks.template.strokeWidth = 2;
valueAxis.renderer.ticks.template.length = 10;
{
  // ...
  "yAxes": [{
    "type": "ValueAxis",
    "renderer": {
      // ...
      "ticks": {
        "strokeOpacity": 1,
        "stroke": "#495C43",
        "strokeWidth": 2,
        "length": 10
      }
    }
  }]
}

See the Pen amCharts V4: Value axis (12) by amCharts (@amcharts) on CodePen.24419

The axis line

By default, the line of the axis itself is hidden - the grid is most often doing a good job of lining the plot area.

If, however, you'd like to re-enable, or highlight the axis line, you the renderer has property line in it, which holds the axis line object.

To make it visible, set its strokeOpacity to a non-zero value (it's currently at 0 to make it invisible).

Since it's a line, we can do any kind of appearance manipulation as well, like set thickness (strokeWidth), color (stroke), add filters and even events, you name it.

categoryAxis.renderer.line.strokeOpacity = 1;
categoryAxis.renderer.line.strokeWidth = 2;
categoryAxis.renderer.line.stroke = am4core.color("#3787ac");
categoryAxis.renderer.line.strokeOpacity = 1;
categoryAxis.renderer.line.strokeWidth = 2;
categoryAxis.renderer.line.stroke = am4core.color("#3787ac");
{
  // ...
  "xAxes": [{
    "type": "CategoryAxis",
    "renderer": {
      // ...
      "line": {
        "strokeOpacity": 1,
        "strokeWidth": 2,
        "stroke": "#3787ac"
      }
    }
  }]
}

See the Pen amCharts V4: Axis lines by amCharts (@amcharts) on CodePen.24419

Positioning grid and labels

Axis (or more like its renderer) will try to position its elements - grid, labels and ticks - as best as it can.

For example, Category axis will try to place all three in the middle of the category. This might not work well, if you have, say, column series and do not want to the grid lines to go straight through the middle of the column.

That's where location property come into play. Grid, labels, and ticks all have that property, so you can precisely control their position.

The location property accepts values from 0 to 1. The value expresses relative position within axis cell / category.

0 means start, 0.5 - middle, and 1 - end. You can have any value in-between, although placing grid at one third of the category probably does not make a lot of sense, although, it's certainly possible, if you feel like that's your cup of tea.

Knowing this, let's try to "fix" our example further, so that grid on category axis marks start of the cell, while labels remain in the middle.

categoryAxis.renderer.grid.template.location = 0;
categoryAxis.renderer.grid.template.location = 0;
{
  // ...
  "xAxes": [{
    "type": "CategoryAxis",
    "renderer": {
      // ...
      "grid": {
        "location": 0
      }
    }
  }]
}

See the Pen amCharts V4: Axis element positioning by amCharts (@amcharts) on CodePen.24419

MORE INFO For more information on positioning axis elements, check our "Positioning Axis Elements" article.

Labels on Date axis

Positioning of labels on a Date axis deserves special mention, because it follows a certain fuzzy logic.

Basically it goes like this:

  • If the distance between two adjacent labels/grid lines is full period (hour, day, month, tear, etc.) we show the label in the middle of that period, because, well it represents the full period.
  • If the distance between two adjacent labels/grid lines is more than a full period, say two days, we show the label at the start of the period, because it would be very misinformative to show it in the middle of the time span that represents several days.

To put this in the perspective, the following example shows labels every single day. Since the each space between each grid line is just one day, we can safely show the label in the middle, because that label represents the whole of the period.

DateAxis with full period

Now, let's take a look at the chart with more labels, which start not fitting and therefore some of them have to be skipped.

DateAxis with multi-period increments

There are 3 days between each grid line/label. It would not make sense showing "Apr 20" label in the middle of the range that spans from 20 to 22.

Disabling certain elements

Occasionally you might want to disable certain elements, like grid, labels, or ticks.

This is supereasily done setting disabled property on a related template. E.g. to disable grid on a category axis, we'd do something like this:

categoryAxis.renderer.grid.template.disabled = true;
categoryAxis.renderer.grid.template.disabled = true;
{
  // ...
  "xAxes": [{
    "type": "CategoryAxis",
    "renderer": {
      // ...
      "grid": {
        "disabled": true
      }
    }
  }]
}

The same goes for labels (axis.renderer.labels.template.disabled = true) and ticks (axis.renderer.ticks.template.disabled = true).

Label formatting

On Category axis, labels are displayed as they come from data - no further formatting is applied.

For Value axis and Date axis the situation is different.

Before a label (value or date/time) is displayed, they are passed through the relative formatter.

Each chart in amCharts 4 has a Number formatter (accesible via numberFormater property) and a Date formatter (accessible via dateFormatter).

Formatters define how a number or a date should be displayed.

MORE INFO Please refer to dedicated "Formatters" article for in-depth details about how formatters work and are configured.

Normally, an axis, when formatting its labels will use chart's default formatter. If you want your axis to use different formats, you can create a separate formatter instance and assign it to axis' numberFormatter or dateFormatter proeprties.

Let's look at how the two are used.

Numeric labels

Numeric labels are used on a Value axis.

When Value axis wants to display a label, it throws the raw value into its Number formatter (either own or inherited from chart) and uses returned formatted string as a label.

Let's say we want to force the values to all have two decimal digits, regardless of actual value.

We can set number format for the whole chart, which will extend to the axis as well:

valueAxis.numberFormatter = new am4core.NumberFormatter();
valueAxis.numberFormatter.numberFormat = "#.00";
valueAxis.numberFormatter = new am4core.NumberFormatter();
valueAxis.numberFormatter.numberFormat = "#.00";
{
  // ...
  "yAxes": [{
    "type": "ValueAxis",
    "numberFormatter": {
      "type": "NumberFormatter",
      "numberFormat": "#.00"
    }
  }]
}

Or, if I don't want my axis settings to affect the whole chart, I can create a local formatter for the axis:

Date/time labels

Date/time labels work just like that, except with one caveat.

Depending on granularity of our data (as discussed earlier in this article about Date axis), the same date/time can be formatted according to different rules.

For example labels should be formatted in one way if we are displaying day-based data, and in a totally different way when we have, say, minute-based data.

That's why, instead of setting format directly on its formatter, Date axis has a property named dateFormats.

It's a dictionary (which is an advanced object) which allows setting formats for each possible way to display date and time.

To set a time for specific time granularity, we use dateFormats.setKey(period, format) syntax.

For example, let's make our day-based labels, instead of default "Apr 20" and "Apr 21" display full month name, day and an appropriate ordinal. E.g. "April 20th", "April 21st", etc.

Looking at "Formatting date and time" article, we see that format option for the above would be "MMMM dt".

dateAxis.dateFormats.setKey("day", "MMMM dt");
dateAxis.dateFormats.setKey("day", "MMMM dt");
{
  // ...
  "xAxes": [{
    "type": "DateAxis",
    "dateFormats": {
      "day": "MMMM dt"
    }
  }]
}

See the Pen amCharts V4: Formatting date axis labels by amCharts (@amcharts) on CodePen.24419

Other label formatting options

There's so much more to axis label formatting. Make sure you take a look at the following articles and tutorials for additional tips:

Axis tooltips

So far we have been creating fairly static charts. In real life we most certainly have a chart cursor added to our charts, for instant interactivity.

A chart cursor is a useful control which displays crosshair-like lines that, among other things, indicate cursor's precise location within any axis.

Cursor balloons on axes

Enabling axis tooltips is as easy as adding a Cursor to your chart.

MORE INFO Both Chart cursor and Axis tooltips are discussed in separate articles (linked). Make sure to check them both out.

Additional axis features

Breaks

In some chapters in this tutorial we were dealing with issues where some extraordinary high values in the series were messing up the generic perception of the data and its dynamics.

In amCharts 4 there's an excellent way to deal with such issue - axis breaks.

An axis break is basically a way to tell the axis to remove a certain range from its scale. And it's not limited to values. You can remove a range of dates (say weekends) on a Date axis, or good chunk of values from Value axis.

Let's try adding an axis break on one of our previous examples:

let axisBreak = valueAxis.axisBreaks.create();
axisBreak.startValue = 300;
axisBreak.endValue = 1200;
axisBreak.breakSize = 0.05;
var axisBreak = valueAxis.axisBreaks.create();
axisBreak.startValue = 300;
axisBreak.endValue = 1200;
axisBreak.breakSize = 0.05;
{
  // ...
  "yAxes": [{
    "type": "ValueAxis",
    // ...
    "axisBreaks": [{
      "startValue": 300,
      "endValue": 1200,
      "breakSize": 0.05
    }]
  }]
}

What the code above basically means is this: create an axis break that removes value range from 300 to 1200 from axis scale and replace it with a gap that is 0.05 width of the removed values, or 45 units.

A break on a Value axis is an object of type ValueAxisBreak.

Let's see how it turned out:

See the Pen amCharts V4: Axis breaks by amCharts (@amcharts) on CodePen.24419

Now, to make this even more cooler, let's add some events handlers to the axis break so that it is stretched out to reveal real axis scale on hover. We'll do it by animating breakSize property to 1 and back to 0.05.

axisBreak.events.on("over", () => {
  axisBreak.animate(
    [{ property: "breakSize", to: 1 }, { property: "opacity", to: 0.1 }],
    1500,
    am4core.ease.sinOut
  );
});
axisBreak.events.on("out", () => {
  axisBreak.animate(
    [{ property: "breakSize", to: 0.05 }, { property: "opacity", to: 1 }],
    1000,
    am4core.ease.quadOut
  );
});
axisBreak.events.on("over", () => {
  axisBreak.animate(
    [{ property: "breakSize", to: 1 }, { property: "opacity", to: 0.1 }],
    1500,
    am4core.ease.sinOut
  );
});
axisBreak.events.on("out", () => {
  axisBreak.animate(
    [{ property: "breakSize", to: 0.05 }, { property: "opacity", to: 1 }],
    1000,
    am4core.ease.quadOut
  );
});
{
  // ...
  "yAxes": [{
    "type": "ValueAxis",
    // ...
    "axisBreaks": [{
      "startValue": 300,
      "endValue": 1200,
      "breakSize": 0.05,
      "events": {
        "over": function(ev) {
          var axisBreak = ev.target;
          axisBreak.animate(
            [{ property: "breakSize", to: 1 }, { property: "opacity", to: 0.1 }],
            1500,
            am4core.ease.sinOut
          );
        },
        "out": function(ev) {
          var axisBreak = ev.target;
          axisBreak.animate(
            [{ property: "breakSize", to: 0.05 }, { property: "opacity", to: 1 }],
            1000,
            am4core.ease.quadOut
          );
        }
      }
    }]
  }]
}

Try running the demo below, and hovering your mouse cursor over the break now:

See the Pen amCharts V4: Axis breaks (2) by amCharts (@amcharts) on CodePen.24419

If we wanted to add a break on a Date axis, we'd have to deal with DateAxisBreak objects, that have different set of properties, e.g. startDate and endDate.

Similarly, for Category axis, we'd use CategoryAxisBreak and startCategory / endCategory.

Ranges

An axis range is a way to define a specific range on an axis, then use that range to override some visual properties of the series to its parts that fall into range, or put visual guides to a particular position or a stretch of the axis.

Axis ranges can be used for two things:

  1. Modify visual properties of part of the series, that falls into specific range, e.g. color parts of the Line series that fall below zero value in red;
  2. Mark specific values or ranges of values on an axis with a straight line and optionally labels, a.k.a. "guides".

MORE INFO It's a pretty wide topic as it is, it deserves a separate article. Make sure you visit and read "Axis ranges" article for more details and live examples.

Zooming

Each axis in amCharts 4 can become "zoomable", meaning that user can zoom in and out, to change the scale dynamically, effectively changing which pat of series is displayed.

To turn on zooming simply create and add a Scrollbar instance.

To add a horizontal scrollbar, you'd assign Scrollbar instance to chart's scrollbarX property. Similarly to add vertical scrollbar, you'd use scrollbarY.

chart.scrollbarX = new am4core.Scrollbar();
chart.scrollbarY = new am4core.Scrollbar();
chart.scrollbarX = new am4core.Scrollbar();
chart.scrollbarY = new am4core.Scrollbar();
{
  // ...
  "scrollbarX": {
    "type": "Scrollbar"
  },
  "scrollbarY": {
    "type": "Scrollbar"
  },
}

The above will create both horizontal and vertical scrollbars, that can be used to zoom the axes. Go ahead - try it out:

See the Pen amCharts V4: Value axis (scrollbars) by amCharts (@amcharts) on CodePen.24419

NOTE Turning on a scrollbar will turn zooming on for all axes with the same orientation. E.g. if you have two vertical value axes (yAxes), and add a vertical scrollbar (scrollbarY), both axes will be zoomed when scrollbar is used.

Related tutorials