# ColourFunction with fixed colour in range

After quite a lot of searching, I cannot seem to find an answer to my query, so I thought I would ask.

I am creating a contour plot of some function of two variables, $$f(x,y)$$, that is small ($$|f(x,y)| \ll 1$$) for positive values, and large ($$|f(x,y)| \gg 1$$) for negative values. Given that I am interested in properly resolving the behaviour of the function for positive values, I have currently been plotting the maximum of my function and zero, as follows:

xmin = 0.006;
xmax = 10;
ymin = 0.01;
ymax = 3

ContourPlot[
Max[f[x,y], 0],
{x, xmin, xmax},
{y, ymin, ymax},
ScalingFunctions -> {"Log", "Log"},
Contours -> {Automatic, 50},
ContourStyle -> None,
Exclusions -> None,
FrameLabel -> {{Style[
"\!$$\*SubscriptBox[\(k$$, $$||$$]\)\!$$\*SubscriptBox[\(L$$, \
$$T$$]\)/\!$$\*SqrtBox[SubscriptBox[\(\[Beta]$$, $$e$$]]\)", 18],
None}, {Style[
"\!$$\*SubscriptBox[\(k$$, $$y$$]\)\!$$\*SubscriptBox[\(d$$, $$e\$$]\)\[Chi]", 18], ""}},
LabelStyle ->
Directive[Black, FontSize -> 12, FontFamily -> "Times New Roman"],
ColorFunction -> ColorData[{"ThermometerColors", {0, 1}}],
PlotLegends ->
BarLegend[Automatic, Ticks -> Table[i, {i, 0, 0.09, 0.01}]],
PlotRange -> All,
PerformanceGoal -> {"Speed", "Quality"},
WorkingPrecision -> MachinePrecision,
GridLinesStyle -> {Dashed, Dashed}
]



with output

Note that I have not included the specific form of the function in the example code, as the code used to solve for $$f(x,y)$$ is too long for a post such as this.

Though the above plot shows most of the information that I would like it to, it is not always obvious as to where the surface $$f(x,y) = 0$$ actually occurs due to the choice of ColourFunction, and the fact that the function is continuous through zero, such there is no sharp --- and thus noticeable --- discontinuity in the colour.

Question: Is there a way to colour everything satisfying $$f(x,y) \leqslant a$$, for some constant $$a$$, (which, in the example above, would just be the values where $$f(x,y)=0$$) a particular colour, while preserving the ColourFunction everywhere else? Essentially, I would love to be able to append another colour to the bottom of the BarLegend that is the "zero-and-below" colour, and label it as such.

Any help would be greatly appreciated. Let me know if you need more information/code, as I'll be happy to provide it :)

You can define a custom ColorFunction:

ClearAll[CF]
CF[cliprange_:{0, 1}, clipcolor_: Automatic, range_: Automatic, cf_: "TemperatureMap"] :=
Module[{rng = range /. Automatic -> {0, 1},
clipcols = ColorData[cf] /@ {0, 1},
cc = clipcolor /. Automatic -> {White, White}},
ColorData[{cf, rng}][Clip[#, cliprange, rng]] /. Thread[clipcols -> cc]] &;


Examples:

f[x_, y_] := Cos[x] + Cos[y];

{min, max} = Through[
{MinValue, MaxValue}[{f[x, y], 0 <= x <= 4 Pi, 0 <= y <= 4 Pi}, {x, y}]];

Row[ContourPlot[f[x, y], {x, 0, 4 Pi}, {y, 0, 4 Pi},
Contours -> {Automatic, 50},
ColorFunction -> CF[#, Blue, {min, max}],
ColorFunctionScaling -> False, ContourStyle -> None,
PlotLegends -> Automatic, ImageSize -> 300,
PlotLabel -> Style["clipped range: " <> ToString[#], 16, Black]] & /@
{{-.5, max}, {min, 1}, {-1, 1.5}}, Spacer[10]]


Replace Blue with {Blue, Red} to get

• Hey @kglr, thanks for the great answer! This looks like a good solution to the problem, but I am having trouble applying it to my particular case. The second argument of CF[] is evidently the colour of the range not clipped, but I am not completely sure what the first and third arguments of CF[] correspond to? When I try to apply this to my problem, rather than your excellent MWE, these two arguments do not behave how I would expect. Nov 17 '21 at 10:36
• @PhysyCola, the third argument is a list of minimum and maximum values of the function (f) over the range of x and y values specified in ContourPlot.
– kglr
Nov 17 '21 at 18:46
• Right, and the first argument is the clipping range? In any case, this is an excellent answer, so will be marking is as answered! Nov 18 '21 at 14:20