%23%20%2F%2F%2F%20script%0A%23%20requires-python%20%3D%20%22%3E%3D3.9%22%0A%23%20dependencies%20%3D%20%5B%0A%23%20%20%20%20%20%22detecta%22%2C%0A%23%20%20%20%20%20%22marimo%22%2C%0A%23%20%20%20%20%20%22matplotlib%22%2C%0A%23%20%20%20%20%20%22numpy%22%2C%0A%23%20%20%20%20%20%22pyversions%22%2C%0A%23%20%5D%0A%23%20%2F%2F%2F%0A%0Aimport%20marimo%0A%0A__generated_with%20%3D%20%220.25.2%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20detect_peaks.py%0A%0A%20%20%20%20A%20function%20from%20%5Bdetecta%5D(https%3A%2F%2Fpypi.org%2Fproject%2Fdetecta%2F)%20-%20Python%20module%20to%20detect%20events%20in%20data.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20One%20way%20to%20detect%20peaks%20(local%20maxima)%20or%20valleys%20(local%20minima)%20in%20data%20is%20to%20use%20the%20property%20that%20a%20peak%20(or%20valley)%20must%20be%20greater%20(or%20smaller)%20than%20its%20immediate%20neighbors.%20The%20function%20%60detect_peaks.py%60%20(%5Bsource%20code%5D(https%3A%2F%2Fgithub.com%2Fdemotu%2Fdetecta%2Fblob%2Fmaster%2Fdetecta%2Fdetect_peaks.py))%20detects%20peaks%20(or%20valleys)%20based%20on%20this%20feature%20and%20other%20characteristics.%20The%20function%20signature%20is%3A%0A%20%20%20%20%60%60%60python%0A%20%20%20%20ind%20%3D%20detect_peaks(x%2C%20mph%3DNone%2C%20mpd%3D1%2C%20threshold%3D0%2C%20edge%3D'rising'%2C%20kpsh%3DFalse%2C%20valley%3DFalse%2C%20show%3DFalse%2C%20ax%3DNone%2C%20title%3DTrue)%0A%20%20%20%20%60%60%60%0A%20%20%20%20The%20parameters%20%60mph%60%2C%20%60mpd%60%2C%20and%20%60threshold%60%20follow%20the%20convention%20of%20the%20Matlab%20function%20%60findpeaks.m%60.%0A%20%20%20%20Let's%20see%20how%20to%20use%20%60detect_peaks.py%60%3B%20first%20let's%20import%20the%20necessary%20Python%20libraries%20and%20configure%20the%20environment.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Installation%0A%0A%20%20%20%20%60%60%60bash%0A%20%20%20%20pip%20install%20%22detecta%5Bplot%5D%22%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20Or%0A%0A%20%20%20%20%60%60%60bash%0A%20%20%20%20conda%20install%20-c%20duartexyz%20detecta%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20To%20run%20this%20%5Bmarimo%5D(https%3A%2F%2Fmarimo.io)%20notebook%20in%20an%20isolated%20environment%20with%20all%20its%20dependencies%3A%0A%0A%20%20%20%20%60%60%60bash%0A%20%20%20%20uvx%20marimo%20edit%20--sandbox%20detect_peaks.py%0A%20%20%20%20%60%60%60%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20timeit%0A%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20pyversions%0A%0A%20%20%20%20from%20detecta%20import%20detect_peaks%0A%0A%20%20%20%20return%20detect_peaks%2C%20mo%2C%20np%2C%20plt%2C%20pyversions%2C%20timeit%0A%0A%0A%40app.cell%0Adef%20_(pyversions)%3A%0A%20%20%20%20_info%20%3D%20pyversions.versions()%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Examples%0A%0A%20%20%20%20Detect%20all%20peaks%20in%20data%20with%20missing%20values%20(NaN's)%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(detect_peaks%2C%20np)%3A%0A%20%20%20%20_rng%20%3D%20np.random.default_rng(42)%0A%20%20%20%20_x%20%3D%20_rng.standard_normal(100)%0A%20%20%20%20_x%5B60%3A81%5D%20%3D%20np.nan%0A%20%20%20%20detect_peaks(_x%2C%20show%3DTrue)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Set%20minimum%20peak%20height%20%3D%200%20and%20minimum%20peak%20distance%20%3D%2020%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(detect_peaks%2C%20np)%3A%0A%20%20%20%20_rng%20%3D%20np.random.default_rng(42)%0A%20%20%20%20_x%20%3D%20np.sin(2*np.pi*5*np.linspace(0%2C%201%2C%20200))%20%2B%20_rng.standard_normal(200)%2F5%0A%20%20%20%20detect_peaks(_x%2C%20mph%3D0%2C%20mpd%3D20%2C%20show%3DTrue)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Set%20minimum%20peak%20distance%20%3D%202%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(detect_peaks)%3A%0A%20%20%20%20_x%20%3D%20%5B0%2C%201%2C%200%2C%202%2C%200%2C%203%2C%200%2C%202%2C%200%2C%201%2C%200%5D%0A%20%20%20%20detect_peaks(_x%2C%20mpd%3D2%2C%20show%3DTrue)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Detection%20of%20valleys%20instead%20of%20peaks%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(detect_peaks%2C%20np)%3A%0A%20%20%20%20_rng%20%3D%20np.random.default_rng(42)%0A%20%20%20%20_x%20%3D%20np.sin(2*np.pi*5*np.linspace(0%2C%201%2C%20200))%20%2B%20_rng.standard_normal(200)%2F5%0A%20%20%20%20detect_peaks(_x%2C%20mph%3D-1.2%2C%20mpd%3D20%2C%20valley%3DTrue%2C%20show%3DTrue)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Detect%20both%20edges%20of%20flat%20peaks%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(detect_peaks)%3A%0A%20%20%20%20_x%20%3D%20%5B0%2C%201%2C%201%2C%200%2C%201%2C%201%2C%200%5D%0A%20%20%20%20detect_peaks(_x%2C%20edge%3D'both'%2C%20show%3DTrue)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Set%20threshold%20%3D%202%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(detect_peaks)%3A%0A%20%20%20%20_x%20%3D%20%5B-2%2C%201%2C%20-2%2C%202%2C%201%2C%201%2C%203%2C%200%5D%0A%20%20%20%20detect_peaks(_x%2C%20threshold%3D2%2C%20show%3DTrue)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Plot%20in%20existing%20axes%2C%20without%20the%20standard%20title%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(detect_peaks%2C%20plt)%3A%0A%20%20%20%20_x%20%3D%20%5B-2%2C%201%2C%20-2%2C%202%2C%201%2C%201%2C%203%2C%200%5D%0A%20%20%20%20_fig%2C%20_axs%20%3D%20plt.subplots(ncols%3D2%2C%20nrows%3D1%2C%20figsize%3D(10%2C%204))%0A%20%20%20%20detect_peaks(_x%2C%20show%3DTrue%2C%20ax%3D_axs%5B0%5D%2C%20threshold%3D0.5%2C%20title%3DFalse)%0A%20%20%20%20detect_peaks(_x%2C%20show%3DTrue%2C%20ax%3D_axs%5B1%5D%2C%20threshold%3D1.5%2C%20title%3DFalse)%0A%20%20%20%20_fig%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Interactive%20example%0A%0A%20%20%20%20Change%20the%20parameters%20and%20see%20the%20detected%20peaks%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20use_mph%20%3D%20mo.ui.checkbox(value%3DTrue%2C%20label%3D'use%20mph')%0A%20%20%20%20mph%20%3D%20mo.ui.slider(-1.5%2C%201.5%2C%20step%3D0.1%2C%20value%3D0%2C%20label%3D'mph'%2C%20show_value%3DTrue)%0A%20%20%20%20mpd%20%3D%20mo.ui.slider(1%2C%2050%2C%20value%3D20%2C%20label%3D'mpd'%2C%20show_value%3DTrue)%0A%20%20%20%20threshold%20%3D%20mo.ui.slider(0%2C%201%2C%20step%3D0.05%2C%20value%3D0%2C%20label%3D'threshold'%2C%20show_value%3DTrue)%0A%20%20%20%20edge%20%3D%20mo.ui.dropdown(%5B'rising'%2C%20'falling'%2C%20'both'%5D%2C%20value%3D'rising'%2C%20label%3D'edge')%0A%20%20%20%20kpsh%20%3D%20mo.ui.checkbox(label%3D'kpsh')%0A%20%20%20%20valley%20%3D%20mo.ui.checkbox(label%3D'valley')%0A%20%20%20%20mo.hstack(%5Bmo.vstack(%5Buse_mph%2C%20mph%2C%20mpd%2C%20threshold%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.vstack(%5Bedge%2C%20kpsh%2C%20valley%5D)%5D%2C%20justify%3D'start'%2C%20gap%3D4)%0A%20%20%20%20return%20edge%2C%20kpsh%2C%20mpd%2C%20mph%2C%20threshold%2C%20use_mph%2C%20valley%0A%0A%0A%40app.cell%0Adef%20_(detect_peaks%2C%20edge%2C%20kpsh%2C%20mpd%2C%20mph%2C%20np%2C%20threshold%2C%20use_mph%2C%20valley)%3A%0A%20%20%20%20_rng%20%3D%20np.random.default_rng(42)%0A%20%20%20%20_x%20%3D%20np.sin(2*np.pi*5*np.linspace(0%2C%201%2C%20200))%20%2B%20_rng.normal(0%2C%20.2%2C%20200)%0A%20%20%20%20detect_peaks(_x%2C%20mph%3Dmph.value%20if%20use_mph.value%20else%20None%2C%20mpd%3Dmpd.value%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20threshold%3Dthreshold.value%2C%20edge%3Dedge.value%2C%20kpsh%3Dkpsh.value%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20valley%3Dvalley.value%2C%20show%3DTrue)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Function%20performance%0A%0A%20%20%20%20The%20function%20%60detect_peaks.py%60%20is%20relatively%20fast%20but%20the%20parameter%20minimum%20peak%20distance%20(mpd)%20slows%20down%20the%20function%20if%20the%20data%20has%20several%20peaks%20(%3E1000).%20Try%20to%20decrease%20the%20number%20of%20peaks%20by%20tuning%20the%20other%20parameters%20or%20smooth%20the%20data%20before%20calling%20this%20function%20with%20several%20peaks%20in%20the%20data.%0A%20%20%20%20Here%20is%20a%20simple%20test%20of%20its%20performance%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(detect_peaks%2C%20np%2C%20timeit)%3A%0A%20%20%20%20_rng%20%3D%20np.random.default_rng(42)%0A%20%20%20%20_x%20%3D%20_rng.standard_normal(10000)%0A%20%20%20%20_ind%20%3D%20detect_peaks(_x)%0A%20%20%20%20print('Data%20with%20%25d%20points%20and%20%25d%20peaks%5Cn'%20%25%20(_x.size%2C%20_ind.size))%0A%0A%20%20%20%20def%20_bench(stmt%2C%20number%3D100)%3A%0A%20%20%20%20%20%20%20%20t%20%3D%20min(timeit.repeat(stmt%2C%20number%3Dnumber%2C%20repeat%3D5))%20%2F%20number%0A%20%20%20%20%20%20%20%20print('%25.3f%20ms%20per%20loop'%20%25%20(1e3*t))%0A%0A%20%20%20%20print('Performance%20(without%20the%20minimum%20peak%20distance%20parameter)%3A')%0A%20%20%20%20print('detect_peaks(x)')%0A%20%20%20%20_bench(lambda%3A%20detect_peaks(_x))%0A%20%20%20%20print('%5CnPerformance%20(using%20the%20minimum%20peak%20distance%20parameter)%3A')%0A%20%20%20%20print('detect_peaks(x%2C%20mpd%3D10)')%0A%20%20%20%20_bench(lambda%3A%20detect_peaks(_x%2C%20mpd%3D10)%2C%20number%3D10)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
d7defcf5df33e2b4e925ae5b15cd9730