%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%22marimo%3E%3D0.23.9%22%2C%20%22numpy%3E%3D2.0%22%2C%20%22matplotlib%3E%3D3.9%22%2C%20%22pandas%3E%3D2.2%22%2C%20%22urllib3%3E%3D2.2%22%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()%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%20pandas%20Data%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%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%20A%20motion-capture%20table%20contains%20dozens%20of%20markers%2C%20each%20with%20X%2C%20Y%2C%20and%20Z%20coordinates.%20How%20can%20labels%20help%20us%20select%20the%20right%20trajectory%3F%0A%0A%20%20%20%20We%20will%20compare%20flat%20column%20names%20and%20a%20two-level%20pandas%20index%2C%20then%20select%20and%20plot%20coordinates%20in%20marimo.%0A%0A%20%20%20%20Predict%20the%20result%20before%20running%20each%20example.%20Try%20the%20**Exercises**%20before%20opening%20their%20worked%20solutions.%20Finish%20with%20the%20**Checkpoint%20questions**%20and%20**Problems**%3B%20the%20latter%20provide%20final%20answers%20only.%0A%0A%20%20%20%20Open%20this%20file%20locally%20in%20marimo%2C%20on%20%5Bmarimo.app%5D(https%3A%2F%2Fmarimo.app%2F)%2C%20or%20in%20%5Bmolab%5D(https%3A%2F%2Fmolab.marimo.io%2Fnotebooks).%20The%20public%20%60data%2Fwalk1.trc%60%20recording%20replaces%20the%20unavailable%20private%20file%20used%20in%20the%20old%20version.%20The%20loader%20checks%20the%20repository%20first%2C%20then%20downloads%20the%20same%20file.%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%20Pandas%20keeps%20column%20and%20time%20labels%3B%20Matplotlib%20draws%20the%20trajectories.%20Marimo%20controls%20update%20the%20plot%20reactively.%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%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20pandas%20as%20pd%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%0A%20%20%20%20return%20mo%2C%20pd%2C%20plt%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20from%20notebook_resources%20import%20repo_file%0A%20%20%20%20except%20ModuleNotFoundError%20as%20_error%3A%0A%20%20%20%20%20%20%20%20if%20_error.name%20!%3D%20%22notebook_resources%22%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%0A%20%20%20%20%20%20%20%20raise%20ModuleNotFoundError(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22This%20notebook%20needs%20notebook_resources.py.%20Download%20it%20from%3A%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%22https%3A%2F%2Fraw.githubusercontent.com%2FBMClab%2FBMC%2Fmaster%2Ffunctions%2Fnotebook_resources.py%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Save%20it%20in%20the%20same%20folder%20as%20this%20notebook%2C%20then%20rerun%20this%20cell.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22notebook_resources%22%2C%0A%20%20%20%20%20%20%20%20)%20from%20None%0A%20%20%20%20return%20(repo_file%2C)%0A%0A%0A%40app.cell%0Adef%20_(repo_file)%3A%0A%20%20%20%20fname%20%3D%20repo_file(%22data%2Fwalk1.trc%22)%0A%20%20%20%20return%20(fname%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%20pandas%20with%20one%20index%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(fname%2C%20pd)%3A%0A%20%20%20%20_lines%20%3D%20fname.read_text().splitlines()%0A%20%20%20%20_markers%20%3D%20%5Bm.replace(%22.%22%2C%20%22%22)%20for%20m%20in%20_lines%5B3%5D.split(%22%5Ct%22)%5B2%3A%3A3%5D%20if%20m%5D%0A%20%20%20%20_raw%20%3D%20pd.read_csv(fname%2C%20sep%3D%22%5Ct%22%2C%20skiprows%3D6%2C%20header%3DNone)%0A%20%20%20%20_values%20%3D%20_raw.iloc%5B%3A%2C%202%3A2%20%2B%203%20*%20len(_markers)%5D.to_numpy(dtype%3Dfloat)%0A%20%20%20%20df%20%3D%20pd.DataFrame(_values%2C%20index%3D_raw.iloc%5B%3A%2C%201%5D.to_numpy()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20columns%3D%5Bm%20%2B%20c%20for%20m%20in%20_markers%20for%20c%20in%20%22XYZ%22%5D)%0A%20%20%20%20df.index.name%20%3D%20%22Time%20%5Bs%5D%22%0A%20%20%20%20df.head()%0A%20%20%20%20return%20(df%2C)%0A%0A%0A%40app.cell%0Adef%20_(df%2C%20plt)%3A%0A%20%20%20%20_ax%20%3D%20df.plot(y%3D'RASISX'%2C%20figsize%3D(8%2C%203)%2C%20title%3D'A%20plot%20of%20kinematics')%0A%20%20%20%20_ax.set_ylabel('Position%20%5Bmm%5D')%0A%20%20%20%20plt.tight_layout(pad%3D0%2C%20h_pad%3D0%2C%20rect%3D%5B0%2C%200%2C%201%2C%200.95%5D)%0A%20%20%20%20_ax.figure%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.**%20What%20does%20%60df%5B%22RASISX%22%5D%60%20select%2C%20and%20what%20is%20the%20index%20measured%20in%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%2F%2F%2F%20details%20%7C%20Solution%20to%20Exercise%201%0A%0A%20%20%20%20It%20selects%20the%20X%20coordinate%20of%20the%20right%20anterior%20superior%20iliac%20spine%20marker.%20The%20index%20is%20acquisition%20time%20in%20seconds.%20The%20recorded%20coordinates%20are%20in%20millimetres%2C%20as%20specified%20by%20the%20TRC%20header.%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%0Adef%20_(df%2C%20mo)%3A%0A%20%20%20%20selected_columns%20%3D%20mo.ui.multiselect(options%3Dlist(df.columns)%2C%20value%3D%5B%22RASISX%22%5D%2C%20label%3D%22Trajectories%22)%0A%20%20%20%20selected_columns%0A%20%20%20%20return%20(selected_columns%2C)%0A%0A%0A%40app.cell%0Adef%20_(df%2C%20plt%2C%20selected_columns)%3A%0A%20%20%20%20_fig%2C%20_ax%20%3D%20plt.subplots(figsize%3D(9%2C%203))%0A%20%20%20%20if%20selected_columns.value%3A%0A%20%20%20%20%20%20%20%20df.loc%5B%3A%2C%20selected_columns.value%5D.plot(ax%3D_ax)%0A%20%20%20%20_ax.set(xlabel%3D%22Time%20%5Bs%5D%22%2C%20ylabel%3D%22Position%20%5Bmm%5D%22)%0A%20%20%20%20_fig%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20pandas%20multiindex%0A%0A%20%20%20%20Data%20with%20hierarchical%20column%20index%20(%5Bmultiindex%5D(https%3A%2F%2Fpandas.pydata.org%2Fdocs%2Fuser_guide%2Fadvanced.html))%20where%20columns%20have%20multiple%20levels.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(df%2C%20pd)%3A%0A%20%20%20%20df_1%20%3D%20df.copy()%0A%20%20%20%20df_1.columns%20%3D%20pd.MultiIndex.from_tuples(%0A%20%20%20%20%20%20%20%20%5B(name%5B%3A-1%5D%2C%20name%5B-1%5D)%20for%20name%20in%20df.columns%5D%2C%20names%3D%5B%22Marker%22%2C%20%22Coordinate%22%5D%0A%20%20%20%20)%0A%20%20%20%20df_1.head()%0A%20%20%20%20return%20(df_1%2C)%0A%0A%0A%40app.cell%0Adef%20_(df_1)%3A%0A%20%20%20%20df_1.head()%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(df_1)%3A%0A%20%20%20%20df_1%5B'RASIS'%5D.head()%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(df_1)%3A%0A%20%20%20%20df_1.RASIS.X.head()%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%202.**%20A%20table%20has%2028%20markers%20and%20three%20coordinates%20each.%20How%20many%20columns%20should%20the%20full%20table%20have%3F%20How%20many%20remain%20after%20selecting%20X%20for%20every%20marker%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%2F%2F%2F%20details%20%7C%20Solution%20to%20Exercise%202%0A%0A%20%20%20%20The%20full%20table%20has%20%2428%5Ctimes3%3D84%24%20columns.%20Selecting%20one%20coordinate%20for%20all%2028%20markers%20gives%2028%20columns.%20The%20number%20of%20time%20rows%20is%20unchanged.%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%0Adef%20_(df_1)%3A%0A%20%20%20%20df_1.xs('X'%2C%20level%3D'Coordinate'%2C%20axis%3D1).head()%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(df_1)%3A%0A%20%20%20%20df_1.loc%5B%3A%2C%20(slice(None)%2C%20'X')%5D.head()%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(df_1)%3A%0A%20%20%20%20df_1.swaplevel(0%2C%201%2C%20axis%3D1).head()%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(df_1)%3A%0A%20%20%20%20_ax%20%3D%20df_1.plot(y%3D('RASIS'%2C%20'X')%2C%20subplots%3DTrue%2C%20figsize%3D(8%2C%202)%2C%20rot%3D0)%0A%20%20%20%20_ax%5B0%5D.figure%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(df_1%2C%20plt)%3A%0A%20%20%20%20_ax%20%3D%20df_1.plot(y%3D'RASIS'%2C%20subplots%3DTrue%2C%20sharex%3DTrue%2C%20figsize%3D(8%2C%204)%2C%20rot%3D0%2C%20title%3D'A%20plot%20of%20kinematics')%0A%20%20%20%20plt.tight_layout(pad%3D0%2C%20h_pad%3D0%2C%20rect%3D%5B0%2C%200%2C%201%2C%200.95%5D)%0A%20%20%20%20_ax%5B0%5D.figure%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.**%20Does%20swapping%20the%20two%20column-index%20levels%20change%20the%20measured%20coordinates%3F%20What%20information%20is%20lost%20in%20%60.values%60%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%2F%2F%2F%20details%20%7C%20Solution%20to%20Exercise%203%0A%0A%20%20%20%20Swapping%20levels%20changes%20the%20label%20hierarchy%2C%20not%20the%20values.%20Converting%20to%20a%20NumPy%20array%20with%20%60.values%60%20drops%20the%20pandas%20labels%3B%20retain%20or%20reconstruct%20those%20labels%20before%20interpreting%20columns.%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%0Adef%20_(df_1)%3A%0A%20%20%20%20values%20%3D%20df_1.reset_index(drop%3DFalse).values%0A%20%20%20%20values%5B0%2C%20%3A5%5D%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(df_1)%3A%0A%20%20%20%20df_1.head()%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(df_1)%3A%0A%20%20%20%20x%20%3D%20df_1.swaplevel(0%2C%201%2C%20axis%3D1)%0A%20%20%20%20return%20(x%2C)%0A%0A%0A%40app.cell%0Adef%20_(x)%3A%0A%20%20%20%20x2%20%3D%20x.unstack(level%3D-1)%0A%20%20%20%20x2.head()%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(x)%3A%0A%20%20%20%20x.head()%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.%20Does%20%60head()%60%20shorten%20the%20stored%20table%3F%0A%0A%20%20%20%202.%20What%20does%20%60xs(%22X%22%2C%20level%3D%22Coordinate%22%2C%20axis%3D1)%60%20select%3F%0A%0A%20%20%20%203.%20Why%20keep%20units%20with%20a%20trajectory%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%2F%2F%2F%20details%20%7C%20Checkpoint%20answers%0A%0A%20%20%20%201.%20No%3B%20it%20only%20displays%20the%20first%20rows.%0A%20%20%20%202.%20The%20X%20coordinate%20for%20each%20marker.%0A%20%20%20%203.%20Labels%20alone%20do%20not%20distinguish%20metres%20from%20millimetres.%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%20Try%20these%20independently%3B%20open%20a%20panel%20only%20to%20check%20your%20final%20answer.%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**Problem%201.**%20A%20table%20has%2010%20markers%2C%203%20coordinates%2C%20and%20200%20frames.%20Give%20its%20shape%20before%20selecting%20a%20coordinate.%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%2F%2F%2F%20details%20%7C%20Answer%20to%20Problem%201%0A%0A%20%20%20%20(200%2C%2030).%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**Problem%202.**%20Give%20a%20pandas%20expression%20selecting%20X%20for%20marker%20RASIS%20from%20the%20two-level%20table%20%60df_1%60.%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%2F%2F%2F%20details%20%7C%20Answer%20to%20Problem%202%0A%0A%20%20%20%20%60df_1.loc%5B%3A%2C%20(%22RASIS%22%2C%20%22X%22)%5D%60.%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%20Compare%20%60xs%60%2C%20%60loc%60%2C%20%60swaplevel%60%2C%20and%20%60unstack%60%20in%20the%20retained%20examples.%20Check%20both%20shape%20and%20labels%20after%20each%20operation.%0A%0A%20%20%20%20%23%23%23%20Video%20lectures%20on%20the%20Internet%0A%0A%20%20%20%20%5BOfficial%20pandas%20presentation%20archive%5D(https%3A%2F%2Fpandas.pydata.org%2Fcommunity%2Fecosystem.html)%20links%20learning%20resources%3B%20%5BPyData%20video%20archive%5D(https%3A%2F%2Fwww.youtube.com%2F%40PyDataTV)%20includes%20pandas%20indexing%20talks.%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%20References%0A%0A%20%20%20%20-%20%5Bpandas%3A%20MultiIndex%20and%20advanced%20indexing%5D(https%3A%2F%2Fpandas.pydata.org%2Fdocs%2Fuser_guide%2Fadvanced.html).%0A%0A%20%20%20%20-%20%5BMarimo%20user-interface%20elements%5D(https%3A%2F%2Fdocs.marimo.io%2Fapi%2Finputs%2F).%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
69dc258a3db6ae442b21e5df31788133