Skip to main content
Version: 5.2.0

Axis

Here you can find guides for most often required configurations of Axis, a critical part of almost all chart types.

Accessing axis

This depends on the type of chart.

const axisX = ChartXY.axisX
const axisY = ChartXY.axisY

const axisZ = Chart3D.axisZ

const radialAxis = PolarChart.radialAxis
const amplitudeAxis = PolarChart.amplitudeAxis

const valueAxis = BarChart.valueAxis
const categoryAxis = BarChart.categoryAxis

Axis title

axis
.setTitle('Voltage')
.setTitleFont(font => font.setSize(10).setFamily('Segoe UI'))
.setTitleFillStyle(new SolidFill({ color: ColorRGBA(255, 0, 0) }))

For more details about style API, please see Styles, colors and fonts.

Axis interval / view

By default, any axis automatically adjusts its "interval" [start - end] to display all series connected to it. The start-end interval can be explicitly set using the setInterval or setDefaultInterval methods.

// Example, show interval between 0 and 100
axis.setInterval({ start: 0, end: 100 })

By using setDefaultInterval this configured interval is also restored if the user triggers the "zoom to fit" interaction (hold left mouse button down and drag towards upper-left).

axis.setDefaultInterval({ start: 0, end: 100 })

Numeric axis

Display numeric values using automatically placed axis ticks (10, 20, 30, etc.). This is the default axis behavior.

axis.setTickStrategy(AxisTickStrategies.Numeric)

Chart with numeric axisChart with numeric axis

Extreme ticks

By default, ticks are placed on logical key values (e.g. 0, 10, 20, 30, ...) depending on active axis interval. Sometimes, with physically small charts you may get problems from not having enough ticks visible. One solution for this is to enable "extreme ticks", this simply means always displaying the axis start and end values, even if they are not "logical key values".

axis.setTickStrategy(AxisTickStrategies.Numeric, (ticks) => ticks
// Enable extreme ticks
.setExtremeTickStyle(ticks.getMajorTickStyle())
)

Date-Time axis

Display seconds, minutes, hours, days, months and years using automatically placed axis ticks.

axis.setTickStrategy(AxisTickStrategies.DateTime)

Chart with date-time axisChart with date-time axis

Date-time axis intervals are defined as UTC timestamps, meaning timestamp = milliseconds since 1st January 1970.

axis.setInterval({
start: Date.UTC(2022, 0, 1), // 1st Jan 2022
end: Date.UTC(2022, 0, 31) // 31st Jan 2022
})

Zoom ability

By default, you can only show time axis intervals of around 1 day range. To improve on this, you can enable so called "high precision axis", which enables zooming to milliseconds range or smaller:

const chart = lc.ChartXY({
defaultAxisX: {
type: 'linear-highPrecision'
}
})

Hide great ticks

Commonly required tweak to hide so-called "great tick level":

axis.setTickStrategy(AxisTickStrategies.DateTime, ticks => ticks
.setGreatTickStyle(emptyTick)
)

Time axis

Display hours, minutes, seconds, milliseconds and microseconds using automatically placed axis ticks.

axis.setTickStrategy(AxisTickStrategies.Time)

Chart with time axisChart with time axis

Time axis intervals are defined as milliseconds.

// Example, show range of 10 seconds
axis.setInterval({ start: 0, end: 10_000 })

Time axis is well suited to display "run-time", as in how long the application has been running:

setInterval(() => {
lineSeries.appendSample({ x: performance.now(), y: Math.random() })
}, 1000 / 60)

Alternatively, you can input UTC timestamps and specify which timestamp is displayed as 00:00:00:

axis.setTickStrategy(AxisTickStrategies.Time, (ticks) => ticks.setTimeOrigin(-Date.now()))
setInterval(() => {
lineSeries.appendSample({ x: Date.now(), y: Math.random() })
}, 1000 / 60)

This can be useful if you want to further in than what is allowed by Date-Time axis (milliseconds, microseconds ranges).

Disable ticks

axis.setTickStrategy(AxisTickStrategies.Empty)

Custom, manual or categorical axis

If built-in tick placement modes don't suit your use case, you can disable them and place ticks manually.

axis.setTickStrategy(AxisTickStrategies.Empty)
const tick = axis
.addCustomTick()
.setValue(2)
.setTextFormatter((value) => `Hello`)

Custom ticks are available currently in XY and 3D charts.

Scrolling axis

// Example, configure a scrolling axis that keeps interval with length: `1000`
axis
.setScrollStrategy(AxisScrollStrategies.progressive)
.setDefaultInterval((state) => ({
end: state.dataMax ?? 0,
start: (state.dataMax ?? 0) - 1_000,
stopAxisAfter: false,
}))

