# Plot columns of table if some condition is fulfilled

I have a table with data, for example

MT = {{1, 80.3, 1, 4, 68}, {2, 80.5, 1, 5.5, 102}, {3, 80.0, 0, 4.2,
78}, {4, 80.4, 0, 3, 17}, {5, 80.2, 1, 5, 180}};


I can plot column 1 against column 2 with

L1 = Table[MT[[i, 1]], {i, 1, 5}];
L2 = Table[MT[[i, 2]], {i, 1, 5}];
ListPlot[Table[{L1[[i]], L2[[i]]}, {i, 1, 5}]]


Now I want to do is the following: I want to plot column 1 against column 2 if the entry in column 3 is == 1. (So that only the points of rows 1,2,5 are shown)

Does anyone know how to do that?

Thanks alot!

-
By the way, welcome to Mathematica.SE! Please consider registering your account so that any upvotes you get on this question are added to those you might get on future questions and answers. That way, over time you will be able to do more on the site (post graphics, edit things, etc). Another tip: after posting a question stay around for a little while, to answer questions raised by commenters. This will streamline the Q&A process considerably. – VLC Oct 9 '12 at 14:30

Before I answer your actual question, let me first show you how to simplify your code a lot.

First, instead of Table[MT[[i, 1]], {i, 1, 5}] you can simply write Table[[All, 1]], which means "take all rows, but only the first column). Obviously you also can do the same with Table[MT[[i, 1]], {i, 1, 5}].

You can also get rid of your third Table by observing that you can also select a list of rows by giving a list of indices. That is, you don't need L1 and L2 at all (unless you need them for your further code, of course), and can simply write

ListPlot[MT[[All, {1, 2}]] ]


# Solution using Select

Now to plot only the rows where the third index is 3, the best way is to first generate a list which only contains those lines, and plot that. For this purpose Mathematica provides the function Select, which takes a list and a predicate function, and returns a list of all elements for which this function returns true. Your table is a list of rows, and you want to select rows, therefore you can apply Select directly to the list. This could be done as follows:

(* the predicate function *)
thirdElementIsOne[row_] := (row[[3]] == 1)

(* the sublist *)
selectedRows = Select[MT, thirdElementIsOne];

(* plot the first two columns *)
ListPlot[selectedRows[[All, {1, 2}]] ]


Now it seems quite wasteful to provide a function definition (and waste another symbol) for the second argument of Select. But Mathematica has a solution for this: pure functions (note however that Mathematica's use of the term "pure functions" don't correspond to what elsewhere is meant by that term; in other languages one usually speaks of "unnamed functions" or "lambda functions" for this concept). A pure function can be written in the form Function[argument, expression] (or, for more than one argument, Function[{arguments}, expression]). So the above code could also be written as

(* the sublist *)
selectedRows = Select[MT, Function[row, row[[3]] == 1] ];

(* plot the first two columns *)
ListPlot[selectedRows[[All, {1, 2}]] ]


But given the simplicity of the function, even this syntax seems unnecessarily verbose. Thus Mathematica offers an even terser syntax: If you write any expression followed by an &, it defines a pure function. With this syntax there's of course no way to name arguments (which can be a problem if you have nested pure functions). Instead, you write the first argument as # or #1 (both are equivalent; # is shorter, but #1 is more consistent if you have more arguments), the second one as #2, etc.

In the case above, there is just one argument (the row), therefore you can write

