or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

centering.mdcollision.mdindex.mdlinks.mdmany-body.mdpositioning.mdsimulation.md
tile.json

many-body.mddocs/

Many-Body Forces

The many-body force applies mutually among all nodes using the Barnes-Hut approximation for efficient n-body simulation. It can simulate gravity (positive strength) or electrostatic charge (negative strength), making it essential for node repulsion in network layouts.

Capabilities

Many-Body Force Factory

Creates a new many-body force with default parameters.

/**
 * Creates a new many-body force with default parameters
 * @returns ManyBodyForce instance with configuration methods
 */
function forceManyBody(): ManyBodyForce;

Usage Examples:

import { forceManyBody } from "d3-force";

// Create with default settings (repulsive force)
const chargeForce = forceManyBody();

// Add to simulation
simulation.force("charge", forceManyBody());

Strength Configuration

Configure the strength of the many-body interaction.

/**
 * Sets or gets the strength accessor for many-body force
 * @param strength - Strength value or accessor function (optional, defaults to -30)
 * @returns Current strength accessor or force instance for chaining
 */
strength(strength?: number | ((d: Node, i: number, nodes: Node[]) => number)): ((d: Node, i: number, nodes: Node[]) => number) | ManyBodyForce;

Usage Examples:

const chargeForce = forceManyBody();

// Fixed repulsive force (negative values repel)
chargeForce.strength(-100);

// Fixed attractive force (positive values attract)
chargeForce.strength(50);

// Variable strength based on node properties
chargeForce.strength(d => d.charge || -30);

// Strength based on node size or importance
chargeForce.strength(d => -(d.size * 10));

Barnes-Hut Theta Configuration

Configure the Barnes-Hut approximation accuracy parameter.

/**
 * Sets or gets the Barnes-Hut approximation criterion
 * @param theta - Theta value (optional, defaults to 0.9)
 * @returns Current theta value or force instance for chaining
 */
theta(theta?: number): number | ManyBodyForce;

Usage Examples:

const chargeForce = forceManyBody();

// More accurate (slower) - smaller theta
chargeForce.theta(0.5);

// Less accurate (faster) - larger theta
chargeForce.theta(1.5);

// Default accuracy
chargeForce.theta(0.9);

Distance Limits Configuration

Configure minimum and maximum interaction distances.

/**
 * Sets or gets the minimum distance between nodes for force calculation
 * @param distance - Minimum distance (optional, defaults to 1)
 * @returns Current minimum distance or force instance for chaining
 */
distanceMin(distance?: number): number | ManyBodyForce;

/**
 * Sets or gets the maximum distance between nodes for force calculation
 * @param distance - Maximum distance (optional, defaults to Infinity)
 * @returns Current maximum distance or force instance for chaining
 */
distanceMax(distance?: number): number | ManyBodyForce;

Usage Examples:

const chargeForce = forceManyBody();

// Prevent extreme forces when nodes are very close
chargeForce.distanceMin(5);

// Limit force range for localized effects
chargeForce.distanceMax(200);

// Combined configuration
chargeForce
  .distanceMin(10)
  .distanceMax(500);

Common Usage Patterns

Standard Node Repulsion

Create typical node repulsion for network diagrams:

const simulation = forceSimulation(nodes)
  .force("charge", forceManyBody()
    .strength(-300)
    .distanceMin(1)
    .distanceMax(Infinity)
  )
  .force("link", forceLink(links))
  .force("center", forceCenter(400, 300));

Variable Node Charges

Assign different charges based on node properties:

const nodes = [
  { id: "A", type: "hub", size: 10 },
  { id: "B", type: "leaf", size: 3 },
  { id: "C", type: "leaf", size: 3 }
];

const simulation = forceSimulation(nodes)
  .force("charge", forceManyBody()
    .strength(d => {
      if (d.type === "hub") return -500; // Strong repulsion for hubs
      return -100; // Weaker repulsion for leaves
    })
  );

Gravity Simulation

Create attractive forces for clustering:

const simulation = forceSimulation(nodes)
  .force("gravity", forceManyBody()
    .strength(50) // Positive = attractive
    .distanceMax(100) // Limit attraction range
  )
  .force("collision", forceCollide(5)); // Prevent overlap

Performance-Optimized Large Networks

Configure for better performance with many nodes:

const simulation = forceSimulation(largeNodeArray)
  .force("charge", forceManyBody()
    .strength(-30)
    .theta(1.2) // Less accuracy for speed
    .distanceMax(300) // Limit computation range
  );

Localized Force Fields

Create multiple localized charge zones:

// Central repulsive force
const centralCharge = forceManyBody()
  .strength(-200)
  .distanceMax(150);

// Peripheral attractive force  
const peripheralCharge = forceManyBody()
  .strength(d => d.x * d.x + d.y * d.y > 100 * 100 ? 20 : 0)
  .distanceMin(50)
  .distanceMax(200);

simulation
  .force("central-repulsion", centralCharge)
  .force("peripheral-attraction", peripheralCharge);

Dynamic Charge Updates

Change node charges based on user interaction or data updates:

const chargeForce = forceManyBody().strength(d => d.currentCharge || -30);
simulation.force("charge", chargeForce);

function updateNodeCharges(nodes, chargeData) {
  nodes.forEach((node, i) => {
    node.currentCharge = chargeData[i];
  });
  
  // Re-initialize force with new charge data
  chargeForce.strength(d => d.currentCharge);
  
  // Reheat simulation to apply new forces
  simulation.alpha(0.3).restart();
}

// Example: Make clicked node strongly repulsive
function onNodeClick(clickedNode) {
  clickedNode.currentCharge = -1000;
  chargeForce.strength(d => d.currentCharge || -30);
  simulation.alpha(0.5).restart();
}

Barnes-Hut Approximation

The Barnes-Hut approximation greatly improves performance by treating distant groups of nodes as single entities:

  • Theta Parameter: Controls accuracy vs. speed trade-off
    • Lower theta (0.1-0.5): More accurate, slower computation
    • Higher theta (1.0-2.0): Less accurate, faster computation
  • Quadtree Structure: Nodes are organized in spatial quadtree for efficient range queries
  • Complexity: Reduces from O(n²) to O(n log n) per application

Force Calculation Details

Many-body forces are calculated using inverse square law:

// Simplified force calculation
const dx = nodeB.x - nodeA.x;
const dy = nodeB.y - nodeA.y;
const distance = Math.sqrt(dx * dx + dy * dy);
const force = (strengthA * strengthB) / (distance * distance);

// Applied as velocity changes
nodeA.vx += (dx / distance) * force * alpha;
nodeA.vy += (dy / distance) * force * alpha;

Performance Considerations

  • Distance Limits: Setting distanceMax can significantly improve performance for large graphs
  • Theta Tuning: Adjust theta based on required accuracy vs. performance needs
  • Strength Magnitude: Very large strength values can cause numerical instability
  • Node Count Scaling: Performance scales as O(n log n) with Barnes-Hut approximation

Key Characteristics

  • Global Effect: Unlike links, many-body forces affect all node pairs
  • Distance-Based: Force strength follows inverse square law
  • Directional: Forces are applied along the line connecting node pairs
  • Symmetric: Equal and opposite forces applied to both nodes in a pair
  • Configurable Range: Distance limits allow for localized or global effects

Default Values

  • strength: -30 (repulsive)
  • theta: 0.9
  • distanceMin: 1
  • distanceMax: Infinity