1

I am currently trying to identify peaks on a randomly generated plot that I have created.

My code is as follows:

x_range = np.arange(0,100,0.5) #my x values
for i in len(ys): #ys is my range of y values on the chart
    for j in range(start,len(ys)): #Brute forcing peak detection
        temp.append(ys[j])
        check = int(classtest.isPeak(temp)[0])
        if check == 1:
            xval = temp.index(max(temp)) #getting the index
            xlist = x_range.tolist()
            plt.plot(xlist[xval],max(temp),"ro") 
    start =  start + 1
    temp = []

However when plotting the values on the graph, it seems to plot the correct y position, but not x. Here is an example of what is happening: As you can see, the x values are going crazy!

I am really not sure what is causing this problem, and I would love some help.

Thanks

0

1 Answer 1

3

Remember that temp is getting shorter and shorter as start increases. So the index, xval, corresponding to a max in temp is not in itself the correct index into x_range. Rather, you have to increase xval by start to find the corresponding index in x_range:

import numpy as np
import matplotlib.pyplot as plt
np.random.seed(2016)

N = 100
ys = (np.random.random(N)-0.5).cumsum()
xs = np.linspace(0, 100, len(ys))

plt.plot(xs, ys)
start = 0
temp = []
for i in range(len(ys)): #ys is my range of y values on the chart
    for j in range(start,len(ys)): #Brute forcing peak detection
        temp.append(ys[j])
        xval = temp.index(max(temp)) #getting the index
        plt.plot(xs[xval+start], max(temp),"ro") 
    start =  start + 1
    temp = []
plt.show()

enter image description here

While that does manage to place the red dots at points on the graph, as you can see the algorithm is placing a dot at every point on the graph, not just at local maxima. Part of the problem is that when temp contains only one point, it is of course the max. And the double for-loop ensures that every point gets considered, so at some point temp contains each point on the graph alone as a single point.

A different algorithm is required. A local max can be identified as any point which is bigger than its neighbors:

ys[i-1] <= ys[i] >= ys[i+1]

therefore, you could use:

import numpy as np
import matplotlib.pyplot as plt
np.random.seed(2016)

N = 100
ys = (np.random.random(N)-0.5).cumsum()
xs = np.linspace(0, 100, len(ys))

plt.plot(xs, ys)
idx = []
for i in range(1, len(ys)-1):
    if ys[i-1] <= ys[i] >= ys[i+1]:
        idx.append(i)
plt.plot(xs[idx], ys[idx], 'ro')
plt.show()

enter image description here

Note that scipy.signal.argrelextrema or scipy.signal.argrelmax can also be used to find local maximums:

from scipy import signal
idx = signal.argrelextrema(ys, np.greater)
plt.plot(xs[idx], ys[idx], 'ro')

produces the same result.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the answer, only problem now is I am getting the error: plt.plot(x_range[idx], ys[idx], 'ro') TypeError: list indices must be integers, not list

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.