Heudiconv - heuristic file

Hello guys,
through heuristic file used in heudiconv, is possible add fields in the json file that are created together with nii.gz ? For example insert the field “Activity name”.
If the answer is YES, can me explain how to do it

thanks,

Piero

Hi @chpiero - this should be possible by defining a DEFAULT_FIELDS dictionary with the key/values you wish to add.

You can find an example within the reproin heuristic

Maybe I did not express the problem well. I give an example. I have a dataset with 4 runs (fmri) that correspond to 4 different tasks obviously with different names. When I convert with Heudiconv for each functional file I have my own json when I validate I have an error that says the “Task Name” is missing, my problem is that I do not know how to insert within each json file corresponding to my nii.gz the field “Task Name” each one with a different fly because they are four tasks with four different names.

below my heuristic file:

import os


def create_key(template, outtype=('nii.gz',), annotation_classes=None):
    if template is None or not template:
        raise ValueError('Template must be a valid format string')
    return template, outtype, annotation_classes


def infotodict(seqinfo):
    
    t1w = create_key('sub-{subject}/anat/sub-{subject}_T1w')
    t2w = create_key('sub-{subject}/anat/sub-{subject}_T2w')
    FLAIR = create_key('sub-{subject}/anat/sub-{subject}_FLAIR')
    fieldmap_p = create_key('sub-{subject}/fmap/sub-{subject}_acq-P_run-{item:02d}_fieldmap')
    fieldmap_a = create_key('sub-{subject}/fmap/sub-{subject}_acq-A_run-{item:02d}_fieldmap')
    rest_pre = create_key('sub-{subject}/func/sub-{subject}_task-restpre_run-{item:02d}_bold')
    task_stim = create_key('sub-{subject}/func/sub-{subject}_task-stim_run-{item:02d}_bold')
    rest_cold_on = create_key('sub-{subject}/func/sub-{subject}_task-restcoldon_run-{item:02d}_bold')
    task_cold_stim = create_key('sub-{subject}/func/sub-{subject}_task-coldstim_run-{item:02d}_bold')
    rest_cold_off = create_key('sub-{subject}/func/sub-{subject}_task-restcoldoff_run-{item:02d}_bold')
    task_stim_after = create_key('sub-{subject}/func/sub-{subject}_task-stimafter_run-{item:02d}_bold')

    info = {t1w: [], 
            t2w: [], 
            FLAIR: [], 
            fieldmap_p: [], 
            fieldmap_a: [], 
            rest_pre: [], 
            task_stim: [], 
            rest_cold_on: [], 
            task_cold_stim: [],
            rest_cold_off: [],
            task_stim_after: []}
    
    for s in seqinfo:
        if  s.dim3 == 175 and s.dim4 == 1 and 'T1W' in s.protocol_name:
            info[t1w] = [s.series_id] # assign if a single series meets criteria
        elif (s.dim3 == 170) and (s.dim4 == 1) and ('T2' in s.protocol_name):
            info[t2w] = [s.series_id] # assign if a single series meets criteria   
        elif (s.dim3 == 190) and (s.dim4 == 1) and ('FLAIR' in s.protocol_name):
            info[FLAIR] = [s.series_id] # assign if a single series meets criteria
        elif (s.dim3 == 52) and (s.dim4 == 1) and ('Fieldmap P' in s.protocol_name):
            info[fieldmap_p] = [s.series_id] # assign if a single series meets criteria
        elif (s.dim3 == 52) and (s.dim4 == 1) and ('Fieldmap A' in s.protocol_name):
            info[fieldmap_a] = [s.series_id] # assign if a single series meets criteria
        elif (s.dim3 == 52) and (s.dim4 == 170) and ('EGG_rest' in s.protocol_name):
            info[rest_pre] = [s.series_id] # assign if a single series meets criteria
        elif (s.dim3 == 52) and (s.dim4 == 170) and ('EGG_stim' in s.protocol_name):
            info[task_stim] = [s.series_id] # assign if a single series meets criteria
        elif (s.dim3 == 52) and (s.dim4 == 60) and ('EGG_cold_on' in s.protocol_name):
            info[rest_cold_on] = [s.series_id] # assign if a single series meets criteria
        elif (s.dim3 == 52) and (s.dim4 == 170) and ('EGG_cold_stim' in s.protocol_name):
            info[task_cold_stim] = [s.series_id] # assign if a single series meets criteria
        elif (s.dim3 == 52) and (s.dim4 == 60) and ('EGG_cold_off' in s.protocol_name):
            info[rest_cold_off] = [s.series_id] # assign if a single series meets criteria
        elif (s.dim3 == 52) and (s.dim4 == 170) and ('EGG_stim_after' in s.protocol_name):
            info[task_stim_after] = [s.series_id] # assign if a single series meets criteria
    print info
    return info

Ah - I don’t believe we have a way of adding entries to exclusive metadata files currently (unless @yarikoptic knows)
In the past, I’ve made a quick python script using pybids (or just glob) and json to add all additional metadata per task

ReproIn is an automatic generation of shareable, version-controlled BIDS datasets from MR scanners how do they create bids and validate them? If they do a rest or a task and do not have the “Task Name” field automatically … I hope they do not do it by hand …:sweat_smile::sob:

$> git grep -1 TaskName 
heudiconv/bids.py-        lgr.debug("Generating %s", task_file)
heudiconv/bids.py:        fields["TaskName"] = ("TODO: full task name for %s" %
heudiconv/bids.py-                              task_acq.split('_')[0].split('-')[1])
--
heudiconv/dicoms.py-        try:
heudiconv/dicoms.py:            meta_info['TaskName'] = (re.search('(?<=_task-)\w+',
heudiconv/dicoms.py-                                               op.basename(infofile))

So we are both “correct”, apparently we (heudiconv, not even reproin heuristic):

  • take TaskName from the _task- specification within “info file” name if there is any (which is kinda automatic)… actually I do not think that one contains any in current version – so might not be in effect
  • but then indeed prepopulate (that is automatic ;)) top level task-*.json file with the TODO item (for manual labor) with a note to fill it out. For more “automated” mapping I have filed https://github.com/ReproNim/reproin/issues/16