Tutorial 5 - Connectome Spectral Analysis

In this tutorial we will learn how to decompose time-series of brain activity into a time-varying weighted composition of connectome harmonics. See refs:

Some of the content in this notebook was inspired from https://hal.inria.fr/hal-02304584/document

Table of content:

    [1] The Fourier transform
       [1.1] What is the Fourier spectrum?
       [1.2] The graph Laplacian
       [1.3] The eigendecomposition of the Laplacian
       [1.4] Oscillations as Fourier modes of a ring graph
       [1.5] The Discrete Fourier Transform
       [1.6] pygsp: a Python toolbox to perform Fourier analysis on graphs.

    [2] 2D Fourier transform and 2D signal processing
       [2.1] The 2D-grid Fourier modes

    [3] Connectome Spectral Analsysis
       [3.1] Connectome Harmonics
       [3.2] Connectome Fourier transform

    [4] Extra material
       [4.1] The uncertainity principle
       [4.2] The Fiedler vector
       [4.3] 2D signal processing

[1] The Fourier transform

Joseph Fourier

https://fr.wikipedia.org/wiki/Joseph_Fourier

Go back to top

[1.1]: What is the Fourier spectrum?

Let's use an example to better explain these concepts. Imagine that we have a one-dimensional (1-d) time-series over discrete time $t \in [0,T]$. In classical signal processing, stationary time is modeled as a 1-d ring graph (i.e., a line with periodic boundary conditions).

Go back to top

[1.2]: The graph Laplacian.

For discrete domains, the (normalized) Laplacian is defined as:

$$\mathbf{L} = \mathbb{I}_{T} - \mathbf{D}^{-1/2}\mathbf{A}\mathbf{D}^{-1/2} $$

where:

Go back to top

[1.3]: The eigendecompostion of the Laplacian.

Go back to top

[1.3.1]: What is an eigendecomposition?

It consists on finding the vectors $\mathbf{v}$ and scalar values $\lambda$ that solve this equation:

$$ \mathbf{A}\mathbf{v} = \lambda \mathbf{v}$$

Let's see what this means.

Go back to top

[1.4]: Oscillations as Fourier modes of a ring graph

Here we have plotted the value of each graph Laplacian eigenvalue (in black), and the eigenvectors associated to 10 of these eigenvalues (in different colors). The eigenvectors, aka Fourier modes, define the spectral domain of the signal, and are vectors that vary smoothly along the ring graph. Only for illustration, we have represented them as if the graph was reshaped into a line.

These variations, in the case of regular graphs such as rings, or 2-d grids (as we will see later) take the shape of oscillations. The frequency of at which the Fourier modes "oscillate" is dictated by their associated eigenvalue (its squared value). Plotting everything together we have:

Go back to top

[1.5]: The Discrete Fourier Transform (DFT)

We have just constructed, and plotted, the Discrete Time Fourier basis. We are now going to define a discrete time signal (a time series), and Fourier-transform it! This is the basic principle underlying the Discrete Fourier Transform (DFT).

Now let's Fourier-transform it using the spectral decomposition of the ring-graph:

Go back to top

[1.6]: pygsp: a Python toolbox to perform Fourier analysis on graphs.

This python library contains many functions and classes that will allow you to apply signal processing on different kind of graphs. We'll start by defining our ring graph, and computing its Fourier modes. All of that in only two lines of code!

The ring object is now a pygsp.graphs.Graph object, and as such, it has many attributes such as:

  1. ring.N: number of nodes
  2. ring.A: binary adjacency matrix
  3. ring.W: weight matrix
  4. ring.e: the graph spectrum (eigenvalues of the Laplacian)
  5. ring.U: the Fourier basis (the columns of this matrix are the Laplacian eigenvectors).

and functions, such as:

  1. ring.compute_fourier_basis(): computes the Laplacian eigendecomposition
  2. ring.gft(x): performs the graph Fourier Transform of the signal x, i.e., left-multiplies x by the Fourier basis (x_hat = U.T@x)
  3. ring.igft(x_hat): performs the inverse graph Fourier Transform of the signal x_hat, i.e., left-multiplies x by the inverse of the Fourier basis (x = U@x_hat).

You can discover other attributes and methods of the pygsp.graph.Graph class has by running:

ring.__dir__()

The Fourier transform is as simple as calling the .gft() method!

Go back to top

[2]: 2D Fourier transform and 2D signal processing

Let's apply these concepts with a bit more complex, but still regular graph. We will a widely used graph in the signal processing community, the two-dimensional grid graph. We will see how this simple graph gives rise to the 2D Fourier transform, which is massively used for image processing.

We can easily create a 2D-grid graph using pygsp:

In the adjacency matrix, and the Laplacian matrix, each row and column correspond to one "node" or "pixel". The original grid is 32x32, making a total of 1024 pixels.

Go back to top

[2.1] The 2D-grid Fourier modes

Here we plot the 2D-grid spectrum and its Fourier modes. Remember that:

Go back to top

[3]: Connectome Spectral Analysis

Let's apply these concepts with a bit more complex and non-regular graph, the connectome!

We will load the connectome from the second tutorial.

Go back to top

[3.1]: Connectome Harmonics

Let's plot the first 10 connectome harmonics.

Go back to top

[3.2]: Connectome Fourier transform

Now, let's load some brain activity data from the tutorial 3 and compute its connectome graph Fourier transform.

Go back to top

[4.1] Extra material

Go back to top

[4.1] The uncertainity principle.

For further information, you can read section 2.3 of the paper https://hal.inria.fr/hal-02304584/document

The uncertainty principle holds here:

The data concentration of a signal and the concentration of its Fourier transform are related and cannot be both small at the same time.

Go back to top

[4.2] The Fiedler vector: interpretation of the Fourier modes

The first Fourier mode with non-zero eigenvalue is called the Fielder vector. As it defined the smallest possible variation (non-zero eigenvalue but the closest to) it only crosses zero once, and that happens where the graph is less connected.
Let's study this effect by creating a graph in which there is a clear region with low connectivity, for example, a graph with two densely connected communities that share few connections among them.

The Fielder vector, i.e., the first Fourier mode corresponding to a non-zero eigenvalue, is the second Fourier mode (index 1 in Python). Lets plot it!

In this graph made of two weakly connected communities, the two communities are represented by a different sign in the Fieldler vector. For graphs with more communities, more Fourier modes will be needed to distinguish them.

Go back to top

[4.3] 2D signal processing

Lets do some 2D image processing! First, we need a 2D signal, for example an image of a car. Lets also plot the Fourier transform of the same image!

Now we can do some signal processing! We will start by smoothing the image. How can we do that? We have mentioned before that the Fourier modes are ordered by smoothness, which is defined by the squared value of the associated eigenvalue. As we have seen in the previous plots, the Fourier modes corresponding to the lowest frequencies (squared Laplacian eigenvalues) are the smoothest ones.
In order smooth the signal, we will first perform the Fourier transform, and we will filter this transformed signal by only keeping the part corresponding to the lowest Fourier modes. Then we will perform the inverse Fourier transform of this filtered signal. This type of signal processing corresponds to a low-pass filtering. Lets do it!