{"id":13689389,"url":"https://github.com/MonsieurV/py-findpeaks","last_synced_at":"2025-05-01T23:34:14.508Z","repository":{"id":33474483,"uuid":"37120161","full_name":"MonsieurV/py-findpeaks","owner":"MonsieurV","description":"Overview of the peaks dectection algorithms available in Python","archived":false,"fork":false,"pushed_at":"2019-11-29T17:07:46.000Z","size":659,"stargazers_count":756,"open_issues_count":1,"forks_count":175,"subscribers_count":40,"default_branch":"master","last_synced_at":"2024-11-05T07:34:13.038Z","etag":null,"topics":["detect-peaks","digital-signal-processing","python","scipy"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MonsieurV.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-06-09T08:32:22.000Z","updated_at":"2024-10-26T05:36:20.000Z","dependencies_parsed_at":"2022-09-12T21:51:20.582Z","dependency_job_id":null,"html_url":"https://github.com/MonsieurV/py-findpeaks","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MonsieurV%2Fpy-findpeaks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MonsieurV%2Fpy-findpeaks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MonsieurV%2Fpy-findpeaks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MonsieurV%2Fpy-findpeaks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MonsieurV","download_url":"https://codeload.github.com/MonsieurV/py-findpeaks/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224215749,"owners_count":17274838,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["detect-peaks","digital-signal-processing","python","scipy"],"created_at":"2024-08-02T15:01:45.595Z","updated_at":"2024-11-12T13:31:38.463Z","avatar_url":"https://github.com/MonsieurV.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"This is an overview of all the ready-to-use algorithms I've found to perform peak detection in Python. I've also written [a blog post](https://blog.ytotech.com/2015/11/01/findpeaks-in-python/) on the subject.\n\n## Overview\n\n| Algorithm | Integration | Filters | MatLab `findpeaks`-like? |\n|-----------| ----------- | ------- | :----------------------: |\n| [scipy.signal.find_peaks_cwt](#scipysignalfind_peaks_cwt) | Included in Scipy | ? | ✘ |\n| [scipy.signal.argrelextrema](#scipysignalargrelextrema) | Included in Scipy 0.11+ | Minimum distance | ✘ |\n| [scipy.signal.find_peaks](#scipysignalfind_peaks) | Included in Scipy 1.1+ | Amplitude\u003cbr\u003eThreshold\u003cbr\u003eDistance\u003cbr\u003eProminence\u003cbr\u003eWidth | ✔ |\n| [detect_peaks](#detect_peaks-from-marcos-duarte) | Single file source\u003cbr\u003eDepends on Numpy | Minimum distance\u003cbr\u003eMinimum height\u003cbr\u003eRelative threshold | ✔ |\n| [peakutils.peak.indexes](#peakutilspeakindexes) | PyPI package PeakUtils\u003cbr\u003e Depends on Scipy | Amplitude threshold\u003cbr\u003eMinimum distance | ✔ |\n| [peakdetect](#peakdetect-from-sixtenbe) | Single file source\u003cbr\u003eDepends on Scipy | Minimum distance | ✘ |\n| [Octave-Forge findpeaks](#octave-forge-findpeaks) | Requires an Octave-Forge distribution\u003cbr\u003e+ PyPI package oct2py\u003cbr\u003eDepends on Scipy | Minimum distance\u003cbr\u003eMinimum height\u003cbr\u003eMinimum peak width | ✘ |\n| [Janko Slavic findpeaks](#janko-slavic-findpeaks) | Single function\u003cbr\u003eDepends on Numpy | Minimum distance\u003cbr\u003eMinimum height | ✘ |\n| [Tony Beltramelli detect_peaks](#tony-beltramelli-detect_peaks) | Single function\u003cbr\u003eDepends on Numpy | Amplitude threshold | ✘ |\n| [mlpy.findpeaks_dist](#mlpyfindpeaks_dist) | Included in mlpy\u003cbr\u003eDepends on Scipy and GSL | Minimum distance | ✘ |\n| [mlpy.findpeaks_win](#mlpyfindpeaks_win) | Single function\u003cbr\u003eDepends on Scipy and GSL | Sliding window width | ✘ |\n\n## How to make your choice?\n\nWhen you're selecting an algorithm, you might consider:\n\n* **The function interface.** You may want the function to work natively with Numpy arrays or may search something similar to other platform algorithms, like the MatLab [`findpeaks`](http://fr.mathworks.com/help/signal/ref/findpeaks.html).\n* **The dependencies.** Does it require extra dependency? Does is it easy to make it run on a fresh box?\n* **The filtering support**. Does the algorithm allows to define multiple filters? Which ones do you need?\n\n--------------------------------\n\n## scipy.signal.find_peaks_cwt\n\n![](/images/scipy_find_peaks_cwt.png?raw=true \"scipy.signal.find_peaks_cwt\")\n\n```python\nimport numpy as np\nvector = [\n    0, 6, 25, 20, 15, 8, 15, 6, 0, 6, 0, -5, -15, -3, 4, 10, 8, 13, 8, 10, 3,\n    1, 20, 7, 3, 0 ]\nimport scipy.signal\nprint('Detect peaks without any filters.')\nindexes = scipy.signal.find_peaks_cwt(vector, np.arange(1, 4),\n    max_distances=np.arange(1, 4)*2)\nindexes = np.array(indexes) - 1\nprint('Peaks are: %s' % (indexes))\n```\n\n[Documentation](http://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.find_peaks_cwt.html).\n[Sample code](/tests/scipy_find_peaks_cwt.py).\n\nThe first historical peak detection algorithm from the Scipy signal processing package.\nIts name appears to make it an obvious choice (when you already work with Scipy), but it may actually not be, as it uses a wavelet convolution approach.\n\nThis function requires to understand wavelets to be properly used. This is less trivial and direct than other algorithms. However the wavelet approach can make it a good choice on noisy data.\n\n## scipy.signal.argrelextrema\n\n![](/images/scipy_argrelextrema.png?raw=true \"scipy.signal.argrelextrema\")\n\n```python\nimport numpy as np\nvector = [\n    0, 6, 25, 20, 15, 8, 15, 6, 0, 6, 0, -5, -15, -3, 4, 10, 8, 13, 8, 10, 3,\n    1, 20, 7, 3, 0 ]\nimport scipy.signal\nprint('Detect peaks with order (distance) filter.')\nindexes = scipy.signal.argrelextrema(\n    np.array(vector),\n    comparator=np.greater,order=2\n)\nprint('Peaks are: %s' % (indexes[0]))\n```\n\n[Documentation](https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.argrelextrema.html).\n[Sample code](/tests/scipy_argrelextrema.py).\n\nNew peak detection algorithm from Scipy since version 0.11.0. Its usage is really trivial,\nbut it misses out of the box filtering capacities.\n\nIt includes an `order` parameter that can serve as a kind of minimum distance filter.\nThe filtering behavior is customizable through the `comparator` parameter, which\ncan make it a good choice for building your own filtering algorithm over it.\n\nSee also related functions [argrelmin](https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.argrelmin.html) and [argrelmax](https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.argrelmax.html).\n\n\n## scipy.signal.find_peaks\n\n![](/images/scipy_find_peaks.png?raw=true \"scipy.signal.find_peaks\")\n\n```python\nimport numpy as np\nimport scipy.signal\nvector = np.array([0, 6, 25, 20, 15, 8, 15, 6, 0, 6, 0, -5, -15, -3, 4, 10, 8,\n                   13, 8, 10, 3, 1, 20, 7, 3, 0])\nprint('Detect peaks with minimum height and distance filters.')\nindexes, _ = scipy.signal.find_peaks(vector, height=7, distance=2.1)\nprint('Peaks are: %s' % (indexes))\n```\n\n[Documentation](https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.find_peaks.html).\n[Sample code](/tests/scipy_signal_find_peaks.py).\n\nThis function was added to SciPy in version 1.1.0 and is comparable to `findpeaks` provided in Matlab's Signal Processing Toolbox.\n\n`scipy.signal.find_peaks` searches for peaks (local maxima) based on simple value comparison of neighbouring samples and returns those peaks whose properties match optionally specified conditions (minimum and / or maximum) for their height, prominence, width, threshold and distance to each other.\n\nOn the prominence parameter, see [this explanation](https://stackoverflow.com/a/52612432).\n\n\n## detect_peaks from Marcos Duarte\n\n![](/images/detect_peaks.png?raw=true \"detect_peaks from Marcos Duarte\")\n\n```python\nimport numpy as np\nvector = [\n    0, 6, 25, 20, 15, 8, 15, 6, 0, 6, 0, -5, -15, -3, 4, 10, 8, 13, 8, 10, 3,\n    1, 20, 7, 3, 0 ]\nfrom libs import detect_peaks\nprint('Detect peaks with minimum height and distance filters.')\nindexes = detect_peaks.detect_peaks(vector, mph=7, mpd=2)\nprint('Peaks are: %s' % (indexes))\n```\n\n[Documentation](http://nbviewer.ipython.org/github/demotu/BMC/blob/master/notebooks/DetectPeaks.ipynb).\n[Source](/tests/libs/detect_peaks.py).\n[Sample code](/tests/detect_peaks.py).\n\nThis algorithm comes from a notebook written by Marcos Duarte and is pretty trivial to use.\n\nThe function has an interface very similar and consistent results with the MatLab Signal Processing Toolbox `findpeaks`, yet with less complete filtering and tuning support.\n\n## peakutils.peak.indexes\n\n![](/images/peakutils_indexes.png?raw=true \"peakutils.peak.indexes\")\n\n```python\nimport numpy as np\nvector = [\n    0, 6, 25, 20, 15, 8, 15, 6, 0, 6, 0, -5, -15, -3, 4, 10, 8, 13, 8, 10, 3,\n    1, 20, 7, 3, 0 ]\nimport peakutils.peak\nprint('Detect peaks with minimum height and distance filters.')\nindexes = peakutils.peak.indexes(np.array(vector),\n    thres=7.0/max(vector), min_dist=2)\nprint('Peaks are: %s' % (indexes))\n```\n\n[Documentation](https://peakutils.readthedocs.io/en/latest/).\n[Package](https://bitbucket.org/lucashnegri/peakutils).\n[Sample code](/tests/peakutils_indexes.py).\n\nThis algorithm can be used as an equivalent of the MatLab `findpeaks` and will give easily give consistent results if you only need minimal distance and height filtering.\n\n## peakdetect from sixtenbe\n\n![](/images/sixtenbe_peakdetect.png?raw=true \"peakdetect from sixtenbe\")\n\n```python\nimport numpy as np\nvector = [\n    0, 6, 25, 20, 15, 8, 15, 6, 0, 6, 0, -5, -15, -3, 4, 10, 8, 13, 8, 10, 3,\n    1, 20, 7, 3, 0 ]\nfrom libs import peakdetect\nprint('Detect peaks with distance filters.')\npeaks = peakdetect.peakdetect(np.array(vector), lookahead=2, delta=2)\n# peakdetect returns two lists, respectively positive and negative peaks,\n# with for each peak a tuple of (indexes, values).\nindexes = []\nfor posOrNegPeaks in peaks:\n    for peak in posOrNegPeaks:\n        indexes.append(peak[0])\nprint('Peaks are: %s' % (indexes))\n```\n\n[Source and documentation](https://gist.github.com/sixtenbe/1178136).\n[Sample code](/tests/peakdetect.py).\n\nThe algorithm was written by sixtenbe based on the previous work of [endolith](https://gist.github.com/endolith/250860) and [Eli Billauer](http://billauer.co.il/peakdet.html).\n\nEasy to setup as it comes in a single source file, but the lookahead parameter make it hard to use on low-sampled signals or short samples. May miss filtering capacities (only minimum peak distance with the delta parameter).\n\n## Octave-Forge findpeaks\n\n![](/images/octave_findpeaks.png?raw=true \"Octave-Forge findpeaks\")\n\n```python\nimport numpy as np\nvector = [\n    0, 6, 25, 20, 15, 8, 15, 6, 0, 6, 0, -5, -15, -3, 4, 10, 8, 13, 8, 10, 3,\n    1, 20, 7, 3, 0 ]\nfrom oct2py import octave\n# Load the Octage-Forge signal package.\noctave.eval(\"pkg load signal\")\nprint('Detect peaks with minimum height and distance filters.')\n(pks, indexes) = octave.findpeaks(np.array(vector), 'DoubleSided',\n    'MinPeakHeight', 6, 'MinPeakDistance', 2, 'MinPeakWidth', 0)\n# The results are in a 2D array and in floats: get back to 1D array and convert\n# peak indexes to integer. Also this is MatLab-style indexation (one-based),\n# so we must substract one to get back to Python indexation (zero-based).\nindexes = indexes[0].astype(int) - 1\nprint('Peaks are: %s' % (indexes))\n```\n\n[Documentation](http://octave.sourceforge.net/signal/function/findpeaks.html).\n[oct2py package](https://github.com/blink1073/oct2py).\n[Sample code](/tests/octave_findpeaks.py).\n\nUse `findpeaks` from the Octave-Forge signal package through the oct2py bridge. This algorithm allows to make a double sided detection, which means it will detect both local maxima and minima in a single run.\n\nRequires a rather complicated and not very efficient setup to be called from Python code. Of course, you will need an up-to-date distribution of Octave, with the signal package installed from Octave-Forge.\n\nAlthough the function have an interface close to the MatLab `findpeaks`, it is harder to have the exact same results that with [detect_peaks](#detect_peaks-from-marcos-duarte) or [peakutils.peak.indexes](#peakutilspeakindexes).\n\n## Janko Slavic findpeaks\n\n![](/images/janko_slavic_findpeaks.png?raw=true \"Janko Slavic findpeaks\")\n\n```python\nimport numpy as np\nvector = [\n    0, 6, 25, 20, 15, 8, 15, 6, 0, 6, 0, -5, -15, -3, 4, 10, 8, 13, 8, 10, 3,\n    1, 20, 7, 3, 0 ]\nfrom libs.findpeaks import findpeaks\nindexes = findpeaks(np.array(vector), spacing=2, limit=7)\nprint('Peaks are: %s' % (indexes))\n```\n\n[Documentation](https://github.com/jankoslavic/py-tools/blob/master/findpeaks/Findpeaks%20example.ipynb).\n[Source](https://github.com/jankoslavic/py-tools/blob/master/findpeaks/findpeaks.py).\n[Sample code](/tests/janko_slavic_findpeaks.py).\n\nSmall and fast peak detection algorithm, with minimum distance and height filtering support. Comes as an handy single function, depending only on Numpy.\n\nContrary to the MatLab `findpeaks`-like distance filters, the Janko Slavic `findpeaks` `spacing` param requires that all points within the specified width to be lower than the peak. If you work on very low sampled signal, the minimum distance filter may miss fine granularity tuning.\n\n## Tony Beltramelli detect_peaks\n\n![](/images/tony_beltramelli_detect_peaks.png?raw=true \"Lightweight standalone peaks\")\n\n```python\nimport numpy as np\nvector = [\n    0, 6, 25, 20, 15, 8, 15, 6, 0, 6, 0, -5, -15, -3, 4, 10, 8, 13, 8, 10, 3,\n    1, 20, 7, 3, 0 ]\nfrom libs.tony_beltramelli_detect_peaks import detect_peaks\nprint('Detect peaks with height threshold.')\nindexes = detect_peaks(vector, 1.5)\nprint('Peaks are: %s' % (indexes))\n```\n\n[Source and documentation](/tests/libs/tony_beltramelli_detect_peaks.py).\n[Sample code](/tests/tony_beltramelli_detect_peaks.py).\n\nStraightforward, simple and lightweight peak detection algorithm, with minimum distance filtering support.\n\nNo minimum peak height filtering support.\n\n## mlpy.findpeaks_dist\n\n![](/images/mlpy_findpeaks_dist.png?raw=true \"mlpy.findpeaks_dist\")\n\n```python\nimport numpy as np\nimport scipy.signal\nvector = [0, 6, 25, 20, 15, 8, 15, 6, 0, 6, 0, -5, -15, -3, 4, 10, 8,\n                   13, 8, 10, 3, 1, 20, 7, 3, 0]\nprint('Detect peaks with minimum distance filter.')\nindexes = mlpy.findpeaks_dist(vector, mindist=2.1)\nprint('Peaks are: %s' % (indexes))\n```\n\n[Documentation](http://mlpy.sourceforge.net/docs/3.5/findpeaks.html#mlpy.findpeaks_dist).\n[Sample code](/tests/mlpy_findpeaks_dist.py).\n\nFind peaks, with a minimum distance filter between peaks. Code written by Davide Albanese.\n\n## mlpy.findpeaks_win\n\n![](/images/mlpy_findpeaks_win.png?raw=true \"mlpy.findpeaks_win\")\n\n```python\nimport numpy as np\nimport scipy.signal\nvector = [0, 6, 25, 20, 15, 8, 15, 6, 0, 6, 0, -5, -15, -3, 4, 10, 8,\n                   13, 8, 10, 3, 1, 20, 7, 3, 0]\nprint('Detect peaks with sliding window of 5.')\nindexes = mlpy.findpeaks_win(vector, span=5)\nprint('Peaks are: %s' % (indexes))\n```\n\n[Documentation](http://mlpy.sourceforge.net/docs/3.5/findpeaks.html#mlpy.findpeaks_win).\n[Sample code](/tests/mlpy_findpeaks_win.py).\n\nFind peaks, with a sliding window of specified width. Code written by Davide Albanese.\n\n----------------------------------\n\n# How to find both lows and highs?\n\nMost algorithms detect only local _maximas_. You may want to detect both _minimas_ and _maximas_.\n\nOne solution is to invert the signal before feeding it to the algorithm for detecting lows, as suggested by [@raoofhujairi](https://github.com/MonsieurV/py-findpeaks/issues/3).\n\nWith two runs, you can then get both lows and highs:\n\n![](/images/highs_and_lows_peakutils_indexes.png?raw=true \"High and low peaks with PeakUtils Indexes\")\n\nSee the related [sample code](/tests/lows_and_highs.py) using PeakUtils.\n\n----------------------------------\n\n# How to run the examples?\n\n## Install Numpy, Scipy and Matplotlib\n\nYou need to have Numpy, Scipy and Matplotlib installed - possibly the latest versions.\n\nTo install - and update - them for Python 3:\n\n```sh\npip3 install -U numpy scipy matplotlib\n```\n\n(you may need to run the command using `sudo` for a system-wide install)\n\n## Install test sample dependencies\n\nSome examples rely on other packages - like [PeakUtils](https://pypi.python.org/pypi/PeakUtils).\nInstall them using Pipenv to run all sample codes:\n\n```sh\n# Go in tests directory.\ncd tests/\n# Install dependencies in a virtualenv using Pipenv.\n# We install also Matplotlib so we can access it in the virtualenv.\npipenv --site-packages install --skip-lock\n```\n\n## Run an example\n\nYou can them run any example to see the results.\n\nFor e.g. for testing PeakUtils:\n\n```sh\npipenv run python3 peakutils_indexes.py\n```\n\n# Contribute\n\nFeel free to [open a new ticket](https://github.com/MonsieurV/py-findpeaks/issues/new) or submit a PR to improve this overview.\n\nHappy processing!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMonsieurV%2Fpy-findpeaks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FMonsieurV%2Fpy-findpeaks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMonsieurV%2Fpy-findpeaks/lists"}