Skip to content

DerivativesDataSink datatype coercion does not skip non-dtseries CIFTIs #778

Closed
@tsalo

Description

@tsalo

I have been trying to write out a dseg-suffixed CIFTI file with the .dlabel.nii extension with DerivativesDataSink, but it raises the following exception:

Traceback:
	Traceback (most recent call last):
	  File "/usr/local/miniconda/lib/python3.8/site-packages/nipype/interfaces/base/core.py", line 398, in run
	    runtime = self._run_interface(runtime)
	  File "/usr/local/miniconda/lib/python3.8/site-packages/niworkflows/interfaces/bids.py", line 712, in _run_interface
	    new_header.set_data_dtype(data_dtype)
	AttributeError: 'Cifti2Header' object has no attribute 'set_data_dtype'

In the following section, DerivativesDataSink checks to see if an output file is a NIFTI by looking at the extension. However, it only counts .dtseries.nii[.gz] files as CIFTIs, and assumes any other files ending in .nii[.gz] are NIFTIs.

is_nifti = out_file.name.endswith(
(".nii", ".nii.gz")
) and not out_file.name.endswith((".dtseries.nii", ".dtseries.nii.gz"))

After that, DerivativesDataSink attempts to coerce the in_file's datatype to a target type for that suffix. However, this step only works for NIFTIs, so any CIFTIs mislabeled as NIFTIs above will cause an error.

I can't think of a great general-purpose solution, but two ideas I had were:

  1. Hardcode the full list of CIFTI extensions in the check. The extensions might need to be updated from time to time though.

  2. In the following section, check for a nii.nifti_header attribute, and set the datatype for that attribute instead of nii.header when it is present.

    if data_dtype:
    data_dtype = np.dtype(data_dtype)
    orig_dtype = nii.get_data_dtype()
    if orig_dtype != data_dtype:
    LOGGER.warning(
    f"Changing {out_file} dtype from {orig_dtype} to {data_dtype}"
    )
    # coerce dataobj to new data dtype
    if np.issubdtype(data_dtype, np.integer):
    new_data = np.rint(nii.dataobj).astype(data_dtype)
    else:
    new_data = np.asanyarray(nii.dataobj, dtype=data_dtype)
    # and set header to match
    if new_header is None:
    new_header = nii.header.copy()
    new_header.set_data_dtype(data_dtype)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions