How to achieve smooth transition between the colors?

As can be seen on the first image the color transition is not smooth. There is a narrow yellow line above yellow arrow and narrow cyan line above cyan arrow. On the other hand the greenish part is too wide compared to other colors.

If it is compared with predefined color gradient "Rainbow" we can see that the transition is perfectly smooth.

How to achieve the same with my colors?

colors = {Red, Yellow, Green, Cyan, Blue, Magenta};
back = Rectangle[{-1/4, -1/4}, {5/4, 3/4}];

Graphics[{back, {LinearGradientFilling[colors], 
   Rectangle[{0, 0}, {1, 1/2}]}, 
  Riffle[colors, Arrow /@ Table[{{n/5, -1/10}, {n/5, 0}}, {n, 0, 5}]]}]

Graphics[{back, {LinearGradientFilling["Rainbow"], 
   Rectangle[{0, 0}, {1, 1/2}]}}]

enter image description here

enter image description here

  • 4
    $\begingroup$ Does this answer your question? Colormaps for linear visual perception AND grayscale printing Namely, you are looking for perceptually uniform colormaps. $\endgroup$
    – Domen
    Mar 13 at 19:25
  • $\begingroup$ If I understand it correctly, there are only predefined color schemes taken from somewhere else (python code). I want to use my own colors. $\endgroup$ Mar 13 at 19:53
  • $\begingroup$ Yes, you cannot just take a random sample of colors and expect them to form a perceptually uniform colormap. There are, however, tools for creating such colormaps (see for example viscm). $\endgroup$
    – Domen
    Mar 13 at 20:04
  • $\begingroup$ Of course you can transit from one color to any other color smoothly. $\endgroup$ Mar 13 at 20:09

1 Answer 1


This is more of an extended comment, than a complete answer.

As I've mentioned in the comments, creating a perceptually uniform colormap is not a completely trivial thing. A first thing to know is that the usual RGB color space is absolutely unsuitable for such task, because it is not perceptually uniform. This means that the Euclidean distances between colors do not corellate well with the perceptual distances between them. A more suitable color space is for example CIELAB.

Therefore, the first mitigation you can do is to simply interpolate your colors in the CIELAB instead of RGB.

showColors[colors_] := 
 Graphics[{Rectangle[{-1/4, -1/4}, {5/4, 3/4}], {LinearGradientFilling[colors], 
    Rectangle[{0, 0}, {1, 1/2}]}, 
   Riffle[colors, Arrow /@ Table[{{n/5, -1/10}, {n/5, 0}}, {n, 0, 5}]]}]

azerbajdzan = {Red, Yellow, Green, Cyan, Blue, Magenta};
azerbajdzanLab = ColorConvert[azerbajdzan, "LAB"];

GraphicsRow[{showColors[azerbajdzan], showColors[azerbajdzanLab]}]

enter image description here

Is it better? Well, green and blue regions are narrower, yellow is more smoothly mixed with the neighbours ... But some of the colors are still very prominently bright? Why is that? Well, just look at the $L^\ast$ component, which describes the perceptual lightness! Also, let's compare it with the built-in rainbow pallete and viridis (I've sampled 6 colors from them, so that we can compare them to yours).

rainbowLab = ColorConvert[ColorData["Rainbow"] /@ Subdivide[1, 5], "LAB"];
viridisLab = ColorConvert[ResourceFunction["ViridisColor"] /@ Subdivide[1, 5], "LAB"]

ListPlot[{rainbowLab[[All, 1]], viridisLab[[All, 1]], azerbajdzanLab[[All, 1]]}, 
 Joined -> True, PlotLegends -> {"Rainbow", "Viridis", "azerbajdzan"}, 
 PlotLabel -> "L*", PlotMarkers -> Automatic]

enter image description here

What do you see? Colours in viridis have a linear lightness profile, colors in rainbow have a smooth concave profile, whereas the colours you've chosen are very scattered around, and even if you do some higher order inteprolation between them, you will inevitably end up with some perceptually lighter/darker bands!

Let me also add a full three-dimensional comparision of your chosen colors (linearly interpolated) and the rainbow/viridis palette.

  List @@ ColorConvert[ColorData["Rainbow"][t], "LAB"], {t, 0, 1}, 
  BoxRatios -> {1, 1, 1}, ColorFunction -> "Rainbow", 
  PlotRange -> {{0, 1.2}, {-1.2, 1.2}, {-1.2, 1.2}}, 
  AxesLabel -> {"L*", "a*", "b*"}], 
  List @@ ColorConvert[ResourceFunction["ViridisColor"][t], 
    "LAB"], {t, 0, 1}, 
  ColorFunction -> (ResourceFunction["ViridisColor"][#] &)], 
 Graphics3D[{Line[List @@@ azerbajdzanLab], 
   PointSize[Large], {#, Point[List @@ #]} & /@ azerbajdzanLab}]]

enter image description here

Now going away from only the lightness profile: If you would somehow want to get a perceptually smooth color maps from your colors, you would have to fit a curve through your points in such a way, that the distance (as measured on the curve) between the sequential colors would be the same. Since the distance between cyan and blue is very large

EuclideanDistance @@@ Partition[List @@@ azerbajdzanLab, 2, 1]
(* {1.08414, 0.654592, 1.0017, 1.65246, 0.650299} *)

you would have to make some very large turn between yellow–green and blue–magenta ... Now, of course it is possible to find such a curve (and there are infinitely many), but probably the end result will have some other problems (out-of-gamut, new spurious colours you may not want, already mentioned weird lightness gradient ...)

  • $\begingroup$ Look at mathematica.stackexchange.com/questions/300452/…. There is the gradient between the same colors as mine just not linear but circular. But it is immediately apparent that the gradient is smooth, i.e. there are no apparent narrow lines of, say, cyan. I admit that your gradient using LAB is better as it treats all colors the same but then each color has its of narrow line at the arrow. Like we can see most on introducing Blue narrow line. $\endgroup$ Mar 14 at 11:52
  • $\begingroup$ And I also do not think it has anything with brightness of colors - that one color is much brighter than the other. You can have smooth transition between black and white. Yet, white has maximum possible brightness and black minimum possible brightness. $\endgroup$ Mar 14 at 12:06
  • $\begingroup$ Not true, you just don't see the same problem, because they are shown in a circle and on a white background. Plot them in the same way and you'll see a similar effect: colorsCircle = With[{img = Import["https://i.sstatic.net/6B71P.png"], r = 260, dx = 266, dy = 266}, Table[RGBColor @@ PixelValue[img, {r Cos[ϕ] + dx, r Sin[ϕ] + dy}], {ϕ, 0, 2 Pi,0.1}]]; showColors[colorsCircle]. As for the lightness, I've answered this in my text above. You can have a linear lightness gradient, but you've chosen a set of colors (not just two!) among which it is difficult to create a nice transition. $\endgroup$
    – Domen
    Mar 14 at 12:07
  • $\begingroup$ In any case, the colors on that circle are indeed very close to the linear interpolation in LAB (which I've already given you in my answer): Show[Graphics3D[{Line[List @@@ azerbajdzanLab], PointSize[Large], {#, Point[List @@ #]} & /@ azerbajdzanLab, Line[List @@@ colorsCircleLab], PointSize[Large], {#, Point[List @@ #]} & /@ colorsCircleLab}]] $\endgroup$
    – Domen
    Mar 14 at 12:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.