SciChart.js JavaScript 2D Charts API > 2D Chart Types > The Uniform Heatmap Chart Type > Heatmap ColorMaps and Legends
Heatmap ColorMaps and Legends

Converting Data-Values to Colors (Defining a Color Map)

Conversion of data value into color is defined by the property UniformHeatmapRenderableSeries.colorMap. The ColorMap is type HeatmapColorPalette. You can define a custom Color Palette in JavaScript as follows:

// Create a Heatmap RenderableSeries with the color map. ColorMap.minimum/maximum defines the values in
// HeatmapDataSeries which correspond to gradient stops at 0..1
const heatmapSeries = new UniformHeatmapRenderableSeries(wasmContext, {
  dataSeries: heatmapDataSeries,
  useLinearTextureFiltering: false,
  fillValuesOutOfRange: true,
  colorMap: new HeatmapColorMap({
    minimum: 0,
    maximum: 200,
    gradientStops: [
      { offset: 1, color: "#EC0F6C" },
      { offset: 0.9, color: "#F48420" },
      { offset: 0.7, color: "#DC7969" },
      { offset: 0.5, color: "#67BDAF" },
      { offset: 0.3, color: "#50C7E0" },
      { offset: 0.2, color: "#264B9377" }, // Start to fade out the transparency here
      { offset: 0, color: "Transparent" }, // Set the zero value as Transparent. Corresponds to zValue <= minimum
    ]
  })
});

sciChartSurface.renderableSeries.add(heatmapSeries);

What this means:

  • The GradientStop at Offset = 0 with Color = "Transparent" corresponds to the HeatmapColorMap.minimum value of 0
  • The GradientStop at Offset = 1 with Color = "#EC0F6C" corresponds to HeatmapColorMap.maximum value of 200.
  • Data within this range will be blended according to the gradient stops between 0 and 1
  • Data outside this range will be clamped to the minimum or maximum colors in the HeatmapColorMap

Defining how Data-values outside of ColorMap range are drawn

By default when defining a HeatmapColorMap any values that fall outside the range are clipped to the edges of the colormap. e.g. in the above example data falling outside of the range 0-200 is clipped to color "#000000" and "#EC0F6C" respectively.

There is also a fillValuesOutOfRange property which defines how the values outside the range are treated. Either clamped to the min/max color or drawn as transparent.

Heatmap Legends

A heatmap legend may be generated with the HeatmapLegend class. It is placed in a element just like a SciChartSurface. It will expand to fit the parent div.

<div class="chartContainer">
    <div id="scichart-root" ></div>
    <div id="legend-root" style="position: absolute;"></div>
</div>

  
body { margin: 0; }

.chartContainer { width: 100%; height: 100vh; position: relative; }

#scichart-root { width: 100%; height: 100%; }

#legend-root {
    position: absolute;
    height: 90%;
    width: 100px;
    top: 0;
    right: 75px;
    margin: 20px
}

  
// This function generates data for the heatmap series example
function generateExampleData(
    width,
    height,
    cpMax,
    index,
    maxIndex
) {
  const { zeroArray2D } = SciChart;
  // or, import { zeroArray2D } from "SciChart";

  // Returns a 2-dimensional javascript array [height (y)] [width (x)] size
  const zValues = zeroArray2D([height, width]);

  const angle = (Math.PI * 2 * index) / maxIndex;

  // When appending data to a 2D Array for the heatmap, the order of appending (X,Y) does not matter
  // but when accessing the zValues[][] array, we set data [y] then [x]
  for (let y = 0; y < height; y++) {
    for (let x = 0; x < width; x++) {
      const v =
          (1 + (Math.sin(x * 0.02 + angle))) * 50 +
          (1 + (Math.sin(y * 0.05 + angle))) * 50 * (1 + (Math.sin(angle * 2)));
      const cx = width / 2;
      const cy = height / 2;
      const r = Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy));
      const exp = Math.max(0, 1 - r * 0.008);
      const zValue = v * exp + Math.random() * 10;
      zValues[y][x] = zValue > cpMax ? cpMax : zValue;
    }
  }
  return zValues;
}

