%23%20%2F%2F%2F%20script%0A%23%20requires-python%20%3D%20%22%3E%3D3.11%22%0A%23%20dependencies%20%3D%20%5B%0A%23%20%20%20%20%20%22marimo%3E%3D0.23.9%22%2C%0A%23%20%20%20%20%20%22matplotlib%3E%3D3.10%22%2C%0A%23%20%20%20%20%20%22numpy%3E%3D2.0%22%2C%0A%23%20%20%20%20%20%22pandas%3E%3D2.2%22%2C%0A%23%20%20%20%20%20%22scipy%3E%3D1.14%22%2C%0A%23%20%20%20%20%20%22sympy%3E%3D1.13%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%20Tutorial%20on%20Python%20for%20scientific%20computing%0A%0A%20%20%20%20%3E%20Marcos%20Duarte%2C%20Renato%20Naville%20Watanabe%3Cbr%3E%0A%20%20%20%20%3E%20%5BLaboratory%20of%20Biomechanics%20and%20Motor%20Control%5D(https%3A%2F%2Fbmclab.pesquisa.ufabc.edu.br%2F)%3Cbr%3E%0A%20%20%20%20%3E%20Federal%20University%20of%20ABC%2C%20Brazil%0A%0A%20%20%20%20Learn%20Python%20by%20calculating%2C%20organizing%20measurements%2C%20and%20exploring%20scientific%20examples%20in%20a%20%5Bmarimo%5D(https%3A%2F%2Fmarimo.io%2F)%20notebook.%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%20How%20to%20use%20this%20guide%0A%0A%20%20%20%20This%20tutorial%20introduces%20the%20Python%20language%20and%20its%20scientific%20computing%20tools.%20No%20programming%20experience%20is%20assumed.%20We%20use%20marimo%20to%20put%20explanations%2C%20executable%20Python%2C%20figures%2C%20and%20experiments%20together.%20The%20Python%20you%20learn%20here%20also%20applies%20to%20programs%20outside%20a%20notebook.%0A%0A%20%20%20%20Work%20through%20the%20guide%20in%20stages%3A%0A%0A%20%20%20%201.%20**Get%20oriented%3A**%20open%20the%20notebook%20and%20learn%20how%20marimo%20runs%20cells.%0A%20%20%20%202.%20**Learn%20Python%3A**%20expressions%2C%20names%2C%20types%2C%20collections%2C%20decisions%2C%20loops%2C%20functions%2C%20and%20errors.%0A%20%20%20%203.%20**Work%20with%20scientific%20data%3A**%20NumPy%20arrays%2C%20interpolation%2C%20files%2C%20Matplotlib%20figures%2C%20SciPy%20signal%20processing%2C%20SymPy%20mathematics%2C%20and%20pandas%20tables.%0A%20%20%20%204.%20**Put%20it%20together%3A**%20explore%20an%20interactive%20model%20and%20analyze%20a%20set%20of%20walking%20trials.%0A%0A%20%20%20%20Read%20the%20examples%20in%20order.%20Before%20running%20a%20cell%2C%20predict%20its%20result%3B%20afterward%2C%20change%20an%20input%20and%20explain%20what%20happened.%20Try%20each%20**Exercise**%20before%20opening%20its%20worked%20solution.%20The%20final%20**Problems**%20provide%20independent%20practice%2C%20with%20final%20answers%20in%20a%20separate%20panel.%20The%20scientific%20sections%20can%20be%20studied%20over%20several%20sessions.%0A%0A%20%20%20%20**Challenge%200.**%20A%20walker%20covers%206%20metres%20in%204%20seconds.%20How%20would%20you%20calculate%20the%20average%20speed%3F%20How%20would%20your%20program%20handle%20three%20trials%2C%20or%20a%20trial%20whose%20duration%20was%20recorded%20as%20zero%3F%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%20Python%20setup%0A%0A%20%20%20%20The%20language%20examples%20need%20Python%20and%20marimo.%20The%20scientific%20examples%20also%20use%20NumPy%2C%20Matplotlib%2C%20SciPy%2C%20SymPy%2C%20and%20pandas.%20This%20repository%20declares%20its%20environment%20in%20%60pyproject.toml%60%20and%20%60uv.lock%60%3B%20the%20notebook%20also%20declares%20its%20dependencies%20for%20services%20that%20open%20it%20independently.%0A%0A%20%20%20%20For%20installation%20instructions%2C%20see%20%5BPython%20installation%5D(https%3A%2F%2Fmolab.marimo.io%2Fgithub%2FBMClab%2FBMC%2Fblob%2Fmaster%2Fnotebooks%2Fpython_installation.py).%20From%20a%20local%20copy%20of%20the%20repository%2C%20enter%20these%20commands%20in%20a%20**terminal**%2C%20in%20the%20repository's%20root%20folder%3A%0A%0A%20%20%20%20%60%60%60bash%0A%20%20%20%20uv%20sync%0A%20%20%20%20uv%20run%20marimo%20edit%20notebooks%2Fpython_tutorial.py%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20If%20you%20are%20reading%20the%20saved%20HTML%20page%2C%20choose%20**Edit%20in%20browser**%20or%20a%20launch%20badge%20to%20run%20and%20edit%20the%20examples.%20The%20saved%20page%20shows%20results%20from%20a%20previous%20execution%3B%20it%20cannot%20recalculate%20Python%20when%20you%20move%20a%20slider.%20Download%20the%20%60.py%60%20file%20to%20keep%20a%20copy%20of%20the%20notebook.%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%20marimo%20as%20mo%0A%0A%20%20%20%20return%20(mo%2C)%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%20Introduction%20to%20marimo%0A%0A%20%20%20%20A%20notebook%20is%20a%20document%20made%20of%20**cells**.%20Text%20cells%20explain%20a%20question%20or%20a%20result%3B%20code%20cells%20contain%20Python%20that%20you%20can%20edit%20and%20execute.%20marimo%20saves%20this%20document%20as%20a%20Python%20%60.py%60%20file%2C%20so%20you%20can%20download%20it%2C%20reopen%20it%2C%20and%20track%20its%20changes%20with%20version%20control.%0A%0A%20%20%20%20The%20official%20%5Bmarimo%20Getting%20Started%20guide%5D(https%3A%2F%2Fdocs.marimo.io%2Fgetting_started%2F)%20includes%20installation%2C%20a%20quickstart%2C%20and%20a%20tour%20of%20the%20key%20concepts.%20Here%20is%20enough%20to%20work%20through%20this%20tutorial%3A%0A%0A%20%20%20%201.%20Open%20the%20notebook%20in%20the%20editor%20and%20run%20its%20cells%20with%20**Run%20all**%20if%20they%20have%20not%20run%20already.%0A%20%20%20%202.%20Read%20a%20code%20cell%2C%20edit%20it%2C%20and%20use%20its%20run%20control%20to%20execute%20the%20edited%20code.%0A%20%20%20%203.%20The%20cell's%20**last%20expression**%20is%20displayed%20as%20its%20result.%20Use%20%60print(...)%60%20to%20display%20several%20intermediate%20values%20or%20messages.%20An%20assignment%20alone%20does%20not%20display%20the%20assigned%20value.%0A%20%20%20%204.%20Add%20a%20code%20cell%20for%20your%20experiments.%20Text%20cells%20use%20Markdown%2C%20commonly%20through%20%60mo.md(...)%60%2C%20to%20combine%20prose%2C%20links%2C%20and%20mathematics.%20The%20editor%20manages%20the%20surrounding%20cell%20definitions%20in%20the%20saved%20Python%20file.%0A%0A%20%20%20%20%23%23%23%20Reactive%20execution%0A%0A%20%20%20%20marimo%20tracks%20which%20cells%20define%20and%20use%20each%20name.%20In%20automatic%20execution%20mode%2C%20running%20a%20changed%20cell%20also%20reruns%20the%20cells%20that%20depend%20on%20it.%20In%20lazy%20execution%20mode%2C%20dependent%20cells%20are%20marked%20stale%20and%20you%20run%20them%20when%20ready.%20Dependencies%20determine%20execution%20order%3B%20reading%20the%20notebook%20from%20top%20to%20bottom%20gives%20the%20teaching%20order.%0A%0A%20%20%20%20Keep%20each%20shared%20name%2C%20such%20as%20%60distance_m%60%2C%20**defined%20in%20one%20cell**.%20To%20change%20an%20input%2C%20edit%20that%20defining%20cell.%20Ordinary%20reassignment%20within%20a%20cell%20or%20a%20function%20is%20still%20valid%20Python.%20For%20a%20scratch%20calculation%2C%20a%20name%20beginning%20with%20%60_%60%2C%20such%20as%20%60_result%60%2C%20is%20local%20to%20that%20marimo%20cell%20and%20can%20be%20reused%20in%20another%20cell.%20This%20cell-local%20behavior%20is%20a%20marimo%20convention%2C%20not%20a%20general%20Python%20scoping%20rule.%0A%0A%20%20%20%20Also%20avoid%20defining%20a%20list%20or%20table%20in%20one%20cell%20and%20modifying%20it%20in%20another%3A%20marimo%20does%20not%20track%20those%20mutations.%20Make%20the%20changes%20in%20the%20cell%20that%20creates%20the%20object%2C%20or%20create%20a%20new%20object%20with%20a%20new%20name.%20We%20will%20practice%20this%20when%20working%20with%20collections.%0A%0A%20%20%20%20**Guiding%20question.**%20If%20a%20result%20should%20change%20when%20a%20walking%20time%20changes%2C%20should%20its%20code%20use%20the%20name%20of%20that%20time%20or%20a%20copied%20number%3F%20Look%20for%20this%20dependency%20in%20the%20next%20examples.%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%20Python%20as%20a%20calculator%0A%0A%20%20%20%20An%20**expression**%20combines%20values%20and%20operations%20to%20produce%20a%20value.%20Run%20this%20first%20calculation%2C%20then%20replace%20one%20of%20its%20numbers.%20The%20result%20is%20an%20average%20speed%20in%20metres%20per%20second%20because%20we%20supplied%20metres%20and%20seconds%3B%20Python%20itself%20does%20not%20attach%20units%20to%20ordinary%20numbers.%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%206%20%2F%204%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%20The%20main%20arithmetic%20operators%20are%3A%0A%0A%20%20%20%20%7C%20Operator%20%7C%20Meaning%20%7C%20Example%20%7C%0A%20%20%20%20%7C%20---%20%7C%20---%20%7C%20---%20%7C%0A%20%20%20%20%7C%20%60%2B%60%2C%20%60-%60%20%7C%20Addition%2C%20subtraction%20%7C%20%606%20%2B%204%60%2C%20%606%20-%204%60%20%7C%0A%20%20%20%20%7C%20%60*%60%2C%20%60%2F%60%20%7C%20Multiplication%2C%20division%20%7C%20%606%20*%204%60%2C%20%606%20%2F%204%60%20%7C%0A%20%20%20%20%7C%20%60%2F%2F%60%2C%20%60%25%60%20%7C%20Floor%20division%2C%20remainder%20%7C%20%607%20%2F%2F%203%60%2C%20%607%20%25%203%60%20%7C%0A%20%20%20%20%7C%20%60**%60%20%7C%20Exponentiation%20%7C%20%603%20**%202%60%20%7C%0A%0A%20%20%20%20Multiplication%20and%20division%20take%20precedence%20over%20addition%20and%20subtraction.%20Parentheses%20make%20the%20intended%20order%20explicit.%20%60**%60%20is%20exponentiation%3B%20%60%5E%60%20is%20a%20different%20operation%2C%20called%20bitwise%20exclusive%20OR.%20%60%2F%60%20produces%20a%20floating-point%20result%20even%20when%20both%20operands%20are%20integers.%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%20print(%222%20%2B%203%20*%204%20%3D%22%2C%202%20%2B%203%20*%204)%0A%20%20%20%20print(%22(2%20%2B%203)%20*%204%20%3D%22%2C%20(2%20%2B%203)%20*%204)%0A%20%20%20%20print(%227%20%2F%203%20%3D%22%2C%207%20%2F%203)%0A%20%20%20%20print(%227%20%2F%2F%203%20%3D%22%2C%207%20%2F%2F%203%2C%20%22and%207%20%25%203%20%3D%22%2C%207%20%25%203)%0A%20%20%20%20print(%223%20**%202%20%3D%22%2C%203**2)%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%20Assignment%2C%20expressions%2C%20and%20names%0A%0A%20%20%20%20%60%3D%60%20assigns%20the%20value%20on%20its%20right%20to%20the%20name%20on%20its%20left.%20A%20variable%20name%20lets%20you%20refer%20to%20that%20value%20later.%20Use%20meaningful%20names%2C%20with%20units%20when%20useful%2C%20instead%20of%20relying%20on%20your%20memory%20of%20what%20a%20number%20means.%20Python%20names%20are%20case%20sensitive%3A%20%60time_s%60%20and%20%60Time_s%60%20are%20different%20names.%0A%0A%20%20%20%20The%20following%20cell%20defines%20two%20inputs.%20The%20next%20cell%20uses%20them%20to%20calculate%20a%20result.%20Change%20%60time_s%60%20from%20%604.0%60%20to%20%608.0%60%20in%20its%20defining%20cell%20and%20run%20that%20cell.%20In%20automatic%20mode%2C%20the%20speed%20updates%20too.%20Restore%20%604.0%60%20before%20continuing%20if%20you%20want%20to%20reproduce%20the%20printed%20answers%20in%20this%20guide.%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%20distance_m%20%3D%206.0%0A%20%20%20%20time_s%20%3D%204.0%0A%20%20%20%20return%20distance_m%2C%20time_s%0A%0A%0A%40app.cell%0Adef%20_(distance_m%2C%20time_s)%3A%0A%20%20%20%20speed_m_s%20%3D%20distance_m%20%2F%20time_s%0A%20%20%20%20print(f%22Speed%3A%20%7Bspeed_m_s%3A.2f%7D%20m%2Fs%22)%0A%20%20%20%20return%20(speed_m_s%2C)%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%20Assignment%20is%20an%20instruction%2C%20not%20an%20equation%20to%20solve.%20%60_count%20%3D%20_count%20%2B%201%60%20evaluates%20the%20old%20value%2C%20adds%20one%2C%20and%20assigns%20the%20result%20back%20to%20the%20name.%20%60_count%20%2B%3D%201%60%20is%20a%20shorter%20way%20to%20express%20this%20update%20for%20a%20number.%20Multiple%20assignment%20can%20unpack%20values%20or%20swap%20them.%0A%0A%20%20%20%20These%20scratch%20names%20begin%20with%20%60_%60%20so%20they%20stay%20in%20this%20marimo%20cell.%20The%20statements%20inside%20the%20cell%20execute%20in%20their%20written%20order.%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%20_count%20%3D%202%0A%20%20%20%20_count%20%3D%20_count%20%2B%201%0A%20%20%20%20_count%20%2B%3D%201%0A%20%20%20%20_left%2C%20_right%20%3D%205%2C%206%0A%20%20%20%20_left%2C%20_right%20%3D%20_right%2C%20_left%0A%20%20%20%20print(%22Count%3A%22%2C%20_count)%0A%20%20%20%20print(%22After%20swapping%3A%22%2C%20_left%2C%20_right)%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**Exercise%201.**%20Predict%20%602%20**%203%60%2C%20%608%20%2F%202%60%2C%20and%20%608%20%2F%2F%203%60.%20For%20the%20walking%20example%2C%20what%20happens%20when%20time%20doubles%3F%20Would%20a%20separate%20cell%20containing%20%606%20%2F%204%60%20change%20too%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Solution%20to%20Exercise%201%0A%20%20%20%20The%20results%20are%20%608%60%2C%20%604.0%60%2C%20and%20%602%60.%20Doubling%20time%20from%204%20to%208%20s%20halves%20the%20speed%20from%201.5%20to%200.75%20m%2Fs.%20A%20literal%20expression%20%606%20%2F%204%60%20stays%20unchanged%20because%20it%20does%20not%20refer%20to%20%60time_s%60.%20Use%20the%20variable%20to%20express%20the%20dependency.%0A%20%20%20%20%2F%2F%2F%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%20Imports%2C%20objects%2C%20and%20help%0A%0A%20%20%20%20Python%20provides%20built-in%20functions%20such%20as%20%60print%60%2C%20%60len%60%2C%20and%20%60type%60.%20Other%20functions%20are%20organized%20in%20**modules**%20and%20**packages**.%20The%20%60import%60%20statement%20makes%20a%20module%20available%3B%20it%20is%20a%20statement%2C%20not%20a%20function%20call.%20The%20standard%20library%20comes%20with%20Python.%20Scientific%20packages%20such%20as%20NumPy%20are%20installed%20separately%20in%20the%20environment.%0A%0A%20%20%20%20After%20%60import%20math%60%2C%20use%20a%20dot%20to%20access%20a%20name%20in%20that%20module%3A%20%60math.sqrt(9)%60%20calls%20its%20square-root%20function.%20The%20trigonometric%20functions%20in%20%60math%60%20use%20radians.%20You%20can%20also%20import%20a%20particular%20name%2C%20as%20in%20%60from%20math%20import%20sqrt%60%2C%20or%20give%20a%20module%20an%20alias%2C%20as%20we%20will%20do%20with%20%60import%20numpy%20as%20np%60.%20Prefer%20explicit%20imports%20over%20%60from%20module%20import%20*%60%2C%20which%20obscures%20where%20names%20come%20from.%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%20math%0A%20%20%20%20import%20platform%0A%0A%20%20%20%20print(%22Python%20version%3A%22%2C%20platform.python_version())%0A%20%20%20%20print(%22Square%20root%20of%209%3A%22%2C%20math.sqrt(9))%0A%20%20%20%20print(%22Cosine%20of%20pi%20radians%3A%22%2C%20math.cos(math.pi))%0A%20%20%20%20return%20(math%2C)%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%23%20Objects%2C%20attributes%2C%20and%20methods%0A%0A%20%20%20%20Values%20in%20Python%20are%20**objects**.%20An%20object%20has%20a%20type%20and%20may%20expose%20attributes%20and%20methods%20through%20the%20dot%20operator.%20An%20attribute%20holds%20information%3B%20a%20method%20is%20an%20operation%20attached%20to%20the%20object.%20For%20example%2C%20%60math.pi%60%20is%20an%20attribute%20of%20the%20module%2C%20and%20%60%22trial%22.upper()%60%20calls%20a%20string%20method.%20Later%2C%20an%20array's%20%60.shape%60%20will%20describe%20its%20dimensions.%0A%0A%20%20%20%20Python%20supports%20object-oriented%20programming%20with%20classes%2C%20but%20you%20can%20use%20these%20objects%20before%20learning%20to%20define%20your%20own%20classes.%0A%0A%20%20%20%20%23%23%23%20Finding%20out%20how%20something%20works%0A%0A%20%20%20%20%60help(object)%60%20displays%20documentation%3B%20%60dir(object)%60%20lists%20available%20names.%20A%20function's%20documentation%20explains%20its%20parameters%20and%20returned%20result.%20The%20marimo%20editor%20also%20offers%20completion%20and%20documentation%20while%20you%20type.%20Standard%20Python%20calls%20work%20in%20these%20cells%3B%20IPython-specific%20syntax%20such%20as%20%60math.sqrt%3F%60%20or%20%60%25matplotlib%20inline%60%20is%20unnecessary%20here.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(math)%3A%0A%20%20%20%20help(math.sqrt)%0A%20%20%20%20print(%22Available%20names%20in%20math%3A%22%2C%20dir(math))%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%23%20Comments%20and%20readable%20code%0A%0A%20%20%20%20A%20comment%20starts%20with%20%60%23%60%20and%20continues%20to%20the%20end%20of%20the%20line.%20Explain%20an%20assumption%20or%20a%20reason%2C%20such%20as%20%60%23%20Ignore%20the%20first%20sample%20because%20acquisition%20had%20not%20started%60.%20Notebook%20text%20explains%20the%20broader%20scientific%20argument.%20A%20**docstring**%20is%20a%20string%20at%20the%20start%20of%20a%20function%2C%20class%2C%20or%20module%20that%20documents%20it%3B%20a%20triple-quoted%20string%20elsewhere%20is%20still%20a%20string%2C%20not%20a%20special%20multiline-comment%20syntax.%0A%0A%20%20%20%20Use%20descriptive%20%60snake_case%60%20names%2C%20spaces%20around%20arithmetic%20operators%2C%20and%20four%20spaces%20for%20each%20indentation%20level.%20Avoid%20names%20such%20as%20%60list%60%2C%20%60sum%60%2C%20or%20%60print%60%20for%20your%20own%20variables%20because%20they%20would%20hide%20Python's%20built-ins.%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%20Values%20and%20types%0A%0A%20%20%20%20A%20value's%20**type**%20determines%20the%20operations%20it%20supports.%20Python%20infers%20types%20from%20values%3B%20you%20do%20not%20need%20to%20declare%20a%20variable's%20type%20before%20using%20it.%0A%0A%20%20%20%20%7C%20Type%20%7C%20Example%20%7C%20Typical%20use%20%7C%0A%20%20%20%20%7C%20---%20%7C%20---%20%7C%20---%20%7C%0A%20%20%20%20%7C%20%60int%60%20%7C%20%603%60%20%7C%20Counts%20and%20indices%20%7C%0A%20%20%20%20%7C%20%60float%60%20%7C%20%603.0%60%2C%20%601.2e-3%60%20%7C%20Measurements%20and%20numerical%20calculations%20%7C%0A%20%20%20%20%7C%20%60complex%60%20%7C%20%601%20%2B%202j%60%20%7C%20Numbers%20with%20real%20and%20imaginary%20parts%20%7C%0A%20%20%20%20%7C%20%60str%60%20%7C%20%60%22trial%201%22%60%20%7C%20Text%20%7C%0A%20%20%20%20%7C%20%60bool%60%20%7C%20%60True%60%2C%20%60False%60%20%7C%20Conditions%20%7C%0A%20%20%20%20%7C%20%60NoneType%60%20%7C%20%60None%60%20%7C%20An%20absent%20value%20or%20no%20returned%20result%20%7C%0A%0A%20%20%20%20%603.0%60%20is%20a%20float%20even%20though%20its%20numerical%20value%20is%20a%20whole%20number.%20%60None%60%20is%20not%20zero%20and%20is%20not%20the%20string%20%60%22None%22%60.%20Use%20%60type(value)%60%20to%20inspect%20a%20type%2C%20and%20explicit%20conversions%20such%20as%20%60float(%224.2%22)%60%20when%20text%20represents%20a%20number.%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%20print(%223%3A%22%2C%20type(3))%0A%20%20%20%20print(%223.0%3A%22%2C%20type(3.0))%0A%20%20%20%20print(%221%20%2B%202j%3A%22%2C%20type(1%20%2B%202j))%0A%20%20%20%20print('%22trial%201%22%3A'%2C%20type(%22trial%201%22))%0A%20%20%20%20print(%22True%3A%22%2C%20type(True))%0A%20%20%20%20print(%22None%3A%22%2C%20type(None))%0A%20%20%20%20print(%22Converted%20duration%3A%22%2C%20float(%224.2%22))%0A%20%20%20%20print(%22Truncation%20toward%20zero%3A%22%2C%20int(4.9))%0A%20%20%20%20print(%22Complex%20parts%3A%22%2C%20(1%20%2B%202j).real%2C%20(1%20%2B%202j).imag)%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%23%20Floating-point%20arithmetic%0A%0A%20%20%20%20Most%20decimal%20fractions%20cannot%20be%20represented%20exactly%20by%20a%20finite%20binary%20floating-point%20number.%20Small%20rounding%20differences%20are%20therefore%20expected%20in%20numerical%20calculations.%20Displaying%20fewer%20decimal%20places%20changes%20how%20a%20number%20is%20shown%3B%20it%20does%20not%20change%20the%20stored%20value.%0A%0A%20%20%20%20Use%20a%20tolerance%20when%20comparing%20calculated%20floats.%20%60math.isclose(a%2C%20b)%60%20compares%20them%20approximately.%20Near%20zero%2C%20choose%20a%20meaningful%20absolute%20tolerance%20with%20%60abs_tol%60%2C%20considering%20the%20units%20and%20accuracy%20of%20your%20problem.%20A%20computer%20tolerance%20is%20not%20a%20substitute%20for%20an%20experimental%20uncertainty%20estimate.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(math)%3A%0A%20%20%20%20print(%220.1%20%2B%200.2%3A%22%2C%200.1%20%2B%200.2)%0A%20%20%20%20print(%22Exact%20comparison%3A%22%2C%200.1%20%2B%200.2%20%3D%3D%200.3)%0A%20%20%20%20print(%22Approximate%20comparison%3A%22%2C%20math.isclose(0.1%20%2B%200.2%2C%200.3))%0A%20%20%20%20print(%22Residual%20near%20zero%3A%22%2C%20math.isclose(0.1%20%2B%200.2%20-%200.3%2C%200%2C%20abs_tol%3D1e-12))%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%20Strings%0A%0A%20%20%20%20Strings%20hold%20text.%20Single%20or%20double%20quotes%20delimit%20a%20string%3B%20choose%20the%20form%20that%20makes%20embedded%20quotation%20marks%20easy%20to%20read.%20%60%5Cn%60%20represents%20a%20newline.%20%60%2B%60%20joins%20strings%20and%20%60*%60%20repeats%20them.%20Neither%20operator%20converts%20numeric%20text%20into%20numbers%20automatically%3A%20%60%224.0%22%20%2B%20%224.2%22%60%20produces%20%60%224.04.2%22%60.%0A%0A%20%20%20%20Indexing%20starts%20at%20zero.%20A%20negative%20index%20counts%20from%20the%20end.%20A%20slice%20%60%5Bstart%3Astop%3Astep%5D%60%20includes%20%60start%60%20and%20excludes%20%60stop%60%3B%20omitted%20bounds%20extend%20to%20the%20beginning%20or%20end.%20These%20ideas%20also%20apply%20to%20lists%20and%20tuples.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(speed_m_s)%3A%0A%20%20%20%20_word%20%3D%20%22Python%22%0A%20%20%20%20_label%20%3D%20%22%20%20participant%20P01%20%20%22%0A%20%20%20%20_csv_line%20%3D%20%22P01%2C4.2%22%0A%20%20%20%20_label_parts%20%3D%20%5B%22P01%22%2C%20%22trial%22%2C%20%2201%22%5D%0A%20%20%20%20print(%22First%20and%20last%3A%22%2C%20_word%5B0%5D%2C%20_word%5B-1%5D)%0A%20%20%20%20print(%22Slices%3A%22%2C%20_word%5B%3A2%5D%2C%20_word%5B2%3A%5D%2C%20_word%5B%3A%3A2%5D)%0A%20%20%20%20print(%22Cleaned%20label%3A%22%2C%20_label.strip().lower())%0A%20%20%20%20print(%22Split%20fields%3A%22%2C%20_csv_line.split(%22%2C%22))%0A%20%20%20%20print(%22Joined%20label%3A%22%2C%20%22-%22.join(_label_parts))%0A%20%20%20%20print(f%22Speed%3A%20%7Bspeed_m_s%3A.2f%7D%20m%2Fs%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%20An%20**f-string**%2C%20prefixed%20with%20%60f%60%2C%20inserts%20expressions%20between%20braces.%20In%20%60%7Bspeed_m_s%3A.2f%7D%60%2C%20%60.2f%60%20requests%20two%20digits%20after%20the%20decimal%20point.%20String%20methods%20such%20as%20%60.strip()%60%20and%20%60.lower()%60%20return%20new%20strings%3A%20strings%20are%20immutable%2C%20so%20their%20characters%20cannot%20be%20changed%20in%20place.%0A%0A%20%20%20%20**Exercise%202.**%20What%20are%20%60%22Python%22%5B1%3A4%5D%60%2C%20%60len(%22Python%22)%60%2C%20and%20%60float(%224.0%22)%20%2B%20float(%224.2%22)%60%3F%20Does%20%60int(4.9)%60%20round%20to%20the%20nearest%20integer%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Solution%20to%20Exercise%202%0A%20%20%20%20The%20results%20are%20%60%22yth%22%60%2C%20%606%60%2C%20and%20%608.2%60.%20%60int(4.9)%60%20gives%20%604%60%3A%20conversion%20truncates%20toward%20zero.%20Use%20a%20rounding%20operation%20when%20rounding%20is%20intended.%0A%20%20%20%20%2F%2F%2F%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%20Collections%3A%20lists%2C%20tuples%2C%20sets%2C%20and%20dictionaries%0A%0A%20%20%20%20%23%23%23%20Lists%20and%20slicing%0A%0A%20%20%20%20A%20list%20stores%20an%20ordered%20sequence%20of%20objects.%20It%20can%20hold%20measurements%2C%20labels%2C%20or%20other%20lists.%20%60len%60%20gives%20its%20length%3B%20%60sum%60%2C%20%60min%60%2C%20and%20%60max%60%20summarize%20numeric%20items.%20Predict%20the%20first%20item%2C%20last%20item%2C%20and%20slice%20below%20before%20running%20the%20cells.%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%20trial_times_s%20%3D%20%5B4.0%2C%204.2%2C%203.8%5D%0A%20%20%20%20print(%22All%20durations%3A%22%2C%20trial_times_s)%0A%20%20%20%20print(%22First%20and%20last%3A%22%2C%20trial_times_s%5B0%5D%2C%20trial_times_s%5B-1%5D)%0A%20%20%20%20print(%22Items%20at%20positions%201%20and%202%3A%22%2C%20trial_times_s%5B1%3A3%5D)%0A%20%20%20%20print(%22Reversed%3A%22%2C%20trial_times_s%5B%3A%3A-1%5D)%0A%20%20%20%20print(%0A%20%20%20%20%20%20%20%20%22Count%3A%22%2C%20len(trial_times_s)%2C%20%22Mean%3A%22%2C%20sum(trial_times_s)%20%2F%20len(trial_times_s)%0A%20%20%20%20)%0A%20%20%20%20return%20(trial_times_s%2C)%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%20Lists%20are%20**mutable**%3A%20you%20can%20replace%20an%20item%20or%20append%20one.%20Assignment%20does%20not%20copy%20an%20object.%20Two%20names%20can%20refer%20to%20the%20same%20list%2C%20so%20modifying%20it%20through%20either%20name%20changes%20that%20list.%20%60.copy()%60%20makes%20a%20shallow%20copy%2C%20which%20is%20enough%20for%20this%20flat%20list%20of%20numbers.%20A%20nested%20list%20needs%20more%20care%20because%20its%20inner%20objects%20are%20still%20shared.%0A%0A%20%20%20%20%60.append(...)%60%20changes%20the%20list%20and%20returns%20%60None%60%3B%20%60sorted(...)%60%20returns%20a%20new%20sorted%20list.%20All%20mutations%20in%20the%20next%20example%20happen%20in%20the%20cell%20that%20creates%20the%20list%2C%20keeping%20the%20marimo%20dependency%20graph%20clear.%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%20_original%20%3D%20%5B4.0%2C%204.2%2C%203.8%5D%0A%20%20%20%20_alias%20%3D%20_original%0A%20%20%20%20_copy%20%3D%20_original.copy()%0A%20%20%20%20_alias%5B0%5D%20%3D%205.0%0A%20%20%20%20_original.append(4.1)%0A%20%20%20%20print(%22Original%20and%20alias%3A%22%2C%20_original%2C%20_alias)%0A%20%20%20%20print(%22Independent%20copy%3A%22%2C%20_copy)%0A%20%20%20%20print(%22Sorted%20copy%3A%22%2C%20sorted(_original))%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(trial_times_s)%3A%0A%20%20%20%20extended_times_s%20%3D%20trial_times_s%20%2B%20%5B4.1%5D%0A%20%20%20%20print(%22A%20new%20list%3A%22%2C%20extended_times_s)%0A%20%20%20%20print(%22The%20input%20list%3A%22%2C%20trial_times_s)%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%23%20Other%20useful%20containers%0A%0A%20%20%20%20%7C%20Container%20%7C%20Example%20%7C%20Main%20idea%20%7C%0A%20%20%20%20%7C%20---%20%7C%20---%20%7C%20---%20%7C%0A%20%20%20%20%7C%20List%20%7C%20%60%5B4.0%2C%204.2%2C%203.8%5D%60%20%7C%20Ordered%2C%20mutable%20sequence%20%7C%0A%20%20%20%20%7C%20Tuple%20%7C%20%60(6.0%2C%204.0)%60%20%7C%20Immutable%20sequence%3B%20convenient%20for%20fixed%20groups%20of%20values%20%7C%0A%20%20%20%20%7C%20Set%20%7C%20%60%7B%22P01%22%2C%20%22P02%22%7D%60%20%7C%20Distinct%20elements%3B%20no%20positional%20indexing%20%7C%0A%20%20%20%20%7C%20Dictionary%20%7C%20%60%7B%22label%22%3A%20%22P01%22%2C%20%22distance_m%22%3A%206.0%7D%60%20%7C%20Values%20accessed%20by%20keys%20%7C%0A%0A%20%20%20%20A%20tuple's%20items%20cannot%20be%20replaced%2C%20although%20a%20mutable%20object%20inside%20a%20tuple%20can%20still%20change.%20An%20empty%20set%20is%20%60set()%60%3B%20%60%7B%7D%60%20creates%20an%20empty%20dictionary.%20%60in%60%20tests%20membership%3A%20in%20a%20dictionary%20it%20checks%20keys.%20A%20dictionary%20preserves%20insertion%20order%2C%20but%20a%20set's%20iteration%20order%20should%20not%20be%20used%20to%20assign%20scientific%20meaning.%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%20_measurement%20%3D%20(6.0%2C%204.0)%0A%20%20%20%20_distance%2C%20_duration%20%3D%20_measurement%0A%20%20%20%20_labels%20%3D%20%5B%22P01%22%2C%20%22P02%22%2C%20%22P01%22%5D%0A%20%20%20%20_participants%20%3D%20set(_labels)%0A%20%20%20%20participant%20%3D%20%7B%22label%22%3A%20%22P01%22%2C%20%22distance_m%22%3A%206.0%7D%0A%20%20%20%20print(%22Unpacked%20tuple%3A%22%2C%20_distance%2C%20_duration)%0A%20%20%20%20print(%22Unique%20labels%2C%20sorted%20for%20display%3A%22%2C%20sorted(_participants))%0A%20%20%20%20print(%22Dictionary%20lookup%3A%22%2C%20participant%5B%22label%22%5D)%0A%20%20%20%20print(%22Dictionary%20items%3A%22%2C%20list(participant.items()))%0A%20%20%20%20print(%22Has%20a%20distance%3F%22%2C%20%22distance_m%22%20in%20participant)%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**Exercise%203.**%20For%20%60values%20%3D%20%5B2%2C%204%2C%206%2C%208%5D%60%2C%20predict%20%60values%5B1%3A3%5D%60%20and%20%60values%5B-1%5D%60.%20If%20%60other%20%3D%20values%60%2C%20does%20%60other.append(10)%60%20leave%20%60values%60%20unchanged%3F%20Which%20container%20would%20associate%20a%20participant's%20label%20with%20their%20walking%20distance%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Solution%20to%20Exercise%203%0A%20%20%20%20The%20slice%20is%20%60%5B4%2C%206%5D%60%20and%20the%20last%20item%20is%20%608%60.%20Both%20names%20refer%20to%20the%20same%20list%2C%20so%20appending%20through%20%60other%60%20also%20changes%20what%20%60values%60%20refers%20to.%20Use%20a%20dictionary%20to%20associate%20named%20keys%20with%20values.%20In%20marimo%2C%20keep%20the%20aliasing%20experiment%20in%20one%20scratch%20cell.%0A%20%20%20%20%2F%2F%2F%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%20Comparisons%20and%20Boolean%20logic%0A%0A%20%20%20%20Comparisons%20such%20as%20%60%3D%3D%60%2C%20%60!%3D%60%2C%20%60%3C%60%2C%20%60%3C%3D%60%2C%20%60%3E%60%2C%20and%20%60%3E%3D%60%20produce%20%60True%60%20or%20%60False%60.%20%60%3D%60%20assigns%3B%20%60%3D%3D%60%20compares.%20Combine%20conditions%20with%20%60and%60%2C%20%60or%60%2C%20and%20%60not%60.%20Python%20allows%20chained%20comparisons%20such%20as%20%600%20%3C%20duration_s%20%3C%3D%2010%60.%0A%0A%20%20%20%20For%20an%20absent%20value%2C%20write%20%60value%20is%20None%60.%20%60is%60%20tests%20object%20identity%2C%20whereas%20%60%3D%3D%60%20tests%20equality%20of%20values.%20Empty%20containers%20and%20zero%20are%20false%20in%20conditions%2C%20but%20a%20scientific%20validity%20check%20should%20state%20its%20meaning%20explicitly%3A%20a%20negative%20duration%20is%20nonzero%2C%20yet%20physically%20invalid%20for%20our%20speed%20calculation.%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%20_duration_s%20%3D%204.0%0A%20%20%20%20_missing%20%3D%20None%0A%20%20%20%20print(%22Positive%20and%20at%20most%2010%20s%3A%22%2C%200%20%3C%20_duration_s%20%3C%3D%2010)%0A%20%20%20%20print(%22Outside%20that%20interval%3A%22%2C%20_duration_s%20%3C%3D%200%20or%20_duration_s%20%3E%2010)%0A%20%20%20%20print(%22Missing%3A%22%2C%20_missing%20is%20None)%0A%20%20%20%20print(%22Not%20positive%3A%22%2C%20not%20(_duration_s%20%3E%200))%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%20Control%20flow%20and%20indentation%0A%0A%20%20%20%20%23%23%23%20Decisions%3A%20%60if%60%2C%20%60elif%60%2C%20and%20%60else%60%0A%0A%20%20%20%20A%20program%20can%20choose%20a%20calculation%20according%20to%20a%20condition.%20A%20colon%20introduces%20a%20block%3B%20its%20indented%20statements%20belong%20together.%20Use%20four%20spaces%20for%20each%20level.%20%60elif%60%20checks%20another%20condition%20if%20the%20preceding%20one%20was%20false%2C%20and%20%60else%60%20handles%20the%20remaining%20cases.%20Only%20the%20first%20matching%20branch%20runs.%0A%0A%20%20%20%20Change%20%60_duration_s%60%20in%20the%20next%20cell%20to%20%604.0%60%2C%20%600.0%60%2C%20and%20%60-1.0%60.%20Predict%20which%20branch%20runs%20each%20time.%20The%20zero%20and%20negative%20cases%20should%20explain%20why%20a%20speed%20cannot%20be%20calculated.%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%20_duration_s%20%3D%200.0%0A%20%20%20%20if%20_duration_s%20%3E%200%3A%0A%20%20%20%20%20%20%20%20print(f%22Speed%3A%20%7B6.0%20%2F%20_duration_s%3A.2f%7D%20m%2Fs%22)%0A%20%20%20%20elif%20_duration_s%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20print(%22A%20zero%20duration%20would%20require%20division%20by%20zero.%22)%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20print(%22A%20walking%20duration%20cannot%20be%20negative.%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%23%20Repetition%3A%20%60for%60%2C%20%60range%60%2C%20%60enumerate%60%2C%20and%20%60zip%60%0A%0A%20%20%20%20A%20%60for%60%20loop%20visits%20each%20item%20of%20an%20iterable%2C%20such%20as%20a%20list%20or%20a%20string.%20%60enumerate%60%20supplies%20a%20counter%20along%20with%20each%20item.%20Its%20optional%20%60start%3D1%60%20makes%20printed%20trial%20labels%20begin%20at%201%20without%20changing%20Python's%20zero-based%20indexing.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(distance_m%2C%20trial_times_s)%3A%0A%20%20%20%20for%20_trial_number%2C%20_duration_s%20in%20enumerate(trial_times_s%2C%20start%3D1)%3A%0A%20%20%20%20%20%20%20%20print(f%22Trial%20%7B_trial_number%7D%3A%20%7Bdistance_m%20%2F%20_duration_s%3A.3f%7D%20m%2Fs%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%60range(start%2C%20stop%2C%20step)%60%20represents%20a%20sequence%20of%20integers%20that%20excludes%20%60stop%60.%20It%20is%20not%20a%20list%2C%20but%20%60list(range(...))%60%20materializes%20its%20values.%20%60zip%60%20pairs%20items%20from%20iterables%3B%20%60strict%3DTrue%60%20reports%20unequal%20lengths%20instead%20of%20silently%20stopping%20at%20the%20shorter%20input.%0A%0A%20%20%20%20A%20**list%20comprehension**%20builds%20a%20list%20from%20an%20iteration%20and%20can%20include%20a%20condition.%20Read%20%60%5B_distance%20%2F%20_time%20for%20_time%20in%20times%5D%60%20as%20%E2%80%9Ccalculate%20this%20expression%20for%20every%20time%E2%80%9D.%20Prefer%20a%20loop%20when%20the%20processing%20needs%20several%20steps.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(distance_m%2C%20trial_times_s)%3A%0A%20%20%20%20print(%22range(3)%3A%22%2C%20list(range(3)))%0A%20%20%20%20print(%22range(1%2C%207%2C%202)%3A%22%2C%20list(range(1%2C%207%2C%202)))%0A%20%20%20%20for%20_label%2C%20_duration%20in%20zip(%5B%22A%22%2C%20%22B%22%2C%20%22C%22%5D%2C%20trial_times_s%2C%20strict%3DTrue)%3A%0A%20%20%20%20%20%20%20%20print(_label%2C%20_duration)%0A%20%20%20%20trial_speeds_m_s%20%3D%20%5Bdistance_m%20%2F%20_duration%20for%20_duration%20in%20trial_times_s%5D%0A%20%20%20%20print(%22Speeds%20from%20a%20comprehension%3A%22%2C%20trial_speeds_m_s)%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%23%20Repetition%20while%20a%20condition%20holds%3A%20%60while%60%0A%0A%20%20%20%20A%20%60while%60%20loop%20checks%20its%20condition%20before%20each%20iteration.%20Something%20in%20the%20loop%20must%20eventually%20make%20the%20condition%20false%2C%20or%20it%20may%20run%20indefinitely.%20Here%20we%20generate%20Fibonacci%20numbers%2C%20each%20the%20sum%20of%20the%20preceding%20two.%20Simultaneous%20assignment%20uses%20the%20old%20values%20on%20the%20right%20before%20updating%20either%20name%20on%20the%20left.%0A%0A%20%20%20%20%60break%60%20exits%20the%20nearest%20loop%3B%20%60continue%60%20skips%20to%20its%20next%20iteration.%20Use%20them%20when%20they%20make%20a%20stopping%20or%20exclusion%20rule%20clearer.%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%20_previous%2C%20_current%20%3D%200%2C%201%0A%20%20%20%20_fibonacci%20%3D%20%5B%5D%0A%20%20%20%20while%20_current%20%3C%20100%3A%0A%20%20%20%20%20%20%20%20_fibonacci.append(_current)%0A%20%20%20%20%20%20%20%20_previous%2C%20_current%20%3D%20_current%2C%20_previous%20%2B%20_current%0A%20%20%20%20print(%22Fibonacci%20numbers%20below%20100%3A%22%2C%20_fibonacci)%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**Exercise%204.**%20Write%20a%20comprehension%20that%20keeps%20only%20positive%20durations%20from%20%60%5B4.0%2C%200.0%2C%205.0%2C%20-1.0%5D%60.%20How%20many%20iterations%20does%20%60for%20_i%20in%20range(2%2C%208%2C%202)%60%20perform%3F%20What%20would%20happen%20if%20the%20Fibonacci%20loop%20never%20updated%20%60_current%60%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Solution%20to%20Exercise%204%0A%20%20%20%20%60%5B_time%20for%20_time%20in%20%5B4.0%2C%200.0%2C%205.0%2C%20-1.0%5D%20if%20_time%20%3E%200%5D%60%20gives%20%60%5B4.0%2C%205.0%5D%60.%20The%20range%20supplies%20%602%60%2C%20%604%60%2C%20and%20%606%60%2C%20giving%20three%20iterations.%20If%20the%20initially%20true%20%60while%60%20condition%20never%20changes%2C%20the%20loop%20does%20not%20terminate.%0A%20%20%20%20%2F%2F%2F%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%20Defining%20and%20using%20functions%0A%0A%20%20%20%20A%20function%20names%20a%20reusable%20calculation.%20%60def%60%20introduces%20the%20function%2C%20parentheses%20contain%20its%20**parameters**%2C%20and%20the%20indented%20body%20runs%20when%20it%20is%20called.%20The%20values%20supplied%20in%20a%20call%20are%20its%20**arguments**.%20%60return%60%20sends%20a%20result%20back%20to%20the%20caller%3B%20%60print%60%20only%20displays%20a%20representation.%20A%20function%20without%20an%20explicit%20return%20value%20returns%20%60None%60.%0A%0A%20%20%20%20Write%20a%20docstring%20that%20explains%20the%20meaning%2C%20units%2C%20and%20valid%20range%20of%20the%20inputs%20and%20result.%20This%20version%20of%20our%20walking%20calculation%20rejects%20nonfinite%20numbers%2C%20negative%20distances%2C%20and%20nonpositive%20durations%20rather%20than%20reporting%20a%20plausible-looking%20speed.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(math)%3A%0A%20%20%20%20def%20walking_speed(distance_m%2C%20duration_s)%3A%0A%20%20%20%20%20%20%20%20%22%22%22Return%20speed%20in%20m%2Fs%20for%20finite%20distance%20%3E%3D%200%20and%20duration%20%3E%200.%0A%0A%20%20%20%20%20%20%20%20Raise%20ValueError%20when%20either%20measurement%20is%20outside%20that%20domain.%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20if%20not%20math.isfinite(distance_m)%20or%20not%20math.isfinite(duration_s)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError(%22Measurements%20must%20be%20finite%22)%0A%20%20%20%20%20%20%20%20if%20distance_m%20%3C%200%20or%20duration_s%20%3C%3D%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError(%22Use%20nonnegative%20distance%20and%20positive%20duration%22)%0A%20%20%20%20%20%20%20%20return%20distance_m%20%2F%20duration_s%0A%0A%20%20%20%20def%20speed_report(speed_m_s%2C%20label%3D%22Trial%22)%3A%0A%20%20%20%20%20%20%20%20%22%22%22Return%20a%20labelled%20speed%2C%20formatted%20to%20two%20decimal%20places.%22%22%22%0A%20%20%20%20%20%20%20%20return%20f%22%7Blabel%7D%3A%20%7Bspeed_m_s%3A.2f%7D%20m%2Fs%22%0A%0A%20%20%20%20return%20speed_report%2C%20walking_speed%0A%0A%0A%40app.cell%0Adef%20_(speed_report%2C%20walking_speed)%3A%0A%20%20%20%20_speed%20%3D%20walking_speed(10%2C%208)%0A%20%20%20%20print(speed_report(_speed))%0A%20%20%20%20print(speed_report(walking_speed(duration_s%3D5%2C%20distance_m%3D6)%2C%20label%3D%22Second%20trial%22))%0A%20%20%20%20print(%22A%20returned%20value%20can%20be%20reused%3A%22%2C%20_speed%20*%203.6%2C%20%22km%2Fh%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%20The%20second%20call%20uses%20**keyword%20arguments**%2C%20making%20the%20inputs%20explicit.%20%60label%3D%22Trial%22%60%20defines%20a%20default%20argument%20for%20%60speed_report%60.%20Avoid%20mutable%20defaults%20such%20as%20an%20empty%20list%20when%20you%20intend%20a%20new%20object%20on%20every%20call.%0A%0A%20%20%20%20Function%20parameters%20and%20variables%20created%20inside%20a%20function%20are%20local%20to%20that%20call.%20They%20can%20have%20the%20same%20names%20as%20notebook%20variables%20without%20redefining%20those%20shared%20variables.%20Pass%20the%20measurements%20into%20the%20function%20rather%20than%20hiding%20them%20as%20fixed%20numbers%20inside%20its%20body.%20In%20marimo%2C%20define%20the%20function%20in%20one%20cell%20and%20call%20it%20in%20downstream%20cells.%0A%0A%20%20%20%20**Exercise%205.**%20Write%20a%20function%20%60metres_to_centimetres(length_m)%60%20that%20returns%20the%20converted%20length.%20What%20do%20%60walking_speed(0%2C%203)%60%20and%20%60walking_speed(3%2C%200)%60%20do%3F%20Why%20would%20replacing%20%60return%60%20with%20%60print%60%20prevent%20later%20calculations%20from%20using%20a%20function's%20result%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Solution%20to%20Exercise%205%0A%20%20%20%20%60%60%60python%0A%20%20%20%20def%20metres_to_centimetres(length_m)%3A%0A%20%20%20%20%20%20%20%20'''Return%20a%20length%20in%20centimetres%20from%20a%20length%20in%20metres.'''%0A%20%20%20%20%20%20%20%20return%20100%20*%20length_m%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20The%20first%20speed%20is%20%600.0%60%20m%2Fs.%20The%20zero-duration%20call%20raises%20%60ValueError%60.%20A%20function%20that%20only%20prints%2C%20with%20no%20return%20statement%2C%20returns%20%60None%60%3B%20the%20displayed%20text%20is%20not%20a%20numeric%20result%20that%20a%20caller%20can%20multiply%20or%20average.%0A%20%20%20%20%2F%2F%2F%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%20Understanding%20and%20handling%20errors%0A%0A%20%20%20%20An%20exception%20reports%20that%20an%20operation%20failed.%20Read%20the%20final%20error%20line%20for%20its%20type%20and%20message%2C%20then%20inspect%20the%20indicated%20line%20in%20the%20traceback.%20A%20syntax%20or%20indentation%20error%20prevents%20code%20from%20being%20parsed%3B%20runtime%20exceptions%20arise%20while%20executing%20valid%20syntax.%0A%0A%20%20%20%20%7C%20Exception%20%7C%20Example%20cause%20%7C%20First%20thing%20to%20check%20%7C%0A%20%20%20%20%7C%20---%20%7C%20---%20%7C%20---%20%7C%0A%20%20%20%20%7C%20%60NameError%60%20%7C%20Using%20a%20name%20that%20has%20not%20been%20defined%20%7C%20Spelling%20and%20the%20defining%20cell%20%7C%0A%20%20%20%20%7C%20%60TypeError%60%20%7C%20Adding%20a%20string%20to%20a%20number%20%7C%20Types%20and%20explicit%20conversion%20%7C%0A%20%20%20%20%7C%20%60IndexError%60%20%7C%20Selecting%20item%203%20from%20a%20three-item%20list%20%7C%20Zero-based%20indices%20and%20length%20%7C%0A%20%20%20%20%7C%20%60KeyError%60%20%7C%20Looking%20up%20an%20absent%20dictionary%20key%20%7C%20Available%20keys%20%7C%0A%20%20%20%20%7C%20%60ZeroDivisionError%60%20%7C%20Dividing%20by%20zero%20%7C%20Input%20validity%20%7C%0A%20%20%20%20%7C%20%60ValueError%60%20%7C%20A%20function%20rejects%20an%20argument's%20value%20%7C%20The%20function's%20documented%20domain%20%7C%0A%0A%20%20%20%20%60try%60%20and%20%60except%60%20let%20a%20program%20handle%20an%20expected%20failure.%20Catch%20the%20specific%20exception%20you%20can%20handle.%20In%20the%20next%20cell%2C%20invalid%20trials%20are%20reported%20and%20the%20loop%20continues%3B%20they%20are%20not%20replaced%20by%20zero%20speeds.%20The%20notebook%20itself%20can%20still%20execute%20all%20its%20cells%20successfully.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(walking_speed)%3A%0A%20%20%20%20for%20_duration%20in%20%5B4.0%2C%200.0%2C%20-1.0%5D%3A%0A%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_speed%20%3D%20walking_speed(6.0%2C%20_duration)%0A%20%20%20%20%20%20%20%20except%20ValueError%20as%20_error%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20print(f%22Duration%20%7B_duration%7D%20s%3A%20%7B_error%7D%22)%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20print(f%22Duration%20%7B_duration%7D%20s%3A%20%7B_speed%3A.2f%7D%20m%2Fs%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%20Numerical%20data%20with%20NumPy%0A%0A%20%20%20%20We%20now%20have%20enough%20Python%20to%20start%20using%20scientific%20libraries.%20NumPy%20provides%20**arrays**%2C%20which%20store%20numerical%20data%20with%20a%20shape%20and%20a%20data%20type%20and%20support%20operations%20on%20many%20elements%20at%20once.%20The%20conventional%20alias%20is%20%60np%60.%0A%0A%20%20%20%20Python%20lists%20and%20NumPy%20arrays%20have%20different%20arithmetic%3A%20multiplying%20a%20list%20by%202%20repeats%20its%20items%2C%20whereas%20multiplying%20a%20numeric%20array%20by%202%20doubles%20each%20value.%20Converting%20our%20trial%20times%20to%20an%20array%20lets%20one%20division%20calculate%20every%20speed.%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%20numpy%20as%20np%0A%0A%20%20%20%20return%20(np%2C)%0A%0A%0A%40app.cell%0Adef%20_(distance_m%2C%20np%2C%20trial_times_s)%3A%0A%20%20%20%20times_array_s%20%3D%20np.array(trial_times_s)%0A%20%20%20%20speeds_array_m_s%20%3D%20distance_m%20%2F%20times_array_s%0A%20%20%20%20print(%22List%20*%202%3A%22%2C%20trial_times_s%20*%202)%0A%20%20%20%20print(%22Array%20*%202%3A%22%2C%20times_array_s%20*%202)%0A%20%20%20%20print(%22Speeds%20%5Bm%2Fs%5D%3A%22%2C%20speeds_array_m_s)%0A%20%20%20%20print(%22Mean%20speed%20%5Bm%2Fs%5D%3A%22%2C%20speeds_array_m_s.mean())%0A%20%20%20%20print(%22Speeds%20above%201.5%20m%2Fs%3A%22%2C%20speeds_array_m_s%5Bspeeds_array_m_s%20%3E%201.5%5D)%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%23%20Shape%2C%20indexing%2C%20and%20axes%0A%0A%20%20%20%20A%20one-dimensional%20array%20can%20hold%20one%20participant's%20repeated%20measurements.%20A%20two-dimensional%20array%20might%20put%20participants%20in%20rows%20and%20trials%20in%20columns.%20%60.shape%60%20gives%20the%20size%20of%20each%20dimension%2C%20%60.ndim%60%20the%20number%20of%20dimensions%2C%20%60.size%60%20the%20total%20number%20of%20elements%2C%20and%20%60.dtype%60%20the%20stored%20element%20type.%0A%0A%20%20%20%20With%20two%20dimensions%2C%20separate%20indices%20with%20a%20comma%3A%20%60%5B0%2C%201%5D%60%20selects%20row%200%2C%20column%201%3B%20%60%5B%3A%2C%200%5D%60%20selects%20column%200%20from%20every%20row.%20In%20%60mean(axis%3D0)%60%2C%20the%20row%20dimension%20is%20reduced%2C%20leaving%20a%20mean%20for%20each%20column.%20%60axis%3D1%60%20reduces%20columns%20and%20leaves%20one%20mean%20per%20row.%20Sketch%20the%20following%20array%20before%20predicting%20these%20means.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(np)%3A%0A%20%20%20%20measurement_array_s%20%3D%20np.array(%5B%5B4.0%2C%204.2%2C%203.8%5D%2C%20%5B4.5%2C%204.3%2C%204.4%5D%5D)%0A%20%20%20%20print(%22Durations%20%5Bs%5D%3A%5Cn%22%2C%20measurement_array_s)%0A%20%20%20%20print(%22Shape%3A%22%2C%20measurement_array_s.shape%2C%20%22Dimensions%3A%22%2C%20measurement_array_s.ndim)%0A%20%20%20%20print(%0A%20%20%20%20%20%20%20%20%22Total%20elements%3A%22%2C%20measurement_array_s.size%2C%20%22Type%3A%22%2C%20measurement_array_s.dtype%0A%20%20%20%20)%0A%20%20%20%20print(%22First%20trial%20for%20each%20participant%3A%22%2C%20measurement_array_s%5B%3A%2C%200%5D)%0A%20%20%20%20print(%22Mean%20for%20each%20trial%3A%22%2C%20measurement_array_s.mean(axis%3D0))%0A%20%20%20%20print(%22Mean%20for%20each%20participant%3A%22%2C%20measurement_array_s.mean(axis%3D1))%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%20Basic%20NumPy%20slices%20often%20return%20**views**%2C%20sharing%20the%20original%20array's%20data.%20Use%20%60.copy()%60%20when%20you%20need%20an%20independent%20array.%20As%20with%20lists%2C%20keep%20in-place%20changes%20in%20the%20defining%20cell.%20Use%20a%20new%20array%20expression%20for%20a%20downstream%20transformation.%0A%0A%20%20%20%20Array%20comparisons%20produce%20Boolean%20arrays%2C%20also%20called%20masks.%20Combine%20elementwise%20conditions%20with%20%60%26%60%20and%20%60%7C%60%2C%20placing%20each%20comparison%20in%20parentheses%3A%20%60(times_array_s%20%3E%200)%20%26%20(times_array_s%20%3C%205)%60.%20Python's%20%60and%60%20and%20%60or%60%20instead%20combine%20individual%20truth%20values.%0A%0A%20%20%20%20%60np.arange%60%20is%20convenient%20for%20regularly%20spaced%20values%20with%20an%20excluded%20endpoint%3B%20%60np.linspace%60%20chooses%20a%20requested%20number%20of%20samples%20between%20endpoints.%20%60np.zeros%60%2C%20%60np.ones%60%2C%20and%20%60np.column_stack%60%20create%20or%20assemble%20arrays.%20For%20random%20examples%2C%20use%20a%20seeded%20generator%20so%20rerunning%20the%20lesson%20reproduces%20the%20same%20data.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(np)%3A%0A%20%20%20%20print(%22Every%20second%20integer%3A%22%2C%20np.arange(0%2C%207%2C%202))%0A%20%20%20%20print(%22Five%20equally%20spaced%20times%3A%22%2C%20np.linspace(0%2C%201%2C%205))%0A%20%20%20%20print(%22A%202%20by%203%20array%20of%20zeros%3A%5Cn%22%2C%20np.zeros((2%2C%203)))%0A%20%20%20%20_rng%20%3D%20np.random.default_rng(2026)%0A%20%20%20%20print(%22Reproducible%20synthetic%20speeds%3A%22%2C%20_rng.normal(loc%3D1.5%2C%20scale%3D0.1%2C%20size%3D4))%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**Exercise%206.**%20An%20array%20has%20two%20participant%20rows%20and%20three%20trial%20columns.%20What%20are%20its%20shape%20and%20size%3F%20Which%20axis%20gives%20one%20mean%20per%20participant%3F%20How%20does%20%60%5B1%2C%202%5D%20*%202%60%20differ%20from%20%60np.array(%5B1%2C%202%5D)%20*%202%60%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Solution%20to%20Exercise%206%0A%20%20%20%20The%20shape%20is%20%60(2%2C%203)%60%20and%20the%20size%20is%20%606%60.%20%60mean(axis%3D1)%60%20gives%20one%20mean%20per%20participant.%20The%20list%20becomes%20%60%5B1%2C%202%2C%201%2C%202%5D%60%3B%20the%20array%20becomes%20%60%5B2%2C%204%5D%60.%20See%20the%20%5BNumPy%20quickstart%5D(https%3A%2F%2Fnumpy.org%2Fdoc%2Fstable%2Fuser%2Fquickstart.html)%20for%20more%20array%20practice.%0A%20%20%20%20%2F%2F%2F%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%23%20Interpolation%0A%0A%20%20%20%20Suppose%20position%20was%20measured%20at%20four%20times%20and%20we%20want%20estimates%20between%20them.%20%60np.interp(new_times%2C%20measured_times%2C%20measured_positions)%60%20performs%20one-dimensional%20linear%20interpolation.%20The%20measured%20time%20coordinates%20must%20be%20increasing.%20More%20interpolated%20points%20make%20a%20denser%20representation%3B%20they%20do%20not%20add%20observations%20or%20recover%20motion%20that%20was%20never%20measured.%0A%0A%20%20%20%20We%20keep%20the%20new%20times%20inside%20the%20observed%20interval.%20Outside%20it%2C%20%60np.interp%60%20uses%20endpoint%20values%20by%20default%20rather%20than%20extending%20the%20slope.%20We%20will%20plot%20the%20measured%20and%20interpolated%20positions%20in%20the%20Matplotlib%20section.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(np)%3A%0A%20%20%20%20sample_time_s%20%3D%20np.array(%5B0.0%2C%201.0%2C%202.0%2C%203.0%5D)%0A%20%20%20%20sample_position_m%20%3D%20np.array(%5B0.0%2C%201.2%2C%202.0%2C%203.6%5D)%0A%20%20%20%20dense_time_s%20%3D%20np.linspace(sample_time_s%5B0%5D%2C%20sample_time_s%5B-1%5D%2C%2013)%0A%20%20%20%20interpolated_position_m%20%3D%20np.interp(dense_time_s%2C%20sample_time_s%2C%20sample_position_m)%0A%20%20%20%20print(%0A%20%20%20%20%20%20%20%20%22Estimated%20position%20at%200.5%20s%3A%22%2C%0A%20%20%20%20%20%20%20%20np.interp(0.5%2C%20sample_time_s%2C%20sample_position_m)%2C%0A%20%20%20%20%20%20%20%20%22m%22%2C%0A%20%20%20%20)%0A%20%20%20%20print(%22New%20positions%20%5Bm%5D%3A%22%2C%20interpolated_position_m)%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20dense_time_s%2C%0A%20%20%20%20%20%20%20%20interpolated_position_m%2C%0A%20%20%20%20%20%20%20%20sample_position_m%2C%0A%20%20%20%20%20%20%20%20sample_time_s%2C%0A%20%20%20%20)%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%20Reading%20and%20saving%20files%0A%0A%20%20%20%20Scientific%20programs%20need%20inputs%20and%20outputs%20beyond%20the%20notebook.%20Text%20files%20store%20characters%20using%20an%20encoding%20such%20as%20UTF-8%3B%20a%20CSV%20file%20is%20text%20organized%20into%20rows%20and%20separated%20fields.%20Binary%20formats%20store%20data%20according%20to%20a%20particular%20format%20rather%20than%20as%20readable%20numeric%20text.%20Match%20the%20reader%20to%20the%20format.%0A%0A%20%20%20%20%60pathlib.Path%60%20represents%20a%20path.%20%60%2F%60%20joins%20path%20components%3B%20it%20is%20not%20numerical%20division%20when%20the%20left%20operand%20is%20a%20%60Path%60.%20A%20relative%20path%20is%20resolved%20from%20the%20working%20directory%2C%20which%20may%20differ%20between%20local%20and%20hosted%20sessions.%20A%20%60with%60%20block%20closes%20an%20opened%20file%20even%20if%20an%20exception%20occurs.%20Mode%20%60%22w%22%60%20writes%20and%20**replaces%20existing%20contents**%3B%20mode%20%60%22r%22%60%20reads.%0A%0A%20%20%20%20These%20examples%20use%20temporary%20folders%20so%20repeated%20runs%20do%20not%20overwrite%20your%20data.%20The%20folder%20is%20removed%20when%20its%20%60with%60%20block%20finishes.%20To%20retain%20a%20result%20in%20your%20own%20work%2C%20choose%20a%20persistent%20output%20folder%20or%20download%20it%20from%20the%20service%20you%20are%20using.%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%20from%20pathlib%20import%20Path%0A%20%20%20%20from%20tempfile%20import%20TemporaryDirectory%0A%0A%20%20%20%20return%20Path%2C%20TemporaryDirectory%0A%0A%0A%40app.cell%0Adef%20_(Path%2C%20TemporaryDirectory)%3A%0A%0A%20%20%20%20with%20TemporaryDirectory(prefix%3D%22bmc-python-text-%22)%20as%20_folder%3A%0A%20%20%20%20%20%20%20%20_path%20%3D%20Path(_folder)%20%2F%20%22notes.txt%22%0A%20%20%20%20%20%20%20%20with%20_path.open(%22w%22%2C%20encoding%3D%22utf-8%22)%20as%20_stream%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_stream.write(%22Participant%3A%20P01%5CnDistance%3A%206%20m%5Cn%22)%0A%20%20%20%20%20%20%20%20with%20_path.open(%22r%22%2C%20encoding%3D%22utf-8%22)%20as%20_stream%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_contents%20%3D%20_stream.read()%0A%20%20%20%20%20%20%20%20print(_contents)%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%20NumPy%20provides%20%60savetxt%60%20and%20%60loadtxt%60%20for%20rectangular%20numeric%20data.%20Here%20each%20row%20contains%20a%20time%20and%20a%20position.%20The%20header%20records%20names%20and%20units%2C%20the%20delimiter%20is%20a%20comma%2C%20and%20the%20reader%20skips%20the%20header%20row.%20For%20labelled%20tables%20with%20text%20and%20numbers%2C%20pandas%20will%20provide%20a%20more%20convenient%20CSV%20reader%20later.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(Path%2C%20TemporaryDirectory%2C%20np%2C%20sample_position_m%2C%20sample_time_s)%3A%0A%20%20%20%20_data%20%3D%20np.column_stack((sample_time_s%2C%20sample_position_m))%0A%20%20%20%20with%20TemporaryDirectory(prefix%3D%22bmc-python-array-%22)%20as%20_folder%3A%0A%20%20%20%20%20%20%20%20_path%20%3D%20Path(_folder)%20%2F%20%22positions.csv%22%0A%20%20%20%20%20%20%20%20np.savetxt(_path%2C%20_data%2C%20delimiter%3D%22%2C%22%2C%20header%3D%22time_s%2Cposition_m%22%2C%20comments%3D%22%22)%0A%20%20%20%20%20%20%20%20_reloaded%20%3D%20np.loadtxt(_path%2C%20delimiter%3D%22%2C%22%2C%20skiprows%3D1)%0A%20%20%20%20%20%20%20%20print(%22Read%20back%3A%5Cn%22%2C%20_reloaded)%0A%20%20%20%20%20%20%20%20print(%22Values%20preserved%3A%22%2C%20np.allclose(_data%2C%20_reloaded))%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**Exercise%207.**%20What%20position%20does%20linear%20interpolation%20predict%20halfway%20between%20%60(1%20s%2C%201.2%20m)%60%20and%20%60(2%20s%2C%202.0%20m)%60%3F%20Does%20saving%201%2C000%20interpolated%20points%20turn%20four%20observations%20into%201%2C000%20observations%3F%20Why%20use%20a%20%60with%60%20block%20for%20a%20file%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Solution%20to%20Exercise%207%0A%20%20%20%20The%20estimate%20at%201.5%20s%20is%201.6%20m.%20Interpolation%20does%20not%20add%20independent%20observations.%20The%20%60with%60%20block%20closes%20the%20file%20reliably%2C%20including%20when%20an%20operation%20raises%20an%20exception.%0A%20%20%20%20%2F%2F%2F%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%20Plotting%20with%20Matplotlib%0A%0A%20%20%20%20A%20figure%20helps%20us%20check%20a%20calculation%20and%20communicate%20its%20meaning.%20Matplotlib's%20%60plt.subplots%60%20returns%20a%20**Figure**%2C%20containing%20the%20whole%20drawing%2C%20and%20one%20or%20more%20**Axes**%2C%20where%20data%20are%20plotted.%20Call%20methods%20on%20an%20Axes%20to%20draw%20lines%2C%20label%20quantities%20with%20units%2C%20and%20add%20a%20legend.%20This%20also%20puts%20Python's%20objects%20and%20methods%20to%20practical%20use.%0A%0A%20%20%20%20We%20will%20compare%20measured%20points%20with%20their%20interpolated%20curve%2C%20then%20show%20a%20histogram%20of%20synthetic%20walking%20speeds.%20A%20histogram%20groups%20observations%20into%20bins%3B%20its%20appearance%20depends%20on%20the%20chosen%20bins.%20Synthetic%20data%20demonstrate%20code%20and%20are%20not%20evidence%20about%20real%20participants.%0A%0A%20%20%20%20In%20marimo%2C%20put%20the%20Figure%20object%20at%20the%20end%20of%20the%20cell%20to%20display%20it%20inline.%20No%20%60%25matplotlib%60%20magic%20or%20separate%20desktop%20window%20is%20needed.%20When%20an%20input%20changes%2C%20create%20the%20updated%20figure%20in%20its%20dependent%20cell.%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%20matplotlib.pyplot%20as%20plt%0A%0A%20%20%20%20return%20(plt%2C)%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20dense_time_s%2C%0A%20%20%20%20interpolated_position_m%2C%0A%20%20%20%20np%2C%0A%20%20%20%20plt%2C%0A%20%20%20%20sample_position_m%2C%0A%20%20%20%20sample_time_s%2C%0A)%3A%0A%20%20%20%20_fig%2C%20_axes%20%3D%20plt.subplots(1%2C%202%2C%20figsize%3D(10%2C%203.8)%2C%20layout%3D%22constrained%22)%0A%20%20%20%20_axes%5B0%5D.plot(%0A%20%20%20%20%20%20%20%20dense_time_s%2C%20interpolated_position_m%2C%20%22-%22%2C%20label%3D%22Linear%20interpolation%22%0A%20%20%20%20)%0A%20%20%20%20_axes%5B0%5D.plot(sample_time_s%2C%20sample_position_m%2C%20%22o%22%2C%20label%3D%22Measured%20samples%22)%0A%20%20%20%20_axes%5B0%5D.set(%0A%20%20%20%20%20%20%20%20xlabel%3D%22Time%20%5Bs%5D%22%2C%20ylabel%3D%22Position%20%5Bm%5D%22%2C%20title%3D%22Samples%20and%20interpolation%22%0A%20%20%20%20)%0A%20%20%20%20_axes%5B0%5D.legend()%0A%20%20%20%20_axes%5B0%5D.grid(alpha%3D0.3)%0A%0A%20%20%20%20_synthetic_speeds%20%3D%20np.random.default_rng(2026).normal(1.5%2C%200.12%2C%20size%3D100)%0A%20%20%20%20_axes%5B1%5D.hist(_synthetic_speeds%2C%20bins%3D12%2C%20edgecolor%3D%22white%22)%0A%20%20%20%20_axes%5B1%5D.set(%0A%20%20%20%20%20%20%20%20xlabel%3D%22Speed%20%5Bm%2Fs%5D%22%2C%20ylabel%3D%22Count%22%2C%20title%3D%22100%20synthetic%20walking%20speeds%22%0A%20%20%20%20)%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**Exercise%208.**%20Which%20line%20of%20code%20distinguishes%20the%20measured%20positions%20from%20the%20interpolated%20estimates%3F%20Change%20the%20histogram%20to%20six%20bins%3A%20did%20the%20observations%20change%3F%20For%20a%20figure%20of%20your%20own%2C%20what%20information%20belongs%20on%20each%20axis%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Solution%20to%20Exercise%208%0A%20%20%20%20The%20%60plot%60%20call%20with%20marker%20%60%22o%22%60%20shows%20the%20measured%20samples%3B%20the%20line%20shows%20the%20interpolation.%20Changing%20the%20bins%20regroups%20the%20same%20synthetic%20observations.%20Each%20axis%20needs%20the%20plotted%20quantity%20and%2C%20where%20applicable%2C%20its%20unit.%20See%20the%20%5BMatplotlib%20quick%20start%5D(https%3A%2F%2Fmatplotlib.org%2Fstable%2Fusers%2Fexplain%2Fquick_start.html).%0A%20%20%20%20%2F%2F%2F%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%20Signal%20processing%20with%20SciPy%0A%0A%20%20%20%20SciPy%20builds%20on%20NumPy%20with%20algorithms%20for%20integration%2C%20optimization%2C%20interpolation%2C%20linear%20algebra%2C%20statistics%2C%20and%20signal%20processing.%20This%20introduction%20follows%20one%20example%3A%20separating%20a%20slow%20movement%20component%20from%20a%20faster%20oscillation.%0A%0A%20%20%20%20We%20sample%20a%202%20Hz%20sine%20wave%20plus%20a%20smaller%2020%20Hz%20sine%20wave%20at%20100%20samples%20per%20second.%20A%20low-pass%20Butterworth%20filter%20attenuates%20the%20faster%20component.%20%60butter(...%2C%20fs%3D...)%60%20takes%20its%20cutoff%20in%20the%20same%20frequency%20unit%20as%20the%20sampling%20rate.%20The%20cutoff%20must%20be%20between%20zero%20and%20half%20the%20sampling%20rate.%20We%20request%20second-order%20sections%20with%20%60output%3D%22sos%22%60%20and%20apply%20them%20using%20%60sosfiltfilt%60.%0A%0A%20%20%20%20This%20is%20**offline%20forward-backward%20filtering**%3A%20it%20uses%20future%20samples%2C%20has%20zero%20phase%20shift%2C%20and%20doubles%20the%20filter%20order.%20Edge%20effects%20still%20need%20inspection%2C%20and%20the%20combined%20response%20at%20the%20specified%20single-pass%20cutoff%20is%20not%20the%20single-pass%20response.%20A%20cutoff%20should%20follow%20the%20scientific%20question%20and%20sampling%20process%2C%20not%20just%20make%20a%20curve%20look%20smooth.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(np)%3A%0A%20%20%20%20from%20scipy.fft%20import%20rfft%2C%20rfftfreq%0A%20%20%20%20from%20scipy.signal%20import%20butter%2C%20sosfiltfilt%0A%0A%20%20%20%20sampling_rate_hz%20%3D%20100.0%0A%20%20%20%20signal_time_s%20%3D%20np.arange(200)%20%2F%20sampling_rate_hz%0A%20%20%20%20raw_signal%20%3D%20np.sin(2%20*%20np.pi%20*%202%20*%20signal_time_s)%20%2B%200.25%20*%20np.sin(%0A%20%20%20%20%20%20%20%202%20*%20np.pi%20*%2020%20*%20signal_time_s%0A%20%20%20%20)%0A%20%20%20%20_sos%20%3D%20butter(4%2C%205.0%2C%20btype%3D%22lowpass%22%2C%20fs%3Dsampling_rate_hz%2C%20output%3D%22sos%22)%0A%20%20%20%20filtered_signal%20%3D%20sosfiltfilt(_sos%2C%20raw_signal)%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20filtered_signal%2C%0A%20%20%20%20%20%20%20%20raw_signal%2C%0A%20%20%20%20%20%20%20%20rfft%2C%0A%20%20%20%20%20%20%20%20rfftfreq%2C%0A%20%20%20%20%20%20%20%20sampling_rate_hz%2C%0A%20%20%20%20%20%20%20%20signal_time_s%2C%0A%20%20%20%20)%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%60scipy.fft.rfft%60%20transforms%20a%20real-valued%20record%20into%20frequency%20components%3B%20%60rfftfreq%60%20supplies%20their%20frequencies.%20Here%20we%20plot%20the%20unnormalized%20FFT%20magnitudes%20to%20compare%20the%20same-length%20records.%20Peaks%20near%202%20and%2020%20Hz%20identify%20the%20generated%20oscillations.%20Boundaries%20and%20a%20record%20containing%20incomplete%20cycles%20can%20spread%20energy%20across%20frequency%20bins.%0A%0A%20%20%20%20The%20bottom%20panels%20also%20show%20a%20finite-difference%20approximation%20to%20the%20**second%20derivative**.%20Dividing%20by%20the%20sample%20interval%20squared%20is%20equivalent%20to%20multiplying%20by%20the%20sampling%20rate%20squared.%20Differentiation%20emphasizes%20faster%20oscillations%3A%20a%20small%20fast%20component%20can%20dominate%20the%20derivative.%20Compare%20the%20raw%20and%20filtered%20results%20before%20choosing%20how%20to%20estimate%20movement%20derivatives.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20filtered_signal%2C%0A%20%20%20%20np%2C%0A%20%20%20%20plt%2C%0A%20%20%20%20raw_signal%2C%0A%20%20%20%20rfft%2C%0A%20%20%20%20rfftfreq%2C%0A%20%20%20%20sampling_rate_hz%2C%0A%20%20%20%20signal_time_s%2C%0A)%3A%0A%20%20%20%20_raw_d2%20%3D%20np.diff(raw_signal%2C%20n%3D2)%20*%20sampling_rate_hz**2%0A%20%20%20%20_filtered_d2%20%3D%20np.diff(filtered_signal%2C%20n%3D2)%20*%20sampling_rate_hz**2%0A%20%20%20%20_frequencies%20%3D%20rfftfreq(raw_signal.size%2C%20d%3D1%20%2F%20sampling_rate_hz)%0A%20%20%20%20_derivative_frequencies%20%3D%20rfftfreq(_raw_d2.size%2C%20d%3D1%20%2F%20sampling_rate_hz)%0A%20%20%20%20_fig%2C%20_axes%20%3D%20plt.subplots(2%2C%202%2C%20figsize%3D(10%2C%206)%2C%20layout%3D%22constrained%22)%0A%0A%20%20%20%20_axes%5B0%2C%200%5D.plot(signal_time_s%2C%20raw_signal%2C%20label%3D%22Raw%22)%0A%20%20%20%20_axes%5B0%2C%200%5D.plot(signal_time_s%2C%20filtered_signal%2C%20label%3D%22Filtered%22)%0A%20%20%20%20_axes%5B0%2C%200%5D.set(xlabel%3D%22Time%20%5Bs%5D%22%2C%20ylabel%3D%22Signal%20%5Ba.u.%5D%22%2C%20title%3D%22Time%20domain%22)%0A%20%20%20%20_axes%5B0%2C%201%5D.plot(_frequencies%2C%20np.abs(rfft(raw_signal))%2C%20label%3D%22Raw%22)%0A%20%20%20%20_axes%5B0%2C%201%5D.plot(_frequencies%2C%20np.abs(rfft(filtered_signal))%2C%20label%3D%22Filtered%22)%0A%20%20%20%20_axes%5B0%2C%201%5D.set(%0A%20%20%20%20%20%20%20%20xlabel%3D%22Frequency%20%5BHz%5D%22%2C%0A%20%20%20%20%20%20%20%20ylabel%3D%22FFT%20magnitude%20%5Ba.u.%5D%22%2C%0A%20%20%20%20%20%20%20%20xlim%3D(0%2C%2030)%2C%0A%20%20%20%20%20%20%20%20title%3D%22Frequency%20domain%22%2C%0A%20%20%20%20)%0A%20%20%20%20_axes%5B1%2C%200%5D.plot(signal_time_s%5B1%3A-1%5D%2C%20_raw_d2%2C%20label%3D%22Raw%22)%0A%20%20%20%20_axes%5B1%2C%200%5D.plot(signal_time_s%5B1%3A-1%5D%2C%20_filtered_d2%2C%20label%3D%22Filtered%22)%0A%20%20%20%20_axes%5B1%2C%200%5D.set(xlabel%3D%22Time%20%5Bs%5D%22%2C%20ylabel%3D%22Second%20derivative%20%5Ba.u.%2Fs%C2%B2%5D%22)%0A%20%20%20%20_axes%5B1%2C%201%5D.plot(_derivative_frequencies%2C%20np.abs(rfft(_raw_d2))%2C%20label%3D%22Raw%22)%0A%20%20%20%20_axes%5B1%2C%201%5D.plot(%0A%20%20%20%20%20%20%20%20_derivative_frequencies%2C%20np.abs(rfft(_filtered_d2))%2C%20label%3D%22Filtered%22%0A%20%20%20%20)%0A%20%20%20%20_axes%5B1%2C%201%5D.set(%0A%20%20%20%20%20%20%20%20xlabel%3D%22Frequency%20%5BHz%5D%22%2C%0A%20%20%20%20%20%20%20%20ylabel%3D%22Derivative%20FFT%20magnitude%20%5Ba.u.%2Fs%C2%B2%5D%22%2C%0A%20%20%20%20%20%20%20%20xlim%3D(0%2C%2030)%2C%0A%20%20%20%20)%0A%20%20%20%20for%20_ax%20in%20_axes.flat%3A%0A%20%20%20%20%20%20%20%20_ax.legend()%0A%20%20%20%20%20%20%20%20_ax.grid(alpha%3D0.3)%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**Exercise%209.**%20Which%20generated%20component%20should%20be%20attenuated%20by%20a%205%20Hz%20low-pass%20filter%3F%20Could%20this%20same%20example%20use%20a%20cutoff%20of%2060%20Hz%20with%20a%20100%20Hz%20sampling%20rate%3F%20Is%20the%20forward-backward%20result%20suitable%20for%20an%20application%20that%20must%20respond%20before%20future%20measurements%20exist%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Solution%20to%20Exercise%209%0A%20%20%20%20The%2020%20Hz%20component%20should%20be%20attenuated%20much%20more%20than%20the%202%20Hz%20component.%20A%2060%20Hz%20cutoff%20is%20outside%20the%20allowed%20interval%20below%20the%2050%20Hz%20Nyquist%20frequency.%20Forward-backward%20filtering%20requires%20future%20data%2C%20so%20this%20offline%20method%20cannot%20directly%20supply%20a%20real-time%20response.%20See%20the%20%5BSciPy%20signal-processing%20tutorial%5D(https%3A%2F%2Fdocs.scipy.org%2Fdoc%2Fscipy%2Ftutorial%2Fsignal.html).%0A%20%20%20%20%2F%2F%2F%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%20Symbolic%20mathematics%20with%20SymPy%0A%0A%20%20%20%20NumPy%20and%20SciPy%20operate%20mainly%20on%20numerical%20values.%20SymPy%20can%20manipulate%20mathematical%20expressions%20containing%20symbols%3A%20solve%20equations%2C%20differentiate%2C%20integrate%2C%20and%20work%20with%20exact%20matrices.%20We%20use%20the%20conventional%20alias%20%60sym%60.%0A%0A%20%20%20%20Defining%20%60symbolic_x%60%20as%20a%20symbol%20does%20not%20assign%20a%20numerical%20value%20to%20it.%20We%20construct%20the%20polynomial%20%24x%5E2-2x-3%24%2C%20solve%20for%20its%20zeros%2C%20and%20calculate%20its%20derivative%20and%20a%20definite%20integral.%20%60sym.latex%60%20converts%20expressions%20to%20mathematical%20notation%20for%20a%20marimo%20text%20cell.%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%20sympy%20as%20sym%0A%0A%20%20%20%20return%20(sym%2C)%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20sym)%3A%0A%20%20%20%20symbolic_x%20%3D%20sym.symbols(%22x%22%2C%20real%3DTrue)%0A%20%20%20%20polynomial%20%3D%20symbolic_x**2%20-%202%20*%20symbolic_x%20-%203%0A%20%20%20%20polynomial_roots%20%3D%20sym.solve(polynomial%2C%20symbolic_x)%0A%20%20%20%20polynomial_derivative%20%3D%20sym.diff(polynomial%2C%20symbolic_x)%0A%20%20%20%20polynomial_integral%20%3D%20sym.integrate(polynomial%2C%20(symbolic_x%2C%200%2C%201))%0A%20%20%20%20mo.md(rf%22%22%22%0A%20%20%20%20Polynomial%3A%20%24p(x)%20%3D%20%7Bsym.latex(polynomial)%7D%24%0A%0A%20%20%20%20Roots%3A%20%24%7Bsym.latex(polynomial_roots)%7D%24%0A%0A%20%20%20%20Derivative%3A%20%24p'(x)%20%3D%20%7Bsym.latex(polynomial_derivative)%7D%24%0A%0A%20%20%20%20Definite%20integral%3A%20%24%5Cint_0%5E1%20p(x)%5C%2Cdx%20%3D%20%7Bsym.latex(polynomial_integral)%7D%24%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%23%20An%20exact%20rotation%20matrix%0A%0A%20%20%20%20A%20rotation%20about%20the%20%24x%24%20axis%20illustrates%20symbolic%20matrices.%20%60.subs(...)%60%20substitutes%20a%20value%20for%20a%20symbol%2C%20and%20%60*%60%20multiplies%20SymPy%20matrices.%20Using%20%60sym.pi%20%2F%202%60%20preserves%20an%20exact%20angle%3B%20using%20a%20floating%20approximation%20to%20%24%5Cpi%24%20instead%20can%20produce%20small%20residuals.%20A%20vector%20along%20the%20positive%20%24y%24%20axis%20becomes%20a%20vector%20along%20the%20positive%20%24z%24%20axis%20after%20this%20right-handed%2090-degree%20rotation.%0A%0A%20%20%20%20The%20same%20approach%20can%20construct%20and%20combine%20rotations%20about%20all%20three%20axes%3B%20the%20order%20of%20matrix%20multiplication%20matters.%20See%20%5BThree-dimensional%20transformations%5D(https%3A%2F%2Fmolab.marimo.io%2Fgithub%2FBMClab%2FBMC%2Fblob%2Fmaster%2Fnotebooks%2Ftransformation_3d.py)%20for%20the%20mechanics.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20sym)%3A%0A%20%20%20%20_theta%20%3D%20sym.symbols(%22theta%22%2C%20real%3DTrue)%0A%20%20%20%20_rotation_x%20%3D%20sym.Matrix(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B1%2C%200%2C%200%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B0%2C%20sym.cos(_theta)%2C%20-sym.sin(_theta)%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B0%2C%20sym.sin(_theta)%2C%20sym.cos(_theta)%5D%2C%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%20%20%20%20_rotated%20%3D%20_rotation_x.subs(_theta%2C%20sym.pi%20%2F%202)%20*%20sym.Matrix(%5B0%2C%201%2C%200%5D)%0A%20%20%20%20mo.md(rf%22%22%22%0A%20%20%20%20%24%24R_x(%5Ctheta)%20%3D%20%7Bsym.latex(_rotation_x)%7D%24%24%0A%0A%20%20%20%20%24%24R_x(%5Cpi%2F2)%5Cbegin%7B%7Bbmatrix%7D%7D0%5C%5C1%5C%5C0%5Cend%7B%7Bbmatrix%7D%7D%20%3D%20%7Bsym.latex(_rotated)%7D%24%24%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**Exercise%2010.**%20Check%20the%20polynomial's%20roots%20by%20substituting%20each%20into%20%24x%5E2-2x-3%24.%20What%20is%20the%20derivative%20at%20%24x%3D2%24%3F%20What%20distinguishes%20%60sym.pi%60%20from%20%60math.pi%60%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Solution%20to%20Exercise%2010%0A%20%20%20%20Both%20%24x%3D-1%24%20and%20%24x%3D3%24%20give%20zero.%20The%20derivative%20is%20%242x-2%24%2C%20so%20its%20value%20at%202%20is%202.%20%60sym.pi%60%20represents%20the%20exact%20symbolic%20constant%3B%20%60math.pi%60%20is%20a%20floating-point%20approximation.%20See%20the%20%5BSymPy%20introductory%20tutorial%5D(https%3A%2F%2Fdocs.sympy.org%2Flatest%2Ftutorials%2Fintro-tutorial%2Findex.html).%0A%20%20%20%20%2F%2F%2F%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%20Data%20analysis%20with%20pandas%0A%0A%20%20%20%20A%20pandas%20**DataFrame**%20organizes%20observations%20in%20rows%20and%20named%20variables%20in%20columns.%20Different%20columns%20can%20contain%20different%20types%2C%20such%20as%20participant%20labels%20and%20numeric%20measurements.%20A%20column%20is%20a%20**Series**.%20We%20use%20the%20conventional%20alias%20%60pd%60.%0A%0A%20%20%20%20The%20following%20small%20table%20contains%20repeated%20walking%20trials%20under%20two%20conditions.%20We%20derive%20a%20speed%20column%20in%20the%20same%20cell%20that%20creates%20the%20table.%20Subsequent%20cells%20select%20and%20summarize%20it%20without%20modifying%20that%20shared%20object.%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%20pandas%20as%20pd%0A%0A%20%20%20%20return%20(pd%2C)%0A%0A%0A%40app.cell%0Adef%20_(pd)%3A%0A%20%20%20%20walking_trials%20%3D%20pd.DataFrame(%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22participant%22%3A%20%5B%22P01%22%2C%20%22P01%22%2C%20%22P01%22%2C%20%22P02%22%2C%20%22P02%22%2C%20%22P02%22%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22condition%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22comfortable%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22comfortable%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22fast%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22comfortable%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22comfortable%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22fast%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22distance_m%22%3A%20%5B6.0%5D%20*%206%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22duration_s%22%3A%20%5B4.0%2C%204.2%2C%203.0%2C%204.5%2C%204.3%2C%203.2%5D%2C%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20)%0A%20%20%20%20walking_trials%5B%22speed_m_s%22%5D%20%3D%20(%0A%20%20%20%20%20%20%20%20walking_trials%5B%22distance_m%22%5D%20%2F%20walking_trials%5B%22duration_s%22%5D%0A%20%20%20%20)%0A%20%20%20%20walking_trials%0A%20%20%20%20return%20(walking_trials%2C)%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%60table%5B%22column%22%5D%60%20selects%20a%20column.%20%60.loc%5Brow_condition%2C%20columns%5D%60%20selects%20rows%20by%20a%20condition%20and%20columns%20by%20their%20labels.%20%60.iloc%60%20instead%20uses%20integer%20positions.%20Here%20the%20equality%20comparison%20creates%20a%20mask%20selecting%20the%20fast%20condition.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(walking_trials)%3A%0A%20%20%20%20walking_trials.loc%5B%0A%20%20%20%20%20%20%20%20walking_trials%5B%22condition%22%5D%20%3D%3D%20%22fast%22%2C%20%5B%22participant%22%2C%20%22speed_m_s%22%5D%0A%20%20%20%20%5D%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%60groupby%60%20organizes%20observations%20by%20labels%20before%20applying%20a%20summary.%20%60agg%60%20requests%20named%20aggregations.%20We%20count%20and%20average%20the%20speeds%20by%20condition.%20%60describe()%60%20gives%20a%20broader%20descriptive%20summary%20of%20numeric%20columns.%0A%0A%20%20%20%20These%20are%20summaries%20of%20the%20listed%20**trials**.%20Participants%20contributed%20repeated%20observations%2C%20so%20treating%20all%20rows%20as%20independent%20participants%20would%20be%20a%20separate%20and%20often%20incorrect%20statistical%20assumption.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(walking_trials)%3A%0A%20%20%20%20condition_summary%20%3D%20walking_trials.groupby(%22condition%22)%5B%22speed_m_s%22%5D.agg(%0A%20%20%20%20%20%20%20%20%5B%22count%22%2C%20%22mean%22%5D%0A%20%20%20%20)%0A%20%20%20%20condition_summary%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(walking_trials)%3A%0A%20%20%20%20walking_trials.describe()%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%23%20CSV%20tables%0A%0A%20%20%20%20%60to_csv(...%2C%20index%3DFalse)%60%20writes%20column%20names%20and%20data%20without%20adding%20the%20DataFrame's%20row%20index%20as%20another%20column.%20%60read_csv%60%20reads%20the%20table%20back%20and%20infers%20column%20types.%20For%20real%20data%2C%20check%20those%20types%2C%20missing%20values%2C%20decimal%20conventions%2C%20and%20units%20rather%20than%20assuming%20a%20successful%20read%20proves%20the%20data%20are%20correct.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(Path%2C%20TemporaryDirectory%2C%20pd%2C%20walking_trials)%3A%0A%20%20%20%20with%20TemporaryDirectory(prefix%3D%22bmc-python-table-%22)%20as%20_folder%3A%0A%20%20%20%20%20%20%20%20_path%20%3D%20Path(_folder)%20%2F%20%22walking_trials.csv%22%0A%20%20%20%20%20%20%20%20walking_trials.to_csv(_path%2C%20index%3DFalse)%0A%20%20%20%20%20%20%20%20_reloaded_table%20%3D%20pd.read_csv(_path)%0A%20%20%20%20%20%20%20%20print(%22CSV%20columns%3A%22%2C%20list(_reloaded_table.columns))%0A%20%20%20%20%20%20%20%20print(%22Rows%20read%3A%22%2C%20len(_reloaded_table))%0A%20%20%20%20_reloaded_table%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**Exercise%2011.**%20Select%20the%20%60duration_s%60%20column%20for%20participant%20P01.%20How%20many%20fast%20trials%20are%20in%20the%20table%3F%20Does%20the%20grouped%20count%20tell%20you%20how%20many%20distinct%20participants%20took%20part%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Solution%20to%20Exercise%2011%0A%20%20%20%20Use%20%60walking_trials.loc%5Bwalking_trials%5B%22participant%22%5D%20%3D%3D%20%22P01%22%2C%20%22duration_s%22%5D%60%2C%20giving%204.0%2C%204.2%2C%20and%203.0%20s.%20There%20are%20two%20fast%20trials.%20A%20row%20count%20counts%20trials%2C%20not%20distinct%20participants%3B%20use%20the%20participant%20identifiers%20to%20establish%20the%20latter.%20See%20%5BGetting%20started%20with%20pandas%5D(https%3A%2F%2Fpandas.pydata.org%2Fdocs%2Fgetting_started%2Fintro_tutorials%2Findex.html).%0A%20%20%20%20%2F%2F%2F%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%20Interactive%20exploration%20in%20marimo%0A%0A%20%20%20%20We%20can%20now%20combine%20a%20Python%20function%2C%20NumPy%20arrays%2C%20a%20Matplotlib%20figure%2C%20and%20marimo%20controls%20to%20explore%20a%20model.%20Consider%20a%20response%20that%20approaches%20a%20limiting%20amplitude%3A%0A%0A%20%20%20%20%24%24y(t)%20%3D%20A%5Cleft(1-e%5E%7B-t%2F%5Ctau%7D%5Cright).%24%24%0A%0A%20%20%20%20%24A%24%20sets%20the%20limiting%20amplitude%20and%20%24%5Ctau%3E0%24%20sets%20how%20quickly%20the%20response%20approaches%20it.%20At%20%24t%3D%5Ctau%24%2C%20the%20response%20is%20approximately%20%240.632A%24.%20This%20is%20a%20mathematical%20example%2C%20not%20a%20fitted%20physiological%20model.%0A%0A%20%20%20%20First%20define%20the%20function.%20Then%20create%20two%20sliders%20and%20display%20them.%20Read%20each%20slider's%20%60.value%60%20in%20a%20**downstream%20cell**%2C%20where%20the%20curve%20and%20figure%20are%20calculated.%20Changing%20a%20control%20reruns%20that%20dependent%20cell.%20This%20replaces%20the%20need%20for%20notebook-specific%20plotting%20magics%20or%20manually%20updating%20existing%20plot%20lines.%0A%0A%20%20%20%20**Guiding%20questions.**%20Which%20control%20should%20change%20the%20curve's%20plateau%3F%20Which%20should%20change%20the%20time%20taken%20to%20reach%20a%20fixed%20fraction%20of%20that%20plateau%3F%20Predict%20the%20answer%20before%20moving%20either%20slider.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(np)%3A%0A%20%20%20%20def%20saturating_response(time_s%2C%20amplitude%2C%20tau_s)%3A%0A%20%20%20%20%20%20%20%20%22%22%22Return%20A%20*%20(1%20-%20exp(-t%2Ftau))%20for%20a%20positive%20time%20constant%20in%20seconds.%22%22%22%0A%20%20%20%20%20%20%20%20if%20tau_s%20%3C%3D%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError(%22The%20time%20constant%20must%20be%20positive%22)%0A%20%20%20%20%20%20%20%20return%20amplitude%20*%20(1%20-%20np.exp(-time_s%20%2F%20tau_s))%0A%0A%20%20%20%20return%20(saturating_response%2C)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20amplitude_control%20%3D%20mo.ui.slider(%0A%20%20%20%20%20%20%20%20start%3D0%2C%20stop%3D10%2C%20step%3D0.5%2C%20value%3D5%2C%20label%3D%22Amplitude%20A%22%2C%20show_value%3DTrue%0A%20%20%20%20)%0A%20%20%20%20time_constant_control%20%3D%20mo.ui.slider(%0A%20%20%20%20%20%20%20%20start%3D5%2C%0A%20%20%20%20%20%20%20%20stop%3D100%2C%0A%20%20%20%20%20%20%20%20step%3D5%2C%0A%20%20%20%20%20%20%20%20value%3D50%2C%0A%20%20%20%20%20%20%20%20label%3D%22Time%20constant%20tau%20%5Bs%5D%22%2C%0A%20%20%20%20%20%20%20%20show_value%3DTrue%2C%0A%20%20%20%20)%0A%20%20%20%20mo.hstack(%5Bamplitude_control%2C%20time_constant_control%5D%2C%20wrap%3DTrue)%0A%20%20%20%20return%20amplitude_control%2C%20time_constant_control%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20amplitude_control%2C%0A%20%20%20%20mo%2C%0A%20%20%20%20np%2C%0A%20%20%20%20plt%2C%0A%20%20%20%20saturating_response%2C%0A%20%20%20%20time_constant_control%2C%0A)%3A%0A%20%20%20%20_time%20%3D%20np.linspace(0%2C%20300%2C%20301)%0A%20%20%20%20_amplitude%20%3D%20amplitude_control.value%0A%20%20%20%20_tau%20%3D%20time_constant_control.value%0A%20%20%20%20_response%20%3D%20saturating_response(_time%2C%20_amplitude%2C%20_tau)%0A%20%20%20%20_fig%2C%20_ax%20%3D%20plt.subplots(figsize%3D(8%2C%203.5)%2C%20layout%3D%22constrained%22)%0A%20%20%20%20_ax.plot(_time%2C%20_response%2C%20label%3D%22Response%22)%0A%20%20%20%20_ax.axhline(_amplitude%2C%20color%3D%22gray%22%2C%20linestyle%3D%22--%22%2C%20label%3D%22Limiting%20amplitude%22)%0A%20%20%20%20_ax.set(xlabel%3D%22Time%20%5Bs%5D%22%2C%20ylabel%3D%22Response%20%5Ba.u.%5D%22%2C%20ylim%3D(-0.2%2C%2010.5))%0A%20%20%20%20_ax.grid(alpha%3D0.3)%0A%20%20%20%20_ax.legend()%0A%20%20%20%20mo.vstack(%5Bmo.md(f%22**Current%20model%3A**%20A%20%3D%20%7B_amplitude%3Ag%7D%2C%20tau%20%3D%20%7B_tau%3Ag%7D%20s%22)%2C%20_fig%5D)%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**Exercise%2012.**%20Double%20%24A%24%20while%20holding%20%24%5Ctau%24%20fixed%2C%20then%20double%20%24%5Ctau%24%20while%20holding%20%24A%24%20fixed.%20What%20changes%20in%20each%20experiment%3F%20Would%20a%20cell%20containing%20only%20%605%20*%20(1%20-%20np.exp(-10%20%2F%2050))%60%20respond%20to%20these%20sliders%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Solution%20to%20Exercise%2012%0A%20%20%20%20Doubling%20%24A%24%20doubles%20the%20response%20at%20every%20time%2C%20including%20the%20limiting%20amplitude.%20Doubling%20%24%5Ctau%24%20makes%20the%20response%20take%20twice%20as%20long%20to%20reach%20the%20same%20fraction%20of%20its%20limit.%20The%20literal%20expression%20contains%20no%20reference%20to%20either%20control%20and%20therefore%20does%20not%20update%20when%20the%20sliders%20move.%20See%20%5Bmarimo%20interactive%20elements%5D(https%3A%2F%2Fdocs.marimo.io%2Fguides%2Finteractivity%2F).%0A%20%20%20%20%2F%2F%2F%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%20Worked%20example%3A%20summarize%20walking%20trials%0A%0A%20%20%20%20Return%20to%20Challenge%200.%20We%20have%20four%20recorded%20durations%2C%20including%20a%20zero%20that%20cannot%20define%20a%20speed.%20Our%20goal%20is%20to%20calculate%20valid%20speeds%2C%20retain%20the%20reason%20for%20an%20excluded%20trial%2C%20and%20report%20a%20summary%20with%20units.%0A%0A%20%20%20%20Before%20running%20the%20code%2C%20identify%20the%20responsibilities%3A%20the%20function%20validates%20one%20calculation%3B%20the%20loop%20processes%20all%20records%3B%20a%20dictionary%20gives%20each%20result%20named%20fields%3B%20and%20pandas%20displays%20the%20table.%20Keeping%20the%20rejected%20trial%20in%20the%20table%20makes%20the%20exclusion%20visible.%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%20recorded_durations_s%20%3D%20%5B4.0%2C%204.2%2C%200.0%2C%203.8%5D%0A%20%20%20%20return%20(recorded_durations_s%2C)%0A%0A%0A%40app.cell%0Adef%20_(pd%2C%20recorded_durations_s%2C%20walking_speed)%3A%0A%20%20%20%20_records%20%3D%20%5B%5D%0A%20%20%20%20for%20_number%2C%20_duration%20in%20enumerate(recorded_durations_s%2C%20start%3D1)%3A%0A%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_speed%20%3D%20walking_speed(6.0%2C%20_duration)%0A%20%20%20%20%20%20%20%20except%20ValueError%20as%20_error%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_records.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22trial%22%3A%20_number%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22duration_s%22%3A%20_duration%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22speed_m_s%22%3A%20None%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22status%22%3A%20str(_error)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_records.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22trial%22%3A%20_number%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22duration_s%22%3A%20_duration%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22speed_m_s%22%3A%20_speed%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22status%22%3A%20%22valid%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20trial_results%20%3D%20pd.DataFrame(_records)%0A%20%20%20%20trial_results%0A%20%20%20%20return%20(trial_results%2C)%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20trial_results)%3A%0A%20%20%20%20_valid%20%3D%20trial_results.loc%5Btrial_results%5B%22status%22%5D%20%3D%3D%20%22valid%22%2C%20%22speed_m_s%22%5D%0A%20%20%20%20_excluded_count%20%3D%20len(trial_results)%20-%20len(_valid)%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20f%22**Summary%3A**%20%7Blen(_valid)%7D%20valid%20trials%3B%20%7B_excluded_count%7D%20excluded%20trial(s).%20%22%0A%20%20%20%20%20%20%20%20%2B%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20f%22Mean%20of%20valid%20trial%20speeds%3A%20**%7B_valid.mean()%3A.3f%7D%20m%2Fs**.%22%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20len(_valid)%0A%20%20%20%20%20%20%20%20%20%20%20%20else%20%22No%20valid%20speeds%20to%20average.%22%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%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%20The%20missing%20speed%20is%20displayed%20as%20%60NaN%60%20in%20the%20numeric%20column%3B%20it%20is%20not%20a%20measured%20speed%20of%20zero.%20The%20summary%20explicitly%20selects%20valid%20records.%20The%20mean%20of%20individual%20trial%20speeds%20is%20also%20a%20different%20quantity%20from%20total%20distance%20divided%20by%20total%20time.%20For%20three%20equal-distance%20trials%20with%20unequal%20durations%2C%20those%20summaries%20need%20not%20agree.%0A%0A%20%20%20%20**Try%20it.**%20Change%20one%20duration%20in%20%60recorded_durations_s%60%2C%20run%20its%20defining%20cell%2C%20and%20explain%20the%20updated%20table%20and%20mean.%20Then%20try%20making%20every%20duration%20zero%3A%20the%20summary%20should%20report%20no%20valid%20speeds%20rather%20than%20invent%20an%20average.%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%20Checkpoint%20questions%0A%0A%20%20%20%201.%20How%20do%20assignment%2C%20equality%20comparison%2C%20and%20approximate%20floating-point%20comparison%20differ%3F%0A%20%20%20%202.%20What%20is%20the%20difference%20between%20a%20list%20and%20a%20NumPy%20array%20when%20multiplying%20by%20a%20scalar%3F%0A%20%20%20%203.%20Why%20can%20modifying%20an%20alias%20also%20change%20the%20original%20list%3F%0A%20%20%20%204.%20What%20do%20a%20function's%20parameters%2C%20docstring%2C%20and%20return%20value%20tell%20you%3F%0A%20%20%20%205.%20How%20do%20you%20read%20an%20error%20without%20hiding%20invalid%20data%3F%0A%20%20%20%206.%20What%20do%20rows%20and%20columns%20mean%20in%20your%20array%20or%20table%3F%0A%20%20%20%207.%20Why%20does%20a%20marimo%20cell%20update%20when%20an%20input%20changes%2C%20and%20what%20changes%20are%20not%20tracked%3F%0A%20%20%20%208.%20What%20must%20accompany%20a%20scientific%20number%20or%20figure%20so%20another%20person%20can%20interpret%20it%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Checkpoint%20answers%0A%20%20%20%201.%20%60%3D%60%20assigns%20a%20value%2C%20%60%3D%3D%60%20compares%20values%2C%20and%20a%20tolerance-based%20function%20such%20as%20%60math.isclose%60%20checks%20approximate%20agreement.%0A%20%20%20%202.%20A%20list%20repeats%20its%20items%3B%20a%20numeric%20array%20multiplies%20each%20element.%0A%20%20%20%203.%20The%20names%20refer%20to%20the%20same%20mutable%20object%3B%20assignment%20did%20not%20copy%20it.%0A%20%20%20%204.%20Parameters%20state%20the%20inputs%2C%20the%20docstring%20explains%20their%20meaning%20and%20domain%2C%20and%20the%20return%20value%20is%20the%20result%20the%20caller%20can%20reuse.%0A%20%20%20%205.%20Inspect%20the%20exception%20type%2C%20message%2C%20and%20indicated%20source%20line%3B%20validate%20inputs%20and%20handle%20only%20expected%20failures%2C%20recording%20exclusions.%0A%20%20%20%206.%20Their%20meaning%20comes%20from%20the%20data%20model%2C%20not%20the%20container%3B%20state%20whether%20they%20represent%20participants%2C%20trials%2C%20time%20points%2C%20or%20variables.%0A%20%20%20%207.%20marimo%20tracks%20dependencies%20through%20names.%20In-place%20mutations%20in%20another%20cell%20are%20not%20tracked%3B%20create%20a%20new%20object%20or%20mutate%20in%20its%20defining%20cell.%0A%20%20%20%208.%20Units%2C%20labels%2C%20input%20provenance%2C%20assumptions%2C%20and%20enough%20information%20to%20reproduce%20the%20calculation.%0A%20%20%20%20%2F%2F%2F%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%20Problems%0A%0A%20%20%20%20Use%20new%20cells%20with%20distinct%20shared%20names%2C%20or%20scratch%20names%20beginning%20with%20%60_%60.%20Keep%20each%20problem's%20inputs%20explicit%20so%20another%20reader%20can%20reproduce%20the%20result.%0A%0A%20%20%20%201.%20Calculate%20the%20speed%20of%20a%2012%20m%20walk%20completed%20in%208%20s.%20Report%20it%20in%20m%2Fs%20and%20km%2Fh.%0A%20%20%20%202.%20For%20%60%5B2%2C%204%2C%206%2C%208%5D%60%2C%20give%20the%20slice%20selecting%20the%20middle%20two%20values%2C%20then%20calculate%20the%20mean%20using%20built-in%20functions.%0A%20%20%20%203.%20Write%20a%20Boolean%20expression%20that%20accepts%20durations%20greater%20than%20zero%20and%20at%20most%2010%20s.%0A%20%20%20%204.%20Write%20a%20function%20that%20takes%20a%20list%20of%20positive%20durations%20and%20a%20distance%20and%20returns%20a%20list%20of%20speeds.%20Use%206%20m%20and%20%60%5B4.0%2C%205.0%2C%203.0%5D%60%20to%20check%20it.%0A%20%20%20%205.%20Explain%20how%20to%20keep%20an%20independent%20copy%20before%20changing%20the%20first%20element%20of%20a%20flat%20list.%20Then%20demonstrate%20it%20in%20one%20cell.%0A%20%20%20%206.%20Create%20the%20array%20%60%5B%5B1%2C%202%2C%203%5D%2C%20%5B4%2C%205%2C%206%5D%5D%60.%20Find%20its%20shape%20and%20the%20mean%20of%20each%20row.%0A%20%20%20%207.%20Interpolate%20position%20at%201.5%20s%20from%20times%20%60%5B0%2C%201%2C%202%5D%60%20s%20and%20positions%20%60%5B0%2C%202%2C%206%5D%60%20m.%20Plot%20the%20measured%20points%20and%20interpolated%20line%20with%20units.%0A%20%20%20%208.%20At%20a%20sampling%20rate%20of%20100%20Hz%2C%20which%20of%20the%20cutoffs%205%2C%2040%2C%20and%2060%20Hz%20can%20be%20passed%20to%20the%20low-pass%20design%20used%20here%3F%20State%20whether%20that%20alone%20establishes%20a%20scientifically%20appropriate%20cutoff.%0A%20%20%20%209.%20Use%20SymPy%20to%20differentiate%20%24x%5E3%24%20and%20integrate%20it%20from%200%20to%202.%0A%20%20%20%2010.%20For%20the%20response%20model%2C%20calculate%20the%20response%20at%20%24t%3D%5Ctau%24%20with%20%24A%3D5%24.%20Explain%20what%20happens%20when%20%24%5Ctau%24%20doubles.%0A%20%20%20%2011.%20In%20the%20worked%20walking%20example%2C%20calculate%20both%20the%20mean%20of%20valid%20trial%20speeds%20and%20total%20valid%20distance%20divided%20by%20total%20valid%20time.%20Explain%20why%20they%20differ.%0A%20%20%20%2012.%20Recreate%20the%20walking%20table%20from%20ordinary%20Python%20values%2C%20save%20it%20to%20a%20temporary%20CSV%20file%2C%20and%20read%20it%20back.%20Check%20the%20column%20names%2C%20units%2C%20and%20number%20of%20rows%20before%20summarizing%20by%20condition.%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Final%20answers%0A%20%20%20%201.%201.5%20m%2Fs%3B%205.4%20km%2Fh.%0A%20%20%20%202.%20%60%5B1%3A3%5D%60%20gives%20%60%5B4%2C%206%5D%60%3B%20the%20mean%20is%205.0.%0A%20%20%20%203.%20%600%20%3C%20duration_s%20%3C%3D%2010%60.%0A%20%20%20%204.%20%60%5B1.5%2C%201.2%2C%202.0%5D%60%20m%2Fs.%0A%20%20%20%205.%20Use%20%60.copy()%60%3B%20modifying%20the%20new%20flat%20list%20leaves%20the%20original%20unchanged.%0A%20%20%20%206.%20Shape%20%60(2%2C%203)%60%3B%20row%20means%20%60%5B2.0%2C%205.0%5D%60.%0A%20%20%20%207.%204.0%20m.%0A%20%20%20%208.%205%20and%2040%20Hz%20meet%20the%20numerical%20cutoff%20constraint%3B%20suitability%20still%20depends%20on%20the%20signal%20and%20scientific%20question.%0A%20%20%20%209.%20Derivative%20%243x%5E2%24%3B%20definite%20integral%204.%0A%20%20%20%2010.%20Approximately%203.161.%20Doubling%20%24%5Ctau%24%20doubles%20the%20time%20needed%20to%20reach%20that%20same%20response%20fraction.%0A%20%20%20%2011.%20Approximately%201.502506%20m%2Fs%20and%201.5%20m%2Fs%2C%20respectively%3B%20the%20first%20averages%20ratios%2C%20while%20the%20second%20is%20a%20time-weighted%20average%20of%20speeds.%0A%20%20%20%2012.%20Six%20rows%20and%20five%20named%20columns%3A%20%60participant%60%2C%20%60condition%60%2C%20%60distance_m%60%2C%20%60duration_s%60%2C%20and%20%60speed_m_s%60.%20Mean%20speeds%20are%20approximately%201.414%20and%201.938%20m%2Fs%20for%20the%20comfortable%20and%20fast%20conditions.%0A%20%20%20%20%2F%2F%2F%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%20Go%20deeper%0A%0A%20%20%20%20Continue%20with%20%5BScalar%20and%20vector%5D(https%3A%2F%2Fmolab.marimo.io%2Fgithub%2FBMClab%2FBMC%2Fblob%2Fmaster%2Fnotebooks%2Fscalar_vector.py)%20for%20array-based%20mechanics%2C%20%5BCode%20structure%5D(https%3A%2F%2Fmolab.marimo.io%2Fgithub%2FBMClab%2FBMC%2Fblob%2Fmaster%2Fnotebooks%2Fcode_structure.py)%20for%20repeated%20file%20processing%2C%20and%20%5BData%20filtering%5D(https%3A%2F%2Fmolab.marimo.io%2Fgithub%2FBMClab%2FBMC%2Fblob%2Fmaster%2Fnotebooks%2Fdata_filtering.py)%20for%20a%20closer%20look%20at%20signal%20processing.%0A%0A%20%20%20%20For%20longer%20Python%20treatments%2C%20see%20Jake%20VanderPlas's%20%5BA%20Whirlwind%20Tour%20of%20Python%5D(https%3A%2F%2Fjakevdp.github.io%2FWhirlwindTourOfPython%2F)%20and%20%5BPython%20Data%20Science%20Handbook%5D(https%3A%2F%2Fjakevdp.github.io%2FPythonDataScienceHandbook%2F).%20Their%20Python%20examples%20complement%20this%20guide%3B%20adapt%20notebook-environment%20instructions%20when%20working%20in%20marimo.%0A%0A%20%20%20%20%23%23%23%20Video%20lectures%20on%20the%20Internet%0A%0A%20%20%20%20%5BMIT%20introductory%20Python%20lectures%5D(https%3A%2F%2Focw.mit.edu%2Fcourses%2F6-0001-introduction-to-computer-science-and-programming-in-python-fall-2016%2Fvideo_galleries%2Flecture-videos%2F)%20offer%20additional%20practice%20with%20expressions%2C%20variables%2C%20branching%2C%20functions%2C%20and%20loops.%0A%0A%20%20%20%20%23%23%20References%0A%0A%20%20%20%20-%20Python%20Software%20Foundation%2C%20%5BPython%203%20tutorial%5D(https%3A%2F%2Fdocs.python.org%2F3%2Ftutorial%2F)%20and%20%5BFloating-point%20arithmetic%5D(https%3A%2F%2Fdocs.python.org%2F3%2Ftutorial%2Ffloatingpoint.html).%0A%20%20%20%20-%20marimo%20team%2C%20%5BGetting%20Started%5D(https%3A%2F%2Fdocs.marimo.io%2Fgetting_started%2F)%2C%20%5BKey%20concepts%5D(https%3A%2F%2Fdocs.marimo.io%2Fgetting_started%2Fkey_concepts%2F)%2C%20and%20%5BHow%20marimo%20runs%20cells%5D(https%3A%2F%2Fdocs.marimo.io%2Fguides%2Freactivity%2F).%0A%20%20%20%20-%20NumPy%20developers%2C%20%5BNumPy%20quickstart%5D(https%3A%2F%2Fnumpy.org%2Fdoc%2Fstable%2Fuser%2Fquickstart.html).%0A%20%20%20%20-%20Matplotlib%20developers%2C%20%5BQuick%20start%20guide%5D(https%3A%2F%2Fmatplotlib.org%2Fstable%2Fusers%2Fexplain%2Fquick_start.html).%0A%20%20%20%20-%20SciPy%20developers%2C%20%5BSignal%20processing%5D(https%3A%2F%2Fdocs.scipy.org%2Fdoc%2Fscipy%2Ftutorial%2Fsignal.html)%20and%20%5BFourier%20transforms%5D(https%3A%2F%2Fdocs.scipy.org%2Fdoc%2Fscipy%2Ftutorial%2Ffft.html).%0A%20%20%20%20-%20SymPy%20developers%2C%20%5BIntroductory%20tutorial%5D(https%3A%2F%2Fdocs.sympy.org%2Flatest%2Ftutorials%2Fintro-tutorial%2Findex.html).%0A%20%20%20%20-%20pandas%20developers%2C%20%5BGetting%20started%20tutorials%5D(https%3A%2F%2Fpandas.pydata.org%2Fdocs%2Fgetting_started%2Fintro_tutorials%2Findex.html).%0A%20%20%20%20%22%22%22)%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
9785eaceec4e340f18775d83fe9dcf4a