From 96623b510a99d013027727bd18d0e759641fd5bd Mon Sep 17 00:00:00 2001 From: smoia Date: Fri, 6 Dec 2019 16:42:48 +0100 Subject: [PATCH 1/8] Expanded `utils.py` docstrings --- phys2bids/utils.py | 136 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 132 insertions(+), 4 deletions(-) diff --git a/phys2bids/utils.py b/phys2bids/utils.py index aac06d7ff..ab22dccc0 100644 --- a/phys2bids/utils.py +++ b/phys2bids/utils.py @@ -11,7 +11,18 @@ def check_input_dir(indir): """ - Checks that the given indir doesn't have a trailing '/' + Checks that the given indir doesn't have a trailing `/` + Possibly useless if better way to handle this in Python. + + Input + ----- + indir: str or path + A string or path that might (or not) end with a `/` + + Output + ------ + indir: str or path + Same as input, but surely without trailing `/` """ if indir[-1:] == '/': indir = indir[:-1] @@ -21,7 +32,22 @@ def check_input_dir(indir): def check_input_ext(filename, ext): """ - Checks that the given file has the given extension + Checks that the given file has the given extension. + It also treats composite extensions such as `.tsv.gz`, + common in BIDS formats. + + Input + ----- + filename: str or path + A string representing a file name or a fullpath + to a file + ext: str + Desired file name extension. Doesn't matter if preceded by `.` + + Output + ------ + Path(filename).with_suffix(ext): path + Path representing the input filename, but with corrected extension. """ if '.gz' in ext: if filename[-len(ext):] != ext: @@ -38,6 +64,30 @@ def check_input_type(filename, indir): """ Check which supported type is the filename. Alternatively, raise an error if file not found or type not supported. + + Input + ----- + filename: str or path + A string representing a file name or a fullpath + to a file + indir: str or path + A string representing a folder in which the file is, + or a fullpath to such folder + + Output + ------ + fname: str or path, same as input `filename` + Complete file name, might be the same or with an extension between + the supported ones + ftype: str + Extension of the file, if the extension is supported + and the file exists + + Outcome + ------- + raise Exception: + If the file doesn't exists or the extension is not supported, + it interrupts the program and return the issue. """ fftype_found = False for ftype in SUPPORTED_FTYPES: @@ -59,6 +109,17 @@ def check_input_type(filename, indir): def path_exists_or_make_it(fldr): """ Check if folder exists, if not make it + + Input + ----- + fldr: str or path + A string representing a folder, + or a fullpath to such folder + + Outcome + ------- + fldr: + Creates the fullpath to `fldr` if it doesn't exists. """ if not os.path.isdir(fldr): os.makedirs(fldr) @@ -67,6 +128,17 @@ def path_exists_or_make_it(fldr): def check_file_exists(filename): """ Check if file exists. + + Input + ----- + filename: str or path + A string representing a file name or a fullpath + to a file + + Outcome + ------- + raise FileNotFoundError: + If the file doesn't exists. """ if not os.path.isfile(filename) and filename is not None: raise FileNotFoundError(f'The file {filename} does not exist!') @@ -75,7 +147,21 @@ def check_file_exists(filename): def move_file(oldpath, newpath, ext=''): """ Moves file from oldpath to newpath. - If file already exists, remove it first. + If file already exists, removes it first. + + Input + ----- + oldpath: str or path + A string or a fullpath to a file that has to be moved + newpath: str or path + A string or a fullpath to the new destination of the file + ext: str + Possible extension to add to the oldpath and newpath. Not necessary. + + Outcome + ------- + newpath + ext: + Moves file to new destination """ check_file_exists(oldpath + ext) @@ -89,6 +175,20 @@ def copy_file(oldpath, newpath, ext=''): """ Copy file from oldpath to newpath. If file already exists, remove it first. + + Input + ----- + oldpath: str or path + A string or a fullpath to a file that has to be copied + newpath: str or path + A string or a fullpath to the new destination of the file + ext: str + Possible extension to add to the oldpath and newpath. Not necessary. + + Outcome + ------- + newpath + ext: + Copies file to new destination """ from shutil import copy as cp @@ -103,7 +203,22 @@ def copy_file(oldpath, newpath, ext=''): def writefile(filename, ext, text): """ Produces a textfile of the specified extension `ext`, - containing the given content `text` + containing the given content `text`. + + Input + ----- + filename: str or path + A string representing a file name or a fullpath + to a file + ext: str + Possible extension to add to the oldpath and newpath. Not necessary. + text: str + Text that has to be printed in `filename` + + Outcome + ------- + filename + ext: + Creates new file `filename.ext`. """ with open(filename + ext, 'w') as text_file: print(text, file=text_file) @@ -112,6 +227,19 @@ def writefile(filename, ext, text): def writejson(filename, data, **kwargs): """ Outputs a json file with the given data inside. + + Input + ----- + filename: str or path + A string representing a file name or a fullpath + to a file + data: dict + dictionary containing data to be printed in json. + + Outcome + ------- + filename: + Creates new file `filename.json`. """ if not filename.endswith('.json'): filename += '.json' From 9f2cf11ee8988ba7b050034343e20d3793805193 Mon Sep 17 00:00:00 2001 From: smoia Date: Fri, 6 Dec 2019 16:52:40 +0100 Subject: [PATCH 2/8] Expanded `viz.py` docstrings --- phys2bids/viz.py | 62 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/phys2bids/viz.py b/phys2bids/viz.py index e88204a78..27d339985 100644 --- a/phys2bids/viz.py +++ b/phys2bids/viz.py @@ -7,15 +7,69 @@ FIGSIZE = (18, 10) -def plot_channel(table, channel, filename, figsize=FIGSIZE, dpi=SET_DPI): +def plot_channel(table, channel, fileprefix, figsize=FIGSIZE, dpi=SET_DPI): + """ + Produces a textfile of the specified extension `ext`, + containing the given content `text`. + + Input + ----- + table: pandas dataframe + Dataframe containing channels + channel: str + name of the desired channel (`table` column) + fileprefix: str or path + A string representing a file name or a fullpath + to a file, WITHOUT extension + figsize: tuple + Desired size of the figure (see `matplotlib`), + Default is {FIGSIZE} + dpi: int + Desired DPI of the figure (see `matplotlib`), + Default is {SET_DPI} + + Outcome + ------- + fileprefix + '_' + channel + '_time.png': + Creates new plot `fileprefix_channel_time.png`. + """ + plt.figure(figsize=figsize, dpi=dpi) plt.title(channel) plt.plot(table.index.values, table[channel], '-') - plt.savefig(filename + '_' + channel + '_time.png', dpi=dpi) + plt.savefig(fileprefix + '_' + channel + '_time.png', dpi=dpi) plt.close() -def plot_trigger(time, trigger, outfile, options, figsize=FIGSIZE, dpi=SET_DPI): +def plot_trigger(time, trigger, fileprefix, options, figsize=FIGSIZE, dpi=SET_DPI): + """ + Produces a textfile of the specified extension `ext`, + containing the given content `text`. + + Input + ----- + time: numpy ndarray + time channel + trigger: numpy ndarray + trigger channel + fileprefix: str or path + A string representing a file name or a fullpath + to a file, WITHOUT extension + options: argparse object + The object produced by `get_parser` in `cli.run.py` + figsize: tuple + Desired size of the figure (see `matplotlib`), + Default is {FIGSIZE} + dpi: int + Desired DPI of the figure (see `matplotlib`), + Default is {SET_DPI} + + Outcome + ------- + fileprefix + _trigger_time.png: + Creates new plot `fileprefix_trigger_time.png`. + """ + def time2ntr(x): return x / options.tr @@ -39,5 +93,5 @@ def ntr2time(x): subplot.set_ylim([-0.2, options.thr * 3]) subplot.secondary_xaxis('top', functions=(time2ntr, ntr2time)) subplot.plot(time, trigger, '-', time, time, '-') - plt.savefig(outfile + '_trigger_time.png', dpi=dpi) + plt.savefig(fileprefix + '_trigger_time.png', dpi=dpi) plt.close() From 229aa6afae7933eb50664499626b8a951ee776e4 Mon Sep 17 00:00:00 2001 From: smoia Date: Fri, 3 Jan 2020 15:56:52 +0100 Subject: [PATCH 3/8] Docstring now stylised as Numpydocs. Corrected some linter warnings. --- phys2bids/cli/run.py | 9 +- phys2bids/interfaces/acq.py | 17 +++- phys2bids/interfaces/txt.py | 51 ++++++----- phys2bids/phys2bids.py | 30 ++++--- phys2bids/physio_obj.py | 169 ++++++++++++++++++------------------ phys2bids/utils.py | 85 +++++++++--------- phys2bids/viz.py | 18 ++-- 7 files changed, 209 insertions(+), 170 deletions(-) diff --git a/phys2bids/cli/run.py b/phys2bids/cli/run.py index 475e327f5..af462feaf 100644 --- a/phys2bids/cli/run.py +++ b/phys2bids/cli/run.py @@ -1,4 +1,7 @@ # -*- coding: utf-8 -*- +""" +Parser for phys2bids +""" import argparse @@ -13,10 +16,12 @@ def _get_parser(): ------- parser.parse_args() : argparse dict - """ - parser = argparse.ArgumentParser() + Notes + ----- # Argument parser follow template provided by RalphyZ. # https://stackoverflow.com/a/43456577 + """ + parser = argparse.ArgumentParser() optional = parser._action_groups.pop() required = parser.add_argument_group('Required Argument:') required.add_argument('-in', '--input-file', diff --git a/phys2bids/interfaces/acq.py b/phys2bids/interfaces/acq.py index d3554b6e3..0ceb51845 100644 --- a/phys2bids/interfaces/acq.py +++ b/phys2bids/interfaces/acq.py @@ -11,7 +11,22 @@ def populate_phys_input(filename, chtrig): """ - Populate object phys_input + Populate object phys_input from acq files. + + Parameters + ---------- + filename: str + path to the txt labchart file + chtrig : int + index of trigger channel + + Returns + ------- + BlueprintInput + + See Also + -------- + physio_obj.BlueprintInput """ data = read_file(filename).channels diff --git a/phys2bids/interfaces/txt.py b/phys2bids/interfaces/txt.py index 8fe8f9811..634527525 100644 --- a/phys2bids/interfaces/txt.py +++ b/phys2bids/interfaces/txt.py @@ -12,41 +12,44 @@ def populate_phys_input(filename, chtrig): """ Populate object phys_input for now this works only with labchart files - Input (Properties) - ------------------ - filename: str + + Parameters + ---------- + filename: str path to the txt labchart file chtrig : int index of trigger channel - Output - ------------------ - BlueprintInput object for more see BlueprintInput docs - """ + Returns + ------- + BlueprintInput + See Also + -------- + physio_obj.BlueprintInput + """ header = [] channel_list = [] - with open(filename,'r') as f: - header_l = 0 + with open(filename, 'r') as f: for line in f: - line=line.rstrip('\n').split('\t') - try: + line = line.rstrip('\n').split('\t') + try: float(line[0]) except ValueError: header.append(line) - continue + continue line = [float(i) for i in line] channel_list.append(line) - # get frequency + # get frequency interval = header[0][1].split(" ") - if interval[-1] not in ['hr', 'min', 's','ms','µs']: - raise AttributeError(f'Interval unit "{interval[-1]}" is not in a valid LabChart time unit, ' - 'this probably means your file is not in labchart format') + if interval[-1] not in ['hr', 'min', 's', 'ms', 'µs']: + raise AttributeError(f'Interval unit "{interval[-1]}" is not in a valid LabChart time unit,' + ' this probably means your file is not in labchart format') if interval[-1] != 's': print('Interval is not in seconds. Converting its value.') if interval[-1] == 'hr': - interval[0] = float(interval)[0]*3600 + interval[0] = float(interval[0])*3600 interval[-1] = 's' elif interval[-1] == 'min': interval[0] = float(interval[0])*60 @@ -65,16 +68,16 @@ def populate_phys_input(filename, chtrig): for item in range_list: units.append(item.split(' ')[1]) # get names - orig_names=header[4][1:] - names = ['time','trigger'] + orig_names = header[4][1:] + names = ['time', 'trigger'] orig_names.pop(chtrig) - names=names+orig_names - # get channels + names = names+orig_names + # get channels timeseries = np.matrix(channel_list).T.tolist() freq = [1/interval[0]]*len(timeseries) - timeseries=[np.array(darray) for darray in timeseries] - ordered_timeseries=[timeseries[0],timeseries[chtrig]] + timeseries = [np.array(darray) for darray in timeseries] + ordered_timeseries = [timeseries[0], timeseries[chtrig]] timeseries.pop(chtrig) timeseries.pop(0) - ordered_timeseries=ordered_timeseries+timeseries + ordered_timeseries = ordered_timeseries + timeseries return BlueprintInput(ordered_timeseries, freq, names, units) diff --git a/phys2bids/phys2bids.py b/phys2bids/phys2bids.py index 0f60ad4ef..5f5693bd0 100644 --- a/phys2bids/phys2bids.py +++ b/phys2bids/phys2bids.py @@ -43,8 +43,8 @@ def print_summary(filename, ntp_expected, ntp_found, samp_freq, time_offset, out """ Prints a summary onscreen and in file with informations on the files. - Input - ----- + Parameters + ---------- filename: str Name of the input of phys2bids. ntp_expected: int @@ -58,8 +58,9 @@ def print_summary(filename, ntp_expected, ntp_found, samp_freq, time_offset, out outfile: str or path Fullpath to output file. - Outcome - ------- + Notes + ----- + Outcome: summary: str Prints the summary on screen outfile: .log file @@ -83,8 +84,8 @@ def print_json(outfile, samp_freq, time_offset, ch_name): """ Prints the json required by BIDS format. - Input - ----- + Parameters + ---------- outfile: str or path Fullpath to output file. samp_freq: float @@ -94,9 +95,9 @@ def print_json(outfile, samp_freq, time_offset, ch_name): ch_name: list of str List of channel names, as specified by BIDS format. - Outcome - ------- - + Notes + ----- + Outcome: outfile: .json file File containing information for BIDS. """ @@ -113,8 +114,8 @@ def use_heuristic(heur_file, sub, ses, filename, outdir, record_label=''): Import the heuristic file specified by the user and uses its output to rename the file. - Input - ----- + Parameters + ---------- heur_file: path Fullpath to heuristic file. sub: str or int @@ -129,7 +130,7 @@ def use_heuristic(heur_file, sub, ses, filename, outdir, record_label=''): record_label: str Optional label for the "record" entry of BIDS. - Output + Returns ------- heurpath: str or path Returned fullpath to tsv.gz new file (post BIDS formatting). @@ -180,6 +181,11 @@ def _main(argv=None): Otherwise, it operates on the input to return a .tsv.gz file, possibily in BIDS format. + Raises + ------ + NotImplementedError + If the file extension is not supported yet. + """ options = _get_parser().parse_args(argv) # Check options to make them internally coherent diff --git a/phys2bids/physio_obj.py b/phys2bids/physio_obj.py index b26775e51..8e06cd52c 100644 --- a/phys2bids/physio_obj.py +++ b/phys2bids/physio_obj.py @@ -13,8 +13,9 @@ def is_valid(var, var_type, list_type=None): Checks that the var is of a certain type. If type is list and list_type is specified, checks that the list contains list_type. - Input - ----- + + Parameters + ---------- var: any type Variable to be checked. var_type: type @@ -22,10 +23,15 @@ def is_valid(var, var_type, list_type=None): list_type: type Like var_type, but applies to list elements. - Output - ------ + Returns + ------- var: any type Variable to be checked (same as input). + + Raises + ------ + AttributeError + If var is not of var_type """ if not isinstance(var, var_type): raise AttributeError(f'The given variable is not a {var_type}') @@ -41,8 +47,9 @@ def has_size(var, data_size, token): """ Checks that the var has the same dimension of the data If it's not the case, fill in the var or removes exceding var entry. - Input - ----- + + Parameters + ---------- var: list Variable to be checked. data_size: int @@ -52,8 +59,8 @@ def has_size(var, data_size, token): it will be padded at the end with this `token`. It has to be the same type as var. - Output - ------ + Returns + ------- var: list Variable to be checked (same as input). """ @@ -74,8 +81,8 @@ class BlueprintInput(): !!! Pay attention: there's rules on how to populate this object. See below ("Attention") !!! - Input (Properties) - ------------------ + Attributes + ---------- timeseries : (ch, [tps]) list List of numpy 1d arrays - one for channel, plus one for time. Time channel has to be the first, trigger the second. @@ -90,17 +97,11 @@ class BlueprintInput(): in the output files. units : (ch) list of strings List of the units of the channels. - - Properties - ---------- ch_amount: int - Number of channels (ch). - - Optional properties - ------------------- + Number of channels (ch). This is computed internally. num_timepoints_found: int - Amount of timepoints found in the automatic count, - *if* check_trigger_amount() is run + Amount of timepoints found in the automatic count. + This is computed internally, *if* check_trigger_amount() is run Methods ------- @@ -116,8 +117,8 @@ class BlueprintInput(): Counts the amounts of triggers and corrects time offset in "time" ndarray. Also adds property ch_amount. - Attention - --------- + Notes + ----- The timeseries (and as a consequence, all the other properties) should start with an entry for time and an entry for trigger. Both should have the same length - hence same sampling. Meaning: @@ -146,18 +147,17 @@ def rename_channels(self, new_names, ch_trigger=None): Renames the channels. If 'time' or 'trigger' were specified, it makes sure that they're the first and second entry. - Input - ----- - self: :obj: `BlueprintInput` - The object on which to operate + Parameters + ---------- new_names: list of str New names for channels. ch_trigger: Number of the channel containing the trigger. - Outcome - ------- - self.ch_name: + Notes + ----- + Outcome: + self.ch_name: list of str Changes content to new_name. """ if 'time' in new_names: @@ -178,15 +178,13 @@ def return_index(self, idx): Returns the proper list entry of all the properties of the object, given an index. - Input - ----- - self: :obj: `BlueprintInput` - The object on which to operate + Parameters + ---------- idx: int Index of elements to return - Output - ------ + Returns + ------- out: tuple Tuple containing the proper list entry of all the properties of the object with index `idx` @@ -199,23 +197,30 @@ def delete_at_index(self, idx): Returns all the proper list entry of the properties of the object, given an index. - Input - ----- - self: :obj: `BlueprintInput` - The object on which to operate + Parameters + ---------- idx: int or range Index of elements to delete from all lists - Outcome - ------- - self: + Notes + ----- + Outcome: + self.timeseries: + Removes element at index idx + self.freq: + Removes element at index idx + self.ch_name: + Removes element at index idx + self.units: + Removes element at index idx + self.ch_amount: In all the property that are lists, the element correspondent to `idx` gets deleted - """ - del(self.timeseries[idx]) - del(self.freq[idx]) - del(self.ch_name[idx]) - del(self.units[idx]) + """ + del self.timeseries[idx] + del self.freq[idx] + del self.ch_name[idx] + del self.units[idx] self.ch_amount -= 1 def check_trigger_amount(self, thr=2.5, num_timepoints_expected=0, tr=0): @@ -223,10 +228,8 @@ def check_trigger_amount(self, thr=2.5, num_timepoints_expected=0, tr=0): Counts trigger points and corrects time offset in the list representing time. - Input - ----- - self: :obj: `BlueprintInput` - The object on which to operate + Parameters + ---------- thr: float Threshold to be used to detect trigger points. Default is 2.5 @@ -235,15 +238,13 @@ def check_trigger_amount(self, thr=2.5, num_timepoints_expected=0, tr=0): tr: float The Repetition Time of the fMRI data. - Output - ------ + Notes + ----- + Outcome: self.num_timepoints_found: int Property of the `BlueprintInput` class. Contains the number of timepoints found with the automatic estimation. - - Outcome - ------- self.timeseries: The property `timeseries` is shifted with the 0 being the time of first trigger. @@ -293,15 +294,14 @@ def print_info(self, filename): """ Print info on the file, channel by channel. - Input - ----- - self: :obj: `BlueprintInput` - The object on which to operate + Parameters + ---------- filename: str or path Name of the input file to phys2bids - Outcome - ------- + Notes + ----- + Outcome: ch: Returns to stdout (e.g. on screen) channels, their names and their sampling rate. @@ -318,8 +318,8 @@ class BlueprintOutput(): Main output object for phys2bids. Contains the blueprint to be exported. - Properties - Input - ------------------ + Attributes + ---------- timeseries : (ch x tps) :obj:`numpy.ndarray` Numpy 2d array of timeseries Contains all the timeseries recorded. @@ -360,15 +360,13 @@ def return_index(self, idx): Returns all the proper list entry of the properties of the object, given an index. - Input - ----- - self: :obj: `BlueprintOutput` - The object on which to operate + Parameters + ---------- idx: int Index of elements to return - Output - ------ + Returns + ------- out: tuple Tuple containing the proper list entry of all the properties of the object with index `idx` @@ -381,38 +379,43 @@ def delete_at_index(self, idx): Returns all the proper list entry of the properties of the object, given an index. - Input - ----- - self: :obj: `BlueprintOutput` - The object on which to operate + Parameters + ---------- idx: int or range Index of elements to delete from all lists - Outcome - ------- - self: + Notes + ----- + Outcome: + self.timeseries: + Removes element at index idx + self.ch_name: + Removes element at index idx + self.units: + Removes element at index idx + self.ch_amount: In all the property that are lists, the element correspondent to `idx` gets deleted """ - del(self.timeseries[idx]) - del(self.ch_name[idx]) - del(self.units[idx]) + del self.timeseries[idx] + del self.ch_name[idx] + del self.units[idx] @classmethod def init_from_blueprint(cls, blueprint): """ Method to populate the output blueprint using BlueprintInput. - Input - ----- + Parameters + ---------- cls: :obj: `BlueprintOutput` The object on which to operate blueprint: :obj: `BlueprintInput` The input blueprint object. !!! All its frequencies should be the same !!! - Output - ------ + Returns + ------- cls: :obj: `BlueprintOutput` Populated `BlueprintOutput` object. """ diff --git a/phys2bids/utils.py b/phys2bids/utils.py index ab22dccc0..44ef04d8f 100644 --- a/phys2bids/utils.py +++ b/phys2bids/utils.py @@ -14,13 +14,13 @@ def check_input_dir(indir): Checks that the given indir doesn't have a trailing `/` Possibly useless if better way to handle this in Python. - Input - ----- + Parameters + ---------- indir: str or path A string or path that might (or not) end with a `/` - Output - ------ + Returns + ------- indir: str or path Same as input, but surely without trailing `/` """ @@ -36,16 +36,16 @@ def check_input_ext(filename, ext): It also treats composite extensions such as `.tsv.gz`, common in BIDS formats. - Input - ----- + Parameters + ---------- filename: str or path A string representing a file name or a fullpath to a file ext: str Desired file name extension. Doesn't matter if preceded by `.` - Output - ------ + Returns + ------- Path(filename).with_suffix(ext): path Path representing the input filename, but with corrected extension. """ @@ -65,8 +65,8 @@ def check_input_type(filename, indir): Check which supported type is the filename. Alternatively, raise an error if file not found or type not supported. - Input - ----- + Parameters + ---------- filename: str or path A string representing a file name or a fullpath to a file @@ -74,8 +74,8 @@ def check_input_type(filename, indir): A string representing a folder in which the file is, or a fullpath to such folder - Output - ------ + Returns + ------- fname: str or path, same as input `filename` Complete file name, might be the same or with an extension between the supported ones @@ -83,9 +83,9 @@ def check_input_type(filename, indir): Extension of the file, if the extension is supported and the file exists - Outcome - ------- - raise Exception: + Raises + ------ + Exception If the file doesn't exists or the extension is not supported, it interrupts the program and return the issue. """ @@ -110,14 +110,15 @@ def path_exists_or_make_it(fldr): """ Check if folder exists, if not make it - Input - ----- + Parameters + ---------- fldr: str or path A string representing a folder, or a fullpath to such folder - Outcome - ------- + Notes + ----- + Outcome: fldr: Creates the fullpath to `fldr` if it doesn't exists. """ @@ -129,15 +130,15 @@ def check_file_exists(filename): """ Check if file exists. - Input - ----- + Parameters + ---------- filename: str or path A string representing a file name or a fullpath to a file - Outcome - ------- - raise FileNotFoundError: + Raises + ------ + FileNotFoundError If the file doesn't exists. """ if not os.path.isfile(filename) and filename is not None: @@ -149,8 +150,8 @@ def move_file(oldpath, newpath, ext=''): Moves file from oldpath to newpath. If file already exists, removes it first. - Input - ----- + Parameters + ---------- oldpath: str or path A string or a fullpath to a file that has to be moved newpath: str or path @@ -158,8 +159,9 @@ def move_file(oldpath, newpath, ext=''): ext: str Possible extension to add to the oldpath and newpath. Not necessary. - Outcome - ------- + Notes + ----- + Outcome: newpath + ext: Moves file to new destination """ @@ -176,8 +178,8 @@ def copy_file(oldpath, newpath, ext=''): Copy file from oldpath to newpath. If file already exists, remove it first. - Input - ----- + Parameters + ---------- oldpath: str or path A string or a fullpath to a file that has to be copied newpath: str or path @@ -185,8 +187,9 @@ def copy_file(oldpath, newpath, ext=''): ext: str Possible extension to add to the oldpath and newpath. Not necessary. - Outcome - ------- + Notes + ----- + Outcome: newpath + ext: Copies file to new destination """ @@ -205,8 +208,8 @@ def writefile(filename, ext, text): Produces a textfile of the specified extension `ext`, containing the given content `text`. - Input - ----- + Parameters + ---------- filename: str or path A string representing a file name or a fullpath to a file @@ -215,8 +218,9 @@ def writefile(filename, ext, text): text: str Text that has to be printed in `filename` - Outcome - ------- + Notes + ----- + Outcome: filename + ext: Creates new file `filename.ext`. """ @@ -228,16 +232,17 @@ def writejson(filename, data, **kwargs): """ Outputs a json file with the given data inside. - Input - ----- + Parameters + ---------- filename: str or path A string representing a file name or a fullpath to a file data: dict dictionary containing data to be printed in json. - Outcome - ------- + Notes + ----- + Outcome: filename: Creates new file `filename.json`. """ diff --git a/phys2bids/viz.py b/phys2bids/viz.py index 27d339985..8f022a79e 100644 --- a/phys2bids/viz.py +++ b/phys2bids/viz.py @@ -12,8 +12,8 @@ def plot_channel(table, channel, fileprefix, figsize=FIGSIZE, dpi=SET_DPI): Produces a textfile of the specified extension `ext`, containing the given content `text`. - Input - ----- + Parameters + ---------- table: pandas dataframe Dataframe containing channels channel: str @@ -28,8 +28,9 @@ def plot_channel(table, channel, fileprefix, figsize=FIGSIZE, dpi=SET_DPI): Desired DPI of the figure (see `matplotlib`), Default is {SET_DPI} - Outcome - ------- + Notes + ----- + Outcome: fileprefix + '_' + channel + '_time.png': Creates new plot `fileprefix_channel_time.png`. """ @@ -46,8 +47,8 @@ def plot_trigger(time, trigger, fileprefix, options, figsize=FIGSIZE, dpi=SET_DP Produces a textfile of the specified extension `ext`, containing the given content `text`. - Input - ----- + Parameters + ---------- time: numpy ndarray time channel trigger: numpy ndarray @@ -64,8 +65,9 @@ def plot_trigger(time, trigger, fileprefix, options, figsize=FIGSIZE, dpi=SET_DP Desired DPI of the figure (see `matplotlib`), Default is {SET_DPI} - Outcome - ------- + Notes + ----- + Outcome: fileprefix + _trigger_time.png: Creates new plot `fileprefix_trigger_time.png`. """ From f27a77756ebfa1156cd769ef5a8a2423c344b99e Mon Sep 17 00:00:00 2001 From: smoia Date: Fri, 3 Jan 2020 16:08:18 +0100 Subject: [PATCH 4/8] Corrected linters and docstrings after merge --- phys2bids/physio_obj.py | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/phys2bids/physio_obj.py b/phys2bids/physio_obj.py index 5a5181688..7231ed460 100644 --- a/phys2bids/physio_obj.py +++ b/phys2bids/physio_obj.py @@ -97,14 +97,14 @@ class BlueprintInput(): in the output files. units : (ch) list of strings List of the units of the channels. - ch_amount: int - Number of channels (ch). This is computed internally. num_timepoints_found: int Amount of timepoints found in the automatic count. This is computed internally, *if* check_trigger_amount() is run Methods ------- + ch_amount: + Property. Returns number of channels (ch). rename_channels: Changes the list "ch_name" in a controlled way. return_index: @@ -143,6 +143,14 @@ def __init__(self, timeseries, freq, ch_name, units): @property def ch_amount(self): + """ + Property. Returns number of channels (ch). + + Returns + ------- + int + Number of channels + """ return len(self.timeseries) def rename_channels(self, new_names, ch_trigger=None): @@ -164,12 +172,12 @@ def rename_channels(self, new_names, ch_trigger=None): Changes content to new_name. """ if 'time' in new_names: - del(new_names[new_names.index('time')]) + del new_names[new_names.index('time')] if 'trigger' in new_names: - del(new_names[new_names.index('trigger')]) + del new_names[new_names.index('trigger')] elif ch_trigger: - del(new_names[ch_trigger]) + del new_names[ch_trigger] new_names = ['time', 'trigger'] + new_names @@ -224,7 +232,6 @@ def delete_at_index(self, idx): del self.freq[idx] del self.ch_name[idx] del self.units[idx] - self.ch_amount -= 1 def check_trigger_amount(self, thr=2.5, num_timepoints_expected=0, tr=0): """ @@ -341,6 +348,8 @@ class BlueprintOutput(): Methods ------- + ch_amount: + Property. Returns number of channels (ch). return_index: Returns the proper list entry of all the properties of the object, given an index. @@ -359,6 +368,14 @@ def __init__(self, timeseries, freq, ch_name, units, start_time): @property def ch_amount(self): + """ + Property. Returns number of channels (ch). + + Returns + ------- + int + Number of channels + """ return len(self.timeseries) def return_index(self, idx): @@ -404,8 +421,8 @@ def delete_at_index(self, idx): `idx` gets deleted """ self.timeseries = np.delete(self.timeseries, idx, axis=0) - del(self.ch_name[idx]) - del(self.units[idx]) + del self.ch_name[idx] + del self.units[idx] @classmethod def init_from_blueprint(cls, blueprint): From 12f0f7175ce8e84f07b074acbbde3307ac41a5de Mon Sep 17 00:00:00 2001 From: Stefano Moia Date: Mon, 27 Jan 2020 12:55:13 +0100 Subject: [PATCH 5/8] Update setup.cfg --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index f21509c16..b562eda33 100644 --- a/setup.cfg +++ b/setup.cfg @@ -6,7 +6,7 @@ author = phys2bids developers maintainer = Stefano Moia maintainer_email = s.moia@bcbl.eu classifiers = - Development Status :: 3 - Alpha + Development Status :: 4 - Beta Intended Audience :: Science/Research License :: OSI Approved :: Apache Software License Programming Language :: Python :: 3.6 From b6996fb2a913c6875c2842df52488440a8d2c4f4 Mon Sep 17 00:00:00 2001 From: smoia Date: Mon, 27 Jan 2020 13:11:35 +0100 Subject: [PATCH 6/8] Refactor use_heuristics for strings and paths --- phys2bids/phys2bids.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/phys2bids/phys2bids.py b/phys2bids/phys2bids.py index 52a100776..25bcea7e5 100644 --- a/phys2bids/phys2bids.py +++ b/phys2bids/phys2bids.py @@ -137,21 +137,20 @@ def use_heuristic(heur_file, sub, ses, filename, outdir, record_label=''): """ if sub[:4] != 'sub-': - name = 'sub-' + sub + name = f'sub-{sub}' else: name = sub - fldr = outdir + '/' + name + fldr = os.path.join(outdir, name) if ses: if ses[:4] != 'ses-': - fldr = fldr + '/ses-' + ses - name = name + '_ses-' + ses - else: - fldr = fldr + '/' + ses - name = name + ses + ses = f'ses-{ses}' - fldr = fldr + '/func' + fldr = os.path.join(fldr, ses) + name = f'{name}{ses}' + + fldr = os.path.join(fldr, 'func') utils.path_exists_or_make_it(fldr) cwd = os.getcwd() @@ -164,7 +163,7 @@ def use_heuristic(heur_file, sub, ses, filename, outdir, record_label=''): if record_label: recording = f'_recording-{record_label}' - heurpath = fldr + '/' + name + recording + '_physio' + heurpath = os.path.join(fldr, f'{name}{recording}_physio') # for ext in ['.tsv.gz', '.json', '.log']: # move_file(outfile, heurpath, ext) os.chdir(cwd) From 21d7fe65283a812277aa6127821ed1e5f63cdfea Mon Sep 17 00:00:00 2001 From: smoia Date: Mon, 27 Jan 2020 13:17:02 +0100 Subject: [PATCH 7/8] linter fix --- phys2bids/interfaces/txt.py | 1 + 1 file changed, 1 insertion(+) diff --git a/phys2bids/interfaces/txt.py b/phys2bids/interfaces/txt.py index ae0851673..90965ae00 100644 --- a/phys2bids/interfaces/txt.py +++ b/phys2bids/interfaces/txt.py @@ -8,6 +8,7 @@ import numpy as np from phys2bids.physio_obj import BlueprintInput + def populate_phys_input(filename, chtrig): """ Populate object phys_input From 8aebff2d8d8e72a79a60b664674e8df266068191 Mon Sep 17 00:00:00 2001 From: smoia Date: Mon, 27 Jan 2020 14:04:10 +0100 Subject: [PATCH 8/8] fix naming --- phys2bids/phys2bids.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phys2bids/phys2bids.py b/phys2bids/phys2bids.py index 25bcea7e5..01b3abaaf 100644 --- a/phys2bids/phys2bids.py +++ b/phys2bids/phys2bids.py @@ -148,7 +148,7 @@ def use_heuristic(heur_file, sub, ses, filename, outdir, record_label=''): ses = f'ses-{ses}' fldr = os.path.join(fldr, ses) - name = f'{name}{ses}' + name = f'{name}_{ses}' fldr = os.path.join(fldr, 'func') utils.path_exists_or_make_it(fldr)