5
$\begingroup$

Let's define some sample data

data = {{-3, -1}, {-2, -1}, {-1, -1}, {-0.2, -0.2}, {0, 0}, {0.5, 0.5},
        {2, 2}, {3, 2}, {4, 2}};

and create the corresponding list plot

L0 = ListPlot[data, Joined -> True, PlotStyle -> {Black, Thick}]

enter image description here

Now, I want the following: change the color at different segments of the thick line. For example:

  • for $-2.4 < x < -1.1$ ---> red thick
  • for $-0.2 < x < 0.94$ ---> blue thick
  • for $2.22 < x < 3.4$ ---> green thick
  • in all other cases ---> black thick

IMPORTANT NOTE: The real data contain thousands of pairs which cannot be separated into sections. Only the intervals on the x axis are known. So, I want a continuous line with different colors in each segment.

What would be an elegant and quick way to do this?

Many thanks in advance!

$\endgroup$
5
  • $\begingroup$ The simplest? Separate the data into sections, run ListPlot[sectioned, PlotStyle -> {Directive[Thick, Blue], Directive[Thick, Blue], Directive[Thick, Green], Directive[Thick, Black]}] where the styles in PlotStyle are in the correct order. $\endgroup$
    – rcollyer
    Oct 10, 2016 at 17:59
  • $\begingroup$ Should be doable with the judicious use of ColorFunction and Piecewise[]. $\endgroup$ Oct 10, 2016 at 18:03
  • $\begingroup$ @rcollyer It's not that simple! The real data contain thousands of pairs which cannot be separated into sections. Only the intervals on the $x$ axis are known. So, I want a continuous line with different colors in each segment. $\endgroup$
    – Vaggelis_Z
    Oct 10, 2016 at 18:03
  • $\begingroup$ @J.M. i thought that too but when you try it, Mathematica blends the colors over and does not make a sharp border.. $\endgroup$ Oct 10, 2016 at 18:09
  • $\begingroup$ You're correct, the boundary points represent a problem. I like the Mesh solutions propose below. Far simpler. $\endgroup$
    – rcollyer
    Oct 10, 2016 at 18:43

3 Answers 3

6
$\begingroup$
data = {{-3, -1}, {-2, -1}, {-1, -1}, {-0.2, -0.2}, {0, 0}, {0.5, 0.5},
        {2, 2}, {3, 2}, {4, 2}};

ListPlot[data, Joined -> True, PlotStyle ->Thick, 
 (* MeshFunctions -> {# &},*) 
 Mesh -> {{-2.4, -1.1, -0.2, 0.94, 2.22, 3.4}}, 
 MeshStyle -> PointSize[0], 
 MeshShading -> Riffle[{Red, Blue, Green}, Black, {1, -1, 2}]]

Mathematica graphics

$\endgroup$
7
  • $\begingroup$ Great answer! What if there is no gap between blue and green? Will it still work or there will be a black point? $\endgroup$
    – BlacKow
    Oct 10, 2016 at 18:47
  • 1
    $\begingroup$ I like that. I wondered why you used MeshFunctions->{#&}. Is there a reason for that? $\endgroup$ Oct 10, 2016 at 18:51
  • $\begingroup$ @BlacKow, this works only for the case with no overlaps. If the list of breakpoints have duplicate elements as in {-2.4, -1.1, -0.2, 0.94, .94, 3.4} then you can use MeshShading->{Black, Red, Black, Blue, Green} $\endgroup$
    – kglr
    Oct 10, 2016 at 18:55
  • 1
    $\begingroup$ @JulienKluge, good point; the default value of MeshFunctions is #&, so it is redundant. $\endgroup$
    – kglr
    Oct 10, 2016 at 18:58
  • 1
    $\begingroup$ @Vaggelis_Z, it inserts Black in every other position in the list {Red,Blue, Green} starting from position one. Without it Riffle[{Red,Blue, Green}, Black] would give {Red, Black,Blue, Black, Green}. See Riffle $\endgroup$
    – kglr
    Oct 10, 2016 at 19:11
3
$\begingroup$

We use an unscaled ColorFunction with a Piecewise which uses your definitions. Interestingly one have to alter the Mesh-settings to allow a sharp color-border otherwise it will blend over.

L0=ListPlot[data,Joined->True,PlotStyle->Thick,ColorFunction->Function[{x,y},Piecewise[{{Red,-2.4<x<-1.1},{Blue,-0.2<x<0.94},{Green,2.22<x<3.4}},Black]],ColorFunctionScaling->False,Mesh->200,MeshShading->{Automatic},MeshStyle->None]

enter image description here

$\endgroup$
4
  • $\begingroup$ Is it just my impression or the middle part is not so smooth? I see it like a bunch of dots... $\endgroup$
    – Vaggelis_Z
    Oct 10, 2016 at 18:35
  • $\begingroup$ Uhm well, it looks good to me on my machine. Try to Increase the Mesh-option. Can you show a screenshot? $\endgroup$ Oct 10, 2016 at 18:38
  • $\begingroup$ The Mesh-option does not have any affect. Try to enlarge the image you posted and you will see that the middle line is not a real straight line! It looks like a join of dots or something else! $\endgroup$
    – Vaggelis_Z
    Oct 10, 2016 at 18:43
  • $\begingroup$ I'm on OSX, MMA 11.0.0.0 and I see the same behavior, but only for this answer. Other options show a smooth curve. $\endgroup$
    – N.J.Evans
    Oct 10, 2016 at 19:07
2
$\begingroup$

As alternative you can follow up idea of separation. Since we don't know if you have the endpoints of your regions in your data set , we can use Interpolation and then break it up into several pieces.

limitF[f_, {xmin_, xmax_}] := 
  Piecewise[{{f[#], xmax > # > xmin}}, Infinity] &;
data = {{-3, -1}, {-2, -1}, {-1, -1}, {-0.2, -0.2}, {0, 0}, {0.5, 
    0.5}, {2, 2}, {3, 2}, {4, 2}};
fun = Interpolation[data, InterpolationOrder -> 1];
separated = 
  limitF[fun, #] & /@ {{-2.4, -1.1}, {-0.2, 0.94}, {2.2, 3.4}};

So separated is list of functions that present fun in different regions.

Plot[Evaluate[{fun[x]}~Join~(#[x] & /@ separated)], {x, -3, 4}, 
 PlotStyle -> {Directive[Thick, Black], Directive[Thick, Red], 
   Directive[Thick, Blue], Directive[Thick, Green]}]

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.