subject {{ subject_label }}: {{ action }}
+ + {% for file in files %} +{{ file.name }}
+About
++ Report generated +
-
+
- on: {{ date }} +
- with bidsmreye {{ version }} +
diff --git a/.gitignore b/.gitignore index b862b72..101a4c6 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ logs # files *.nii *.h5 -*.html *desc-bidsmreye_eyetrack.tsv pybids_db tmp.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b690145..221cea6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -60,7 +60,7 @@ repos: rev: v1.11.1 hooks: - id: mypy - additional_dependencies: [pydantic, numpy] + additional_dependencies: [pydantic, numpy, types-Jinja2] files: bidsmreye args: [--config-file, pyproject.toml] diff --git a/bidsmreye/_cli.py b/bidsmreye/_cli.py index 919a739..fd893e5 100644 --- a/bidsmreye/_cli.py +++ b/bidsmreye/_cli.py @@ -11,7 +11,7 @@ from bidsmreye.bidsmreye import bidsmreye from bidsmreye.defaults import default_log_level, log_levels from bidsmreye.download import download -from bidsmreye.logging import bidsmreye_log +from bidsmreye.logger import bidsmreye_log log = bidsmreye_log(name="bidsmreye") diff --git a/bidsmreye/bids_utils.py b/bidsmreye/bids_utils.py index 434e011..cdb890a 100644 --- a/bidsmreye/bids_utils.py +++ b/bidsmreye/bids_utils.py @@ -15,7 +15,7 @@ get_bidsname_config, get_pybids_config, ) -from bidsmreye.logging import bidsmreye_log +from bidsmreye.logger import bidsmreye_log from bidsmreye.methods import methods from bidsmreye.utils import copy_license, create_dir_if_absent, return_regex diff --git a/bidsmreye/bidsmreye.py b/bidsmreye/bidsmreye.py index 76c0a9e..ca85362 100755 --- a/bidsmreye/bidsmreye.py +++ b/bidsmreye/bidsmreye.py @@ -9,7 +9,7 @@ from bidsmreye._version import __version__ from bidsmreye.configuration import Config from bidsmreye.defaults import default_log_level -from bidsmreye.logging import bidsmreye_log +from bidsmreye.logger import bidsmreye_log log = bidsmreye_log(name="bidsmreye") diff --git a/bidsmreye/config/config_bidsname.json b/bidsmreye/config/config_bidsname.json index 8eae1f9..4fb5fc9 100644 --- a/bidsmreye/config/config_bidsname.json +++ b/bidsmreye/config/config_bidsname.json @@ -1,6 +1,6 @@ { "mask": "sub-{subject}/[ses-{session}]/func/sub-{subject}[_ses-{session}]_task-{task}[_acq-{acquisition}][_ce-{ce}][_rec-{rec}][_dir-{dir}][_run-{run}][_space-{space}][_res-{res}][_den-{den}]_desc-eye_mask.p", - "report": "sub-{subject}/[ses-{session}]/func/sub-{subject}[_ses-{session}]_task-{task}[_acq-{acquisition}][_ce-{ce}][_rec-{rec}][_dir-{dir}][_run-{run}][_space-{space}][_res-{res}][_den-{den}]_desc-eye_report.html", + "report": "sub-{subject}/[ses-{session}]/figures/sub-{subject}[_ses-{session}]_task-{task}[_acq-{acquisition}][_ce-{ce}][_rec-{rec}][_dir-{dir}][_run-{run}][_space-{space}][_res-{res}][_den-{den}]_desc-eye_report.html", "no_label": "sub-{subject}/[ses-{session}]/func/sub-{subject}[_ses-{session}]_task-{task}[_acq-{acquisition}][_ce-{ce}][_rec-{rec}][_dir-{dir}][_run-{run}][_space-{space}][_res-{res}][_den-{den}]_desc-nolabel_bidsmreye.npz", "confounds_tsv": "sub-{subject}/[ses-{session}]/func/sub-{subject}[_ses-{session}]_task-{task}[_acq-{acquisition}][_ce-{ce}][_rec-{rec}][_dir-{dir}][_run-{run}][_space-{space}]_desc-bidsmreye_eyetrack.tsv", "confounds_json": "sub-{subject}/[ses-{session}]/func/sub-{subject}[_ses-{session}]_task-{task}[_acq-{acquisition}][_ce-{ce}][_rec-{rec}][_dir-{dir}][_run-{run}][_space-{space}]_desc-bidsmreye_eyetrack.json", diff --git a/bidsmreye/configuration.py b/bidsmreye/configuration.py index f856731..35e4b5e 100644 --- a/bidsmreye/configuration.py +++ b/bidsmreye/configuration.py @@ -9,7 +9,7 @@ from attrs import asdict, converters, define, field from bids import BIDSLayout # type: ignore -from bidsmreye.logging import bidsmreye_log +from bidsmreye.logger import bidsmreye_log log = bidsmreye_log(name="bidsmreye") diff --git a/bidsmreye/download.py b/bidsmreye/download.py index 9f9dd06..51e5a40 100644 --- a/bidsmreye/download.py +++ b/bidsmreye/download.py @@ -10,7 +10,7 @@ import bidsmreye from bidsmreye.defaults import available_models, default_model -from bidsmreye.logging import bidsmreye_log +from bidsmreye.logger import bidsmreye_log log = bidsmreye_log(name="bidsmreye") diff --git a/bidsmreye/generalize.py b/bidsmreye/generalize.py index 45f7b00..cb57fc5 100644 --- a/bidsmreye/generalize.py +++ b/bidsmreye/generalize.py @@ -22,7 +22,7 @@ list_subjects, ) from bidsmreye.configuration import Config -from bidsmreye.logging import bidsmreye_log +from bidsmreye.logger import bidsmreye_log from bidsmreye.quality_control import quality_control_output from bidsmreye.utils import ( add_sidecar_in_root, diff --git a/bidsmreye/logging.py b/bidsmreye/logger.py similarity index 100% rename from bidsmreye/logging.py rename to bidsmreye/logger.py diff --git a/bidsmreye/methods.py b/bidsmreye/methods.py index 49973b3..fe9c7cb 100644 --- a/bidsmreye/methods.py +++ b/bidsmreye/methods.py @@ -6,10 +6,9 @@ import warnings from pathlib import Path -import chevron - from bidsmreye._version import __version__ from bidsmreye.defaults import available_models, default_model +from bidsmreye.report import TEMPLATES_DIR, return_jinja_env from bidsmreye.utils import create_dir_for_file @@ -44,29 +43,26 @@ def methods( if not model: model = default_model() - is_known_models = False + is_known_model = False is_default_model = False if model in available_models(): - is_known_models = True + is_known_model = True if model == default_model(): is_default_model = True - if not is_known_models: + if not is_known_model: warnings.warn(f"{model} is not a known model name.", stacklevel=3) - template_file = str(Path(__file__).parent / "templates" / "CITATION.mustache") - with open(template_file) as template: - output = chevron.render( - template=template, - data={ - "version": __version__, - "model": model, - "is_default_model": is_default_model, - "is_known_models": is_known_models, - "qc_only": qc_only, - }, - warn=True, - ) + env = return_jinja_env(searchpath=TEMPLATES_DIR) + template = env.get_template("CITATION.jinja") + + output = template.render( + version=__version__, + model=model, + is_default_model=is_default_model, + is_known_model=is_known_model, + qc_only=qc_only, + ) output_file.write_text(output) diff --git a/bidsmreye/prepare_data.py b/bidsmreye/prepare_data.py index 3cba8ca..3568b31 100644 --- a/bidsmreye/prepare_data.py +++ b/bidsmreye/prepare_data.py @@ -20,7 +20,8 @@ save_sampling_frequency_to_json, ) from bidsmreye.configuration import Config -from bidsmreye.logging import bidsmreye_log +from bidsmreye.logger import bidsmreye_log +from bidsmreye.report import generate_report from bidsmreye.utils import ( check_if_file_found, get_deepmreye_filename, @@ -213,4 +214,7 @@ def prepare_data(cfg: Config) -> None: ) for subject_label in subjects: process_subject(cfg, layout_in, layout_out, subject_label) + generate_report( + output_dir=cfg.output_dir, subject_label=subject_label, action="prepare" + ) progress.update(subject_loop, advance=1) diff --git a/bidsmreye/quality_control.py b/bidsmreye/quality_control.py index e8df3ea..8c09a03 100644 --- a/bidsmreye/quality_control.py +++ b/bidsmreye/quality_control.py @@ -3,7 +3,6 @@ from __future__ import annotations import json -import logging import math from pathlib import Path @@ -20,7 +19,8 @@ list_subjects, ) from bidsmreye.configuration import Config -from bidsmreye.logging import bidsmreye_log +from bidsmreye.logger import bidsmreye_log +from bidsmreye.report import generate_report from bidsmreye.utils import ( check_if_file_found, create_dir_for_file, @@ -142,9 +142,7 @@ def perform_quality_control( add_qc_to_sidecar(confounds, sidecar_name) fig = visualize_eye_gaze_data(confounds) - fig.update_layout(title=Path(confounds_tsv).name) - if log.isEnabledFor(logging.DEBUG): - fig.show() + fig.update_layout(showlegend=False, height=800) create_dir_for_file(visualization_html_file) fig.write_html(visualization_html_file) @@ -184,6 +182,11 @@ def quality_control_output(cfg: Config) -> None: ) for subject_label in subjects: qc_subject(cfg, layout_out, subject_label) + generate_report( + output_dir=cfg.output_dir, + subject_label=subject_label, + action="generalize", + ) progress.update(subject_loop, advance=1) @@ -203,6 +206,11 @@ def quality_control_input(cfg: Config) -> None: ) for subject_label in subjects: qc_subject(cfg, layout_in, subject_label, layout_out) + generate_report( + output_dir=cfg.output_dir, + subject_label=subject_label, + action="generalize", + ) progress.update(subject_loop, advance=1) diff --git a/bidsmreye/report.py b/bidsmreye/report.py new file mode 100644 index 0000000..30576cf --- /dev/null +++ b/bidsmreye/report.py @@ -0,0 +1,80 @@ +"""Compile outputs from all tasks, spaces, runs into a single HTML.""" + +import datetime +from pathlib import Path + +from jinja2 import Environment, FileSystemLoader, select_autoescape + +from bidsmreye._version import __version__ +from bidsmreye.logger import bidsmreye_log + +log = bidsmreye_log(name="bidsmreye") + +TEMPLATES_DIR = Path(__file__).parent / "templates" + + +def return_jinja_env(searchpath=None) -> Environment: + if searchpath is None: + searchpath = TEMPLATES_DIR / "report" + return Environment( + loader=FileSystemLoader(searchpath), + autoescape=select_autoescape(), + lstrip_blocks=True, + trim_blocks=True, + ) + + +def generate_report(output_dir: Path, subject_label: str, action: str) -> None: + + env = return_jinja_env() + template = env.get_template("base.html") + + if action == "prepare": + input_files = sorted(output_dir.glob(f"sub-{subject_label}/**/*report.html")) + elif action == "generalize": + input_files = sorted(output_dir.glob(f"sub-{subject_label}/**/*eyetrack.html")) + + files = [] + for html_report in input_files: + with open(html_report) as f: + content = f.read() + + name: str = html_report.stem + if action == "prepare": + name = name.replace("_desc-eye_report", "_desc-preproc_bold") + + files.append({"name": name, "content": content, "path": html_report}) + + date = datetime.datetime.now().astimezone().replace(microsecond=0).isoformat() + + report = template.render( + action=action, + files=files, + subject_label=subject_label, + date=date, + version=__version__, + ) + + report_filename = ( + output_dir / f"sub-{subject_label}" / f"sub-{subject_label}_{action}.html" + ) + + with open(report_filename, "w") as f: + f.write(report) + + log.info(f"Report saved at: '{report_filename}'.") + + +if __name__ == "__main__": + + cwd = Path("/home/remi/github/cpp-lln-lab/bidsMReye") + + output_dir = cwd / "outputs" / "moae_fmriprep" / "derivatives" / "bidsmreye" + subject = "01" + + output_dir = Path("/home/remi/gin/CPP/yin/bidsmreye") + subject_label = "02" + + action = "prepare" + + generate_report(output_dir, subject_label, action) diff --git a/bidsmreye/templates/CITATION.mustache b/bidsmreye/templates/CITATION.jinja similarity index 92% rename from bidsmreye/templates/CITATION.mustache rename to bidsmreye/templates/CITATION.jinja index 78f46bd..c3f71d9 100644 --- a/bidsmreye/templates/CITATION.mustache +++ b/bidsmreye/templates/CITATION.jinja @@ -6,7 +6,7 @@ performed using [*bidsMReye*](https://github.com/cpp-lln-lab/bidsMReye) (version a BIDS app relying on [deepMReye](https://github.com/DeepMReye/DeepMReye) (@deepmreye) to decode eye motion from fMRI time series data. -{{^qc_only}} +{% if not qc_only %} ### data extraction The data of each BOLD runs underwent co-registration conducted @@ -28,19 +28,18 @@ across voxels (spatial normalization). Voxels time series were used as inputs for generalization decoding using a -{{#is_known_models}} + {% if is_known_model %} pre-trained model {{ model }} from deepMReye from [OSF](https://osf.io/23t5v). - {{#is_default_model}} + {% if is_default_model %} This model was trained on the following datasets: guided fixations (@alexander_open_2017), smooth pursuit (@nau_real-motion_2018, @polti_rapid_2022, @nau_hexadirectional_2018), free viewing (@julian_human_2018). - {{/is_default_model}} -{{/is_known_models}} -{{^is_known_models}} + {% endif %} + {% else %} model trained on calibration data from the current study. -{{/is_known_models}} -{{/qc_only}} + {% endif %} +{% endif %} ### quality control diff --git a/bidsmreye/templates/report/base.html b/bidsmreye/templates/report/base.html new file mode 100644 index 0000000..809e922 --- /dev/null +++ b/bidsmreye/templates/report/base.html @@ -0,0 +1,59 @@ + + +
+ + + ++ Report generated +