4
$\begingroup$

I have data in the form:

{{0, 3, 4}, {1, 3, -1}, {2, 4, -1}, ...}

and I would like to implement something similar to ColorFunction for the style of a line. Basically I would like to plot a standard line plot using the first two entries of each point {x, y, ..}, and then decide on the line style using the 3rd {.., .., z}.

Specifically I would like to plot dashed lines when the 3rd entry is positive and filled lines when negative, formed as one continuous curve.

EDIT: to clarify, there will be large regions where the 3rd entry is consistently positive or negative, so its purpose is to set the style for those regions. This method wouldn't really work for situations where the 3rd value oscillates between the two.

Many thanks, Hemmer

$\endgroup$
2
  • 5
    $\begingroup$ Welcome to Mathematica.SE! It is not very clear what you are trying to obtain. The 3rd entry is specific for a certain point, but you want to specify the style of a line segment that connects two points. Which two points? $\endgroup$
    – VLC
    Commented Oct 8, 2012 at 15:51
  • $\begingroup$ Hi there. I hadn't actually given thought to which two, I guess applying the line between the current point and the next. As the are large contiguous regions of positive & negative, I hadn't worried about that! $\endgroup$
    – Hemmer
    Commented Oct 8, 2012 at 16:47

4 Answers 4

6
$\begingroup$

This is my interpretation of your question: the 3rd element of a point specifies the style of the line that connects that point with the next one.

data = Table[{i, RandomInteger[{1, 10}], RandomChoice[{-1, 1}]}, {i, 20}];
setsN = DeleteCases[Table[If[data[[i, 3]] < 0, data[[i ;; i + 1, {1, 2}]], {}], {i, 
    Length[data] - 1}], {}];
setsP = DeleteCases[Table[If[data[[i, 3]] > 0, data[[i ;; i + 1, {1, 2}]], {}], {i, 
    Length[data] - 1}], {}];
Show[
    ListLinePlot[setsN, PlotStyle -> {{Thick, Black}}],
    ListLinePlot[setsP, PlotStyle -> {{Thick, Black, Dashed}}]
]

enter image description here

$\endgroup$
2
  • $\begingroup$ Thanks, this is what I was looking for. I had wondered if there was an inbuilt way to do this without manually processing the data beforehand, but this will certainly do the job! I guess the style of the line doesn't map naturally to continuous functions in the same way a ColorFunction might. $\endgroup$
    – Hemmer
    Commented Oct 8, 2012 at 16:49
  • 1
    $\begingroup$ @Hemmer You're welcome. Now that is clear what is your desired output there might be someone else that could provide a more direct approach to the question. $\endgroup$
    – VLC
    Commented Oct 8, 2012 at 16:50
3
$\begingroup$

Correction!

Sorry for misunderstanding. Here is a updated code

Options[plot] = Options[ListPlot];
plot[data_, options : OptionsPattern[ListPlot]] := Block[{line},
  line[{pt1_, pt2_}] := Module[
   {z},
   z = pt1[[3]];
   {
    If[z >= 0, Dashed, Thickness[0.0045]], 
    If[z >= 0, Orange, Cyan],
    Line[(#[[1 ;; 2]]) & /@ {pt1, pt2}]
   }
  ];
Show[ListPlot[data[[All, 1 ;; 2]], options],
     Graphics[line[#] & /@ Partition[data, 2, 1]]
    ]
]

Now we test it. We intentionally use PlotStyle -> None to hide the data points!

fun[x_] := Sin[13 x] + Cos[7 x];
data = Table[{i, a = fun[ i]; a, If[ a >= 0, 1, -1]}, {i, - Pi, Pi,2. Pi/120}];
plot[data, Frame -> True, Axes -> False, PlotStyle -> None]

enter image description here

$\endgroup$
0
2
$\begingroup$

It seems to me that using Graphics would be easier than messing with LinePlots.

We can define any number of styles with a function:

ClearAll[lineStyle];
lineStyle[z_] /; z < 0 := {Orange, Dashed};
lineStyle[z_] /; z > 0 := {Blue, Thick};
lineStyle[z_] := {Black};

Then create a function to plot data using this style:

ClearAll[styledPlot];
styledPlot[data_, o : OptionsPattern[]] := Graphics[Partition[data, 2, 1] /.
  {{x1_, y1_, z1_}, {x2_, y2_, z2_}} :> Append[lineStyle[z1], Line[{{x1, y1}, {x2, y2}}]], 
    Evaluate[FilterRules[{o}, Options[Graphics]]]]

In use:

styledPlot[
  Table[{i, RandomInteger[{1, 10}], RandomInteger[{-5, 5}]}, {i, 20}], 
  Frame -> True, PlotLabel -> "Styled"]

1

$\endgroup$
2
  • $\begingroup$ Might be better to use something like lineStyle[z_?Negative] or lineStyle[z_?Positive] in the definitions. no? $\endgroup$ Commented Oct 8, 2012 at 23:36
  • $\begingroup$ @J.M. I was trying to show how to be a bit more general than just positive or negative. $\endgroup$
    – wxffles
    Commented Oct 8, 2012 at 23:49
1
$\begingroup$

Using a minor modification of this answer to another question, Mesh, MeshFunctions, MeshStyle and MeshShading options can be used to specify the directives for different pieces of the lines in ListLinePlot.

Data:

 breaks = Join[{0}, Sort@RandomInteger[{2, 99}, 5], {100}];
 i = 2; arg3 = (j = i++; ConstantArray[(-1)^j, {#}]) & /@ Differences[breaks];
 data = {Range[100], RandomInteger[100, {100}], Flatten@arg3} // Transpose;

Calculate mesh points:

 meshpoints = Most@Accumulate[Length /@ Split[data, Last[#1] == Last[#2] &]];

... plot:

ListLinePlot[data[[All, ;; 2]], PlotStyle -> Blue,ImageSize -> 450, 
  Mesh -> {meshpoints},
  MeshStyle -> None, 
  MeshFunctions -> (#1 &), 
  MeshShading -> {Thick, Directive[Thick, Dashed]}]

enter image description here

$\endgroup$
2
  • $\begingroup$ I think that this approach fails if the entries in 3rd position are not part of contiguous regions of positive or negative values. And, the assignment on which segments are dashed and which continuous is arbitrary because it depends on the category of the first segment. $\endgroup$
    – VLC
    Commented Oct 9, 2012 at 9:29
  • $\begingroup$ @VLC, both concerns can be fixed easily: using .01 + meshpoints instead of meshpoints is enough to care of the cases where the third column values alternate between positive and negative at every observation. And reversing the list Thick, Directive[Thick, Dashed] based on the sign of data[[1,1]], that is, using omething like MeshShading -> Switch[Sign[data[[1, 3]]], 1, Identity@#, _, Reverse@#] &@{Thick, Directive[Thick, Dashed]} takes care of the second concern. $\endgroup$
    – kglr
    Commented Oct 11, 2012 at 19:44

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.