Usage

This page covers the most common usage patterns: reusable options, the NetworkX- and igraph-style entry points, state and multilayer networks, and a short migration guide for users coming from other community-detection packages.

For single-cell analysis workflows using AnnData or Scanpy, see Using Infomap with AnnData and Scanpy.

For GraphML and GEXF files with module assignments attached to nodes, see Export GraphML and GEXF.

Reusable options

Use infomap.InfomapOptions when you want to reuse the same configuration across multiple runs:

from infomap import Infomap, InfomapOptions

options = InfomapOptions(
    two_level=True,
    directed=True,
    silent=True,
    num_trials=20,
)

im = Infomap.from_options(options)
im.add_link(0, 1)
im.add_link(1, 2)
im.run()

# Reuse the same settings on another instance or another run
im2 = Infomap(silent=True)
im2.add_link(2, 3)
im2.run_with_options(options)

Inspecting state

repr(im) shows a compact snapshot that is useful in a Python shell, notebook, debugger, or failed test output:

from infomap import Infomap

im = Infomap(silent=True)
im.add_link(1, 2)
im
# Infomap(nodes=2, links=1, physical_nodes=2, state_nodes=0, status='not run')

im.run()
im
# Infomap(nodes=2, links=1, physical_nodes=2, state_nodes=0, status='run', multilayer_network=False, levels=2, top_modules=1, codelength=1.0)

Use infomap.Infomap.summary() when you want the full inspection data as a dictionary:

im.summary()
# {
#     "nodes": 2,
#     "links": 1,
#     "physical_nodes": 2,
#     "state_nodes": 0,
#     "status": "run",
#     ...
# }

NetworkX graphs

infomap.find_communities() provides a NetworkX-style entry point that returns communities as a list[set] partition using the original graph node labels. It is duck-typed and does not import NetworkX, so NetworkX remains an optional user-installed package:

import networkx as nx
import infomap

graph = nx.Graph([("a", "b"), ("a", "c")])
communities = infomap.find_communities(graph, weight="weight")

Directed graphs are detected from the graph object:

graph = nx.DiGraph([("a", "b"), ("b", "c")])
communities = infomap.find_communities(graph)

To annotate a graph for drawing or downstream NetworkX workflows, pass a node attribute name:

infomap.find_communities(graph, module_attribute="community")

This follows NetworkX community conventions where algorithms return partitions and node attributes are stored on the graph. See the NetworkX documentation for community algorithms, Louvain communities, and setting node attributes.

infomap.Infomap.add_networkx_graph() remains available when you need direct control over the infomap.Infomap instance. It accepts standard, state, and multilayer NetworkX graphs. Non-integer node labels are mapped to stable internal ids in first-seen order and returned as a mapping:

import networkx as nx
from infomap import Infomap

graph = nx.Graph([("a", "b"), ("a", "c")])
im = Infomap(silent=True)
mapping = im.add_networkx_graph(graph)
im.run()

SciPy sparse matrices

Use infomap.Infomap.from_scipy_sparse_matrix() when your graph is already stored as a SciPy sparse adjacency matrix. CSR, CSC and COO matrices and sparse arrays are accepted. The adapter imports SciPy lazily, so SciPy is only required when this API is used.

import scipy.sparse as sp
from infomap import Infomap

adjacency = sp.csr_matrix([
    [0, 1, 0],
    [1, 0, 2],
    [0, 2, 0],
])

im = Infomap.from_scipy_sparse_matrix(adjacency, directed=False, args="--silent")
im.run()
modules = im.get_modules()

For unweighted graphs, pass weighted=False to treat every nonzero matrix entry as weight 1.0:

im = Infomap.from_scipy_sparse_matrix(adjacency, weighted=False, args="--silent")

For directed graphs, pass directed=True. Then A[i, j] is interpreted as a directed edge from row i to column j:

directed_adjacency = sp.coo_matrix([
    [0, 1],
    [0, 0],
])
im = Infomap.from_scipy_sparse_matrix(
    directed_adjacency,
    directed=True,
    args="--silent",
)

Custom node ids can be supplied in matrix row order. The adapter returns a mapping from Infomap’s internal integer ids to those external ids, matching the pattern used by infomap.Infomap.add_networkx_graph():

adjacency = sp.coo_matrix([
    [0, 3],
    [3, 0],
])
im = Infomap(silent=True)
mapping = im.add_scipy_sparse_matrix(adjacency, directed=False, node_ids=["gene_a", "gene_b"])
im.run()
modules = {mapping[node_id]: module_id for node_id, module_id in im.get_modules().items()}
assert set(modules) == {"gene_a", "gene_b"}

For undirected input, symmetric entries are de-duplicated: if both A[i, j] and A[j, i] exist, one undirected link is added. If the two entries have different weights, the larger weight is used. For large graphs, prefer CSR or COO input to avoid unnecessary conversion work.

edge_index and graph ML workflows

Use infomap.Infomap.from_edge_index() when your graph is stored in the PyTorch Geometric-style edge_index format. The input has shape (2, num_edges), with source node ids in row 0 and target node ids in row 1. NumPy arrays, Python lists and PyTorch tensors are accepted. PyTorch is optional; tensor inputs are converted with detach().cpu().numpy() only when provided. NumPy is required for edge-index conversion; install it with python -m pip install numpy if it is not already available.

