📊 Block models for Multilayer networks

Tutorial based on the sbm package

Author

Sophie Donnet for the Econet group

Published

April 1, 2026

This tutorial illustrates the use of the block models on multilayer networks.

0. Requirements

The only package required for the analysis is sbm.

library(sbm)

1. From bipartite to multipartite network

First, we consider a PlantđŸŒ±-Ant🐜-Pollinator🐝 -Bird🩜 network which can be seen as a multipartite network, as defined in the course.

1.A Dattilo dataset

The dataset –compiled and conducted by Dáttilo et al. (2016) at Centro de Investigaciones Costeras La Mancha (CICOLMA), located on the central coast of the Gulf of Mexico, Veracruz, Mexico– involves three general types of plant-animal mutualistic interaction: pollination, seed dispersal by frugivorous birds, and protective mutualisms between ants and plants with extrafloral nectaries.

The dataset –which is one of the largest compiled so far with respect to species richness, number of interactions and sampling effort– includes 4 functional groups (FG), namely plants, pollinator species (referred as floral visitors), ant species and frugivorous bird species. Three binary bipartite networks have been collected representing interactions between

  • 1/ plants and florals visitor, đŸŒ± - 🐝
  • 2/ plants and ants, đŸŒ± - 🐜
  • 3/ plants and seed dispersal birds đŸŒ± - 🩜

resulting into three bipartite networks.

The FG are of respective sizes: \(n_1 = 141\) plant đŸŒ± species, \(n_2 = 173\) pollinator 🐝 species, \(n_3 = 46\) frugivorous bird 🩜 species and \(n_4 = 30\) ant 🐜 species.

The 3 networks contain \(753\) observed interactions of which \(55\%\) are plant-pollinator đŸŒ± - 🐝 interactions, \(17\%\) are plant-birds đŸŒ± - 🩜 interactions and \(28\%\) are plant-ant đŸŒ± - 🐜 interactions.

data(multipartiteEcologicalNetwork)
str(multipartiteEcologicalNetwork)
#> List of 3
#>  $ Inc_plant_ant   : int [1:141, 1:30] 0 1 0 0 1 0 1 0 1 0 ...
#>   ..- attr(*, "dimnames")=List of 2
#>   .. ..$ : chr [1:141] "Acacia_cornigera" "Acacia_macracantha" "Achatocarpus_nigricans" "Agave_angustifolia" ...
#>   .. ..$ : chr [1:30] "Camponotus_planatus" "Camponotus_mucronatus" "Paratrechina_longicornis_" "Crematogaster_brevispinosa" ...
#>  $ Inc_plant_bird  : int [1:141, 1:46] 0 0 1 0 0 0 0 0 0 0 ...
#>   ..- attr(*, "dimnames")=List of 2
#>   .. ..$ : chr [1:141] "Acacia_cornigera" "Acacia_macracantha" "Achatocarpus_nigricans" "Agave_angustifolia" ...
#>   .. ..$ : chr [1:46] "Cyanocorax_morio" "Tyrannus_forficatus" "Ortalis_vetula" "Myiozetetes_similis" ...
#>  $ Inc_plant_flovis: int [1:141, 1:173] 0 0 0 0 0 0 0 1 1 0 ...
#>   ..- attr(*, "dimnames")=List of 2
#>   .. ..$ : chr [1:141] "Acacia_cornigera" "Acacia_macracantha" "Achatocarpus_nigricans" "Agave_angustifolia" ...
#>   .. ..$ : chr [1:173] "Apis_melifera" "Lasioglossum_sp1" "Trigona_nigra" "Ascia_monuste" ...
names(multipartiteEcologicalNetwork)
#> [1] "Inc_plant_ant"    "Inc_plant_bird"   "Inc_plant_flovis"
Net <- multipartiteEcologicalNetwork

1.B Inference of multipartite network

From bipartite to multipartite

As seen on Day 3, we could look for blocks of plants when they are interacting with ants, birds and pollinators separately and “compare” the blocks of plants?

Code
res_biSBM_plant_bird <- estimateBipartiteSBM(Net$Inc_plant_bird)
res_biSBM_plant_pollinator <- estimateBipartiteSBM(Net$Inc_plant_flovis)
res_biSBM_plant_ant <- estimateBipartiteSBM(Net$Inc_plant_ant)

However, plants are in interactions with all of them, so we would like to consider all the interactions at the same time.

Formatting the data

We format the data to be able to use our functions i.e. we transform the matrices into an list containing

  • the matrix itself,
  • ‘model’: the distribution you want to fit on the network
  • ‘type’ : simple for simple network, “bipartite” if it is bipartite (it can be deduces from the size of the matrix)
  • ‘dimLabels’: the name of functional group in row and the name of functional group in column.

