def _check_annotatechannelfunc_params(annotate_params, function): """Check channel annotation (view, write, read) function parameters and output user-friendly text.""" bids_root = Path(_get_bidsroot_path()) subject_id = annotate_params["subject_id"] session_id = annotate_params["session_id"] acquisition_id = annotate_params["acquisition_id"] subject_ids = [ os.path.basename(x).split("-")[-1] for x in bids_root.glob("*") if x.is_dir() if "sub" in x.as_posix() ] if subject_id not in subject_ids: message_str = (f"Subject {subject_id} you passed in " f"is not a valid subject in your subject pool. " f"Here are the current subjects {subject_ids}.") error_msg = f"ez {function}: Subject {subject_id} is not a valid subject" logger.error(error_msg) counted("CLI_exceptions") raise CLI_Input_Error(message_str) if function is not "view_bad_chs": chs = annotate_params["chs"] if chs is None: logger.error(f"ez {function}: Must pass in channels to annotate.") counted("CLI_exceptions") raise CLI_Input_Error( f"ez {function}: Must pass in channels to annotate.")
def print_channel_status(bids_root, subject_id, session_id, acquisition_id): """ Print the channel and status of every channel for a certain acquisition type. Parameters ---------- bids_root : Union[Path or str] The directory where data is being stored. subject_id : str The unique identifier of the subject session_id: str The identifier of the recording session, usually 'seizure' or 'interictal' acquisition_id : str One of 'eeg', 'ecog', or 'seeg' """ channel_fpaths = _get_subject_channels_tsvs( bids_root, subject_id, session_id, acquisition_id ) logger.info(f"Found channel files for subject {subject_id}: {channel_fpaths}") if len(channel_fpaths) == 0: logger.error(f"No channel files for subject: {subject_id}") raise RuntimeError(f"No channel files for subject: {subject_id}.") channel_fpath = channel_fpaths[0] logger.info(f"Using channel file '{channel_fpath}'") # Read in current channel statuses channel_tsv = _from_tsv(channel_fpath) bad_chs = [] good_chs = [] for i, ch in enumerate(channel_tsv["name"]): if channel_tsv["status"][i] == "bad": bad_chs.append(ch) else: good_chs.append(ch) # create string of channels to display to user if len(bad_chs) == 0: bad_channels_str = "None" else: bad_channels_str = ", ".join(bad_chs) if len(bad_chs) == 0: good_channels_str = "None" else: good_channels_str = ", ".join(good_chs) click.echo(f"Bad channels for {subject_id}:") click.echo(bad_channels_str) click.echo(f"Channels included in analysis for {subject_id}:") click.echo(good_channels_str)
def _check_metadatafunc_params(run_params, function): """Checks metadata or pat-summary function parameters and outputs user-friendly text.""" # subject_ids = layout.get_subjects() # faster using os.glob if too many subjects bids_root = Path(_get_bidsroot_path()) # Get subject_id from dict subject_id = run_params["subject_id"] # subject_id of None is allowed for these commands if subject_id is None: pass # if not none, check if a valid subject subject_ids = [ os.path.basename(x).split("-")[-1] for x in bids_root.glob("*") if x.is_dir() if "sub" in x.as_posix() ] if subject_id not in subject_ids and subject_id is not "all": message_str = (f"Subject {subject_id} you passed in " f"is not a valid subject in your subject pool. " f"Here are the current subjects {subject_ids}.") error_msg = f"ez {function}: Subject {subject_id} is not a valid subject" logger.error(error_msg) counted("CLI_exceptions") raise CLI_Input_Error(message_str)
def _check_types(df, col, key, ineq): if df.dtypes[col] == "int64": try: if ineq == ">": boolmeta = df[col] > int(key) elif ineq == "<": boolmeta = df[col] < int(key) else: boolmeta = df[col] == int(key) return boolmeta except ValueError as ex: logger.error(f"Column {col} has type int, but {key} was passed") counted("CLI_exception") raise CLI_Input_Error( f"Column {col} has type int. Please pass in a valid int") elif df.dtypes[col] is "datetime": try: if ineq == ">": boolmeta = df[col] > datetime.strptime(key, format="%m/%d/%Y") elif ineq == "<": boolmeta = df[col] < datetime.strptime(key, format="%m/%d/%Y") else: boolmeta = df[col] == datetime.strptime(key, format="%m/%d/%Y") return boolmeta except ValueError as ex: logger.error( f"Column {col} has type datetime with format mm/dd/YYYY, but {key} was passed" ) counted("CLI_exception") raise CLI_Input_Error( f"Column {col} has type datetime. Please pass in a valid datetime with format" f"mm/dd/YYYY") else: # otherwise it is a str if ineq == "<" or ineq == ">": logger.error(f"Cannot compare {ineq} for type str") counted("CLI_exception") raise CLI_Input_Error(f"Cannot compare {ineq} for type str") else: boolmeta = df[col] == key return boolmeta
def filter_metadata(participants_df, toggle_options): """Filter metadata dataframe to rows with subjects meeting requirements.""" cols = [] bools = [] keys = [] toggle_count = 0 # If there are filters, otherwise just returns the original dataframe for opt in toggle_options: toggle_count += 1 # Remove any spaces the user may have enter opt = opt.replace(" ", "") # Check for equality option (i.e. sex = M) equals = opt.split("=") # If len == 2, then it was an equality if len(equals) == 2: col = equals[0] key = equals[1] cols.append(col) bools.append("=") keys.append(key) # Make sure the search column actually exists try: valid_col = participants_df[col] except KeyError: logger.error("{col} is not a valid option in metadata.") counted("CLI_exception") raise CLI_Input_Error( f"{col} is not a valid option in metadata. \n Available columns and types" f"are: \n{participants_df.dtypes}") # Check to make sure the types match. i.e. sex > 22 makes no sense boolmeta = _check_types(participants_df, col, key, "=") # filter based on the columns participants_df = participants_df[boolmeta] # Check for greater than option (i.e. age > 22) greater = opt.split(">") if len(greater) == 2: col = greater[0] key = greater[1] cols.append(col) bools.append(">") keys.append(key) try: valid_col = participants_df[col] except KeyError: logger.error("{col} is not a valid option in metadata.") counted("CLI_exception") raise CLI_Input_Error( f"{col} is not a valid option in metadata. \n Available columns and types " f"are: {participants_df.dtypes}") boolmeta = _check_types(participants_df, col, key, ">") participants_df = participants_df[boolmeta] # Check for less than option (i.e. age < 40) less = opt.split("<") if len(less) == 2: col = less[0] key = less[1] cols.append(col) bools.append("<") keys.append(key) try: valid_col = participants_df[col] except KeyError: logger.error("{col} is not a valid option in metadata.") counted("CLI_exception") raise CLI_Input_Error( f"{col} is not a valid option in metadata. \n Available columns and types " f"are: {participants_df.dtypes}") boolmeta = _check_types(participants_df, col, key, "<") participants_df = participants_df[boolmeta] return participants_df, cols, bools, keys
def _check_runfunc_params(run_params, function): """Check run or plot parameters and outputs user-friendly text.""" bids_root = Path(_get_bidsroot_path()) subject_id = run_params["subject_id"] session_id = run_params["session_id"] acquisition_id = run_params["acquisition_id"] run_id = run_params["run_id"] if any(x is None for x in [subject_id, session_id, run_id]): logger.error( f"ez {function} with subject_id: {subject_id}, session_id: {session_id}, " f"acquisition_id: {acquisition_id}, and run_id: {run_id}. \n" f"subject_id, session_id, and run_id must be set.") counted("CLI_exceptions") raise CLI_Input_Error( "\n\nEZTrack run requires subject_id, session_id, and run_id to be " "specified to analyze a specifically uploaded dataset. " "To see all subjects available, use the 'pat-summary' command. " "To see all datasets available, use the 'metadata' command. \n\n" "An example command looks like: " f"'ez {function} --subject_id <sub_id> --session_id <session_id> --run_id <run_id>'" "\n\nReplace words in brackets with your desired data identifiers." ) subject_ids = [ os.path.basename(x).split("-")[-1] for x in bids_root.glob("*") if x.is_dir() if "sub" in x.as_posix() ] if subject_id not in subject_ids: message_str = (f"Subject {subject_id} you passed in " f"is not a valid subject in your subject pool. " f"Here are the current subjects {subject_ids}.") error_msg = f"ez {function}: Subject {subject_id} is not a valid subject" logger.error(error_msg) counted("CLI_exceptions") raise CLI_Input_Error(message_str) acquisitions = ["ecog", "seeg", "eeg"] if acquisition_id not in acquisitions: error_msg = f"ez {function}: Acquisition {acquisition_id} is not supported yet." logger.error(error_msg) counted("CLI_exceptions") raise CLI_Input_Error(f"{acquisition_id} is not supported yet... " f"Pass 'ecog', 'seeg', or 'eeg'.") subj_bids_parser = BidsParser(bids_root, subject_id) # get the file paths to datasets _fpaths = [ x.as_posix() for x in Path(bids_root / f"sub-{subject_id}").rglob("*.vhdr") ] _fpaths = [x for x in _fpaths if acquisition_id in x] # extract run run_ids = [_extract_run(x) for x in _fpaths] run_ids = ",".join(run_ids) if run_id not in run_ids: message_str = ( f"Run {run_id} you passed in " f"is not a valid run for subject {subject_id} and acquisition {acquisition_id}. " f"Here are the current run ids {run_ids}.") error_msg = f"ez {function}: Run {run_id} is not a valid run" logger.error(error_msg) counted("CLI_exceptions") raise CLI_Input_Error(message_str) if function == "plot": colorblind = run_params["colorblind"] cmap = run_params["cmap"] # If colorblind is turned on, cmap should be None if colorblind and cmap is not None: logger.error( f"ez {function} with colorblind: True and cmap: {cmap}. Only one option can" f" be turned on.") counted("CLI_exceptions") raise CLI_Input_Error( "The colorblind option was turned on. You cannot also set a colormap." ) # Check if a valid colormap was entered cmap_opts = plt.colormaps() if cmap not in cmap_opts and cmap is not None: logger.error( f"ez {function} with cmap: {cmap}. This is not a valid matplotlib cmap." ) counted("CLI_exceptions") raise CLI_Input_Error( f"{cmap} is not a value colormap. Options are: {cmap_opts}")