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)
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)
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)
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:
- Use
Axis.fit()
after data is pushed in
// Add data to series
// Afterwards, fit axis to view immediately
chart.axisX.fit()
- 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 })
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()) })
}
The key parts here are:
iStack
parameter given toaddAxisY
method. This determines the vertical position of the Y axis.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.- 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()) })
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
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.