From 49cb77d98f63df94b8e2ad7454814eb8083c4473 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Tue, 7 Jun 2022 18:30:55 -0400 Subject: [PATCH 1/2] ENH: little helper utility to find dicts intersection --- heudiconv/tests/test_utils.py | 23 ++++++++++++++++------- heudiconv/utils.py | 14 ++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/heudiconv/tests/test_utils.py b/heudiconv/tests/test_utils.py index 48448c25..96ee36de 100644 --- a/heudiconv/tests/test_utils.py +++ b/heudiconv/tests/test_utils.py @@ -5,18 +5,20 @@ import mock from heudiconv.utils import ( - get_known_heuristics_with_descriptions, + create_tree, + get_datetime, + get_dicts_intersection, get_heuristic_description, - load_heuristic, + get_known_heuristics_with_descriptions, json_dumps_pretty, + JSONDecodeError, + load_heuristic, load_json, - create_tree, + remove_prefix, + remove_suffix, save_json, update_json, - get_datetime, - remove_suffix, - remove_prefix, - JSONDecodeError) +) import pytest from .utils import HEURISTICS_PATH @@ -170,3 +172,10 @@ def test_remove_prefix(): assert remove_prefix(s, '') == s assert remove_prefix(s, 'foo') == s assert remove_prefix(s, 'jason') == '.bourne' + + +def test_get_dicts_intersection(): + assert get_dicts_intersection([]) == {} + assert get_dicts_intersection([{"a": 1}]) == {"a": 1} + assert get_dicts_intersection([{"a": 1}, {"b": 2}]) == {} + assert get_dicts_intersection([{"a": 1}, {"a": 1, "b": 2}]) == {"a": 1} \ No newline at end of file diff --git a/heudiconv/utils.py b/heudiconv/utils.py index d51dd5ce..b6b57799 100644 --- a/heudiconv/utils.py +++ b/heudiconv/utils.py @@ -645,3 +645,17 @@ def remove_prefix(s, pre): if pre and s.startswith(pre): return s[len(pre):] return s + + +def get_dicts_intersection(recs: list[dict]) -> dict: + """Given a list of dictionaries, return a dict of key:values which are the same + across all entries + """ + if not recs: + return {} + common_keys = recs[0].copy() + for r in recs[1:]: + for k, v in common_keys.copy().items(): + if k not in r or r[k] != v: + common_keys.pop(k) + return common_keys From d51eddd4d5cbcbeb76b080e578f9bd49b8a13b85 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Tue, 7 Jun 2022 18:31:37 -0400 Subject: [PATCH 2/2] -c ls-studysections to show tables with unique fields in dicom series --- heudiconv/cli/run.py | 3 ++- heudiconv/main.py | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/heudiconv/cli/run.py b/heudiconv/cli/run.py index 42bc85d0..3c0b03a5 100644 --- a/heudiconv/cli/run.py +++ b/heudiconv/cli/run.py @@ -134,7 +134,8 @@ def get_parser(): '--command', choices=( 'heuristics', 'heuristic-info', - 'ls', 'populate-templates', + 'ls', 'ls-studysessions', + 'populate-templates', 'sanitize-jsons', 'treat-jsons', 'populate-intended-for' ), diff --git a/heudiconv/main.py b/heudiconv/main.py index 5c6f37d5..775fe088 100644 --- a/heudiconv/main.py +++ b/heudiconv/main.py @@ -94,6 +94,46 @@ def process_extra_commands(outdir, command, files, dicom_dir_template, "\t%s %d sequences%s" % (str(study_session), len(sequences), suf) ) + elif command == 'ls-studysessions': + ensure_heuristic_arg(heuristic) + heuristic = load_heuristic(heuristic) + # heuristic_ls = getattr(heuristic, 'ls', None) + study_sessions = get_study_sessions( + dicom_dir_template, files, heuristic, outdir, + session, subjs, grouping=grouping) + for ss, seqinfos in study_sessions.items(): + print(f"{ss}:") + # deduce unique attributes + from heudiconv.utils import get_dicts_intersection + seqinfo_dicts = [s._asdict() for s in seqinfos] + common_seqinfo = get_dicts_intersection(seqinfo_dicts) + + diff_seqinfo = [] + for sd in seqinfo_dicts: + diff = { + k: v for k, v in sd.items() + if (k not in common_seqinfo) and + (k not in {'total_files_till_now', 'series_uid'})} + # some transformations might be needed to please pyout + for k, v in diff.items(): + if isinstance(v, tuple): + diff[k] = ', '.join(v) + diff_seqinfo.append(diff) + + if diff_seqinfo == [{}]: + print(f" only common: {common_seqinfo}") + continue + from pyout import Tabular + with Tabular( + columns=['example_dcm_file', 'series_files', 'series_id', 'protocol_name', 'series_description'], + style={"header_": dict(bold=True,), + "example_dcm_file": dict(bold=True,), + "image_type": dict(transform=str)}, + mode='final' + ) as out: + for diffs, files in zip(diff_seqinfo, seqinfos.values()): + out(diffs) + # print(f"{path_id} {diffs}") elif command == 'populate-templates': ensure_heuristic_arg(heuristic) heuristic = load_heuristic(heuristic)