Skip to content

Commit c57aad4

Browse files
authored
Merge pull request #754 from mgxd/fix/res-metadata
ENH: Add `Resolution` field to metadata if data has `res` entity
2 parents 33b2146 + 801e2c7 commit c57aad4

File tree

1 file changed

+52
-3
lines changed

1 file changed

+52
-3
lines changed

niworkflows/interfaces/bids.py

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
SimpleInterface,
4848
)
4949
from nipype.interfaces.io import add_traits
50-
from templateflow.api import templates as _get_template_list
50+
import templateflow as tf
5151
from ..utils.bids import _init_layout, relative_to_root
5252
from ..utils.images import set_consumables, unsafe_write_nifti_header_and_data
5353
from ..utils.misc import _copy_any, unlink
@@ -57,7 +57,7 @@
5757
BIDS_DERIV_ENTITIES = frozenset({e["name"] for e in _pybids_spec["entities"]})
5858
BIDS_DERIV_PATTERNS = tuple(_pybids_spec["default_path_patterns"])
5959

60-
STANDARD_SPACES = _get_template_list()
60+
STANDARD_SPACES = tf.api.templates()
6161
LOGGER = logging.getLogger("nipype.interface")
6262

6363

@@ -457,7 +457,10 @@ class DerivativesDataSink(SimpleInterface):
457457
>>> lines[1]
458458
' "RepetitionTime": 0.75,'
459459
460-
>>> lines[2]
460+
>>> lines[2] # doctest: +ELLIPSIS
461+
' "Resolution": "Template MNI152NLin6Asym (1.0x1.0x1.0 mm^3)...'
462+
463+
>>> lines[3]
461464
' "SkullStripped": true'
462465
463466
>>> bids_dir = tmpdir / 'bidsroot' / 'sub-02' / 'ses-noanat' / 'func'
@@ -576,6 +579,17 @@ def _run_interface(self, runtime):
576579
if out_entities.get("resolution") == "native" and out_entities.get("space"):
577580
out_entities.pop("resolution", None)
578581

582+
# Expand templateflow resolutions
583+
resolution = out_entities.get("resolution")
584+
space = out_entities.get("space")
585+
if resolution:
586+
# Standard spaces
587+
if space in STANDARD_SPACES:
588+
res = _get_tf_resolution(space, resolution)
589+
else: # TODO: Nonstandard?
590+
res = "Unknown"
591+
self._metadata['Resolution'] = res
592+
579593
if len(set(out_entities["extension"])) == 1:
580594
out_entities["extension"] = out_entities["extension"][0]
581595

@@ -926,3 +940,38 @@ def _run_interface(self, runtime):
926940
)
927941

928942
return runtime
943+
944+
945+
def _get_tf_resolution(space: str, resolution: str) -> str:
946+
"""
947+
Query templateflow template information to elaborate on template resolution.
948+
949+
Examples
950+
--------
951+
>>> _get_tf_resolution('MNI152NLin2009cAsym', '01') # doctest: +ELLIPSIS
952+
'Template MNI152NLin2009cAsym (1.0x1.0x1.0 mm^3)...'
953+
>>> _get_tf_resolution('MNI152NLin2009cAsym', '1') # doctest: +ELLIPSIS
954+
'Template MNI152NLin2009cAsym (1.0x1.0x1.0 mm^3)...'
955+
>>> _get_tf_resolution('MNI152NLin2009cAsym', '10')
956+
'Unknown'
957+
"""
958+
metadata = tf.api.get_metadata(space)
959+
resolutions = metadata.get('res', {})
960+
res_meta = None
961+
962+
# Due to inconsistencies, resolution keys may or may not be zero-padded
963+
padded_res = f'{str(resolution):0>2}'
964+
for r in (resolution, padded_res):
965+
if r in resolutions:
966+
res_meta = resolutions[r]
967+
if res_meta is None:
968+
return "Unknown"
969+
970+
def _fmt_xyz(coords: list) -> str:
971+
xyz = "x".join([str(c) for c in coords])
972+
return f"{xyz} mm^3"
973+
974+
return (
975+
f"Template {space} ({_fmt_xyz(res_meta['zooms'])}),"
976+
f" curated by TemplateFlow {tf.__version__}"
977+
)

0 commit comments

Comments
 (0)