Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Finding peaks & valleys in 2d Data

709 views
Skip to first unread message

Todd Cumming

unread,
Aug 19, 2005, 4:33:02 PM8/19/05
to
This seems like it should be simple but I can't find a function in Matlab to
find the peaks and valleys in some simple x y data. I've spent some time
searching the help but only find complicated stuff in the Image Processing
Toolbox.

If someone could point me in the right direction it would be greatly
appriciated.

Todd Cumming
The National Research Council of Canada


Jeremy Smith

unread,
Aug 19, 2005, 5:00:47 PM8/19/05
to
From the sounds of it you have the data. To find the maximum value in
a matrix you want the max function.
>> max(YourMatrix)
If you also want the corresponding value in the other set of data
you'll want to find the linear index value of the maximum you just
found and then use it to find it's value in the other set of data.
Lets assume your x data is in a matrix called x and your y data is in
y.

>> MaxX = max(x)
>> Location = find(x == MaxX)
>> YValue = y(Location)

us

unread,
Aug 19, 2005, 5:14:10 PM8/19/05
to
Todd Cumming:
<SNIP is looking for min/max spots in his/her 2d arrays...

a hint:

help imregionalmin
help imregionalmax

us

Todd Cumming

unread,
Aug 19, 2005, 5:18:08 PM8/19/05
to
That will only find the highest peak in the data. The MIN function will
only find the deepest valley. Technically I am looking for the points at
which the "Y" values change from increasing to decreasing (peaks) and
decreasing to increasing (valleys). This can be tricky if there are
plateaus in the data or the direction changes from "X" value to "X" value.

Thanks for the response!

Todd

"Jeremy Smith" <smit...@umn.NOSPAM.edu> wrote in message
news:ef11...@webx.raydaftYaTP...

Rune Allnor

unread,
Aug 19, 2005, 5:49:17 PM8/19/05
to

Todd Cumming skrev:

> This seems like it should be simple but I can't find a function in Matlab to
> find the peaks and valleys in some simple x y data. I've spent some time
> searching the help but only find complicated stuff in the Image Processing
> Toolbox.
>
> If someone could point me in the right direction it would be greatly
> appriciated.

I don't know if there are particular functions to do this, but I would
look at the first and second differences in the x and y directions,
assuming the data are sampled on a regular 2D grid. If they are not,
implementing the simple idea below could get messy...

To sketch the idea, we know that a 1D function f(x) has a maximum or
minimum at point x_0 if the 1st derivative f'(x_0) == 0. To check
which it was, consider the 2nd derivative f"(x) to find

f(x_0) is a minimum if f"(x_0) > 0
f(x_0) is a maximum if f"(x_0) < 0

So your porblem basically amounts to search the first difference
of your data to find extremal points, and then check the 2nd
differences at those points to see if they are minima or maxima.

Remember to include the posibility of saddle points, where the point
is a maximum along the x direction and minimum along the y direction,
or vice versa.

Rune

Paul Mennen

unread,
Aug 21, 2005, 12:08:45 AM8/21/05
to
Todd Cumming wrote:
> That will only find the highest peak in the data. The MIN function will
> only find the deepest valley. Technically I am looking for the points at
> which the "Y" values change from increasing to decreasing (peaks) and
> decreasing to increasing (valleys). This can be tricky if there are
> plateaus in the data or the direction changes from "X" value to "X" value.

A fairly simple minded expression to return the indexes of all
the local maxima of a vector "a" follows:

find(a>=[a(2:end) inf] & a>[inf a(1:end-1)])

If the maxima is a sequence of several equal values, this will
return the index of the first of those. If you wanted it to
return the index of the last one, just swap the >= and the >.
If you wanted to include endpoints of the sequence as possible
local maxima, just change the two instances of "inf" to "-inf".

If you think about how this works, I think you will find it
easy to extend it to look for local minima as well.

This may be good enough for many applications, although the reason
I called it "simple minded" is that it can be fooled by a plateau.
(As Todd mentioned, plateaus can be tricky).

For instance a sequence such as [1 2 3 3 3 4 4] has no local
maximum, but one will be identified by my simple minded approach.

Suppose we take this 15 element example:

a = [1 2 2 3 2 1 1 5 1 17 17 17 15 20 1 ];
% 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - index of a

