LiDAR 3D Point Cloud of Geospatial Data

Demonstrates how to visualize LiDAR UAV Data from the Defra survey using SciChart.js. A 1km x 1km slice of London is visualised as a 3D point-cloud with contour map overlaid. A heatmap legend on the right indicates the heightmap.

Fullscreen

Edit

 Edit

Docs

drawExample.ts

index.tsx

ExampleDataProvider.ts

theme.ts

AscReader.ts

Copy to clipboard
Minimise
Fullscreen
1import {
2    CameraController,
3    EColorMapMode,
4    EDrawMeshAs,
5    EMeshPaletteMode,
6    ETitlePosition,
7    GradientColorPalette,
8    HeatmapLegend,
9    linearColorMapLerp,
10    MouseWheelZoomModifier3D,
11    NumericAxis3D,
12    OrbitModifier3D,
13    PixelPointMarker3D,
14    ScatterRenderableSeries3D,
15    SciChart3DSurface,
16    SurfaceMeshRenderableSeries3D,
17    TLinearColorMap,
18    UniformGridDataSeries3D,
19    Vector3,
20    XyzDataSeries3D,
21    zeroArray2D,
22} from "scichart";
23import { AscData, AscReader } from "./AscReader";
24import { appTheme } from "../../../theme";
25import { fetchLidarData } from "../../../ExampleData/ExampleDataProvider";
26
27type TMetadata = {
28    vertexColor: number;
29    pointScale: number;
30};
31
32export const drawExample = async (rootElement: string | HTMLDivElement) => {
33    // Load data from the server
34    const dataFromServer = await getDataFromServer();
35
36    // Create a SciChart3DSurface
37    const { wasmContext, sciChart3DSurface } = await SciChart3DSurface.create(rootElement, {
38        theme: appTheme.SciChartJsTheme,
39    });
40    sciChart3DSurface.worldDimensions = new Vector3(1000, 200, 1000);
41
42    // Create and attach a camera to the 3D Viewport
43    sciChart3DSurface.camera = new CameraController(wasmContext, {
44        position: new Vector3(800, 1000, 800),
45        target: new Vector3(0, 50, 0),
46    });
47
48    // Add an X,Y,Z axis to the viewport
49    sciChart3DSurface.xAxis = new NumericAxis3D(wasmContext, { axisTitle: "X Distance (Meters)" });
50    sciChart3DSurface.yAxis = new NumericAxis3D(wasmContext, { axisTitle: "Height (Meters)" });
51    sciChart3DSurface.zAxis = new NumericAxis3D(wasmContext, { axisTitle: "Z Distance (Meters)" });
52
53    // Create a ScatterRenderableSeries3D and configure as a point cloud with 1px markers
54    sciChart3DSurface.renderableSeries.add(
55        new ScatterRenderableSeries3D(wasmContext, {
56            pointMarker: new PixelPointMarker3D(wasmContext),
57            dataSeries: new XyzDataSeries3D(wasmContext, {
58                xValues: dataFromServer.ascData.XValues,
59                yValues: dataFromServer.ascData.YValues,
60                zValues: dataFromServer.ascData.ZValues,
61                metadata: dataFromServer.meta,
62            }),
63            opacity: 1,
64        })
65    );
66
67    // Also render the point-cloud data as a heightmap / topology map with contours
68    sciChart3DSurface.renderableSeries.add(
69        new SurfaceMeshRenderableSeries3D(wasmContext, {
70            dataSeries: new UniformGridDataSeries3D(wasmContext, {
71                xStart: 0,
72                xStep: dataFromServer.ascData.CellSize,
73                zStart: 0,
74                zStep: dataFromServer.ascData.CellSize,
75                yValues: dataFromServer.heightValues2D,
76            }),
77            minimum: 0,
78            maximum: 50,
79            drawSkirt: true,
80            opacity: 0.7,
81            meshColorPalette: new GradientColorPalette(wasmContext, {
82                gradientStops: [
83                    { offset: 1, color: appTheme.VividPink },
84                    { offset: 0.9, color: appTheme.VividOrange },
85                    { offset: 0.7, color: appTheme.MutedRed },
86                    { offset: 0.5, color: appTheme.VividGreen },
87                    { offset: 0.3, color: appTheme.VividSkyBlue },
88                    { offset: 0.2, color: appTheme.Indigo },
89                    { offset: 0, color: appTheme.DarkIndigo },
90                ],
91            }),
92            contourStroke: appTheme.PaleSkyBlue,
93            meshPaletteMode: EMeshPaletteMode.HEIGHT_MAP_INTERPOLATED,
94            contourStrokeThickness: 2,
95            drawMeshAs: EDrawMeshAs.SOLID_WITH_CONTOURS,
96        })
97    );
98
99    // Add interactivity modifiers for orbiting and zooming with the mousewheel
100    sciChart3DSurface.chartModifiers.add(new MouseWheelZoomModifier3D());
101    sciChart3DSurface.chartModifiers.add(new OrbitModifier3D());
102
103    return { sciChartSurface: sciChart3DSurface, wasmContext };
104};
105
106export const drawHeatmapLegend = async (rootElement: string | HTMLDivElement) => {
107    const { heatmapLegend, wasmContext } = await HeatmapLegend.create(rootElement, {
108        theme: {
109            ...appTheme.SciChartJsTheme,
110            sciChartBackground: appTheme.DarkIndigo + "BB",
111            loadingAnimationBackground: appTheme.DarkIndigo + "BB",
112        },
113        yAxisOptions: {
114            isInnerAxis: true,
115            labelStyle: {
116                fontSize: 12,
117                color: appTheme.ForegroundColor,
118            },
119            axisBorder: {
120                borderRight: 1,
121                color: appTheme.ForegroundColor + "77",
122            },
123            majorTickLineStyle: {
124                color: appTheme.ForegroundColor,
125                tickSize: 6,
126                strokeThickness: 1,
127            },
128            minorTickLineStyle: {
129                color: appTheme.ForegroundColor,
130                tickSize: 3,
131                strokeThickness: 1,
132            },
133        },
134        colorMap: {
135            minimum: 0,
136            maximum: 50,
137            gradientStops: [
138                { offset: 1, color: appTheme.VividPink },
139                { offset: 0.9, color: appTheme.VividOrange },
140                { offset: 0.7, color: appTheme.MutedRed },
141                { offset: 0.5, color: appTheme.VividGreen },
142                { offset: 0.3, color: appTheme.VividSkyBlue },
143                { offset: 0.2, color: appTheme.Indigo },
144                { offset: 0, color: appTheme.DarkIndigo },
145            ],
146        },
147    });
148
149    heatmapLegend.innerSciChartSurface.sciChartSurface.title = "Height (m)";
150
151    heatmapLegend.innerSciChartSurface.sciChartSurface.titleStyle = {
152        fontSize: 12,
153        color: appTheme.ForegroundColor,
154        position: ETitlePosition.Bottom,
155    };
156
157    return { sciChartSurface: heatmapLegend.innerSciChartSurface.sciChartSurface };
158};
159
160async function getDataFromServer() {
161    // The LinearColorMap type in SciChart allows you to generate a colour map based on a
162    // minimum and maximum value, e.g. min=0, max=50 means the gradient brush below is mapped into that range
163    //
164    const colorMap: TLinearColorMap = {
165        Minimum: 0,
166        Maximum: 50,
167        Mode: EColorMapMode.Interpolated,
168        GradientStops: [
169            { color: appTheme.DarkIndigo, offset: 0 },
170            { color: appTheme.Indigo, offset: 0.2 },
171            { color: appTheme.VividSkyBlue, offset: 0.3 },
172            { color: appTheme.VividGreen, offset: 0.5 },
173            { color: appTheme.MutedRed, offset: 0.7 },
174            { color: appTheme.VividOrange, offset: 0.9 },
175            { color: appTheme.VividPink, offset: 0 },
176        ],
177    };
178
179    // Read the ASC Lidar data file with optional color map data
180    const reader: AscReader = new AscReader((height) => {
181        // Linearly interpolate each heightValue into a colour and return to the ASCReader
182        // This will be injected into the SciChart XyzDataSeries3D to colour points in the point-cloud
183        return linearColorMapLerp(colorMap, height);
184    });
185
186    // See our source-code file tq3080_DSM_2M.js for format on this ASC Point cloud data
187    // find the source online at github: https://github.com/ABTSoftware/SciChart.JS.Examples/blob/master/Examples/src/server/Data/t
188    const rawData = await fetchLidarData();
189    const ascData: AscData = reader.parse(await rawData.text());
190
191    // Prepare metadata to contain the color values from ASCData
192    const meta: TMetadata[] = ascData.ColorValues.map((c) => ({
193        vertexColor: c,
194        pointScale: 0,
195    }));
196
197    // Prepare heightValues2D for the uniform surface mesh (transform point cloud to 2d array of heights)
198    const heightValues2D = zeroArray2D([ascData.NumberRows, ascData.NumberColumns]);
199    for (let index = 0, z = 0; z < ascData.NumberRows; z++) {
200        for (let x = 0; x < ascData.NumberColumns; x++) {
201            heightValues2D[z][x] = ascData.YValues[index++];
202        }
203    }
204
205    return {
206        ascData,
207        meta,
208        heightValues2D,
209    };
210}
211