The three created objects are gathered in a list.

To do so, we use the function defineNetwork.

type = "bipartite"
model = "bernoulli"
PlantFlovis <- defineSBM(netMat=Net$Inc_plant_flovis, model=model, dimLabels = c("Plants",
    "Flovis"))
PlantAnt <- defineSBM(netMat=Net$Inc_plant_ant, model=model, dimLabels = c("Plants",
    "Ants"))
PlantBird <- defineSBM(netMat = Net$Inc_plant_bird, model = model, dimLabels = c("Plants",
    "Birds"))
Note

To make it work, you must be sure to have exactly the same set of plants (in the same order) in each matrix. The dimLabels arguments specifies which group is in row or columns in the matrices you provide.

Tip

If one wants to keep a track of the names of the species, they should be used as rownames and colnames in the matrices.

PlantFlovis$networkData[1:2, 1:2]
#>                    Apis_melifera Lasioglossum_sp1
#> Acacia_cornigera               0                1
#> Acacia_macracantha             0                0

A plot of the data can be obtained with following command.

plotMyMultipartiteMatrix(list(PlantFlovis, PlantAnt, PlantBird))

Finding clusters in the 3 networks jointly

We are now ready to find block of species (based on Bar-Hen, Barbillon, and Donnet (2022)).

data(multipartiteEcologicalNetwork)
estimOptions = list(initBM = FALSE)
listSBM <- list(PlantFlovis, PlantAnt, PlantBird)
res_MSBM_dattilo <- estimateMultipartiteSBM(listSBM, estimOptions)

As yesterday, we can plot the results.

plot(res_MSBM_dattilo) 

plot(res_MSBM_dattilo, type = "expected")

2. Multiplex networks

Assume that you have two (or more) networks involving the same species, but representing different interactions. For instance

  • Observations at different times (on the year, of the day or along time)
  • Different types of interactions : mutualistic and co-occurrence.

These networks can be bipartite or simple. We provide here a synthetic dataset, maybe you have one in mind.

load(file='synthetic_multiplex.rda')
dim(X1)
#> [1]  70 150
dim(X2)
#> [1]  70 150

We provide a function to plot such a multiplex data. First the data must be formatted.

SBM1 <-defineSBM(netMat = X1,model = "bernoulli",dimLabels =c('plant','polli') )
SBM2 <-defineSBM(netMat = X2,model = "bernoulli",dimLabels =c('plant','polli') )
plotMyMultiplexMatrix(list(SBM1,SBM2))

The blocks can be discovered as follows.

res_Multiplex <- estimateMultiplexSBM(list(SBM1,SBM2), dependent = FALSE)
Note

The argument dependant = FALSE means that, conditionally on \(Z_i =k, W_j = \ell\), \(X^1_{ij}\) and \(X^2_{ij}\) are independent variables. As a consequent, the model is: \[\begin{eqnarray*} Z_i &\sim& \mathcal{C}at_K(\pi_1,\dots, \pi_K)\\ W_j &\sim& \mathcal{C}at_L(\rho_1,\dots, \rho_L)\\ X^1_{ij} \sim Z_i=k, W_j = \ell&\sim & \mathcal{B}ern(\alpha^1_{k\ell})\\ X^2_{ij}\sim Z_i=k, W_j = \ell&\sim & \mathcal{B}ern(\alpha^2_{k\ell}) \end{eqnarray*}\] If you have two simple binary networks, you can relax the assumption of independence, relying on Barbillon et al. (2017).

You can plot the results as before by reordering the matrices

plot(res_Multiplex)
plot(res_Multiplex,type='expected')

References

Barbillon, Pierre, Sophie Donnet, Emmanuel Lazega, and Avner Bar-Hen. 2017. “Stochastic block models for multiplex networks: an application to a multilevel network of researchers.” Journal of the Royal Statistical Society Series A 180 (1): 295–314. https://ideas.repec.org/a/bla/jorssa/v180y2017i1p295-314.html.
Bar-Hen, Avner, Pierre Barbillon, and Sophie Donnet. 2022. “Block Models for Generalized Multipartite Networks: Applications in Ecology and Ethnobiology.” Statistical Modelling 22 (4): 273–96. https://doi.org/10.1177/1471082X20963254.
DĂĄttilo, Wesley, Nubia Lara-Rodrı́guez, Pedro Jordano, Paulo R. GuimarĂŁes, John N. Thompson, Robert J. Marquis, Lucas P. Medeiros, Raul Ortiz-Pulido, Maria A. Marcos-Garcı́a, and Victor Rico-Gray. 2016. “Unravelling Darwin’s Entangled Bank: Architecture and Robustness of Mutualistic Networks with Multiple Interaction Types.” Proceedings of the Royal Society of London B: Biological Sciences 283 (1843).