Source code for biomechzoo.processing.combine_files_data

import os
import re
import copy
import warnings

from biomechzoo.utils.engine import engine
from biomechzoo.utils.zload import zload
from biomechzoo.utils.fileparts import fileparts
from biomechzoo.processing.addchannel_data import addchannel_data
from biomechzoo.processing.renamechannel_data import renamechannel_data
from biomechzoo.utils.zsave import zsave


[docs] def combine_files_within(fld:str, suffix_map:list[str], name_contains:str | list[str], subfolders:str | list[str], inplace:bool, out_folder:str): """ Combines zoo-files within a subfolder into a single file This function operates on a root folder and automatically finds all the subdirectories. All channels withing the files within the folders will be combined into a single zoo-file. Parameters ---------- fld : str Path to the root folder containing all zoo-files suffix_map : list[str] List of names containing suffixes for channels --> must be matched to the file names name_contains : str or list of str Name of list of names that should be within the filepath subfolders : str of list of str Folder of list of folders that should be within the filepath inplace : bool out_folder : str Returns ------- None Notes ----- Automatically saves the combined file to the out-folder. """ # Get all base directories. all_files = engine(fld, extension="zoo", name_contains=name_contains, subfolders=subfolders) dirs = set() for f in all_files: dir_path = os.path.dirname(f) dirs.add(dir_path) for d in dirs: fl = engine(d, extension="zoo") data1 = zload(fl[0]) data_new = copy.deepcopy(data1) #Rename channels with the suffix of the first file. directory, filename, extension = fileparts(fl[0]) # find the suffix based on filename and rename the channel names s = [s for s in suffix_map if s in filename] suffix = ' '.join(s) ch_names = list(data_new.keys()) ch_names.remove("zoosystem") new_ch_names = [f"{ch}_{suffix}" for ch in ch_names if ch != "zoosystem"] data_new = renamechannel_data(data_new, ch_names, new_ch_names) # add all the data from the other files to data_new sections = ["Video", "Analog"] for f in fl[1:]: _, filename, _ = fileparts(f) # find the suffix based on filename s = [s for s in suffix_map if s in filename] suffix = ' '.join(s) data2 = zload(f) for section in sections: channels = data2["zoosystem"][section]["Channels"] for ch in channels: line_data = data2[ch]["line"] event_data = data2[ch]["event"] data_new = addchannel_data(data=data_new, ch_new_name= f"{ch}_{suffix}", ch_new_data=line_data, section=section) data_new[f"{ch}_{suffix}"]["event"] = event_data zsave(fl[0], data_new, inplace=inplace, out_folder=out_folder, root_folder=fld)
[docs] def combine_files_between(in_folder:str, fld1:str, fld2:str, suffix:str, name_contains:str | list[str], subfolders:str | list[str], method:str="down",inplace:bool=False, fl1exclude:list=None, fl2exclude:list=None, out_folder:str=None, strmatch:str=None,): """ Combines 2 zoo-files in different subfolders into a single file. This function operates on 2 folders that have the same root and automatically finds all the subdirectories. The function find the files to combine by matching the filename. Possible use case is combining data collected with different motion capture devices, e.g. IMUs and Vicon, Vicon and Force plates. Parameters ---------- in_folder : str Path to the root folder containing all zoo-files fld1 : str Path to the subfolder th be merged fld2 : str Path to the subfolder to be merged suffix : str Name containing suffix for the channels name_contains : str or list of str Name of list of names that should be within the filepath subfolders : str of list of str Folder of list of folders that should be within the filepath method: str determines if you want to upsample the signal with the lower frequency ("up"), if you want to downsample the signal with the highest frequency ('down'), or leave them the same 'none'. Default is down if frequencies are different. inplace: bool fl1exclude: str or list of str files names to ignore from fld1. Default is None. fl2exclude: str or list of str filenames to ignore from fld2. Default is None. strmatch: str The regular expression to find the common subject folder. out_folder : str Returns ------- None Notes ----- Automatically saves the combined file to the out-folder using the subdirectories of the first folder path. Filenames MUST have the exact same name. Currently files need to have the same file name in order to combine successfully e.g. #TODO: Allow to work without strmatch #TODO: find the files to exclude for fl1 and fl2 #TODO: Find the files that are shared between the two folders. #TODO: REWORK COMBINE TO INCLUDE RESAMPLING METHODS AND TO USE THE SELF INPUT """ fl1 = engine(fld1, extension="zoo", name_contains=name_contains, subfolders=subfolders) fl2= engine(fld2, extension="zoo", name_contains=name_contains, subfolders=subfolders) # set up framework for the first folder fname1 = [] dict1 = {} for f in fl1: match = re.search(strmatch, f) if match: if match[0] not in dict1.keys(): dict1.update({match[0]: {}}) directory, filename, extension = fileparts(f) fname1.append(filename + extension) dict1[match[0]].update({filename + extension: f}) # set up the framework for the second folder fname2 = [] dict2 = {} for f in fl2: match = re.search(strmatch, f) if match: if match[0] not in dict2.keys(): dict2.update({match[0]: {}}) directory, filename, extension = fileparts(f) fname2.append(filename + extension) dict2[match[0]].update({filename + extension: f}) # Find the match between framework 1 and framework 2 on the first (participant?) level lvl1 = [s for s in dict1.keys() if s in dict2.keys()] for key in lvl1: # Find common file names. lvl2 = [f for f in dict1[key].keys() if f in dict2[key].keys()] for l2 in lvl2: # load data f1 = dict1[key][l2] data1 = zload(f1) f2 = dict2[key][l2] data2 = zload(f2) # combining the data data_new = copy.deepcopy(data1) sections = ["Video", "Analog"] # Add all the video an analog files from data2 for section in sections: ch2 = data2["zoosystem"][section]["Channels"] freq1 = data1["zoosystem"][section]["Freq"] freq2 = data2["zoosystem"][section]["Freq"] if freq1 != freq2: warnings.warn("Frequencies do not match") # TODO: implement resample if ch2: for ch in ch2: line_data = data2[ch]["line"] event_data = data2[ch]["event"] data_new = addchannel_data(data=data_new, ch_new_name=f"{ch}_{suffix}", ch_new_data=line_data) data_new[f"{ch}_{suffix}"]["event"] = event_data zsave(f1, data_new, inplace=inplace, out_folder=out_folder, root_folder=in_folder)
if __name__ == '__main__': from biomechzoo.biomechzoo import BiomechZoo current_dir = os.path.dirname(os.path.abspath(__file__)) project_root = os.path.dirname(os.path.dirname(os.path.dirname(current_dir))) data_dir = os.path.join(project_root, 'data', 'sample_study') # test combine_files_between # create copy of normalized where channel names are changed bmech = BiomechZoo(os.path.join(data_dir, 'normalized')) ch_old = ['LeftAnklePower', 'LeftKneePower', 'LeftHipPower'] ch_new = ['LAnklePower', 'LKPower', 'LHipPower'] bmech.renamechannnel(ch=ch_old, ch_new=ch_new, out_folder='normalized_rename') bmech.removechannel(ch=ch_new, mode='keep', out_folder='normalized_rename_remove') bmech.combine_files(within=False, fld1=os.path.join(data_dir, 'normalized_rename_remove'), fld2=os.path.join(data_dir, 'normalized'), strmatch=r"HC\w+", )