Each node i carries a feature vector hi ∈ ℝ³. One round of message passing replaces every node's vector with an aggregate of its neighbors' vectors:
h_i(t+1) = AGGREGATE( { h_j(t) : j ∈ N(i) } ∪ { h_i(t) } )
With self-loop weight α, the neighborhood of i is weighted by α·I + A:
Sum: h_i' = α·h_i + Σ_j h_j
Mean: h_i' = (α·h_i + Σ_j h_j) / (α + deg_i)
Sym-norm: h_i' = (α/D_i)·h_i + Σ_j h_j / √(D_i·D_j) [Kipf & Welling GCN, D_i = α + deg_i]
This 2D version renders the exact same feature dynamics two ways at once, instead of one 3D scene: a 2D-native graph diagram (nodes scattered in a disk, edges from 2D k-nearest-neighbor + a few random long-range shortcuts — never a flattened camera view of a 3D layout) on the left, and an embedding-space scatter plot on the right that plots every node directly at (hi[0], hi[1]), with hi[2] shown as dot brightness. The scatter plot is a genuine phase-space diagram of the dynamical system: as message passing repeats, the low-pass nature of neighbor-averaging is over-smoothing (Li et al. 2018) — every point cloud visibly collapses toward its centroid. The panel tracks it numerically too: Dirichlet energy Σ(i,j)∈E ‖h_i − h_j‖² and the embedding variance across all nodes, both decaying toward zero as smoothing progresses.
- Step — apply one round of message passing; pulses travel along the graph edges to show information flowing from neighbors into each node.
- Aggregation rule — sum, mean, or the symmetric-normalized rule GCN uses; sum tends to blow up node magnitudes (and the scatter cloud), mean and sym-norm stay bounded.
- Self-loop weight α — how strongly a node retains its own previous state versus its neighbors' messages; α=0 removes self-information entirely and accelerates over-smoothing, large α slows it down.
- tanh nonlinearity — toggles a squashing activation after aggregation, as a real GNN layer applies between linear steps.