6
$\begingroup$

I have data that I would like to graph that alternates colors when a condition is identified. For example, say I have the following list:

templist={{5,1},{5,2},{5,3},{1,4},{1,5},{1,6},{4,7},{4,8},{5,9},{5,10}};

where the first value in each point is a categorical identifier and the second value is what I would like to graph. Is there a way to make a function that will graph the second values in the data and toggle between two colors when the categorical value changes?

I have tried to use the show function, but I'm unsure of how to do that properly in this example as the number of different categorical values will differ for each data set I'd like to apply this to.

EDIT: I would like to use something akin to ListLinePlot as the practical application of this function will involve trending data.

$\endgroup$
  • $\begingroup$ look at SplitBy $\endgroup$ – george2079 Jun 16 '17 at 11:44
  • $\begingroup$ @george2079 I have looked at SplitBy. My problem isn't so much with the separating of the values but the coloring aspect of the graph(s). $\endgroup$ – HaschelSmithers Jun 16 '17 at 11:51
5
$\begingroup$
list = 
   {{5, 1}, {5, 2}, {5, 3}, {1, 4}, {1, 5}, {1, 6}, {4, 7}, {4, 8}, {5, 9}, {5, 10}}

cat = Split[First /@ list];

col = Flatten@Transpose[{cat[[1 ;; ;; 2]] /. x_Integer -> Blue, 
    cat[[2 ;; ;; 2]] /. x_Integer -> Red}];

ListLinePlot[
 Last /@ list,
 GridLines -> Automatic,
 Mesh -> Length@list - 1,
 MeshShading -> col,
 PlotStyle -> Directive[PointSize[0], Thick]]

enter image description here

$\endgroup$
  • $\begingroup$ This works partially well, but I'd like the color change to be maintained through the new part instead of only on the first different value. $\endgroup$ – HaschelSmithers Jun 16 '17 at 12:10
  • $\begingroup$ Is this now what you have in mind? $\endgroup$ – eldo Jun 16 '17 at 12:44
  • $\begingroup$ This is indeed what I was looking for. $\endgroup$ – HaschelSmithers Jun 16 '17 at 12:55
  • $\begingroup$ @eldo What is your Mma version? I'm using 11.1 and your PointSize directive is not suppressing the mesh for me. $\endgroup$ – Alan Jun 16 '17 at 13:29
  • $\begingroup$ I have version 10.0 $\endgroup$ – eldo Jun 16 '17 at 15:53
2
$\begingroup$
templist = {{5, 1}, {5, 2}, {5, 3}, {1, 4}, {1, 5}, {1, 6}, {4, 
    7}, {4, 8}, {5, 9}, {5, 10}};
catpts = MapIndexed[Append[#1, First@#2] &, templist]
cats = SplitBy[catpts, First]
data = Map[Reverse@*Rest, cats, {2}]
ListLinePlot[data, PlotStyle -> {Red, Blue}]

enter image description here

$\endgroup$
1
$\begingroup$

First prepare the data, separating it into different lists according to the labels. In this process we also add the x coordinate to each point, so that ListPlot can correctly draw them regardless of their position in a list:

templist = {{5, 1}, {5, 2}, {5, 3}, {1, 4}, {1, 5}, {1, 6}, {4, 7}, {4, 8}, {5, 9}, {5, 10}};

dataByLabel = Association[(# -> {}) & /@ Union[First /@ templist]];
Do[
  AppendTo[dataByLabel[templist[[idx, 1]]], {idx, templist[[idx, 2]]}],
  {idx, Range@Length@templist}
  ];

This gathers the data in the association dataByLabel. To plot it as requested just use ListPlot:

ListPlot @ Values @ dataByLabel

With this method is also easier to successively handle the data, as they are now nicely gathered in dataByLabel.

$\endgroup$
  • $\begingroup$ This is definitely along the lines of what I'm looking for, but is there any way to make a line graph out of this? If I change the graph function to ListLinePlot the line is only the first color. $\endgroup$ – HaschelSmithers Jun 16 '17 at 12:12
0
$\begingroup$

While @eldo's answer was initially useful to me, I found that the color transitions not being exactly on the point that they transitioning on was quite irritating for me. When using data with a size of thousands, it's an irrelevant factor, but I came up with a way that negates this problem. The downside is that the image takes significantly longer to graph the more categories there are, but that should also be a moot point with smaller sample sizes.

The first block is only variable assignment.

templist = {{5, 1}, {5, 2}, {5, 3}, {1, 4}, {1, 5}, {1, 6}, {4, 
    7}, {4, 8}, {5, 9}, {5, 10}};
lowerBound = 1; upperBound = 1; graphInfo = {};    

The second block creates a list containing the lower and upper bounds of each sublist of the data, as well as the color for that sublist.

For[i = 1, i < Length[templist], i++,
 If[templist[[i, 1]] != templist[[i + 1, 1]],
  {AppendTo[
    graphInfo, {lowerBound, upperBound, 
     If[Mod[Length[graphInfo], 2] == 1, Green, Red]}], 
   lowerBound = upperBound, upperBound++},
  upperBound++]]

graphInfo
{{1, 3, RGBColor[1, 0, 0]}, {3, 6, RGBColor[0, 1, 0]}, {6, 8, 
  RGBColor[1, 0, 0]}, {8, 10, RGBColor[0, 1, 0]}}

The third and fourth blocks of code create another list that contains the actual data as well as the color for each sublist.

AppendTo[graphInfo, {lowerBound, upperBound, 
   If[Last[graphInfo][[3]] == Red, Green, Red]}];
graphsData = {};
For[j = 1, j <= Length[graphInfo], j++, 
 AppendTo[graphsData, {Take[
    templist[[All, 2]], {graphInfo[[j, 1]], graphInfo[[j, 2]]}], 
   graphInfo[[j, 3]]}]]

counter = 0;
For[l = 1, l <= Length[graphsData], 
 l++, {graphsData[[l, 
     1]] = {Table[{counter + i, graphsData[[l, 1, i]]}, {i, 
      Length[graphsData[[l, 1]]]}]}, 
  counter = counter + Length[graphsData[[l, 1, 1]]] - 1}]

graphsData
{{{{{1, 1}, {2, 2}, {3, 3}}}, RGBColor[
  1, 0, 0]}, {{{{3, 3}, {4, 4}, {5, 5}, {6, 6}}}, RGBColor[
  0, 1, 0]}, {{{{6, 6}, {7, 7}, {8, 8}}}, RGBColor[
  1, 0, 0]}, {{{{8, 8}, {9, 9}, {10, 10}}}, RGBColor[0, 1, 0]}}

The final block serves to deploy all of the sublists in graphs.

graphs = {};
For[x = 1, x <= Length[graphsData], x++, 
 AppendTo[graphs, 
  ListLinePlot[graphsData[[x, 1]], PlotStyle -> graphsData[[x, 2]]]]]
Show[graphs, PlotRange -> All, GridLines -> Automatic]

And voila: enter image description here

I have yet to pare down the code to a cleaner state, but it works.

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