Skip to main content
Emergent is a Python framework for agent-based modeling on graphs. This guide walks you through installing Emergent, defining agent behaviors, and running a complete opinion dynamics simulation where agents average their opinions with their neighbors until the group converges.

Prerequisites

  • Python 3.10.7 or later
  • pip or uv
1

Install Emergent

Install the emergent package from PyPI.
pip install emergent
The Emergent project uses uv for development. If you’re contributing to Emergent itself, clone the repository and run uv sync to install all dependencies.
2

Create the model

An AgentModel is the central object in every Emergent simulation. It holds your graph, your parameters, and the functions that define how agents behave.
simulation.py
from emergent.main import AgentModel

model = AgentModel()
By default the model is configured with the following parameters:
ParameterDefaultDescription
num_nodes3Number of agents in the graph
graph_type"complete"Graph topology ("complete", "cycle", or "wheel")
convergence_data_keyNoneNode attribute to monitor for convergence
convergence_std_dev100Standard deviation threshold for convergence
Override any of these with update_parameters:
simulation.py
model.update_parameters({
    "num_nodes": 20,
    "graph_type": "cycle",
    "convergence_data_key": "opinion",
    "convergence_std_dev": 0.5,
})
convergence_data_key must be set to the name of a node attribute before calling run_to_convergence. The simulation stops when the standard deviation of that attribute across all nodes falls below convergence_std_dev.
3

Define agent behaviors

You supply two functions to the model:
  • initial_data_function — called once per node when the graph is initialized. Returns a dictionary of node attributes.
  • timestep_function — called once per timestep. Updates node attributes in place.
For opinion dynamics, each agent starts with a random opinion between 0 and 1. On each timestep, every agent replaces their opinion with the average of their own opinion and their neighbors’ opinions.
simulation.py
import random

def initial_data(model):
    """Assign each agent a random opinion in [0, 1]."""
    return {"opinion": random.random()}

def timestep(model):
    """Each agent averages their opinion with their neighbors."""
    graph = model.get_graph()
    new_opinions = {}

    for node in graph.nodes():
        neighbors = list(graph.neighbors(node))
        all_nodes = [node] + neighbors
        avg_opinion = sum(graph.nodes[n]["opinion"] for n in all_nodes) / len(all_nodes)
        new_opinions[node] = avg_opinion

    for node, opinion in new_opinions.items():
        graph.nodes[node]["opinion"] = opinion

model.set_initial_data_function(initial_data)
model.set_timestep_function(timestep)
Always compute new values before writing them back to the graph. Writing opinions inside the loop would cause agents later in the iteration to see already-updated values from earlier agents, producing inconsistent results.
4

Initialize the graph

initialize_graph creates the networkx graph based on num_nodes and graph_type, then calls your initial_data_function once for each node.
simulation.py
model.initialize_graph()
After initialization you can inspect the graph directly:
simulation.py
graph = model.get_graph()
for node, data in graph.nodes(data=True):
    print(f"Agent {node}: opinion = {data['opinion']:.4f}")
5

Run to convergence

run_to_convergence repeatedly calls your timestep_function until the standard deviation of convergence_data_key across all nodes falls below convergence_std_dev, or until the maximum timestep limit is reached (default: 100,000).
simulation.py
model.run_to_convergence()

graph = model.get_graph()
final_opinions = [data["opinion"] for _, data in graph.nodes(data=True)]
print(f"Converged opinion: {sum(final_opinions) / len(final_opinions):.4f}")
If your simulation never converges, lower convergence_std_dev may be the cause — try raising it. You can also reduce the maximum timestep limit with model.change_max_timesteps(1000) to fail fast during development.

Complete example

Here is the full opinion dynamics simulation in a single file:
simulation.py
import random
from emergent.main import AgentModel

# 1. Create the model
model = AgentModel()
model.update_parameters({
    "num_nodes": 20,
    "graph_type": "cycle",
    "convergence_data_key": "opinion",
    "convergence_std_dev": 0.5,
})

# 2. Define behaviors
def initial_data(model):
    return {"opinion": random.random()}

def timestep(model):
    graph = model.get_graph()
    new_opinions = {}
    for node in graph.nodes():
        neighbors = list(graph.neighbors(node))
        all_nodes = [node] + neighbors
        avg_opinion = sum(graph.nodes[n]["opinion"] for n in all_nodes) / len(all_nodes)
        new_opinions[node] = avg_opinion
    for node, opinion in new_opinions.items():
        graph.nodes[node]["opinion"] = opinion

model.set_initial_data_function(initial_data)
model.set_timestep_function(timestep)

# 3. Initialize and run
model.initialize_graph()
model.run_to_convergence()

# 4. Inspect results
graph = model.get_graph()
final_opinions = [data["opinion"] for _, data in graph.nodes(data=True)]
print(f"Converged opinion: {sum(final_opinions) / len(final_opinions):.4f}")

Next steps

Agent model

Full API reference for AgentModel, including all parameters and methods.

Graph structures

Learn about the built-in graph types and how to supply a custom networkx graph.

Defining behaviors

Patterns for writing initial data and timestep functions for complex simulations.

Examples

Explore NK landscape fitness, homogenization, and other ready-to-run examples.

Build docs developers (and LLMs) love