LiDAR 3D Point Cloud Demo in React

Overview

This example demonstrates a comprehensive visualization of LiDAR UAV data as a 3D point cloud using SciChart.js in a React environment. The demo visualizes a 1km x 1km slice of London with a point cloud overlaid by a contour map, and it includes a dynamic heatmap legend to indicate elevation values.

Technical Implementation

The example leverages the <SciChartReact/> component to integrate SciChart.js 3D charts into a React application, ensuring a smooth and native integration as outlined in the React Charts with SciChart.js: Introducing “SciChart React” guide. The main chart is initialized using the asynchronous function drawExample, which sets up the 3D scene with a custom camera, numeric axes, and both a point cloud (using ScatterRenderableSeries3D) and a surface mesh with contours (using SurfaceMeshRenderableSeries3D). Data is fetched asynchronously from a server, parsed using a custom AscReader for ASC formatted LiDAR data, and then integrated into the chart. Performance is further optimized by leveraging WebAssembly via the wasmContext, ensuring smooth rendering of complex 3D datasets as described in the Getting Started with SciChart JS documentation.

Features and Capabilities

The demo showcases advanced features including real-time data integration, interactive 3D manipulation with modifiers like OrbitModifier3D and MouseWheelZoomModifier3D, and dynamic color mapping implemented through a gradient palette. The heatmap legend, rendered by the additional <SciChartReact/> instance, provides visual context for the elevation data, making use of the Heatmap ColorMaps and Legends approach to dynamically map elevation values to colors.

