Source code for bidsmreye.utils

from __future__ import annotations

import re
import shutil
from pathlib import Path
from typing import Any

import numpy as np
import pandas as pd
from bids import BIDSLayout  # type: ignore
from bids.layout import BIDSFile
from rich.progress import (
    BarColumn,
    MofNCompleteColumn,
    Progress,
    SpinnerColumn,
    TaskProgressColumn,
    TextColumn,
    TimeElapsedColumn,
    TimeRemainingColumn,
)

from bidsmreye.configuration import Config
from bidsmreye.logger import bidsmreye_log

log = bidsmreye_log(name="bidsmreye")


TEMPLATES_DIR = Path(__file__).parent / "templates"


[docs] def progress_bar(text: str, color: str = "green") -> Progress: return Progress( TextColumn(f"[{color}]{text}"), SpinnerColumn("dots"), TimeElapsedColumn(), BarColumn(), MofNCompleteColumn(), TaskProgressColumn(), TimeRemainingColumn(), )
[docs] def copy_license(output_dir: Path) -> Path: """Copy CCO license to output directory. :param output_dir: :type output_dir: Path """ input_file = str(TEMPLATES_DIR / "CCO") output_file = output_dir / "LICENSE" create_dir_if_absent(output_dir) if not (output_dir / "LICENSE").is_file(): shutil.copy(input_file, output_dir) move_file(output_dir / "CCO", output_file) return output_file
[docs] def check_if_file_found( bf: list[BIDSFile], this_filter: dict[str, Any], layout: BIDSLayout ) -> None: if not bf: log.warning(f"No file found for filter {this_filter}") else: to_print = [str(Path(x.path).relative_to(layout.root)) for x in bf] log.debug(f"Found files\n{to_print}")
[docs] def set_this_filter( cfg: Config, subject_label: str | list[str], filter_type: str ) -> dict[str, Any]: this_filter = cfg.bids_filter[filter_type] this_filter["suffix"] = return_regex(this_filter["suffix"]) this_filter["task"] = return_regex(cfg.task) if filter_type not in ("eyetrack", "eyetrack_qc"): this_filter["space"] = return_regex(cfg.space) this_filter["subject"] = subject_label if cfg.run: this_filter["run"] = return_regex(cfg.run) log.debug(f"Looking for files with filter\n{this_filter}") return this_filter
[docs] def move_file(input: Path, output: Path) -> None: """Move or rename a file and create target directory if it does not exist. Should work even the source and target names are on different file systems. :param input:File to move. :type input: Path :param output: :type output: Path :param root: Optional. If specified, the printed path will be relative to this path. :type root: Path """ log.debug(f"{input.absolute()} --> {output.absolute()}") create_dir_for_file(output) shutil.copy(input, output) input.unlink()
[docs] def create_dir_if_absent(output_path: str | Path) -> None: """Create a path if it does not exist. :param output_path: :type output_path: Union[str, Path] """ if isinstance(output_path, str): output_path = Path(output_path) if not output_path.is_dir(): log.debug(f"Creating dir: {output_path}") output_path.mkdir(parents=True, exist_ok=True)
[docs] def create_dir_for_file(file: Path) -> None: """Create the path to a file if it does not exist. :param file: :type file: Path """ output_path = file.absolute().parent create_dir_if_absent(output_path)
# TODO refactor with create_dir_if_absent
[docs] def return_regex(value: str | list[str] | None) -> str | None: """Return the regular expression for a string or a list of strings. :param value: :type value: Union[str, Optional[list]] :return: :rtype: Optional[str] """ if isinstance(value, str): if value[0] != "^": value = f"^{value}" if not value.endswith("$"): value = f"{value}$" if isinstance(value, list): new_value = "" for i in value: new_value = f"{new_value}{return_regex(i)}|" value = new_value[:-1] return value
[docs] def get_deepmreye_filename( layout: BIDSLayout, img: str, filetype: str | None = None ) -> Path: """Get deepmreye filename. :param layout: BIDSLayout of the dataset. :type layout: BIDSLayout :param img: _description_ :type img: str :param filetype: Any of the following: None, "mask", "report"D defaults to None :type filetype: str, optional :raises ValueError: _description_ :return: _description_ :rtype: Path """ if not img: raise ValueError("No file") if isinstance(img, (list)): img = img[0] bf = layout.get_file(img) filename = bf.filename filename = return_deepmreye_output_filename(filename, filetype) return Path(img).parent.absolute() / filename
[docs] def return_deepmreye_output_filename(filename: str, filetype: str | None = None) -> str: """Return deepmreye output filename. :param filename: :type filename: str :param filetype: Any of the following: None, "mask", "report". defaults to None :type filetype: str, optional :return: _description_ :rtype: str """ if filetype is None: pass elif filetype == "mask": filename = "mask_" + re.sub(r"\.nii.*", ".p", filename) elif filetype == "report": filename = "report_" + re.sub(r"\.nii.*", ".html", filename) return filename
[docs] def add_timestamps_to_dataframe(df: pd.DataFrame, sampling_frequency: float): nb_timepoints = df.shape[0] timestamp = np.arange( 0, 1 / sampling_frequency * nb_timepoints, 1 / sampling_frequency ) df["timestamp"] = timestamp cols = df.columns.tolist() cols.insert(0, cols.pop(cols.index("timestamp"))) return df[cols]