# Discrete colorbar with PlotlyJS

**URL:** <https://discourse.julialang.org/t/discrete-colorbar-with-plotlyjs/80773>\
**Category:** Visualization\
**Tags:** plotting, plotlyjs\
**Created:** [May 9, 2022, 7:01pm UTC](https://discourse.julialang.org/t/discrete-colorbar-with-plotlyjs/80773 "2022-05-09T19:01:46Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Line](https://avatars.discourse-cdn.com/v4/letter/l/b38774/32.png) [@Line](https://discourse.julialang.org/u/Line)\
**Post date:** [May 9, 2022, 7:01pm UTC](https://discourse.julialang.org/t/discrete-colorbar-with-plotlyjs/80773/1 "2022-05-09T19:01:46Z")

</div>

Hi, wonder if there is any good way to make a discrete colour bar when making a heatmap plot with PlotlyJS? It would also be nice to be able to label these.

---

<div class="post-metadata">

**Author:** ![jd-foster](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jd-foster/32/35824_2.png) [@jd-foster](https://discourse.julialang.org/u/jd-foster)\
**Post date:** [May 11, 2022, 3:47am UTC](https://discourse.julialang.org/t/discrete-colorbar-with-plotlyjs/80773/2 "2022-05-11T03:47:38Z")

</div>

Here is an example:

 ![plotly-discrete-heatmap](https://global.discourse-cdn.com/julialang/original/3X/0/e/0e43b76df4b1e0c8aadca979e625cd1bbb974b26.jpeg)

The code to produce this is

```julia

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:

> [@Set custom colorbar tick-labels](https://discourse.julialang.org/t/set-custom-colorbar-tick-labels/69806/5):
>
> Everything is possible, with some imagination: play_button using Plots; gr()

---

<div class="post-metadata">

**Author:** ![empet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/empet/32/221303_2.png) [@empet](https://discourse.julialang.org/u/empet)\
**Post date:** [May 11, 2022, 7:02am UTC](https://discourse.julialang.org/t/discrete-colorbar-with-plotlyjs/80773/3 "2022-05-11T07:02:56Z")

</div>

I post a Julia version of the plotly.py code for a heatmap with discrete colorscale  
[https://chart-studio.plotly.com/~empet/15229/heatmap-with-a-discrete-colorscale/#/](https://chart-studio.plotly.com/~empet/15229/heatmap-with-a-discrete-colorscale/#/)

```julia
using PlotlyJS
function discrete_colorscale(boundary_vals, mycolors)
    #boundary_vals - vector of values bounding intervals/ranges of interest
    #colors - list of rgb or hex colorcodes for values in [bvals[k], bvals[k+1]],1<=k < length(boundary_vals)
    #returns the plotly discrete colorscale
    if length(boundary_vals) != length(mycolors)+1
           error("length of boundary values should be equal to length(mycolors)+1")
    end
    bvals = sort(boundary_vals)     
    nvals = [(v-bvals[1])/(bvals[end]-bvals[1]) for v in bvals] #normalized values
    
    dcolorscale = [] #discrete colorscale
    for k in 1:length(mycolors)
        append!(dcolorscale, [[nvals[k], mycolors[k]], [nvals[k+1], mycolors[k]]])
    end    
    return dcolorscale 
      
end            

function colorbar_ticks(bvals)
    tickvals = [sum(bvals[k:k+1])/2 for k in 1:length(bvals)-1] #position with respect to bvals, to be placed ticktext 
    ticktext = String[]
    push!(ticktext, "<$(bvals[2])")
    for k in 2:length(bvals)-2
        push!(ticktext, "$(bvals[k])-$(bvals[k+1])")
    end        
    push!(ticktext, ">$(bvals[end-1])")  
    return tickvals, ticktext
end        
       
z = rand(2:90, 20, 20)
bvals = [2, 15, 40, 65, 90]
mycolors = ["#09ffff", "#19d3f3", "#e763fa" , "#ab63fa"]
#mycolors = ["rgb(133,187,77)","rgb(202,216,216)","rgb(238,164,2)", "rgb(221,114,54)"]
dcolorscale = discrete_colorscale(bvals, mycolors)

tvals, ttext= colorbar_ticks(bvals)

pl = Plot(heatmap(z=z, colorscale=dcolorscale,
                  colorbar=attr(tickvals=tvals, ticktext=ttext)), 
          Layout(width=450, height=400))

```

![discrete-colorscale](https://global.discourse-cdn.com/julialang/original/3X/f/8/f8d947d4d3a94ed4eaf34bca1ab0fa3abe27ec08.png)

---

<div class="post-metadata">

**Author:** ![jd-foster](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jd-foster/32/35824_2.png) [@jd-foster](https://discourse.julialang.org/u/jd-foster)\
**Post date:** [May 11, 2022, 7:19am UTC](https://discourse.julialang.org/t/discrete-colorbar-with-plotlyjs/80773/4 "2022-05-11T07:19:37Z")

</div>

This is really nice; more adaptive than my example by using functions to generate labels, for example. And I really like your colour choice 😋!

---

<div class="post-metadata">

**Author:** ![Line](https://avatars.discourse-cdn.com/v4/letter/l/b38774/32.png) [@Line](https://discourse.julialang.org/u/Line)\
**Post date:** [June 13, 2022, 4:29pm UTC](https://discourse.julialang.org/t/discrete-colorbar-with-plotlyjs/80773/5 "2022-06-13T16:29:10Z")

</div>

Thanks for you`re advice, by using a combination of these suggestions I ended up with a really nice plot! Thanks!
