Flocc

Agent-based modeling in JavaScript in the browser or on the server. [v0.5.16]

Quick Start

Overview

The easiest way to create a new Flocc model is by using CodeSandbox, a tool that provides an in-browser code editor.

Open this link in a new tab: flocc.network/new to create a Flocc model in CodeSandbox.

In this example, we’ll create an environment with fifty agents of various ages. We’ll include a rule for life expectancy — agents will generally die around a certain age, but there will be plenty of variation.

1. Set Up an Environment

We’ll create a new basic environment and call it env. Then, we’ll use a native JavaScript for loop to add 50 agents to the environment. Replace the existing line with function setup() {} with the following setup function:

function setup() {
  // create the environment
  const env = new flocc.Environment();
  // loop 50 times...
  for (let i = 0; i < 50; i++) {
    // and each time, add a new agent to the environment
    const agent = new Agent();
    env.addAgent(agent);
  }
}

2. Initialize Agents with Data

Now we have an environment with 50 agents. But right now, none of these agents have any data associated with them, other than the environment they are in. Let’s update the for loop and initialize them with an age. This value will be a number pulled from a normal distribution, so that there are a lot of middle-aged agents and only a few young and old ones.

for (let i = 0; i < 50; i++) {
  // utils.gaussian generates a bell-shaped curve.
  // In this case it's centered at 40 with most values falling within
  // 10 of the mean (i.e. most between 30 and 50)
  let age = utils.gaussian(40, 10);
  age = Math.round(age);
  // We can instantiate the agent with a piece of data called "age"
  // that is set to the above value we just generated.
  const agent = new Agent({
    age: age
  });
  env.addAgent(agent);
}

3. Adding an Update Rule

The last step is to add some sort of rule for how agents behave with each tick of the simulation. A rule is a function that takes as a single parameter the Agent on which the rule is executing.

For our environment, we’ll again use a normal distribution to model life expectancy/age of death for our agents. The rule will also increase age. Add this code above thesetup function:

function tick(agent) {
  // Let the mean age of death be around 80, with most
  // falling between 75 and 85.
  const ageOfDeath = utils.gaussian(80, 5);
  // If the agent's current age is at or above the age of
  // their death (which changes with each tick of the simulation!),
  // they are dead, so remove them from the simulation.
  if (agent.get('age') >= ageOfDeath) {
    env.removeAgent(agent);
  } else {
    agent.increment('age');
  }
}

Next, back in the setup function, add this tick function as a value when you instantiate the agent:

  const agent = new Agent({ 
    age: age,
    tick: tick 
  }); 
  env.addAgent(agent);

4. Visualizing Data

In a non-spatial model (with no x or y values to plot), we can still display information about agents. One way to do that with these agents is with a LineChartRenderer. In the setup function, below the for loop, add this code:

const renderer = new LineChartRenderer(environment, { autoScale: true });

renderer.mount('#container');

renderer.metric('age');

The mount method tells the renderer where on the page it should display, and the metric method takes a string matching the key of agent data you want to visualize. When you refresh the model, you will see a chart begin animating that should look similar to this:

By default, the metric method shows the mean (average) value of all agent ages. But we can customize that by passing additional configuration. Try adding the following code:

renderer.metric('age', {
  fn: utils.min,
  color: 'blue'
});

renderer.metric('age', {
  fn: utils.max,
  color: 'red'
});

After refreshing, your chart should now look like this:

By adding two additional metrics for the same key but with different display functions, you can now see the minimum (blue), maximum (red), and mean (black) values on one chart!

5. Extending the Model

You’ll notice that, relatively quickly, all of the metrics on the line chart will disappear, at the point when all of the agents in the environment die out. To counteract this, we can add code that adds agents back into the environment to try to reach a stable population. While adding one whenever an agent dies would guarantee a perfectly level population, adding them semi-randomly is more realistic and leads to more interesting dynamics.

In the tick function, add the following lines before the end of the function:

const chanceOfReproducing = 0.0015;

if (utils.uniform() < chanceOfReproducing) {
  environment.addAgent(new Agent({
    age: 0,
    tick: tick
  }));
}

And, in the setup function, let's add one more metric to show the total population:

renderer.metric('population', {
  fn() {
    return environment.getAgents().length;
  },
  color: 'green'
});

When you refresh, the chart will now show an additional green line displaying the total population. The variable chanceOfReproducing means that, with each tick, every agent has a 0.0015 (0.15%) chance of reproducing and creating a new agent with age 0. This value should maintain a relatively steady population, but it's still not very realistic, because it's exactly the same for all agents, at all stages of their life, with no variation due to internal or external factors.

Depending on what you're interested in modeling, you might want to revise or extend this model to introduce other variables. For example, how is an agent's chance of reproducing affected by lifestyle or environmental factors? How could the model be extended so agents reproduce in pairs rather than individually? What about creating connections between parents, children, and siblings? These are all possible directions for this model, but ultimately it depends on what you want to simulate and observe. To summarize Albert Einstein, remember that "a good model should be as simple as possible, but no simpler"!

To learn more about the tools you can use to build more interesting agent-based models, check out the documentation!