Find every local peaks and bottom values
import numpy as np
from scipy import signal
import matplotlib.pyplot as plt
data = np.array([ 0.1, 1, 3, 1, 0.2, 1, 3.1, 3.2, 3, 1, 0 , -0.1, -0.2, -0.1, -0.2])
peak_index = signal.argrelextrema(data, np.greater_equal, order=1)
bottom_index = signal.argrelextrema(data, np.less_equal, order=1)
print('peak values are {}'.format(data[peak_index]))
print('bottom values are {}'.format(data[bottom_index]))
fig = plt.figure()
plt.plot(range(len(data)), data)
plt.scatter(peak_index, data[peak_index], color = 'red')
plt.scatter(bottom_index, data[bottom_index], color = 'blue')
plt.show()
A better solution
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import find_peaks
# 1. Generate a random signal with peaks and bottoms
np.random.seed(42)
t = np.linspace(0, 10, 1000)
# Sum of sine waves + random Gaussian noise
signal = np.sin(2 * np.pi * 0.5 * t) + 0.5 * np.sin(2 * np.pi * 2 * t) + np.random.normal(0, 0.1, 1000)
# 2. Set your prominence threshold (the "recovery" height)
# Only peaks/bottoms that stand out by at least 0.5 will be detected
threshold = 0.5
# 3. Find Peaks
peaks, _ = find_peaks(signal, prominence=threshold)
# 4. Find Bottoms (by inverting the signal)
bottoms, _ = find_peaks(-signal, prominence=threshold)
# 5. Visualise results
plt.figure(figsize=(12, 6))
plt.plot(t, signal, label='Signal', color='gray', alpha=0.6)
plt.plot(t[peaks], signal[peaks], "x", label='Detected Peaks', markersize=10, color='red')
plt.plot(t[bottoms], signal[bottoms], "x", label='Detected Bottoms', markersize=10, color='blue')
plt.title(f"Peak & Bottom Detection (Prominence Threshold: {threshold})")
plt.xlabel("Time")
plt.ylabel("Amplitude")
plt.legend()
plt.grid(True)
plt.show()
# Print results
print(f"Detected {len(peaks)} peaks and {len(bottoms)} bottoms.")