This results in the axis automatically revealing new data as it is spawned, but keeping the size of axis interval unchanged - resulting in older data going out of view.

Loading animations

LightningChart JS doesn't have any "loading animations" as such, but a very common user issue is when the chart is created and data pushed in, there is a long Axis scroll animation, generally on Date-Time Axes especially.

There's a few easy ways to get rid of this kind of behavior:

  1. Use Axis.fit() after data is pushed in
// Add data to series
// Afterwards, fit axis to view immediately
chart.axisX.fit()
  1. Disable axis scroll animations all together
chart.axisX.setAnimationScroll(false)

Multiple axes and positioning

In ChartXY, you can have more than two axes, and axes can also be positioned in different locations. Additional axes can be added with addAxisX and addAxisY methods:

const axisX2 = chart.addAxisX().setTitle('Extra Axis X')

By default, series are attached to the default axes. When an application has several axes, it is recommended to explicitly specify which axis each series should be connected to:

const lineSeries = chart.addLineSeries({
xAxis: axisX2,
yAxis: chart.axisY
})

Axis side

Axes can be positioned at the opposite end of the chart (right for X axis, top for Y axis):

const axisY2 = chart.addAxisY({ opposite: true })

Opposite Y axisOpposite Y axis

For default axes, this has to be specified when the ChartXY is created:

const chart = lc.ChartXY({
defaultAxisY: { opposite: true }
})

Stacked axes

Multiple axes can also be stacked on top of each other. Most commonly this is used to share 1 X axis between many different Y axes and respective Series:

chart.axisY.dispose()
for (let i = 0; i < 3; i += 1) {
const axisY = chart.addAxisY({ iStack: i }).setMargins(i > 0 ? 15 : 0, i < 2 ? 15 : 0)
const series = chart
.addPointLineAreaSeries({ axisY, dataPattern: 'ProgressiveX' })
.setAreaFillStyle(emptyFill)
.appendSamples({ yValues: new Array(100).fill(0).map((_) => Math.random()) })
}

Stacked Y axisStacked Y axis

The key parts here are:

  1. iStack parameter given to addAxisY method. This determines the vertical position of the Y axis.
  2. Axis.setMargins is used to add empty space along vertical plane to avoid Y axis tick labels colliding, and adding a clear separation between channels.
  3. For simplicity of implementation, the default Y axis is disposed before creating the stacked Y axes.

The length of axes can be changed in two different ways:

// Set relative length of axis to `0.5`
// By default, every axis has relative length of `1`, so this operation would effectively make the axis half the length of others
axis.setLength({ relative: 0.5 })
// Set length of axis to 200 pixels exactly.
axis.setLength({ pixels: 200 })

Parallel axes

Axes can also be placed parallel to each other:

const axisY1 = chart.axisY
const axisY2 = chart.addAxisY({ iParallel: 1 })
.setTickStrategy(AxisTickStrategies.Numeric, (ticks) => ticks.setTickStyle((major) => major.setGridStrokeStyle(emptyLine)))
const series1 = chart.addPointLineAreaSeries({ axisY: axisY1, dataPattern: 'ProgressiveX' })
.setAreaFillStyle(emptyFill)
.appendSamples({ yValues: new Array(100).fill(0).map((_) => Math.random()) })
const series2 = chart.addPointLineAreaSeries({ axisY: axisY2, dataPattern: 'ProgressiveX' })
.setAreaFillStyle(emptyFill)
.appendSamples({ yValues: new Array(100).fill(0).map((_) => Math.random()) })

Parallel Y axisParallel Y axis

Generally, when there are parallel axis, you want to disable tick gridlines because it is practically impossible to recognize which axis they belong to. In above example, one of the Y axis has gridlines visible and the other not.

Parallel axes can also be combined with opposite axes, so that one Y axis is on left, and another on right.

User interactions

info

Axes from different chart types can expose different set of these methods! Use Intellisense, Type definitions, or API reference to be certain.

Built-in user interactions can conveniently be selectively disabled from any axis. A very common use case is to disable most interactions from the charts Y axis:

// Make axis unaffected by interaction where user pans chart.
yAxis.setChartInteractionPanByDrag(false)
// Make axis unaffected by interaction where user zooms the chart in/out with mouse wheel.
yAxis.setChartInteractionZoomByWheel(false)
// Make axis unaffected by interaction where user zooms into chart by dragging with left mouse button down.
yAxis.setChartInteractionZoomByDrag(false)
// Disable all mouse interactions of an Axis
axis.setMouseInteractions(false)
// Make axis unaffected by all chart interactions
axis.setChartInteractions(false)
// These methods only affect user interactions directly above the Axis
axis.setAxisInteractionPanByDragging(false)
axis.setAxisInteractionZoomByDragging(false)
axis.setAxisInteractionZoomByWheeling(false)
axis.setAxisInteractionReleaseByDoubleClicking(false)