A better algorithm that handles plateaus should return the following
indices as local maxima: 4, 8, 10, 14
And for local minima is should return indicies: 6, 9, 13

This is tricky, but I think you will find that the following code
produces this result exactly:

--------------------------------------------------------------
p = 1:length(a);
b = diff([inf a])~=0;
aa = a(b); pp = p(b);
maxima = pp(find(aa>[aa(2:end) inf] & aa>[inf aa(1:end-1)]))
minima = pp(find(aa<[aa(2:end) -inf] & aa<[-inf aa(1:end-1)]))
---------------------------------------------------------------

~Paul

Doug Schwarz

unread,
Aug 21, 2005, 2:04:07 AM8/21/05
to

Expanding on this with an example:

---------------------- findextrema.m -----------------------
% create array with maxima and minima
p = peaks(101);
x = 0:100; % x values
y = 0:100; % y values

% compute derivatives in x- and y-directions
[dp_dx,dp_dy] = gradient(p,x,y);

% compute second derivatives
[d2p_dx2,d2p_dy_dx] = gradient(dp_dx,x,y);
[d2p_dx_dy,d2p_dy2] = gradient(dp_dy,x,y);

% plot contour lines where the first derivatives are zero
cx = contour(x,y,dp_dx,[0 0],'r');
hold on
cy = contour(x,y,dp_dy,[0 0],'g');

% Wherever the red and green lines cross is a point where the derivatives
% are both zero and hence either a local extremum or a saddle point. To
% determine which, check the second derivatives at those intersections-- if
% d2p_dx2 and d2p_dy2 are the same sign and positive then you have a
% minimum, if they are the same sign and negative then you are at a minimum
% and if they have different signs then you are at a saddle point.

flag = zeros(101,101);
flag(d2p_dx2 > 0 & d2p_dy2 > 0) = 1; % minima
flag(sign(d2p_dx2) ~= sign(d2p_dy2)) = 2; % saddle
flag(d2p_dx2 < 0 & d2p_dy2 < 0) = 3; % maxima

% Let's plot those regions using yellow for maxima, gray for saddle points
% and cyan for minima and then overlay the contour lines from the first
% figure
figure
map = [0 1 1;0.5 0.5 0.5;1 1 0];
surf(x,y,flag)
colormap(map)
shading flat
view(2)
axes
contour(x,y,dp_dx,[0 0],'r')
hold on
contour(x,y,dp_dy,[0 0],'g')
-------------------- end findextrema.m ---------------------


I'll leave it for you to figure out how to find the intersections of the red
and green lines, cx and cy.

--
Doug Schwarz
dmschwarz&urgrad,rochester,edu
Make obvious changes to get real email address.

Annie

unread,
May 21, 2009, 12:32:01 PM5/21/09
to
Hello Paul

I was going through this thread as even I need to find the first peak in my data (ignoring the plateaus) and then shift that first peak to origin. I did try the following lines of code but it is giving error on line 2 i.e b= diff.. and then when I remove '~=0' theni it gives error at line 3 :aa= a(b)

Please help me with my problem as I am new to MATLAB

Thank you

p = 1:length(a);
b = diff([inf a])~=0;
aa = a(b); pp = p(b);
maxima = pp(find(aa>[aa(2:end) inf] & aa>[inf aa(1:end-1)]))
minima = pp(find(aa<[aa(2:end) -inf] & aa<[-inf aa(1:end-1)]))


Paul Mennen <pa...@mennen.org> wrote in message <4307FE4D...@mennen.org>...

Johnathan

unread,
May 21, 2009, 1:01:02 PM5/21/09
to
maybe I'm stupid, but....

function peaks=findpeaks222(pressuredata)
[m,n]=size(pressuredata);

startindex=2;
finalindex=m-1;
index=1;
peaks=zeros(m,2);

for i=startindex:finalindex

if (pressuredata(i,2)>=pressuredata((i-1),2)...
&& pressuredata(i,2)>=pressuredata((i+1),2))...
|| (pressuredata(i,2)<=pressuredata((i-1),2)...
&& pressuredata(i,2)<=pressuredata((i+1),2))

peaks(index,1)=pressuredata(i,1);
peaks(index,2)=pressuredata(i,2);

index=index+1;


end

end

peaks=[peaks(1:(index-1),1),peaks(1:(index-1),2)];

