Heudiconv: BIDS label



Hi all,

When trying to use heudiconv for DCM to BIDS conversion, I got incorrect label on fieldmap file.

Indeed, sub-207187M020161011_dir-WIP B0 map CLEAR_run-01_epi.nii.gz, the general problem is that BIDS label (and particularly the dir-) do not accept spaces, underscores or hyphens.

According initial dicom names how should I proper set the heuristics to avoid these problems ? Is there an automatic way of correcting it ?

Thanks !


hi @mattvan83 - which heuristic file (-f) are you using for conversion?

Heudiconv allows you create your own heuristic to customize the output file names, so this shouldn’t be a problem as long as you adhere to the BIDS standard.

Here are a few resources that should hopefully help guide the way - a nice tutorial, a video, and a sample conversion.


Hi @mgxd,

I have used banda-bids.py heuristic file and adapted it for conversion to BIDS format.

Maybe this code line causes problem ?
dirtype = s.protocol_name.split('_')[-1]



If you could paste the heuristic you’re using, I can take a look


Hi @mgxd,

Please find below the copy of the personal heuristic I am using.

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):
    """Heuristic evaluator for determining which runs belong where

    allowed template fields - follow python string module:

    item: index within category
    subject: participant id
    seqitem: run number during scanning
    subindex: sub index within group
    t1 = create_key('sub-{subject}/anat/sub-{subject}_T1w')
    t2 = create_key('sub-{subject}/anat/sub-{subject}_T2w')
    rest = create_key('sub-{subject}/func/sub-{subject}_task-rest_run-{item:02d}_bold')
    rest_corrpa = create_key('sub-{subject}/func/sub-{subject}_task-rest_run-{item:02d}_corrpa')
    rest_corrap = create_key('sub-{subject}/func/sub-{subject}_task-rest_run-{item:02d}_corrap')
    dwi = create_key('sub-{subject}/dwi/sub-{subject}_run-{item:02d}_dwi')
    dwi_corr = create_key('sub-{subject}/dwi/sub-{subject}_run-{item:02d}_corr')
    fmap = create_key('sub-{subject}/fmap/sub-{subject}_dir-{dir}_run-{item:02d}_epi')

    info = {t1:[], t2:[],
            rest:[], dwi:[],
            rest_corrpa:[], rest_corrap:[], dwi_corr:[],

    for idx, s in enumerate(seqinfo):
        # T1 and T2 scans
        if (s.dim3 == 160) and (s.dim4 == 1) and ('s3DT1 ISO 1mm' in s.protocol_name):
            info[t1] = [s.series_id]
        if (s.dim3 == 44) and (s.dim4 == 1) and ('FLAIR_3 mm SENSE' in s.protocol_name):
            info[t2] = [s.series_id]
        # diffusion scans
        if ('DTI' in s.protocol_name):
            key = None
            if (s.dim3 == 960):
                key = dwi
            elif (s.dim3 == 480) and ('DTI CORRECTION' in s.series_description):
                key = dwi_corr
            if key:
                info[key].append({'item': s.series_id})
        # functional scans
        if (s.dim3 == 10000) and ('EPI 64x64 resting state' in s.protocol_name):
            info[rest].append({'item': s.series_id})
        if (s.dim3 == 40) and ('FMRI_CORR_PA' in s.protocol_name):
            info[rest_corrpa].append({'item': s.series_id})
        if (s.dim3 == 40) and ('FMRI_CORR_AP' in s.protocol_name):
            info[rest_corrap].append({'item': s.series_id})
        if (s.dim3 == 60) and ('B0 map' in s.protocol_name):
            dirtype = s.protocol_name.split('_')[-1]
            info[fmap].append({'item': s.series_id, 'dir': dirtype})

    # You can even put checks in place for your protocol
    msg = []
    if len(info[t1]) != 1: msg.append('Missing correct number of t1 runs')
    if len(info[t2]) != 1: msg.append('Missing correct number of t2 runs')
    if len(info[dwi]) != 2: msg.append('Missing correct number of dwi runs')
    if len(info[dwi_corr]) != 1: msg.append('Missing correct number of dwi_corr runs')
    if len(info[rest]) != 1: msg.append('Missing correct number of resting runs')
    if len(info[rest_corrpa]) != 1: msg.append('Missing correct number of rest_corrpa runs')
    if len(info[rest_corrap]) != 1: msg.append('Missing correct number of rest_corrap runs')
    if msg:
        raise ValueError('\n'.join(msg))
    return info

Thanks !


Are you collecting field maps in both AP/PA directions? If not, you can change the following:

fmap = create_key(‘sub-{subject}/fmap/sub-{subject}_dir-{dir}_run-{item:02d}_epi’)


fmap = create_key('sub-{subject}/fmap/sub-{subject}_dir-{dir}_run-{item:02d}_epi')


dirtype = s.protocol_name.split(’_’)[-1]
info[fmap].append({‘item’: s.series_id, ‘dir’: dirtype})



Otherwise, as you said you will have to change

dirtype = s.protocol_name.split(’_’)[-1]

to grab the proper encoding directions


@mgxd in facts for RS-fMRI SD correction, 2 spin echo 3D volumes have been acquired according reverse phase encoding direction. @ChrisGorgolewski sent me back to fmaps section in BIDS specifications for this case. How should I manage these files to allow BIDS validation ?


Here’s a sample heuristic that extracts AP/PA fieldmaps - the relevant lines are 23-24 and 62-66


Thanks @mgxd should I use the same syntax for dwi files implied in SDC ?


the [dir-] key isn’t supported for diffusion scans under BIDS, but you could use the [acq-] key