Demonstrates how to create a React Chart with BaseValue axes using SciChart.js to build non-linear and adaptive scales
drawExample.ts
index.tsx
ExampleDataProvider.ts
theme.ts
1import {
2 AnnotationDragDeltaEventArgs,
3 BaseValueAxis,
4 CoordinateCalculatorBase,
5 CursorModifier,
6 ELabelPlacement,
7 EllipsePointMarker,
8 EXyDirection,
9 FastLineRenderableSeries,
10 MouseWheelZoomModifier,
11 NumberRange,
12 NumericAxis,
13 SciChartSurface,
14 VerticalLineAnnotation,
15 XDataSeries,
16 XyDataSeries,
17 ZoomExtentsModifier,
18 ZoomPanModifier,
19} from "scichart";
20import { ExampleDataProvider } from "../../../ExampleData/ExampleDataProvider";
21import { appTheme } from "../../../theme";
22
23/**
24 * Generate baseValues for a non-linear scale based on a power law
25 * @param visibleRange The visible range to generate values for
26 * @param base The base for the power law (e.g., 10 for powers of 10)
27 * @returns An array of values based on the power law, including zero if in range
28 */
29const generatePowerLawBaseValues = (
30 visibleRange: NumberRange,
31 base: number = 10,
32 minimumPower: number = 1
33): number[] => {
34 const baseValues: number[] = [];
35
36 // Generate negative powers
37 if (visibleRange.min < 0) {
38 const lowPower = Math.ceil(Math.log(Math.abs(visibleRange.min)) / Math.log(base));
39 const max =
40 visibleRange.max >= 0 ? minimumPower : Math.floor(Math.log(Math.abs(visibleRange.max)) / Math.log(base));
41 for (let power = lowPower; power >= minimumPower; power--) {
42 const value = -Math.pow(base, power);
43 baseValues.push(value);
44 }
45 }
46
47 // Add zero if it's within the range
48 if (visibleRange.min <= 0 && visibleRange.max >= 0) {
49 baseValues.push(0);
50 }
51
52 // Generate positive powers
53 if (visibleRange.max > 0) {
54 const highPower = Math.ceil(Math.log(Math.abs(visibleRange.max)) / Math.log(base));
55 const min =
56 visibleRange.min <= 0 ? minimumPower : Math.floor(Math.log(Math.abs(visibleRange.min)) / Math.log(base));
57 for (let power = minimumPower; power <= highPower; power++) {
58 const value = Math.pow(base, power);
59 baseValues.push(value);
60 }
61 }
62 return baseValues;
63};
64
65export const drawExample = async (rootElement: string | HTMLDivElement) => {
66 const { sciChartSurface, wasmContext } = await SciChartSurface.create(rootElement, {
67 theme: appTheme.SciChartJsTheme,
68 });
69
70 const xAxis = new BaseValueAxis(wasmContext, {
71 id: "BaseValueAxis",
72 visibleRange: new NumberRange(-0.1, 10.1),
73 flippedCoordinates: false,
74 labelPrecision: 3,
75 cursorLabelPrecision: 2,
76 baseValues: [0, 1, 2, 3, 4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, 5.1, 5.2, 5.3, 5.4, 5.5, 6, 7, 8, 9, 10],
77 // autoTicks: true,
78 // majorDelta: 10,
79 // minorDelta: 2,
80 // labelProvider: new NumericLabelProvider()
81 });
82 sciChartSurface.xAxes.add(xAxis);
83 const baseXValues = xAxis.getBaseValues() as XDataSeries;
84
85 // Generate baseYValues using power law with base 10
86 const initialVisibleRange = new NumberRange(-500, 500);
87 const powerLawBase = 10;
88 const baseYValueSeries = new XDataSeries(wasmContext, {
89 xValues: generatePowerLawBaseValues(initialVisibleRange, powerLawBase),
90 });
91
92 const yAxis = new BaseValueAxis(wasmContext, {
93 visibleRange: initialVisibleRange,
94 minorsPerMajor: 9,
95 baseValues: baseYValueSeries,
96 autoTicks: false,
97 });
98 yAxis.visibleRangeChanged.subscribe((data) => {
99 baseYValueSeries.clear();
100 baseYValueSeries.appendRange(
101 generatePowerLawBaseValues(yAxis.visibleRange.union(initialVisibleRange), powerLawBase)
102 );
103 });
104
105 yAxis.tickProvider.getMajorTicks = (
106 minorDelta: number,
107 majorDelta: number,
108 visibleRange: NumberRange,
109 coordCalc?: CoordinateCalculatorBase
110 ) => {
111 const ticks = generatePowerLawBaseValues(visibleRange, powerLawBase);
112 return ticks;
113 };
114
115 yAxis.tickProvider.getMinorTicks = (
116 minorDelta: number,
117 majorDelta: number,
118 visibleRange: NumberRange,
119 coordCalc?: CoordinateCalculatorBase
120 ) => {
121 const majors = generatePowerLawBaseValues(visibleRange, powerLawBase);
122 const minors: number[] = [];
123 for (let i = 0; i < majors.length - 1; i++) {
124 const cur = majors[i];
125 const next = majors[i + 1];
126 const mpm = yAxis.minorsPerMajor + (next === 0 || cur === 0 ? 1 : 0);
127 const step = (next - cur) / mpm;
128 for (let j = 1; j < mpm; j++) {
129 minors.push(cur + step * j);
130 }
131 }
132 return minors;
133 };
134
135 sciChartSurface.yAxes.add(yAxis);
136
137 const lineSeries = new FastLineRenderableSeries(wasmContext, {
138 stroke: "white",
139 pointMarker: new EllipsePointMarker(wasmContext, {
140 width: 9,
141 height: 9,
142 strokeThickness: 0,
143 fill: "steelblue",
144 stroke: "LightSteelBlue",
145 }),
146 });
147
148 lineSeries.rolloverModifierProps.tooltipTextColor = "black";
149
150 sciChartSurface.renderableSeries.add(lineSeries);
151
152 const { xValues, yValues } = ExampleDataProvider.getNoisySinewave(1000, 10, 10, 150, 20);
153 lineSeries.dataSeries = new XyDataSeries(wasmContext, { xValues: xValues, yValues });
154
155 // We use a hidden numeric axis synced to the BaseValue x axis to position the vertical line
156 const linearXAxis = new NumericAxis(wasmContext, {
157 isVisible: false,
158 visibleRange: xAxis.visibleRange,
159 });
160 sciChartSurface.xAxes.add(linearXAxis);
161 xAxis.visibleRangeChanged.subscribe((data) => (linearXAxis.visibleRange = data.visibleRange));
162
163 const magnifierAnnotation = new VerticalLineAnnotation({
164 xAxisId: linearXAxis.id,
165 x1: 5,
166 stroke: appTheme.MutedOrange,
167 strokeThickness: 3,
168 labelValue: "Drag Me!",
169 showLabel: true,
170 labelPlacement: ELabelPlacement.Top,
171 isEditable: true,
172 onDrag: (args: AnnotationDragDeltaEventArgs) => {
173 // Update the BaseValues adding more points around the annotation x coordinate, effectively zooming in that area and compressing elsewhere
174 const newBaseValues: number[] = [];
175 for (let x = 0; x <= 10; x++) {
176 if (x < args.sender.x1 - 0.5 || x > args.sender.x1 + 0.5) {
177 newBaseValues.push(x);
178 } else {
179 for (let d = -0.5; d <= 0.5; d += 0.1) {
180 newBaseValues.push(args.sender.x1 + d);
181 }
182 }
183 }
184 baseXValues.clear();
185 baseXValues.appendRange(newBaseValues);
186 },
187 });
188
189 sciChartSurface.annotations.add(magnifierAnnotation);
190
191 sciChartSurface.chartModifiers.add(
192 new ZoomPanModifier({ xyDirection: EXyDirection.XyDirection, includedXAxisIds: [xAxis.id] })
193 );
194 sciChartSurface.chartModifiers.add(new ZoomExtentsModifier({ includedXAxisIds: [xAxis.id] }));
195 sciChartSurface.chartModifiers.add(new MouseWheelZoomModifier({ includedXAxisIds: [xAxis.id] }));
196 sciChartSurface.chartModifiers.add(new CursorModifier({ showAxisLabels: true }));
197
198 return { sciChartSurface, wasmContext };
199};
200This example demonstrates how to implement BaseValueAxis within a React application using SciChart.js. BaseValue axes enable advanced, non-linear scaling by mapping numeric values to evenly spaced index positions, allowing developers to dynamically reshape how data is distributed along an axis.
This technique is particularly useful for visualizing datasets with clustered values, logarithmic behavior, or regions requiring focused magnification.
The chart is initialized using the <SciChartReact /> component, which invokes a custom draw function to create the SciChartSurface, axes, series, and modifiers. A BaseValueAxis is configured for both X and Y dimensions, with base values supplied either as arrays or as dynamic IDataSeries instances.
For the Y-axis, base values are generated using a power-law function and updated automatically when the visible range changes. Custom major and minor tick logic is implemented via the axis tick provider, giving precise control over tick placement.
A draggable vertical line annotation modifies the X-axis base values in real time, creating a magnification effect around the annotation position. This demonstrates how BaseValue axes can be used for interactive data exploration and contextual zooming.
React-Friendly Architecture: Axis behavior is fully encapsulated in the draw function, avoiding conflicts with React’s render lifecycle.
Dynamic Base Value Updates: Base values can be recalculated and reapplied at runtime without reinitializing the chart.
Advanced Cursor and Annotation Support: Despite the non-linear layout, cursor readouts and annotations remain numerically accurate.
WebAssembly Performance: All index calculations and transformations are handled efficiently, ensuring responsive interaction.
When integrating BaseValue axes into React, it is recommended to isolate chart logic within the SciChart initialization callback and manage base value updates through axis events. This example provides a strong foundation for building advanced analytical tools and scientific visualizations. For further reading, see the SciChart React Tutorials and the BaseValue Axis documentation.

Demonstrates Multiple X & Y Axis on a React Chart using SciChart.js. SciChart supports unlimited left, right, top, bottom X, Y axis with configurable alignment and individual zooming, panning

Demonstrates Secondary Y Axis on a React Chart using SciChart.js. SciChart supports unlimited, multiple left, right, top, bottom X, Y axis with configurable alignment and individual zooming, panning

Demonstrates alignment of Axis to create a vertical chart with SciChart.js - JavaScript Charts.

Demonstrates Central Axes on a React Chart using SciChart.js. SciChart supports unlimited left, right, top, bottom X, Y axis with configurable layout

Demonstrates isStaticAxis on a React Chart using SciChart.js.

Demonstrates Vertically Stacked Axes on a React Chart using SciChart.js, allowing data to overlap

Demonstrates Logarithmic Axis on a React Chart using SciChart.js. SciChart supports logarithmic axis with scientific or engineering notation and positive and negative values


Demonstrates the option of the transparent Axes customization on a React Chart using SciChart.js.

Demonstrates how to use arbitrary text for axis labels, rather than formatted data values, using the new TextLabelProvider

Demonstrates outer, inner, central and stacked axes, and use of axis alignment to create vertical charts