Swapping left / right mouse buttons

A common desire is to swap default interaction mouse buttons (left/right) in XY charts for panning and zooming. This can be done like so:

const lc = lightningChart({
// LightningChartOptions
overrideInteractionMouseButtons: {
chartXYPanMouseButton: 0, // LMB
chartXYRectangleZoomFitMouseButton: 2, // RMB
axisXYPanMouseButton: 0, // LMB
axisXYZoomMouseButton: 2, // RMB
}
})
const chart = lc.ChartXY()

Styling axis ticks

Axis ticks are configured via the AxisTickStrategy interface:

axis.setTickStrategy(AxisTickStrategies.Numeric, tickStrategy => tickStrategy
.setTickStyle(ticks => ticks
.setLabelFillStyle(new SolidFill({ color: ColorRGBA(255, 0, 0) }))
.setLabelFont(font => font.setSize(10).setFamily('Segoe UI'))
.setGridStrokeStyle(new SolidLine({ thickness: 1, fillStyle: new SolidFill({ color: ColorRGBA(255, 0, 0) }) }))
.setTickStyle(emptyLine)
)
)

Alternatively instead of setTickStyle, you can style major and minor ticks separately using setMajorTickStyle / setMinorTickStyle.

For more details about style API, please see Styles, colors and fonts.

Same syntax works for DateTime and Time axis tick strategies.

Styling axis line

// Hide axis line
axis.setStrokeStyle(emptyLine)
// Red axis line
axis.setStrokeStyle(new SolidLine({ thickness: 1, fillStyle: new SolidFill({ color: ColorRGBA(255, 0, 0) }) }))

For more details about style API, please see Styles, colors and fonts.

Hiding grid-lines

axis.setTickStrategy(AxisTickStrategies.Numeric, tickStrategy => tickStrategy
.setTickStyle(ticks => ticks
.setGridStrokeStyle(emptyLine)
)
)

Same syntax works for DateTime and Time axis tick strategies.

Logarithmic axis

Logarithmic axes can be enabled when creating an Axis or Chart. Here's how it looks for ChartXY:

const chart = lc.ChartXY({
defaultAxisY: {
type: 'logarithmic',
base: 10,
}
})

...or for non-default Axis:

const axisLog = chart.addAxisY({ type: 'logarithmic', base: 10 })

Please note that logarithmic axis range is not defined at 0, so you should confirm that your data doesn't have exact 0 values.

Inverted or reverted axis

By default, axis fits visible data range so that min value is shown at axis "start" (left for X axis, bottom for Y axis). This can be reversed so that min value is shown at axis "end" (right for X axis, top for Y axis) like this:

// Reverse axis interval
axis.setInterval({ start: 1, end: 0, stopAxisAfter: false })

Restricting axis interval

// Example 1, prevent zooming outside active data set
axis.setIntervalRestrictions((state) => ({
startMin: state.dataMin,
endMax: state.dataMax,
}))
// Example 2, set max zoom in level (intervalMin)
axis.setIntervalRestrictions({ intervalMin: 10 })
// Example 3, set max zoom out level (intervalMax)
axis.setIntervalRestrictions({ intervalMax: 1000 })

Following changes to axis interval

axis.onIntervalChange((_, start, end) => {
console.log(start, end)
})

Synchronizing several axes

Any number of axes can be conveniently synchronized with synchronizeAxisIntervals function. This ensures that their interval is always the same.

synchronizeAxisIntervals(axis1, axis2, axis3)

Removing series from affecting axis

Individual series can be disabled from affecting any axis scrolling or fitting using setAutoScrollingEnabled method:

series.setAutoScrollingEnabled(false)

Zoom range limitations

LightningChart JS is based on WebGL powered graphics. This imposes some limitations when dealing with extremely large numbers, or numbers with extremely precise decimal points.

The main way this limitation shows itself is Axis zoom range limitations, meaning axis preventing its interval [start: number, end: number] from going to ranges that could result in rendering errors.

If your application results in Axis refusing to go to required zoom range, you should change the axis type to "high precision":

const chart = lightningChart().ChartXY({
defaultAxisX: {
type: 'linear-highPrecision'
}
})

The high precision axis supports almost all series types, but not every single one, and comes with a slight performance penalty. To find what series types are unsupported, navigate to API documentation and find the AxisOptions entry.