Colours from a [0,1] float?

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:

  1. the relationship between colors may be more complex than a simple mean ;
  2. 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 ;
  3. 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)
2 Likes

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).

2 Likes