# Copyright (C) 2009-2021, Ecole Polytechnique Federale de Lausanne (EPFL) and
# Hospital Center and University of Lausanne (UNIL-CHUV), Switzerland, and CMP3 contributors
# All rights reserved.
#
# This software is distributed under the open-source license Modified BSD.
"""Module that defines CMTK functions and Nipype interfaces for connectome mapping."""
from os import path as op
import csv
import glob
import os
import copy
from traits.api import *
import nibabel as nib
import numpy as np
import networkx as nx
import scipy.io as sio
from nipype.interfaces.base import traits, \
File, TraitedSpec, BaseInterface, \
BaseInterfaceInputSpec, isdefined, \
InputMultiPath, OutputMultiPath
from nipype.interfaces import cmtk
from nipype.utils.filemanip import split_filename
from .util import mean_curvature, length
from .parcellation import get_parcellation
[docs]def group_analysis_sconn(output_dir, subjects_to_be_analyzed):
"""Perform group level analysis of structural connectivity matrices."""
print("Perform group level analysis ...")
[docs]def compute_curvature_array(fib):
"""Computes the curvature array."""
print("Compute curvature ...")
n = len(fib)
pc = -1
meancurv = np.zeros((n, 1))
for i, fi in enumerate(fib):
# Percent counter
pcN = int(round(float(100 * i) / n))
if pcN > pc and pcN % 1 == 0:
pc = pcN
print('%4.0f%%' % pc)
meancurv[i, 0] = mean_curvature(fi[0])
return meancurv
[docs]def create_endpoints_array(fib, voxelSize, print_info):
"""Create the endpoints arrays for each fiber.
Parameters
----------
fib: the fibers data
voxelSize: 3-tuple
It contains the voxel size of the ROI image
print_info : bool
If True, print extra information
Returns
-------
(endpoints: matrix of size [#fibers, 2, 3] containing for each fiber the
index of its first and last point in the voxelSize volume
endpointsmm) : endpoints in milimeter coordinates
"""
if print_info:
print("========================")
print("create_endpoints_array")
# Init
n = len(fib)
endpoints = np.zeros((n, 2, 3))
endpointsmm = np.zeros((n, 2, 3))
pc = -1
# Computation for each fiber
for i, fi in enumerate(fib):
# Percent counter
if print_info:
pcN = int(round(float(100 * i) / n))
if pcN > pc and pcN % 20 == 0:
pc = pcN
print('%4.0f%%' % pc)
f = fi[0]
# store startpoint
endpoints[i, 0, :] = f[0, :]
# store endpoint
endpoints[i, 1, :] = f[-1, :]
# store startpoint
endpointsmm[i, 0, :] = f[0, :]
# store endpoint
endpointsmm[i, 1, :] = f[-1, :]
# print 'endpoints (mm) : ',endpoints[i, 0, :],' ; ',endpoints[i, 1, :]
# Translate from mm to index
endpoints[i, 0, 0] = int(endpoints[i, 0, 0] / float(voxelSize[0]))
endpoints[i, 0, 1] = int(endpoints[i, 0, 1] / float(voxelSize[1]))
endpoints[i, 0, 2] = int(endpoints[i, 0, 2] / float(voxelSize[2]))
endpoints[i, 1, 0] = int(endpoints[i, 1, 0] / float(voxelSize[0]))
endpoints[i, 1, 1] = int(endpoints[i, 1, 1] / float(voxelSize[1]))
endpoints[i, 1, 2] = int(endpoints[i, 1, 2] / float(voxelSize[2]))
# print 'endpoints : ',endpoints[i, 0, :],' ; ',endpoints[i, 1, :]
# Return the matrices
return endpoints, endpointsmm
[docs]def save_fibers(oldhdr, oldfib, fname, indices):
"""Stores a new trackvis file fname using only given indices.
Parameters
----------
oldhdr : the tractogram header
Tractogram header to use as reference
oldfib : the fibers data
Input fibers
fname : string
Output tractogram filename
indices : list
Indices of fibers included
"""
hdrnew = oldhdr.copy()
outstreams = []
for i in indices:
outstreams.append(oldfib[i])
n_fib_out = len(outstreams)
hdrnew['n_count'] = n_fib_out
print("Writing final no orphan fibers: %s" % fname)
nib.trackvis.write(fname, outstreams, hdrnew)
[docs]def cmat(intrk, roi_volumes, roi_graphmls, parcellation_scheme, compute_curvature=True, additional_maps={},
output_types=['gPickle'], atlas_info={}):
"""Create the connection matrix for each resolution using fibers and ROIs.
Parameters
----------
intrk : TRK file
Reconstructed tractogram
roi_volumes : list
List of parcellation files for a given parcellation scheme
roi_graphmls : list
List of graphmls files that describes parcellation nodes
parcellation_scheme : ['NativeFreesurfer','Lausanne2008','Lausanne2018']
compute_curvature : Boolean
additional_maps : dict
A dictionary of key/value for each additional map where the value
is the path to the map
output_types : ['gPickle','mat','graphml']
atlas_info : dict
Dictionary storing information such as path to files related to a
parcellation atlas / scheme.
"""
print("========================")
print("> Creation of connectome maps")
# create the endpoints for each fibers
en_fname = 'endpoints.npy'
en_fnamemm = 'endpointsmm.npy'
# ep_fname = 'lengths.npy'
curv_fname = 'meancurvature.npy'
# intrk = op.join(gconf.get_cmp_fibers(), 'streamline_filtered.trk')
print('... tractogram :' + intrk)
fib, hdr = nib.trackvis.read(intrk, False)
# print "Header trackvis : ",hdr
# print "Header trackvis id_string : ",hdr['id_string']
# print "Fibers trackvis : ",fib
print('... parcellation : %s' % parcellation_scheme)
if parcellation_scheme != "Custom":
if parcellation_scheme != "Lausanne2018":
# print "get resolutions from parcellation_scheme"
resolutions = get_parcellation(parcellation_scheme)
else:
resolutions = get_parcellation(parcellation_scheme)
for parkey, parval in list(resolutions.items()):
for vol, graphml in zip(roi_volumes, roi_graphmls):
# print parkey
if parkey in vol:
roi_fname = vol
# print roi_fname
if parkey in graphml:
roi_graphml_fname = graphml
# print roi_graphml_fname
# roi_fname = roi_volumes[r]
# r += 1
roi = nib.load(roi_fname)
roiData = roi.get_data()
resolutions[parkey]['number_of_regions'] = roiData.max()
resolutions[parkey]['node_information_graphml'] = op.abspath(
roi_graphml_fname)
del roi, roiData
# print("##################################################")
# print("Atlas info (Lausanne2018) :")
# print(resolutions)
# print("##################################################")
else:
# print "get resolutions from atlas_info: "
resolutions = atlas_info
# print resolutions
# print "resolutions : %s" % resolutions
# Previously, load_endpoints_from_trk() used the voxel size stored
# in the track hdr to transform the endpoints to ROI voxel space.
# This only works if the ROI voxel size is the same as the DSI/DTI
# voxel size. In the case of DTI, it is not.
# We do, however, assume that all of the ROI images have the same
# voxel size, so this code just loads the first one to determine
# what it should be
firstROIFile = roi_volumes[0]
firstROI = nib.load(firstROIFile)
roiVoxelSize = firstROI.get_header().get_zooms()
# print "roi Voxel Size",roiVoxelSize
(endpoints, endpointsmm) = create_endpoints_array(fib, roiVoxelSize, True)
np.save(en_fname, endpoints)
np.save(en_fnamemm, endpointsmm)
# only compute curvature if required
if compute_curvature:
meancurv = compute_curvature_array(fib)
np.save(curv_fname, meancurv)
print("========================")
n = len(fib)
# resolution = gconf.parcellation.keys()
streamline_wrote = False
for parkey, parval in list(resolutions.items()):
# if parval['number_of_regions'] != 83:
# continue
# print("Resolution = "+parkey)
print("------------------------")
print("Resolution = " + parkey)
print("------------------------")
# create empty fiber label array
fiberlabels = np.zeros((n, 2))
final_fiberlabels = []
final_fibers_idx = []
# Open the corresponding ROI (scale1 for lausanne2008/18) (first volume for nativefreesurfer)
# print("Open the corresponding ROI")
for vol in roi_volumes:
# print parkey
if (parkey in vol) or (len(roi_volumes) == 1):
roi_fname = vol
# print roi_fname
# roi_fname = roi_volumes[r]
# r += 1
roi = nib.load(roi_fname)
roiData = roi.get_data()
# affine_vox_to_world = np.matrix(roi.affine[:3, :3])
# print "roiData shape : %s " % roiData.shape
# print "Affine Voxel 2 World transformation : ",affine_vox_to_world
# affine_world_to_vox = np.linalg.inv(affine_vox_to_world)
# origin = np.matrix(roi.affine[:3, 3]).T
# print "Affine World 2 Voxel transformation : ",affine_world_to_vox
# Create the matrix
print(" >> Create the connection matrix (%s rois)" %
parval['number_of_regions'])
nROIs = parval['number_of_regions']
G = nx.Graph()
# add node information from parcellation
gp = nx.read_graphml(parval['node_information_graphml'])
n_nodes = len(gp)
pc = -1
cnt = -1
thalamic_labels = []
for u, d in gp.nodes(data=True):
# Percent counter
cnt += 1
pcN = int(round(float(100 * cnt) / n_nodes))
if pcN > pc and pcN % 10 == 0:
pc = pcN
print('%4.0f%%' % pc)
G.add_node(int(u))
for key in d:
G.nodes[int(u)][key] = d[key]
# compute a position for the node based on the mean position of the
# ROI in voxel coordinates (segmentation volume )
if parcellation_scheme != "Lausanne2018":
G.nodes[int(u)]['dn_position'] = tuple(
np.mean(np.where(roiData == int(d["dn_correspondence_id"])), axis=1))
G.nodes[int(u)]['roi_volume'] = np.sum(
roiData == int(d["dn_correspondence_id"]))
# print "Add node %g - roi volume : %g " % (int(u),np.sum( roiData== int(d["dn_correspondence_id"]) ))
# Store parcellation labels corresponding to thalamic nuclei
# if gp.node[int(u)]['dn_fsname'] == 'thalamus':
# thalamic_labels.append(int(u))
else:
# if int(u) == 53:
# print("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&")
G.nodes[int(u)]['dn_position'] = tuple(
np.mean(np.where(roiData == int(d["dn_multiscaleID"])), axis=1))
G.nodes[int(u)]['roi_volume'] = np.sum(
roiData == int(d["dn_multiscaleID"]))
# if int(u) == 53:
# print("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&")
# print "Add node %g - roi volume (2018): %g " % (int(u),np.sum( roiData== int(d["dn_multiscaleID"]) ))
# if int(u) == 53:
# print("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&")
thalamic_labels = np.array(thalamic_labels)
print(" ************************")
print(' >> Labels of thalamic nuclei :')
print(' {}'.format(thalamic_labels))
print(" ************************")
dis = 0
# prepare: compute the measures
t = [c[0] for c in fib]
h = np.array(t, dtype=np.object)
mmap = additional_maps
mmapdata = {}
print(' >> Maps to be processed :')
for k, v in list(mmap.items()):
print(" - %s map" % k)
da = nib.load(v)
mdata = da.get_data()
print(mdata.max())
mdata = np.nan_to_num(mdata)
print(mdata.max())
mmapdata[k] = (mdata, da.get_header().get_zooms())
# print("mmapdata size : %g " % len(mmapdata.items()))
print(" ************************")
print(" >> Processing fibers and computing metrics (%s fibers)" % n)
pc = -1
for i in range(n): # n: number of fibers
# Percent counter
pcN = int(round(float(100 * i) / n))
if pcN > pc and pcN % 10 == 0:
pc = pcN
print('%4.0f%%' % pc)
# ROI start => ROI end
try:
startvox = np.zeros((3, 1)).astype(int)
startvox[0] = np.int(endpoints[i, 0, 0])
startvox[1] = np.int(endpoints[i, 0, 1])
startvox[2] = np.int(endpoints[i, 0, 2])
endvox = np.zeros((3, 1)).astype(int)
endvox[0] = np.int(endpoints[i, 1, 0])
endvox[1] = np.int(endpoints[i, 1, 1])
endvox[2] = np.int(endpoints[i, 1, 2])
# print "start point : ",startvox
# print "end point : ",endvox
# print "roi data shape : ",roiData.shape
# endpoints from create_endpoints_array
startROI = int(roiData[startvox[0], startvox[1], startvox[2]])
endROI = int(roiData[endvox[0], endvox[1], endvox[2]])
except IndexError:
print(
"... ERROR: An index error occured for fiber %s. This means that the fiber start or endpoint is outside the volume. Continue." % i)
continue
# Filter
if startROI == 0 or endROI == 0:
dis += 1
fiberlabels[i, 0] = -1
continue
if startROI > nROIs or endROI > nROIs:
# print("Start or endpoint of fiber terminate in a voxel which is labeled higher")
# print("than is expected by the parcellation node information.")
# print("Start ROI: %i, End ROI: %i" % (startROI, endROI))
# print("This needs bugfixing!")
continue
# Switch the rois in order to enforce startROI < endROI
if endROI < startROI:
tmp = startROI
startROI = endROI
endROI = tmp
# TODO: Refine fibers ending in thalamus
# if (startROI in thalamic_labels) or (endROI in thalamic_labels):
# Extract all thalamic nuclei the fiber is passing through
# Refine start/endROI connecting to the most probable nucleus
# Update fiber label
fiberlabels[i, 0] = startROI
fiberlabels[i, 1] = endROI
final_fiberlabels.append([startROI, endROI])
final_fibers_idx.append(i)
# Add edge to graph
if G.has_edge(startROI, endROI):
G[startROI][endROI]['fiblist'].append(i)
else:
G.add_edge(startROI, endROI, fiblist=[i])
print(
" ... INFO - Found %i (%f percent out of %i fibers) fibers that start or terminate in a voxel which is not labeled. (orphans)" % (
dis, dis * 100.0 / n, n))
print(" ... INFO - Valid fibers: %i (%f percent)" %
(n - dis, 100 - dis * 100.0 / n))
# print "roi : ",roi
# print "roiData size : ",roiData.size
# print "roiData shape : ",roiData.shape
# create a final fiber length array
finalfiberlength = []
for idx in final_fibers_idx:
# compute length of fiber
# print('Fiber %i length: %d' % (idx, length(fib[idx][0])))
finalfiberlength.append(length(fib[idx][0]))
# convert to array
final_fiberlength_array = np.array(finalfiberlength)
# make final fiber labels as array
final_fiberlabels_array = np.array(final_fiberlabels, dtype=np.int32)
total_fibers = 0
total_volume = 0
u_old = -1
for u, v, d in G.edges(data=True):
total_fibers += len(d['fiblist'])
if u != u_old:
# print("Node %i"%int(u))
# print(G.nodes[int(u)])
total_volume += G.nodes[int(u)]['roi_volume']
u_old = u
G_out = copy.deepcopy(G)
# update edges
# measures to add here
# FIXME treat case of self-connection that gives di['fiber_length_mean'] = 0.0
for u, v, d in G.edges(data=True):
# Check for diagonal elements that raise an error when the edge is visited a second time
# print('({}, {}): {}'.format(u, v, list(G[u][v].keys())))
G_out.remove_edge(u, v)
# print("u / v : {} / {}".format(u,v))
if len(list(G[u][v].keys())) == 1:
di = {'number_of_fibers': len(G[u][v]['fiblist'])}
# print("G[u][v]['fiblist'] : {}".format(G[u][v]['fiblist']))
# additional measures
# compute mean/std of fiber measure
if u <= v:
idx = np.where((final_fiberlabels_array[:, 0] == int(u)) & (
final_fiberlabels_array[:, 1] == int(v)))[0]
else:
idx = np.where((final_fiberlabels_array[:, 0] == int(v)) & (
final_fiberlabels_array[:, 1] == int(u)))[0]
# print("idx : {}".format(idx))
# print("final_fiberlength_array[idx] : {}".format(final_fiberlength_array[idx]))
di['fiber_length_mean'] = float(
np.nanmean(final_fiberlength_array[idx]))
di['fiber_length_median'] = float(
np.nanmedian(final_fiberlength_array[idx]))
di['fiber_length_std'] = float(
np.nanstd(final_fiberlength_array[idx]))
di['fiber_proportion'] = float(
100.0 * (di['number_of_fibers'] / float(total_fibers)))
# Compute density
# density = (#fibers / mean_fibers_length) * (2 / (area_roi_u + area_roi_v))
# print "G.nodes[int(u)]['roi_volume'] : %i / G.nodes[int(v)]['roi_volume'] : %i"
# % (G.nodes[int(u)]['roi_volume'],G.nodes[int(v)]['roi_volume'])
# print "di['number_of_fibers'] : %i / di['fiber_length_mean'] : %i" % (di['number_of_fibers'],di['fiber_length_mean'])
if di['fiber_length_mean'] > 0.0:
di['fiber_density'] = float((float(di['number_of_fibers']) / float(di['fiber_length_mean'])) * float(
2.0 / (G.nodes[int(u)]['roi_volume'] + G.nodes[int(v)]['roi_volume'])))
di['normalized_fiber_density'] = float(
((float(di['number_of_fibers']) / float(total_fibers)) / float(di['fiber_length_mean'])) * (
(2.0 * float(total_volume)) / (
G.nodes[int(u)]['roi_volume'] + G.nodes[int(v)]['roi_volume'])))
else:
di['fiber_density'] = 0.0
di['normalized_fiber_density'] = 0.0
# this is indexed into the fibers that are valid in the sense of touching start
# and end roi and not going out of the volume
if u <= v:
idx_valid = np.where((fiberlabels[:, 0] == int(u)) & (
fiberlabels[:, 1] == int(v)))[0]
else:
idx_valid = np.where((fiberlabels[:, 0] == int(v)) & (
fiberlabels[:, 1] == int(u)))[0]
for k, vv in list(mmapdata.items()):
val = []
# print("Processing %s map..." % k)
# print(vv[1])
for i in idx_valid:
# retrieve indices
try:
# print(h[i])
idx2 = (h[i] / vv[1]).astype(np.uint32)
# print "idx2 : ",idx2
val.append(vv[0][idx2[:, 0], idx2[:, 1], idx2[:, 2]])
except IndexError as e:
print(
" ... ERROR - Index error occured when trying extract scalar values for measure", k)
print(" ... ERROR - Discard fiber with index",
i, "Exception: ", e)
# print(k)
if len(val) > 0:
da = np.concatenate(val)
# print(da.max())
# print(np.median(da))
if k == 'shore_rtop':
di[k + '_mean'] = da.astype(np.float64).mean()
di[k + '_std'] = da.astype(np.float64).std()
di[k + '_median'] = np.median(da.astype(np.float64))
else:
di[k + '_mean'] = da.mean().astype(np.float)
di[k + '_std'] = da.std().astype(np.float)
di[k + '_median'] = np.median(da).astype(np.float)
# print(di[k + '_median'])
del da
del val
G_out.add_edge(u, v)
for key in di:
G_out[u][v][key] = di[key]
# print('({}, {}): {}'.format(u, v, list(G[u][v].keys())))
# print(" ************************************************************************")
# for u, v, d in G.edges(data=True):
# print('({}, {}): {}'.format(u, v, list(d.keys())))
# if 'fiblist' in list(d.keys()):
# print(G[u][v]['fiblist'])
del G
print(" ************************************************")
print(" >> Save connectome maps as :")
# Get the edge attributes/keys/weights from the first edge and then break.
# Change w.r.t networkx2
edge_keys = []
for u, v, d in G_out.edges(data=True):
# print(list(d.keys()))
edge_keys = list(d.keys())
break
# Storing network/graph in TSV format (by default to be BIDS compliant)
print(' - connectome_%s.tsv' % parkey)
# Write header fields
with open('connectome_%s.tsv' % parkey, 'w') as out_file:
tsv_writer = csv.writer(out_file, delimiter='\t')
header = ['source', 'target']
header = header + [key for key in edge_keys]
tsv_writer.writerow(header)
# Write list of graph edges with all connectivity metrics (edge_keys)
with open('connectome_%s.tsv' % parkey, 'ab') as out_file:
nx.write_edgelist(G_out,
out_file,
comments='#',
delimiter='\t',
data=edge_keys,
encoding='utf-8')
# Storing network/graph in other formats that might be prefered by the user
if 'gPickle' in output_types:
print(' - connectome_%s.gpickle' % parkey)
nx.write_gpickle(G_out, 'connectome_%s.gpickle' % parkey)
if 'mat' in output_types:
# edges
# size_edges = (int(parval['number_of_regions']), int(
# parval['number_of_regions']))
edge_struct = {}
for edge_key in edge_keys:
if edge_key != 'fiblist':
# print('edge key: %s ' % edge_key)
edge_struct[edge_key] = nx.to_numpy_matrix(G_out, weight=edge_key)
# nodes
size_nodes = int(parval['number_of_regions'])
# Get the node attributes/keys from the first node and then break.
# Change w.r.t networkx2
for u, d in G_out.nodes(data=True):
node_keys = list(d.keys())
break
# print "size_nodes : "
# print size_nodes
#
# print "Number of nodes : %i" % len(G)
node_struct = {}
for node_key in node_keys:
if node_key == 'dn_position':
node_arr = np.zeros([size_nodes, 3], dtype=np.float)
else:
node_arr = np.zeros(size_nodes, dtype=np.object_)
node_n = 0
for _, node_data in G_out.nodes(data=True):
node_arr[node_n] = node_data[node_key]
# print " node_arr[%i]:" % node_n
# print node_arr[node_n]
node_n += 1
# print('node key: %s ' % node_key)
node_struct[node_key] = node_arr
print(' - connectome_%s.mat' % parkey)
sio.savemat('connectome_%s.mat' % parkey, long_field_names=True,
mdict={'sc': edge_struct,
'nodes': node_struct})
if 'graphml' in output_types:
g2 = nx.Graph()
for u_gml, v_gml, d_gml in G_out.edges(data=True):
g2.add_edge(u_gml, v_gml)
for key in d_gml:
g2[u_gml][v_gml][key] = d_gml[key]
for u_gml, d_gml in G_out.nodes(data=True):
g2.add_node(u_gml)
if parcellation_scheme != "Lausanne2018":
g2.nodes[u_gml]['dn_correspondence_id'] = d_gml['dn_correspondence_id']
else:
g2.nodes[u_gml]['dn_multiscaleID'] = d_gml['dn_multiscaleID']
g2.nodes[u_gml]['dn_fsname'] = d_gml['dn_fsname']
g2.nodes[u_gml]['dn_hemisphere'] = d_gml['dn_hemisphere']
g2.nodes[u_gml]['dn_name'] = d_gml['dn_name']
g2.nodes[u_gml]['dn_position_x'] = d_gml['dn_position'][0]
g2.nodes[u_gml]['dn_position_y'] = d_gml['dn_position'][1]
g2.nodes[u_gml]['dn_position_z'] = d_gml['dn_position'][2]
g2.nodes[u_gml]['dn_region'] = d_gml['dn_region']
print(' - connectome_%s.graphml' % parkey)
nx.write_graphml(g2, 'connectome_%s.graphml' % parkey)
# print("Storing final fiber length array")
fiberlabels_fname = 'final_fiberslength_%s.npy' % str(parkey)
np.save(fiberlabels_fname, final_fiberlength_array)
# print("Storing all fiber labels (with orphans)")
fiberlabels_fname = 'filtered_fiberslabel_%s.npy' % str(parkey)
np.save(fiberlabels_fname, np.array(fiberlabels, dtype=np.int32), )
# print("Storing final fiber labels (no orphans)")
fiberlabels_noorphans_fname = 'final_fiberlabels_%s.npy' % str(parkey)
np.save(fiberlabels_noorphans_fname, final_fiberlabels_array)
if not streamline_wrote:
print(" > Filtering tractography - keeping only no orphan fibers")
finalfibers_fname = 'streamline_final.trk'
save_fibers(hdr, fib, finalfibers_fname, final_fibers_idx)
print("Done.")
print("========================")
class CMTK_cmatInputSpec(BaseInterfaceInputSpec):
track_file = InputMultiPath(File(exists=True),
desc='Tractography result',
mandatory=True)
roi_volumes = InputMultiPath(File(exists=True),
desc='ROI volumes registered to diffusion space')
parcellation_scheme = traits.Enum('Lausanne2008', ['Lausanne2008', 'Lausanne2018', 'NativeFreesurfer', 'Custom'],
desc="Parcellation scheme",
usedefault=True)
roi_graphmls = InputMultiPath(File(exists=True),
desc='GraphML description of ROI volumes (Lausanne2018)')
atlas_info = Dict(mandatory=False, desc="custom atlas information")
compute_curvature = traits.Bool(
True, desc='Compute curvature', usedefault=True)
additional_maps = traits.List(
File, desc='Additional calculated maps (ADC, gFA, ...)')
output_types = traits.List(
Str, desc='Output types of the connectivity matrices')
probtrackx = traits.Bool(False, desc="MUST be set to True if probtrackx was used (Not used anymore in CMP3)")
voxel_connectivity = InputMultiPath(File(exists=True),
desc="ProbtrackX connectivity matrices (# seed voxels x # target ROIs)")
class CMTK_cmatOutputSpec(TraitedSpec):
endpoints_file = File(desc="Numpy files storing the list of fiber endpoint")
endpoints_mm_file = File(desc="Numpy files storing the list of fiber endpoint in mm")
final_fiberslength_files = OutputMultiPath(File(),
desc="List of fiber length")
filtered_fiberslabel_files = OutputMultiPath(File(), desc="List of fiber start end ROI parcellation label after filtering")
final_fiberlabels_files = OutputMultiPath(File(), desc="List of fiber start end ROI parcellation label")
streamline_final_file = File(desc="Final tractogram of fibers considered in the creation of connectivity matrices")
connectivity_matrices = OutputMultiPath(File(), desc="Connectivity matrices")
class CMTK_cmat(BaseInterface):
"""Creates the structural connectivity matrices for a given parcellation scheme.
Examples
--------
>>> from cmtklib.connectome import CMTK_cmat
>>> cmat = CMTK_cmat()
>>> cmat.inputs.base_dir = '/my_directory'
>>> cmat.inputs.track_file = '/path/to/sub-01_tractogram.trk'
>>> cmat.inputs.roi_volumes = ['/path/to/sub-01_space-DWI_atlas-L2018_desc-scale1_dseg.nii.gz',
>>> '/path/to/sub-01_space-DWI_atlas-L2018_desc-scale2_dseg.nii.gz',
>>> '/path/to/sub-01_space-DWI_atlas-L2018_desc-scale3_dseg.nii.gz',
>>> '/path/to/sub-01_space-DWI_atlas-L2018_desc-scale4_dseg.nii.gz',
>>> '/path/to/sub-01_space-DWI_atlas-L2018_desc-scale5_dseg.nii.gz']
>>> cmat.inputs.roi_graphmls = ['/path/to/sub-01_atlas-L2018_desc-scale1_dseg.graphml',
>>> '/path/to/sub-01_atlas-L2018_desc-scale2_dseg.graphml',
>>> '/path/to/sub-01_atlas-L2018_desc-scale3_dseg.graphml',
>>> '/path/to/sub-01_atlas-L2018_desc-scale4_dseg.graphml',
>>> '/path/to/sub-01_atlas-L2018_desc-scale5_dseg.graphml']
>>> cmat.inputs.parcellation scheme = 'Lausanne2018'
>>> cmat.inputs.output_types = ['gPickle','mat','graphml']
>>> cmat.run() # doctest: +SKIP
"""
input_spec = CMTK_cmatInputSpec
output_spec = CMTK_cmatOutputSpec
def _run_interface(self, runtime):
if isdefined(self.inputs.additional_maps):
additional_maps = dict(
(split_filename(add_map)[1], add_map) for add_map in self.inputs.additional_maps if add_map != '')
else:
additional_maps = {}
# if self.inputs.probtrackx:
# probtrackx_cmat(voxel_connectivity_files=self.inputs.track_file, roi_volumes=self.inputs.roi_volumes,
# parcellation_scheme=self.inputs.parcellation_scheme, atlas_info=self.inputs.atlas_info,
# output_types=self.inputs.output_types)
# elif len(self.inputs.track_file) > 1:
# prob_cmat(intrk=self.inputs.track_file, roi_volumes=self.inputs.roi_volumes,
# parcellation_scheme=self.inputs.parcellation_scheme, atlas_info=self.inputs.atlas_info,
# output_types=self.inputs.output_types)
# else:
cmat(intrk=self.inputs.track_file[0], roi_volumes=self.inputs.roi_volumes,
roi_graphmls=self.inputs.roi_graphmls,
parcellation_scheme=self.inputs.parcellation_scheme, atlas_info=self.inputs.atlas_info,
compute_curvature=self.inputs.compute_curvature,
additional_maps=additional_maps,
output_types=self.inputs.output_types)
if 'cff' in self.inputs.output_types:
cvt = cmtk.CFFConverter()
cvt.inputs.title = 'Connectome mapper'
cvt.inputs.nifti_volumes = self.inputs.roi_volumes
cvt.inputs.tract_files = ['streamline_final.trk']
cvt.inputs.gpickled_networks = glob.glob(
os.path.abspath("connectome_*.gpickle"))
cvt.run()
return runtime
def _list_outputs(self):
outputs = self._outputs().get()
outputs['endpoints_file'] = os.path.abspath('endpoints.npy')
outputs['endpoints_mm_file'] = os.path.abspath('endpointsmm.npy')
outputs['final_fiberslength_files'] = glob.glob(
os.path.abspath('final_fiberslength*'))
outputs['filtered_fiberslabel_files'] = glob.glob(
os.path.abspath('filtered_fiberslabel*'))
outputs['final_fiberlabels_files'] = glob.glob(
os.path.abspath('final_fiberlabels*'))
outputs['streamline_final_file'] = os.path.abspath(
'streamline_final.trk')
outputs['connectivity_matrices'] = glob.glob(
os.path.abspath('connectome*'))
return outputs
class rsfmri_conmat_InputSpec(BaseInterfaceInputSpec):
func_file = File(exists=True, mandatory=True, desc="fMRI volume")
roi_volumes = InputMultiPath(File(exists=True),
desc='ROI volumes registered to functional space')
roi_graphmls = InputMultiPath(File(exists=True),
desc='GraphML description file for ROI volumes (used only if parcellation_scheme == Lausanne2018)')
parcellation_scheme = traits.Enum('Lausanne2008', ['Lausanne2008', 'Lausanne2018', 'NativeFreesurfer', 'Custom'],
desc="Parcellation scheme",
usedefault=True)
atlas_info = Dict(mandatory=False, desc="custom atlas information")
apply_scrubbing = Bool(False, desc="Apply scrubbing")
FD = File(exists=True, desc="FD file if scrubbing is performed")
FD_th = Float(desc="FD threshold")
DVARS = File(exists=True, desc="DVARS file if scrubbing is performed")
DVARS_th = Float(desc="DVARS threshold")
output_types = traits.List(Str,
desc='Output types of the connectivity matrices')
class rsfmri_conmat_OutputSpec(TraitedSpec):
avg_timeseries = OutputMultiPath(File(exists=True),
desc="ROI average timeseries")
scrubbed_idx = File(exists=True,
desc="Scrubbed indices")
connectivity_matrices = OutputMultiPath(File(exists=True),
desc="Functional connectivity matrices")
class rsfmri_conmat(BaseInterface):
"""Creates the functional connectivity matrices for a given parcellation scheme.
It applies scrubbing (if enabled), computes the average GM ROI time-series and computes
the Pearson's correlation coefficient between each GM ROI time-series poir.
Examples
--------
>>> from cmtklib.connectome import rsfmri_conmat
>>> cmat = rsfmri_conmat()
>>> cmat.inputs.base_dir = '/my_directory'
>>> cmat.inputs.func_file = '/path/to/sub-01_task-rest_desc-preproc_bold.nii.gz'
>>> cmat.inputs.roi_volumes = ['/path/to/sub-01_space-meanBOLD_atlas-L2018_desc-scale1_dseg.nii.gz',
>>> '/path/to/sub-01_space-meanBOLD_atlas-L2018_desc-scale2_dseg.nii.gz',
>>> '/path/to/sub-01_space-meanBOLD_atlas-L2018_desc-scale3_dseg.nii.gz',
>>> '/path/to/sub-01_space-meanBOLD_atlas-L2018_desc-scale4_dseg.nii.gz',
>>> '/path/to/sub-01_space-meanBOLD_atlas-L2018_desc-scale5_dseg.nii.gz']
>>> cmat.inputs.roi_graphmls = ['/path/to/sub-01_atlas-L2018_desc-scale1_dseg.graphml',
>>> '/path/to/sub-01_atlas-L2018_desc-scale2_dseg.graphml',
>>> '/path/to/sub-01_atlas-L2018_desc-scale3_dseg.graphml',
>>> '/path/to/sub-01_atlas-L2018_desc-scale4_dseg.graphml',
>>> '/path/to/sub-01_atlas-L2018_desc-scale5_dseg.graphml']
>>> cmat.inputs.parcellation scheme = 'Lausanne2018'
>>> cmat.inputs.apply_scrubbing = False
>>> cmat.inputs.output_types = ['gPickle','mat','graphml']
>>> cmat.run() # doctest: +SKIP
"""
input_spec = rsfmri_conmat_InputSpec
output_spec = rsfmri_conmat_OutputSpec
def _run_interface(self, runtime):
print("Compute average rs-fMRI signal for each cortical ROI")
print("====================================================")
fdata = nib.load(self.inputs.func_file).get_data()
tp = fdata.shape[3]
# OLD
# if self.inputs.parcellation_scheme != "Custom":
# resolutions = get_parcellation(self.inputs.parcellation_scheme)
# else:
# resolutions = self.inputs.atlas_info
# NEW
print('Parcellation_scheme : %s' % self.inputs.parcellation_scheme)
if self.inputs.parcellation_scheme != "Custom":
if self.inputs.parcellation_scheme != "Lausanne2018":
print("get resolutions from parcellation_scheme")
resolutions = get_parcellation(self.inputs.parcellation_scheme)
else:
resolutions = get_parcellation(self.inputs.parcellation_scheme)
for parkey, parval in list(resolutions.items()):
for vol, graphml in zip(self.inputs.roi_volumes, self.inputs.roi_graphmls):
print(parkey)
if parkey in vol:
roi_fname = vol
print(roi_fname)
if parkey in graphml:
roi_graphml_fname = graphml
print(roi_graphml_fname)
# roi_fname = roi_volumes[r]
# r += 1
roi = nib.load(roi_fname)
roiData = roi.get_data()
resolutions[parkey]['number_of_regions'] = roiData.max()
resolutions[parkey]['node_information_graphml'] = os.path.abspath(
roi_graphml_fname)
del roi, roiData
print("##################################################")
print("Atlas info (Lausanne2018) :")
print(resolutions)
print("##################################################")
else:
print("get resolutions from atlas_info: ")
resolutions = self.inputs.atlas_info
print(resolutions)
index = np.linspace(0, tp - 1, tp).astype('int')
# if self.inputs.apply_scrubbing:
# # load scrubbing FD and DVARS series
# FD = np.load( self.inputs.FD )
# DVARS = np.load( self.inputs.DVARS )
# # evaluate scrubbing mask
# FD_th = self.inputs.FD_th
# DVARS_th = self.inputs.DVARS_th
# FD_mask = np.array(np.nonzero(FD < FD_th))[0,:]
# DVARS_mask = np.array(np.nonzero(DVARS < DVARS_th))[0,:]
# index = np.sort(np.unique(np.concatenate((FD_mask,DVARS_mask)))) + 1
# index = np.concatenate(([0],index))
# log_scrubbing = "DISCARDED time points after scrubbing: " + str(FD.shape[0]-index.shape[0]+1) + " over " + str(FD.shape[0]+1)
# print(log_scrubbing)
# np.save( os.path.abspath( 'tp_after_scrubbing.npy'), index )
# sio.savemat( os.path.abspath('tp_after_scrubbing.mat'), {'index':index} )
# else:
# index = np.linspace(0,tp-1,tp).astype('int')
# loop throughout all the resolutions ('scale33', ..., 'scale500')
for parkey, parval in list(resolutions.items()):
print("Resolution = " + parkey)
# Open the corresponding ROI
print("Open the corresponding ROI")
for vol in self.inputs.roi_volumes:
if (parkey in vol) or (len(self.inputs.roi_volumes) == 1):
roi_fname = vol
print(roi_fname)
roi = nib.load(roi_fname)
mask = roi.get_data()
# Compute average time-series
# nROIs: number of ROIs for current resolution
nROIs = parval['number_of_regions']
# matrix number of rois vs timepoints
ts = np.zeros((nROIs, tp), dtype=np.float32)
# loop throughout all the ROIs (current resolution)
for i in range(1, nROIs + 1):
ts[i - 1, :] = fdata[mask == i].mean(axis=0)
print("ts_shape:", ts.shape)
np.save(os.path.abspath('averageTimeseries_%s.npy' % parkey), ts)
sio.savemat(os.path.abspath(
'averageTimeseries_%s.mat' % parkey), {'ts': ts})
# Apply scrubbing (if enabled) and compute correlation
# loop throughout all the resolutions ('scale33', ..., 'scale500')
for parkey, parval in list(resolutions.items()):
print("Resolution = " + parkey)
# Open the corresponding ROI
print("Open the corresponding ROI")
for vol in self.inputs.roi_volumes:
if parkey in vol:
roi_fname = vol
print(roi_fname)
roi = nib.load(roi_fname)
roiData = roi.get_data()
# Average roi time-series
ts = np.load(os.path.abspath('averageTimeseries_%s.npy' % parkey))
# nROIs: number of ROIs for current resolution
nROIs = parval['number_of_regions']
# Create matrix, add node information from parcellation and recover ROI indexes
print("Create the connection matrix (%s rois)" % nROIs)
G = nx.Graph()
gp = nx.read_graphml(parval['node_information_graphml'])
ROI_idx = []
for u, d in gp.nodes(data=True):
G.add_node(int(u))
for key in d:
G.nodes[int(u)][key] = d[key]
# compute a position for the node based on the mean position of the
# ROI in voxel coordinates (segmentation volume )
if self.inputs.parcellation_scheme != "Lausanne2018":
G.nodes[int(u)]['dn_position'] = tuple(
np.mean(np.where(mask == int(d["dn_correspondence_id"])), axis=1))
ROI_idx.append(int(d["dn_correspondence_id"]))
else:
G.nodes[int(u)]['dn_position'] = tuple(
np.mean(np.where(mask == int(d["dn_multiscaleID"])), axis=1))
ROI_idx.append(int(d["dn_multiscaleID"]))
# # matrix number of rois vs timepoints
# ts = np.zeros( (nROIs,tp), dtype = np.float32 )
#
# # loop throughout all the ROIs (current resolution)
# roi_line = 0
# for i in ROI_idx:
# ts[roi_line,:] = fdata[roiData==i].mean( axis = 0 )
# roi_line += 1
#
# np.save( os.path.abspath('averageTimeseries_%s.npy' % parkey), ts )
# sio.savemat( os.path.abspath('averageTimeseries_%s.mat' % parkey), {'TCS':ts} )
# Censoring time-series
if self.inputs.apply_scrubbing:
# load scrubbing FD and DVARS series
FD = np.load(self.inputs.FD)
DVARS = np.load(self.inputs.DVARS)
# evaluate scrubbing mask
FD_th = self.inputs.FD_th
DVARS_th = self.inputs.DVARS_th
FD_mask = np.array(np.nonzero(FD < FD_th))[0, :]
DVARS_mask = np.array(np.nonzero(DVARS < DVARS_th))[0, :]
index = np.sort(
np.unique(np.concatenate((FD_mask, DVARS_mask)))) + 1
index = np.concatenate(([0], index))
log_scrubbing = "DISCARDED time points after scrubbing: " + str(
FD.shape[0] - index.shape[0] + 1) + " over " + str(FD.shape[0] + 1)
print(log_scrubbing)
np.save(os.path.abspath('tp_after_scrubbing.npy'), index)
sio.savemat(os.path.abspath(
'tp_after_scrubbing.mat'), {'index': index})
ts_after_scrubbing = ts[:, index]
np.save(os.path.abspath(
'averageTimeseries_%s_after_scrubbing.npy' % parkey), ts_after_scrubbing)
sio.savemat(os.path.abspath('averageTimeseries_%s_after_scrubbing.mat' % parkey),
{'ts': ts_after_scrubbing})
ts = ts_after_scrubbing
print('ts.shape : ', ts.shape)
# initialize connectivity matrix
nnodes = ts.shape[0]
i = -1
for i_signal in ts:
i += 1
for j in range(i, nnodes):
j_signal = ts[j, :]
value = np.corrcoef(i_signal, j_signal)[0, 1]
G.add_edge(ROI_idx[i], ROI_idx[j])
G[ROI_idx[i]][ROI_idx[j]]['corr'] = value
# fmat[i,j] = value
# fmat[j,i] = value
# np.save( op.join(gconf.get_timeseries(), 'fconnectome_%s_after_scrubbing.npy' % s), fmat )
# sio.savemat( op.join(gconf.get_timeseries(),
# 'fconnectome_%s_after_scrubbing.mat' % s), {'fmat':fmat} )
else:
nnodes = ts.shape[0]
i = -1
for i_signal in ts:
i += 1
for j in range(i, nnodes):
j_signal = ts[j, :]
value = np.corrcoef(i_signal, j_signal)[0, 1]
G.add_edge(ROI_idx[i], ROI_idx[j])
G[ROI_idx[i]][ROI_idx[j]]['corr'] = value
# fmat[i,j] = value
# fmat[j,i] = value
# np.save( op.join(gconf.get_timeseries(), 'fconnectome_%s.npy' % s), fmat )
# sio.savemat( op.join(gconf.get_timeseries(), 'fconnectome_%s.mat' % s), {'fmat':fmat} )
# Get the edge attributes/keys/weights from the first edge and then break.
# Change w.r.t networkx2
edge_keys = []
for _, _, d in G.edges(data=True):
# print(list(d.keys()))
edge_keys = list(d.keys())
break
print(' - connectome_%s.tsv' % parkey)
with open('connectome_%s.tsv' % parkey, 'w') as out_file:
tsv_writer = csv.writer(out_file, delimiter='\t')
header = ['source', 'target']
header = header + [key for key in edge_keys]
tsv_writer.writerow(header)
with open('connectome_%s.tsv' % parkey, 'ab') as out_file:
nx.write_edgelist(G,
out_file,
comments='#',
delimiter='\t',
data=edge_keys,
encoding='utf-8')
# storing network
if 'gPickle' in self.inputs.output_types:
nx.write_gpickle(G, 'connectome_%s.gpickle' % parkey)
if 'mat' in self.inputs.output_types:
# edges
# size_edges = (int(parval['number_of_regions']), int(
# parval['number_of_regions']))
edge_struct = {}
for edge_key in edge_keys:
edge_struct[edge_key] = nx.to_numpy_matrix(
G, weight=edge_key)
# nodes
size_nodes = int(parval['number_of_regions'])
# Get the node attributes/keys from the first node and then break.
# Change w.r.t networkx2
for u, d in G.nodes(data=True):
node_keys = list(d.keys())
break
node_struct = {}
for node_key in node_keys:
if node_key == 'dn_position':
node_arr = np.zeros([size_nodes, 3], dtype=np.float)
else:
node_arr = np.zeros(size_nodes, dtype=np.object_)
node_n = 0
for _, node_data in G.nodes(data=True):
node_arr[node_n] = node_data[node_key]
node_n += 1
node_struct[node_key] = node_arr
sio.savemat('connectome_%s.mat' % parkey, mdict={
'sc': edge_struct, 'nodes': node_struct})
if 'graphml' in self.inputs.output_types and self.inputs.parcellation_scheme != "Lausanne2018":
g2 = nx.Graph()
for u_gml, d_gml in G.nodes(data=True):
g2.add_node(u_gml, {'dn_correspondence_id': d_gml['dn_correspondence_id'],
'dn_fsname': d_gml['dn_fsname'],
'dn_hemisphere': d_gml['dn_hemisphere'],
'dn_name': d_gml['dn_name'],
'dn_position_x': float(d_gml['dn_position'][0]),
'dn_position_y': float(d_gml['dn_position'][1]),
'dn_position_z': float(d_gml['dn_position'][2]),
'dn_region': d_gml['dn_region']})
for u_gml, v_gml, d_gml in G.edges(data=True):
g2.add_edge(u_gml, v_gml, {'corr': float(d_gml['corr'])})
nx.write_graphml(g2, 'connectome_%s.graphml' % parkey)
if 'graphml' in self.inputs.output_types and (
self.inputs.parcellation_scheme == "Lausanne2018" or self.inputs.parcellation_scheme == 'NativeFreesurfer'):
g2 = nx.Graph()
for u_gml, d_gml in G.nodes(data=True):
g2.add_node(u_gml, {'dn_multiscaleID': d_gml['dn_multiscaleID'],
'dn_fsname': d_gml['dn_fsname'],
'dn_hemisphere': d_gml['dn_hemisphere'],
'dn_name': d_gml['dn_name'],
'dn_position_x': float(d_gml['dn_position'][0]),
'dn_position_y': float(d_gml['dn_position'][1]),
'dn_position_z': float(d_gml['dn_position'][2]),
'dn_region': d_gml['dn_region']})
for u_gml, v_gml, d_gml in G.edges(data=True):
g2.add_edge(u_gml, v_gml, {'corr': float(d_gml['corr'])})
nx.write_graphml(g2, 'connectome_%s.graphml' % parkey)
if 'cff' in self.inputs.output_types:
cvt = cmtk.CFFConverter()
cvt.inputs.title = 'Connectome mapper'
cvt.inputs.nifti_volumes = self.inputs.roi_volumes
cvt.inputs.gpickled_networks = glob.glob(
os.path.abspath("connectome_*.gpickle"))
cvt.run()
print("[ DONE ]")
return runtime
def _list_outputs(self):
outputs = self._outputs().get()
outputs['connectivity_matrices'] = glob.glob(
os.path.abspath('connectome*'))
outputs['avg_timeseries'] = glob.glob(
os.path.abspath('averageTimeseries_*'))
if self.inputs.apply_scrubbing:
outputs['scrubbed_idx'] = os.path.abspath('tp_after_scrubbing.npy')
return outputs
# OLD implementations
# class MRTrix3BaseInputSpec(CommandLineInputSpec):
# nthreads = traits.Int(
# argstr='-nthreads %d', desc='number of threads. if zero, the number'
# ' of available cpus will be used', nohash=True)
# # DW gradient table import options
# grad_file = File(exists=True, argstr='-grad %s',
# desc='dw gradient scheme (MRTrix format')
# grad_fsl = traits.Tuple(
# File(exists=True), File(exists=True), argstr='-fslgrad %s %s',
# desc='(bvecs, bvals) dw gradient scheme (FSL format')
# bval_scale = traits.Enum(
# 'yes', 'no', argstr='-bvalue_scaling %s',
# desc='specifies whether the b - values should be scaled by the square'
# ' of the corresponding DW gradient norm, as often required for '
# 'multishell or DSI DW acquisition schemes. The default action '
# 'can also be set in the MRtrix config file, under the '
# 'BValueScaling entry. Valid choices are yes / no, true / '
# 'false, 0 / 1 (default: true).')
# in_bvec = File(exists=True, argstr='-fslgrad %s %s',
# desc='bvecs file in FSL format')
# in_bval = File(exists=True, desc='bvals file in FSL format')
# class MRTrix3Base(CommandLine):
# def _format_arg(self, name, trait_spec, value):
# if name == 'nthreads' and value == 0:
# value = 1
# try:
# from multiprocessing import cpu_count
# value = cpu_count()
# except:
# logger.warn('Number of threads could not be computed')
# pass
# return trait_spec.argstr % value
# if name == 'in_bvec':
# return trait_spec.argstr % (value, self.inputs.in_bval)
# return super(MRTrix3Base, self)._format_arg(name, trait_spec, value)
# def _parse_inputs(self, skip=None):
# if skip is None:
# skip = []
# try:
# if (isdefined(self.inputs.grad_file) or
# isdefined(self.inputs.grad_fsl)):
# skip += ['in_bvec', 'in_bval']
# is_bvec = isdefined(self.inputs.in_bvec)
# is_bval = isdefined(self.inputs.in_bval)
# if is_bvec or is_bval:
# if not is_bvec or not is_bval:
# raise RuntimeError('If using bvecs and bvals inputs, both'
# 'should be defined')
# skip += ['in_bval']
# except AttributeError:
# pass
# return super(MRTrix3Base, self)._parse_inputs(skip=skip)
# class BuildConnectomeInputSpec(CommandLineInputSpec):
# in_file = File(exists=True, argstr='%s', mandatory=True, position=-3,
# desc='input tractography')
# in_parc = File(exists=True, argstr='%s', position=-2,
# desc='parcellation file')
# out_file = File(
# 'connectome.csv', argstr='%s', mandatory=True, position=-1,
# usedefault=True, desc='output file after processing')
# nthreads = traits.Int(
# argstr='-nthreads %d', desc='number of threads. if zero, the number'
# ' of available cpus will be used', nohash=True)
# vox_lookup = traits.Bool(
# argstr='-assignment_voxel_lookup',
# desc='use a simple voxel lookup value at each streamline endpoint')
# search_radius = traits.Float(
# argstr='-assignment_radial_search %f',
# desc='perform a radial search from each streamline endpoint to locate '
# 'the nearest node. Argument is the maximum radius in mm; if no node is'
# ' found within this radius, the streamline endpoint is not assigned to'
# ' any node.')
# search_reverse = traits.Float(
# argstr='-assignment_reverse_search %f',
# desc='traverse from each streamline endpoint inwards along the '
# 'streamline, in search of the last node traversed by the streamline. '
# 'Argument is the maximum traversal length in mm (set to 0 to allow '
# 'search to continue to the streamline midpoint).')
# search_forward = traits.Float(
# argstr='-assignment_forward_search %f',
# desc='project the streamline forwards from the endpoint in search of a'
# 'parcellation node voxel. Argument is the maximum traversal length in '
# 'mm.')
# metric = traits.Enum(
# 'count', 'meanlength', 'invlength', 'invnodevolume', 'mean_scalar',
# 'invlength_invnodevolume', argstr='-metric %s', desc='specify the edge'
# ' weight metric')
# in_scalar = File(
# exists=True, argstr='-image %s', desc='provide the associated image '
# 'for the mean_scalar metric')
# in_weights = File(
# exists=True, argstr='-tck_weights_in %s', desc='specify a text scalar '
# 'file containing the streamline weights')
# keep_unassigned = traits.Bool(
# argstr='-keep_unassigned', desc='By default, the program discards the'
# ' information regarding those streamlines that are not successfully '
# 'assigned to a node pair. Set this option to keep these values (will '
# 'be the first row/column in the output matrix)')
# zero_diagonal = traits.Bool(
# argstr='-zero_diagonal', desc='set all diagonal entries in the matrix '
# 'to zero (these represent streamlines that connect to the same node at'
# ' both ends)')
# class BuildConnectomeOutputSpec(TraitedSpec):
# out_file = File(exists=True, desc='the output response file')
# class BuildConnectome(MRTrix3Base):
# """
# Generate a connectome matrix from a streamlines file and a node
# parcellation image
# Example
# -------
# >>> import nipype.interfaces.mrtrix3 as mrt
# >>> mat = mrt.BuildConnectome()
# >>> mat.inputs.in_file = 'tracks.tck'
# >>> mat.inputs.in_parc = 'aparc+aseg.nii'
# >>> mat.cmdline # doctest: +ELLIPSIS +ALLOW_UNICODE
# 'tck2connectome tracks.tck aparc+aseg.nii connectome.csv'
# >>> mat.run() # doctest: +SKIP
# """
# _cmd = 'tck2connectome'
# input_spec = BuildConnectomeInputSpec
# output_spec = BuildConnectomeOutputSpec
# def _list_outputs(self):
# outputs = self.output_spec().get()
# outputs['out_file'] = op.abspath(self.inputs.out_file)
# return outputs
# def mrtrixcmat(intck, fod_file, roi_volumes, parcellation_scheme, compute_curvature=True, additional_maps={},
# output_types=['gPickle'], atlas_info={}):
# """ Create the connection matrix using MRTrix fibers and Freesurfer ROIs. """
# conflow = pe.Workflow(name='MRTRix_connectome_pipeline')
# # connectome_inputnode = pe.Node(interface=util.IdentityInterface(fields=['intck','fod_file','roi_volumes']),name='inputnode')
# # connectome_outputnode = pe.Node(interface=util.IdentityInterface(fields=['connectome']),name='outputnode')
# print "INTCK : ", intck
# fibers_filter = pe.Node(interface=FilterTractogram(), name='fibers_filter')
# fibers_filter.inputs.in_tracks = op.intck
# fibers_filter.inputs.in_fod = fod_file
# fibers_filter.inputs.out_file = 'streamlines_weights.txt'
# connectome_builder = pe.Node(interface=BuildConnectome(), name='connectome_builder')
# connectome_builder.inputs.in_tracks = intck
# connectome_builder.inputs.in_parc = roi_volumes
# connectome_builder.inputs.zero_diagonal = True
# conflow.connect([
# (fibers_filter, connectome_builder, [('out_weights', 'in_weights')]),
# ])
# conflow.run()