Creating a Stacked Mountain Chart (JS)
Tags: javascript, datascience, chartinglibrary, data
Published: 2024-04-10 10:49:58

In data visualization, stacked mountain charts are used to demonstrate how variables develop where each is **stacked** on top of the other.

In today's article, we will create a Stacked Mountain chart in JavaScript that uses NodeJS + [LightningChart JS library](https://lightningchart.com/js-charts/).

The stacked area chart has another characteristic, it represents data as percentages, considering the highest value of the series (or series) as a reference of the 100%. The rest of the data will be stacked according to its percentage level with respect to the reference.

The chart will also be filled from the plot line to the upper level, with a limit of 100% (the _reference_). This is how the 100% stacked area chart can look fully plotted from the X-axis to the Y-axis.

##Project
To get started, consider that the stacked mountains chart works better for visualizing large datasets and representing them as a percentage.

However, if you need to present several data series, this chart type may be best to display only a handful of series, e.g., the most important categories of your dataset.

**This chart can be edited online too**

[![stacked-mountain-chart-editor](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nafttjg4qqufi9q6xbes.jpg)](https://lightningchart.com/js-charts/interactive-examples/edit/lcjs-example-0104-stackedMountains.html?disable-animations=1&isList=true)

##Template Setup
To initialize the project, let's set up a working template and follow along the tutorial. You'll see a file tree like this one:

![stacked-mountain-chart-file-tree](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4x4pwczljt0qed0xyxkz.jpg)

Then open a new terminal and as usual in a Node JS project, run the NPM Install command. That'd be it, let's code. <br>

##Creating the chart
Today the most recent versions are [LightningChart JS 5.1.0](https://www.npmjs.com/package/@arction/lcjs?activeTab=versions) and [XYData 1.4.0](https://www.npmjs.com/package/@arction/xydata?activeTab=versions). I recommend that you review the most recent versions and update them. This is because some LightningChart JS tools do not exist in previous versions.

In the project’s package.json file you can find the LightningChart JS dependencies:

```javascript
"dependencies": {
"@arction/lcjs": "^5.1.0",
"@arction/xydata": "^1.4.0",
"webgl-obj-loader": "^2.0.8",
}
```
1) Importing libraries
We will start by importing the necessary libraries to create our chart.

```javascript
const lcjs = require('@arction/lcjs')
import data from './data.json'

// Extract required parts from LightningChartJS.
const { lightningChart, AxisTickStrategies, AutoCursorModes, Themes } = lcjs
```
2) Add license key (free)
Once the LightningChart JS libraries are installed, we will import them into our chart.ts file. Note you will need a [trial license](https://lightningchart.com/js-charts/free-trial/), which is free. We would then add it to a variable that will be used for creating the chart object.

3) Properties

```javascript
// Create a XY Chart.
const xyChart = lightningChart({license: license})
    .ChartXY({
        theme: Themes.cyberSpace,
    })
```

– [Theme](https://lightningchart.com/js-charts/api-documentation/v5.1.1/interfaces/Themes.html): defines the look and feel of your JavaScript stacked bar chart. Note that you must specify the color theme of the chart components beforehand.

– [setTitle](https://lightningchart.com/js-charts/api-documentation/v5.1.1/classes/Chart.html#setTitle): Sets the name at the top of the chart.

![stacked-mountain-chart-setTitle](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/31soe0wcxklnqdv6bpcm.png)

## Setting up axes
```javascript
xyChart.getDefaultAxisX()
    .setTickStrategy(AxisTickStrategies.DateTime)
    .setInterval({
        start: new Date(2017, 0, 1).getTime(),
        end: new Date(2018, 3, 1).getTime()
    })
    .setMouseInteractions(false)
```

The `getDefaultAxes` function allows us to access all the axes of the object. For each axis, we can apply the same properties, or if we need specific properties for each one, we can access each of them by using `Chart3D.getDefaultAxisX()`, `Chart3D.getDefaultAxisY()`, `Chart3D.getDefaultAxisZ()`.

The `setTickStrategy` function defines the positioning and formatting logic of Axis ticks and the style of created ticks. In this case, we use the `DateTime` format for our axes. In the styles collection, we can use number, time, time, and date or void.

`setInterval` sets the axis scale interval. Intervals are number type, for that reason, we are using the `getTime()`  function. This transforms the date object to a number (milliseconds).
• start: (Number) Start scale value.
• end: (Number) End scale value.

`SetMouseInteractions` sets if mouse and cursor interactions should be disabled during zooming animations for the chart's series.

## Adding the series

```javascript
// ---- Add multiple series with different names and values. ----
const versionName = [
    'Version 1',
    'Version 2',
    'Version 3',
    'Version 4',
    'Version 5',
    'Version 6',
    'Version 7',
    'Version 8',
    'Version 9',
    'Version 10',
    'Version 11',
    'Version 12',
]
// Array to store the created Area Series.
const version = []
// Create a Series for each version name.
versionName.forEach((v, k) => {
    // The first version (data) is drawn at the bottom of the chart, so we can just use an Area Series to render it.
    if (k == 0) {
        version[k] = xyChart.addAreaSeries().setName(v)
    } else {
        //The rest of the versions (data) are drawn based on the version before, so we'll use Area Range Series to render it.
        version[k] = xyChart.addAreaRangeSeries().setName(v)
    }
    // Set up how to display the Result Table.
    version[k].setCursorResultTableFormatter((builder, series, xValue, yValueHigh, yValueLow) => {
        return builder
            .addRow(v)
            .addRow('Date: ' + series.axisX.formatValue(xValue))
            .addRow('Distribution: ' + (yValueHigh - yValueLow).toFixed(2) + '%')
    })
})
```
Now we need to create a series for each version. All the versions are stored in the `versionName` array object. The `addAreaSeries` method adds a new `AreaSeries` to the chart.

This series type visualizes areas between a static baseline and supplied curve data. Note that the `AreaSeries` is optimized for handling large amounts of data.

The `addAreaRangeSeries` method adds a new `AreaRangeSeries` to the chart. This series type is used for visualizing bands of data between two curves of data.

## Creating cursor result tables
The result cursor tables are the boxes that appear above the cursor when we position it on a coordinate of the chart. These tables can contain a specific format.

![stacked-mountain-chart-cursorResultsTable](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5iwr7u12sl7v2bbzvylw.jpg)

```javascript
version[k].setCursorResultTableFormatter((builder, series, xValue, yValueHigh, yValueLow) => {
        return builder
            .addRow(v)
            .addRow('Date: ' + series.axisX.formatValue(xValue))
            .addRow('Distribution: ' + (yValueHigh - yValueLow).toFixed(2) + '%')
    })
```
- [setCursorResultTableFormatter](https://lightningchart.com/js-charts/api-documentation/v5.1.1/classes/LineSeries.html#setCursorResultTableFormatter): This property configures the format of the `CursorResultTable` when pointing at this series (on-hover). The result table will be shown as a popup with the values that we want to show. Each line is generated as a row (`.addrow`), and we can format it freely.

## Setting up data points

```javascript
data[0].forEach((point, i) => {
    version.forEach((series, index) => {
        // For the first series, only one Y value is needed.
        if (index == 0) {
            version[index].add({
                x: point.x,
                y: point.y,
            })
            // Rest of the series need both the High and Low values;
            // Low is the previous Series' High value.
        } else {
            version[index].add({
                position: point.x,
                high: getYHigh(index, i),
                low: getYLow(index, i),
            })
        }
    })
```

For each data point we have in the JSON file, we will have a process to configure the values of this point in each version series. For the first version, we don’t need the high and low values. For the rest of the versions, we need to get the previous and next values (Low-High). This will help us stack each version on top of each other.

## Conclusion
Finally, execute the `npm start` command to run the chart and open the localhost path to visualize the application on your browser.

This chart is a tool that stacks each group on a percentage basis to the total, making a relative contribution so that its limit is 100%. This allows us to observe how each group of values participates in our dataset analysis.

Visually, it allows us to understand the importance of each category within the dataset. Perhaps it is not as complex as other chart types we have seen, but its objective is just the opposite, it tries to show us categories and their relevance in the analysis.

On the LightningChart JS side, we used once more an XY object, accessed the axes, configured, and added the series to the chart. The most complex part was configuring the values obtained from the JSON. [LightningChart JS](https://lightningchart.com/js-charts/) makes it easy to implement each chart type. Thanks!

---

**Written by:**
Omar Urbano | Software Engineer & Technical Writer
[Send me your questions via LinkedIn](https://www.linkedin.com/in/omarurbanocuellar/)