Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

Telemetry Dashboard

LightningChart JSCreate a JavaScript Telemetry Dashboard with LightningChart JS

TutorialLearn how to create a JavaScript Telemetry dashboard for data logging

Continue Reading

JavaScript Telemetry Dashboard

Today we will do a telemetry dashboard exercise with 3 chart types that often are used for telemetry studies. All these three charts will be displayed within the same dashboard while sharing the same view at the same time.

For the telemetry dashboard, we will use a heatmap, line chart, and multichannel line chart. This board has an automatic approach in which we will simulate the temperature by the acceleration of a car on a track, and we will show data in real-time.

But before I continue, I would like to briefly explain what telemetry is. Telemetry is the real-time measurement of data from remote sources. Data is usually transmitted wirelessly using temperature sensors, vibration sensors, etc.

Telemetry is used in various sciences, from monitoring computer applications to meteorology, seismology, racing applications, etc.

In this chart, we’ll make use of the LightningChart JS library dashboard. The telemetry dashboard is a component that allows us to display more than one chart within the same view.

This component is very useful and allows us to inherit properties such as the look and feel (the theme of the dashboard). The dashboard allows you to create a grid of columns and rows and we can assign a specific area of the grid to each chart to be displayed.

If needed, the three charts used in this telemetry dashboard exercise have their own article. So, I recommend you visit the articles with a more detailed code review.

  • Data Grid Heatmap Chart
  • Race Car Telemetry Chart

So let’s start!

Project Overview

In this project, we’ll use a JavaScript race car track chart, a real-time data grid component, and a multichannel monitoring XY chart. These 3 components will be used to process real-time data from radio-controlled vehicles. 

Download the project to follow the tutorial

Telemetry Dashboard Project (.ZIP)

Template Setup

1. Download the template provided to follow the tutorial.

2. After downloading the template, you’ll see a file tree like this:

3. Open a new terminal and run the npm install command:

As usual in a NodeJS project, you need to run the npm install command. That would be everything for our initial setup. Let’s code.

CHART.ts

Inside this file, we will have all the logic needed to create our chart, configure animations, and format the data.

1. Declare the constant lcjs that will refer to our @arction/lcjs/xydata libraries.

// Import LightningChartJS
const lcjs = require('@arction/lcjs')