figure
hold on
plot(pressuredata(:,1),pressuredata(:,2),'k')
plot(peaks(:,1),peaks(:,2),'ro','linewidth',3)
hold off

end

So run this like:

t=1:.1:20;
x=sin(t)+.5*sin(5*t);
pressuredata=[t',x']

z=findpeaks222(pressuredata)

Hope this helps,
--John

Johnathan

unread,
May 21, 2009, 1:07:01 PM5/21/09
to
oops, take out the >= and make them just > etc.

ImageAnalyst

unread,
May 21, 2009, 1:22:39 PM5/21/09
to
On May 21, 12:32 pm, "Annie " <annieman...@gmail.com> wrote:
> Hello Paul
>
> I was going through this thread as even I need to find the first peak in my data (ignoring the plateaus) and then shift that first peak to origin. I did try the following lines of code but it is giving error on line 2 i.e b= diff.. and then when I remove '~=0' theni it gives error at line 3 :aa= a(b)
>
> Please help me with my problem as I am new to MATLAB
>
> Thank you
>
> p = 1:length(a);
> b = diff([inf a])~=0;
> aa = a(b); pp = p(b);
> maxima = pp(find(aa>[aa(2:end) inf] & aa>[inf aa(1:end-1)]))
> minima = pp(find(aa<[aa(2:end) -inf] & aa<[-inf aa(1:end-1)]))
>
>
>
--------------------------------------------------------------------------------------------------
Annie:
I ran the code with Paul's a of this:

> > a = [1 2 2 3 2 1 1 5 1 17 17 17 15 20 1 ];
> > %    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - index of a
>
and it ran fine. No errors whatsoever. What is the a array that you
used?
Regards,
ImageAnalyst
P.S. I agree that finding peaks in a 2D data, particularly if there is
any noise, is a difficult task, and it's not quite as straightforward
as with 1D signals. MATLAB's Image Processing Toolkit has imextended
max which uses the h maxima transform but this is not always what you
expect.

ImageAnalyst

unread,
May 21, 2009, 1:31:45 PM5/21/09
to
On May 21, 1:01 pm, "Johnathan " <durchfalldurchf...@yahoo.com> wrote:
> maybe I'm stupid, but....
[snip]
>
> Hope this helps,
> --John
---------------------------------------------------
John:
Your code will find every local peak. You could probably do the same
thing in one line just by using the local max operator, imdilate,
something like
peaksImage = (originalImage == imdilate(originalImage));
In real world situations where you often have small noise oscillations
on the "true" peak, this will end up finding a bunch of spurious noise
pixels. Every time a pixel is just slightly higher than its
neighbors, you have a new (unwanted) peak. It's a lot more difficult
(and can be rather subjective) to have an algorithm that can robustly
handle noise.
-ImageAnalyst

Annie

unread,
May 21, 2009, 3:31:01 PM5/21/09
to
Hello

Okay so I have a text filw with 10 columns (floating point integers) and I read this file doing a textscan and separate all 10 columns in a cell array each so each is like variable is like huge column matrix. Then from each column I plot that data Vs time and from that figure I need to find first peak value (I have to ignore plateaus). And it is giving me error when I used Paul's code

Thanks

Annie


ImageAnalyst <imagea...@mailinator.com> wrote in message <44d4951a-0971-459d...@p4g2000vba.googlegroups.com>...


> On May 21, 12:32?pm, "Annie " <annieman...@gmail.com> wrote:
> > Hello Paul
> >
> > I was going through this thread as even I need to find the first peak in my data (ignoring the plateaus) and then shift that first peak to origin. I did try the following lines of code but it is giving error on line 2 i.e b= diff.. and then when I remove '~=0' theni it gives error at line 3 :aa= a(b)
> >
> > Please help me with my problem as I am new to MATLAB
> >
> > Thank you
> >
> > p = 1:length(a);
> > b = diff([inf a])~=0;
> > aa = a(b); pp = p(b);
> > maxima = pp(find(aa>[aa(2:end) inf] & aa>[inf aa(1:end-1)]))
> > minima = pp(find(aa<[aa(2:end) -inf] & aa<[-inf aa(1:end-1)]))
> >
> >
> >
> --------------------------------------------------------------------------------------------------
> Annie:
> I ran the code with Paul's a of this:
> > > a = [1 2 2 3 2 1 1 5 1 17 17 17 15 20 1 ];

