4
$\begingroup$

I have a contour plot for which I have selected a finite set of contours. However, the contours overlap in some places and I would like to reverse the order in which they are drawn.

In other words, the last contour (with the largest function value) is currently drawn on bottom, but I would like this contour to be on top. It is confusing for the contour with the largest value to be drawn as if it is beneath the others.

I have struggled to come up with a simple Minimal Working Example which includes contours which actually overlap, so here is my current MWE:

list = {0.25, 0.3, 0.5, 0.7, 0.8}; t = 0.01;  
gray = 0.8; styles = {{GrayLevel[gray], Thickness[t]}, {GrayLevel[3/4 gray],Thickness[t]}, {GrayLevel[2/4 gray], Thickness[t]}, {GrayLevel[1/4 gray], Thickness[t]}, {GrayLevel[0], Thickness[t]}};  

ContourPlot[Sqrt[x^2 + y^2], {x, -1, 1}, {y, -1, 1}, Contours -> list, ContourStyle -> styles] /. _Polygon -> Sequence[]

The only "problem" with this MWE is I couldn't devise a "simple" function for which the contours overlapped.

However, when I perform this same code for my real (more complex problem) the 100% black line you see in the MWE would be drawn as if on the bottom, and the smaller value (gray) contours are drawn on top.

I have tried to simply apply

list=Reverse[list];  

after defining "list" before ContourPlot, but this does not correct the issue.

What can I do to fix this problem?

Lastly, here is an example image from one of my plots that illustrates the gray line (with smaller value) drawn atop the 100% black line (with larger value)

enter image description here

$\endgroup$
  • $\begingroup$ Apparently Mathematica always draws contours in increasing order of function value. The easiest solution I can think of is to plot the negative of the function, ContourPlot[-Sqrt[...], ..., Contours -> -list]. $\endgroup$ – Rahul Jan 13 '16 at 21:21
3
$\begingroup$

One way to do this is to create each contour separately, that then combine them via Show, which respects order. To illustrate:

Show@Table[
  ContourPlot[
   Sqrt[y x^2 + y^2]/(x y + 1) == list[[i]], {x, -1, 1}, {y, -1, 1}, 
   ContourStyle -> styles[[i]],
   ContourShading -> None],
  {i, 1, Length@list}]

plot1

Show@Reverse@Table[
  ContourPlot[
   Sqrt[y x^2 + y^2]/(x y + 1) == list[[i]], {x, -1, 1}, {y, -1, 1}, 
   ContourStyle -> styles[[i]],
   ContourShading -> None], 
  {i, 1, Length@list}]

plot2

In the lower right corner where the contours overlap, the black line is on the top in the first plot and on the bottom in the second.

$\endgroup$
  • $\begingroup$ Probably quite an elegant solution you have, but unfortunately I don't currently understand how it works well enough to generalize it to my expanded code. Is there a way to accomplish this without the pure function "#1 &," etc. stuff? Or can you help me understand how this works. Thanks! $\endgroup$ – Steve Jan 14 '16 at 17:37
  • 1
    $\begingroup$ @Steve I've changed the code to use Table and explicitly plot a contour for each entry in list with ContourStyle given by the corresponding entry in styles. The pure function from before was doing the same thing, but this way is hopefully more transparent. $\endgroup$ – Virgil Jan 14 '16 at 20:56
  • $\begingroup$ Sadly, I guess it is my (your) MWE that is failing me. The MWE works, but in my plots the argument of ContourPlot is "Sort@Re@Eigenvalues[hamiltonian]" and for some reason the change from "Contours->list" to "==list[[i]]" does not work for this. Not sure if this practically a new problem altogether and I'd be forced to submit a new thread, but if you have any idea on how I could fix this, I would definitely appreciate it! $\endgroup$ – Steve Jan 15 '16 at 20:35
  • $\begingroup$ @Steve do you mean list = Sort@Re@Eigenvalues[hamiltonian]? $\endgroup$ – Virgil Jan 16 '16 at 2:58
  • $\begingroup$ No, actually not. In my problem, hamiltonian is a matrix with 2 degrees of freedom which become the domain variables for the contour plot and the eigenvalue functional dependence on them is the function for which I take a contour plot. However, I have now made your solution work for me by simply using ",Contours->{list[[j]]}" and then making a table as you did. For some reason the "==list[[j]]" bit was not working for me. Either way, thank you very much for the help. $\endgroup$ – Steve Jan 19 '16 at 17:19
3
$\begingroup$

You can reverse the order of graphics elements too:

cp = ContourPlot[Sqrt[y x^2 + y^2]/(x y + 1), {x, -1, 1}, {y, -1, 1}, 
  Contours -> list, ContourStyle -> styles, ContourShading -> None]

enter image description here

MapAt[Reverse, cp, {1, 2, 2}]

enter image description here

$\endgroup$
  • $\begingroup$ I really like this solution because it seems the simplest minimal change to my existing code. However, I can get it to work as you did in your MWE, but it gives error in my real code. Can you help me understand the {1,2,2} arguments? I'm thinking maybe in my real code I might have more objects and need a 4-element list, etc. to solve it similarly? $\endgroup$ – Steve Jan 14 '16 at 17:32
  • $\begingroup$ @Steve 1 is a GraphicsComplex in Graphics generated by plot, 2 is a second arg of that, which is a set of primitives, and the second there contains Lines we want to flip. It's semi manual so probably not the best approach. So basically find, where those lines are and map there. $\endgroup$ – Kuba Jan 14 '16 at 17:41
0
$\begingroup$

Another way (maybe not efficient way) is to trick the ContourPlot as follows:

ContourPlot[-Sqrt[y x^2 + y^2]/(x y + 1), {x, -1, 1}, {y, -1, 1}, 
  Contours -> -list, ContourStyle -> Reverse@styles, 
  ContourShading -> None] /. Tooltip[x_, y_] :> Tooltip[x, -y]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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