// Import xydata
const xydata = require('@arction/xydata'

2. Import JSON data

import speed from "./demo-data-speed.json";
import steering from "./demo-data-steering.json";
import throttle from "./demo-data-throttle.json";

3. Extract required classes from lcjs

const {
    lightningChart,
    UIElementBuilders,
    UIOrigins,
    PalettedFill,
    LUT,
    ColorRGBA,
    emptyLine,
    AxisTickStrategies,
    Themes,
    synchronizeAxisIntervals,
    AxisScrollStrategies,
    LegendBoxBuilders,
    SolidFill,
    SolidLine
} = lcjs

const { createProgressiveFunctionGenerator,createProgressiveTraceGenerator } = xydata

4. Important!

In this project, we need to work with the chart component DataGrid. This component requires a LightningChart JS License. If you don’t have a license, the data grid elements won’t display. If you have an LC JS license, you need to assign the code to the license property:

let license = undefined
try {
    license = 'XXXXXXXXXXXXXXXXXXXXXXXXXXX'
} catch (e) {}

5. Dashboard

const db = lightningChart({
    license: license,
}).Dashboard({
    theme: Themes.darkGold,
    numberOfRows: 3,
    numberOfColumns: 2,
})

The dashboard will be the container for all the charts. The dashboard method will create the component and we can assign all the rows and columns we need. Inside each zone, we can display one or more charts.

Race car chart

We’ll now create the Race Car Chart for integration into the Telemetry Dashboard. This example takes place in the field of motorsports, more specifically the analysis of gathered data from a remote-controlled racecar while driving on a race track.

Both the data and the use case in this example originate from a real user of LightningChart JS: TestLogger. They produce a complete data management and analytics system for radio-controlled cars and are one of our satisfied long-time partners.

The TestLogger software gathers an immense amount of high-precision data from an RC car in real time. For example in this telemetry dashboard, we’re visualizing the speed, steering, and throttle information from the vehicle.

Each measurement is paired with the information of the location from the track. This tells where the RC car was located at the time of the measurement (when data was recorded).

const raceChart = db
    .createChartXY({
        theme: Themes.darkGold,
        columnIndex: 0,
        rowIndex: 0,
        columnSpan: 1,
        rowSpan: 2,
    })
    .setTitle('Loading example data ...')

The race car chart is an XY chart type which means that we need to use the createChartXY property. You can assign its own theme or inherit the theme (UI) of the dashboard. As you can see, the location for this chart is in the column-row zero which is in the first zone from the top:

2. Formatting the series

const dataSources = [
   {
     name: "Speed",
     file: speed,
     lut: new LUT({
       steps: [
         { value: 0, color: ColorRGBA(255, 255, 255) },
         { value: 25, color: ColorRGBA(255, 215, 0) },
         { value: 50, color: ColorRGBA(255, 0, 0) },
       ],
       interpolate: true,
       units: "km/h",
     }),
     format: (value) => `${value.toFixed(1)} km/h`,
   },
   {
     name: "Steering",

We need to create visual properties for each data type. As we know, we have three data sources (Speed, Steering, and Throttle) and for each of them, we need to add some color and name properties to distinguish each source.

3. LUT

LUT is a style class for describing a table of colors with associated lookup values (numbers). Examples of LUT, like all LCJS style classes, are immutable. This means that its setters don’t modify the actual object but instead return a completely new modified object.

Properties of LUT

  • The steps property refers to the list of color steps (color + number value pair).
  • The interpolate property set to true enables the automatic linear interpolation between color steps.
lineSeries
     .clear()
     .setName(sourceName)
     .add(data)
     .setStrokeStyle((stroke) =>
       stroke.setFillStyle(new PalettedFill({ lut: dataSource.lut }))
     )
     .setCursorResultTableFormatter((builder, _, __, ___, dataPoint) =>
       builder
         .addRow(sourceName)
         .addRow(dataPoint.value && dataSource.format(dataPoint.value))
     );

All dataSource properties will be used in the line series. The series will get the entire JSON data and apply the LUT to all nodes.

Multichannel Monitoring Chart

Now we’ll create a Multichannel Monitoring Chart for the Telemetry Dashboard. This is an ultra-fast line chart visualization happening over multiple channels that progress on the same X-axis. This type of chart is widely used in all kinds of fields for monitoring live-streamed data from hundreds to even thousands of data sources at the same time processing billions of data points.

You can see the number of Frames per second (FPS) processed live being displayed on the Chart title. For reference, an FPS of 40-60 indicates a smooth running performance.

To create a monitor chart, we need to use the chart XY type. The creation process is the same as the previous chart but the only difference is its location in the dashboard.

const monitorChart = db
.createChartXY({
    columnIndex: 0,
    rowIndex: 2,
    columnSpan: 2,
})

1. Adding the series for each channel

const series = new Array(CHANNELS_AMOUNT).fill(0).map((_, iChannel) => {
    // Create line series optimized for regular progressive X data.
    const nSeries = monitorChart
        .addLineSeries({
            dataPattern: {
                // pattern: 'ProgressiveX' => Each consecutive data point has increased X coordinate.
                pattern: 'ProgressiveX',
                // regularProgressiveStep: true => The X step between each consecutive data point is regular (for example, always `1.0`).
                regularProgressiveStep: true,
            },
        })
        .setName(`Channel ${iChannel + 1}`)
        // Use -1 thickness for best performance, especially on low end devices like mobile / laptops.
        .setStrokeStyle((style) => style.setThickness(-1))
        .setMouseInteractions(false)
        // Enable automatic data cleaning.
        .setDataCleaning({ minDataPointCount: xIntervalMax })
This loop will create a line series for each channel we specified in the CHANNELS_AMOUNT variable.

2. Define the unique signals that will be used for channels

const signals = [
    { length: 100 * 2 * Math.PI, func: (x) => Math.sin(x / 100) },
    { length: 100 * 2 * Math.PI, func: (x) => Math.cos(x / 100) },
    {
        length: 200 * 2 * Math.PI,
        func: (x) => Math.cos(x / 200) + Math.sin(x / 100),
    },
    {
        length: 200 * 2 * Math.PI,
        func: (x) => Math.sin(x / 50) + Math.cos(x / 200),
    },
    {
        length: 200 * 2 * Math.PI,
        func: (x) => Math.sin(x / 100) * Math.cos(x / 200),
    },
    { length: 450 * 2 * Math.PI, func: (x) => Math.cos(x / 450) },
    { length: 800 * 2 * Math.PI, func: (x) => Math.sin(x / 800) },
    {
        length: 650 * 2 * Math.PI,
        func: (x) => Math.sin(x / 200) * Math.cos(x / 650),
    },
]

3. Adding data points to each signal

The following code is just random data created from initial values. Each data series needs data points and in this case, the code will create data points for each signal channel and add them to each data series.

for (let iChannel = 0; iChannel  series.add(seriesNewDataPoints[iChannel]))

Monitoring Heatmap Chart

This heatmap monitoring chart will be the third and last component added to the Telemetry Dashboard. This application simulates real-time data coming in at high speed. Data are then displayed both in a scrolling line chart and within a DataGrid.

This example highlights the use of the DataGrid component text and background coloring capabilities to highlight the meaning of the data. For example, the red color indicates a negative value.

Of course, this is helpful for end-users as the human eye may have difficulties perceiving the meaning of trends within datasets. Similarly, brightly-colored indicators can be faster and easier to understand and of course, the use of colors is always customizable.

1. Adding the chart to the dashboard

const heatmapChart = db
    .createChartXY({
        theme: Themes.darkGold,
        columnIndex: 1,
        rowIndex: 0,
    }).setTitle('Real-Time Chart + DataGrid')

2. Adding the trends (Line Series)

Here the exampleDataCount will define the limit of data points within the chart.

const exampleTrends = [
        {
            name: 'Trend #1',
        },
        {
            name: 'Trend #2',
        },
        {
            name: 'Trend #3',
        },
    ]
    const exampleTrendsCount = exampleTrends.length
    const exampleDataCount = 10000

3. Adding a series for each trend

We’ll add a progressive series for each trend. The progressive X series type will be like a “scrolling-horizontal” series.

const seriesXYList = exampleTrends.map((trend) =>
heatmapChart
        .addLineSeries({ dataPattern: { pattern: 'ProgressiveX' } })
        .setDataCleaning({ minDataPointCount: 1 })
        .setName(trend.name),
)

4. Creating data

new Array(exampleTrendsCount).fill(0).map((_) =>
        createProgressiveTraceGenerator()
            .setNumberOfPoints(exampleDataCount)
            .generate()
            .toPromise()
            .then((data) => data.map((xy) => 100 + xy.y)),
    ),

To create and refresh the values, we can use the createProgressiveTraceGenerator method (included in the XY data library). The generator creates random data with a progressive X-axis and a random Y-axis.

A progressive trace data generator generates data points that have a progressive X-axis. Notice that the data are always derived from the previous point.

const streamOneSample = (sample, isFirst) => {
        const tNow = Date.now()

        seriesXYList.forEach((series, iTrend) => series.add({ x: tNow - tStart, y: sample[iTrend] }))

        if (isFirst) {
            trendsHistory.forEach((trendHistory, iTrend) => {
                trendHistory.previous15s = sample[iTrend]
            })
            setInterval(() => {
                trendsHistory.forEach((trendHistory, iTrend) => {
                    trendHistory.previous15s = trendHistory.previous
                })
                indicator15s.setValue(Date.now() - tStart)
            }, 1000 * 15)
        }

Each point that was generated will be added to the series-trend and an interval will be drawn using the previous value as a join line. The obtained values will help to give format to the grid:

sample.forEach((value, iTrend) => {
            const trendHistory = trendsHistory[iTrend]
            const current = value
            const previous = trendHistory.previous
            const previous15s = trendHistory.previous15s
            dataGrid
                // Current
                .setCellContent(1, iTrend + 1, `${current.toFixed(1)}`)
                .setCellTextFillStyle(1, iTrend + 1, current > previous ? textFillGood : textFillBad)
                .setCellBackgroundFillStyle(1, iTrend + 1, current > previous ? bgFillGood : bgFillBad)
                // Previous
                .setCellContent(2, iTrend + 1, `${previous.toFixed(1)}`)
                .setCellTextFillStyle(2, iTrend + 1, previous > previous15s ? textFillGood : textFillBad)
                .setCellBackgroundFillStyle(2, iTrend + 1, previous > previous15s ? bgFillGood : bgFillBad)
                // Previous 15 s
                .setCellContent(3, iTrend + 1, `${previous15s.toFixed(1)}`)

If the current sample is larger than the previous one, the grid will be green, if not it will be red. The same logic applies to the previous samples.

Final Telemetry Dashboard

Finally, to run the telemetry dashboard in your browser, open a new terminal and run the npm start command. This will retrieve you a local path where the project is running, usually something like http://localhost:8080/, CTRL + click to visualize.

This was a quick tutorial on how to create a telemetry dashboard with LightningChart JS. In practice, this is a powerful application capable of processing live-streamed data from multiple sources. For instance, via sensors connected to machinery and feeding the components in real-time.

You can fully customize the dashboard with different components available from the LC JS library. See you in the next article!

Start your 30-day free trial

Omar Urbano

Software Engineer

Continue learning with LightningChart

TutorialCreate a JavaScript Pie Chart with NodeJS, TypeScript, and LightningChart JS

TutorialDevelop a cross-platform medical electrocardiogram (ECG) application

The post Telemetry Dashboard appeared first on LightningChart.



This post first appeared on Arction Ltd - Webgl Charts Library, please read the originial post: here

Share the post

Telemetry Dashboard

×

Subscribe to Arction Ltd - Webgl Charts Library

Get updates delivered right to your inbox!

Thank you for your subscription

×