Skip to content

Getting Started

Installation

pip install fa2

For maximum performance, install with Cython:

pip install cython
pip install fa2 --no-binary fa2

Optional Dependencies

Package Install Purpose
networkx pip install 'fa2[networkx]' NetworkX graph support
igraph pip install 'fa2[igraph]' igraph graph support
cython pip install cython 10-100x speedup (requires C compiler)

Usage

With NetworkX

import networkx as nx
from fa2 import ForceAtlas2

G = nx.karate_club_graph()

fa2 = ForceAtlas2(verbose=False)
positions = fa2.forceatlas2_networkx_layout(G, iterations=100)

# positions is a dict: {node: (x, y)}
nx.draw_networkx(G, pos=positions, node_size=50)

With igraph

import igraph as ig
from fa2 import ForceAtlas2

G = ig.Graph.Famous("Petersen")

fa2 = ForceAtlas2(verbose=False)
layout = fa2.forceatlas2_igraph_layout(G, iterations=100)

# layout is an igraph.Layout object
ig.plot(G, layout=layout)

With Raw Adjacency Matrix

import numpy as np
from fa2 import ForceAtlas2

# Symmetric adjacency matrix
G = np.array([
    [0, 1, 1, 0],
    [1, 0, 0, 1],
    [1, 0, 0, 1],
    [0, 1, 1, 0],
], dtype=float)

fa2 = ForceAtlas2(verbose=False)
positions = fa2.forceatlas2(G, iterations=100)
# positions is a list of (x, y) tuples

With Sparse Matrix

from scipy.sparse import csr_matrix
from fa2 import ForceAtlas2

row = [0, 0, 1, 1, 2, 2, 3, 3]
col = [1, 2, 0, 3, 0, 3, 1, 2]
data = [1, 1, 1, 1, 1, 1, 1, 1]
G = csr_matrix((data, (row, col)), shape=(4, 4))

fa2 = ForceAtlas2(verbose=False)
positions = fa2.forceatlas2(G, iterations=100)

Weighted Graph

import networkx as nx
from fa2 import ForceAtlas2

G = nx.Graph()
G.add_edge("A", "B", weight=5.0)
G.add_edge("B", "C", weight=1.0)
G.add_edge("A", "C", weight=0.1)

fa2 = ForceAtlas2(verbose=False)
positions = fa2.forceatlas2_networkx_layout(
    G, iterations=100, weight_attr="weight"
)
# Strongly connected A-B will be closer together

The weight_attr parameter tells ForceAtlas2 which edge attribute to use as weight. Works with both NetworkX and igraph.

Auto-Tuning with inferSettings()

import networkx as nx
from fa2 import ForceAtlas2

G = nx.barabasi_albert_graph(5000, 3)

# Analyzes graph density and size to select:
#   scalingRatio, gravity, barnesHutOptimize, barnesHutTheta
fa2 = ForceAtlas2.inferSettings(G)
positions = fa2.forceatlas2_networkx_layout(G, iterations=100)

# You can override any inferred parameter:
fa2 = ForceAtlas2.inferSettings(G, linLogMode=True, gravity=5.0)

3D Layout

ForceAtlas2 3D layout — 1000 nodes, 8 communities

1000-node graph with 8 communities laid out in 3D

import numpy as np
from fa2 import ForceAtlas2

G = np.array([[0, 1, 1], [1, 0, 1], [1, 1, 0]], dtype=float)

fa2 = ForceAtlas2(dim=3, verbose=False)
positions = fa2.forceatlas2(G, iterations=100)
# positions is a list of (x, y, z) tuples

Reproducible Layouts

Use the seed parameter for deterministic results:

fa2 = ForceAtlas2(seed=42, verbose=False)
pos1 = fa2.forceatlas2(G, iterations=100)

fa2 = ForceAtlas2(seed=42, verbose=False)
pos2 = fa2.forceatlas2(G, iterations=100)
# pos1 == pos2

Next Steps