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

 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,
 PlotRangePadding -> Automatic,
 PerformanceGoal -> {"Speed", "Quality"},
 WorkingPrecision -> MachinePrecision,
 GridLinesStyle -> {Dashed, Dashed}

with output

enter image description here

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 :)


1 Answer 1


You can define a custom ColorFunction:

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]] &;


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]]

enter image description here

Replace Blue with {Blue, Red} to get

enter image description here

  • $\begingroup$ 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. $\endgroup$
    – PhysyCola
    Nov 17, 2021 at 10:36
  • $\begingroup$ @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. $\endgroup$
    – kglr
    Nov 17, 2021 at 18:46
  • $\begingroup$ Right, and the first argument is the clipping range? In any case, this is an excellent answer, so will be marking is as answered! $\endgroup$
    – PhysyCola
    Nov 18, 2021 at 14:20

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.