async function heatmapColorMaps(divElementId) {
  // Demonstrates how to create a uniform heatmap chart with SciChart.js
  const {
    SciChartSurface,
    NumericAxis,
    HeatmapColorMap,
    UniformHeatmapDataSeries,
    UniformHeatmapRenderableSeries,
    SciChartJsNavyTheme,
    NumberRange
  } = SciChart;

  // or, for npm, import { SciChartSurface, ... } from "scichart"

  // Create a SciChartSurface with X & Y Axis
  const { wasmContext, sciChartSurface } = await SciChartSurface.create(divElementId, {
    theme: new SciChartJsNavyTheme()
  });
  sciChartSurface.xAxes.add(new NumericAxis(wasmContext, { visibleRange: new NumberRange(150, 350) }));
  sciChartSurface.yAxes.add(new NumericAxis(wasmContext, { visibleRange: new NumberRange(80, 200) }));

  const WIDTH = 500;
  const HEIGHT = 300;
  const MAX_SERIES = 200;
  let index = 20;

  // Create a Heatmap Data-series. Pass heatValues as a number[][] to the UniformHeatmapDataSeries
  // Open the Codepen below to see the definition of this function
  const initialZValues = generateExampleData(WIDTH, HEIGHT, 200, index, MAX_SERIES);
  const heatmapDataSeries = new UniformHeatmapDataSeries(wasmContext, {
    xStart: 0,
    xStep: 1,
    yStart: 0,
    yStep: 1,
    zValues: initialZValues
  });

  // #region ExampleA
  // Create a Heatmap RenderableSeries with the color map. ColorMap.minimum/maximum defines the values in
  // HeatmapDataSeries which correspond to gradient stops at 0..1
  const heatmapSeries = new UniformHeatmapRenderableSeries(wasmContext, {
    dataSeries: heatmapDataSeries,
    useLinearTextureFiltering: false,
    fillValuesOutOfRange: true,
    colorMap: new HeatmapColorMap({
      minimum: 0,
      maximum: 200,
      gradientStops: [
        { offset: 1, color: "#EC0F6C" },
        { offset: 0.9, color: "#F48420" },
        { offset: 0.7, color: "#DC7969" },
        { offset: 0.5, color: "#67BDAF" },
        { offset: 0.3, color: "#50C7E0" },
        { offset: 0.2, color: "#264B9377" }, // Start to fade out the transparency here
        { offset: 0, color: "Transparent" }, // Set the zero value as Transparent. Corresponds to zValue <= minimum
      ]
    })
  });

  sciChartSurface.renderableSeries.add(heatmapSeries);
  // #endregion

  // Add zooming, panning for the example
  const { ZoomPanModifier, ZoomExtentsModifier, MouseWheelZoomModifier } = SciChart;
  sciChartSurface.chartModifiers.add(new ZoomPanModifier(), new ZoomExtentsModifier(), new MouseWheelZoomModifier());

};

heatmapColorMaps("scichart-root");

async function heatmapLegend(divElementId) {
  // #region ExampleB
  const { HeatmapLegend, SciChartJsNavyTheme } = SciChart;
  const { heatmapLegend, wasmContext } = await HeatmapLegend.create(divElementId, {
    theme: {
      ...new SciChartJsNavyTheme(),
      sciChartBackground: "#14233CBB",
      loadingAnimationBackground: "#14233CBB",
    },
    yAxisOptions: {
      axisBorder: {
        borderLeft: 1,
        color: "#FFFFFF77"
      },
      majorTickLineStyle: {
        color: "White",
        tickSize: 6,
        strokeThickness: 1
      },
      minorTickLineStyle: {
        color: "White",
        tickSize: 3,
        strokeThickness: 1
      }
    },
    colorMap: {
      minimum: 0,
      maximum: 200,
      gradientStops: [
        { offset: 1, color: "#EC0F6C" },
        { offset: 0.9, color: "#F48420" },
        { offset: 0.7, color: "#DC7969" },
        { offset: 0.5, color: "#67BDAF" },
        { offset: 0.3, color: "#50C7E0" },
        { offset: 0.2, color: "#264B9377" }, // Start to fade out the transparency here
        { offset: 0, color: "Transparent" }, // Set the zero value as Transparent. Corresponds to zValue <= minimum
      ]
    }
  });
  // #endregion
}

heatmapLegend("legend-root");



  

