Convert VertexCluster to 2d Numpy array

Given a communities extracted using VertexClustering as below

partition_all = ig.VertexClustering(G, partitions[0].membership)
I using the following line to convert it into numpy

label_arr=np.array([f'{v["name"]}-{v["slice"]}' for v in G.vs]).reshape(3,-1).transpose()

However, the above solution only work if all node are present across slices and will throw an error if some nodes are missing,

ValueError: cannot reshape array of size 20 into shape (3,newaxis)

Hence, I wonder whether there is build-in function to cater transformation to numpy array?

The full code to reproduce the above error

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

# Create first slice graph
G1 = ig.Graph.Formula('A-B-D-C-A, D-E-G-F-D')

# Make a copy, remove edge between C and F
G2 = G1.copy(); G2.add_edge('C', 'F')

# Make a copy, remove vertex A
G3 = G1.copy();G3.delete_vertices('A')

# Convert from slices to layers
G_layers, G_interslice, G = la.time_slices_to_layers([G1, G2, G3], interslice_weight=1e-1,
                                                     slice_attr='slice', vertex_id_attr='name',
                                                     edge_type_attr='type', weight_attr='weight' )

# Create partitions
gamma = 0.3
partitions = [la.CPMVertexPartition(H, node_sizes='node_size',weights='weight',
                                    resolution_parameter=gamma) for H in G_layers]
interslice_partition = la.CPMVertexPartition(G_interslice, resolution_parameter=0,
                                             node_sizes='node_size', weights='weight')

# Detect communities
optimiser = la.Optimiser()
diff = optimiser.optimise_partition_multiplex(partitions + [interslice_partition])

partition_all = ig.VertexClustering(G, partitions[0].membership)
label_arr=np.array([f'{v["name"]}-{v["slice"]}' for v in G.vs]).reshape(3,-1).transpose()
# G3.delete_vertices('A')

It might be most useful to convert the results first in an easy to use representation. The following code transforms the membership into a dict-of-dicts, representing the membership of each node in each slice:

# Get results for each slice separately
membership_slice = {}
for v, m in zip(G.vs, partitions[0].membership):
  if v['slice'] not in membership_slice:
    membership_slice[v['slice']] = {}
  membership_slice[v['slice']][v['name']] = m

This produces something like

{0: {'A': 1, 'B': 1, 'D': 0, 'C': 1, 'E': 0, 'G': 0, 'F': 0},
 1: {'A': 1, 'B': 1, 'D': 0, 'C': 0, 'E': 0, 'G': 0, 'F': 0},
 2: {'B': 0, 'D': 0, 'C': 0, 'E': 2, 'G': 2, 'F': 2}}

Note that indeed the second slice does not have a node A. This is something that is expected, graphs across different slices do not all necessarily need to have all nodes present. It is then most convenient to convert it to a pandas dataframe, using

membership_df = pd.DataFrame(membership_slice)

We now have a pandas DataFrame that looks like

   0  1    2
A  1  1  NaN
B  1  1  0.0
D  0  0  0.0
C  1  0  0.0
E  0  0  2.0
G  0  0  2.0
F  0  0  2.0

Here, node A for slice 2 is missing, indicated by NaN (not a number). Notice that the membership for slice 2 is now a float instead of an int, because an int cannot represent NaN.

If you really need a numpy representation of this, you can simply get that by using membership_df.values.

Thanks for the suggestion, presenting the membership as proposed above remove ambiguity about the node membership.

The graph (with missing node A) used in this discussion is not ideal for the flexibility calculation. This metric is usually used in neuro-image research, and rarely there are missing node (brain region/node).