```"""
Tutorial 2: Customizing and aligning gradients
=================================================
In this tutorial you’ll learn about the methods available within the
GradientMaps class. The flexible usage of this class allows for the
customization of gradient computation with different kernels and dimensionality
reductions, as well as aligning gradients from different datasets. This
tutorial will only show you how to apply these techniques.
"""

###############################################################################
# +++++++++++++++++++++++++++++++++

# First load mean connectivity matrix and Schaefer parcellation

# and load the conte69 hemisphere surfaces

###############################################################################
# The GradientMaps object allows for many different kernels and dimensionality
# reduction techniques. Let’s have a look at three different kernels.

import numpy as np

from brainspace.plotting import plot_hemispheres
from brainspace.utils.parcellation import map_to_labels

kernels = ['pearson', 'spearman', 'normalized_angle']

for i, k in enumerate(kernels):
gm.fit(conn_matrix)

fill=np.nan)

label_text = ['Pearson', 'Spearman', 'Normalized\nAngle']
cmap='viridis_r', color_bar=True, label_text=label_text, zoom=1.45)

###############################################################################
# It seems the gradients provided by these kernels are quite similar although
# their scaling is quite different. Do note that the gradients are in arbitrary
# units, so the smaller/larger axes across kernels do not imply anything.
# Similar to using different kernels, we can also use different dimensionality
# reduction techniques.

# PCA, Laplacian eigenmaps and diffusion mapping
embeddings = ['pca', 'le', 'dm']

for i, emb in enumerate(embeddings):
gm.fit(conn_matrix)

fill=np.nan)

# sphinx_gallery_thumbnail_number = 2
label_text = ['PCA', 'LE', 'DM']
cmap='viridis_r', color_bar=True, label_text=label_text, zoom=1.45)

###############################################################################
# +++++++++++++++++++
#
# A more principled way of increasing comparability across gradients are
# alignment techniques. BrainSpace provides two alignment techniques:
# Procrustes analysis, and joint alignment. For this example we will load
# functional connectivity data of a second subject group and align it with the
# first group.

gp.fit([conn_matrix, conn_matrix2])
gj.fit([conn_matrix, conn_matrix2])

###############################################################################
# Here, `gp` contains the Procrustes aligned data and `gj` contains the joint
# aligned data. Let’s plot them, but in separate figures to keep things
# organized.

# First gradient from original and holdout data, without alignment
for i in range(2):

label_text = ['Unaligned\nGroup 1', 'Unaligned\nGroup 2']
cmap='viridis_r', color_bar=True, label_text=label_text, zoom=1.5)

###############################################################################

# With procrustes alignment
for i in range(2):
fill=np.nan)

label_text = ['Procrustes\nGroup 1', 'Procrustes\nGroup 2']
cmap='viridis_r', color_bar=True, label_text=label_text, zoom=1.5)

###############################################################################

# With joint alignment
for i in range(2):
fill=np.nan)

label_text = ['Joint\nGroup 1', 'Joint\nGroup 2']
cmap='viridis_r', color_bar=True, label_text=label_text, zoom=1.5)

###############################################################################
# Although in this example, we don't see any big differences, if the input data
# was less similar, alignments may also resolve changes in the order of the
# gradients. However, you should always inspect the output of an alignment;
# if the input data are sufficiently dissimilar then the alignment may produce
# odd results.
#
#
# In some instances, you may want to align gradients to an out-of-sample
# gradient, for example when aligning individuals to a hold-out group gradient.
# When performing a Procrustes alignemnt, a 'reference' can be specified.
# The first alignment iteration will then be to the reference. For purposes of
# this example, we will use the gradient of the hold-out group as the
# reference.

gref.fit(conn_matrix2)

###############################################################################
# The gradients in `galign.aligned_` are now aligned to the reference
#
# +++++++++++++++++++
# We can also fuse data across multiple modalities and build mutli-modal
# gradients. In this case we only look at one set of output gradients,
# rather than one per modality.
#
# First, let's load the example data of microstructural profile covariance
# `(Paquola et al., 2019) <https://journals.plos.org/plosbiology/article?
# id=10.1371/journal.pbio.3000284>`_ and functional connectivity.

# First load mean connectivity matrix and parcellation

seeds = [None] * 2

# visualise the features from a seed region (seed 0)
plot_hemispheres(surf_lh, surf_rh, array_name=seeds, label_text=['FC', 'MPC'],
size=(1200, 400), color_bar=True, cmap='viridis', zoom=1.45)

###############################################################################
# In order to fuse the matrices, we simply pass the matrices to the fusion
# command which will rescale and horizontally concatenate the matrices.

# Negative numbers are not allowed in fusion.
fc[fc < 0] = 0

def fusion(*args):
from scipy.stats import rankdata
from sklearn.preprocessing import minmax_scale

max_rk = [None] * len(args)
for j, a in enumerate(args):
m = masks[j] = a != 0
a[m] = rankdata(a[m])
max_rk[j] = a[m].max()

max_rk = min(max_rk)
for j, a in enumerate(args):
a[m] = minmax_scale(a[m], feature_range=(1, max_rk))

return np.hstack(args)

# fuse the matrices
fused_matrix = fusion(fc, mpc)

###############################################################################
# We then use this output in the fit function. This will convert the long
# horizontal array into a square affinity matrix, and then perform embedding.

gm.fit(fused_matrix)

for i in range(2):
fill=np.nan)

color_bar=True, cmap='viridis', zoom=1.45)

###############################################################################
# .. note::
#   The mpc matrix presented here matches the subject cohort of `(Paquola et
#   al., 2019) <https://journals.plos.org/plosbiology/article?id=10.1371/
#   journal.pbio.3000284>`_. Other matrices in this package match the subject
#   groups used by `(Vos de Wael et al., 2018) <https://www.pnas.org/content/
#   115/40/10154.short>`_. We make direct comparisons in our tutorial for
#   didactic purposes only.
#
# That concludes the second tutorial. In the third tutorial we will consider
# null hypothesis testing of comparisons between gradients and other markers.
```