Return columns with for rows containing a range of values

5 views (last 30 days)
I have a series of pressure taps from a wind tunnel test. The values are displayed in a 4x500 matrix (Tap #, Face #, X, Y). Where Tap # is the pressure tap number, Face # is the building face number, X & Y are the 2D coordinates of the building.
I am looking for the pressure tap numbers for a specific location on the building. How do a return all the columns that contain:
Face # = 3. X coordinates: 0 <= X <= 2.5. Y coordinates: O <= X <= 2.5
Thanks!

Answers (2)

dpb
dpb on 28 Feb 2014
Edited: dpb on 1 Mar 2014
Given the ranges for x and y as _lo|hi, respectively, and the specific face as F--
ix=x(:,2)==F & iswithin(x(:,3),xlo,xhi) & iswithin(x(:,4,ylo,yhi);
taps=x(ix,1);
where iswithin is my helper function to reduce higher-level complexity (otherwise known as "syntactic sugar" :) )
function flg=iswithin(x,lo,hi)
% returns T for values within range of input
% SYNTAX:
% [log] = iswithin(x,lo,hi)
% returns T for x between lo and hi values, inclusive
flg= (x>=lo) & (x<=hi);
You can, of course, dispense with the intermediary logical addressing array if you can keep association of the expression as an index straight as you try to write it. :)
I find it much easier to build the expression and then use it and often one finds use for the index array elsewhere, anyway.
ADDENDUM:
If you have the Statistics Toolbox, the dataset object has the facility to write such multiple cases by creating a structure with named fields. You can also do that manually with more effort if there are going to be a very large number of these queries. Otherwise, the general pattern is as outlined above; you can, of course, again always generalize to a higher level for simplification of the usage.
ERRATUM:
I didn't read carefully enough, I presumed one would organize by column w/ rows being observations rather than vice versa. Swap the order of the array indices--
ix=x(2,:)==F & iswithin(x(3,:),xlo,xhi) & iswithin(x(4,:),ylo,yhi);
taps=x(1,ix);
  2 Comments
Tucker
Tucker on 1 Mar 2014
I don't understand. I used a very inefficient, but simple method. Essentially I need to get the columns (which have the tap #, face # and X, Y coordinates) for an area defined by the X,Y coordinates (i.e. the 3rd and 4th row). If A is the original matrix...
A1 = A(:,A(3,:)>=0)
A2 = A1(:,A1(3,:)<=0)
A3 = A2(:,A2(4,:)>=116.5)
A4 = A3(:,A3(4,:)<=124.5)
.. In order to retrieve the columns that fall within the coordinates
0 <= X <= 8 (Row 3)
116.5 <= Y <= 124.5 (Row 4)
Can this be done in one line??
dpb
dpb on 1 Mar 2014
Edited: dpb on 1 Mar 2014
I don't know what could be simpler than the one-line expression to return the desired index. I do see that I mistakenly transposed the direction so instead of
ix=x(:,2)==F & iswithin(x(:,3),xlo,xhi) & iswithin(x(:,4,ylo,yhi);
I'd write
iy=x(2,:)==F & iswithin(x(3,:),xlo,xhi) & iswithin(x(4,:),ylo,yhi);
taps=x(1,iy);
If you're adamant about it being a one-liner that'd be
taps=x(1,x(2,:)==F & iswithin(x(3,:),xlo,xhi) & iswithin(x(4,:),ylo,yhi));
and if your really don't like the alternate variables for the limits but want the actual values built into the expression it would be
taps=x(1,x(2,:)==3 & iswithin(x(3,:),0,2.5) & iswithin(x(4,:),0,2.5));
But, it's much easier to modify for a different set of values if you can simply make the change in a variable or two instead of editing the code.
Or, to obfuscate even further, one can remove the call to iswithin and write the actual expression in line but surely you can then see why I choose the other...
taps=x(1,x(2,:)==3 & ((x(3,:)>=0) & (x(3,:)<=2.5)) ...
& ((x(4,:)>=0) & (x(4,:)<=2.5)));
If you think that's easier to read and decipher what the intent is, power to ya'... :)
ADDENDUM:
You've changed the problem definition of what you're after from the initial posting -- for consistency I've stayed with the first posted--
FACE==3, X,Y both between 0 and 2.5
The beauty of the solution I gave initially is that all you do is change the values to match in the initial variables for any selection.
If you change the logic to be a range of FACE as well instead of a fixed value then you do need to add that condition.
It ( iy) is the result of combining the conditions as you've written them above except not selecting the columns specifically until the logical operations have been completed all together--you've selected subsets that meet a single condition at a time, not all the conditions you've laid out simultaneously.
Search for "Using Logical Arrays in Indexing" in the documentation.
PS:
If you note, it's identical to the solution IA gave but more legible if use the helper function. To use it, simply copy it and paste it into a new m-file named 'iswithin.m' and save it somewhere on your Matlab path--I have an additional subdirectory I call "utilities" I've added and that is on my permanent matlabpath that contains this and a number of other such useful snippets. Besides iswithin there's an isbetween which is non-inclusive. (Altho these are simplified; the actual ones in my library include optional parameters that allow the upper/lower limits to be set as inclusive/noninclusive as desired for full flexibility)

Sign in to comment.


Image Analyst
Image Analyst on 1 Mar 2014
Try it this way:
X = A(:,3);
Y = A(:,4);
% Now get all the rows that meet the criteria
rowsToExtract = (A(:,2) == 3) & (X > 0) & (X < .25) & (Y > 0) & (Y < 2.5)
% Extract the rows we want to keep
keeperRows = A(rowsToExtract, :);
  3 Comments
Tucker
Tucker on 1 Mar 2014
I agree - understandability is impt. Could you explain the line of coding
rowsToExtract = (A(:,2) == 3) & (X > 0) & (X < .25) & (Y > 0) & (Y < 2.5)
Were those just arbitrary #'s you chose? B/c they don't match the ones for my problem. I also don't understand the command ' (A(:,2)==3) '. Isn't that saying for all the second columns equal to 3?
Apologies - I am very new to Matlab
Image Analyst
Image Analyst on 1 Mar 2014
This is a quote from your problem statement "Face # = 3. X coordinates: 0 <= X <= 2.5. Y coordinates: O <= X <= 2.5" so I didn't just make up those numbers. You said that x had to be between 0 and 2.5 and you said that y had to be between 0 and 2.5 (assuming corrections for your typos).
X>0 means that X (which is the column of all your X values which was extracted from column 3 of A) must be greater than 0. and (X<0.25) means that all the X must be less than 2.5. I used & to AND them together which means that X must be greater than 0 AND less than 2.5.
A(:,2) - the colon means "all" so this means all rows in column #2. You said that face was column #2 so I'm saying that you must have a 3 in column #2 (the face value must be 3).
Does that explain it?

Sign in to comment.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!