> > > % ? ?1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - index of a

Johnathan

unread,
May 22, 2009, 12:28:01 AM5/22/09
to
true, but I thought that's what she wanted! All the peaks...?

Didn't know matlab had nice neat functions for local maxes and mins.

Shows how much I know.

--John

Bruno Luong

unread,
May 22, 2009, 3:07:01 AM5/22/09
to
"Annie " <annie...@gmail.com> wrote in message <gv4a5l$drk$1...@fred.mathworks.com>...

> Hello
>
> Okay so I have a text filw with 10 columns (floating point integers) and I read this file doing a textscan and separate all 10 columns in a cell array each so each is like variable is like huge column matrix. Then from each column I plot that data Vs time and from that figure I need to find first peak value (I have to ignore plateaus). And it is giving me error when I used Paul's code
>
> Thanks
>
> Annie

It is hard to make any effective help if you don't provide the error message. From what I read Paul assume row vectors, but your data is columns. Did you take any action to take care of that? (use ";" for concatenation or transpose your vector; not doing both of course)

Bruno

Annie

unread,
May 22, 2009, 8:24:01 AM5/22/09
to
Hello Bruno

The error message I get is as follows:

??? Error using ==> horzcat
CAT arguments dimensions are not consistent.

Error in ==> data_analysis at 63


b = diff([inf a])~=0;

Regarding the column vector point, I tried swapping diff([inf a]) to [a inf] as well but same error. Also what will be limits in aa>[aa(2:end) inf] & aa>[inf aa(1:end-1)])); for column vector? It wont change right?

Thanks a lot

Annie

"Bruno Luong" <b.l...@fogale.findmycountry> wrote in message <gv5iul$jhv$1...@fred.mathworks.com>...

Bruno Luong

unread,
May 22, 2009, 8:29:02 AM5/22/09
to
"Annie " <annie...@gmail.com> wrote in message <gv65h1$1rj$1...@fred.mathworks.com>...

> Hello Bruno
>
> The error message I get is as follows:
>
> ??? Error using ==> horzcat
> CAT arguments dimensions are not consistent.
>
> Error in ==> data_analysis at 63
> b = diff([inf a])~=0;
>
> Regarding the column vector point, I tried swapping diff([inf a]) to [a inf] as well but same error. Also what will be limits in aa>[aa(2:end) inf] & aa>[inf aa(1:end-1)])); for column vector? It wont change right?
>

You must change [ x y ] to [ x ; y ]

The first is row-concatenation the second is column.

Bruno

Matt

unread,
May 22, 2009, 1:04:02 PM5/22/09
to
"Todd Cumming" <todd.c...@nrc.ca> wrote in message <de5flu$hfr$1...@nrc-news.nrc.ca>...

> This seems like it should be simple but I can't find a function in Matlab to
> find the peaks and valleys in some simple x y data. I've spent some time
> searching the help but only find complicated stuff in the Image Processing
> Toolbox.
>
> If someone could point me in the right direction it would be greatly
> appriciated.

I'll just throw out one more solution based on convolutions


%%Sample data array
D=zeros(5); D(9)=-1; D(13)=1;


%%%%Find local maxes as follows. To find local mins, do the same on -D


A1=[-1 0 0; 0 1 0; 0 0 0];
A2=rot90(A1);
A3=rot90(A2);
A4=rot90(A3);

B1=[0 -1 0; 0 1 0; 0 0 0];
B2=rot90(B1);
B3=rot90(B2);
B4=rot90(B3);

T=conv2(D,A1,'valid')>0;
T=T&( conv2(D,A2,'valid')>0 );
T=T&( conv2(D,A3,'valid')>0 );
T=T&( conv2(D,A4,'valid')>0 );
T=T&( conv2(D,B1,'valid')>0 );
T=T&( conv2(D,B2,'valid')>0 );
T=T&( conv2(D,B3,'valid')>0 );
T=T&( conv2(D,B4,'valid')>0 );

[I,J]=find(T);
I=I+1;
J=J+1;

Annie

unread,
May 22, 2009, 1:52:02 PM5/22/09
to
"Bruno Luong" <b.l...@fogale.findmycountry> wrote in message <gv65qe$j20$1...@fred.mathworks.com>...

Hello Bruno

