I think this is pretty close, and there are some parameters you can tweak to get the effect you like.
Code for the plot above
using GADM, DataFrames, GLMakie, GeoMakie
import Colors: HSL, LCHuv
# Helper functions
function desaturate(col::T, amount)::T where T
col_lch = LCHuv(col)
return LCHuv(col_lch.l, col_lch.c * (1-amount), col_lch.h)
end
function lighten(col::T, amount)::T where T
col_hsl = HSL(col)
return HSL(col_hsl.h, col_hsl.s, 1 - (1 - col_hsl.l) * (1-amount))
end
# Generate a color matrix
function vsup_colormatrix(;
cmap, n_uncertainty,
max_desat, # 0-1, 1 = most desaturated is grey, 0 = no desaturation
pow_desat, # higher values to desature more slowly
max_light, # 0-1 1 = most light is white, 0 = no light
pow_light # higher values to lighten more slowly
)
n_levels = [2^(i-1) for i in 1:n_uncertainty]
max_levels = n_levels[end]
rel_col = @. (ceil(Int, (1:max_levels)'/(max_levels/n_levels)) - 0.5) / n_levels
col_shift = @. 1 - ((1:n_uncertainty) - 1)/(n_uncertainty - 1)
col = getindex.(Ref(cmap), rel_col)
col_desat = desaturate.(
col,
max_desat.*col_shift.^pow_desat
)
return lighten.(
col_desat,
max_light.*col_shift.^pow_light
)
end
function val_u_to_color(
v, u, colormatrix;
colorrange = extrema(v), uncertaintyrange = extrema(u),
v_edges = range(colorrange...; length = size(colormatrix, 2)+1),
u_edges = range(uncertaintyrange...; length = size(colormatrix, 1)+1)
)
n_uncertainty, n_values = size(colormatrix)
# Find which bin each value is in
v_bins = clamp.(searchsortedfirst.(Ref(v_edges), v).-1, 1, n_values)
u_bins = clamp.(searchsortedfirst.(Ref(u_edges), u).-1, 1, n_uncertainty)
# Get colors
getindex.(Ref(colormatrix), u_bins, v_bins)
end
# Polygons to plot
dk_munic = DataFrame(GADM.get("DNK"; depth = 2))
# Mockups values for observations and uncertainty
vals = rand(nrow(dk_munic))
u = rand(nrow(dk_munic))
# Generate color matrix
vsup_cmap = vsup_colormatrix(;
cmap = cgrad(:viridis), n_uncertainty = 4,
max_desat = 0.8, pow_desat = 1.0, max_light = 0.7, pow_light = 1
)
# Get colors
col_final = val_u_to_color(vals, u, vsup_cmap; colorrange = (0,1), uncertaintyrange = (0,1))
# Draw the figure
f, ax, p = poly(dk_munic.geom; color = col_final, strokewidth = 0.5)
hidespines!(ax)
hidedecorations!(ax)
# Legend axis
ax_legend = PolarAxis(f[1,1];
thetalimits = (1.5pi/4, 2.5pi/4),
rlimits = (0,10),
rticks = (collect(range(0,10; length = 5)), string.(range(0,1; length = 5))),
thetaticks = ([1.5pi/4, 2pi/4, 2.5pi/4], ["100%", "50%", "0%"]),
clip = false,
height= Relative(0.7), width = Relative(0.5), tellwidth = false,tellheight = false,
halign = 1.0, valign = 1.0 # found these values to be right through trial and error
)
# Draw the legend - the meshimage trick is needed because surface plot is bugged
# See https://github.com/MakieOrg/Makie.jl/issues/5235
mi = meshimage!(
ax_legend,
ax_legend.thetalimits[], 0..10, rotl90(vsup_cmap), shading = NoShading,
)
mi.plots[1].interpolate[] = false
GLMakie.closeall()
f