biomechzoo 0.5.9__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.
Files changed (58) hide show
  1. __init__.py +33 -0
  2. biomechzoo/__init__.py +0 -0
  3. biomechzoo/__main__.py +6 -0
  4. biomechzoo/biomech_ops/__init__.py +0 -0
  5. biomechzoo/biomech_ops/continuous_relative_phase_data.py +31 -0
  6. biomechzoo/biomech_ops/continuous_relative_phase_line.py +36 -0
  7. biomechzoo/biomech_ops/filter_data.py +58 -0
  8. biomechzoo/biomech_ops/filter_line.py +85 -0
  9. biomechzoo/biomech_ops/movement_onset.py +53 -0
  10. biomechzoo/biomech_ops/normalize_data.py +36 -0
  11. biomechzoo/biomech_ops/normalize_line.py +51 -0
  12. biomechzoo/biomech_ops/phase_angle_data.py +39 -0
  13. biomechzoo/biomech_ops/phase_angle_line.py +48 -0
  14. biomechzoo/biomechzoo.py +447 -0
  15. biomechzoo/conversion/__init__.py +0 -0
  16. biomechzoo/conversion/c3d2zoo_data.py +95 -0
  17. biomechzoo/conversion/mvnx2zoo_data.py +113 -0
  18. biomechzoo/conversion/opencap2zoo_data.py +23 -0
  19. biomechzoo/conversion/table2zoo_data.py +114 -0
  20. biomechzoo/imu/__init__.py +0 -0
  21. biomechzoo/imu/kinematics.py +0 -0
  22. biomechzoo/imu/tilt_algorithm.py +112 -0
  23. biomechzoo/linear_algebra_ops/__init__.py +0 -0
  24. biomechzoo/linear_algebra_ops/compute_magnitude_data.py +43 -0
  25. biomechzoo/mvn/__init__.py +0 -0
  26. biomechzoo/mvn/load_mvnx.py +514 -0
  27. biomechzoo/mvn/main_mvnx.py +75 -0
  28. biomechzoo/mvn/mvn.py +232 -0
  29. biomechzoo/mvn/mvnx_file_accessor.py +464 -0
  30. biomechzoo/processing/__init__.py +0 -0
  31. biomechzoo/processing/addchannel_data.py +71 -0
  32. biomechzoo/processing/addevent_data.py +116 -0
  33. biomechzoo/processing/explodechannel_data.py +69 -0
  34. biomechzoo/processing/partition_data.py +46 -0
  35. biomechzoo/processing/removechannel_data.py +46 -0
  36. biomechzoo/processing/removeevent_data.py +57 -0
  37. biomechzoo/processing/renamechannel_data.py +79 -0
  38. biomechzoo/processing/renameevent_data.py +62 -0
  39. biomechzoo/processing/split_trial_data.py +40 -0
  40. biomechzoo/statistics/eventval.py +118 -0
  41. biomechzoo/utils/__init__.py +0 -0
  42. biomechzoo/utils/batchdisp.py +21 -0
  43. biomechzoo/utils/compute_sampling_rate_from_time.py +25 -0
  44. biomechzoo/utils/engine.py +88 -0
  45. biomechzoo/utils/findfield.py +11 -0
  46. biomechzoo/utils/get_split_events.py +33 -0
  47. biomechzoo/utils/peak_sign.py +24 -0
  48. biomechzoo/utils/set_zoosystem.py +66 -0
  49. biomechzoo/utils/version.py +5 -0
  50. biomechzoo/utils/zload.py +57 -0
  51. biomechzoo/utils/zplot.py +61 -0
  52. biomechzoo/utils/zsave.py +54 -0
  53. biomechzoo-0.5.9.dist-info/METADATA +46 -0
  54. biomechzoo-0.5.9.dist-info/RECORD +58 -0
  55. biomechzoo-0.5.9.dist-info/WHEEL +5 -0
  56. biomechzoo-0.5.9.dist-info/entry_points.txt +2 -0
  57. biomechzoo-0.5.9.dist-info/licenses/LICENSE +21 -0
  58. biomechzoo-0.5.9.dist-info/top_level.txt +2 -0
