This example demonstrates a high performance Scatter chart grid with 5000 points per chart using the subcharts api in SciChart.js which can be used to create a React Correlation Plot
drawExample.ts
index.tsx
helpers.ts
theme.ts
correlationLinePoints.ts
1import { appTheme } from "../../../theme";
2import {
3 EllipsePointMarker,
4 NumericAxis,
5 NumberRange,
6 SciChartSurface,
7 XyDataSeries,
8 XyScatterRenderableSeries,
9 FastLineRenderableSeries,
10 INumericAxisOptions,
11 ENumericFormat,
12 EAutoRange,
13 ESubSurfacePositionCoordinateMode,
14 SciChartSubSurface,
15 Rect,
16 I2DSubSurfaceOptions,
17 Thickness,
18 TextAnnotation,
19 ECoordinateMode,
20 EHorizontalAnchorPoint,
21 EVerticalAnchorPoint,
22 FadeAnimation,
23 ZoomExtentsModifier,
24 ZoomPanModifier,
25 MouseWheelZoomModifier,
26 EModifierMouseArgKey,
27 EExecuteOn,
28 EAxisAlignment,
29 TextLabelProvider,
30 ELabelAlignment,
31 ETitlePosition,
32 SciChartVerticalGroup,
33} from "scichart";
34
35import correlationLinePoints from "./correlationLinePoints";
36import { getSubChartPositionIndexes } from "../../FeatureDemos/SubChartsAPI/helpers";
37
38const axisOptions: INumericAxisOptions = {
39 useNativeText: true,
40 isVisible: false,
41 drawMajorBands: false,
42 drawMinorGridLines: false,
43 drawMinorTickLines: false,
44 drawMajorTickLines: false,
45 drawMajorGridLines: false,
46 labelStyle: { fontSize: 8 },
47 labelFormat: ENumericFormat.Decimal,
48 labelPrecision: 1,
49};
50
51// theme overrides
52const sciChartTheme = appTheme.SciChartJsTheme;
53
54export const drawExample = async (rootElement: string | HTMLDivElement) => {
55 // Use createSingle here to get the performance benefit of subcharts
56 const { wasmContext, sciChartSurface: mainSurface } = await SciChartSurface.createSingle(rootElement, {
57 theme: sciChartTheme,
58 title: "Hold Ctrl to Zoom / Pan the whole grid rather than an individual chart",
59 titleStyle: { fontSize: 14, position: ETitlePosition.Bottom },
60 });
61
62 const subChartsNumber = 24;
63 const columnsNumber = 6;
64 const rowsNumber = 4;
65
66 const pointsOnChart = 5000;
67
68 const subchartBorderColor = appTheme.VividSkyBlue;
69 const scatterColor = appTheme.VividSkyBlue;
70 const lineUp = appTheme.VividGreen;
71 const lineDown = appTheme.VividRed;
72 const lineHorizontal = appTheme.ForegroundColor;
73 const annotationColor = appTheme.ForegroundColor;
74
75 const annotationFontSize = 14;
76
77 const xAxisVisibleRange = new NumberRange(0, columnsNumber);
78 const yAxisVisibleRange = new NumberRange(0, rowsNumber);
79
80 const mainXAxis = new NumericAxis(wasmContext, {
81 zoomExtentsRange: new NumberRange(xAxisVisibleRange.min, xAxisVisibleRange.max),
82 drawMajorBands: false,
83 drawMajorGridLines: false,
84 drawMinorGridLines: false,
85 isVisible: true,
86 id: "mainXAxis",
87 visibleRange: new NumberRange(xAxisVisibleRange.min, xAxisVisibleRange.max),
88 // Uncomment this to limit panning when fully zoomed out
89 //visibleRangeLimit: new NumberRange(xAxisVisibleRange.min, xAxisVisibleRange.max),
90 axisAlignment: EAxisAlignment.Top,
91 useNativeText: false,
92 labelProvider: new TextLabelProvider({
93 labels: { 0.5: "A", 1.5: "B", 2.5: "C", 3.5: "D", 4.5: "E", 5.5: "F" },
94 useNativeText: false,
95 }),
96 labelStyle: {
97 alignment: ELabelAlignment.Center,
98 fontFamily: "Arial",
99 fontSize: 24,
100 fontWeight: "bold",
101 color: "White",
102 },
103 });
104
105 // provide hardcoded tick values for the x axis as these will be used to position column names
106 mainXAxis.tickProvider.getMajorTicks = (minorDelta: number, majorDelta: number, visibleRange: NumberRange) =>
107 [...new Array(columnsNumber)].map((d, i) => i + 0.5);
108
109 mainSurface.xAxes.add(mainXAxis);
110
111 const mainYAxis = new NumericAxis(wasmContext, {
112 zoomExtentsRange: new NumberRange(yAxisVisibleRange.min, yAxisVisibleRange.max),
113 drawMajorBands: false,
114 drawMajorGridLines: false,
115 drawMinorGridLines: false,
116 isVisible: true,
117 id: "mainYAxis",
118 visibleRange: new NumberRange(yAxisVisibleRange.min, yAxisVisibleRange.max),
119 // Uncomment this to limit panning when fully zoomed out
120 //visibleRangeLimit: new NumberRange(yAxisVisibleRange.min, yAxisVisibleRange.max),
121 axisAlignment: EAxisAlignment.Left,
122 flippedCoordinates: true,
123 useNativeText: false,
124 labelProvider: new TextLabelProvider({
125 labels: { 0.5: "1", 1.5: "2", 2.5: "3", 3.5: "4" },
126 useNativeText: false,
127 }),
128 labelStyle: {
129 alignment: ELabelAlignment.Center,
130 fontFamily: "Arial",
131 fontSize: 24,
132 fontWeight: "bold",
133 color: "White",
134 },
135 });
136 mainSurface.yAxes.add(mainYAxis);
137
138 // The executeCondition set here allows these modifiers to activate independently of the ones on the individual subSurfaces
139 mainSurface.chartModifiers.add(
140 new ZoomExtentsModifier({ executeCondition: { key: EModifierMouseArgKey.Ctrl } }),
141 new ZoomPanModifier({
142 executeCondition: { button: EExecuteOn.MouseLeftButton, key: EModifierMouseArgKey.Ctrl },
143 }),
144 new MouseWheelZoomModifier({ executeCondition: { key: EModifierMouseArgKey.Ctrl } })
145 );
146
147 const subChartPositioningCoordinateMode = ESubSurfacePositionCoordinateMode.DataValue;
148 const vGroup = new SciChartVerticalGroup();
149 let maxYRange = new NumberRange(-1, 1);
150
151 const initSubChart = (subChartIndex: number) => {
152 const { rowIndex, columnIndex } = getSubChartPositionIndexes(subChartIndex, columnsNumber);
153
154 const width = 1;
155 const height = 1;
156
157 const position = new Rect(columnIndex * width, rowIndex * height, width, height);
158 // sub-surface configuration
159 const subChartOptions: I2DSubSurfaceOptions = {
160 id: `subChart-${subChartIndex}`,
161 theme: sciChartTheme,
162 position,
163 parentXAxisId: mainXAxis.id,
164 parentYAxisId: mainYAxis.id,
165 coordinateMode: subChartPositioningCoordinateMode,
166 padding: Thickness.fromNumber(0),
167 viewportBorder: {
168 color: subchartBorderColor + "30",
169 border: 1,
170 },
171 };
172
173 // create sub-surface
174 const subChartSurface = SciChartSubSurface.createSubSurface(mainSurface, subChartOptions);
175
176 // add axes to the sub-surface
177 const subChartXAxis = new NumericAxis(wasmContext, {
178 ...axisOptions,
179 id: `${subChartSurface.id}-XAxis`,
180 growBy: new NumberRange(0.04, 0.04),
181 isVisible: rowIndex === rowsNumber - 1,
182 });
183
184 subChartSurface.xAxes.add(subChartXAxis);
185
186 const subChartYAxis = new NumericAxis(wasmContext, {
187 ...axisOptions,
188 id: `${subChartSurface.id}-YAxis`,
189 axisAlignment: EAxisAlignment.Left,
190 isVisible: columnIndex === 0,
191 });
192
193 subChartSurface.yAxes.add(subChartYAxis);
194
195 if (columnIndex === 0) {
196 // Synchonise axis sizes
197 vGroup.addSurfaceToGroup(subChartSurface);
198 // Set y ranges for previous Row
199 if (rowIndex > 0) {
200 const start = (rowIndex - 1) * columnsNumber;
201 for (let index = start; index < start + columnsNumber; index++) {
202 mainSurface.subCharts[index].yAxes.get(0).visibleRange = maxYRange;
203 }
204 }
205 // reset range tracking
206 maxYRange = new NumberRange(-1, 1);
207 }
208
209 const gaussianRand = (mean: number = 0.5, dist: number = 1) => {
210 let rand = 0;
211 for (let i = 0; i < 6; i += 1) {
212 rand += Math.random() * dist + mean;
213 }
214 return rand / 6;
215 };
216
217 // generating random data for scatterplots
218 function generateScatterplotData(numElements: number) {
219 let x: number[] = [];
220 let y: number[] = [];
221
222 let randomNum = (Math.random() - 0.5) * 3;
223 let randomNum1 = Math.random();
224
225 for (let i = 0; i < numElements; i++) {
226 const xVal = gaussianRand(0.5, 1);
227 x.push(xVal);
228 y.push(gaussianRand(xVal * randomNum, 1 + randomNum1 * 3));
229 }
230 return { x, y };
231 }
232
233 const { x: xValues, y: yValues } = generateScatterplotData(pointsOnChart);
234
235 const { correlationCoefficient, linePoints } = correlationLinePoints(xValues, yValues);
236
237 const lineSeries = new FastLineRenderableSeries(wasmContext, {
238 dataSeries: new XyDataSeries(wasmContext, {
239 xValues: [linePoints.x1, linePoints.x2],
240 yValues: [linePoints.y1, linePoints.y2],
241 }),
242 stroke: correlationCoefficient > 0.1 ? lineUp : correlationCoefficient < -0.1 ? lineDown : lineHorizontal,
243 strokeThickness: 3,
244 opacity: 0.8,
245 animation: new FadeAnimation({ duration: 600, fadeEffect: true }),
246 });
247
248 const scatterSeries = new XyScatterRenderableSeries(wasmContext, {
249 dataSeries: new XyDataSeries(wasmContext, { xValues, yValues }),
250 pointMarker: new EllipsePointMarker(wasmContext, {
251 width: 2,
252 height: 2,
253 strokeThickness: 0,
254 fill: scatterColor,
255 }),
256 opacity: 1,
257 });
258
259 const annotation = new TextAnnotation({
260 x1: 5,
261 y1: 0.07,
262 xCoordinateMode: ECoordinateMode.Pixel,
263 yCoordinateMode: ECoordinateMode.Relative,
264 horizontalAnchorPoint: EHorizontalAnchorPoint.Left,
265 verticalAnchorPoint: EVerticalAnchorPoint.Center,
266 textColor: annotationColor,
267 fontSize: annotationFontSize,
268 fontFamily: "Default",
269 text: `i = ${subChartIndex}, r = ${correlationCoefficient.toFixed(2)}`,
270 });
271
272 subChartSurface.renderableSeries.add(scatterSeries, lineSeries);
273 subChartSurface.annotations.add(annotation);
274
275 const xRange = scatterSeries.getXRange();
276 const yRange = scatterSeries.getYRange(xRange);
277 if (yRange.min < maxYRange.min || yRange.max > maxYRange.max) {
278 maxYRange = maxYRange.union(yRange);
279 }
280
281 subChartSurface.chartModifiers.add(
282 new ZoomExtentsModifier(),
283 new ZoomPanModifier(),
284 new MouseWheelZoomModifier()
285 );
286 };
287
288 // generate the subcharts grid
289 for (let subChartIndex = 0; subChartIndex < subChartsNumber; subChartIndex += 1) {
290 initSubChart(subChartIndex);
291 }
292 // set last row y range
293 const start = (rowsNumber - 1) * columnsNumber;
294 for (let index = start; index < start + columnsNumber; index++) {
295 mainSurface.subCharts[index].yAxes.get(0).visibleRange = maxYRange;
296 }
297
298 return {
299 wasmContext,
300 sciChartSurface: mainSurface,
301 };
302};
303This example demonstrates how to build a Correlation Plot in a React application using SciChart.js. A correlation plot is a powerful visualization tool used to show the correlation matrix between many variables, presented as a grid of sub-charts.
The core of this example is the use of the Subcharts API to efficiently create and manage the grid of charts within a single SciChartSurface. Each individual chart in the matrix displays a relationship between two variables using an XY Scatter Renderable Series. It uses randomly generated dataSets for each chart with a random correlation.
The example demonstrates the programatic use of renderableSeries.getXRange and renderableSeries.getYRange to synchronise the y ranges for each row, and SciChartVerticalGroup to synchronise the chart sizes for the first column. The chart is fully interactive, supporting zooming and panning of individual charts and also the grid as a whole, when holding Ctrl. This is achieved using modifiers on the main surface which different executeCondition configured.
Integration into a React application is seamless using the <SciChartReact> component. The main chart configuration logic is encapsulated in the drawExample function, which is passed to the initChart prop. This approach ensures that the SciChart.js surface is correctly initialized and disposed of, aligning with React's component lifecycle and preventing memory leaks.

In this example we are simulating four channels of data showing that SciChart.js can be used to draw real-time ECG/EKG charts and graphs to monitor heart reate, body temperature, blood pressure, pulse rate, SPO2 blood oxygen, volumetric flow and more.

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

Demonstrating the capability of SciChart.js to create JavaScript 3D Point Cloud charts and visualize LiDAR data from the UK Defra Survey.

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

See the frequency of recordings with the React audio spectrum analyzer example from SciChart. This real-time audio visualizer demo uses a Fourier Transform.

Demonstrating the capability of SciChart.js to create a JavaScript Audio Analyzer Bars and visualize the Fourier-Transform of an audio waveform in realtime.

Demonstrates how to create a Waterfall chart in SciChart.js, showing chromotragraphy data with interactive selection of points.

See the React Phasor Diagram example to combine a Cartesian surface with a Polar subsurface. Get seamless React integration with SciChart. View demo now.
React **Semiconductors Dashboard** using SciChart.js, by leveraging the **FastRectangleRenderableSeries**, and its `customTextureOptions` property to have a custom tiling texture fill.

React **Wafer Analysis Chart** using SciChart.js, by leveraging the **FastRectangleRenderableSeries**, and crossfilter to enable live filtering.