Don't forget that, even if you're working with LAB colour values, RGB values have to be output to show it on a screen. At some point, it has to tell the red, green and blue pixels of a screen what to do.
Look at it in RGB terms, and the cause of the bands is actually pretty simple.
Grab a colour picker and look at the gradients, and you'll notice that the bands are around the points where the nature of the gradient changes:
- In the red, it's around where it turns from smoothly increasing the R in the RGB to adding G to become yellow - around #FF0000 to #FF2500
- In the blue, it's around where it turns from smoothly increasing the B in the RGB to adding G to become cyan - around #0000FF to #0025FF
And likewise with the bottom plots, adding yellow to white: they're essentially three gradients joined together. Using the red gradient as an example:
- it's #000000 to #FF0000 (increasing Brightness in HSB terms, increasing Red channel in RGB)
- then #FF0000 to #FFFF00 (changing Hue in HSB terms, increasing Green channel in RGB)
- then #FFFF00 to #FFFFFF (changing Saturation in HSB terms, increasing Blue channel in RGB)
So there's always going to be a visible join, if that's how it's set up. As a general rule, where accuracy and linearity are the main aim, it's best to keep a gradient simple, varying one feature constantly (unless you want banding, e.g. on some types of brain scan).
That said, if you're determined to run through the wider spectrum (it does look good), I'd look into either beginning to add the second channel before the first is complete, forming a bridging section between the gradients, or having a slight reverse S shape curve to the rate at which the second channel is added (probably both).
So instead of:
- #000000 to #FF0000, 100% black to 100% red
- #FF0000 to #FFFF00, 100% red to 100% yellow
- #FFFF00 to #FFFFFF, 100% yellow to 100% white
...it might be (just guesses off the top of my head, will need adjustment):
- #000000 to #E90000, 100% black to bright red
- #E90000 to #FF2500, (SHORT BRIDGE) bright red (dark) to bright red (slightly orange)
- #FF2500 to #FFE900, bright red (slightly orange) to bright yellow (slightly orange)
- #FFE900 to #FFFF25, (SHORT BRIDGE) bright yellow (slightly orange) to bright yellow (light)
- #FFFF25 to #FFFFFF, bright yellow (light) to 100% white
...then adjust the curves of each section according to taste :-)
Edit: Here's a demonstration of the 'cutting the corners' suggestion. It's not perfect - it's fairly unrefined, just something I put together by eye in a few minutes using the Illustrator blend tool (unblended objects at the bottom to show the colour points). Each segment of the gradient between each colour point is 100% linear, whereas you'd probably want something more rounded - and as a result, if you look carefully you can spot bands.
Results naturally vary between monitors: on my 'good' monitor, it's smooth; on the 'bad' monitor I use for checking the resilience of web images (where the original bands don't show very clearly), oranges always appear subdued making the red and yellow ares seem brighter than the joining orange, over-emphasising the red and yellow areas - but you can still see that the 'edge' of the original bands has largely gone.
Either way, compared with the original gradients, you can clearly see the difference. (as for the maths behind this - no idea, I'm no mathematician, but hopefully this helps identify the problem and solution)
The other advantage is, you're free to use the clearer black > one channel transition more.
Or the same idea on an RGB colour cube (forgive the crudeness, it's intended to be demonstrative not accurate...):
This shows probably more clearly what I meant when I said the example gradient can be improved by making the transitions from main segments to corner-cutting segments smooth rather than angular.