@@ -0,0 +1,71 @@
1
+ import numpy as np
2
+
3
+
4
+ def addchannel_data(data, ch_new_name, ch_new_data, section='Video'):
5
+ """
6
+ Add a new channel to zoo data.
7
+
8
+ Parameters
9
+ ----------
10
+ data : dict
11
+ Zoo file data.
12
+ ch_new_name : str
13
+ Name of the new channel.
14
+ ch_new_data : array-like
15
+ New data to be added to the channel (should be n x 1 or n x 3).
16
+ section : str
17
+ Section of zoo data ('Video' or 'Analog').
18
+
19
+ Returns
20
+ -------
21
+ dict
22
+ Updated zoo data with new channel added.
23
+
24
+ Notes
25
+ -----
26
+ - If the channel already exists, it will be overwritten.
27
+ - Adds channel name to the list in data['zoosystem'][section]['Channels'].
28
+ """
29
+
30
+ # Warn if overwriting
31
+ if ch_new_name in data:
32
+ print('Warning: channel {} already exists, overwriting...'.format(ch_new_name))
33
+
34
+ # Assign channel data
35
+ data[ch_new_name] = {
36
+ 'line': ch_new_data,
37
+ 'event': {}
38
+ }
39
+
40
+ # Update channel list
41
+ ch_list = data['zoosystem'][section].get('Channels', [])
42
+
43
+ # If the channel list is a NumPy array, convert it to a list
44
+ if isinstance(ch_list, np.ndarray):
45
+ ch_list = ch_list.tolist()
46
+
47
+ # Ensure it's a flat list of strings
48
+ if isinstance(ch_list, list) and ch_new_name not in ch_list:
49
+ ch_list.append(ch_new_name)
50
+ data['zoosystem'][section]['Channels'] = ch_list
51
+
52
+ return data
53
+
54
+
55
+ if __name__ == '__main__':
56
+ # -------TESTING--------
57
+ import os
58
+ from src.biomechzoo.utils.zload import zload
59
+ from src.biomechzoo.utils.zplot import zplot
60
+ # get path to sample zoo file
61
+ current_dir = os.path.dirname(os.path.abspath(__file__))
62
+ project_root = os.path.dirname(current_dir)
63
+ fl = os.path.join(project_root, 'data', 'other', 'HC030A05.zoo')
64
+
65
+ # load zoo file
66
+ data = zload(fl)
67
+ data = data['data']
68
+ r = data['RKneeAngles']['line']*3
69
+ data= addchannel_data(data, ch_new_name='blah', ch_new_data=r)
70
+ zplot(data, 'blah')
71
+
@@ -0,0 +1,116 @@
1
+ import numpy as np
2
+ import copy
3
+ import warnings
4
+ from scipy.signal import find_peaks
5
+ from biomechzoo.utils.peak_sign import peak_sign
6
+ from biomechzoo.biomech_ops.movement_onset import movement_onset
7
+
8
+ def addevent_data(data, channels, ename, etype, constant=None):
9
+
10
+ data_new = copy.deepcopy(data)
11
+
12
+ if isinstance(channels, str):
13
+ channels = [channels]
14
+
15
+ if len(channels) == 1 and channels[0].lower() == 'all':
16
+ channels = [key for key in data if key != 'zoosystem']
17
+
18
+ for channel in channels:
19
+ if ename == '':
20
+ data[channel]['event'] = {}
21
+ continue
22
+
23
+ if channel not in data:
24
+ raise KeyError('Channel {} does not exist'.format(channel))
25
+
26
+ yd = data_new[channel]['line'] # 1D array
27
+ etype = etype.lower()
28
+ if etype == 'absmax':
29
+ exd = int(np.argmax(np.abs(yd)))
30
+ eyd = float(yd[exd])
31
+ elif etype == 'first':
32
+ exd = 0
33
+ eyd = float(yd[exd])
34
+ elif etype == 'last':
35
+ exd = len(yd) - 1
36
+ eyd = float(yd[exd])
37
+ elif etype == 'max':
38
+ exd = int(np.argmax(yd))
39
+ eyd = float(yd[exd])
40
+ elif etype == 'min':
41
+ exd = int(np.argmin(yd))
42
+ eyd = float(yd[exd])
43
+ elif etype == 'rom':
44
+ eyd = float(np.max(yd) - np.min(yd))
45
+ exd = 0 # dummy index (like MATLAB version)
46
+ elif etype == 'first peak':
47
+ # special event for gait and running
48
+ exd = find_first_peak(yd, constant)
49
+ eyd = float(yd[exd])
50
+ elif etype == 'movement_onset':
51
+ exd = movement_onset(yd, constant, etype=etype)
52
+ eyd = yd[exd]
53
+ elif etype == 'movement_offset':
54
+ yd2 = yd[::-1].copy() # Reverse the time series.
55
+ exd = movement_onset(yd2, constant, etype=etype)
56
+ eyd = yd[exd]
57
+ elif etype in ['fs_fp', 'fo_fp']:
58
+ # --- Handle constant ---
59
+ if constant is None:
60
+ print('Warning: Force plate threshold not set, defaulting to 0.')
61
+ constant = 0.0
62
+
63
+ # --- Check sampling rates ---
64
+ AVR = data['zoosystem']['AVR']
65
+ if AVR != 1:
66
+ warnings.warn('Video and Analog channels must be at the same sampling rate or events will be incorrect.')
67
+
68
+ # --- Handle units ---
69
+ units = data['zoosystem']['Units']['Forces']
70
+ if units == 'N/kg':
71
+ m = data['zoosystem']['Anthro']['Bodymass']
72
+ else:
73
+ m = 1.0
74
+
75
+ # --- Extract force signal ---
76
+ if '_' not in channel:
77
+ yd = data_new[channel]['line'][:, 2] # looking for GRF Z
78
+ else:
79
+ yd = data_new[channel]['line']
80
+
81
+ # --- Determine peak sign ---
82
+ peak = peak_sign(yd) # user-defined function
83
+
84
+ # --- Find threshold crossing ---
85
+ threshold_signal = peak * yd * m
86
+ if 'fs' in etype:
87
+ exd_array = np.where(threshold_signal > constant)[0]
88
+ exd = exd_array[0] - 1 # MATLAB indexing correction
89
+ eyd = yd[exd]
90
+ else: # 'FO' type
91
+ exd_array = np.where(threshold_signal > constant)[0]
92
+ exd = exd_array[-1] + 1
93
+ eyd = yd[exd]
94
+
95
+ else:
96
+ raise ValueError(f'Unknown event type: {etype}')
97
+
98
+ # Add event to the channel's event dict
99
+ data_new[channel]['event'][ename] = [exd, eyd, 0]
100
+
101
+ return data_new
102
+
103
+ def find_first_peak(yd, constant):
104
+ """ extracts first peak from a series of 2 peaks """
105
+ # Find peaks above threshold
106
+ peaks, _ = find_peaks(yd, height=constant)
107
+
108
+ if len(peaks) == 0:
109
+ raise ValueError('No peaks found')
110
+ elif len(peaks) == 1:
111
+ raise ValueError('Only 1 peak found')
112
+ else:
113
+ # Take the first valid peak
114
+ exd = peaks[0]
115
+
116
+ return exd
@@ -0,0 +1,69 @@
1
+ import copy
2
+ import numpy as np
3
+
4
+ def explodechannel_data(data, channels=None):
5
+ """ Explodes 3D channels (n x 3 arrays) into separate X, Y, Z channels.
6
+
7
+ Arguments:
8
+ data (dict): Zoo data loaded from a file
9
+ channels (list of str or None): Channels to explode.
10
+ If None, explode all channels with 'line' shaped (n x 3).
11
+
12
+ Returns:
13
+ data_new (dict): Modified zoo dictionary with exploded channels.
14
+ """
15
+ data_new = copy.deepcopy(data)
16
+
17
+ # Ensure zoosystem channel lists are Python lists
18
+ for sys in ['Video', 'Analog']:
19
+ if sys in data_new.get('zoosystem', {}):
20
+ ch_list = data_new['zoosystem'][sys].get('Channels', [])
21
+ if isinstance(ch_list, np.ndarray):
22
+ ch_list = ch_list.tolist()
23
+ # strip whitespace
24
+ ch_list = [str(ch).strip() for ch in ch_list]
25
+ data_new['zoosystem'][sys]['Channels'] = ch_list
26
+
27
+ # Find default channels if none provided
28
+ if channels is None:
29
+ channels = []
30
+ for ch in data_new:
31
+ if ch == 'zoosystem':
32
+ continue
33
+ ch_data = data_new[ch]['line']
34
+ if ch_data.ndim == 2 and ch_data.shape[1] == 3:
35
+ channels.append(ch)
36
+
37
+ # Explode each channel
38
+ for ch in channels:
39
+ if ch not in data_new:
40
+ print('Warning: channel {} not found, skipping.'.format(ch))
41
+ continue
42
+
43
+ ch_data = data_new[ch]['line']
44
+ if ch_data.ndim != 2 or ch_data.shape[1] != 3:
45
+ print(f"Warning: channel '{ch}' 'line' is not n x 3 shape, skipping.")
46
+ continue
47
+
48
+ x, y, z = ch_data[:, 0], ch_data[:, 1], ch_data[:, 2]
49
+ for axis, line in zip(['_x', '_y', '_z'], [x, y, z]):
50
+ key = ch + axis
51
+ data_new[key] = {
52
+ 'line': line,
53
+ 'event': data_new[ch]['event']}
54
+
55
+ # Remove original channel
56
+ del data_new[ch]
57
+
58
+ # --- Update zoosystem lists ---
59
+ for sys in ['Video', 'Analog']:
60
+ if sys in data_new['zoosystem']:
61
+ ch_list = data_new['zoosystem'][sys]['Channels']
62
+ if ch in ch_list:
63
+ # Remove original channel
64
+ ch_list = [c for c in ch_list if c != ch]
65
+ # Add exploded channels
66
+ ch_list.extend([ch + '_x', ch + '_y', ch + '_z'])
67
+ data_new['zoosystem'][sys]['Channels'] = ch_list
68
+
69
+ return data_new
@@ -0,0 +1,46 @@
1
+ from biomechzoo.utils.findfield import findfield
2
+ import warnings
3
+ import copy
4
+ import numpy as np
5
+
6
+
7
+ def partition_data(data, evt_start, evt_end):
8
+ """ partition data for all channels between events evt_start and evt_end"""
9
+
10
+ # extract event values
11
+ e1, _ = findfield(data, evt_start)
12
+ e2, _ = findfield(data, evt_end)
13
+
14
+ if e1 is None or e2 is None or len(e1) == 0 or len(e2) == 0:
15
+ raise ValueError(f"Event not found: evt_start='{evt_start}' returned {e1}, evt_end='{evt_end}' returned {e2}")
16
+
17
+ # convert to int and get first value
18
+ e1 = int(e1[0])
19
+ e2 = int(e2[0])
20
+
21
+ data_new = copy.deepcopy(data)
22
+ for ch_name, ch_data in sorted(data_new.items()):
23
+ if ch_name != 'zoosystem':
24
+ r = ch_data['line']
25
+ try:
26
+ if r.ndim == 1:
27
+ data_new[ch_name]['line'] = r[e1:e2]
28
+ else:
29
+ data_new[ch_name]['line'] = r[e1:e2, :]
30
+ except (IndexError, ValueError) as e:
31
+ # IndexError: if e1[0]:e2[0] goes beyond the available indices
32
+ # ValueError: less likely, but may arise with shape mismatches
33
+ warnings.warn(f"Skipping {ch_name} due to error: {e}")
34
+
35
+ # partition events
36
+ events = ch_data['event']
37
+ for event_name, value in events.items():
38
+ original_frame = int(value[0])
39
+ if original_frame == 999:
40
+ continue # do not change outlier markers
41
+ else:
42
+ arr = np.array(data_new[ch_name]['event'][event_name], dtype=np.int32)
43
+ arr[0] = original_frame - e1
44
+ data_new[ch_name]['event'][event_name] = arr
45
+
46
+ return data_new
@@ -0,0 +1,46 @@
1
+ def removechannel_data(data, channels, mode='remove'):
2
+ """
3
+ File-level processing: Remove or keep specified channels in a single zoo dictionary.
4
+
5
+ Parameters:
6
+ - data (dict): Zoo data loaded from a file
7
+ - channels (list of str): List of channels to remove or keep
8
+ - mode (str): 'remove' or 'keep'
9
+
10
+ Returns:
11
+ - dict: Modified zoo dictionary with updated channels
12
+ """
13
+ if mode not in ['remove', 'keep']:
14
+ raise ValueError("mode must be 'remove' or 'keep'.")
15
+
16
+ all_channels = [ch for ch in data if ch != 'zoosystem']
17
+
18
+ # Check for missing channels
19
+ missing = [ch for ch in channels if ch not in all_channels]
20
+ if missing:
21
+ print('Warning: the following channels were not found {}'.format(missing))
22
+
23
+ if mode == 'remove':
24
+ keep_channels = [ch for ch in all_channels if ch not in channels]
25
+ elif mode == 'keep':
26
+ keep_channels = [ch for ch in all_channels if ch in channels]
27
+ else:
28
+ raise ValueError("Mode must be 'remove' or 'keep'.")
29
+
30
+ # --- Compute channels to remove ---
31
+ remove_channels = [ch for ch in all_channels if ch not in keep_channels]
32
+
33
+ if remove_channels:
34
+ print('Removing channels: {}'.format(remove_channels))
35
+ else:
36
+ print('No channels to remove')
37
+
38
+ # Remove from main data dict ---
39
+ for ch in remove_channels:
40
+ data.pop(ch, None)
41
+ if ch in data['zoosystem']['Video']['Channels']:
42
+ data['zoosystem']['Video']['Channels'] = [c for c in data['zoosystem']['Video']['Channels'] if c != ch]
43
+ if ch in data['zoosystem']['Analog']['Channels']:
44
+ data['zoosystem']['Analog']['Channels'] = [c for c in data['zoosystem']['Analog']['Channels'] if c != ch]
45
+
46
+ return data
@@ -0,0 +1,57 @@
1
+ import copy
2
+ import warnings
3
+ from biomechzoo.utils.findfield import findfield
4
+
5
+ def removeevent_data(data, events, mode='remove'):
6
+ """
7
+ Remove or keep specified events in all channels of a zoo dictionary.
8
+
9
+ Parameters
10
+ ----------
11
+ data : dict
12
+ Zoo data loaded from a file
13
+ events : list of str
14
+ Events to remove or keep
15
+ mode : str
16
+ 'remove' or 'keep'
17
+
18
+ Returns
19
+ -------
20
+ dict
21
+ Modified zoo dictionary with events removed or kept
22
+ """
23
+ if mode not in ['remove', 'keep']:
24
+ raise ValueError("mode must be 'remove' or 'keep'.")
25
+
26
+ if isinstance(events, str):
27
+ events = [events]
28
+
29
+ # check if any events are not present
30
+ valid_events = []
31
+ for evt in events:
32
+ e, _ = findfield(data, evt)
33
+ if e is None:
34
+ warnings.warn('Could not find event {} in zoo file, skipping'.format(evt))
35
+ else:
36
+ valid_events.append(evt)
37
+ events = valid_events
38
+
39
+ data_new = copy.deepcopy(data)
40
+ channels = sorted([ch for ch in data_new if ch != 'zoosystem'])
41
+ for ch in channels:
42
+ event_dict = data_new[ch].get('event', {})
43
+ events_to_remove = []
44
+
45
+ for evt in list(event_dict.keys()):
46
+ if mode == 'remove' and evt in events:
47
+ events_to_remove.append(evt)
48
+ elif mode == 'keep' and evt not in events:
49
+ events_to_remove.append(evt)
50
+
51
+ for evt in events_to_remove:
52
+ event_dict.pop(evt, None)
53
+ # print('Removed event "{}" from channel "{}"'.format(evt, ch))
54
+
55
+ data_new[ch]['event'] = event_dict
56
+
57
+ return data_new
@@ -0,0 +1,79 @@
1
+ import numpy as np
2
+
3
+
4
+ def renamechannel_data(data, ch_old_names, ch_new_names, section='Video'):
5
+ """
6
+ Rename channels in a zoo data.
7
+
8
+ Parameters
9
+ ----------
10
+ data : dict
11
+ Zoo file data.
12
+ ch_old_names : str or list
13
+ Name of the old channels.
14
+ ch_new_names : str or list
15
+ Name of the new channels.
16
+
17
+ section : str
18
+ Section of zoo data ('Video' or 'Analog').
19
+
20
+ Returns
21
+ -------
22
+ dict
23
+ Updated zoo data with new channel added.
24
+
25
+ Notes
26
+ -----
27
+ - If the channel already exists, it will be overwritten.
28
+ - Adds channel name to the list in data['zoosystem'][section]['Channels'].
29
+ """
30
+
31
+ for i, ch_old_name in enumerate(ch_old_names):
32
+ ch_new_name = ch_new_names[i]
33
+ # Warn if overwriting
34
+ if ch_new_name in data:
35
+ print('Warning: channel {} already exists, overwriting...'.format(ch_new_name))
36
+
37
+ # Assign new channel
38
+ data[ch_new_name] = {
39
+ 'line': data[ch_old_name]['line'],
40
+ 'event': data[ch_old_name]['event']
41
+ }
42
+
43
+ # remove old channel
44
+ data.pop(ch_old_name)
45
+
46
+ # Update channel list
47
+ ch_list = data['zoosystem'][section].get('Channels', [])
48
+
49
+ # If the channel list is a NumPy array, convert it to a list
50
+ if isinstance(ch_list, np.ndarray):
51
+ ch_list = ch_list.tolist()
52
+
53
+ # Ensure it's a flat list of strings
54
+ if isinstance(ch_list, list) and ch_new_name not in ch_list:
55
+ ch_list.append(ch_new_name)
56
+ data['zoosystem'][section]['Channels'] = ch_list
57
+
58
+ return data
59
+
60
+
61
+ if __name__ == '__main__':
62
+ # -------TESTING--------
63
+ import os
64
+ from src.biomechzoo.utils.zload import zload
65
+ current_dir = os.path.dirname(os.path.abspath(__file__))
66
+ project_root = os.path.dirname(current_dir)
67
+ fl = os.path.join(project_root, 'data', 'other', 'HC030A05.zoo')
68
+
69
+ # load zoo file
70
+ data = zload(fl)
71
+ ch_old_name = 'RKneeAngles'
72
+ ch_new_name = 'RightKneeAngles'
73
+ data = renamechannel_data(data, ch_old_name=ch_old_name, ch_new_name=ch_new_name)
74
+
75
+ if ch_old_name not in data:
76
+ print('RkneeAngles removed')
77
+ if ch_new_name in data:
78
+ print('RightKneeAngles added')
79
+
@@ -0,0 +1,62 @@
1
+ def renameevent_data(data, evt, nevt):
2
+ """
3
+ Rename events in the Zoo data structure.
4
+
5
+ Parameters
6
+ ----------
7
+ data : dict
8
+ The Zoo-formatted dictionary.
9
+ evt : str or list of str
10
+ Names of existing events to rename.
11
+ nevt : str or list of str
12
+ Names of new events to apply.
13
+
14
+ Returns
15
+ -------
16
+ data : dict
17
+ Updated Zoo data with renamed events.
18
+ """
19
+ # Convert to list if passed as single string
20
+ if isinstance(evt, str):
21
+ evt = [evt]
22
+ if isinstance(nevt, str):
23
+ nevt = [nevt]
24
+
25
+ if len(evt) != len(nevt):
26
+ raise ValueError("`evt` and `nevt` must have the same length.")
27
+
28
+ # Get all data channels except 'zoosystem'
29
+ channels = [ch for ch in data if ch != 'zoosystem']
30
+ for old_name, new_name in zip(evt, nevt):
31
+ for ch in channels:
32
+ events = data[ch].get('event', {})
33
+ if old_name in events:
34
+ data[ch]['event'][new_name] = events[old_name]
35
+ del data[ch]['event'][old_name]
36
+
37
+ return data
38
+
39
+
40
+ if __name__ == '__main__':
41
+ # -------TESTING--------
42
+ import os
43
+ from src.biomechzoo.utils.zload import zload
44
+ # get path to sample zoo file
45
+ current_dir = os.path.dirname(os.path.abspath(__file__))
46
+ project_root = os.path.dirname(current_dir)
47
+ fl = os.path.join(project_root, 'data', 'other', 'HC030A05.zoo')
48
+
49
+ # load zoo file
50
+ data = zload(fl)
51
+ evt = ['Left_FootStrike1', 'Left_FootStrike2', 'NonExistingEvent']
52
+
53
+ # see existing keys
54
+ missing = [k for k in evt if k not in data['SACR']['event']]
55
+ print("Missing keys:", missing) # expected behavior is missing 'NonExistingEvent'
56
+
57
+ nevt = ['LFS_1', 'LFS2', 'NE_1']
58
+ data = renameevent_data(data, evt=evt, nevt=nevt)
59
+
60
+ # after applying renameevent_data
61
+ missing = [k for k in nevt if k not in data['SACR']['event']]
62
+ print("Missing keys:", missing) # expected behavior is missing 'NE_1'
@@ -0,0 +1,40 @@
1
+ import copy
2
+ from biomechzoo.utils.findfield import findfield
3
+
4
+
5
+ def split_trial_data(data, start_event, end_event):
6
+ # todo check index problem compared to matlab start at 0 or 1
7
+ data_new = copy.deepcopy(data)
8
+
9
+ start_event_indx, _ = findfield(data_new, start_event)
10
+ end_event_indx, _ = findfield(data_new, end_event)
11
+
12
+ if start_event_indx is None:
13
+ raise ValueError('start_event {} not found'.format(start_event))
14
+
15
+ if end_event_indx is None:
16
+ raise ValueError('event_event {} not found'.format(end_event))
17
+
18
+ for key, value in data_new.items():
19
+ if key == 'zoosystem':
20
+ continue
21
+
22
+ # Slice the line data
23
+ trial_length = len(data_new[key]['line'])
24
+ if trial_length > end_event_indx[0]:
25
+ data_new[key]['line'] = value['line'][start_event_indx[0]:end_event_indx[0]+1]
26
+ else:
27
+ print('skipping split trial since event is outside range of data')
28
+ return None
29
+
30
+ # Update events if present
31
+ if 'event' in value:
32
+ new_events = {}
33
+ for evt_name, evt_val in value['event'].items():
34
+ event_frame = evt_val[0]
35
+ # Adjust index relative to new start
36
+ n = event_frame - start_event_indx[0]
37
+ new_events[evt_name] = [n, 0, 0]
38
+ data_new[key]['event'] = new_events
39
+
40
+ return data_new