The constructor accepts IHeatmapLegendOptions which lets you specify theme, colorMap and yAxisOptions. This allows configuration of the appearance of the heatmap legend. See these are the TypeDoc documentation for this type. 

Here's a full code sample below.

const { HeatmapLegend, SciChartJsNavyTheme } = SciChart;
const { heatmapLegend, wasmContext } = await HeatmapLegend.create(divElementId, {
  theme: {
    ...new SciChartJsNavyTheme(),
    sciChartBackground: "#14233CBB",
    loadingAnimationBackground: "#14233CBB",
  },
  yAxisOptions: {
    axisBorder: {
      borderLeft: 1,
      color: "#FFFFFF77"
    },
    majorTickLineStyle: {
      color: "White",
      tickSize: 6,
      strokeThickness: 1
    },
    minorTickLineStyle: {
      color: "White",
      tickSize: 3,
      strokeThickness: 1
    }
  },
  colorMap: {
    minimum: 0,
    maximum: 200,
    gradientStops: [
      { offset: 1, color: "#EC0F6C" },
      { offset: 0.9, color: "#F48420" },
      { offset: 0.7, color: "#DC7969" },
      { offset: 0.5, color: "#67BDAF" },
      { offset: 0.3, color: "#50C7E0" },
      { offset: 0.2, color: "#264B9377" }, // Start to fade out the transparency here
      { offset: 0, color: "Transparent" }, // Set the zero value as Transparent. Corresponds to zValue <= minimum
    ]
  }
});

Defining the ColorMap on the HeatmapLegend control 

ColorMaps obey similar rules to Heatmap series (see above).

Styling the Axis on the HeatmapLegend control

yAxisOptions is type IAxisBase2dOptions. This is the same type that is passed to an Axis in SciChart.

To Style the HeatmapLegend is very similar to styling an axis in SciChart. See more at the page Axis Styling.

Updating ColorMaps Dynamically

HeatmapColorMaps can be updated dynamically by changing their properties. All the properties such as minimum, maximum, gradientStops are fully reactive and when set, the chart will redraw.

Below we've created a demo to show how to update HeatmapColorMap.gradientStops dynamically by adding interactivity to the HeatmapLegend.

// .. Assuming SciChartSurface, UniformHeatmapDataSeries already created
//

// Create a colormap
const colorMap = new HeatmapColorMap({
  minimum: 0,
  maximum: 200,
  gradientStops: [
    { offset: 1, color: "#EC0F6C" },
    { offset: 0.9, color: "#F48420" },
    { offset: 0.7, color: "#DC7969" },
    { offset: 0.5, color: "#67BDAF" },
    { offset: 0.3, color: "#50C7E0" },
    { offset: 0.2, color: "#264B9377" },
    { offset: 0, color: "Transparent" },
  ]
});

// Create a Heatmap RenderableSeries with the color map
sciChartSurface.renderableSeries.add(new UniformHeatmapRenderableSeries(wasmContext, {
  dataSeries: heatmapDataSeries,
  useLinearTextureFiltering: false,
  fillValuesOutOfRange: true,
  colorMap
}));

// Create the heatmapLegend with the same colorMap
const { heatmapLegend, wasmContext2 } = await HeatmapLegend.create(divElementIdLegend, {
  theme: {
    ...new SciChartJsNavyTheme(),
    sciChartBackground: "#14233CBB",
    loadingAnimationBackground: "#14233CBB",
  },
  colorMap
});

// The HeatmapLegend is implemented using a SciChartSurface, You can access the inner chart
const legendSciChartSurface = heatmapLegend.innerSciChartSurface.sciChartSurface;

// Create an AxisMarkerAnnotation and subscribe to onDrag
const axisAnnotation = new AxisMarkerAnnotation({
  y1: colorMap.maximum * 0.9,
  isEditable: true,
  onDrag: (args) => {

    // First step: prevent dragging outside the min/max
    if (axisAnnotation.y1 > 200) axisAnnotation.y1 = 200;
    if (axisAnnotation.y1 < 0) axisAnnotation.y1 = 0;

    // On-drag, update the gradient stops and re-assign. The Chart automatically redraws
    const gradientStops = [
      { offset: 1, color: "#EC0F6C" },
      { offset: axisAnnotation.y1 / 200, color: "#F48420" },
      { offset: 0.7, color: "#DC7969" },
      { offset: 0.5, color: "#67BDAF" },
      { offset: 0.3, color: "#50C7E0" },
      { offset: 0.2, color: "#264B9377" },
      { offset: 0, color: "Transparent" },
    ];
    colorMap.gradientStops = gradientStops;
  }
});

