How to create custom continuous and discrete colorscales with Plotly.js

·

4 min read

Recently I've been looking at bathymetric survey maps at work and creating different types of charts using Plotly.js. One requirement I had was to use a previously defined colour scale for all of the Plotly outputs. This article will step through creating a custom continuous and discrete colour scale from a predefined legend. The image below will show the finished results that will be achieved.

An example of a previously defined colour scale can be viewed from this example bathymetric survey map. Below I've taken a part of the elevation legend from the map as we'll be looking to build a custom colour scale based off of this data. The elevations legend shows a minimum and maximum elevation given in feet and the colour which should represent a data point in this range.

Following the Plotly.js scatter colorscale reference we'll start by creating a normalised colour scale with the data above. I'll use just a portion of the legend and create a colour scale for depths 0 to -13.5 feet. We'll have to normalise the last nine entries in the legend to achieve this scale. Starting with a continuous colour scale, we'll want to create equal steps to normalise our colours between 0 and 1. 0 will be the lowest point of the colour scale and 1 the highest. To find the number we'll need to increment by you can use the formula

$$1/(n-1)$$

Where n above is the number of entries in the scale.

$$1/(9 - 1) = 0.125$$

Colours will be found by painfully using a colour picker on the pdf. I'm using Digital Colour Meter on my macbook.


[
    [0, 'rgb(253, 180, 7)'], // -13.5 -> -12.0 feet
    [0.125, 'rgb(255, 217, 109)'], // -12.0 -> -10.5 feet
    [0.25, 'rgb(253, 180, 7)'], // -10.5 -> -9.0 feet
    [0.375, 'rgb(253, 178, 109)'], // -9.0 -> -7.5 feet
    [0.5, 'rgb(253, 105, 9)'], // -7.5 -> 6.0 feet
    [0.625, 'rgb(254, 140, 108)'], // -6.0 -> -4.5 feet
    [0.75, 'rgb(252, 38, 9)'], // -4.5 -> -3.0 feet
    [0.875, 'rgb(253, 103, 109)'], // -3.0 -> -1.5 feet
    [1, 'rgb(251, 0, 5)'], // -1.5 -> 0 feet
]

Creating a discrete colour scale requires a slightly different configuration. The scale will include "pairs" of colours, defining the start and stop explicitly and avoiding all interpolation between colours. Because the treatment of 0 and 1 is slightly different here the formula for the increment is also slightly different.

$$1/n$$

Where n above is the number of entries in the scale.

$$1/9 = 0.1111111...$$

We'll round to 3 decimal places to make the scale simpler.

colorscale: [
      [0, 'rgb(253, 180, 7)'], // -13.5 -> -12.0 feet
      [0.111, 'rgb(253, 180, 7)'], // -13.5 -> -12.0 feet

      [0.111, 'rgb(255, 217, 109)'], // -12.0 -> -10.5 feet
      [0.222, 'rgb(255, 217, 109)'], // -12.0 -> -10.5 feet

      [0.222, 'rgb(253, 180, 7)'], // -10.5 -> -9.0 feet
      [0.333, 'rgb(253, 180, 7)'], // -10.5 -> -9.0 feet

      [0.333, 'rgb(253, 178, 109)'], // -9.0 -> -7.5 feet
      [0.444, 'rgb(253, 178, 109)'], // -9.0 -> -7.5 feet

      [0.444, 'rgb(253, 105, 9)'], // -7.5 -> 6.0 feet
      [0.555, 'rgb(253, 105, 9)'], // -7.5 -> 6.0 feet

      [0.555, 'rgb(254, 140, 108)'], // -6.0 -> -4.5 feet
      [0.666, 'rgb(254, 140, 108)'], // -6.0 -> -4.5 feet

      [0.666, 'rgb(252, 38, 9)'], // -4.5 -> -3.0 feet
      [0.777, 'rgb(252, 38, 9)'], // -4.5 -> -3.0 feet

      [0.777, 'rgb(253, 103, 109)'], // -3.0 -> -1.5 feet
      [0.888, 'rgb(253, 103, 109)'], // -3.0 -> -1.5 feet

      [0.888, 'rgb(251, 0, 5)'], // -1.5 -> 0 feet
      [1, 'rgb(251, 0, 5)'], // -1.5 -> 0 feet
    ],

The scale needs to end with 1 to meet Plotly's expectations, so at the end our last discrete box will just be slightly larger.


To fully describe our newly created colorscale we must describe certain metadata in colorbar.

colorbar:{
  tick0: -13.5,
  dtick: 1.5,
  title: {
    text: 'depth in feet',
    side: 'right',
  }
}

We'll set tick0 to be -13.5. This attribute describes what the 0 entry of your colorscale should describe. We'll also need to set dtick to be an increment of 1.5. From the image of the legend we're trying to recreate, we can see each coloured box is supposed to describe an elevation of 1.5 feet.

Lastly, to put everything together here are a couple of codepens which have the continuous and discrete colour scales defined.

Did you find this article valuable?

Support Naomi Aro by becoming a sponsor. Any amount is appreciated!