biomechzoo 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of biomechzoo might be problematic. Click here for more details.

Files changed (44) hide show
  1. biomechzoo/__init__.py +5 -0
  2. biomechzoo/__main__.py +6 -0
  3. biomechzoo/biomech_ops/continuous_relative_phase_data.py +31 -0
  4. biomechzoo/biomech_ops/continuous_relative_phase_line.py +36 -0
  5. biomechzoo/biomech_ops/filter_data.py +56 -0
  6. biomechzoo/biomech_ops/filter_line.py +88 -0
  7. biomechzoo/biomech_ops/normalize_data.py +35 -0
  8. biomechzoo/biomech_ops/normalize_line.py +27 -0
  9. biomechzoo/biomech_ops/phase_angle_data.py +39 -0
  10. biomechzoo/biomech_ops/phase_angle_line.py +48 -0
  11. biomechzoo/biomechzoo.py +349 -0
  12. biomechzoo/conversion/__init__.py +0 -0
  13. biomechzoo/conversion/c3d2zoo_data.py +65 -0
  14. biomechzoo/conversion/csv2zoo_data.py +78 -0
  15. biomechzoo/conversion/mvnx2zoo_data.py +71 -0
  16. biomechzoo/conversion/opencap2zoo_data.py +23 -0
  17. biomechzoo/mvn/load_mvnx.py +514 -0
  18. biomechzoo/mvn/main_mvnx.py +75 -0
  19. biomechzoo/mvn/mvn.py +232 -0
  20. biomechzoo/mvn/mvnx_file_accessor.py +463 -0
  21. biomechzoo/processing/add_channel_data.py +71 -0
  22. biomechzoo/processing/addchannel_data.py +71 -0
  23. biomechzoo/processing/addevent_data.py +46 -0
  24. biomechzoo/processing/explodechannel_data.py +46 -0
  25. biomechzoo/processing/partition_data.py +51 -0
  26. biomechzoo/processing/removechannel_data.py +36 -0
  27. biomechzoo/processing/renamechannel_data.py +79 -0
  28. biomechzoo/processing/renameevent_data.py +68 -0
  29. biomechzoo/processing/split_trial_by_gait_cycle.py +52 -0
  30. biomechzoo/utils/batchdisp.py +21 -0
  31. biomechzoo/utils/compute_sampling_rate_from_time.py +25 -0
  32. biomechzoo/utils/engine.py +68 -0
  33. biomechzoo/utils/findfield.py +11 -0
  34. biomechzoo/utils/get_split_events.py +33 -0
  35. biomechzoo/utils/split_trial.py +23 -0
  36. biomechzoo/utils/zload.py +46 -0
  37. biomechzoo/utils/zplot.py +61 -0
  38. biomechzoo/utils/zsave.py +50 -0
  39. biomechzoo-0.1.1.dist-info/METADATA +48 -0
  40. biomechzoo-0.1.1.dist-info/RECORD +44 -0
  41. biomechzoo-0.1.1.dist-info/WHEEL +5 -0
  42. biomechzoo-0.1.1.dist-info/entry_points.txt +2 -0
  43. biomechzoo-0.1.1.dist-info/licenses/LICENSE +21 -0
  44. biomechzoo-0.1.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,23 @@
