# How to quantify time-dependent network flexibility in igraph

**URL:** <https://igraph.discourse.group/t/how-to-quantify-time-dependent-network-flexibility-in-igraph/843>\
**Category:** Usage\
**Tags:** Python\
**Created:** [5 September 2021 15:47 UTC](https://igraph.discourse.group/t/how-to-quantify-time-dependent-network-flexibility-in-igraph/843 "2021-09-05T15:47:08Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![balandongiv](https://yyz2.discourse-cdn.com/free1/user_avatar/igraph.discourse.group/balandongiv/32/553_2.png) [@balandongiv](https://igraph.discourse.group/u/balandongiv)\
**Post date:** [5 September 2021 15:47 UTC](https://igraph.discourse.group/t/how-to-quantify-time-dependent-network-flexibility-in-igraph/843/1 "2021-09-05T15:47:08Z")

</div>

I have search the net, but Im unable to find any resource about calculating network flexibility with `igraph`.

I would like to double confirm whether such a feature exist or not in igraph-python?

Specifically, flexbility measure that measure the frequency of a node change module allegiance; the transition of brain states between consecutive temporal segments.

… [Basset2011] Bassett, D. S., Wymbs, N. F., Porter, M. A., Mucha, P. J., Carlson, J. M., & Grafton, S. T. (2011). Dynamic reconfiguration of human brain networks during learning. Proceedings of the National Academy of Sciences, 108(18), 7641-7646.

---

<div class="post-metadata">

**Author:** ![vtraag](https://yyz2.discourse-cdn.com/free1/user_avatar/igraph.discourse.group/vtraag/32/38_2.png) [@vtraag](https://igraph.discourse.group/u/vtraag)\
**Post date:** [5 September 2021 22:12 UTC](https://igraph.discourse.group/t/how-to-quantify-time-dependent-network-flexibility-in-igraph/843/2 "2021-09-05T22:12:26Z")

</div>

I’m not 100% sure if I understand correctly what “flexibility” refers to in this context. Nevertheless, I’m fairly confident that `igraph` does not provide it indeed.

From what I could gather quickly from a glance at [the paper](https://doi.org/10.1073/pnas.1018985108), it is simply a metric that describes how often a node changed from one partition to another partition (across partitions in temporally adjacent graphs). This does not require any graph theoretical calculation I believe, so in principle you can simply calculate this yourself in Python. If you’re not sure how to do that, let us know, preferably with some (minimal) code demonstrating what you would like to do.

Perhaps my understanding of “flexibility” is incorrect. If so, could you then perhaps provide a mathematical definition of the term?

---

<div class="post-metadata">

**Author:** ![balandongiv](https://yyz2.discourse-cdn.com/free1/user_avatar/igraph.discourse.group/balandongiv/32/553_2.png) [@balandongiv](https://igraph.discourse.group/u/balandongiv)\
**Post date:** [7 September 2021 14:20 UTC](https://igraph.discourse.group/t/how-to-quantify-time-dependent-network-flexibility-in-igraph/843/5 "2021-09-07T14:20:15Z")

</div>

Thanks for the confirmation [@vtraag](https://igraph.discourse.group/u/vtraag).

For future reader, the flexibility for membership produced by find\_partition\_temporal can be calculated with code attach at the bottom of this thread.

For future reader on how to calculate flexibility

Idea based on maksim/dyconnmap package :

[github.com](https://github.com/makism/dyconnmap/blob/abe5cc10d2ddcde8526e9bf517861c5955d983ad/dyconnmap/chronnectomics/flexibility_index.py)

```auto
import leidenalg as la
import igraph as ig
import numpy as np

A1 = np.array ( [[0., 0., 0., 0., 0, 0, 0], [5., 0., 0., 0., 0, 0, 0], [1., 0., 0., 0., 0, 0, 0],
                 [0., 1., 2., 0., 0, 0, 0], [0., 0., 0., 1., 0, 0, 0], [0., 0., 0., 1., 0, 0, 0],
                 [0., 0., 0., 0., 1, 1, 0]] )

A2 = np.array ( [[0., 0., 0., 0., 0, 0, 0], [5., 0., 0., 0., 0, 0, 0], [1., 0., 0., 0., 0, 0, 0],
                 [0., 1., 2., 0., 0, 0, 0], [0., 0., 0., 1., 0, 0, 0], [0., 0., 1., 1., 0, 0, 0],
                 [0., 0., 0., 0., 1, 1, 0]] )

A3 = np.array ( [[0., 0., 0., 0., 0, 0, 0], [0., 0., 0., 0., 0, 0, 0], [0., 0., 0., 0., 0, 0, 0],
                 [0., 1., 2., 0., 0, 0, 0], [0., 0., 0., 1., 0, 0, 0], [0., 0., 0., 1., 0, 0, 0],
                 [0., 0., 0., 0., 1, 1, 0]] )

G_1 = ig.Graph.Weighted_Adjacency ( A1.tolist () )
G_2 = ig.Graph.Weighted_Adjacency ( A2.tolist () )
G_3 = ig.Graph.Weighted_Adjacency ( A3.tolist () )
G_1.vs ['id'] = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
G_2.vs ['id'] = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
G_3.vs ['id'] = ['A', 'B', 'C', 'D', 'E', 'F', 'G']

gamma = 0.05
membership, improvement = la.find_partition_temporal ( [G_1, G_2, G_3], la.CPMVertexPartition,
                                                       interslice_weight=0.1, resolution_parameter=gamma )
ntime_membership=np.array(membership)

def flexibility_index (x):

    l = len ( x )

    counter = 0
    for k in range ( l - 1 ):
        if x [k] != x [k + 1]:
            counter += 1

    fi = counter / np.float32 ( l - 1 )

    return fi

flexibility_accross_time=[flexibility_index (ntime_membership[:,x]) for x in range(ntime_membership.shape[1])]

```

---

<div class="post-metadata">

**Author:** ![balandongiv](https://yyz2.discourse-cdn.com/free1/user_avatar/igraph.discourse.group/balandongiv/32/553_2.png) [@balandongiv](https://igraph.discourse.group/u/balandongiv)\
**Post date:** [7 September 2021 15:36 UTC](https://igraph.discourse.group/t/how-to-quantify-time-dependent-network-flexibility-in-igraph/843/6 "2021-09-07T15:36:40Z")

</div>

Hi @vtraag, I would like to confirm about the node label order. This question is somehow related to the [OP](https://igraph.discourse.group/t/igraph-plot-for-multiple-layers-partition-does-not-return-expected-output/844/2),

Given 3 time-slice as in the figure below,

 ![Expected_output](https://global.discourse-cdn.com/free1/uploads/igraph/original/1X/43342e5dda1e025c73ccca5b9f4dd910ce1afd90.jpeg)

the node’s label are order in the sequence of t {1,2,3}, and can be extracted via

vertex\_label = [f’{v[“name”]}-{v[“slice”]}’ for v in G.vs]

For future reader:  
Assuming this is correct, then the time-dependent network flexibility (i.e.node) can be calculated as below

```auto
vertex_label = [f'{v["name"]}-{v["slice"]}' for v in G.vs]

node_label = np.array([x[0].split('-')[0] for x in vertex_label])
dic_idx = {v: np.where(node_label == v)[0].tolist() for v in np.unique(node_label)}

ntime_membership=np.array(partition_all.membership)

node_flexibility=[{dtx:flexibility_index (ntime_membership[dic_idx[dtx]])} for dtx in dic_idx]

```

Remark: The derivation of `partition_all` can be found at this [OP](https://igraph.discourse.group/t/igraph-plot-for-multiple-layers-partition-does-not-return-expected-output/844/5), the flexibility index function is embedded in [this thread](https://igraph.discourse.group/t/how-to-quantify-time-dependent-network-flexibility-in-igraph/843/5).

---

<div class="post-metadata">

**Author:** ![vtraag](https://yyz2.discourse-cdn.com/free1/user_avatar/igraph.discourse.group/vtraag/32/38_2.png) [@vtraag](https://igraph.discourse.group/u/vtraag)\
**Post date:** [16 September 2021 07:47 UTC](https://igraph.discourse.group/t/how-to-quantify-time-dependent-network-flexibility-in-igraph/843/7 "2021-09-16T07:47:06Z")

</div>

Working from the cost posted [here](https://igraph.discourse.group/t/convert-vertexcluster-to-2d-numpy-array/861/2) we can easily calculate flexibility of each node across slices.

```python
membership_df.apply(flexibility_index, axis=1)

```

where `membership_df` is a `pandas` `DataFrame` as explained in [this post](https://igraph.discourse.group/t/convert-vertexcluster-to-2d-numpy-array/861/2).

Please note that it is not clear how you would like to deal with the “missing” nodes that have a membership of `NaN` in a particular slice. In the code above this is implicitly treated as a “change” across slices, but perhaps you would like to deal with it differently. For example, you could simply not count any comparison with a `NaN` as a change and divide by the number of comparisons you would then like to make.
