Complex colormap in Julia Plots?


is there any colormap that can be used together with Julia Plots that encodes amplitude and phase of a complex field in a single color plot?
E.g. hue encodes the phase and “lightness” or value the amplitude.
Similar to this: Color map for complex numbers


You can find a related Plots.jl example in this other post.

We have quite recently added a function complexColoring into the package ImageUtils. It colors complex arrays using a desaturation colormap. It is designed such that changes in phase do not alter its gray value. From the example posted this seems to be what you want.

You can see the colormap in action in one of our publications in figures 1 and 5.

The example in this post does only encode phase and does not seem to desaturate towards z=0. If both phase and absolute value are important, this kind of coloring is not really suitable.

1 Like

The method of visualization of a complex function illustrated in this other post is very popular in mathematics community. It implements one of the methods presented by Elias Wegert in his excellent book,
In this book it is proved that HSV colors can encode all properties of a complex function, zeros and poles positions, analysing the plot patterns, according to the so called argument principle from Complex Function Theory.
Also, Elias Wegert publishes each year a calendar, Complex Beauties, associating to each month a topic related to a celebrated complex function. Hence to see different methods of visulizing complex functions, you can browse the collection of calendars


I am aware of this method of coloring complex numbers and it is perfectly fine for qualitative coloring, which is likely the application scenario. However, if you are interested in a quantitative colormap, you might want one which is perceptionally uniform along phase and absolute-value direction. This way perceived changes in color can be attributed to changes in the underlying data and not gradients in your colormap. This was the motivation for our colormap.

From an artistic point of view of cause, there is no arguing that the coloring methods from Elias Wegert are superior.

1 Like

Complexcoloring seems to do exactly what I need.
Thanks to everyone who replied!

Here is one colormap I use, it gives beautiful results on some cases (not all).

function colormap(z)
    x = real(z)
    y = imag(z)
    a = angle(z)
    r = mod(abs(z), 1.0)
    g = 2 * mod(a, 0.5)
    b = mod(x*y, 1.0)
    return RGB(
        (1.0 - cos(r-0.5))*8.0,
        (1.0 - cos(g-0.5))*8.0,
        (1.0 - cos(b-0.5))*8.0

For example (these are some elliptic functions):


The colormap defined by complexColoring is a modified version of the cmocean colormap, phase. All cmocean colormaps, as well as matplotlib viridis, plasma, magma, inferno are perceptually uniform within the color space CAM02-UCS, NOT CIELab (Lab)!!!
Namely, if C is such a colormap, and x represents normalized data to be mapped to C, then the geometry of the 3d curve in the RGB color space

color(x)=(R(x), G(x), B(x))∈ C 

doesn’t give any information on the quality of the considered colormap.
Converting the RGB color-space to the CAM02-UCS space, referenced to a system of cylindrical coordinates, (Lightness, Chroma, Hue), to the above curve corresponds the curve

               x∈[0,1]-> (Lightnesss(x), Chroma(x), Hue(x))

in the latter space.

By definition, the colormap C is perceptually uniform in the CAM02-UCS space if the graph of the first component

x ∈[0,1]-->  Lightness(x)

is linear.
The colormap ColorSchemes.phase has a linear and constant Lightness (see the first image in the panel below).

Inside the function complexColoring it is called the function

function normalizeGray(c::T,g=0.7) where {T<:Colorant}
    cluv = Lab(c)
    # test range
    minG = Gray.(Lab(0,cluv.a,cluv.b)).val
    maxG = Gray.(Lab(100,cluv.a,cluv.b)).val
    if g < minG
      g = minG
      @warn "Normalization of gray value failed, g ≈ $(ceil(minG,digits=3)) is used. Use g >= $(ceil(minG,digits=3)) for a consistent normalization."
    elseif g > maxG
      g = maxG
      @warn "Normalization of gray value failed, g ≈ $(floor(maxG,digits=3)) is used. Use g <= $(floor(maxG,digits=3)) for a consistent normalization."
    l = find_zero(l->Gray.(Lab(l,cluv.a,cluv.b)).val-g, (0, 100))
    return T(Lab(l,cluv.a,cluv.b))

which modifies the Lab components of a perceptually uniform colormap not in the CIELab space, but within the space CAM02-UCS. And this mixture of colorspaces transforms the phase colormap into one which is no more perceptually uniform.
In the panel below I included the plots of Lightness, Chroma and Hue of the initial ColorSchemes.phase (the colorful line representing its linear and constant lightness), the colorscheme obtained from phase by calling normalizeGray. with g=0.35, respectively, g=0.7 (the default value). We notice that the lightness for the last two cases is not linear. Hence the last two colormaps are not perceptually uniform, and the (de)saturation can deviate further their lightness from linearity.


@empet You are absolutely right and I simply forgot about this fact. Thank you for pointing this out. Our initial goal was a perceptionaly uniform map, however, we were facing several problems and our current map is a compromise.

The first issue is that desaturation does change uniformity along the way as you pointed out. Moreover, the map looked quite disturbed with band structures if viewed at gray values. Something we wanted to avoid in a publication setting (which quite often gets printed out in gray values), where overall structure given by the absolute values was most important and the phase information in second place.

So the map we came up with primarily focuses on the second issue, while trying to minimize band like distortions (non-uniformity). Of cause it would be even better to a complex color map, which is perceptually uniform in phase and absolute value direction as well as good looking in gray values (phase information lost, but mapping of absolute values to gray values the same for all phases). However, since I am no color expert I was not able to come up with such a map.

1 Like