Integration and Best Practices

Integration into React is achieved by rendering multiple <SciChartReact/> components simultaneously, which is efficient for dashboard scenarios as discussed in Efficiently Rendering Multiple Components in Your React Applications. The implementation follows best practices for asynchronous data loading and chart initialization, ensuring that data is properly fetched and parsed before rendering the charts. Developers can further customize chart interactivity and apply performance optimizations by reusing the wasmContext, a technique recommended in related performance discussions available on the SciChart Documentation pages.

This demo exemplifies how to combine asynchronous operations, advanced 3D rendering, and interactive controls in a React application, resulting in a powerful tool for scientific visualization of geospatial LiDAR data.

react Chart Examples & Demos

See Also: Scientific & Medical Charts (10 Demos)

React Vital Signs ECG/EKG Medical Demo | SciChart.js Demo

React Vital Signs ECG/EKG Medical Demo

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.

React Chart with Logarithmic Axis Example | SciChart.js

React Chart with Logarithmic Axis Example

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

React Chart with Vertically Stacked Axes | SciChart.js

React Chart with Vertically Stacked Axes

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

Realtime Audio Spectrum Analyzer Chart | SciChart.js Demo

Realtime Audio Spectrum Analyzer Chart Example

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

Realtime Audio Analyzer Bars Demo | SciChart.js Demo

Realtime Audio Analyzer Bars Demo

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

Interactive Waterfall Chart | React Charts | SciChart.js

Interactive Waterfall Spectral Chart

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

Interactive Phasor Diagram chart | React Charts | SciChart.js

Phasor Diagram Chart Example

See the React Phasor Diagram example to combine a Cartesian surface with a Polar subsurface. Get seamless React integration with SciChart. View demo now.

NEW!
React Correlation Plot | React Charts | SciChart.js Demo

React Correlation Plot

Create React Correlation Plot with high performance SciChart.js. Easily render pre-defined point types. Supports custom shapes. Get your free trial now.

NEW!
React Semiconductors Dashboard | JavaScript Charts | SciChart.js

Semiconductors Dashboard

React **Semiconductors Dashboard** using SciChart.js, by leveraging the **FastRectangleRenderableSeries**, and its `customTextureOptions` property to have a custom tiling texture fill.

NEW!
React Wafer Analysis Chart | JavaScript Charts | SciChart.js

Wafer Analysis Chart

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

SciChart Ltd, 16 Beaufort Court, Admirals Way, Docklands, London, E14 9XL.