1
+ def split_trial(data, start_event_indx, end_event_indx):
2
+ # todo check index problem compared to matlab start at 0 or 1
3
+ data_new = data.copy()
4
+
5
+ for key, value in data_new.items():
6
+ if key == 'zoosystem':
7
+ continue
8
+
9
+ # Slice the line data
10
+ data_new[key]['line'] = value['line'][start_event_indx:end_event_indx]
11
+
12
+ # Update events if present
13
+ if 'event' in value:
14
+ new_events = {}
15
+ for evt_name, evt_val in value['event'].items():
16
+ event_frame = evt_val[0]
17
+ # Check if event falls within the new window
18
+ if start_event_indx <= event_frame < end_event_indx:
19
+ # Adjust index relative to new start
20
+ new_events[evt_name] = [event_frame - start_event_indx, 0, 0]
21
+ data_new[key]['event'] = new_events
22
+
23
+ return data_new
@@ -0,0 +1,46 @@
1
+ from scipy.io import loadmat
2
+ import os
3
+
4
+
5
+ def zload(filepath):
6
+ if not filepath.endswith('.zoo'):
7
+ raise ValueError(f"{filepath} is not a .zoo file")
8
+
9
+ if not os.path.exists(filepath):
10
+ raise FileNotFoundError(f"File not found: {filepath}")
11
+
12
+ mat_data = loadmat(filepath, struct_as_record=False, squeeze_me=True)
13
+
14
+ # Remove default MATLAB metadata fields
15
+ mat_data = {k: v for k, v in mat_data.items() if not k.startswith('__')}
16
+
17
+ # Convert MATLAB structs to Python dicts (recursively)
18
+ def mat_struct_to_dict(obj):
19
+ if isinstance(obj, dict):
20
+ return {k: mat_struct_to_dict(v) for k, v in obj.items()}
21
+ elif hasattr(obj, '_fieldnames'):
22
+ return {field: mat_struct_to_dict(getattr(obj, field)) for field in obj._fieldnames}
23
+ elif isinstance(obj, list):
24
+ return [mat_struct_to_dict(item) for item in obj]
25
+ else:
26
+ return obj
27
+ data = {k: mat_struct_to_dict(v) for k, v in mat_data.items()}
28
+
29
+ if 'data' in data:
30
+ data = data['data']
31
+
32
+ return data
33
+
34
+
35
+ if __name__ == '__main__':
36
+ """ testing: load a single zoo file from the other subfolder in data"""
37
+ # -------TESTING--------
38
+ current_dir = os.path.dirname(os.path.abspath(__file__))
39
+ project_root = os.path.dirname(current_dir)
40
+ fl = os.path.join(project_root, 'data', 'other', 'HC030A05.zoo')
41
+ data = zload(fl)
42
+
43
+ channels = [k for k in data.keys()]
44
+ print('{} channels found'.format(len(channels)))
45
+ for ch in channels:
46
+ print({ch})
@@ -0,0 +1,61 @@
1
+ import matplotlib.pyplot as plt
2
+
3
+
4
+ def zplot(data, ch, xlabel='frames', ylabel='angles (deg)'):
5
+ """
6
+ Plot a single channel of a zoo file, along with any existing events.
7
+
8
+ Parameters
9
+ ----------
10
+ data : dict
11
+ Loaded zoo file.
12
+ ch : str
13
+ Name of the channel to plot, e.g., 'RkneeAngles'.
14
+ xlabel : str
15
+ Label for x-axis. Default is 'frames'.
16
+ ylabel : str
17
+ Label for y-axis. Default is 'angles (deg)'.
18
+
19
+ Returns
20
+ -------
21
+ None
22
+ """
23
+
24
+ if ch not in data:
25
+ raise KeyError(f"Channel '{ch}' not found in data.")
26
+
27
+ y = data[ch]['line']
28
+ x = range(len(y))
29
+
30
+ plt.figure(figsize=(10, 4))
31
+ plt.plot(x, y, label='Signal', linewidth=2)
32
+ plt.title(ch)
33
+ plt.xlabel(xlabel)
34
+ plt.ylabel(ylabel)
35
+ plt.grid(True)
36
+
37
+ # Plot events if available
38
+ events = data[ch].get('event', {})
39
+ for name, coords in events.items():
40
+ evtx, evty = coords[0], coords[1]
41
+ plt.plot(evtx, evty, 'ro')
42
+ plt.text(evtx, evty, name, fontsize=8, color='red', ha='left', va='bottom')
43
+
44
+ plt.tight_layout()
45
+ plt.show()
46
+
47
+
48
+ if __name__ == '__main__':
49
+ # -------TESTING--------
50
+ import os
51
+ from biomechzoo.utils.zload import zload
52
+
53
+ # get path to sample zoo file
54
+ current_dir = os.path.dirname(os.path.abspath(__file__))
55
+ project_root = os.path.dirname(current_dir)
56
+ fl = os.path.join(project_root, 'data', 'other', 'HC030A05.zoo')
57
+
58
+ # load zoo file
59
+ data = zload(fl)
60
+ ch = 'SACR'
61
+ zplot(data, ch)
@@ -0,0 +1,50 @@
1
+ from scipy.io import savemat
2
+ import inspect
3
+ import os
4
+
5
+
6
+ def zsave(fl, data, inplace=True, out_folder=None, root_folder=None):
7
+ """
8
+ Save zoo data to .zoo file (MAT format)
9
+
10
+ Arguments:
11
+ fl (str): Full path to original .zoo file
12
+ data (dict): Zoo data to save
13
+ inplace (bool): Whether to overwrite original file
14
+ out_folder (str or None): If not inplace, output folder name (relative to root_folder or file location)
15
+ root_folder (str or None): Optional base directory for saving when inplace=False
16
+ """
17
+ # Get caller function name for logging
18
+ caller_name = inspect.stack()[1].function
19
+
20
+ # Initialize zoosystem and processing history
21
+ zoosystem = data.get('zoosystem', {})
22
+ processing = zoosystem.get('Processing', [])
23
+ if not isinstance(processing, list):
24
+ processing = [processing]
25
+ processing.append(caller_name)
26
+ zoosystem['Processing'] = processing
27
+ data['zoosystem'] = zoosystem
28
+
29
+ # Determine save path
30
+ if inplace:
31
+ save_path = fl
32
+ else:
33
+ filename = os.path.basename(fl)
34
+ if out_folder is None:
35
+ out_folder = 'processed'
36
+
37
+ if root_folder is None:
38
+ root_folder = os.path.dirname(fl)
39
+
40
+ root_path = os.path.dirname(root_folder)
41
+ in_folder = os.path.basename(root_folder)
42
+ out_dir = os.path.join(root_path, out_folder)
43
+ os.makedirs(out_dir, exist_ok=True)
44
+ fl_new = fl.replace(in_folder, out_folder)
45
+ save_folder = os.path.dirname(fl_new)
46
+ os.makedirs(save_folder, exist_ok=True)
47
+
48
+ # Save the .zoo file
49
+ savemat(fl_new, data)
50
+
@@ -0,0 +1,48 @@
1
+ Metadata-Version: 2.4
2
+ Name: biomechzoo
3
+ Version: 0.1.1
4
+ Summary: Python implementation of the biomechZoo Matlab toolbox
5
+ License-Expression: MIT
6
+ Project-URL: Homepage, https://github.com/mcgillmotionlab/biomechzoo
7
+ Requires-Python: >=3.13
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: ezc3d>=1.5.19
11
+ Requires-Dist: matplotlib>=3.10.6
12
+ Requires-Dist: numpy>=2.3.3
13
+ Requires-Dist: pandas>=2.3.2
14
+ Requires-Dist: scipy>=1.16.2
15
+ Dynamic: license-file
16
+
17
+ # Repository for the Python version of biomechZoo
18
+ This is a development version of the biomechzoo toolbox for python. To use biomechzoo
19
+ as a packagage alongside your code, follow the "How to install" instructions below
20
+
21
+ ## How to install
22
+ - make sure the local version of your code sits at the same level as biomechzoo.
23
+ e.g.
24
+ code_root/
25
+ code_root/biomechzoo/ ← the repo with the actual package
26
+ code_root/student_code/ ← where your scripts or notebooks live
27
+
28
+ - open terminal or command window
29
+ - create an environment for your research project: ``conda create -n name python=3.13 -c conda-forge``, where name is of your choice
30
+ - activate your new environment: ``conda activate name``
31
+ - navigate to parent directory where biomechzoo was cloned. e.g. ``code_root``
32
+ - install biomechzoo: ``pip install -e biomechzoo``
33
+ - install additional requirements: ``pip install -r biomechzoo/pip_requirements.txt``
34
+
35
+ ## Updates (not tested)
36
+ - If updates are made to biomechzoo, simply pull the latest version
37
+ from github, you won't need to reinstall (unless there are new dependencies)
38
+
39
+ ## Usage notes
40
+ - To use biomechzoo in your project, you will need to import biomechzoo as:
41
+ ``from biomechzoo.biomechzoo import BiomechZoo``
42
+ - Then, you can create an object that is an instance of the BimechZoo class as:
43
+ ``bmech = BiomechZoo(fld)`` where ``fld`` is the path to your data
44
+
45
+
46
+ # opencap users
47
+ - opencap users should pre-process their data using ``https://github.com/stanfordnmbl/opencap-processing``
48
+ - processed data could be saved to csv using pandas and then imported to biomechzoo using csv2zoo (not yet functional)
@@ -0,0 +1,44 @@
1
+ biomechzoo/__init__.py,sha256=IXj0mVJCHQ06awsQVJo0CCRDbplqP6dxZ1MQ6GUuCPw,107
2
+ biomechzoo/__main__.py,sha256=hSMHN1Rxn2367fSGTLHoOQ4_pocZw0IWI7HFxl-74oY,88
3
+ biomechzoo/biomechzoo.py,sha256=bmP81dLlYPE2NnZ76xK-MVlVyDuKKU08OF58dtzieps,15433
4
+ biomechzoo/biomech_ops/continuous_relative_phase_data.py,sha256=RePbt6zyOI1iv74CWhxSrunIokTFYVfFmFnoW51781E,1300
5
+ biomechzoo/biomech_ops/continuous_relative_phase_line.py,sha256=Fa1LFRuPlmGPLQLvln6HVnJy3zMSm9z5YeooHmTu0lc,1365
6
+ biomechzoo/biomech_ops/filter_data.py,sha256=LZSlemUfbBTrqbo7miFubgTf9R4pr1kEgdmvljmNWdQ,1742
7
+ biomechzoo/biomech_ops/filter_line.py,sha256=BuUFALIkmdFhmVocFaZ3aczy_efh2CY_qX9-5CoQZr0,2716
8
+ biomechzoo/biomech_ops/normalize_data.py,sha256=gpoUh6EpxpCprBdrSjmZ4UsAWgonJgD41XUJWD8Yo9Y,1299
9
+ biomechzoo/biomech_ops/normalize_line.py,sha256=KUE8gEkIolA-VDFCdUuaskk-waO8jjJ20ZMZaS8Qha8,854
10
+ biomechzoo/biomech_ops/phase_angle_data.py,sha256=_ekUBW2v3iC4UawcDL38ZZLYJmQsAmyqA61Q6_AMtmQ,1435
11
+ biomechzoo/biomech_ops/phase_angle_line.py,sha256=p6osB17_3QQSyKLNojuc6nYhv-k0K6EUUH75EXu8ifc,1391
12
+ biomechzoo/conversion/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ biomechzoo/conversion/c3d2zoo_data.py,sha256=kmiLQHglchSHty6DrMEl5yTOUi3U4Ai5nHoSGvbF6k8,2660
14
+ biomechzoo/conversion/csv2zoo_data.py,sha256=-c4CXxcKd70HJWWgHRztOxOckvA1XgIDzo8EhgJhcKE,2185
15
+ biomechzoo/conversion/mvnx2zoo_data.py,sha256=ID1X_VtzFQrgqNpTMd-_DJ-3mVUIW0t9qwCsI5VJI-M,2861
16
+ biomechzoo/conversion/opencap2zoo_data.py,sha256=n4bLsrJI0wTSzG5bgJcmxj1dp2plnUKFNRzcTIbmV1o,608
17
+ biomechzoo/mvn/load_mvnx.py,sha256=B4VGuidQ-5G_5E1t5vpU51Nb_Lu85_EOS_FmGZYjfX8,22499
18
+ biomechzoo/mvn/main_mvnx.py,sha256=e1LasJQ9icyzjWnRCEcAWQq_-L13-mIzf7PzYA3QYDg,2394
19
+ biomechzoo/mvn/mvn.py,sha256=I62ljRo0I0ajc6KLW8J4SmXL_M-rHerHinD_UaFzS8U,7537
20
+ biomechzoo/mvn/mvnx_file_accessor.py,sha256=kLMg3mwpqqRyqFycoaPkI6ejKJzxBnPK9iiIYl-LmY8,20097
21
+ biomechzoo/processing/add_channel_data.py,sha256=U1xLLBSnyJeeDWzgmHSxOz1hyguzuuDXxQCQ8IFoZkw,1955
22
+ biomechzoo/processing/addchannel_data.py,sha256=rmnnlMRVkoMlQCR-nRg1jjh-hzMDt37Sx9fAmocrpqA,1953
23
+ biomechzoo/processing/addevent_data.py,sha256=DyTfvjOWZIlsWfnT6XDwvsU1jOzSDf4HhLa1TaKIhwI,1325
24
+ biomechzoo/processing/explodechannel_data.py,sha256=t4gC2ZQD4baECexj0hQYDzOnXV5GHb-z068mtZzh0DQ,1470
25
+ biomechzoo/processing/partition_data.py,sha256=8pMGRVXzYbPa4tuB7K3OOjUCnROpXb2v1gcRRNAbSig,1704
26
+ biomechzoo/processing/removechannel_data.py,sha256=ndZcbWJRDvd7drlahGaq8MseT-rsxiu7pgdMtA1cTlo,1218
27
+ biomechzoo/processing/renamechannel_data.py,sha256=5lEnWJknAwnJYXDlwO6cFe7C8ct5o42tTHW0Y4GeIL4,2210
28
+ biomechzoo/processing/renameevent_data.py,sha256=9w7C_fQOsQ8XbdTr_hrg_iQe51oDczq2Rj7yJLyYG0M,2215
29
+ biomechzoo/processing/split_trial_by_gait_cycle.py,sha256=maMUwumSlFLFc5LHdNdBO9JCoT06aaLbpdp43dgowDA,1684
30
+ biomechzoo/utils/batchdisp.py,sha256=Ke7yeZ4cYQvyf8bmgsiLaRElUeQm49TYIYzAcPWan9s,839
31
+ biomechzoo/utils/compute_sampling_rate_from_time.py,sha256=iyHbN734vYe5bXEoAsHScJN7Qw--2quUgII7judSQDk,579
32
+ biomechzoo/utils/engine.py,sha256=WSZmi6DDZHcdOhgsu2LvmLF-Ftxcjteh9TbKDMZIN5k,3240
33
+ biomechzoo/utils/findfield.py,sha256=i7ewGQOMIiTC06tYFK-JctehHLCippkY9FoXIygx14w,381
34
+ biomechzoo/utils/get_split_events.py,sha256=xNhEuG6Yqsr1bjWIBHLbepfX-fcqcCYIXZzS3eaDDHQ,911
35
+ biomechzoo/utils/split_trial.py,sha256=Fumz_ZukNBNtPauUhCge5EAHkg05dYDhA1_njQw0lHE,886
36
+ biomechzoo/utils/zload.py,sha256=FPT6_-gwaOOqOckjgPRfnKEVKMsmNVIcenmQZF2KOvo,1535
37
+ biomechzoo/utils/zplot.py,sha256=WVA8aCy1Pqy_bo_HXab9AmW-cBd8J8MPX2LAOd6dznU,1512
38
+ biomechzoo/utils/zsave.py,sha256=2DeF6A1R32SnXJXtb8jtPqZAmlSEB0PVi09UGiskzMo,1625
39
+ biomechzoo-0.1.1.dist-info/licenses/LICENSE,sha256=Fsz62nrgRORre3A1wNXUDISaHoostodMvocRPDdXc9w,1076
40
+ biomechzoo-0.1.1.dist-info/METADATA,sha256=mrVsykfuRyZqM15ARHUAX--XOfjzmnMysxVT4HYKtpY,2096
41
+ biomechzoo-0.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
42
+ biomechzoo-0.1.1.dist-info/entry_points.txt,sha256=VdryUUiwwvx0WZxrgmMrsyfe5Z1jtyaxdXOi0zWHOqk,41
43
+ biomechzoo-0.1.1.dist-info/top_level.txt,sha256=W148kdiK-6L0Nohbw8UALkAzHJvJLAhFDRykuva2WjY,11
44
+ biomechzoo-0.1.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ biomechzoo = main:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) [2025] McGill MOTION Lab
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1 @@
1
+ biomechzoo