def test_find_cut_slices(): data = np.zeros((50, 50, 50)) x_map, y_map, z_map = 25, 5, 20 data[x_map - 15:x_map + 15, y_map - 3:y_map + 3, z_map - 10:z_map + 10] = 1 img = nibabel.Nifti1Image(data, np.eye(4)) for n_cuts in (2, 4): for direction in 'xz': cuts = find_cut_slices(img, direction=direction, n_cuts=n_cuts, spacing=2) # Test that we are indeed getting the right number of cuts assert_equal(len(cuts), n_cuts) # Test that we are not getting cuts that are separated by # less than the minimum spacing that we asked for assert_equal(np.diff(cuts).min(), 2) # Test that the cuts indeed go through the 'activated' part # of the data for cut in cuts: if direction == 'x': cut_value = data[cut] elif direction == 'z': cut_value = data[..., cut] assert_equal(cut_value.max(), 1) # Now ask more cuts than it is possible to have with a given spacing n_cuts = 15 for direction in 'xz': # Only a smoke test cuts = find_cut_slices(img, direction=direction, n_cuts=n_cuts, spacing=2)
def test_passing_of_ncuts_in_find_cut_slices(): data = np.zeros((50, 50, 50)) affine = np.eye(4) x_map, y_map, z_map = 25, 5, 20 data[x_map - 15:x_map + 15, y_map - 3:y_map + 3, z_map - 10:z_map + 10] = 1 img = nibabel.Nifti1Image(data, affine) # smoke test to check if it rounds the floating point inputs for n_cuts in (1, 5., 0.9999999, 2.000000004): cut1 = find_cut_slices(img, direction='x', n_cuts=n_cuts) cut2 = find_cut_slices(img, direction='x', n_cuts=round(n_cuts)) np.testing.assert_array_equal(cut1, cut2)
def test_find_cut_slices(): data = np.zeros((50, 50, 50)) x_map, y_map, z_map = 25, 5, 20 data[x_map - 15:x_map + 15, y_map - 3:y_map + 3, z_map - 10:z_map + 10] = 1 img = nibabel.Nifti1Image(data, np.eye(4)) for n_cuts in (2, 4): for direction in 'xz': cuts = find_cut_slices(img, direction=direction, n_cuts=n_cuts, spacing=2) # Test that we are indeed getting the right number of cuts assert len(cuts) == n_cuts # Test that we are not getting cuts that are separated by # less than the minimum spacing that we asked for assert np.diff(cuts).min() == 2 # Test that the cuts indeed go through the 'activated' part # of the data for cut in cuts: if direction == 'x': cut_value = data[int(cut)] elif direction == 'z': cut_value = data[..., int(cut)] assert cut_value.max() == 1 # Now ask more cuts than it is possible to have with a given spacing n_cuts = 15 for direction in 'xz': # Only a smoke test cuts = find_cut_slices(img, direction=direction, n_cuts=n_cuts, spacing=2) # non-diagonal affines affine = np.array([[-1., 0., 0., 123.46980286], [0., 0., 1., -94.11079407], [0., -1., 0., 160.694], [0., 0., 0., 1.]]) img = nibabel.Nifti1Image(data, affine) cuts = find_cut_slices(img, direction='z') assert np.diff(cuts).min() != 0. affine = np.array([[-2., 0., 0., 123.46980286], [0., 0., 2., -94.11079407], [0., -2., 0., 160.694], [0., 0., 0., 1.]]) img = nibabel.Nifti1Image(data, affine) cuts = find_cut_slices(img, direction='z') assert np.diff(cuts).min() != 0. # Rotate it slightly angle = np.pi / 180 * 15 rotation_matrix = np.array([[np.cos(angle), -np.sin(angle)], [np.sin(angle), np.cos(angle)]]) affine[:2, :2] = rotation_matrix * 2.0 img = nibabel.Nifti1Image(data, affine) cuts = find_cut_slices(img, direction='z') assert np.diff(cuts).min() != 0.
def test_validity_of_ncuts_error_in_find_cut_slices(): data = np.zeros((50, 50, 50)) affine = np.eye(4) x_map, y_map, z_map = 25, 5, 20 data[x_map - 15:x_map + 15, y_map - 3:y_map + 3, z_map - 10:z_map + 10] = 1 img = nibabel.Nifti1Image(data, affine) direction = 'z' for n_cuts in (0, -2, -10.00034, 0.999999, 0.4, 0.11111111): message = ( "Image has %d slices in direction %s. Therefore, the number " "of cuts must be between 1 and %d. You provided n_cuts=%s " % (data.shape[0], direction, data.shape[0], n_cuts)) with pytest.raises(ValueError, match=message): find_cut_slices(img, n_cuts=n_cuts)
def test_validity_of_ncuts_error_in_find_cut_slices(): data = np.zeros((50, 50, 50)) affine = np.eye(4) x_map, y_map, z_map = 25, 5, 20 data[x_map - 15:x_map + 15, y_map - 3:y_map + 3, z_map - 10:z_map + 10] = 1 img = nibabel.Nifti1Image(data, affine) for direction, n_cuts in zip('xyz', (0, -2, -10.00034)): message = ("The number of cuts in the given direction %s must be an " "integer which should be greater than 0 and less than " "or equal to %d. You provided n_cuts=%s" % ( direction, data.shape[0], n_cuts)) assert_raises_regex(ValueError, message, find_cut_slices, img, direction=direction, n_cuts=n_cuts) # smoke test to check if it rounds the floating point inputs n_cuts = [0.999999, 9.99999, 1, 5., 10.0000045] for n_cut in n_cuts: find_cut_slices(img, direction='x', n_cuts=n_cut)
def test_validity_of_ncuts_error_in_find_cut_slices(): data = np.zeros((50, 50, 50)) affine = np.eye(4) x_map, y_map, z_map = 25, 5, 20 data[x_map - 15:x_map + 15, y_map - 3:y_map + 3, z_map - 10:z_map + 10] = 1 img = nibabel.Nifti1Image(data, affine) for direction, n_cuts in zip('xyz', (0, -2, -10.00034)): message = ("The number of cuts in the given direction %s must be an " "integer which should be greater than 0 and less than " "or equal to %d. You provided n_cuts=%s" % (direction, data.shape[0], n_cuts)) assert_raises_regex(ValueError, message, find_cut_slices, img, direction=direction, n_cuts=n_cuts) # smoke test to check if it rounds the floating point inputs n_cuts = [0.999999, 9.99999, 1, 5., 10.0000045] for n_cut in n_cuts: find_cut_slices(img, direction='x', n_cuts=n_cut)
def test_outlier_cut_coords(): """Test to plot a subset of a large set of cuts found for a small area.""" bg_img = load_mni152_template() data = np.zeros((79, 95, 79)) affine = np.array([[-2., 0., 0., 78.], [0., 2., 0., -112.], [0., 0., 2., -70.], [0., 0., 0., 1.]]) # Color a cube around a corner area: x, y, z = 20, 22, 60 x_map, y_map, z_map = coord_transform(x, y, z, np.linalg.inv(affine)) data[int(x_map) - 1:int(x_map) + 1, int(y_map) - 1:int(y_map) + 1, int(z_map) - 1:int(z_map) + 1] = 1 img = Nifti1Image(data, affine) cuts = find_cut_slices(img, n_cuts=20, direction='z') plot_stat_map(img, display_mode='z', cut_coords=cuts[-4:], bg_img=bg_img)
def test_outlier_cut_coords(): """ Test to plot a subset of a large set of cuts found for a small area.""" bg_img = load_mni152_template() data = np.zeros((79, 95, 79)) affine = np.array([[ -2., 0., 0., 78.], [ 0., 2., 0., -112.], [ 0., 0., 2., -70.], [ 0., 0., 0., 1.]]) # Color a cube around a corner area: x, y, z = 20, 22, 60 x_map, y_map, z_map = coord_transform(x, y, z, np.linalg.inv(affine)) data[int(x_map) - 1:int(x_map) + 1, int(y_map) - 1:int(y_map) + 1, int(z_map) - 1:int(z_map) + 1] = 1 img = nibabel.Nifti1Image(data, affine) cuts = find_cut_slices(img, n_cuts=20, direction='z') p = plot_stat_map(img, display_mode='z', cut_coords=cuts[-4:], bg_img=bg_img)
def test_singleton_ax_dim(): for axis, direction in enumerate("xyz"): shape = [5, 6, 7] shape[axis] = 1 img = nibabel.Nifti1Image(np.ones(shape), np.eye(4)) find_cut_slices(img, direction=direction)
z_maps = {} for condition_id in event_types: z_maps[condition_id] = glm.transform(contrasts[condition_id], contrast_name=condition_id, output_z=True, output_stat=False, output_effects=False, output_variance=False) fig, axx = plt.subplots(nrows=len(event_types), ncols=2, figsize=(8, 8)) for i, ((cond_id, mask), (condition_id, z_map)) in enumerate( zip(masks.items(), z_maps.items())): img_z_map = z_map[0].get_data() niimg = nb.Nifti1Image(mask.astype('int'), affine=np.eye(4)) cuts = find_cuts.find_cut_slices(niimg) axx[i, 0].imshow(mask[..., cuts[0]]) axx[i, 1].imshow(img_z_map[..., cuts[0]]) axx[i, 1].set_title('z map: %s' % condition_id) axx[i, 0].set_title('ground truth: %s' % condition_id) axx[i, 0].axis('off') axx[i, 1].axis('off') plt.hot() plt.show()
def plotGlassbrainSlices(niftipath, mnipath, ortho='z', nRows=2, nCuts=6, threshpos=0, threshneg=0, figLayout='Both', showLRannot=True, findOptimalCut=True, imageType='svg'): """ Creates nice glassbrain slice figures in the direction x, y and z """ # Initiation of relevant parameters img = nb.load(niftipath) lineW = 2. / (nRows + int((figLayout == 'Brain' or figLayout == 'Both'))) # Reduce 4D volume to 3D if len(img.shape) == 4: data4D = img.get_data() data4D = data4D.reshape(data4D.shape[:-1]) img = Nifti1Image(data4D, img.get_affine()) # Get voxel extend in all directions dirMin = np.dot(img.get_affine(), [0, 0, 0, 1])[:3] dirMax = np.dot(img.get_affine(), np.array(img.shape).tolist() + [1])[:3] if findOptimalCut: # Find cuts automatically cut_coords = find_cut_slices(img, direction=ortho, n_cuts=nCuts) else: # Split orientation in x-equal parts cut_coords = getEqualSpacing(dirMin, dirMax, ortho, nCuts) # Split cuts according nRows cut_coords = [cut_coords[int(i * len(cut_coords) / np.float(nRows)): int((i + 1) * len(cut_coords) / np.float(nRows))] for i in range(nRows)] # Create Slices for i in range(nRows): # Create axes for plotting ax = plt.subplot(nRows + int((figLayout == 'Brain' or figLayout == 'Both')), 1, i + 1) # Plot the white background for all slices as a zeros value brain # (without it, the view focuses around the first area plotted) zerobrain = Nifti1Image(img.get_data() * 0, img.get_affine()) brain = plot_roi( zerobrain, zerobrain, colorbar=False, cut_coords=cut_coords[i], display_mode=ortho, alpha=1, draw_cross=False, cmap=plt.cm.gray, black_bg=False, axes=ax, annotate=False) # Plot positive values posdata = np.copy(img.get_data()) posdata[posdata <= threshpos] = 0.001 # = 0 crashes contour function posbrain = Nifti1Image(posdata, img.get_affine()) brain.add_contours( posbrain, filled=False, cmap=plt.cm.hot, alpha=1, linewidths=lineW) # Plot negative values negdata = np.copy(img.get_data()) negdata[negdata >= -threshneg] = 0.001 # = 0 crashes contour function negbrain = Nifti1Image(negdata, img.get_affine()) brain.add_contours( negbrain, filled=False, cmap=plt.cm.winter, alpha=1, linewidths=lineW) # Plot outer MNI contours brain.add_contours( smooth_img(mnipath, 4), alpha=1, filled=False, levels=[100], linewidths=lineW, cmap=plt.cm.gray) # Plot inner MNI contours brain.add_contours( nb.load(mnipath), alpha=0.8, levels=[5000], linewidths=lineW, cmap=plt.cm.gray) # Add annotation if requested if figLayout == 'Both' or figLayout == 'Number': brain.annotate(left_right=showLRannot, size=int(12 * lineW)) # Plot overview Brain at the bottom if figLayout == 'Brain' or figLayout == 'Both': # Create axes for overview brain ax = plt.subplot(nRows + 1, 1, nRows + 1) # Find overview view direction if ortho == 'z': direction = 'x' elif ortho == 'x': direction = 'z' elif ortho == 'y': direction = 'z' # Plot the white backgroundas a zeros value brain brain = plot_roi( zerobrain, zerobrain, colorbar=False, cut_coords=[0], display_mode=direction, alpha=1, draw_cross=False, cmap=plt.cm.gray, black_bg=False, axes=ax, annotate=False) # Plot positive values brain.add_contours( posbrain, filled=False, cmap=plt.cm.hot, alpha=1, linewidths=lineW) # Plot negative values brain.add_contours( negbrain, filled=False, cmap=plt.cm.winter, alpha=1, linewidths=lineW) # Plot outer MNI contours brain.add_contours( smooth_img(mnipath, 4), alpha=1, filled=False, levels=[100], linewidths=lineW, cmap=plt.cm.gray) # Plot inner MNI contours brain.add_contours( nb.load(mnipath), alpha=0.8, levels=[5000], linewidths=lineW, cmap=plt.cm.gray) # Plot the line indicating the cut for i in np.array(cut_coords).flatten(): if ortho == 'z' or ortho == 'y': ax.plot([-100, 100], [i, i], 'k-', lw=lineW) elif ortho == 'x': ax.plot([i, i], [-100, 100], 'k-', lw=lineW) if ortho == 'z': ax.axis((-300.0, 300.0, dirMin[2], dirMax[2])) elif ortho == 'y': ax.axis((-300.0, 300.0, dirMin[1], dirMax[1])) elif ortho == 'x': stretcher = (nRows + 1) / 2. ax.axis((-300.0 * stretcher, 300.0 * stretcher, -100.0, 100.0)) # Add annotation if requested if figLayout == 'Both' or figLayout == 'Number': brain.annotate(left_right=showLRannot, size=int(12 * lineW)) # Get file prefix if niftipath.endswith('.nii'): filename = opb(niftipath)[:-4] elif niftipath.endswith('.nii.gz'): filename = opb(niftipath)[:-7] # Create output folder path2Figure = opj(os.path.split(os.path.realpath(niftipath))[0], 'figures') if not os.path.exists(opj(path2Figure)): os.makedirs(opj(path2Figure)) # Save figure figname = '_'.join([filename, '%s-cut' % ortho]) plt.savefig(opj(path2Figure, '%s.%s' % (figname, imageType))) plt.clf()
def plotZslices_alloption(niftipath,mnipath='',ortho='z',cut_coords='',Nraw=1,smoothing=0,LR=False,outdir='',colorpos='r',colorneg='b',Zannotate=False,thresholdpos='def',Zannotates='def',thresholdneg=False,alphamap=1,alphabrain=1): "niftipath: path to the nifti file, can be a 3D - if activation map, specify thresholds," "mnipath : path to the mni T1 brain "cut_coords can be a int as the number of zslices to display of a list of slices number (in MNI) (even list of one to get one specific slice)" "Nraw: the number of raw" "smoothing: number of voxel to smooth; LR:annotate left and right" "outdir:path to save the file" "color:list of color for each volume, or only one color, neg or pos if corresponding threshold to display" "Zannotate : Number=annotate z number, False=not annotate, Brain=on a X slice, with lign, or Both" "thresholdpos: specify threshold to cut and see above (can be a list for activation map: layer effect) or False will not be displayed or 'def' as 0.5 on normalized file" "thresholdneg: specify threshold to cut and see bellow (can be a list for activation map: layer effect) or False will not be displayed " import matplotlib.pyplot as plt import numpy as np import nilearn.plotting import nilearn.image from nilearn.plotting import plot_roi, plot_stat_map from nilearn.plotting.find_cuts import find_cut_slices from nilearn.image.image import mean_img import nibabel import seaborn as sns initialcol=sns.light_palette((0,0,0), as_cmap=True)#'Greys' data=nibabel.load(niftipath) datasize=data.get_shape() lineW=1./(Nraw+int((Zannotate=='Brain' or Zannotate=='Both'))) if mnipath=='': mnipath='/home/mrstats/maamen/Software/fsl/data/standard/MNI152_T1_1mm_brain.nii.gz' ##this only works for the donders institute (Nijmegen, The Neterlands) if type(cut_coords)==int or cut_coords=='': if cut_coords=='': cut_coords=6 #find best cut if len(datasize)==4: #for 4D nifti cut_coords=find_cut_slices(mean_img(nibabel.nifti1.Nifti1Image(np.sign(np.abs(data.get_data())),data.get_affine())), n_cuts=cut_coords) else: #for 3D nifti cut_coords=find_cut_slices(data, n_cuts=cut_coords) #split in N raw if cut_coords!=(0,0,0): cut_coords=np.array(cut_coords) cc=cut_coords cut_coords=[cut_coords[i*len(cut_coords)/np.float(Nraw):(i+1)*len(cut_coords)/np.float(Nraw)] for i in range(Nraw)] else: cut_coords=[cut_coords] #define color as a vector (length :the number of volume): #if not enought color are proveded, the last of them is repeated #color are defined independantly for negative value display and positive value display if type(colorneg)==str: colorneg=[colorneg] if type(colorpos)==str: colorpos=[colorpos] if len(datasize)==4 and len(colorpos)!=datasize[3]: provcol=colorpos[len(colorpos)-1] colorpos=np.concatenate([colorpos,[provcol for i in range(datasize[3]-len(colorpos))]]) if len(datasize)==4 and len(colorneg)!=datasize[3]: provcol=colorneg[len(colorneg)-1] colorneg=np.concatenate([colorneg,[provcol for i in range(datasize[3]-len(colorneg))]]) #adjust threshold by normalizing image in the default version and taking 0.5 if thresholdpos=='def': data=nibabel.nifti1.Nifti1Image(data.get_data()/np.float(np.max(data.get_data())),data.get_affine()) thresholdpos=[0.5] #organize thresholds, more than 1 threshold to make a layer effect, #positive and negative values display are treated independantly: if type(thresholdpos)!=np.bool: thresholdpos=[i for i in np.sort(thresholdpos)] if type(thresholdneg)!=np.bool: thresholdneg=[i for i in -np.sort(-1*np.array(thresholdneg))] #load data to create a white backgroung func=mean_img(nibabel.nifti1.Nifti1Image(np.sign(np.abs(data.get_data())),data.get_affine())) ####################subplot for i in range(Nraw): ax=plt.subplot(Nraw+int((Zannotate=='Brain' or Zannotate=='Both')),1,i+1) #plot the white backgroung as a zeros value brain (without it, the view focus aroung the first area plotted) brain=nilearn.plotting.plot_roi(nibabel.nifti1.Nifti1Image(np.zeros(func.get_shape()),data.get_affine()), nibabel.nifti1.Nifti1Image(np.zeros(func.get_shape()),data.get_affine()),colorbar=False,cut_coords=cut_coords[i],display_mode=ortho,alpha=1,draw_cross=False,cmap=initialcol,black_bg=False,axes=ax,annotate=False) ###############plot the volumes for Z brain slices if len(datasize)==3: iter_imgs=[data] else: iter_imgs=nilearn.image.iter_img(niftipath) j=0 for img in iter_imgs: ##plot the positive values if thresholdpos!=False: colorprovpos=sns.light_palette(colorpos[j],len(thresholdpos),reverse=True)[::-1] img2=nilearn.image.smooth_img(img,smoothing) ##plot the different threshold (layer effect) for the positive values for kn,k in enumerate(thresholdpos): brain.add_contours(img2,filled=True,levels=[k],cmap=None,colors=[[colorprovpos[kn][0],colorprovpos[kn][1],colorprovpos[kn][2]]],linewidths=lineW,alpha=k/np.max(thresholdpos))#alphamap) ##plot the negative values if thresholdneg!=False: colorprovneg=sns.light_palette(colorneg[j],len(thresholdneg),reverse=True)[::-1] #switch negative to positive img2=nibabel.nifti1.Nifti1Image(-1*nilearn.image.smooth_img(img,smoothing).get_data(),data.get_affine()) ##plot the negatives values for each negative threshold for kn,k in enumerate(thresholdneg): brain.add_contours(img2,filled=True,levels=[k],cmap=None,colors=[[colorprovneg[kn][0],colorprovneg[kn][1],colorprovneg[kn][2]]],linewidths=lineW,alpha=k/np.max(thresholdpos))#alphamap) j+=1 ##plot the brain contour for Z brain slices #externe brain.add_contours(nilearn.image.smooth_img(mnipath,5),alpha=1*alphabrain, levels=[95],linewidths=lineW, cmap=sns.dark_palette('w', as_cmap=True),) #interne (a little transparent) brain.add_contours(nilearn.image.smooth_img(mnipath,0.5),alpha=0.8*alphabrain, levels=[5000],linewidths=lineW) #add annotation if reauested if Zannotate=='Both' or Zannotate=='Number' : brain.annotate(left_right=LR,size=int(12*lineW)) print 'raw '+str(i)+' ready' ########################## plot the X brain (same process but on X) if Zannotate=='Brain' or Zannotate=='Both': print 'doing annotate X slice' ax=plt.subplot(Nraw+1,1,Nraw+1) if len(datasize)==4: cut_coords=find_cut_slices(mean_img(nibabel.nifti1.Nifti1Image(np.sign(np.abs(data.get_data())),data.get_affine())), n_cuts=1,direction='x') else: cut_coords=find_cut_slices(data, n_cuts=1,direction='x') #plot the white background Xbrain brain=nilearn.plotting.plot_roi(nibabel.nifti1.Nifti1Image(np.zeros(func.get_shape()),data.get_affine()), nibabel.nifti1.Nifti1Image(np.zeros(func.get_shape()),data.get_affine()),colorbar=False,cut_coords=cut_coords,display_mode='x',alpha=1,draw_cross=False,cmap=initialcol,black_bg=False,axes=ax,annotate=False) if Zannotate=='Both' or Zannotate=='Number' : brain.annotate(left_right=LR,size=int(12*lineW)) if len(datasize)==3: iter_imgs=[data] else: iter_imgs=nilearn.image.iter_img(niftipath) #plot the volumes j=0 for img in iter_imgs: if thresholdpos!=False: colorprovpos=sns.light_palette(colorpos[j],len(thresholdpos),reverse=True)[::-1] img2=nilearn.image.smooth_img(img,smoothing) for kn,k in enumerate(thresholdpos): brain.add_contours(img2,filled=True,levels=[k],cmap=None,colors=[[colorprovpos[kn][0],colorprovpos[kn][1],colorprovpos[kn][2]]],linewidths=lineW,alpha=k/np.max(thresholdpos))#alphamap) if thresholdneg!=False: colorprovneg=sns.light_palette(colorneg[j],len(thresholdneg),reverse=True)[::-1] img2=nibabel.nifti1.Nifti1Image(-1*nilearn.image.smooth_img(img,smoothing).get_data(),data.get_affine()) for kn,k in enumerate(thresholdneg): brain.add_contours(img2,filled=True,levels=[k],cmap=None,colors=[[colorprovneg[kn][0],colorprovneg[kn][1],colorprovneg[kn][2]]],linewidths=lineW,alpha=k/np.max(thresholdpos))#alphamap) j+=1 brain.add_contours(nilearn.image.smooth_img(mnipath,5),alpha=1*alphabrain, levels=[95],linewidths=lineW, cmap=sns.dark_palette('w', as_cmap=True),) brain.add_contours(nilearn.image.smooth_img(mnipath,0.5),alpha=0.8*alphabrain, levels=[5000],linewidths=lineW) ##plot the line indicating the cut for i in cc: ax.plot([-100, 100], [i, i], 'k-',lw=lineW)#/(85.+73.) ax.axis((-300.0, 300.0, -80.0, 110.0)) #save if outdir!='': plt.savefig(outdir,dpi=300)