(* the sublist *)
selectedRows = Select[MT, #[[3]] == 1&];

(* plot the first two columns *)
ListPlot[selectedRows[[All, {1, 2}]] ]


Now the expression is so short that it again doesn't seem to make sense to store it in a separate variable (unless you need it again later), therefore let's just insert it in the ListPlot command to get

ListPlot[Select[MT, #[[3]] == 1&][[All, {1, 2}]] ]


# Solution using Position

If your table gets large, and there are many rows containing 1 in the third column, you might not want to actually copy all that data. In that case, you might want to first get a list of row indices, and use that to select the data to plot.

To this end, we need the indices of rows where the third column is 1. To Get a list of indices, there's the Mathematica function Position. It takes a list and a pattern, and gives a list of indices for elements matching the pattern.

Now what a pattern is and how they are matched is a topic in itself, however in this case all you have to know is that to match a given specific expression you normally use the expression itself as pattern.

Now the list we need to examine is the third column of ML, which, as described in the beginning, can be obtained as MT[[All, 3]]. The expression we want to select for is 1. Therefore the expression we need is

Position[MT[[All, 3]], 1]
(*
==> {{1}, {2}, {5}}
*)


However as you can see above, this does not return a list of indices, but a list of one-element list of indices. This is because in general, you need several indices to specify a position (e.g. if we had applied it to ML itself, you would need two indices to specify the position of any 1 in it), and thus the elements returned are lists giving all the elements. However, knowing that our list has only one-element sublists, we can use Flatten to get rid of the extra level:

Flatten@Position[MT[[All, 3]], 1]
(*
==> {1, 2, 5}
*)


(The @ syntax I've used here is just another way to apply a function to a single argument, which saves you a keystroke: Flatten@x is exactly equivalent to Flatten[x].)

Now that we have a list of indices, we can just use it as first index to ML:

ListPlot[MT[[Flatten@Position[MT[[All, 3]], 1], {1, 2}]] ]

-
 Well done, a very useful intro lecture! – VLC Oct 9 '12 at 14:58 @VLC: Thank you. I hope you find the addition well done, too. – celtschk Oct 9 '12 at 15:12 Wow thank you very much. This is really very usful :) – user3053 Oct 9 '12 at 15:41 @user3053: You're welcome. – celtschk Oct 9 '12 at 15:54 I love your "The Missing Manual" answers :) – cormullion Oct 9 '12 at 17:48
show 1 more comment

In addition to celtschk's fine answer I'll show Cases and Pick.

MT = {{1, 80.3, 1, 4, 68}, {2, 80.5, 1, 5.5, 102}, {3, 80.0, 0, 4.2, 78},
{4, 80.4, 0, 3, 17}, {5, 80.2, 1, 5, 180}};

Cases[MT, {a_, b_, 1, ___} :> {a, b}]

{{1, 80.3}, {2, 80.5}, {5, 80.2}}

Pick[MT, MT[[All, 3]], 1][[All, {1, 2}]]

{{1, 80.3}, {2, 80.5}, {5, 80.2}}


(In this formulation Pick will usually be the faster of the two.)

Complete plot expression including a couple of options you may find useful:

ListPlot[
Cases[MT, {a_, b_, 1, ___} :> {a, b}],
PlotStyle -> PointSize[Large],
]


If my condition when to plot is not only 3rd column == 1 but instead something like 5th column larger than 100. I managed to do this using Select, but is there also a way to do this using Cases or Pick?

Yes. For Cases you can use Condition or PatternTest as discussed here to specify the pattern. For example:

Cases[MT, {a_, b_, 1, _, x_ /; x > 100} :> {a, b}]

{{2, 80.5}, {5, 80.2}}


Pick gets a bit tricky here because it looks at the entire expression tree (by default Cases operates at level 1). At first it seems that we could theoretically do:

Pick[MT, MT[[All, {3, 5}]], {1, x_ /; x > 100}]  (* failure *)


But we get this error message:

Pick::incomp: Expressions <<>> and <<>> have incompatible shapes. >>

This is because Pick is trying to compare the expressions at all levels, and it fails to map MT and MT[[All, {3, 5}]] because, as reported, they are not the same shape. Here is a simple example of where this behavior of Pick is useful:

lst = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}};
mask = {{1, 0, 1}, {0, 1, 0}, {1, 1, 0}, {0, 0, 0}};


{{1, 3}, {5}, {7, 8}, {}}


We can still make Pick work in your application but we need to make sure that the second argument is a simple list rather than an array. This code will make use of Function (short form &), Slot (#3 and #5) and Apply at level one (@@@), as well as Span (;;).

Pick[MT, #3 == 1 && #5 > 100 & @@@ MT][[All, ;; 2]]


{{2, 80.5}, {5, 80.2}}

-
 Nice. I didn't know about Pick; it is definitely superior to the Position solution. The Cases solution is also quite elegant. – celtschk Oct 9 '12 at 15:52 @celtschk thanks; Pick is really powerful, be sure to learn it well! – Mr.Wizard♦ Oct 9 '12 at 15:55 Also thanks to you. Maybe one more follow up question: If my condition when to plot is not only 3rd column == 1 but instead something like 5th column larger than 100. I managed to do this using Select, but is there also a way to do this using Cases or Pick? – user3053 Oct 9 '12 at 16:37 @user3053 I added further explanation and examples of these functions based on your requested condition. – Mr.Wizard♦ Oct 9 '12 at 17:35 fantastic :) Thank you so much – user3053 Oct 9 '12 at 18:24

You can use Select[] to select your desired rows and then plot:

ListPlot[Select[MT, #[[3]] == 1 &][[All, {1, 2}]]]

-
 Yes this does what I wanted, thanks! – user3053 Oct 9 '12 at 15:39

My effort:

ind = Flatten[Position[MT[[#, 3]] == 1 & /@ Range[5], False]];
newdata = Drop[MT, ind][[All, {1, 2}]]
ListLinePlot[newdata]