how to extract a column from a wave

Hi all,

I am very new to Igor and still getting used to wave indexing. I have a 200 by 65 dataset. I would like to calculate max and min for each column. I can calculate min and mix for the entire wave

minPeakWave = WaveMin(w);
maxPeakWave = WaveMax(w);

but could not figure out how to extract (or reference) an entire column from a wave?

All help is much appreciated!

Vishi
Function doit()
Wave w
variable ii, cols, rows
cols = dimsize(w, 1)
rows = dimsize(w, 0)
make/d/n=(cols)/o wmax, wmin
for(ii = 0 ; ii < cols ; ii += 1)
    imagestats/G={0, rows - 1, ii, ii} w
    if(!V_flag)
        wmax[ii] = V_min
        wmin[ii] = V_max
    endif
endfor
End
Thanks Andy! This works great. I am wondering though why the code below did not work for me. It runs but leaves me with empty wmin and wmax. while i am happy with yours, i also would like to store the row number at which max or min occurs

Function doit()
Wave w
variable ii, cols, rows
cols = dimsize(w, 1)
rows = dimsize(w, 0)
make/d/n=(cols,cols)/o wmax, wmin
for(ii = 0 ; ii < cols ; ii += 1)
Make/d/n=(rows) currentCol; currentCol=w[p][ii];
wmin[p][ii]= WaveMin(currentCol);  
wmax[p][ii] = WaveMax(currentCol);
endfor
End
vishivishi wrote:
Thanks Andy! This works great. I am wondering though why the code below did not work for me. It runs but leaves me with empty wmin and wmax. while i am happy with yours, i also would like to store the row number at which max or min occurs

Function doit()
Wave w
variable ii, cols, rows
cols = dimsize(w, 1)
rows = dimsize(w, 0)
make/d/n=(cols,cols)/o wmax, wmin
for(ii = 0 ; ii < cols ; ii += 1)
Make/d/n=(rows) currentCol; currentCol=w[p][ii];
wmin[p][ii]= WaveMin(currentCol);  
wmax[p][ii] = WaveMax(currentCol);
endfor
End


Your code uses p on the left hand side of the assignment within the loop. That doesn't make any sense.

ImageStats gives you the row at which the minimum and maximum was found in the V_minRowLoc and V_maxRowLoc variables. So all you need to do to Andy's version is to store those values as well. Something like this should work:

Function doit()
    Wave w
    variable ii, cols, rows
    cols = dimsize(w, 1)
    rows = dimsize(w, 0)
    make/d/n=(cols)/o wmax, wmin, wmaxloc, wminloc
    for(ii = 0 ; ii < cols ; ii += 1)
        imagestats/G={0, rows - 1, ii, ii} w
        if(!V_flag)
            wmax[ii] = V_min
            wmin[ii] = V_max
            wmaxloc[ii] = V_maxRowLoc
            wminloc[ii] = V_minRowLoc
        endif
    endfor
End


Note that you could change the Make statement to create a 2D wave with 4 columns instead of 4 separate waves if you wanted to:
Function doit()
    Wave w
    variable ii, cols, rows
    cols = dimsize(w, 1)
    rows = dimsize(w, 0)
    make/d/n=(cols, 4)/o statsWave
    for(ii = 0 ; ii < cols ; ii += 1)
        imagestats/G={0, rows - 1, ii, ii} w
        if(!V_flag)
            statsWave[ii][0] = V_min
            statsWave[ii][1] = V_max
            statsWave[ii][2] = V_maxRowLoc
            statsWave[ii][3] = V_minRowLoc
        endif
    endfor
End

Here is why "wmin[p][ii] = ..." is wrong in this code:

for(ii = 0 ; ii < cols ; ii += 1)
    Make/d/n=(rows) currentCol; currentCol=w[p][ii];
    wmin[p][ii]= WaveMin(currentCol);  
    wmax[p][ii] = WaveMax(currentCol);
endfor


p is a built-in Igor function that returns the value of an internal Igor global variable. Let's call this internal variable IgorP.

