7
$\begingroup$

Here is an example:

ContourPlot[Sin[y - x^2] == 0, {x, -1, 1}, {y, -10, 10}]

stupid example

Because all these separate lines come from the same contour line Sin[y - x^2] == 0, ColorFunction color the contour lines as the same color. This is the correct behavior for most contour plots. However, for this example, color the same contour line with different color make sense. How can I do it in Mathematica?

Update

Let's make this question even more silly, because I actually have a figure must be draw part by part. Consider following code:

Show[{ContourPlot[Sin[y - x^2] == 0, {x, -2, 0}, {y, -10, 10}], 
  ContourPlot[Sin[-y - x^2] == 0, {x, 0, }, {y, -10, 10}]}, 
 PlotRange -> All]

stupid 3

The question is the same, how to color the lines with different colors?

$\endgroup$
10
$\begingroup$

If it is acceptable to order the lines by the y value of the first point in each contour we can use a modification of Pickett's method:

plot = Show[{ContourPlot[Sin[y - x^2] == 0, {x, -1, 0}, {y, -10, 10}], 
   ContourPlot[Sin[-y - x^2] == 0, {x, 0, 1}, {y, -10, 10}]}, PlotRange -> All];

cols = {Red, Black, Blue, Orange, Green, Pink, Brown};

Normal[plot] /. {a___, l : Longest[Line[_] ..], b___} :>
  {a, Riffle[cols, {l} ~SortBy~ Extract[{1, 1, 2}] ], b}

enter image description here

Or using xslittlegrass's restylePlot2 as the base method:

restyleWithSort[p_, op : OptionsPattern[ListLinePlot]] :=
  ListLinePlot[Cases[Normal@p, Line[x__] :> x, ∞] ~SortBy~ Extract[{1, 2}], 
   op, Options[p]]

Show[restyleWithSort /@ {
   ContourPlot[Sin[y - x^2] == 0, {x, -1, 0}, {y, -10, 10}],
   ContourPlot[Sin[-y - x^2] == 0, {x, 0, 1}, {y, -10, 10}]
   },
 PlotRange -> All
]
$\endgroup$
  • $\begingroup$ +1, using Normal to flatten out GraphicsComplex is new to me. $\endgroup$ – C. E. Jun 19 '15 at 4:05
  • 1
    $\begingroup$ Change the x range to (-2,2), a continuous line will be colored to two different colors. Because, the lowest segment only appear in the left side. $\endgroup$ – Kattern Jun 19 '15 at 4:33
  • 1
    $\begingroup$ @Kattern I anticipated such problems which is why I specifically wrote "If it is acceptable." This is a puzzle I haven't faced before (that I can recall) and I don't have a nice solution for it. Sorry. :-/ $\endgroup$ – Mr.Wizard Jun 19 '15 at 6:01
  • $\begingroup$ @Mr.Wizard it is all right. You have already helped a lot. I can manage the special cases using Inkscape. Only 10% of the figures have the problem, it is about 10 figures. It is not hard to adjust them by hand. Thanks in advance! $\endgroup$ – Kattern Jun 19 '15 at 6:17
  • 1
    $\begingroup$ @Kattern Do you know that you can edit line colors from within Mathematica as well? Perhaps I should have included that in my answer but I assumed you were looking for a programmatic solution. $\endgroup$ – Mr.Wizard Jun 19 '15 at 6:19
7
$\begingroup$

You can manipulate the expression manually:

plot = ContourPlot[
   Sin[y - x^2] == 0, {x, -1, 1}, {y, -10, 10}
   ];

plot /. {a___, l : Longest[Line[_] ..], b___} :>
  {a, Riffle[Array[ColorData[97], Length@{l}], {l}], b}

Mathematica graphics

In order to find the pattern it helps to look at plot // FullForm. ColorData[97] is the list of default colors for Mathematica 10. Here is another answer I wrote two days ago, which also shows how this technique can be used.

$\endgroup$
  • 1
    $\begingroup$ I will check the answer later. It seems I cannot get control of the color used in the lines, like Black for the lowest line, Red for the second. $\endgroup$ – Kattern Jun 19 '15 at 3:36
  • $\begingroup$ @Kattern It seem that the contour lines are not produced in that order. In your application is it acceptable to perform a simple sort on them? $\endgroup$ – Mr.Wizard Jun 19 '15 at 3:42
  • $\begingroup$ @Mr.Wizard Yes, I noticed that as well. And please also see the updated question. $\endgroup$ – Kattern Jun 19 '15 at 3:46
5
$\begingroup$
func[cplot_, cf_, s_] := With[{cp = cplot},
  pt = cp[[1, 1]];
  lines = Cases[cp, Line[x__] :> x, -1];
  max = Max[#[[All, 2]]] & /@ (Part[pt, #] & /@ lines);
  Show[Graphics[
    GraphicsComplex[pt, 
     MapThread[{cf[Abs[Rescale[#1, {Min[max], Max[max]}] - s]], Thick,
         Line[#2]} &, {max, lines}]], Frame -> True, 
    AspectRatio -> Full]]
  ]

For this example:

p1 = ContourPlot[Sin[y - x^2] == 0, {x, -1, 0}, {y, -10, 10}];
p2 = ContourPlot[Sin[-y - x^2] == 0, {x, 0, 1}, {y, -10, 10}];
Manipulate[
 Show @@ (func[#, color, s] & /@ {p1, p2}), {{color, 
   Hue}, {Hue -> "Hue", ColorData["Rainbow"] -> "Rainbow", 
   ColorData["Pastel"] -> "Pastel"}}, {{s, 0, "invert"}, {0, 1}}]

enter image description here

$\endgroup$
  • $\begingroup$ Woo, this one is pretty hard to understand. $\endgroup$ – Kattern Jun 19 '15 at 6:18
  • 1
    $\begingroup$ @Kattern (i) I take each ContourPlot and decompose it into coordinates and contour lines (ii) in order to deal with gradient of colour varying with y, I take the maximum y for each line (which has 1-1 correspondence with line) and put in max (iii) I then use this (rescaled) as an argument for desired color function matched with line (iv) then recompose into GraphicsComplex (v) I then map to the separate plots and combine with Show. I prefer Mr. Wizard's answer, and have up voted it. $\endgroup$ – ubpdqn Jun 19 '15 at 6:23
  • $\begingroup$ @Kattern this worked nicely for this example as the separation by y was very easy but more complex examples may require other better approaches...hope it allows you to play around and get what you want. $\endgroup$ – ubpdqn Jun 19 '15 at 6:26
  • $\begingroup$ Thanks for your explanations! The (ii) and (iii) steps are not easy to understand. I will explore your code to understand the mechanism. Thanks again! $\endgroup$ – Kattern Jun 19 '15 at 6:29
  • 1
    $\begingroup$ ...and upvoted Pickett's of course (as basis) $\endgroup$ – ubpdqn Jun 19 '15 at 6:38
4
$\begingroup$

Not sure if this will help in other examples but you can do it like this:

sol = (y /. Solve[Sin[x^2 - y] == 0, GeneratedParameters -> a] // 
     Normal) /. a -> (a &);
fun = Flatten@Table[sol, {a, -2, 1}];

p1 = Plot[fun, {x, -1, 0}, Axes -> False, Frame -> True, 
  PlotStyle -> Directive[Dashed, Thick]];
p2 = ContourPlot[Sin[y - x^2] == 0, {x, -1, 0}, {y, -10, 10}, 
  ContourStyle -> Black];
Show[p2, p1]

enter image description here

$\endgroup$
  • $\begingroup$ This one is nice if the analytical expression can be solve by Solve. NSolve in this case is not handy. $\endgroup$ – Kattern Jun 19 '15 at 7:03
2
$\begingroup$

MeshStyle + MeshFunctions

colors = ColorData[97, "ColorList"][[;; 15]];

ContourPlot[x , {x, -1, 1}, {y, -10, 10},  Contours->{},
 MeshFunctions -> {Sin[#2 - #^2] &}, Mesh -> {{0}},
 MeshStyle -> ({Thick, First[colors = RotateRight[colors]], #} &), 
 BaseStyle->FaceForm[]]

enter image description here

OP's second example can be handled in the same way using a Piecewise mesh function with some adjustment to ensure continuity at 0:

ContourPlot[x , {x, -2, 2}, {y, -10, 10}, Contours -> {}, 
MeshFunctions -> {Piecewise[{{Sin[-#2]-Sin[#2]+Sin[#2 - #^2] , # <= 0},
  {Sin[-#2 - #^2] , # >= 0}}]&}, Mesh -> {{0}}, 
 MeshStyle -> ({Thick, First[colors = RotateRight[colors]], #} &),
 BaseStyle -> FaceForm[]]

enter image description here

$\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.