JuliaGraphics / ColorSchemes.jl

colorschemes, colormaps, gradients, and palettes
http://juliagraphics.github.io/ColorSchemes.jl/
Other
187 stars 33 forks source link

optimized get(colorscheme, data) function #91

Closed stevengj closed 2 years ago

stevengj commented 2 years ago

In the course of this discussion on the fastest way to display large matrices as images, I noticed that the get(colorscheme, data) function is not as fast as it could be, and allocates a lot of large temporary arrays (the same size as the image).

The following function seems to be more than 2x faster, and allocates 5x less memory (it only allocates the output image):

import ColorSchemes: AllowedInput, defaultrange
import ColorVectorSpace, Colors

# faster weighted_color_mean that assumes w ∈ [0,1] and
# exploits ColorVectorSpace operations for RGB and Gray types.
fast_weighted_color_mean(w::Real, c1, c2) = Colors.weighted_color_mean(w, c1, c2)
fast_weighted_color_mean(w::Real, c1::ColorVectorSpace.MathTypes, c2::ColorVectorSpace.MathTypes) = w*c1 + (1-w)*c2

function myget(cscheme::ColorScheme, X::AllowedInput, rangescale::NTuple{2,<:Real}=defaultrange(x))
    rangemin, rangemax = !iszero(rangescale[2] - rangescale[1]) ?
        rangescale : (zero(rangescale[1]), oneunit(rangescale[2]))
    scaleby = (length(cscheme) - 1) / (rangemax - rangemin)
    return map(X) do x
        xclamp = clamp(x, rangemin, rangemax)
        before_fp = (xclamp - rangemin) * scaleby + 1
        before = round(Int, before_fp, RoundDown)
        after =  min(before + 1, length(cscheme))
        cpt = before_fp - before
        #  blend between the two colors adjacent to the point
        @inbounds fast_weighted_color_mean(cpt, cscheme.colors[before], cscheme.colors[after])
    end
end

It adds a dependency on ColorVectorSpace.jl, but that's pretty lightweight (and is pulled in by things like Images.jl anyway).

cormullion commented 2 years ago

This is great, thanks. There's a bit of "journeyman" code in this package that would benefit from modernization.