// Add it to the legend's SciChartSurface
legendSciChartSurface.annotations.add(axisAnnotation);

This results in the following output:

<div class="chartContainer">
    <div id="scichart-root" ></div>
    <div id="legend-root" style="position: absolute;"></div>
</div>

  
body { margin: 0; }

.chartContainer { width: 100%; height: 100vh; position: relative; }

#scichart-root { width: 100%; height: 100%; }

#legend-root {
    position: absolute;
    height: 90%;
    width: 100px;
    top: 0;
    right: 75px;
    margin: 20px
}

  
// This function generates data for the heatmap series example
function generateExampleData(
    width,
    height,
    cpMax,
    index,
    maxIndex
) {
  const { zeroArray2D } = SciChart;
  // or, import { zeroArray2D } from "SciChart";

  // Returns a 2-dimensional javascript array [height (y)] [width (x)] size
  const zValues = zeroArray2D([height, width]);

  const angle = (Math.PI * 2 * index) / maxIndex;

  // When appending data to a 2D Array for the heatmap, the order of appending (X,Y) does not matter
  // but when accessing the zValues[][] array, we set data [y] then [x]
  for (let y = 0; y < height; y++) {
    for (let x = 0; x < width; x++) {
      const v =
          (1 + (Math.sin(x * 0.02 + angle))) * 50 +
          (1 + (Math.sin(y * 0.05 + angle))) * 50 * (1 + (Math.sin(angle * 2)));
      const cx = width / 2;
      const cy = height / 2;
      const r = Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy));
      const exp = Math.max(0, 1 - r * 0.008);
      const zValue = v * exp + Math.random() * 10;
      zValues[y][x] = zValue > cpMax ? cpMax : zValue;
    }
  }
  return zValues;
}

