How to construct a categorical colormap with one specific value corresponding to a specific color?

What I want to do:

I have an array of intergers that ranges over -3:2, which I want to plot with heatmap. The difficult part is that I want the 0 to be ploted by some “neutral” color, say grey in the colormap :coolwarm.

what I have tried

let
    Random.seed!(10)
    n = 10
    x = 1:n
    y = fill(1, n)
    cn = rand(-3:2, n)
    cnmin, cnmax = minimum(cn), maximum(cn)
    colormap1 = cgrad(:coolwarm, 2 * abs(cnmin) + 1, categorical=true)[1:cnmax-cnmin+1]
    colormap2 = cgrad(colormap1, cnmax-cnmin+1, categorical=true)
    @show length(colormap1)
    @show length(colormap2)
    fig = Figure()
    ax = Axis(fig[1, 1])
    heatmap!(ax, x, y, cn, colormap=colormap1, colorrange=(cnmin, cnmax))
    Colorbar(fig[2, 1], colormap=colormap1, ticklabelsize=25,
             limits=(cnmin-0.5, cnmax+0.5), ticks=cnmin:cnmax,
             vertical=false, flipaxis=false, height=20, width=Relative(0.65), labelsize=40)
    Colorbar(fig[3, 1], colormap=colormap2, ticklabelsize=25,
             limits=(cnmin-0.5, cnmax+0.5), ticks=cnmin:cnmax,
             vertical=false, flipaxis=false, height=20, width=Relative(0.65), labelsize=40)
    fig
end

my questions

  1. why I have to use cgrad twice to get the real categorical colormap?
  2. length(colormap1) == length(colormap2) == 5, but when colormap1 and colormap2 is plotted in colormap, they are so different, why?
  3. Is there a better way to do this?