I have some data that I want to represent in a histogram with a different colour of the bin that depends on a float in the 0,1 range.
I can see I can pass to the histogram call a colour
parameter with the vector of colours, but how do I create the colours when my “colour data” is in the range [0,1] ? For example, 0 is a full green colour, 1 is a full red one, and I want a colour associated to 0.2 (so, mostly green).
Got it:
weighted_color_mean(0.2, colorant"red", colorant"green")
You might also want to use ColorSchemes.jl
: after all a color scheme is nothing but a tool that maps a scalar value into a color.
I don’t know about your specific use case, but using a fully-fledged color may have several advantages w.r.t a simpler, more manual technique like you did:
- the relationship between colors may be more complex than a simple mean ;
- I’m no expert myself, but I know that a lot of research has been spent devising color schemes that are “good” (considering what the human eye perceives, and how visually impaired persons might be affected) or simply visually appealing ;
- you benefit from a very large catalogue of schemes to choose from.
For example:
julia> using ColorSchemes
# this comes from the `colorcet` collection and has green on one end,
# white in the middle and red on the other end. But you may choose any
# other color scheme and still get a consistent API for accessing the
# colors in it.
julia> cs = ColorSchemes.diverging_gwr_55_95_c38_n256;
julia> get(cs, 0.1)
RGB{Float64}(0.39467,0.662455,0.270175)
julia> get(cs, 0.9)
RGB{Float64}(0.958145,0.43425,0.391305)
Thanks. Can the “limits” of the colour scheme be specified programmatically?
This is the function I am ending up using, where I specific the lower and upper bound colours:
function generate_bin_colours(data,classes,bins;lcolour=colorant"green",ucolour=colorant"red")
# Creation of shares per bin
nbins = length(bins)
ndata = length(data)
shares = zeros(nbins-1)
for ib in 1:nbins-1
ndata_per_bean = 0
sum_per_bean = 0.0
bin_l = bins[ib]
bin_u = bins[ib+1]
for id in 1:ndata
if data[id] >= bin_l && data[id] < bin_u
sum_per_bean += classes[id]
ndata_per_bean += 1
end
end
shares[ib] = ndata_per_bean > 0 ? sum_per_bean / ndata_per_bean : 0.5
end
return [weighted_color_mean(x, lcolour, ucolour) for x in shares]
end
Yes. See: Color Range: pick color in range base on values in a vector - #4 by stevengj
As explained in the linked post, doing linear interpolation like this produces a color map that is not perceptually uniform (distorts data).