예제 #1
0
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.")
예제 #2
0
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)
예제 #3
0
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)
예제 #4
0
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
예제 #5
0
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
예제 #6
0
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}")