import numpy as np
from infomap import Infomap

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

im = Infomap.from_edge_index(edge_index, directed=False, args="--silent")
im.run()
modules = im.get_modules()

Pass edge_weight for weighted graphs:

edge_weight = np.array([1.0, 1.0, 3.5, 3.5])
im = Infomap.from_edge_index(
    edge_index,
    edge_weight=edge_weight,
    directed=False,
    args="--silent",
)

PyTorch tensors can be passed directly when PyTorch is installed:

import torch
from infomap import Infomap

edge_index = torch.tensor([
    [0, 1, 2],
    [1, 2, 0],
])
im = Infomap.from_edge_index(edge_index, directed=True, args="--silent")

PyTorch Geometric Data objects are not required. Pass their attributes to the edge-index API:

im = Infomap.from_edge_index(
    data.edge_index,
    edge_weight=data.edge_weight,
    num_nodes=data.num_nodes,
    args="--silent",
)

Pass num_nodes to preserve isolated nodes that do not appear in edge_index. For undirected input, reverse duplicate edges are de-duplicated; if the two entries have different weights, the larger weight is used. Custom node_ids follow the same mapping pattern as infomap.Infomap.add_networkx_graph():

im = Infomap(silent=True)
mapping = im.add_edge_index(edge_index, node_ids=["gene_a", "gene_b", "gene_c"])
im.run()
modules = {mapping[node_id]: module_id for node_id, module_id in im.get_modules().items()}

State and multilayer networks

State networks are inferred from a node_id node attribute, and multilayer networks additionally use layer_id. infomap.find_communities() returns a partition of the graph’s own nodes, which are state nodes for these inputs:

import networkx as nx
from infomap import Infomap

graph = nx.Graph()
graph.add_node("state-a", node_id="a", layer_id=1)
graph.add_node("state-b", node_id="b", layer_id=1)
graph.add_node("state-a-next", node_id="a", layer_id=2)
graph.add_edge("state-a", "state-b")
graph.add_edge("state-a", "state-a-next")

im = Infomap(silent=True)
im.add_networkx_graph(graph)
im.run()

For the NetworkX-style wrapper:

communities = infomap.find_communities(graph)

igraph graphs

infomap.find_igraph_communities() provides an igraph-native entry point without making igraph a required dependency. It imports igraph only when the igraph-specific API is used and returns an igraph.VertexClustering with a codelength attribute, matching python-igraph community conventions:

import igraph as ig
import infomap

graph = ig.Graph.TupleList([("a", "b"), ("a", "c")], directed=False)
communities = infomap.find_igraph_communities(graph, trials=10)
communities.codelength

Use edge_weights the same way as python-igraph’s community functions:

graph.es["weight"] = [2.0, 1.0]
communities = infomap.find_igraph_communities(graph, edge_weights="weight")

Directed igraph graphs are detected from the graph object:

graph = ig.Graph.TupleList([("a", "b"), ("b", "c")], directed=True)
communities = infomap.find_igraph_communities(graph)

To annotate an igraph graph for plotting or downstream igraph workflows, pass vertex attribute names:

infomap.find_igraph_communities(
    graph,
    module_attribute="community",
    flow_attribute="flow",
)

infomap.Infomap.add_igraph_graph() remains available when you need direct control over the infomap.Infomap instance. It accepts standard, state, and multilayer igraph graphs. The igraph vertex index is used as the state/internal id, while non-numeric node_id labels in state and multilayer graphs are mapped to stable internal physical ids:

graph = ig.Graph(edges=[(0, 1), (0, 2)])
graph.vs["name"] = ["state-a", "state-b", "state-a-next"]
graph.vs["node_id"] = ["a", "b", "a"]
graph.vs["layer_id"] = [1, 1, 2]

im = infomap.Infomap(silent=True)
im.add_igraph_graph(graph)
im.run()

python-igraph also includes Graph.community_infomap(). The infomap package API is useful when you want the current Infomap package implementation, Infomap-specific options, or state/multilayer import, while still receiving an igraph-native VertexClustering result. See the python-igraph documentation for Graph.community_infomap and VertexClustering.

Migration guide for NetworkX and igraph users

NetworkX community functions usually return a partition such as list[set]. Use infomap.find_communities() for that style. Pass weight as the edge attribute name, pass None for unweighted edges, and use module_attribute or flow_attribute when you want values written back to graph nodes. Directed DiGraph inputs are detected automatically unless you already set an Infomap flow model.

python-igraph community functions usually return a VertexClustering. Use infomap.find_igraph_communities() for that style. Pass edge_weights as an igraph edge attribute name, an explicit sequence, or None for unweighted edges. Directed igraph graphs are detected automatically, and optional module_attribute and flow_attribute arguments write results back to vertices.

Use infomap.Infomap.add_networkx_graph() or infomap.Infomap.add_igraph_graph() instead of the one-shot helpers when you need state networks, multilayer networks, explicit result iteration, dataframe export, or several runs with different Infomap options.

For worked comparisons against Louvain and Leiden in NetworkX and igraph workflows, see the unnumbered comparison tutorials on the Tutorial notebooks page.

See the API reference reference for the full surface.