Dou you mean change [inf a] to [inf;a] or [inf : a]?? If we put a semicolon, it gives a syntax error

Bruno Luong

unread,
May 22, 2009, 2:03:03 PM5/22/09
to
"Annie " <annie...@gmail.com> wrote in message <gv6oo2$77$1...@fred.mathworks.com>...


Semi colon is correct, like below:

>> a=[1; 2; 3]

a =

1
2
3

>> [inf; a]

ans =

Inf
1
2
3

Further reading: http://www.mathworks.com/access/helpdesk/help/techdoc/learn_matlab/f2-12841.html#f2-21117

Bruno

Annie

unread,
May 26, 2009, 4:13:02 PM5/26/09
to
Hello Bruno

Thanks a lot but I am still not able to get this right and it is critical for me, please help.

Now my code looks like

p = 1:length(y);
b = diff([inf ; y])~=0;
aa = y(b); pp = p(b);
Imx = pp(find(aa>[aa(2:end) inf] & aa>[inf aa(1:end-1)]));

and I get following error still

??? Error using ==> horzcat
CAT arguments dimensions are not consistent.

Error in ==> data_analysis_peak at 65
Imx = pp(find(aa>[aa(2:end) inf] & aa>[inf aa(1:end-1)]));

Please help!
_______________________________________________________________

"Bruno Luong" <b.l...@fogale.findmycountry> wrote in message <gv6pcn$bo5$1...@fred.mathworks.com>...

Bruno Luong

unread,
May 26, 2009, 4:39:02 PM5/26/09
to
"Annie " <annie...@gmail.com> wrote in message <gvhige$385$1...@fred.mathworks.com>...

> Hello Bruno
>
> Thanks a lot but I am still not able to get this right and it is critical for me, please help.
>
> Now my code looks like
>
> p = 1:length(y);
> b = diff([inf ; y])~=0;
> aa = y(b); pp = p(b);
> Imx = pp(find(aa>[aa(2:end) inf] & aa>[inf aa(1:end-1)]));
>

You haven't read carefully Annie. I wrote above "You must change [ x y ] to [ x ; y ]", and look at the line where the error occurs. Did you change the syntax accordingly? And did you try to understand the difference between
[x y] % and
[x; y] %?

Again, please read the doc.

> help horzcat
> help vertcat

It is fundamental to understand the basic matrix manipulation. You cannot rely permanently on me or people on this board to fish for you. It's time for you to catch the fish.

Bruno

Am

unread,
May 26, 2009, 5:37:01 PM5/26/09
to
I understood the difference between [x y] and [x;y]. Sorry, I am quite new to MATLAB and dont know much about it and trying to learn and do my work. Finally I conceptually understood and implemented as per my requirement but this code still does not solve my problem of finding first peak and do pick value on the plateau. I can find a point where the peak is but I dont wish to hardquote the value in the code as it has to run through different files and not necessarily everytime it will have same event at same value.

Is there a way to capture the first relevant peak in a generic and consistent manner?
__________________________________________________________________

"Bruno Luong" <b.l...@fogale.findmycountry> wrote in message <gvhk16$efr$1...@fred.mathworks.com>...

Richard Holland

unread,
May 27, 2009, 7:08:02 AM5/27/09
to
"Todd Cumming" <todd.c...@nrc.ca> wrote in message <de5flu$hfr$1...@nrc-news.nrc.ca>...
> Todd
Check out findpeaks MATLAB function
[pk_pos,loc_pos]=findpreaks(Y);
[pk_neg,loc_neg]=findpeaks(-Y);
>

Rajendra

unread,
Aug 6, 2014, 4:57:10 AM8/6/14
to

Check this
[pks,locs] = findpeaks(data)


"Todd Cumming" <todd.c...@nrc.ca> wrote in message <de5flu$hfr$1...@nrc-news.nrc.ca>...

Maasi AL-Mayali

unread,
Jun 18, 2015, 7:24:06 AM6/18/15
to
"Todd Cumming" <todd.c...@nrc.ca> wrote in message <de5flu$hfr$1...@nrc-news.nrc.ca>...
> Dear Sir,
Im a PhD student at Cardiff university I have roughness profile data (x,y).
I need to find the deepest valleys in profile how i can do that by Matlab.can you provide me please with the code?
your help is appreciated
Maasi
0 new messages