Source code for bids.reports.report

"""Generate publication-quality data acquisition methods section from BIDS
dataset.
"""
from __future__ import print_function
import json
from os.path import dirname
from os.path import abspath
from os.path import join as pathjoin
from collections import Counter

from bids.reports import utils
from bids.reports import parsing


[docs]class BIDSReport(object): """ Generates publication-quality data acquisition methods section from BIDS dataset. Parameters ---------- layout : :obj:`bids.layout.BIDSLayout` Layout object for a BIDS dataset. config : :obj:`str` or :obj:`dict`, optional Configuration info for methods generation. Can be a path to a file (str), a dictionary, or None. If None, loads and uses default configuration information. Keys in the dictionary include: 'dir': a dictionary for converting encoding direction strings (e.g., j-) to descriptions (e.g., anterior to posterior) 'seq': a dictionary of sequence abbreviations (e.g., EP) and corresponding names (e.g., echo planar) 'seqvar': a dictionary of sequence variant abbreviations (e.g., SP) and corresponding names (e.g., spoiled) """ def __init__(self, layout, config=None): self.layout = layout if config is None: config = pathjoin(dirname(abspath(__file__)), 'config', 'converters.json') if isinstance(config, str): with open(config) as fobj: config = json.load(fobj) if not isinstance(config, dict): raise ValueError('Input config must be None, dict, or path to ' 'json file containing dict.') self.config = config
[docs] def generate(self, **kwargs): """Generate the methods section. Parameters ---------- task_converter : :obj:`dict`, optional A dictionary with information for converting task names from BIDS filename format to human-readable strings. Returns ------- counter : :obj:`collections.Counter` A dictionary of unique descriptions across subjects in the dataset, along with the number of times each pattern occurred. Examples -------- >>> from os.path import join >>> from bids.layout import BIDSLayout >>> from bids.reports import BIDSReport >>> from bids.tests import get_test_data_path >>> layout = BIDSLayout(join(get_test_data_path(), 'synthetic')) >>> report = BIDSReport(layout) >>> counter = report.generate(session='01') >>> counter.most_common()[0][0] """ descriptions = [] subjs = self.layout.get_subjects(**kwargs) kwargs = {k: v for k, v in kwargs.items() if k != 'subject'} for sid in subjs: descriptions.append(self._report_subject(subject=sid, **kwargs)) counter = Counter(descriptions) print('Number of patterns detected: {0}'.format(len(counter.keys()))) print(utils.reminder()) return counter
def _report_subject(self, subject, **kwargs): """Write a report for a single subject. Parameters ---------- subject : :obj:`str` Subject ID. Attributes ---------- layout : :obj:`bids.layout.BIDSLayout` Layout object for a BIDS dataset. config : :obj:`dict` Configuration info for methods generation. Returns ------- description : :obj:`str` A publication-ready report of the dataset's data acquisition information. Each scan type is given its own paragraph. """ description_list = [] # Remove sess from kwargs if provided, else set sess as all available sessions = kwargs.pop('session', self.layout.get_sessions(subject=subject, **kwargs)) if not sessions: sessions = [None] elif not isinstance(sessions, list): sessions = [sessions] for ses in sessions: niftis = self.layout.get(subject=subject, extensions='nii.gz', **kwargs) if niftis: description_list.append('For session {0}:'.format(ses)) description_list += parsing.parse_niftis(self.layout, niftis, subject, self.config, session=ses) metadata = self.layout.get_metadata(niftis[0].path) else: raise Exception('No niftis for subject {0}'.format(subject)) # Assume all data were converted the same way and use the last nifti # file's json for conversion information. if 'metadata' not in vars(): raise Exception('No valid jsons found. Cannot generate final ' 'paragraph.') description = '\n\t'.join(description_list) description = description.replace('\tFor session', '\nFor session') description += '\n\n{0}'.format(parsing.final_paragraph(metadata)) return description