3
$\begingroup$

I have produced used the following code to create a contour plot:

ContourPlot[Cos[x] + Cos[y], {x, 0, 4 Pi}, {y, 0, 4 Pi}]

However, I would like to modify this plot so that when the function is positive the shading is blue, and when it is negative the shading is red.

Now I know there's already similar threads on this site to achieving this but I would like to impose another condition which makes things trickier.

I would also like the contours lines to have the OPPOSITE colour to the shading (i.e if the region is shaded blue then I want the contours to be red). The contours can be isolated by turning shading off:

ContourPlot[Cos[x] + Cos[y], {x, 0, 4 Pi}, {y, 0, 4 Pi}, 
 ContourShading -> None]

So I would like the contours to be coloured as follows:

The Contours

Combined with the shading, I hope that the final image will look like this:

The Goal

Final Result

I would be really grateful if someone could shed some light on this.

I'm really hoping there's a way of implimenting an IF statement which will condition on the sign of the function.

Thanks in advance!

$\endgroup$
1
  • $\begingroup$ Related: (6916) $\endgroup$
    – Mr.Wizard
    Mar 7, 2016 at 12:05

4 Answers 4

5
$\begingroup$

A non-hackish method using Mesh and MeshFunctions:

ContourPlot[Cos[x] + Cos[y], {x, 0, 4 Pi}, {y, 0, 4 Pi}, 
 ContourShading -> {Red, Blue}, Contours -> {{0}},
 Mesh -> 4, MeshFunctions -> {Max[Cos[#] + Cos[#2], 0] &, Min[Cos[#] + Cos[#2], 0] &}, 
 BaseStyle -> Thick, MeshStyle -> {Red, Blue},
 PlotPoints -> 100
]

enter image description here


Here is a way using only contours but requiring manually generated styles. I was hoping that a function could be given directly to Contours for automatic generation but at least as I formulated it this did not work.

ContourPlot[Cos[x] + Cos[y], {x, 0, 4 Pi}, {y, 0, 4 Pi}, 
  ContourShading -> {Red, Red, Red, Red, Red, Blue, Blue, Blue, Blue, Blue}, 
  Contours -> Array[If[# > 0, {#, Red}, {#, Blue}] &, 9, {-2, 2}]
]

Alternatively:

sty = If[# > 0, {#, Blue}, {#, Red}] & /@ Range[-2, 2, 1/2]

ContourPlot[Cos[x] + Cos[y], {x, 0, 4 Pi}, {y, 0, 4 Pi},
 ContourShading -> (sty[[All, 2]] /. {Red -> Blue, Blue -> Red}), Contours -> sty]

enter image description here

$\endgroup$
11
  • $\begingroup$ Nice! (IOU one upvote.) $\endgroup$ Feb 21, 2016 at 19:54
  • $\begingroup$ @J.M. Thanks! I don't know if this is best however. I often wonder how Heike would do it were she here. $\endgroup$
    – Mr.Wizard
    Feb 21, 2016 at 19:57
  • $\begingroup$ This Alternative solution is really nice as it uses terminology of which I am familiar with. However, could I ask why you've included 'Red', and 'Blue' five times each in the list? $\endgroup$
    – Mr S 100
    Feb 21, 2016 at 20:26
  • $\begingroup$ @MrS100 Because unlike the first method I could not separate the number contour lines from the number of contour fill styles. With only ContourShading -> {Red, Blue} here I would get a striped plot instead. $\endgroup$
    – Mr.Wizard
    Feb 21, 2016 at 20:29
  • $\begingroup$ Thanks for the prompt reply. I've just tested this now and I see exactly what you mean. I'm struggling to understand what the function & /@ Range[#, #2, 1/2] &[-2, 2]' is doing as changing the values dramatically changes the result. I ask this because I have not seen this function before used in this context and I am keen to understand your choice of parameters. $\endgroup$
    – Mr S 100
    Feb 21, 2016 at 20:35
2
$\begingroup$

This rather hackish solution relies on the fact that the Tooltip[] objects within the output of ContourPlot[] store the height of the corresponding (set of) contours:

ContourPlot[Cos[x] + Cos[y], {x, 0, 4 π}, {y, 0, 4 π}, 
            ColorFunction -> (Blend[{Red, Blue}, LogisticSigmoid[2 #]] &), 
            ColorFunctionScaling -> False, Contours -> 20] /.
Tooltip[stuff_, c_] :> Tooltip[Prepend[Cases[stuff, _Line],
                                       Directive[{Blue, Red}[[UnitStep[c] + 1]],
                                       Opacity[0.5], CapForm["Butt"]]], c]

looks a bit trippy to me

$\endgroup$
1
  • $\begingroup$ Thanks for the response J. M! I've upvoted as the code works as required. $\endgroup$
    – Mr S 100
    Feb 21, 2016 at 20:36
2
$\begingroup$

Yet another hackish solution that however regenerates the contour plot multiple times is the following combination:

Show[
 (* Generate the shaded areas *)
 ContourPlot[Cos[x] + Cos[y], {x, 0, 4 Pi}, {y, 0, 4 Pi},
  ColorFunctionScaling -> False,
  ColorFunction -> Function[z, If[z >= 0, Blue, Red]],
  ContourStyle -> None
  ],

 (* Generate the contours *)
 MapThread[
  ContourPlot[
    Boole[#1[Cos[x] + Cos[y], 0]] (Cos[x] + Cos[y]),
    {x, 0, 4 Pi}, {y, 0, 4 Pi}, Contours -> 4,
    ContourStyle -> Directive[Thick, #2], ContourShading -> None
    ] &,
  {{Greater, Less}, {Red, Blue}}
 ]
]

Mathematica graphics


Mr. Wizard's solution presented in his answer above is clearly superior, but I put this together before I saw his answer, so I thought I might as well post it anyway.

$\endgroup$
1
  • $\begingroup$ I like this response as this is how I initially thought about approaching the problem - by essentially combining two results. Upvoted $\endgroup$
    – Mr S 100
    Feb 21, 2016 at 20:37
2
$\begingroup$

I would also define my color style and use it like this:

   Clear[contours]
contours[n_?OddQ, color1_, color2_] := Module[{m},
  m = IntegerPart[n/2];
  cont = n; 
  col = Join[ConstantArray[color1, m], {Gray}, 
    ConstantArray[color2, m]];];

contours[11, Blue, Red]

p1 = ContourPlot[Cos[x] + Cos[y], {x, 0, 4 Pi}, {y, 0, 4 Pi}, 
   ContourShading -> None, ContourStyle -> col, Contours -> cont];
p2 = ContourPlot[Cos[x] + Cos[y], {x, 0, 4 Pi}, {y, 0, 4 Pi}, 
   ColorFunction -> (If[# <= 0, Red, Blue] &), 
   ColorFunctionScaling -> False, Contours -> 1];
Show[p2, p1]

enter image description here

not ot get something close to your Goal picuter you can sue Show

$\endgroup$
3
  • 1
    $\begingroup$ I somehow didn't see this answer before adding the second method to mine; sorry if I plagiarized accidentally, and +1. $\endgroup$
    – Mr.Wizard
    Feb 21, 2016 at 20:20
  • 1
    $\begingroup$ Upvoted. This is a clever solution to the problem. I've only just become familiar with the show function today, but it been of use already. $\endgroup$
    – Mr S 100
    Feb 21, 2016 at 20:38
  • $\begingroup$ @Mr.Wizard not at all and thanks for Upvote :-) $\endgroup$ Feb 21, 2016 at 20:41

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.