async function dynamicColorMaps(divElementIdChart, divElementIdLegend) {
  // Demonstrates how to create a uniform heatmap chart with dynamic colormap using SciChart.js
  const {
    SciChartSurface,
    NumericAxis,
    HeatmapColorMap,
    UniformHeatmapDataSeries,
    UniformHeatmapRenderableSeries,
    SciChartJsNavyTheme,
    NumberRange,
    HeatmapLegend,
    AxisMarkerAnnotation,
    TextAnnotation,
    BoxAnnotation,
    ECoordinateMode,
    EHorizontalAnchorPoint,
    EVerticalAnchorPoint
  } = SciChart;

  // or, for npm, import { SciChartSurface, ... } from "scichart"

  const addChartTitle = (sciChartSurface, titleText, subTitleText) => {
    sciChartSurface.annotations.add(new BoxAnnotation({
      x1: 0, x2: 1,
      y1: 0, y2: 0.18,
      fill: "#14233C77",
      strokeThickness: 0,
      xCoordinateMode: ECoordinateMode.Relative, yCoordinateMode: ECoordinateMode.Relative,
    }));
    // Note: we will be improving titles shortly in scichart.js v3.1
    sciChartSurface.annotations.add(new TextAnnotation({
      text: titleText,
      x1: 0.5, y1: 0,
      yCoordShift: 10,
      xCoordinateMode: ECoordinateMode.Relative, yCoordinateMode: ECoordinateMode.Relative,
      horizontalAnchorPoint: EHorizontalAnchorPoint.Center, verticalAnchorPoint: EVerticalAnchorPoint.Top,
      opacity: 0.77,
      fontSize: 28,
      fontWeight: "Bold",
      textColor: "White",
    }));
    sciChartSurface.annotations.add(new TextAnnotation({
      text: subTitleText,
      x1: 0.5, y1: 0,
      yCoordShift: 50,
      xCoordinateMode: ECoordinateMode.Relative, yCoordinateMode: ECoordinateMode.Relative,
      horizontalAnchorPoint: EHorizontalAnchorPoint.Center, verticalAnchorPoint: EVerticalAnchorPoint.Top,
      opacity: 0.77,
      fontSize: 14,
      textColor: "White",
    }));
  };

  // Create a SciChartSurface with X & Y Axis
  const { wasmContext, sciChartSurface } = await SciChartSurface.create(divElementIdChart, {
    theme: new SciChartJsNavyTheme()
  });
  sciChartSurface.xAxes.add(new NumericAxis(wasmContext, { visibleRange: new NumberRange(150, 350) }));
  sciChartSurface.yAxes.add(new NumericAxis(wasmContext, { visibleRange: new NumberRange(80, 200) }));

  addChartTitle(sciChartSurface, "Dynamic ColorMaps", "Drag the Axis Marker on the legend to update the HeatmapColorMap");

  const WIDTH = 500;
  const HEIGHT = 300;
  const MAX_SERIES = 200;
  let index = 20;

  // Create a Heatmap Data-series. Pass heatValues as a number[][] to the UniformHeatmapDataSeries
  const initialZValues = generateExampleData(WIDTH, HEIGHT, 200, index, MAX_SERIES);
  const heatmapDataSeries = new UniformHeatmapDataSeries(wasmContext, {
    xStart: 0,
    xStep: 1,
    yStart: 0,
    yStep: 1,
    zValues: initialZValues
  });

  // #region ExampleA
  // .. Assuming SciChartSurface, UniformHeatmapDataSeries already created
  //

  // Create a colormap
  const colorMap = new HeatmapColorMap({
    minimum: 0,
    maximum: 200,
    gradientStops: [
      { offset: 1, color: "#EC0F6C" },
      { offset: 0.9, color: "#F48420" },
      { offset: 0.7, color: "#DC7969" },
      { offset: 0.5, color: "#67BDAF" },
      { offset: 0.3, color: "#50C7E0" },
      { offset: 0.2, color: "#264B9377" },
      { offset: 0, color: "Transparent" },
    ]
  });

  // Create a Heatmap RenderableSeries with the color map
  sciChartSurface.renderableSeries.add(new UniformHeatmapRenderableSeries(wasmContext, {
    dataSeries: heatmapDataSeries,
    useLinearTextureFiltering: false,
    fillValuesOutOfRange: true,
    colorMap
  }));

  // Create the heatmapLegend with the same colorMap
  const { heatmapLegend, wasmContext2 } = await HeatmapLegend.create(divElementIdLegend, {
    theme: {
      ...new SciChartJsNavyTheme(),
      sciChartBackground: "#14233CBB",
      loadingAnimationBackground: "#14233CBB",
    },
    colorMap
  });

  // The HeatmapLegend is implemented using a SciChartSurface, You can access the inner chart
  const legendSciChartSurface = heatmapLegend.innerSciChartSurface.sciChartSurface;

  // Create an AxisMarkerAnnotation and subscribe to onDrag
  const axisAnnotation = new AxisMarkerAnnotation({
    y1: colorMap.maximum * 0.9,
    isEditable: true,
    onDrag: (args) => {

      // First step: prevent dragging outside the min/max
      if (axisAnnotation.y1 > 200) axisAnnotation.y1 = 200;
      if (axisAnnotation.y1 < 0) axisAnnotation.y1 = 0;

      // On-drag, update the gradient stops and re-assign. The Chart automatically redraws
      const gradientStops = [
        { offset: 1, color: "#EC0F6C" },
        { offset: axisAnnotation.y1 / 200, color: "#F48420" },
        { offset: 0.7, color: "#DC7969" },
        { offset: 0.5, color: "#67BDAF" },
        { offset: 0.3, color: "#50C7E0" },
        { offset: 0.2, color: "#264B9377" },
        { offset: 0, color: "Transparent" },
      ];
      colorMap.gradientStops = gradientStops;
    }
  });

  // Add it to the legend's SciChartSurface
  legendSciChartSurface.annotations.add(axisAnnotation);
  // #endregion
};

dynamicColorMaps("scichart-root", "legend-root");


  
The HeatmapLegend is implemented internally using a SciChartSurface. You can access the surface via the innerSciChartSurface property. After that, you can configure the axis, series, annotations just like you would any other SciChartSurface.