Igor sets IgorP during a waveform assignment statement. For example:
Make/O/N=5 test=0
test = p    // Igor internally loops 5 times and sets IgorP to 0, 1, 2, 3, 4


This is equivalent to:
Make/O/N=5 test=0
test[0,4] = p   // Igor internally loops 5 times and sets IgorP to 0, 1, 2, 3, 4


which is equivalent to:
Make/O/N=5 test=0
test[] = p  // Igor internally loops 5 times and sets IgorP to 0, 1, 2, 3, 4


This would loop 3 times instead of 5:
Make/O/N=5 test=0
test[1,3] = p   // Igor internally loops 3 times and sets IgorP to 1, 2, 3


However this would "loop" just once:
Make/O/N=5 test=0
test[1,1] = p   // Igor internally loops 1 time and sets IgorP to 1


This would also "loop" just once:
Make/O/N=5 test=0
test[1] = p // Igor internally loops 1 time and sets IgorP to 1


Now finally, to the point. This would also "loop" just once:
Make/O/N=5 test=0
test[p] = p // Igor internally loops 1 time and sets IgorP to whatever was already in IgorP


"Whatever was already in IgorP" will be whatever was left over from the previous waveform assignment statement.

In summary, the value returned by the Igor built-in function p comes from an internal Igor global variable that Igor sets based on the range of rows specified on the lefthand side of a waveform assignment statement.


Thank you aclight, i was wondering how to keep all of the data in one wave so this is great. I surely will have more questions very soon but for now Happy New Year from New York!
vishivishi wrote:
hrodstein, it totally makes sense. great info. the manual sometimes is confusing

TRK
I was looking for some help related to the similar problem above and found this forum post useful. Moving a step ahead, I want to normalize 2D wave (image), dividing each column by the max value in the column. After finding max value as discussed above, I tried to normalize the wave; but executing the function displays only max value of the first col (rest cols returns 0) and only first col gets divided and returns the same value for the entire rows. However, clearing the part below endif statement in the code, the max value of each col can be retained. I am assuming there should be some error in dimensions. I would appreciate for any insight/comments to fix this issue.
Thanks
Function Normalize(input)
Wave input
//Wave waveratio
variable ii, cols, rows
cols = dimsize(input, 1)
rows = dimsize(input, 0)
make/d/n=(1,cols)/o wmax, wmin
//make/d/n=(rows,cols)/O waveratio
for(ii = 0 ; ii < cols ; ii += 1)
    imagestats/G={0, rows-1, ii, ii} input
    if(!V_flag)
        wmax[ii] = V_max
       endif
    Duplicate/O input waveratio
    //MatrixOp/O waveratio = input[rows-1][ii]/wmax[0][ii]
    waveratio[][ii] = input[rows-1][ii]/wmax[0][ii]   //Dividing each cols of 2D wave by V_max of  respective col
    return waveratio
endfor
End
Your Make statement is making waves with one row and cols columns. Then the assignment
        wmax[ii] = V_max

is setting row ii to V_max. You probably want
        wmax[][ii] = V_max

This sets all rows (and there is just one) of column ii to V_max.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
johnweeks wrote:
Your Make statement is making waves with one row and cols columns. Then the assignment
        wmax[ii] = V_max

is setting row ii to V_max. You probably want
        wmax[][ii] = V_max

This sets all rows (and there is just one) of column ii to V_max.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com

TRK
That works perfectly! Earlier, I spend many hours to fix this with no luck; still a beginner in programming but I am enjoying it. Thank you johnweeks !
To solve the original problem of max and min of each column, IP7 adds the /PCST flag.

So wavestats /PCST Inputwave does it all in one shot with lots of other info also calculated.

Andy
Tika wrote:
... I want to normalize 2D wave (image), dividing each column by the max value in the column. ...


Check out the new IP7 scaleCols and maxCols features of MatrixOP. You only need one line for what you want to accomplish:

MatrixOP/O w2D_nor = scaleCols(w2D, rec(maxCols(w2D)^t))