Source code for biomechzoo.processing.explodechannel_data

import copy
import numpy as np
from typing import Dict, List, Optional, Any
from biomechzoo.utils.update_channel_list import update_channel_list

[docs] def explodechannel_data( data: Dict[str, Any], channels: Optional[List[str]] = None ) -> Dict[str, Any]: """ Explode 3D channels (n x 3 arrays) into separate X, Y, Z component channels. This function takes channels containing 3D data (e.g., position, angle, or force vectors) and splits them into three separate channels with '_x', '_y', and '_z' suffixes. Events from the original channel are preserved in the '_x' component only. Parameters ---------- data : dict of str to Any Biomechanical data dictionary loaded from a zoo file. channels : list of str, optional List of channel names to explode. If None, automatically explodes all channels with 'line' data shaped (n x 3). Returns ------- dict of str to Any Deep copy of input data with specified channels exploded into X, Y, Z components. Raises ------ ValueError If channel section (Video/Analog) cannot be determined. Notes ----- Original channel events are transferred only to the '_x' component channel. The '_y' and '_z' components will have empty event dictionaries. Channels that are not n x 3 shaped will be skipped with a warning message. """ data_new = copy.deepcopy(data) # Find default channels if none provided if channels is None: channels = [] for ch in data_new: if ch == 'zoosystem': continue ch_data = data_new[ch]['line'] if ch_data.ndim == 2 and ch_data.shape[1] == 3: channels.append(ch) # Explode each channel for ch in channels: if ch not in data_new: print('Warning: channel {} not found, skipping.'.format(ch)) continue # find section if ch in data_new['zoosystem']['Video']['Channels']: section = 'Video' elif ch in data_new['zoosystem']['Analog']['Channels']: section = 'Analog' else: raise ValueError('Unknown section for channel {}'.format(ch)) ch_data = data_new[ch]['line'] if ch_data.ndim != 2 or ch_data.shape[1] != 3: print(f"Warning: channel '{ch}' 'line' is not n x 3 shape, skipping.") continue # Add exploded channels x, y, z = ch_data[:, 0], ch_data[:, 1], ch_data[:, 2] for axis, line in zip(['_x', '_y', '_z'], [x, y, z]): key = ch + axis # Bring the old events to _x only if axis == '_x': edata = data_new[ch]['event'] else: edata = {} data_new[key] = { 'line': line, 'event': edata } # Update channel list and assign back data_new = update_channel_list(data_new, section=section, ch_add=key) # Remove original channel from list and dict data_new = update_channel_list(data_new, section=section, ch_remove=ch) data_new.pop(ch) return data_new
if __name__ == '__main__': # -------TESTING-------- import os from biomechzoo.utils.zload import zload current_dir = os.path.dirname(os.path.abspath(__file__)) project_root = os.path.dirname(os.path.dirname(os.path.dirname(current_dir))) fl = os.path.join(project_root, 'data', 'other', 'HC030A05.zoo') # load zoo file data = zload(fl) ch_old_name = 'RKneeAngles' ch_new_name = 'RightKneeAngles' data = explodechannel_data(data)