Discrete colorbar with PlotlyJS

Here is an example:

The code to produce this is


using PlotlyJS

## Set-up:
# Define the categories and corresponding border levels between them:
categories = ["Undetectable", "Low", "Medium", "High", "Extreme", "Wat"]
levels = [0, 8, 16, 24, 32, 40, 48]
label_levels = levels .+ 4 # note the shift to centre the labels

# Some random data:
data = [
    29  16  15   7  14
    10   4  36  14   2
    25  23   0  29  41
]
# data = rand(minimum(levels):maximum(levels), 3, 5)

# A discrete colour scheme: see https://juliagraphics.github.io/Colors.jl/dev/namedcolors/
colour_pairs = [
    "crimson"      => (220,  20,  60),
    "orangered"    => (255,  69,   0),
    "goldenrod"    => (218, 165,  32),
    "aquamarine3"  => (102, 205, 170),
    "royalblue"    => ( 65, 105, 225),
    "darkviolet"   => (148,   0, 211),
    "black"        => (  0,   0,   0),
]
# Make it into a suitable list:
colour_list = map(x -> "rgb$(x[2])", colour_pairs)

# The tricky part - creating ordered ranges of colours:
norm_levels = (levels .- minimum(levels))/maximum(levels)
colour_marks = [[norm_levels[1], colour_list[1]]]
for i in 2:length(levels)
    push!(colour_marks, [norm_levels[i], colour_list[i-1]])
    push!(colour_marks, [norm_levels[i], colour_list[i]])
end

## Plot:
# Adapting http://juliaplots.org/PlotlyJS.jl/stable/examples/heatmaps/
# See https://plotly.com/julia/reference/heatmap/ for reference to keyword arguments
function heatmap2()
    trace = heatmap(
        x=["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
        y=["Morning", "Afternoon", "Evening"],
        z=data,
        autocolorscale=false,
        colorbar=attr(tickmode="array",
                      tickvals=label_levels,
                      ticktext=categories),
        colorscale=colour_marks,
        zmin=minimum(levels),
        zmax=maximum(levels)
    )
    plot(trace)
end
p = heatmap2()

See also this post: