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$
1
  • 1
    $\begingroup$ Related: (70102) $\endgroup$
    – Mr.Wizard
    Jul 1, 2015 at 20:24

5 Answers 5

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$
6
  • $\begingroup$ +1, using Normal to flatten out GraphicsComplex is new to me. $\endgroup$
    – C. E.
    Jun 19, 2015 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, 2015 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, 2015 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, 2015 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, 2015 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$
3
  • 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, 2015 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, 2015 at 3:42
  • $\begingroup$ @Mr.Wizard Yes, I noticed that as well. And please also see the updated question. $\endgroup$
    – Kattern
    Jun 19, 2015 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$
5
  • $\begingroup$ Woo, this one is pretty hard to understand. $\endgroup$
    – Kattern
    Jun 19, 2015 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, 2015 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, 2015 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, 2015 at 6:29
  • 1
    $\begingroup$ ...and upvoted Pickett's of course (as basis) $\endgroup$
    – ubpdqn
    Jun 19, 2015 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$
1
  • $\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, 2015 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 and acknowledge that you have read and understand our privacy policy and code of conduct.

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