# Table of Contents
- [Getting started — Mesa .1 documentation](#getting-started-mesa-1-documentation)
- [Mesa: Agent-based modeling in Python — Mesa .1 documentation](#mesa-agent-based-modeling-in-python-mesa-1-documentation)
- [Overview of the MESA library — Mesa .1 documentation](#overview-of-the-mesa-library-mesa-1-documentation)
- [Mesa Core Examples — Mesa .1 documentation](#mesa-core-examples-mesa-1-documentation)
- [Mesa Migration guide — Mesa .1 documentation](#mesa-migration-guide-mesa-1-documentation)
- [Adding Space — Mesa .1 documentation](#adding-space-mesa-1-documentation)
- [APIs — Mesa .1 documentation](#apis-mesa-1-documentation)
- [Visualization - Dynamic Agents — Mesa .1 documentation](#visualization-dynamic-agents-mesa-1-documentation)
- [Agent Management Through AgentSet — Mesa .1 documentation](#agent-management-through-agentset-mesa-1-documentation)
- [Creating Your First Model — Mesa .1 documentation](#creating-your-first-model-mesa-1-documentation)
- [Collecting Data — Mesa .1 documentation](#collecting-data-mesa-1-documentation)
- [Visualization - Basic Dashboard — Mesa .1 documentation](#visualization-basic-dashboard-mesa-1-documentation)
- [BatchRunner — Mesa .1 documentation](#batchrunner-mesa-1-documentation)
- [Best Practices — Mesa .1 documentation](#best-practices-mesa-1-documentation)
- [Comparing Scenarios — Mesa .1 documentation](#comparing-scenarios-mesa-1-documentation)
- [Model — Mesa .1 documentation](#model-mesa-1-documentation)
- [Unknown](#unknown)
- [Schelling Segregation Model — Mesa .1 documentation](#schelling-segregation-model-mesa-1-documentation)
- [Boids Flockers — Mesa .1 documentation](#boids-flockers-mesa-1-documentation)
- [Virus on a Network — Mesa .1 documentation](#virus-on-a-network-mesa-1-documentation)
- [Boltzmann Wealth Model (Tutorial) — Mesa .1 documentation](#boltzmann-wealth-model-tutorial-mesa-1-documentation)
- [Visualization - Custom Components — Mesa .1 documentation](#visualization-custom-components-mesa-1-documentation)
- [Agent — Mesa .1 documentation](#agent-mesa-1-documentation)
- [Data collection — Mesa .1 documentation](#data-collection-mesa-1-documentation)
- [Epstein Civil Violence Model — Mesa .1 documentation](#epstein-civil-violence-model-mesa-1-documentation)
- [Visualization — Mesa .1 documentation](#visualization-mesa-1-documentation)
- [Demographic Prisoner’s Dilemma on a Grid — Mesa .1 documentation](#demographic-prisoner-s-dilemma-on-a-grid-mesa-1-documentation)
- [Discrete Space — Mesa .1 documentation](#discrete-space-mesa-1-documentation)
- [Spaces — Mesa .1 documentation](#spaces-mesa-1-documentation)
- [Experimental — Mesa .1 documentation](#experimental-mesa-1-documentation)
- [Documentation page not found
- Read the Docs](#documentation-page-not-found-read-the-docs)
- [Unknown](#unknown)
- [Conway’s Game Of “Life” — Mesa .1 documentation](#conway-s-game-of-life-mesa-1-documentation)
- [Batchrunner — Mesa .1 documentation](#batchrunner-mesa-1-documentation)
- [Wolf-Sheep Predation Model — Mesa .1 documentation](#wolf-sheep-predation-model-mesa-1-documentation)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Documentation page not found
- Read the Docs](#documentation-page-not-found-read-the-docs)
- [Mesa Extensions Overview — Mesa .1 documentation](#mesa-extensions-overview-mesa-1-documentation)
- [Sugarscape Constant Growback Model with Traders — Mesa .1 documentation](#sugarscape-constant-growback-model-with-traders-mesa-1-documentation)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Mesa Core Examples — Mesa .1 documentation](#mesa-core-examples-mesa-1-documentation)
- [Unknown](#unknown)
- [Index — Mesa .1 documentation](#index-mesa-1-documentation)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Search - Mesa .1 documentation](#search-mesa-1-documentation)
- [Python Module Index — Mesa .1 documentation](#python-module-index-mesa-1-documentation)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Mesa: Agent-based modeling in Python — Mesa .1 documentation](#mesa-agent-based-modeling-in-python-mesa-1-documentation)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Documentation page not found
- Read the Docs](#documentation-page-not-found-read-the-docs)
- [Getting started — Mesa .1 documentation](#getting-started-mesa-1-documentation)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Documentation page not found
- Read the Docs](#documentation-page-not-found-read-the-docs)
- [Mesa: Agent-based modeling in Python — Mesa .1 documentation](#mesa-agent-based-modeling-in-python-mesa-1-documentation)
- [Unknown](#unknown)
- [Mesa Migration guide — Mesa .1 documentation](#mesa-migration-guide-mesa-1-documentation)
- [APIs — Mesa .1 documentation](#apis-mesa-1-documentation)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Conway’s Game Of “Life” — Mesa .1 documentation](#conway-s-game-of-life-mesa-1-documentation)
- [Overview of the MESA library — Mesa .1 documentation](#overview-of-the-mesa-library-mesa-1-documentation)
- [Schelling Segregation Model — Mesa .1 documentation](#schelling-segregation-model-mesa-1-documentation)
- [Wolf-Sheep Predation Model — Mesa .1 documentation](#wolf-sheep-predation-model-mesa-1-documentation)
- [Boltzmann Wealth Model (Tutorial) — Mesa .1 documentation](#boltzmann-wealth-model-tutorial-mesa-1-documentation)
- [Unknown](#unknown)
- [Unknown](#unknown)
- [Virus on a Network — Mesa .1 documentation](#virus-on-a-network-mesa-1-documentation)
- [Demographic Prisoner’s Dilemma on a Grid — Mesa .1 documentation](#demographic-prisoner-s-dilemma-on-a-grid-mesa-1-documentation)
- [Epstein Civil Violence Model — Mesa .1 documentation](#epstein-civil-violence-model-mesa-1-documentation)
- [Boids Flockers — Mesa .1 documentation](#boids-flockers-mesa-1-documentation)
- [Introductory Tutorial — Mesa .1 documentation](#introductory-tutorial-mesa-1-documentation)
- [Visualization Tutorial — Mesa .1 documentation](#visualization-tutorial-mesa-1-documentation)
- [Sugarscape Constant Growback Model with Traders — Mesa .1 documentation](#sugarscape-constant-growback-model-with-traders-mesa-1-documentation)
- [Best Practices — Mesa .1 documentation](#best-practices-mesa-1-documentation)
- [Unknown](#unknown)
- [Model — Mesa .1 documentation](#model-mesa-1-documentation)
- [Mesa Extensions Overview — Mesa .1 documentation](#mesa-extensions-overview-mesa-1-documentation)
- [Agent — Mesa .1 documentation](#agent-mesa-1-documentation)
- [Data collection — Mesa .1 documentation](#data-collection-mesa-1-documentation)
- [Python Module Index — Mesa .1 documentation](#python-module-index-mesa-1-documentation)
- [Search - Mesa .1 documentation](#search-mesa-1-documentation)
- [Unknown](#unknown)
- [Unknown](#unknown)
---
# Getting started — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Getting started[#](#getting-started "Link to this heading")
============================================================
Mesa is a modular framework for building, analyzing and visualizing agent-based models.
**Agent-based models** are computer simulations involving multiple entities (the agents) acting and interacting with one another based on their programmed behavior. Agents can be used to represent living cells, animals, individual humans, even entire organizations or abstract entities. Sometimes, we may have an understanding of how the individual components of a system behave, and want to see what system-level behaviors and effects emerge from their interaction. Other times, we may have a good idea of how the system overall behaves, and want to figure out what individual behaviors explain it. Or we may want to see how to get agents to cooperate or compete most effectively. Or we may just want to build a cool toy with colorful little dots moving around.
Tutorials[#](#tutorials "Link to this heading")
------------------------------------------------
If you want to get a quick start on how to build agent based models with MESA, check the overview and tutorials:
* [Overview of the MESA library](overview.html)
: Learn about the core concepts and components of Mesa.
* [Creating Your First Model](tutorials/0_first_model.html)
: Learn how to create your first Mesa model.
* [Adding Space](tutorials/1_adding_space.html)
: Learn how to add space to your Mesa model and understand Mesa’s space architecture.
* [Collecting Data](tutorials/2_collecting_data.html)
: Learn how to collect model level and agent level data with Mesa’ DataCollector.
* [AgentSet](tutorials/3_agentset.html)
: Learn how to more effectively manage agents with Mesa’s AgentSet.
* [Basic Visualization](tutorials/4_visualization_basic.html)
: Learn how to build an interactive dashboard with Mesa’s visualization module.
* [Dynamic Agent Visualization](tutorials/5_visualization_dynamic_agents.html)
: Learn how to dynamically represent your agents in your interactive dashboard.
* [Custom Visualization Components](tutorials/6_visualization_custom.html)
: Learn how to add custom visual components to your interactive dashboard.
* [Parameter Sweeps](tutorials/7_batch_run.html)
: Learn how to conduct parameter sweeps on multiple processors with Mesa’s BatchRunner.
* [Comparing Scenarios](tutorials/8_comparing_scenarios.html)
: Think through how to analyze your parameter sweep results to find insight in your Mesa simulations.
Examples[#](#examples "Link to this heading")
----------------------------------------------
Mesa ships with a collection of example models. These are classic ABMs, so if you are familiar with ABMs and want to get a quick sense of how MESA works, these examples are great place to start. You can find them [here](examples.html)
.
Further resources[#](#further-resources "Link to this heading")
----------------------------------------------------------------
To further explore Mesa and its features, we have the following resources available:
### Best practices[#](#best-practices "Link to this heading")
* [Mesa best practices](best-practices.html)
: an overview of tips and guidelines for using MESA.
### API documentation[#](#api-documentation "Link to this heading")
* [Mesa API reference](#apis)
: Detailed documentation of Mesa’s classes and functions.
### Repository of models built using MESA[#](#repository-of-models-built-using-mesa "Link to this heading")
* [Mesa Examples repository](https://github.com/projectmesa/mesa-examples)
: A collection of example models demonstrating various Mesa features and modeling techniques.
### Migration guide[#](#migration-guide "Link to this heading")
* [Mesa 3.0 Migration guide](migration_guide.html)
: If you’re upgrading from an earlier version of Mesa, this guide will help you navigate the changes in Mesa 3.0.
### Source Ccode and development[#](#source-ccode-and-development "Link to this heading")
* [Mesa GitHub repository](https://github.com/projectmesa/mesa)
: Access the full source code of Mesa, contribute to its development, or report issues.
* [Mesa release notes](https://github.com/projectmesa/mesa/releases)
: View the detailed changelog of Mesa, including all past releases and their features.
### Community and support[#](#community-and-support "Link to this heading")
* [Mesa GitHub Discussions](https://github.com/projectmesa/mesa/discussions)
: Join discussions, ask questions, and connect with other Mesa users.
* [Matrix Chat](https://matrix.to/#/#project-mesa:matrix.org)
: Real-time chat for quick questions and community interaction.
Enjoy modelling with Mesa, and feel free to reach out!
On this page
### This Page
* [Show Source](_sources/getting_started.md.txt)
---
# Mesa: Agent-based modeling in Python — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Mesa: Agent-based modeling in Python[#](#mesa-agent-based-modeling-in-python "Link to this heading")
=====================================================================================================
[](https://doi.org/10.21105/joss.07668)
[](https://github.com/projectmesa/mesa/actions)
[](https://codecov.io/gh/projectmesa/mesa)
[](https://github.com/psf/black)
[](https://matrix.to/#/#project-mesa:matrix.org)
[Mesa](https://github.com/projectmesa/mesa/)
is an Apache2 licensed agent-based modeling (or ABM) framework in Python.
Mesa allows users to quickly create agent-based models using built-in core components (such as spatial grids and agent schedulers) or customized implementations; visualize them using a browser-based interface; and analyze their results using Python’s data analysis tools. Mesa’s goal is to make simulations accessible to everyone, so humanity can more effectively understand and solve complex problems.
 _A visualisation of the Wolf Sheep model build with Mesa._
Features[#](#features "Link to this heading")
----------------------------------------------
* Built-in core modeling components
* Flexible agent and model management through AgentSet
* Browser-based Solara visualization
* Built-in tools for data collection and analysis
* Example model library
Using Mesa[#](#using-mesa "Link to this heading")
--------------------------------------------------
### Installation Options[#](#installation-options "Link to this heading")
To install our latest stable release, run:
pip install \-U mesa
To also install our recommended dependencies:
pip install \-U mesa\[rec\]
The `[rec]` option installs additional recommended dependencies needed for visualization, plotting, and network modeling capabilities.
On a Mac, this command might cause an error stating `zsh: no matches found: mesa[all]`. In that case, change the command to `pip install -U "mesa[rec]"`.
### Resources[#](#resources "Link to this heading")
For help getting started with Mesa, check out these resources:
* [Getting started](getting_started.html)
- Learn about Mesa’s core concepts and components
* [Migration Guide](migration_guide.html)
- Upgrade to Mesa 3.0
* [Mesa Examples](https://mesa.readthedocs.io/stable/examples.html)
- Browse user-contributed models and implementations
* [Mesa Extensions](mesa_extension.html)
- Overview of mesa’s Extensions
* [GitHub Discussions](https://github.com/projectmesa/mesa/discussions)
- Ask questions and discuss Mesa
* [Matrix Chat Room](https://matrix.to/#/#project-mesa:matrix.org)
- Real-time chat with the Mesa community
### Development and Support[#](#development-and-support "Link to this heading")
Mesa is an open source project and welcomes contributions:
* [GitHub Repository](https://github.com/projectmesa/mesa/)
- Access the source code
* [Issue Tracker](https://github.com/projectmesa/mesa/issues)
- Report bugs or suggest features
* [Contributors Guide](https://github.com/projectmesa/mesa/blob/main/CONTRIBUTING.md)
- Learn how to contribute
### Citing Mesa[#](#citing-mesa "Link to this heading")
To cite Mesa in your publication, you can refer to our peer-reviewed article in the Journal of Open Source Software (JOSS):
* ter Hoeven, E., Kwakkel, J., Hess, V., Pike, T., Wang, B., rht, & Kazil, J. (2025). Mesa 3: Agent-based modeling with Python in 2025. Journal of Open Source Software, 10(107), 7668. https://doi.org/10.21105/joss.07668
Our [CITATION.cff](https://github.com/projectmesa/mesa/blob/main/CITATION.cff)
can be used to generate APA, BibTeX and other citation formats.
The original Mesa conference paper from 2015 is [available here](http://conference.scipy.org.s3-website-us-east-1.amazonaws.com/proceedings/scipy2015/jacqueline_kazil.html)
.
Indices and tables[#](#indices-and-tables "Link to this heading")
==================================================================
* [Index](genindex.html)
* [Module Index](py-modindex.html)
* [Search Page](search.html)
On this page
### This Page
* [Show Source](_sources/index.md.txt)
---
# Overview of the MESA library — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Overview of the MESA library[#](#overview-of-the-mesa-library "Link to this heading")
======================================================================================
Mesa is modular, meaning that its modeling, analysis and visualization components are kept separate but intended to work together. The modules are grouped into three categories:
1. **Modeling:** Classes used to build the models themselves: a model and agent classes, space for them to move around in, and built-in functionality for managing agents.
2. **Analysis:** Tools to collect data generated from your model, or to run it multiple times with different parameter values.
3. **Visualization:** Classes to create and launch an interactive model visualization, using a browser-based interface.
Modeling modules[#](#modeling-modules "Link to this heading")
--------------------------------------------------------------
Most models consist of one class to represent the model itself and one or more classes for agents. Mesa provides built-in functionality for managing agents and their interactions. These are implemented in Mesa’s modeling modules:
* [mesa.model](apis/model.html)
* [mesa.agent](apis/agent.html)
* [mesa.space](apis/space.html)
The skeleton of a model might look like this:
import mesa
class MyAgent(mesa.Agent):
def \_\_init\_\_(self, model, age):
super().\_\_init\_\_(model)
self.age \= age
def step(self):
self.age += 1
print(f"Agent {self.unique\_id} now is {self.age} years old")
\# Whatever else the agent does when activated
class MyModel(mesa.Model):
def \_\_init\_\_(self, n\_agents):
super().\_\_init\_\_()
self.grid \= mesa.space.MultiGrid(10, 10, torus\=True)
for \_ in range(n\_agents):
initial\_age \= self.random.randint(0, 80)
a \= MyAgent(self, initial\_age)
coords \= (self.random.randrange(0, 10), self.random.randrange(0, 10))
self.grid.place\_agent(a, coords)
def step(self):
self.agents.shuffle\_do("step")
Spaces in Mesa[#](#spaces-in-mesa "Link to this heading")
----------------------------------------------------------
Mesa provides several types of spaces where agents can exist and interact:
### Discrete Spaces[#](#discrete-spaces "Link to this heading")
Mesa implements discrete spaces using a doubly-linked structure where each cell maintains connections to its neighbors. Available variants include:
1. **Grid-based Spaces:**
\# Create a Von Neumann grid (4 neighbors per cell)
grid \= mesa.space.OrthogonalVonNeumannGrid((width, height), torus\=False)
\# Create a Moore grid (8 neighbors per cell)
grid \= mesa.space.OrthogonalMooreGrid((width, height), torus\=True)
\# Create a hexagonal grid
grid \= mesa.space.HexGrid((width, height), torus\=False)
2. **Network Space:**
\# Create a network-based space
network \= mesa.space.NetworkGrid(network)
3. **Voronoi Space:**
\# Create an irregular tessellation
mesh \= mesa.space.VoronoiMesh(points)
### Property Layers[#](#property-layers "Link to this heading")
Discrete spaces support PropertyLayers - efficient numpy-based arrays for storing cell-level properties:
\# Create and use a property layer
grid.create\_property\_layer("elevation", default\_value\=10)
high\_ground \= grid.elevation.select\_cells(lambda x: x \> 50)
### Continuous Space[#](#continuous-space "Link to this heading")
For models requiring continuous movement:
\# Create a continuous space
space \= mesa.space.ContinuousSpace(x\_max, y\_max, torus\=True)
\# Move an agent to specific coordinates
space.move\_agent(agent, (new\_x, new\_y))
Time Advancement and Agent Activation[#](#time-advancement-and-agent-activation "Link to this heading")
--------------------------------------------------------------------------------------------------------
Mesa supports multiple approaches to advancing time and activating agents:
### Basic Time Steps[#](#basic-time-steps "Link to this heading")
The simplest approach runs the model for a specified number of steps:
model \= MyModel(seed\=42)
for \_ in range(100):
model.step()
### Agent Activation Patterns[#](#agent-activation-patterns "Link to this heading")
Mesa 3.0 provides flexible agent activation through the AgentSet API:
\# Sequential activation
model.agents.do("step")
\# Random activation
model.agents.shuffle\_do("step")
\# Multi-stage activation
for stage in \["move", "eat", "reproduce"\]:
model.agents.do(stage)
\# Activation by agent type
for klass in model.agent\_types:
model.agents\_by\_type\[klass\].do("step")
### Event-Based Scheduling[#](#event-based-scheduling "Link to this heading")
Mesa also supports event-based time progression (experimental):
\# Pure event-based
simulator \= mesa.experimental.DiscreteEventSimulator()
model \= MyModel(seed\=42, simulator\=simulator)
simulator.schedule\_event\_relative(some\_function, 3.1415)
\# Hybrid time-step and event scheduling
model \= MyModel(seed\=42, simulator\=mesa.experimental.ABMSimulator())
model.simulator.schedule\_event\_next\_tick(some\_function)
AgentSet and model.agents[#](#agentset-and-model-agents "Link to this heading")
--------------------------------------------------------------------------------
Mesa 3.0 makes `model.agents` and the AgentSet class central in managing and activating agents.
### model.agents[#](#model-agents "Link to this heading")
`model.agents` is an AgentSet containing all agents in the model. It’s automatically updated when agents are added or removed:
\# Get total number of agents
num\_agents \= len(model.agents)
\# Iterate over all agents
for agent in model.agents:
print(agent.unique\_id)
### AgentSet Functionality[#](#agentset-functionality "Link to this heading")
AgentSet offers several methods for efficient agent management:
1. **Selecting**: Filter agents based on criteria.
high\_energy\_agents \= model.agents.select(lambda a: a.energy \> 50)
2. **Shuffling and Sorting**: Randomize or order agents.
shuffled\_agents \= model.agents.shuffle()
sorted\_agents \= model.agents.sort(key\="energy", ascending\=False)
3. **Applying methods**: Execute methods on all agents.
model.agents.do("step")
model.agents.shuffle\_do("move") \# Shuffle then apply method
4. **Aggregating**: Compute aggregate values across agents.
avg\_energy \= model.agents.agg("energy", func\=np.mean)
5. **Grouping**: Group agents by attributes.
grouped\_agents \= model.agents.groupby("species")
for \_, agent\_group in grouped\_agents:
agent\_group.shuffle\_do()
species\_counts \= grouped\_agents.count()
mean\_age\_by\_group \= grouped\_agents.agg("age", np.mean)
`model.agents` can also be accessed within a model instance using `self.agents`.
These are just some examples of using the AgentSet, there are many more possibilities, see the [AgentSet API docs](apis/agent.html)
.
Analysis modules[#](#analysis-modules "Link to this heading")
--------------------------------------------------------------
If you’re using modeling for research, you’ll want a way to collect the data each model run generates. You’ll probably also want to run the model multiple times, to see how some output changes with different parameters. Data collection and batch running are implemented in the appropriately-named analysis modules:
* [mesa.datacollection](apis/datacollection.html)
* [mesa.batchrunner](apis/batchrunner.html)
You’d add a data collector to the model like this:
import mesa
import numpy as np
\# ...
class MyModel(mesa.Model):
def \_\_init\_\_(self, n\_agents):
super().\_\_init\_\_()
\# ... (model initialization code)
self.datacollector \= mesa.DataCollector(
model\_reporters\={"mean\_age": lambda m: m.agents.agg("age", np.mean)},
agent\_reporters\={"age": "age"}
)
def step(self):
self.agents.shuffle\_do("step")
self.datacollector.collect(self)
The data collector will collect the specified model- and agent-level data at each step of the model. After you’re done running it, you can extract the data as a [pandas](http://pandas.pydata.org/)
DataFrame:
model \= MyModel(5)
for t in range(10):
model.step()
model\_df \= model.datacollector.get\_model\_vars\_dataframe()
agent\_df \= model.datacollector.get\_agent\_vars\_dataframe()
To batch-run the model while varying, for example, the n\_agents parameter, you’d use the [`batch_run`](apis/batchrunner.html)
function:
import mesa
parameters \= {"n\_agents": range(1, 6)}
results \= mesa.batch\_run(
MyModel,
parameters,
iterations\=5,
max\_steps\=100,
data\_collection\_period\=1,
number\_processes\=1 \# Change to use multiple CPU cores for parallel execution
)
The results are returned as a list of dictionaries, which can be easily converted to a pandas DataFrame for further analysis.
Visualization[#](#visualization "Link to this heading")
--------------------------------------------------------
Mesa now uses a new browser-based visualization system called SolaraViz. This allows for interactive, customizable visualizations of your models.
Note: SolaraViz is experimental and still in active development in Mesa 3.x. While we attempt to minimize them, there might be API breaking changes in minor releases.
> **Note:** SolaraViz instantiates new models using `**model_parameters.value`, so all model inputs must be keyword arguments.
Ensure your model’s `__init__` method accepts keyword arguments matching the `model_params` keys.
class MyModel(Model):
def \_\_init\_\_(self, n\_agents\=10, seed\=None):
super().\_\_init\_\_(seed\=seed)
\# Initialize the model with N agents
The core functionality for building your own visualizations resides in the [`mesa.visualization`](apis/visualization.html)
namespace.
Here’s a basic example of how to set up a visualization:
from mesa.visualization import SolaraViz, make\_space\_component, make\_plot\_component
def agent\_portrayal(agent):
return {"color": "blue", "size": 50}
model\_params \= {
"N": {
"type": "SliderInt",
"value": 50,
"label": "Number of agents:",
"min": 10,
"max": 100,
"step": 1,
}
}
page \= SolaraViz(
MyModel,
\[\
make\_space\_component(agent\_portrayal),\
make\_plot\_component("mean\_age")\
\],
model\_params\=model\_params
)
page
This will create an interactive visualization of your model, including:
* A grid visualization of agents
* A plot of a model metric over time
* A slider to adjust the number of agents
On this page
### This Page
* [Show Source](_sources/overview.md.txt)
---
# Mesa Core Examples — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Mesa Core Examples[#](#mesa-core-examples "Link to this heading")
==================================================================
This repository contains a curated set of classic agent-based models implemented using Mesa. These core examples are maintained by the Mesa development team and serve as both demonstrations of Mesa’s capabilities and starting points for your own models.
Overview[#](#overview "Link to this heading")
----------------------------------------------
The examples are categorized into two groups:
1. **Basic Examples** - Simpler models that use only stable Mesa features; ideal for beginners
2. **Advanced Examples** - More complex models that demonstrate additional concepts and may use some experimental features
> **Note:** Looking for more examples? Visit the [mesa-examples](https://github.com/projectmesa/mesa-examples)
> repository for user-contributed models and showcases.
Basic Examples[#](#basic-examples "Link to this heading")
----------------------------------------------------------
The basic examples are relatively simple and only use stable Mesa features. They are good starting points for learning how to use Mesa.
### [Boltzmann Wealth Model](examples/basic/boltzmann_wealth_model.html)
[#](#boltzmann-wealth-model "Link to this heading")
Completed code to go along with the [tutorial](https://mesa.readthedocs.io/latest/tutorials/intro_tutorial.html)
on making a simple model of how a highly-skewed wealth distribution can emerge from simple rules.
### [Boids Flockers Model](examples/basic/boid_flockers.html)
[#](#boids-flockers-model "Link to this heading")
[Boids](https://en.wikipedia.org/wiki/Boids)
\-style flocking model, demonstrating the use of agents moving through a continuous space following direction vectors.
### [Conway’s Game of Life](examples/basic/conways_game_of_life.html)
[#](#conway-s-game-of-life "Link to this heading")
Implementation of [Conway’s Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life)
, a cellular automata where simple rules can give rise to complex patterns.
### [Schelling Segregation Model](examples/basic/schelling.html)
[#](#schelling-segregation-model "Link to this heading")
Mesa implementation of the classic [Schelling segregation](http://nifty.stanford.edu/2014/mccown-schelling-model-segregation/)
model.
### [Virus on a Network Model](examples/basic/virus_on_network.html)
[#](#virus-on-a-network-model "Link to this heading")
This model is based on the NetLogo [Virus on a Network](https://ccl.northwestern.edu/netlogo/models/VirusonaNetwork)
model.
Advanced Examples[#](#advanced-examples "Link to this heading")
----------------------------------------------------------------
The advanced examples are more complex and may use experimental Mesa features. They are good starting points for learning how to build more complex models.
### [Epstein Civil Violence Model](examples/advanced/epstein_civil_violence.html)
[#](#epstein-civil-violence-model "Link to this heading")
Joshua Epstein’s [model](https://www.pnas.org/doi/10.1073/pnas.092080199)
of how a decentralized uprising can be suppressed or reach a critical mass of support.
### [Demographic Prisoner’s Dilemma on a Grid](examples/advanced/pd_grid.html)
[#](#demographic-prisoner-s-dilemma-on-a-grid "Link to this heading")
Grid-based demographic prisoner’s dilemma model, demonstrating how simple rules can lead to the emergence of widespread cooperation – and how a model activation regime can change its outcome.
### [Sugarscape Model with Traders](examples/advanced/sugarscape_g1mt.html)
[#](#sugarscape-model-with-traders "Link to this heading")
This is Epstein & Axtell’s Sugarscape model with Traders, a detailed description is in Chapter four of _Growing Artificial Societies: Social Science from the Bottom Up (1996)_. The model shows how emergent price equilibrium can happen via decentralized dynamics.
### [Wolf-Sheep Predation Model](examples/advanced/wolf_sheep.html)
[#](#wolf-sheep-predation-model "Link to this heading")
Implementation of an ecological model of predation and reproduction, based on the NetLogo [Wolf Sheep Predation](http://ccl.northwestern.edu/netlogo/models/WolfSheepPredation)
model.
On this page
### This Page
* [Show Source](_sources/examples.md.txt)
---
# Mesa Migration guide — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Mesa Migration guide[#](#mesa-migration-guide "Link to this heading")
======================================================================
This guide contains breaking changes between major Mesa versions and how to resolve them.
Non-breaking changes aren’t included, for those see our [Release history](https://github.com/projectmesa/mesa/releases)
.
Mesa 3.0[#](#mesa-3-0 "Link to this heading")
----------------------------------------------
Mesa 3.0 introduces significant changes to core functionalities, including agent and model initialization, scheduling, and visualization. The guide below outlines these changes and provides instructions for migrating your existing Mesa projects to version 3.0.
_This guide is a work in progress. The development of it is tracked in [Issue #2233](https://github.com/projectmesa/mesa/issues/2233)
._
### Upgrade strategy[#](#upgrade-strategy "Link to this heading")
We recommend the following upgrade strategy:
* Update to the latest Mesa 2.x release (`mesa<3`).
* Update to the latest Mesa 3.0.x release (`mesa<3.1`).
* Update to the latest Mesa 3.x release (`mesa<4`).
With each update, resolve all errors and warnings, before updating to the next one.
### Reserved and private variables[#](#reserved-and-private-variables "Link to this heading")
#### Reserved variables[#](#reserved-variables "Link to this heading")
Currently, we have reserved the following variables:
* Model: `agents`, `current_id`, `random`, `running`, `steps`, `time`.
* Agent: `unique_id`, `model`.
You can use (read) any reserved variable, but Mesa may update them automatically and rely on them, so modify/update at your own risk.
#### Private variables[#](#private-variables "Link to this heading")
Any variables starting with an underscore (`_`) are considered private and for Mesa’s internal use. We might use any of those. Modifying or overwriting any private variable is at your own risk.
* Ref: [Discussion #2230](https://github.com/projectmesa/mesa/discussions/2230)
, [PR #2225](https://github.com/projectmesa/mesa/pull/2225)
### Removal of `mesa.flat` namespace[#](#removal-of-mesa-flat-namespace "Link to this heading")
The `mesa.flat` namespace is removed. Use the full namespace for your imports.
* Ref: [PR #2091](https://github.com/projectmesa/mesa/pull/2091)
### Mandatory Model initialization with `super().__init__()`[#](#mandatory-model-initialization-with-super-init "Link to this heading")
In Mesa 3.0, it is now mandatory to call `super().__init__()` when initializing your model class. This ensures that all necessary Mesa model variables are correctly set up and agents are properly added to the model. If you want to control the seed of the random number generator, you have to pass this as a keyword argument to super as shown below.
Make sure all your model classes explicitly call `super().__init__()` in their `__init__` method:
class MyModel(mesa.Model):
def \_\_init\_\_(self, some\_arg\_I\_need, seed\=None, some\_kwarg\_I\_need\=True):
super().\_\_init\_\_(seed\=seed) \# Calling super is now required, passing seed is highly recommended
\# Your model initialization code here
\# this code uses some\_arg\_I\_need and my\_init\_kwarg
This change ensures that all Mesa models are properly initialized, which is crucial for:
* Correctly adding agents to the model
* Setting up other essential Mesa model variables
* Maintaining consistency across all models
If you forget to call `super().__init__()`, you’ll now see this error:
RuntimeError: The Mesa Model class was not initialized. You must explicitly initialize the Model by calling super().\_\_init\_\_() on initialization.
* Ref: [PR #2218](https://github.com/projectmesa/mesa/pull/2218)
, [PR #1928](https://github.com/projectmesa/mesa/pull/1928)
, Mesa-examples [PR #83](https://github.com/projectmesa/mesa-examples/pull/83)
### Automatic assignment of `unique_id` to Agents[#](#automatic-assignment-of-unique-id-to-agents "Link to this heading")
In Mesa 3.0, `unique_id` for agents is now automatically assigned, simplifying agent creation and ensuring unique IDs across all agents in a model.
1. Remove `unique_id` from agent initialization:
\# Old
agent \= MyAgent(unique\_id\=unique\_id, model\=self, ...)
agent \= MyAgent(unique\_id, self, ...)
agent \= MyAgent(self.next\_id(), self, ...)
\# New
agent \= MyAgent(model\=self, ...)
agent \= MyAgent(self, ...)
2. Remove `unique_id` from Agent super() call:
\# Old
class MyAgent(Agent):
def \_\_init\_\_(self, unique\_id, model, ...):
super().\_\_init\_\_(unique\_id, model)
\# New
class MyAgent(Agent):
def \_\_init\_\_(self, model, ...):
super().\_\_init\_\_(model)
3. Important notes:
* `unique_id` is now automatically assigned relative to a Model instance and starts from 1
* `Model.next_id()` is removed
* If you previously used custom `unique_id` values, store that information in a separate attribute
* Ref: [PR #2226](https://github.com/projectmesa/mesa/pull/2226)
, [PR #2260](https://github.com/projectmesa/mesa/pull/2260)
, Mesa-examples [PR #194](https://github.com/projectmesa/mesa-examples/pull/194)
, [Issue #2213](https://github.com/projectmesa/mesa/issues/2213)
### AgentSet and `Model.agents`[#](#agentset-and-model-agents "Link to this heading")
In Mesa 3.0, the Model class internally manages agents using several data structures:
* `self._agents`: A dictionary containing hard references to all agents, indexed by their `unique_id`.
* `self._agents_by_type`: A dictionary of AgentSets, organizing agents by their type.
* `self._all_agents`: An AgentSet containing all agents in the model.
These internal structures are used to efficiently manage and access agents. Users should interact with agents through the public `model.agents` property, which returns the `self._all_agents` AgentSet.
#### `Model.agents`[#](#model-agents "Link to this heading")
* Attempting to set `model.agents` now raises an `AttributeError` instead of a warning. This attribute is reserved for internal use by Mesa.
* If you were previously setting `model.agents` in your code, you must update it to use a different attribute name for custom agent storage.
For example, replace:
model.agents \= my\_custom\_agents
With:
model.custom\_agents \= my\_custom\_agents
### Time and schedulers[#](#time-and-schedulers "Link to this heading")
#### Automatic increase of the `steps` counter[#](#automatic-increase-of-the-steps-counter "Link to this heading")
The `steps` counter is now automatically increased. With each call to `Model.steps()` it’s increased by 1, at the beginning of the step.
You can access it by `Model.steps`, and it’s internally in the datacollector, batchrunner and the visualisation.
* Ref: [PR #2223](https://github.com/projectmesa/mesa/pull/2223)
, Mesa-examples [PR #161](https://github.com/projectmesa/mesa-examples/pull/161)
#### Removal of `Model._time` and rename `._steps`[#](#removal-of-model-time-and-rename-steps "Link to this heading")
* `Model._time` is removed. You can define your own time variable if needed.
* `Model._steps` steps is renamed to `Model.steps`.
#### Removal of `Model._advance_time()`[#](#removal-of-model-advance-time "Link to this heading")
* The `Model._advance_time()` method is removed. This now happens automatically.
#### Replacing Schedulers with AgentSet functionality[#](#replacing-schedulers-with-agentset-functionality "Link to this heading")
The whole Time module in Mesa is deprecated and will be removed in Mesa 3.1. All schedulers should be replaced with AgentSet functionality and the internal `Model.steps` counter. This allows much more flexibility in how to activate Agents and makes it explicit what’s done exactly.
Here’s how to replace each scheduler:
##### BaseScheduler[#](#basescheduler "Link to this heading")
Replace:
self.schedule \= BaseScheduler(self)
self.schedule.step()
With:
self.agents.do("step")
##### RandomActivation[#](#randomactivation "Link to this heading")
Replace:
self.schedule \= RandomActivation(self)
self.schedule.step()
With:
self.agents.shuffle\_do("step")
##### SimultaneousActivation[#](#simultaneousactivation "Link to this heading")
Replace:
self.schedule \= SimultaneousActivation(self)
self.schedule.step()
With:
self.agents.do("step")
self.agents.do("advance")
##### StagedActivation[#](#stagedactivation "Link to this heading")
Replace:
self.schedule \= StagedActivation(self, \["stage1", "stage2", "stage3"\])
self.schedule.step()
With:
for stage in \["stage1", "stage2", "stage3"\]:
self.agents.do(stage)
If you were using the `shuffle` and/or `shuffle_between_stages` options:
stages \= \["stage1", "stage2", "stage3"\]
if shuffle:
self.random.shuffle(stages)
for stage in stages:
if shuffle\_between\_stages:
self.agents.shuffle\_do(stage)
else:
self.agents.do(stage)
##### RandomActivationByType[#](#randomactivationbytype "Link to this heading")
Replace:
self.schedule \= RandomActivationByType(self)
self.schedule.step()
With:
for agent\_class in self.agent\_types:
self.agents\_by\_type\[agent\_class\].shuffle\_do("step")
###### Replacing `step_type`[#](#replacing-step-type "Link to this heading")
The `RandomActivationByType` scheduler had a `step_type` method that allowed stepping only agents of a specific type. To replicate this functionality using AgentSet:
Replace:
self.schedule.step\_type(AgentType)
With:
self.agents\_by\_type\[AgentType\].shuffle\_do("step")
##### General Notes[#](#general-notes "Link to this heading")
1. The `Model.steps` counter is now automatically incremented. You don’t need to manage it manually.
2. If you were using `self.schedule.agents`, replace it with `self.agents`.
3. If you were using `self.schedule.get_agent_count()`, replace it with `len(self.agents)`.
4. If you were using `self.schedule.agents_by_type`, replace it with `self.agents_by_type`.
5. Agents are now automatically added to or removed from the model’s `AgentSet` (`model.agents`) when they are created or deleted, eliminating the need to manually call `self.schedule.add()` or `self.schedule.remove()`.
* However, you still need to explicitly remove the Agent itself by using `Agent.remove()`. Typically, this means:
* Replace `self.schedule.remove(agent)` with `agent.remove()` in the Model.
* Replace `self.model.schedule.remove(self)` with `self.remove()` within the Agent.
From now on you’re now not bound by 5 distinct schedulers, but can mix and match any combination of AgentSet methods (`do`, `shuffle`, `select`, etc.) to get the desired Agent activation.
Ref: Original discussion [#1912](https://github.com/projectmesa/mesa/discussions/1912)
, decision discussion [#2231](https://github.com/projectmesa/mesa/discussions/2231)
, example updates [#183](https://github.com/projectmesa/mesa-examples/pull/183)
and [#201](https://github.com/projectmesa/mesa-examples/pull/201)
, PR [#2306](https://github.com/projectmesa/mesa/pull/2306)
### Visualisation[#](#visualisation "Link to this heading")
Mesa has adopted a new API for our frontend. If you already migrated to the experimental new SolaraViz you can still use the import from mesa.experimental. Otherwise here is a list of things you need to change.
> **Note:** SolaraViz is experimental and still in active development for Mesa 3.0. While we attempt to minimize them, there might be API breaking changes between Mesa 3.0 and 3.1. There won’t be breaking changes between Mesa 3.0.x patch releases.
#### Model Initialization[#](#model-initialization "Link to this heading")
Previously SolaraViz was initialized by providing a `model_cls` and a `model_params`. This has changed to expect a model instance `model`. You can still provide (user-settable) `model_params`, but only if users should be able to change them. It is now also possible to pass in a “reactive model” by first calling `model = solara.reactive(model)`. This is useful for notebook environments. It allows you to pass the model to the SolaraViz Module, but continue to use the model. For example calling `model.value.step()` (notice the extra .value) will automatically update the plots. This currently only automatically works for the step method, you can force visualization updates by calling `model.value.force_update()`.
### Model Initialization with Keyword Arguments[#](#model-initialization-with-keyword-arguments "Link to this heading")
With the introduction of SolaraViz in Mesa 3.0, models are now instantiated using `**model_parameters.value`. This means all inputs for initializing a new model must be keyword arguments. Ensure your model’s `__init__` method accepts keyword arguments matching the keys in `model_params`.
class MyModel(mesa.Model):
def \_\_init\_\_(self, n\_agents\=10, seed\=None):
super().\_\_init\_\_(seed\=seed)
\# Initialize the model with N agents
#### Default space visualization[#](#default-space-visualization "Link to this heading")
Previously we included a default space drawer that you could configure with an `agent_portrayal` function. You now have to explicitly create a space drawer with the `agent_portrayal` function
\# old
from mesa.experimental import SolaraViz
SolaraViz(model\_cls, model\_params, agent\_portrayal\=agent\_portrayal)
\# new
from mesa.visualization import SolaraViz, make\_space\_component
SolaraViz(model, components\=\[make\_space\_component(agent\_portrayal)\])
#### Plotting “measures”[#](#plotting-measures "Link to this heading")
“Measure” plots also need to be made explicit here. Previously, measure could either be 1) A function that receives a model and returns a solara component or 2) A string or list of string of variables that are collected by the datacollector and are to be plotted as a line plot. 1) still works, but you can pass that function to “components” directly. 2) needs to explicitly call the `make_plot_measure()`function.
\# old
from mesa.experimental import SolaraViz
def make\_plot(model):
...
SolaraViz(model\_cls, model\_params, measures\=\[make\_plot, "foo", \["bar", "baz"\]\])
\# new
from mesa.visualization import SolaraViz, make\_plot\_component
SolaraViz(model, components\=\[make\_plot, make\_plot\_component("foo"), make\_plot\_component("bar", "baz")\])
#### Plotting text[#](#plotting-text "Link to this heading")
To plot model-dependent text the experimental SolaraViz provided a `make_text` function that wraps another functions that receives the model and turns its string return value into a solara text component. Again, this other function can now be passed directly to the new SolaraViz components array. It is okay if your function just returns a string.
\# old
from mesa.experimental import SolaraViz, make\_text
def show\_steps(model):
return f"Steps: {model.steps}"
SolaraViz(model\_cls, model\_params, measures\=make\_text(show\_steps))
\# new
from mesa.visualisation import SolaraViz
def show\_steps(model):
return f"Steps: {model.steps}"
SolaraViz(model, components\=\[show\_steps\])
### Other changes[#](#other-changes "Link to this heading")
#### Removal of Model.initialize\_data\_collector[#](#removal-of-model-initialize-data-collector "Link to this heading")
The `initialize_data_collector` in the Model class is removed. In the Model class, replace:
Replace:
self.initialize\_data\_collector(...)
With:
self.datacollector \= DataCollector(...)
* Ref: [PR #2327](https://github.com/projectmesa/mesa/pull/2327)
, Mesa-examples [PR #208](https://github.com/projectmesa/mesa-examples/pull/208)
)
On this page
### This Page
* [Show Source](_sources/migration_guide.md.txt)
---
# Adding Space — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Adding Space[#](#adding-space "Link to this heading")
======================================================
The Boltzmann Wealth Model[#](#the-boltzmann-wealth-model "Link to this heading")
----------------------------------------------------------------------------------
If you want to get straight to the tutorial checkout these environment providers:
(with Google Account) [](https://colab.research.google.com/github/projectmesa/mesa/blob/main/docs/tutorials/1_adding_space.ipynb)
(no Google Account) [](https://mybinder.org/v2/gh/projectmesa/mesa/main?labpath=docs%2Ftutorials%2F1_adding_space.ipynb)
(This can take 30 seconds to 5 minutes to load)
_If you are running locally, please ensure you have the latest Mesa version installed._
Tutorial Description[#](#tutorial-description "Link to this heading")
----------------------------------------------------------------------
This tutorial extends the Boltzmann wealth model from the [Running Your First Model tutorial](https://mesa.readthedocs.io/latest/tutorials/0_first_model.html)
, by adding Mesa’s discrete space module.
In this portion, `MoneyAgent`s will move in a two dimensional grid, made up of discrete cells and randomly exchange money with other agents.
_If you are starting here please see the [Running Your First Model tutorial](https://mesa.readthedocs.io/latest/tutorials/0_first_model.html)
for dependency and start-up instructions_
### IN COLAB? - Run the next cell[#](#in-colab-run-the-next-cell "Link to this heading")
### Import Dependencies[#](#import-dependencies "Link to this heading")
This includes importing of dependencies needed for the tutorial.
\# Has multi-dimensional arrays and matrices.
\# Has a large collection of mathematical functions to operate on these arrays.
import numpy as np
\# Data manipulation and analysis.
import pandas as pd
\# Data visualization tools.
import seaborn as sns
import mesa
Base Model[#](#base-model "Link to this heading")
--------------------------------------------------
The below provides the base model from which we will add our space functionality.
This is from the [Running Your First Model tutorial](https://mesa.readthedocs.io/latest/tutorials/0_first_model.html)
tutorial. If you have any questions about it functionality please review that tutorial.
class MoneyAgent(mesa.Agent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model):
\# Pass the parameters to the parent class.
super().\_\_init\_\_(model)
\# Create the agent's variable and set the initial values.
self.wealth \= 1
def exchange(self):
\# Verify agent has some wealth
if self.wealth \> 0:
other\_agent \= self.random.choice(self.model.agents)
if other\_agent is not None:
other\_agent.wealth += 1
self.wealth \-= 1
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n):
super().\_\_init\_\_()
self.num\_agents \= n
\# Create agents
MoneyAgent.create\_agents(model\=self, n\=n)
def step(self):
"""Advance the model by one step."""
\# This function psuedo-randomly reorders the list of agent objects and
\# then iterates through calling the function passed in as the parameter
self.agents.shuffle\_do("exchange")
\# Execute the model
model \= MoneyModel(10)
model.step()
\# Make sure it worked
print(f"You have {len(model.agents)} agents.")
You have 10 agents.
Adding space[#](#id1 "Link to this heading")
---------------------------------------------
**Background:** Due to the complex dynamics of space and movement, Mesa offers a wide range space options and has built a structure to allow for the addition of even more spaces or custom user space creation. (Please contribute to Mesa if you develop a new space that can add to user options.)
The two main approaches to space are discrete space (think cells or nodes that agents occupy) and continuous space (agents can occupy any location(s) in a three-dimensional space). Continuous space is still experimental as we continue to develop it.
**Overview of Discrete Space:** For this tutorial we will be using discrete space in the classic cartesian coordinated system. As indicated in the diagram discrete space is made up of two modules. Cells and Cell Agents.
**Cells:** The cell class represents a location that can:
* Have properties (like temperature or resources)
* Track and limit the agents it contains
* Connect to neighboring cells
* Provide neighborhood information
Cells form the foundation of the cell space system, enabling rich spatial environments where both location properties and agent behaviors matter. They’re useful for modeling things like varying terrain, infrastructure capacity, or environmental conditions.
**Cell Agents:** Agents that understand how to exist in and move through cell spaces.
Cell Agents are specialized agent classes that handle cell occupation, movement, and proper registration:
* `CellAgent`: Mobile agents that can move between cells
* `FixedAgent`: Immobile agents permanently fixed to cells
* `Grid2DMovingAgent`: Agents with grid-specific movement capabilities
These classes ensure consistent agent-cell relationships and proper state management as agents move through the space. They can be used directly or as examples for creating custom cell-aware agents.
From these basic building blocks we can then add features to allow for different types of spaces and behaviors. To keep this tutorial concise we will not go through all of them, however, the current layout of discrete space is below as well as the different support modules. To find out more about the other options and what they can do, check out the [Discrete Space API](https://mesa.readthedocs.io/latest/apis/discrete_space.html)

_A big thanks to maintainer qualquel and his creation of this exceptional space dynamic._
**Model-specific information:** In addition to using discrete space, the agents will access their [Moore neighborhood](https://en.wikipedia.org/wiki/Moore_neighborhood)
. A Moore neighborhood means agents can interact with 8 neighbors. Instead of giving their unit of money to any random agent, they’ll give it to an agent on the same cell. For the Money model multiple agents can be in the same spaces and since they are on a torus the agents on the left side can exchange money with agent on the right. Agents on the top can exchange with agents on the bottom.
### Code Implementation[#](#code-implementation "Link to this heading")
To ensure we give our agents discrete space functionality we now instantiate our `MoneyAgent`s as `CellAgent`s. `Cell Agent` is a subclass to Mesa’s `Agent` class that is specifically built to interact and move within the `discrete space` module.
Below highlights each of the changes to the base code to add space and movement of agents.
**Imports**
\# Import Cell Agent and OrthogonalMooreGrid
* _Description:_ Import the cell agent class and a specific grid construct the OrthognalMooreGrid.
* _API_: [CellAgent](https://mesa.readthedocs.io/latest/apis/discrete_space.html#mesa.discrete_space.__init__.CellAgent)
and [OrthogonalMooreGrid](https://mesa.readthedocs.io/latest/apis/discrete_space.html#mesa.discrete_space.grid.OrthogonalMooreGrid)
**MoneyAgent Class**
\# Instantiate MoneyAgent as CellAgent
* _Description:_ `MoneyAgent` inherits `CellAgent`, a subclass of `Agent`.
* _API_: [CellAgent](https://mesa.readthedocs.io/latest/apis/discrete_space.html#mesa.discrete_space.__init__.CellAgent)
\# Instantiate agent with location (x,y)
* _Description:_ Pass the cell object as a parameter to the agent to give the agent a location
* _API_: N/A
\# Move function
* _Description:_ Update the agents cell through methods in Mesa’s discrete\_space module `neighborhood`, which defaults to radius one and `select_random_cell` which selects a random cell for the provided neighborhood
* _API_: [neighborhood](https://mesa.readthedocs.io/latest/apis/discrete_space.html#mesa.discrete_space.__init__.Cell.neighborhood)
and [select\_random\_cell](https://mesa.readthedocs.io/latest/apis/discrete_space.html#mesa.discrete_space.__init__.CellCollection.select_random_cell)
**MoneyModel Class**
\# Instantiate an instance of Moore neighborhood space
* _Description:_ Instantiate a OrthgonalMooreGrid as `self.grid` with passing in the parameters width and height as a tuple, torus as True, a cell capacity of 5 agents, and the models random seed to the discrete space
* _API_: [OrthogonalMooreGrid](https://mesa.readthedocs.io/latest/apis/discrete_space.html#mesa.discrete_space.grid.OrthogonalMooreGrid)
\# Randomly select agents cell
* _Description:_ Use Python’s `random.choices` and pass in all cells with discrete space all\_cells properties and the number of choices `k` to assign each agent a location.
* _API_: [random.choices](https://docs.python.org/3/library/random.html#random.choices)
and [all\_cells](https://mesa.readthedocs.io/latest/apis/discrete_space.html#id1)
\# Import Cell Agent and OrthogonalMooreGrid
from mesa.discrete\_space import CellAgent, OrthogonalMooreGrid
\# Instantiate MoneyAgent as CellAgent
class MoneyAgent(CellAgent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model, cell):
super().\_\_init\_\_(model)
self.cell \= cell \# Instantiate agent with location (x,y)
self.wealth \= 1
\# Move Function
def move(self):
self.cell \= self.cell.neighborhood.select\_random\_cell()
def give\_money(self):
cellmates \= \[\
a for a in self.cell.agents if a is not self\
\] \# Get all agents in cell
if self.wealth \> 0 and cellmates:
other\_agent \= self.random.choice(cellmates)
other\_agent.wealth += 1
self.wealth \-= 1
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n, width, height, seed\=None):
super().\_\_init\_\_(seed\=seed)
self.num\_agents \= n
\# Instantiate an instance of Moore neighborhood space
self.grid \= OrthogonalMooreGrid(
(width, height), torus\=True, capacity\=10, random\=self.random
)
\# Create agents
agents \= MoneyAgent.create\_agents(
self,
self.num\_agents,
\# Randomly select agents cell
self.random.choices(self.grid.all\_cells.cells, k\=self.num\_agents),
)
def step(self):
self.agents.shuffle\_do("move")
self.agents.do("give\_money")
Let’s create a model with 100 agents on a 10x10 grid, and run it for 20 steps.
model \= MoneyModel(100, 10, 10)
for \_ in range(20):
model.step()
Now let’s use seaborn and numpy to visualize the number of agents residing in each cell. To do that, we create a numpy array of the same size as the grid, filled with zeros.
Then again use `all_cells` to loop over every cell in the grid, giving us each cell’s position (cell coordinate attribute) and its contents (cell agent attribute).
[Cell API](https://mesa.readthedocs.io/latest/apis/discrete_space.html#mesa.discrete_space.__init__.Cell)
agent\_counts \= np.zeros((model.grid.width, model.grid.height))
for cell in model.grid.all\_cells:
agent\_counts\[cell.coordinate\] \= len(cell.agents)
\# Plot using seaborn, with a visual size of 5x5
g \= sns.heatmap(agent\_counts, cmap\="viridis", annot\=True, cbar\=False, square\=True)
g.figure.set\_size\_inches(5, 5)
g.set(title\="Number of agents on each cell of the grid");

### Exercises[#](#exercises "Link to this heading")
* Change the size of the grid
* Change the capacity of the cells
* Try a different grid space like OrthognalVonNeumann, Network, or Voronoi
Next Steps[#](#next-steps "Link to this heading")
--------------------------------------------------
Check out the [collecting data tutorial](https://mesa.readthedocs.io/latest/tutorials/2_collecting_data_tutorial.html)
on how to collect data form your model.
\[Comer2014\] Comer, Kenneth W. “Who Goes First? An Examination of the Impact of Activation on Outcome Behavior in AgentBased Models.” George Mason University, 2014. http://mars.gmu.edu/bitstream/handle/1920/9070/Comer\_gmu\_0883E\_10539.pdf
\[Dragulescu2002\] Drăgulescu, Adrian A., and Victor M. Yakovenko. “Statistical Mechanics of Money, Income, and Wealth: A Short Survey.” arXiv Preprint Cond-mat/0211175, 2002. http://arxiv.org/abs/cond-mat/0211175.
On this page
### This Page
* [Show Source](../_sources/tutorials/1_adding_space.ipynb.txt)
---
# APIs — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
APIs[#](#apis "Link to this heading")
======================================
* [Model](model.html)
* [`Model`](model.html#mesa.model.Model)
* [`Model.running`](model.html#mesa.model.Model.running)
* [`Model.steps`](model.html#mesa.model.Model.steps)
* [`Model.random`](model.html#mesa.model.Model.random)
* [`Model.rng`](model.html#mesa.model.Model.rng)
* [`Model.agents`](model.html#mesa.model.Model.agents)
* [`Model.agent_types`](model.html#mesa.model.Model.agent_types)
* [`Model.agents_by_type`](model.html#mesa.model.Model.agents_by_type)
* [`Model.register_agent()`](model.html#mesa.model.Model.register_agent)
* [`Model.deregister_agent()`](model.html#mesa.model.Model.deregister_agent)
* [`Model.run_model()`](model.html#mesa.model.Model.run_model)
* [`Model.step()`](model.html#mesa.model.Model.step)
* [`Model.reset_randomizer()`](model.html#mesa.model.Model.reset_randomizer)
* [`Model.reset_rng()`](model.html#mesa.model.Model.reset_rng)
* [`Model.remove_all_agents()`](model.html#mesa.model.Model.remove_all_agents)
* [Agent](agent.html)
* [`Agent`](agent.html#mesa.agent.Agent)
* [`Agent.model`](agent.html#mesa.agent.Agent.model)
* [`Agent.unique_id`](agent.html#mesa.agent.Agent.unique_id)
* [`Agent.pos`](agent.html#mesa.agent.Agent.pos)
* [`Agent.remove()`](agent.html#mesa.agent.Agent.remove)
* [`Agent.step()`](agent.html#mesa.agent.Agent.step)
* [`Agent.create_agents()`](agent.html#mesa.agent.Agent.create_agents)
* [`Agent.random`](agent.html#mesa.agent.Agent.random)
* [`Agent.rng`](agent.html#mesa.agent.Agent.rng)
* [`AgentSet`](agent.html#mesa.agent.AgentSet)
* [`AgentSet.model`](agent.html#mesa.agent.AgentSet.model)
* [`AgentSet.select()`](agent.html#mesa.agent.AgentSet.select)
* [`AgentSet.shuffle()`](agent.html#mesa.agent.AgentSet.shuffle)
* [`AgentSet.sort()`](agent.html#mesa.agent.AgentSet.sort)
* [`AgentSet.do()`](agent.html#mesa.agent.AgentSet.do)
* [`AgentSet.shuffle_do()`](agent.html#mesa.agent.AgentSet.shuffle_do)
* [`AgentSet.map()`](agent.html#mesa.agent.AgentSet.map)
* [`AgentSet.agg()`](agent.html#mesa.agent.AgentSet.agg)
* [`AgentSet.get()`](agent.html#mesa.agent.AgentSet.get)
* [`AgentSet.set()`](agent.html#mesa.agent.AgentSet.set)
* [`AgentSet.add()`](agent.html#mesa.agent.AgentSet.add)
* [`AgentSet.discard()`](agent.html#mesa.agent.AgentSet.discard)
* [`AgentSet.remove()`](agent.html#mesa.agent.AgentSet.remove)
* [`AgentSet.groupby()`](agent.html#mesa.agent.AgentSet.groupby)
* [`AgentSet.clear()`](agent.html#mesa.agent.AgentSet.clear)
* [`AgentSet.count()`](agent.html#mesa.agent.AgentSet.count)
* [`AgentSet.index()`](agent.html#mesa.agent.AgentSet.index)
* [`AgentSet.isdisjoint()`](agent.html#mesa.agent.AgentSet.isdisjoint)
* [`AgentSet.pop()`](agent.html#mesa.agent.AgentSet.pop)
* [`GroupBy`](agent.html#mesa.agent.GroupBy)
* [`GroupBy.groups`](agent.html#mesa.agent.GroupBy.groups)
* [`GroupBy.map()`](agent.html#mesa.agent.GroupBy.map)
* [`GroupBy.do()`](agent.html#mesa.agent.GroupBy.do)
* [`GroupBy.count()`](agent.html#mesa.agent.GroupBy.count)
* [`GroupBy.agg()`](agent.html#mesa.agent.GroupBy.agg)
* [Spaces](space.html)
* [Classes](space.html#classes)
* [`accept_tuple_argument()`](space.html#mesa.space.accept_tuple_argument)
* [`is_integer()`](space.html#mesa.space.is_integer)
* [`warn_if_agent_has_position_already()`](space.html#mesa.space.warn_if_agent_has_position_already)
* [`is_single_argument_function()`](space.html#mesa.space.is_single_argument_function)
* [`PropertyLayer`](space.html#mesa.space.PropertyLayer)
* [`PropertyLayer.name`](space.html#mesa.space.PropertyLayer.name)
* [`PropertyLayer.width`](space.html#mesa.space.PropertyLayer.width)
* [`PropertyLayer.height`](space.html#mesa.space.PropertyLayer.height)
* [`PropertyLayer.data`](space.html#mesa.space.PropertyLayer.data)
* [`PropertyLayer.set_cell()`](space.html#mesa.space.PropertyLayer.set_cell)
* [`PropertyLayer.set_cells()`](space.html#mesa.space.PropertyLayer.set_cells)
* [`PropertyLayer.modify_cell()`](space.html#mesa.space.PropertyLayer.modify_cell)
* [`PropertyLayer.modify_cells()`](space.html#mesa.space.PropertyLayer.modify_cells)
* [`PropertyLayer.select_cells()`](space.html#mesa.space.PropertyLayer.select_cells)
* [`PropertyLayer.aggregate_property()`](space.html#mesa.space.PropertyLayer.aggregate_property)
* [`SingleGrid`](space.html#mesa.space.SingleGrid)
* [`SingleGrid.remove_agent()`](space.html#mesa.space.SingleGrid.remove_agent)
* [`SingleGrid.add_property_layer()`](space.html#mesa.space.SingleGrid.add_property_layer)
* [`SingleGrid.agents`](space.html#mesa.space.SingleGrid.agents)
* [`SingleGrid.coord_iter()`](space.html#mesa.space.SingleGrid.coord_iter)
* [`SingleGrid.default_val()`](space.html#mesa.space.SingleGrid.default_val)
* [`SingleGrid.empty_mask`](space.html#mesa.space.SingleGrid.empty_mask)
* [`SingleGrid.exists_empty_cells()`](space.html#mesa.space.SingleGrid.exists_empty_cells)
* [`SingleGrid.get_neighborhood()`](space.html#mesa.space.SingleGrid.get_neighborhood)
* [`SingleGrid.get_neighborhood_mask()`](space.html#mesa.space.SingleGrid.get_neighborhood_mask)
* [`SingleGrid.get_neighbors()`](space.html#mesa.space.SingleGrid.get_neighbors)
* [`SingleGrid.is_cell_empty()`](space.html#mesa.space.SingleGrid.is_cell_empty)
* [`SingleGrid.iter_neighborhood()`](space.html#mesa.space.SingleGrid.iter_neighborhood)
* [`SingleGrid.iter_neighbors()`](space.html#mesa.space.SingleGrid.iter_neighbors)
* [`SingleGrid.move_agent()`](space.html#mesa.space.SingleGrid.move_agent)
* [`SingleGrid.move_agent_to_one_of()`](space.html#mesa.space.SingleGrid.move_agent_to_one_of)
* [`SingleGrid.move_to_empty()`](space.html#mesa.space.SingleGrid.move_to_empty)
* [`SingleGrid.out_of_bounds()`](space.html#mesa.space.SingleGrid.out_of_bounds)
* [`SingleGrid.remove_property_layer()`](space.html#mesa.space.SingleGrid.remove_property_layer)
* [`SingleGrid.select_cells()`](space.html#mesa.space.SingleGrid.select_cells)
* [`SingleGrid.swap_pos()`](space.html#mesa.space.SingleGrid.swap_pos)
* [`SingleGrid.torus_adj()`](space.html#mesa.space.SingleGrid.torus_adj)
* [`MultiGrid`](space.html#mesa.space.MultiGrid)
* [`MultiGrid.default_val()`](space.html#mesa.space.MultiGrid.default_val)
* [`MultiGrid.remove_agent()`](space.html#mesa.space.MultiGrid.remove_agent)
* [`MultiGrid.iter_neighbors()`](space.html#mesa.space.MultiGrid.iter_neighbors)
* [`MultiGrid.add_property_layer()`](space.html#mesa.space.MultiGrid.add_property_layer)
* [`MultiGrid.agents`](space.html#mesa.space.MultiGrid.agents)
* [`MultiGrid.coord_iter()`](space.html#mesa.space.MultiGrid.coord_iter)
* [`MultiGrid.empty_mask`](space.html#mesa.space.MultiGrid.empty_mask)
* [`MultiGrid.exists_empty_cells()`](space.html#mesa.space.MultiGrid.exists_empty_cells)
* [`MultiGrid.get_neighborhood()`](space.html#mesa.space.MultiGrid.get_neighborhood)
* [`MultiGrid.get_neighborhood_mask()`](space.html#mesa.space.MultiGrid.get_neighborhood_mask)
* [`MultiGrid.get_neighbors()`](space.html#mesa.space.MultiGrid.get_neighbors)
* [`MultiGrid.is_cell_empty()`](space.html#mesa.space.MultiGrid.is_cell_empty)
* [`MultiGrid.iter_neighborhood()`](space.html#mesa.space.MultiGrid.iter_neighborhood)
* [`MultiGrid.move_agent()`](space.html#mesa.space.MultiGrid.move_agent)
* [`MultiGrid.move_agent_to_one_of()`](space.html#mesa.space.MultiGrid.move_agent_to_one_of)
* [`MultiGrid.move_to_empty()`](space.html#mesa.space.MultiGrid.move_to_empty)
* [`MultiGrid.out_of_bounds()`](space.html#mesa.space.MultiGrid.out_of_bounds)
* [`MultiGrid.remove_property_layer()`](space.html#mesa.space.MultiGrid.remove_property_layer)
* [`MultiGrid.select_cells()`](space.html#mesa.space.MultiGrid.select_cells)
* [`MultiGrid.swap_pos()`](space.html#mesa.space.MultiGrid.swap_pos)
* [`MultiGrid.torus_adj()`](space.html#mesa.space.MultiGrid.torus_adj)
* [`HexSingleGrid`](space.html#mesa.space.HexSingleGrid)
* [`HexSingleGrid.add_property_layer()`](space.html#mesa.space.HexSingleGrid.add_property_layer)
* [`HexSingleGrid.agents`](space.html#mesa.space.HexSingleGrid.agents)
* [`HexSingleGrid.coord_iter()`](space.html#mesa.space.HexSingleGrid.coord_iter)
* [`HexSingleGrid.default_val()`](space.html#mesa.space.HexSingleGrid.default_val)
* [`HexSingleGrid.empty_mask`](space.html#mesa.space.HexSingleGrid.empty_mask)
* [`HexSingleGrid.exists_empty_cells()`](space.html#mesa.space.HexSingleGrid.exists_empty_cells)
* [`HexSingleGrid.get_neighborhood()`](space.html#mesa.space.HexSingleGrid.get_neighborhood)
* [`HexSingleGrid.get_neighborhood_mask()`](space.html#mesa.space.HexSingleGrid.get_neighborhood_mask)
* [`HexSingleGrid.get_neighbors()`](space.html#mesa.space.HexSingleGrid.get_neighbors)
* [`HexSingleGrid.is_cell_empty()`](space.html#mesa.space.HexSingleGrid.is_cell_empty)
* [`HexSingleGrid.iter_neighborhood()`](space.html#mesa.space.HexSingleGrid.iter_neighborhood)
* [`HexSingleGrid.iter_neighbors()`](space.html#mesa.space.HexSingleGrid.iter_neighbors)
* [`HexSingleGrid.move_agent()`](space.html#mesa.space.HexSingleGrid.move_agent)
* [`HexSingleGrid.move_agent_to_one_of()`](space.html#mesa.space.HexSingleGrid.move_agent_to_one_of)
* [`HexSingleGrid.move_to_empty()`](space.html#mesa.space.HexSingleGrid.move_to_empty)
* [`HexSingleGrid.out_of_bounds()`](space.html#mesa.space.HexSingleGrid.out_of_bounds)
* [`HexSingleGrid.remove_agent()`](space.html#mesa.space.HexSingleGrid.remove_agent)
* [`HexSingleGrid.remove_property_layer()`](space.html#mesa.space.HexSingleGrid.remove_property_layer)
* [`HexSingleGrid.select_cells()`](space.html#mesa.space.HexSingleGrid.select_cells)
* [`HexSingleGrid.swap_pos()`](space.html#mesa.space.HexSingleGrid.swap_pos)
* [`HexSingleGrid.torus_adj()`](space.html#mesa.space.HexSingleGrid.torus_adj)
* [`HexMultiGrid`](space.html#mesa.space.HexMultiGrid)
* [`HexMultiGrid.add_property_layer()`](space.html#mesa.space.HexMultiGrid.add_property_layer)
* [`HexMultiGrid.agents`](space.html#mesa.space.HexMultiGrid.agents)
* [`HexMultiGrid.coord_iter()`](space.html#mesa.space.HexMultiGrid.coord_iter)
* [`HexMultiGrid.default_val()`](space.html#mesa.space.HexMultiGrid.default_val)
* [`HexMultiGrid.empty_mask`](space.html#mesa.space.HexMultiGrid.empty_mask)
* [`HexMultiGrid.exists_empty_cells()`](space.html#mesa.space.HexMultiGrid.exists_empty_cells)
* [`HexMultiGrid.get_neighborhood()`](space.html#mesa.space.HexMultiGrid.get_neighborhood)
* [`HexMultiGrid.get_neighborhood_mask()`](space.html#mesa.space.HexMultiGrid.get_neighborhood_mask)
* [`HexMultiGrid.get_neighbors()`](space.html#mesa.space.HexMultiGrid.get_neighbors)
* [`HexMultiGrid.is_cell_empty()`](space.html#mesa.space.HexMultiGrid.is_cell_empty)
* [`HexMultiGrid.iter_neighborhood()`](space.html#mesa.space.HexMultiGrid.iter_neighborhood)
* [`HexMultiGrid.iter_neighbors()`](space.html#mesa.space.HexMultiGrid.iter_neighbors)
* [`HexMultiGrid.move_agent()`](space.html#mesa.space.HexMultiGrid.move_agent)
* [`HexMultiGrid.move_agent_to_one_of()`](space.html#mesa.space.HexMultiGrid.move_agent_to_one_of)
* [`HexMultiGrid.move_to_empty()`](space.html#mesa.space.HexMultiGrid.move_to_empty)
* [`HexMultiGrid.out_of_bounds()`](space.html#mesa.space.HexMultiGrid.out_of_bounds)
* [`HexMultiGrid.remove_agent()`](space.html#mesa.space.HexMultiGrid.remove_agent)
* [`HexMultiGrid.remove_property_layer()`](space.html#mesa.space.HexMultiGrid.remove_property_layer)
* [`HexMultiGrid.select_cells()`](space.html#mesa.space.HexMultiGrid.select_cells)
* [`HexMultiGrid.swap_pos()`](space.html#mesa.space.HexMultiGrid.swap_pos)
* [`HexMultiGrid.torus_adj()`](space.html#mesa.space.HexMultiGrid.torus_adj)
* [`ContinuousSpace`](space.html#mesa.space.ContinuousSpace)
* [`ContinuousSpace.agents`](space.html#mesa.space.ContinuousSpace.agents)
* [`ContinuousSpace.move_agent()`](space.html#mesa.space.ContinuousSpace.move_agent)
* [`ContinuousSpace.remove_agent()`](space.html#mesa.space.ContinuousSpace.remove_agent)
* [`ContinuousSpace.get_neighbors()`](space.html#mesa.space.ContinuousSpace.get_neighbors)
* [`ContinuousSpace.get_heading()`](space.html#mesa.space.ContinuousSpace.get_heading)
* [`ContinuousSpace.get_distance()`](space.html#mesa.space.ContinuousSpace.get_distance)
* [`ContinuousSpace.torus_adj()`](space.html#mesa.space.ContinuousSpace.torus_adj)
* [`ContinuousSpace.out_of_bounds()`](space.html#mesa.space.ContinuousSpace.out_of_bounds)
* [`NetworkGrid`](space.html#mesa.space.NetworkGrid)
* [`NetworkGrid.agents`](space.html#mesa.space.NetworkGrid.agents)
* [`NetworkGrid.default_val()`](space.html#mesa.space.NetworkGrid.default_val)
* [`NetworkGrid.get_neighborhood()`](space.html#mesa.space.NetworkGrid.get_neighborhood)
* [`NetworkGrid.get_neighbors()`](space.html#mesa.space.NetworkGrid.get_neighbors)
* [`NetworkGrid.move_agent()`](space.html#mesa.space.NetworkGrid.move_agent)
* [`NetworkGrid.remove_agent()`](space.html#mesa.space.NetworkGrid.remove_agent)
* [`NetworkGrid.is_cell_empty()`](space.html#mesa.space.NetworkGrid.is_cell_empty)
* [`NetworkGrid.get_cell_list_contents()`](space.html#mesa.space.NetworkGrid.get_cell_list_contents)
* [`NetworkGrid.get_all_cell_contents()`](space.html#mesa.space.NetworkGrid.get_all_cell_contents)
* [`NetworkGrid.iter_cell_list_contents()`](space.html#mesa.space.NetworkGrid.iter_cell_list_contents)
* [Discrete Space](discrete_space.html)
* [`Cell`](discrete_space.html#mesa.discrete_space.__init__.Cell)
* [`Cell.coordinate`](discrete_space.html#mesa.discrete_space.__init__.Cell.coordinate)
* [`Cell.agents`](discrete_space.html#mesa.discrete_space.__init__.Cell.agents)
* [`Cell.capacity`](discrete_space.html#mesa.discrete_space.__init__.Cell.capacity)
* [`Cell.random`](discrete_space.html#mesa.discrete_space.__init__.Cell.random)
* [`Cell.add_agent()`](discrete_space.html#mesa.discrete_space.__init__.Cell.add_agent)
* [`Cell.agents`](discrete_space.html#id0)
* [`Cell.connect()`](discrete_space.html#mesa.discrete_space.__init__.Cell.connect)
* [`Cell.disconnect()`](discrete_space.html#mesa.discrete_space.__init__.Cell.disconnect)
* [`Cell.get_neighborhood()`](discrete_space.html#mesa.discrete_space.__init__.Cell.get_neighborhood)
* [`Cell.is_empty`](discrete_space.html#mesa.discrete_space.__init__.Cell.is_empty)
* [`Cell.is_full`](discrete_space.html#mesa.discrete_space.__init__.Cell.is_full)
* [`Cell.neighborhood`](discrete_space.html#mesa.discrete_space.__init__.Cell.neighborhood)
* [`Cell.remove_agent()`](discrete_space.html#mesa.discrete_space.__init__.Cell.remove_agent)
* [`CellAgent`](discrete_space.html#mesa.discrete_space.__init__.CellAgent)
* [`CellAgent.cell`](discrete_space.html#mesa.discrete_space.__init__.CellAgent.cell)
* [`CellAgent.remove()`](discrete_space.html#mesa.discrete_space.__init__.CellAgent.remove)
* [`CellCollection`](discrete_space.html#mesa.discrete_space.__init__.CellCollection)
* [`CellCollection.cells`](discrete_space.html#mesa.discrete_space.__init__.CellCollection.cells)
* [`CellCollection.agents`](discrete_space.html#mesa.discrete_space.__init__.CellCollection.agents)
* [`CellCollection.random`](discrete_space.html#mesa.discrete_space.__init__.CellCollection.random)
* [`CellCollection.select()`](discrete_space.html#mesa.discrete_space.__init__.CellCollection.select)
* [`CellCollection.select_random_agent()`](discrete_space.html#mesa.discrete_space.__init__.CellCollection.select_random_agent)
* [`CellCollection.select_random_cell()`](discrete_space.html#mesa.discrete_space.__init__.CellCollection.select_random_cell)
* [`DiscreteSpace`](discrete_space.html#mesa.discrete_space.__init__.DiscreteSpace)
* [`DiscreteSpace.capacity`](discrete_space.html#mesa.discrete_space.__init__.DiscreteSpace.capacity)
* [`DiscreteSpace.all_cells`](discrete_space.html#mesa.discrete_space.__init__.DiscreteSpace.all_cells)
* [`DiscreteSpace.random`](discrete_space.html#mesa.discrete_space.__init__.DiscreteSpace.random)
* [`DiscreteSpace.cell_klass`](discrete_space.html#mesa.discrete_space.__init__.DiscreteSpace.cell_klass)
* [`DiscreteSpace.empties`](discrete_space.html#mesa.discrete_space.__init__.DiscreteSpace.empties)
* [`DiscreteSpace.property_layers`](discrete_space.html#mesa.discrete_space.__init__.DiscreteSpace.property_layers)
* [`DiscreteSpace.agents`](discrete_space.html#mesa.discrete_space.__init__.DiscreteSpace.agents)
* [`DiscreteSpace.all_cells`](discrete_space.html#id1)
* [`DiscreteSpace.empties`](discrete_space.html#id2)
* [`DiscreteSpace.select_random_empty_cell()`](discrete_space.html#mesa.discrete_space.__init__.DiscreteSpace.select_random_empty_cell)
* [`FixedAgent`](discrete_space.html#mesa.discrete_space.__init__.FixedAgent)
* [`FixedAgent.remove()`](discrete_space.html#mesa.discrete_space.__init__.FixedAgent.remove)
* [`Grid`](discrete_space.html#mesa.discrete_space.__init__.Grid)
* [`Grid.dimensions`](discrete_space.html#mesa.discrete_space.__init__.Grid.dimensions)
* [`Grid.torus`](discrete_space.html#mesa.discrete_space.__init__.Grid.torus)
* [`Grid.capacity`](discrete_space.html#mesa.discrete_space.__init__.Grid.capacity)
* [`Grid.random`](discrete_space.html#mesa.discrete_space.__init__.Grid.random)
* [`Grid._try_random`](discrete_space.html#mesa.discrete_space.__init__.Grid._try_random)
* [`Grid.height`](discrete_space.html#mesa.discrete_space.__init__.Grid.height)
* [`Grid.select_random_empty_cell()`](discrete_space.html#mesa.discrete_space.__init__.Grid.select_random_empty_cell)
* [`Grid.width`](discrete_space.html#mesa.discrete_space.__init__.Grid.width)
* [`Grid2DMovingAgent`](discrete_space.html#mesa.discrete_space.__init__.Grid2DMovingAgent)
* [`Grid2DMovingAgent.move()`](discrete_space.html#mesa.discrete_space.__init__.Grid2DMovingAgent.move)
* [`HexGrid`](discrete_space.html#mesa.discrete_space.__init__.HexGrid)
* [`Network`](discrete_space.html#mesa.discrete_space.__init__.Network)
* [`OrthogonalMooreGrid`](discrete_space.html#mesa.discrete_space.__init__.OrthogonalMooreGrid)
* [`OrthogonalVonNeumannGrid`](discrete_space.html#mesa.discrete_space.__init__.OrthogonalVonNeumannGrid)
* [`PropertyLayer`](discrete_space.html#mesa.discrete_space.__init__.PropertyLayer)
* [`PropertyLayer.name`](discrete_space.html#mesa.discrete_space.__init__.PropertyLayer.name)
* [`PropertyLayer.dimensions`](discrete_space.html#mesa.discrete_space.__init__.PropertyLayer.dimensions)
* [`PropertyLayer.data`](discrete_space.html#mesa.discrete_space.__init__.PropertyLayer.data)
* [`PropertyLayer.aggregate()`](discrete_space.html#mesa.discrete_space.__init__.PropertyLayer.aggregate)
* [`PropertyLayer.from_data()`](discrete_space.html#mesa.discrete_space.__init__.PropertyLayer.from_data)
* [`PropertyLayer.modify_cells()`](discrete_space.html#mesa.discrete_space.__init__.PropertyLayer.modify_cells)
* [`PropertyLayer.select_cells()`](discrete_space.html#mesa.discrete_space.__init__.PropertyLayer.select_cells)
* [`PropertyLayer.set_cells()`](discrete_space.html#mesa.discrete_space.__init__.PropertyLayer.set_cells)
* [`VoronoiGrid`](discrete_space.html#mesa.discrete_space.__init__.VoronoiGrid)
* [`Cell`](discrete_space.html#mesa.discrete_space.cell.Cell)
* [`Cell.coordinate`](discrete_space.html#mesa.discrete_space.cell.Cell.coordinate)
* [`Cell.agents`](discrete_space.html#mesa.discrete_space.cell.Cell.agents)
* [`Cell.capacity`](discrete_space.html#mesa.discrete_space.cell.Cell.capacity)
* [`Cell.random`](discrete_space.html#mesa.discrete_space.cell.Cell.random)
* [`Cell.connect()`](discrete_space.html#mesa.discrete_space.cell.Cell.connect)
* [`Cell.disconnect()`](discrete_space.html#mesa.discrete_space.cell.Cell.disconnect)
* [`Cell.add_agent()`](discrete_space.html#mesa.discrete_space.cell.Cell.add_agent)
* [`Cell.remove_agent()`](discrete_space.html#mesa.discrete_space.cell.Cell.remove_agent)
* [`Cell.is_empty`](discrete_space.html#mesa.discrete_space.cell.Cell.is_empty)
* [`Cell.is_full`](discrete_space.html#mesa.discrete_space.cell.Cell.is_full)
* [`Cell.agents`](discrete_space.html#id3)
* [`Cell.neighborhood`](discrete_space.html#mesa.discrete_space.cell.Cell.neighborhood)
* [`Cell.get_neighborhood()`](discrete_space.html#mesa.discrete_space.cell.Cell.get_neighborhood)
* [`HasCellProtocol`](discrete_space.html#mesa.discrete_space.cell_agent.HasCellProtocol)
* [`HasCell`](discrete_space.html#mesa.discrete_space.cell_agent.HasCell)
* [`BasicMovement`](discrete_space.html#mesa.discrete_space.cell_agent.BasicMovement)
* [`BasicMovement.move_to()`](discrete_space.html#mesa.discrete_space.cell_agent.BasicMovement.move_to)
* [`BasicMovement.move_relative()`](discrete_space.html#mesa.discrete_space.cell_agent.BasicMovement.move_relative)
* [`FixedCell`](discrete_space.html#mesa.discrete_space.cell_agent.FixedCell)
* [`CellAgent`](discrete_space.html#mesa.discrete_space.cell_agent.CellAgent)
* [`CellAgent.cell`](discrete_space.html#mesa.discrete_space.cell_agent.CellAgent.cell)
* [`CellAgent.remove()`](discrete_space.html#mesa.discrete_space.cell_agent.CellAgent.remove)
* [`FixedAgent`](discrete_space.html#mesa.discrete_space.cell_agent.FixedAgent)
* [`FixedAgent.remove()`](discrete_space.html#mesa.discrete_space.cell_agent.FixedAgent.remove)
* [`Grid2DMovingAgent`](discrete_space.html#mesa.discrete_space.cell_agent.Grid2DMovingAgent)
* [`Grid2DMovingAgent.move()`](discrete_space.html#mesa.discrete_space.cell_agent.Grid2DMovingAgent.move)
* [`CellCollection`](discrete_space.html#mesa.discrete_space.cell_collection.CellCollection)
* [`CellCollection.cells`](discrete_space.html#mesa.discrete_space.cell_collection.CellCollection.cells)
* [`CellCollection.agents`](discrete_space.html#mesa.discrete_space.cell_collection.CellCollection.agents)
* [`CellCollection.random`](discrete_space.html#mesa.discrete_space.cell_collection.CellCollection.random)
* [`CellCollection.select_random_cell()`](discrete_space.html#mesa.discrete_space.cell_collection.CellCollection.select_random_cell)
* [`CellCollection.select_random_agent()`](discrete_space.html#mesa.discrete_space.cell_collection.CellCollection.select_random_agent)
* [`CellCollection.select()`](discrete_space.html#mesa.discrete_space.cell_collection.CellCollection.select)
* [`DiscreteSpace`](discrete_space.html#mesa.discrete_space.discrete_space.DiscreteSpace)
* [`DiscreteSpace.capacity`](discrete_space.html#mesa.discrete_space.discrete_space.DiscreteSpace.capacity)
* [`DiscreteSpace.all_cells`](discrete_space.html#mesa.discrete_space.discrete_space.DiscreteSpace.all_cells)
* [`DiscreteSpace.random`](discrete_space.html#mesa.discrete_space.discrete_space.DiscreteSpace.random)
* [`DiscreteSpace.cell_klass`](discrete_space.html#mesa.discrete_space.discrete_space.DiscreteSpace.cell_klass)
* [`DiscreteSpace.empties`](discrete_space.html#mesa.discrete_space.discrete_space.DiscreteSpace.empties)
* [`DiscreteSpace.property_layers`](discrete_space.html#mesa.discrete_space.discrete_space.DiscreteSpace.property_layers)
* [`DiscreteSpace.agents`](discrete_space.html#mesa.discrete_space.discrete_space.DiscreteSpace.agents)
* [`DiscreteSpace.all_cells`](discrete_space.html#id4)
* [`DiscreteSpace.empties`](discrete_space.html#id5)
* [`DiscreteSpace.select_random_empty_cell()`](discrete_space.html#mesa.discrete_space.discrete_space.DiscreteSpace.select_random_empty_cell)
* [`pickle_gridcell()`](discrete_space.html#mesa.discrete_space.grid.pickle_gridcell)
* [`unpickle_gridcell()`](discrete_space.html#mesa.discrete_space.grid.unpickle_gridcell)
* [`Grid`](discrete_space.html#mesa.discrete_space.grid.Grid)
* [`Grid.dimensions`](discrete_space.html#mesa.discrete_space.grid.Grid.dimensions)
* [`Grid.torus`](discrete_space.html#mesa.discrete_space.grid.Grid.torus)
* [`Grid.capacity`](discrete_space.html#mesa.discrete_space.grid.Grid.capacity)
* [`Grid.random`](discrete_space.html#mesa.discrete_space.grid.Grid.random)
* [`Grid._try_random`](discrete_space.html#mesa.discrete_space.grid.Grid._try_random)
* [`Grid.width`](discrete_space.html#mesa.discrete_space.grid.Grid.width)
* [`Grid.height`](discrete_space.html#mesa.discrete_space.grid.Grid.height)
* [`Grid.select_random_empty_cell()`](discrete_space.html#mesa.discrete_space.grid.Grid.select_random_empty_cell)
* [`OrthogonalMooreGrid`](discrete_space.html#mesa.discrete_space.grid.OrthogonalMooreGrid)
* [`OrthogonalVonNeumannGrid`](discrete_space.html#mesa.discrete_space.grid.OrthogonalVonNeumannGrid)
* [`HexGrid`](discrete_space.html#mesa.discrete_space.grid.HexGrid)
* [`Network`](discrete_space.html#mesa.discrete_space.network.Network)
* [`Delaunay`](discrete_space.html#mesa.discrete_space.voronoi.Delaunay)
* [`Delaunay.add_point()`](discrete_space.html#mesa.discrete_space.voronoi.Delaunay.add_point)
* [`Delaunay.export_triangles()`](discrete_space.html#mesa.discrete_space.voronoi.Delaunay.export_triangles)
* [`Delaunay.export_voronoi_regions()`](discrete_space.html#mesa.discrete_space.voronoi.Delaunay.export_voronoi_regions)
* [`VoronoiGrid`](discrete_space.html#mesa.discrete_space.voronoi.VoronoiGrid)
* [Data collection](datacollection.html)
* [`DataCollector`](datacollection.html#datacollection.DataCollector)
* [`DataCollector.collect()`](datacollection.html#datacollection.DataCollector.collect)
* [`DataCollector.add_table_row()`](datacollection.html#datacollection.DataCollector.add_table_row)
* [`DataCollector.get_model_vars_dataframe()`](datacollection.html#datacollection.DataCollector.get_model_vars_dataframe)
* [`DataCollector.get_agent_vars_dataframe()`](datacollection.html#datacollection.DataCollector.get_agent_vars_dataframe)
* [`DataCollector.get_agenttype_vars_dataframe()`](datacollection.html#datacollection.DataCollector.get_agenttype_vars_dataframe)
* [`DataCollector.get_table_dataframe()`](datacollection.html#datacollection.DataCollector.get_table_dataframe)
* [Batchrunner](batchrunner.html)
* [`batch_run()`](batchrunner.html#batchrunner.batch_run)
* [Visualization](visualization.html)
* [Jupyter Visualization](visualization.html#module-mesa.visualization.solara_viz)
* [`split_model_params()`](visualization.html#mesa.visualization.solara_viz.split_model_params)
* [`check_param_is_fixed()`](visualization.html#mesa.visualization.solara_viz.check_param_is_fixed)
* [`make_initial_grid_layout()`](visualization.html#mesa.visualization.solara_viz.make_initial_grid_layout)
* [`make_space_component()`](visualization.html#mesa.visualization.components.__init__.make_space_component)
* [`make_plot_component()`](visualization.html#mesa.visualization.components.__init__.make_plot_component)
* [User Parameters](visualization.html#module-mesa.visualization.user_param)
* [`UserParam`](visualization.html#mesa.visualization.user_param.UserParam)
* [`Slider`](visualization.html#mesa.visualization.user_param.Slider)
* [Matplotlib-based visualizations](visualization.html#module-mesa.visualization.components.matplotlib_components)
* [`make_space_matplotlib()`](visualization.html#mesa.visualization.components.matplotlib_components.make_space_matplotlib)
* [`make_mpl_space_component()`](visualization.html#mesa.visualization.components.matplotlib_components.make_mpl_space_component)
* [`make_plot_measure()`](visualization.html#mesa.visualization.components.matplotlib_components.make_plot_measure)
* [`make_mpl_plot_component()`](visualization.html#mesa.visualization.components.matplotlib_components.make_mpl_plot_component)
* [`collect_agent_data()`](visualization.html#mesa.visualization.mpl_space_drawing.collect_agent_data)
* [`draw_space()`](visualization.html#mesa.visualization.mpl_space_drawing.draw_space)
* [`draw_property_layers()`](visualization.html#mesa.visualization.mpl_space_drawing.draw_property_layers)
* [`draw_orthogonal_grid()`](visualization.html#mesa.visualization.mpl_space_drawing.draw_orthogonal_grid)
* [`draw_hex_grid()`](visualization.html#mesa.visualization.mpl_space_drawing.draw_hex_grid)
* [`draw_network()`](visualization.html#mesa.visualization.mpl_space_drawing.draw_network)
* [`draw_continuous_space()`](visualization.html#mesa.visualization.mpl_space_drawing.draw_continuous_space)
* [`draw_voronoi_grid()`](visualization.html#mesa.visualization.mpl_space_drawing.draw_voronoi_grid)
* [Altair-based visualizations](visualization.html#module-mesa.visualization.components.altair_components)
* [`make_space_altair()`](visualization.html#mesa.visualization.components.altair_components.make_space_altair)
* [`make_altair_space()`](visualization.html#mesa.visualization.components.altair_components.make_altair_space)
* [`chart_property_layers()`](visualization.html#mesa.visualization.components.altair_components.chart_property_layers)
* [Command Console](visualization.html#module-mesa.visualization.command_console)
* [`ConsoleEntry`](visualization.html#mesa.visualization.command_console.ConsoleEntry)
* [`CaptureOutput`](visualization.html#mesa.visualization.command_console.CaptureOutput)
* [`InteractiveConsole`](visualization.html#mesa.visualization.command_console.InteractiveConsole)
* [`ConsoleManager`](visualization.html#mesa.visualization.command_console.ConsoleManager)
* [`format_command_html()`](visualization.html#mesa.visualization.command_console.format_command_html)
* [`format_output_html()`](visualization.html#mesa.visualization.command_console.format_output_html)
* [Experimental](experimental.html)
* [Devs](experimental.html#module-experimental.devs.eventlist)
* [`Priority`](experimental.html#experimental.devs.eventlist.Priority)
* [`SimulationEvent`](experimental.html#experimental.devs.eventlist.SimulationEvent)
* [`EventList`](experimental.html#experimental.devs.eventlist.EventList)
* [`Simulator`](experimental.html#experimental.devs.simulator.Simulator)
* [`ABMSimulator`](experimental.html#experimental.devs.simulator.ABMSimulator)
* [`DEVSimulator`](experimental.html#experimental.devs.simulator.DEVSimulator)
* [Continuous Space](experimental.html#module-experimental.continuous_space.continuous_space)
* [`ContinuousSpace`](experimental.html#experimental.continuous_space.continuous_space.ContinuousSpace)
* [`HasPositionProtocol`](experimental.html#experimental.continuous_space.continuous_space_agents.HasPositionProtocol)
* [`ContinuousSpaceAgent`](experimental.html#experimental.continuous_space.continuous_space_agents.ContinuousSpaceAgent)
### This Page
* [Show Source](../_sources/apis/api_main.md.txt)
---
# Visualization - Dynamic Agents — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Visualization - Dynamic Agents[#](#visualization-dynamic-agents "Link to this heading")
========================================================================================
The Boltzmann Wealth Model[#](#the-boltzmann-wealth-model "Link to this heading")
----------------------------------------------------------------------------------
If you want to get straight to the tutorial checkout these environment providers:
[](https://mybinder.org/v2/gh/projectmesa/mesa/main?labpath=docs%2Ftutorials%2F4_visualization_basic.ipynb)
(This can take 30 seconds to 5 minutes to load)
Due to conflict with Colab and Solara there are no colab links for this tutorial
_If you are running locally, please ensure you have the latest Mesa version installed._
Tutorial Description[#](#tutorial-description "Link to this heading")
----------------------------------------------------------------------
This tutorial extends the Boltzmann wealth model from the [Visualization Basic Dashboard tutorial](https://mesa.readthedocs.io/latest/tutorials/4_visualization_basic.html)
, by adding an interactive dashboard.
In this portion, we will demonstrate how users can employ create dynamic agent representation with their Mesa dashboards. This is part two of three visualization tutorials.
_If you are starting here please see the [Running Your First Model tutorial](https://mesa.readthedocs.io/latest/tutorials/0_first_model.html)
for dependency and start-up instructions_
### Import Dependencies[#](#import-dependencies "Link to this heading")
This includes importing of dependencies needed for the tutorial.
\# Has multi-dimensional arrays and matrices.
\# Has a large collection of mathematical functions to operate on these arrays.
import numpy as np
\# Data manipulation and analysis.
import pandas as pd
\# Data visualization tools.
import seaborn as sns
import mesa
from mesa.discrete\_space import CellAgent, OrthogonalMooreGrid
from mesa.visualization import SolaraViz, make\_plot\_component, make\_space\_component
Basic Model[#](#basic-model "Link to this heading")
----------------------------------------------------
The following is the basic model we will be using to build the dashboard. This is the same model seen in tutorials 0-3.
def compute\_gini(model):
agent\_wealths \= \[agent.wealth for agent in model.agents\]
x \= sorted(agent\_wealths)
N \= model.num\_agents
B \= sum(xi \* (N \- i) for i, xi in enumerate(x)) / (N \* sum(x))
return 1 + (1 / N) \- 2 \* B
class MoneyAgent(CellAgent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model, cell):
"""initialize a MoneyAgent instance.
Args:
model: A model instance
"""
super().\_\_init\_\_(model)
self.cell \= cell
self.wealth \= 1
def move(self):
"""Move the agent to a random neighboring cell."""
self.cell \= self.cell.neighborhood.select\_random\_cell()
def give\_money(self):
"""Give 1 unit of wealth to a random agent in the same cell."""
cellmates \= \[a for a in self.cell.agents if a is not self\]
if cellmates: \# Only give money if there are other agents present
other \= self.random.choice(cellmates)
other.wealth += 1
self.wealth \-= 1
def step(self):
"""do one step of the agent."""
self.move()
if self.wealth \> 0:
self.give\_money()
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n\=10, width\=10, height\=10, seed\=None):
"""Initialize a MoneyModel instance.
Args:
N: The number of agents.
width: width of the grid.
height: Height of the grid.
"""
super().\_\_init\_\_(seed\=seed)
self.num\_agents \= n
self.grid \= OrthogonalMooreGrid((width, height), random\=self.random)
\# Create agents
MoneyAgent.create\_agents(
self,
self.num\_agents,
self.random.choices(self.grid.all\_cells.cells, k\=self.num\_agents),
)
self.datacollector \= mesa.DataCollector(
model\_reporters\={"Gini": compute\_gini}, agent\_reporters\={"Wealth": "wealth"}
)
self.datacollector.collect(self)
def step(self):
"""do one step of the model"""
self.agents.shuffle\_do("step")
self.datacollector.collect(self)
\# Lets make sure the model works
model \= MoneyModel(100, 10, 10)
for \_ in range(20):
model.step()
data \= model.datacollector.get\_agent\_vars\_dataframe()
\# Use seaborn
g \= sns.histplot(data\["Wealth"\], discrete\=True)
g.set(title\="Wealth distribution", xlabel\="Wealth", ylabel\="number of agents");

### Adding visualization[#](#adding-visualization "Link to this heading")
So far, we’ve built a model, run it, and analyzed some output afterwards. However, one of the advantages of agent-based models is that we can often watch them run step by step, potentially spotting unexpected patterns, behaviors or bugs, or developing new intuitions, hypotheses, or insights. Other times, watching a model run can explain it to an unfamiliar audience better than static explanations. Like many ABM frameworks, Mesa allows you to create an interactive visualization of the model. In this section we’ll walk through creating a visualization using built-in components, and (for advanced users) how to create a new visualization element.
First, a quick explanation of how Mesa’s interactive visualization works. The visualization is done in a browser window or Jupyter instance, using the [Solara](https://solara.dev/)
framework, a pure Python, React-style web framework. Running `solara run app.py` will launch a web server, which runs the model, and displays model detail at each step via a plotting library. Alternatively, you can execute everything inside a Jupyter instance and display it inline.
Dynamic Agent Representation[#](#dynamic-agent-representation "Link to this heading")
--------------------------------------------------------------------------------------
In the first visualization, all we could see is the agents moving around – but not how much money they had, or anything else of interest. In this tutorial let’s change it so that agents are represented by the units of wealth they have. So those who are broke (wealth 0) are drawn in red, smaller.
As Mesa is open source, it is important to point out that currently, we can’t direct the drawing order of the circles, so a broke agent may be overshadowed by a wealthy agent. If you have some ideas, please feel free to [contribute](https://github.com/projectmesa/mesa/blob/main/CONTRIBUTING.md)
.
In addition to size and color, an agent’s shape can also be customized when using the default drawer. The allowed values for shapes can be found [here](https://matplotlib.org/stable/api/markers_api.html)
.
To do this, we go back to our `agent_portrayal` code and add some code to change the portrayal based on the agent properties and launch the server again.
def agent\_portrayal(agent):
size \= 10
color \= "tab:red"
if agent.wealth \> 0:
size \= 50
color \= "tab:blue"
return {"size": size, "color": color}
As like last time we then instantiate the model parameters, some of which are modifiable by user inputs. In this case, the number of agents, N, is specified as a slider of integers.
model\_params \= {
"n": {
"type": "SliderInt",
"value": 50,
"label": "Number of agents:",
"min": 10,
"max": 100,
"step": 1,
},
"width": 10,
"height": 10,
}
Then just like last time we instantiate the visualization object which (by default) displays the grid containing the agents, and timeseries of values computed by the model’s data collector. In this example, we specify the Gini coefficient.
There are 3 buttons:
* the step button, which advances the model by 1 step
* the play button, which advances the model indefinitely until it is paused
* the pause button, which pauses the model
To reset the model, the order of operations are important
1. Stop the model
2. Update the parameters (e.g. move the sliders)
3. Press reset
\# Create initial model instance
money\_model \= MoneyModel(n\=50, width\=10, height\=10)
SpaceGraph \= make\_space\_component(agent\_portrayal)
GiniPlot \= make\_plot\_component("Gini")
page \= SolaraViz(
money\_model,
components\=\[SpaceGraph, GiniPlot\],
model\_params\=model\_params,
name\="Boltzmann Wealth Model",
)
\# This is required to render the visualization in the Jupyter notebook
page
Exercise[#](#exercise "Link to this heading")
----------------------------------------------
* Change the agent representations, such as squares, triangles or even .pngs
Next Steps[#](#next-steps "Link to this heading")
--------------------------------------------------
Check out the next [visualization tutorial custom components](https://mesa.readthedocs.io/latest/tutorials/6_visualization_custom.html)
on how to further enahnce your interactive dashboard.
\[Comer2014\] Comer, Kenneth W. “Who Goes First? An Examination of the Impact of Activation on Outcome Behavior in AgentBased Models.” George Mason University, 2014. http://mars.gmu.edu/bitstream/handle/1920/9070/Comer\_gmu\_0883E\_10539.pdf
\[Dragulescu2002\] Drăgulescu, Adrian A., and Victor M. Yakovenko. “Statistical Mechanics of Money, Income, and Wealth: A Short Survey.” arXiv Preprint Cond-mat/0211175, 2002. http://arxiv.org/abs/cond-mat/0211175.
On this page
### This Page
* [Show Source](../_sources/tutorials/5_visualization_dynamic_agents.ipynb.txt)
---
# Agent Management Through AgentSet — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Agent Management Through AgentSet[#](#agent-management-through-agentset "Link to this heading")
================================================================================================
The Boltzmann Wealth Model[#](#the-boltzmann-wealth-model "Link to this heading")
----------------------------------------------------------------------------------
If you want to get straight to the tutorial checkout these environment providers:
(with Google Account) [](https://colab.research.google.com/github/projectmesa/mesa/blob/main/docs/tutorials/2_collecting_data.ipynb)
(No Google Account) [](https://mybinder.org/v2/gh/projectmesa/mesa/main?labpath=docs%2Ftutorials%2F2_collecting_data.ipynb)
(This can take 30 seconds to 5 minutes to load)
_If you are running locally, please ensure you have the latest Mesa version installed._
Tutorial Description[#](#tutorial-description "Link to this heading")
----------------------------------------------------------------------
This tutorial extends the Boltzmann wealth model from the [Collecting Data tutorial](https://mesa.readthedocs.io/latest/tutorials/2_collecting_data.html)
, by demonstrating Mesa’s AgentSet functionality.
In this portion, we will demonstrate how users can employ AgentSet for different purposes.
_If you are starting here please see the [Running Your First Model tutorial](https://mesa.readthedocs.io/latest/tutorials/0_first_model.html)
for dependency and start-up instructions_
### IN COLAB? - Run the next cell[#](#in-colab-run-the-next-cell "Link to this heading")
### Import Dependencies[#](#import-dependencies "Link to this heading")
This includes importing of dependencies needed for the tutorial.
\# Has multi-dimensional arrays and matrices.
\# Has a large collection of mathematical functions to operate on these arrays.
import numpy as np
\# Data manipulation and analysis.
import pandas as pd
\# Data visualization tools.
import seaborn as sns
import mesa
Agent Management Through AgentSet[#](#id1 "Link to this heading")
------------------------------------------------------------------
**Background:** Mesa uses a set based approach, [AgentSet](https://github.com/projectmesa/mesa/blob/f511a4bc57340cb2dd0ba4b0af76307b37aea0ca/mesa/agent.py#L147)
to allow users efficiently and intuitively manage their agents. For the most part users will never explicitly call AgentSet and in fact, we have already used the AgentSet methods functionality when we used `shuffle_do(move)` to reorder the agents and then `do(exchange)` to have the agents exchange money in sequence. Although you will likely never interact with AgentSent directly it is important to know the Mesa uses a set based approach for agent management.
Beyond the method functionality there are additional ways AgentSet can help you manage your agents and we will look at two additional examples in this tutorial, but you can see more in the [Getting Started Section of Mesa](https://mesa.readthedocs.io/stable/getting_started.html#agentset-functionality)
.
**Model-specific information:** We will show two agent management techniques just to demonstrate the capability
1. **Selecting** We will institute a policy that has the rich agents give money to the poor agents
2. **GroupBy** We will group agents together based on wealth
_A big thanks to @Ewout for his exceptional work on developing and implementing AgentSet_
### Selecting[#](#selecting "Link to this heading")
**Model-specific Information:** For this variation of the model we are going to institute a policy that only rich agents give money to poor agent
**Code Implementation:** We will use `agents.select` to separate the agents into rich and poor agents. If there are rich agents then they are the only ones who give money.
\# Get lists of rich and poor agents
* **Description:** Uses `AgentSet.select` with a function (in this case a lambda function) to select agents with greater than 3 units of wealth and less than three units of wealth. This will give us two lists of agents rich agent and poor agent which we can then use to execute the `give_money` method.
* **API:** [AgentSet.select](https://mesa.readthedocs.io/latest/apis/agent.html#mesa.agent.AgentSet.select)
def compute\_gini(model):
agent\_wealths \= \[agent.wealth for agent in model.agents\]
x \= sorted(agent\_wealths)
n \= model.num\_agents
B \= sum(xi \* (n \- i) for i, xi in enumerate(x)) / (n \* sum(x))
return 1 + (1 / n) \- 2 \* B
class MoneyAgent(mesa.Agent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model):
super().\_\_init\_\_(model)
self.wealth \= 1
def give\_money(self, poor\_agents):
if self.wealth \> 0:
other\_agent \= self.random.choice(poor\_agents)
other\_agent.wealth += 1
self.wealth \-= 1
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n):
super().\_\_init\_\_()
self.num\_agents \= n
\# Create agents
MoneyAgent.create\_agents(model\=self, n\=n)
self.datacollector \= mesa.DataCollector(
model\_reporters\={"Gini": compute\_gini}, agent\_reporters\={"Wealth": "wealth"}
)
def step(self):
self.datacollector.collect(self)
\# Get lists of rich and poor agents
rich\_agents \= model.agents.select(lambda a: a.wealth \>= 3)
poor\_agents \= model.agents.select(lambda a: a.wealth < 3)
\# When there is rich agents only have them give money to poor agents
if len(rich\_agents) \> 0:
rich\_agents.shuffle\_do("give\_money", poor\_agents)
else:
poor\_agents.shuffle\_do("give\_money", poor\_agents)
We now run the model, collect the data, and plot the results.
model \= MoneyModel(100)
for \_ in range(20):
model.step()
data \= model.datacollector.get\_agent\_vars\_dataframe()
\# Use seaborn
g \= sns.histplot(data\["Wealth"\], discrete\=True)
g.set(title\="Wealth distribution", xlabel\="Wealth", ylabel\="number of agents");

### Group By[#](#group-by "Link to this heading")
**Model-specific implementation:** In this case we will give agents an attribute of ethnicity of Green, Blue or Mixed. Green and Blue agents only give money to their ethnicity while Mixed can give money to anyone.
**Code Implementation**: Using `groupby` we will execute the above logic in our code by passing a list of grouped agents into our `give_money` function. To ensure we can plot wealth by group we also need to add ethnicity to our datacollector.
\# Create dictionary of agents groupby
**Description:** Uses `AgentSet.groupby` to group agents by their ethnicity attribute. This will give us a dictionary where the keys are the different ethnicities and the values are an `AgentSet`. In this case we will then use the `AgentSet` class and leverage its `shuffle_do` capability to then give money to the target groups.
* **API:** [AgentSet.select](https://mesa.readthedocs.io/latest/apis/agent.html#mesa.agent.AgentSet.groupby)
* **Note:** `AgentSet` has a lot of functionality and similar to `discrete_space` has the ability to add new features and make Mesa models more user-friendly. We strongly encourage you to check out the [AgentSet API](https://mesa.readthedocs.io/latest/apis/agent.html#mesa.agent.AgentSet)
to see all the functionality and if you have an idea feel free to [contribute](https://github.com/projectmesa/mesa/blob/main/CONTRIBUTING.md)
class MoneyAgent(mesa.Agent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model, ethnicity):
super().\_\_init\_\_(model)
self.wealth \= 1
self.ethnicity \= ethnicity
def give\_money(self, similars):
if self.wealth \> 0:
other\_agent \= self.random.choice(similars)
other\_agent.wealth += 1
self.wealth \-= 1
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n):
super().\_\_init\_\_()
self.num\_agents \= n
\# Create a list of our different ethnicities
ethnicities \= \["Green", "Blue", "Mixed"\]
\# Create agents
MoneyAgent.create\_agents(
model\=self,
n\=self.num\_agents,
ethnicity\=self.random.choices(ethnicities, k\=self.num\_agents),
)
self.datacollector \= mesa.DataCollector(
model\_reporters\={"Gini": compute\_gini},
agent\_reporters\={"Wealth": "wealth", "Ethnicity": "ethnicity"},
)
def step(self):
self.datacollector.collect(self)
\# Create dictionary of agents groupby
grouped\_agents \= model.agents.groupby("ethnicity")
for ethnic, similars in grouped\_agents:
if ethnic != "Mixed":
similars.shuffle\_do("give\_money", similars)
else:
similars.shuffle\_do(
"give\_money", self.agents
) \# This allows mixed to trade with anyone
\# Run the model
model \= MoneyModel(100)
for \_ in range(20):
model.step()
\# get the data
data \= model.datacollector.get\_agent\_vars\_dataframe()
\# assign histogram colors
palette \= {"Green": "green", "Blue": "blue", "Mixed": "purple"}
sns.histplot(data\=data, x\="Wealth", hue\="Ethnicity", discrete\=True, palette\=palette)
g.set(title\="Wealth distribution", xlabel\="Wealth", ylabel\="number of agents");

### Exercises[#](#exercises "Link to this heading")
* Create a new policy or alter an existing policy in this model to see the impact
* Use a different feature in `AgentSet` and integrate into this model
Next Steps[#](#next-steps "Link to this heading")
--------------------------------------------------
Check out the [basic visualization tutorial](https://mesa.readthedocs.io/latest/tutorials/4_visualization_basic.html)
on how to build interactive dashboards for your models.
\[Comer2014\] Comer, Kenneth W. “Who Goes First? An Examination of the Impact of Activation on Outcome Behavior in AgentBased Models.” George Mason University, 2014. http://mars.gmu.edu/bitstream/handle/1920/9070/Comer\_gmu\_0883E\_10539.pdf
\[Dragulescu2002\] Drăgulescu, Adrian A., and Victor M. Yakovenko. “Statistical Mechanics of Money, Income, and Wealth: A Short Survey.” arXiv Preprint Cond-mat/0211175, 2002. http://arxiv.org/abs/cond-mat/0211175.
On this page
### This Page
* [Show Source](../_sources/tutorials/3_agentset.ipynb.txt)
---
# Creating Your First Model — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Creating Your First Model[#](#creating-your-first-model "Link to this heading")
================================================================================
The Boltzmann Wealth Model[#](#the-boltzmann-wealth-model "Link to this heading")
----------------------------------------------------------------------------------
**Important:**
* If you are just exploring Mesa and want the fastest way to execute the code we recommend executing this tutorial online in a Colab notebook. [](https://colab.research.google.com/github/projectmesa/mesa/blob/main/docs/tutorials/0_first_model.ipynb)
or if you do not have a Google account you can use [](https://mybinder.org/v2/gh/projectmesa/mesa/main?labpath=docs%2Ftutorials%2F)
0\_first\_model.ipynb) (This can take 30 seconds to 5 minutes to load)
* If you are running locally, please ensure you have the latest Mesa version installed.
Tutorial Description[#](#tutorial-description "Link to this heading")
----------------------------------------------------------------------
[Mesa](https://github.com/projectmesa/mesa)
is a Python framework for [agent-based modeling](https://en.wikipedia.org/wiki/Agent-based_model)
. This tutorial is the first in a series of introductory tutorials that will assist you in getting started and discover some of the core features of Mesa. The tutorial starts with the key pieces of a model and then progressively adds functionality.
Should anyone find any errors, bugs, have a suggestion, or just are looking for clarification, let us know in our [chat](https://matrix.to/#/#project-mesa:matrix.org)
!
The premise of this tutorial is to create a starter-level model representing agents exchanging money.
Model Description[#](#model-description "Link to this heading")
----------------------------------------------------------------
This is a simulated agent-based economy. In an agent-based economy, the behavior of an individual economic agent, such as a consumer or producer, is studied in a market environment. This model is drawn from the field econophysics, specifically a paper prepared by Drăgulescu et al. for additional information on the modeling assumptions used in this model. \[Drăgulescu, 2002\].
The assumption that govern this model are:
1. There are some number of agents.
2. All agents begin with 1 unit of money.
3. At every step of the model, an agent gives 1 unit of money (if they have it) to some other agent.
Even as a starter-level model it yields results that are both interesting and unexpected.
Due to its simplicity and intriguing results, we found it to be a good starter model.
### Tutorial Setup[#](#tutorial-setup "Link to this heading")
Create and activate a [virtual environment](http://docs.python-guide.org/en/latest/dev/virtualenvs/)
. _Python version 3.11 or higher is required_.
Install Mesa:
pip install mesa\[rec\]
Install Jupyter notebook (optional):
pip install jupyter
Install [Seaborn](https://seaborn.pydata.org/)
(which is used for data visualization):
pip install seaborn
### IN COLAB? - Run the next cell[#](#in-colab-run-the-next-cell "Link to this heading")
Building the Sample Model[#](#building-the-sample-model "Link to this heading")
--------------------------------------------------------------------------------
After Mesa is installed a model can be built.
This tutorial is written in [Jupyter](http://jupyter.org)
to facilitate the explanation portions.
Start Jupyter form the command line:
jupyter lab
Create a new notebook named `money_model.ipynb` (or whatever you want to call it).
### Import Dependencies[#](#import-dependencies "Link to this heading")
This includes importing of dependencies needed for the tutorial.
\# Has multi-dimensional arrays and matrices.
\# Has a large collection of mathematical functions to operate on these arrays.
import numpy as np
\# Data manipulation and analysis.
import pandas as pd
\# Data visualization tools.
import seaborn as sns
import mesa
### Create Agent[#](#create-agent "Link to this heading")
First create the agent. As the tutorial progresses, more functionality will be added to the agent.
**Background:** Agents are the individual entities that act in the model. Mesa automatically assigns each agent that is created an integer as a `unique_id.`
**Model-specific information:** Agents are the individuals that exchange money, in this case the amount of money an individual agent has is represented as wealth.
**Code implementation:** This is done by creating a new class (or object) that extends `mesa.Agent` creating a subclass of the `Agent` class from mesa. The new class is named `MoneyAgent`. The inherited code of the Mesa agent object can be found in the [mesa repo](https://github.com/projectmesa/mesa/blob/main/mesa/agent.py)
.
The `MoneyAgent` class is created with the following code:
class MoneyAgent(mesa.Agent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model):
\# Pass the parameters to the parent class.
super().\_\_init\_\_(model)
\# Create the agent's variable and set the initial values.
self.wealth \= 1
### Create Model[#](#create-model "Link to this heading")
Next, create the model. This gives us the two basic classes of any Mesa ABM - the agent class (population of agent objects that doing something) and the manager class (a model object that manages the creation, activation, datacollection etc of the agents)
**Background:** The model can be visualized as a list containing all the agents. The model creates, holds and manages all the agent objects, specifically in a dictionary. The model activates agents in discrete time steps.
**Model-specific information:** When a model is created the number of agents within the model is specified. The model then creates the agents and places them in a set of agents.
**Code implementation:** This is done by creating a new class (or object) that extends `mesa.Model` and calls `super().__init__()`, creating a subclass of the `Model` class from mesa. The new class is named `MoneyModel`. The Mesa code you are using can be found in [model module](https://github.com/projectmesa/mesa/blob/main/mesa/model.py)
and the AgentSet in the [agent module](https://github.com/projectmesa/mesa/blob/d7a3834c99a3be809abe2edc8b83610f3d4438ba/mesa/agent.py#L86)
. A critical point is that you can use the `seed` kwarg (keyword argument) to set a seed which controls the random number generator of the model class allowing for the reproducibility of results.
The `MoneyModel` class is created with the following code:
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n, seed\=None):
super().\_\_init\_\_(seed\=seed)
self.num\_agents \= n
\# Create agents
MoneyAgent.create\_agents(model\=self, n\=n)
### Making the Agents `do`[#](#making-the-agents-do "Link to this heading")
With the basics of the Agent class and Model class created we can now activate the agents to `do` things
**Background:** Mesa’s `do` function calls agent functions to grow your ABM. A step is the smallest unit of time in the model, and is often referred to as a tick. The `do` function and Python functionality can be configured to activate agents in different orders. This can be important as the order in which agents are activated can impact the results of the model \[Comer2014\]. At each step of the model, one or more of the agents – usually all of them – are activated and take their own step, changing internally and/or interacting with one another or the environment.
**Model-specific information:** For this section we will randomly reorder the Agent activation order using `mesa.Agent.shuffle_do` and have the agents `step` function print the agent’s unique id that they were assigned during the agent creation process.
**Code implementation:** Using standard ABM convention we add a `step` function to the `MoneyModel` class which calls the `mesa.Agent.shuffle_do` function. We then pass into `shuffle_do` the parameter “step”. This tells mesa to look for and execute the `step` function in our MoneyAgent class.
class MoneyAgent(mesa.Agent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model):
\# Pass the parameters to the parent class.
super().\_\_init\_\_(model)
\# Create the agent's attribute and set the initial values.
self.wealth \= 1
def say\_hi(self):
\# The agent's step will go here.
\# For demonstration purposes we will print the agent's unique\_id
print(f"Hi, I am an agent, you can call me {self.unique\_id!s}.")
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n, seed\=None):
super().\_\_init\_\_(seed\=seed)
self.num\_agents \= n
\# Create n agents
MoneyAgent.create\_agents(model\=self, n\=n)
def step(self):
"""Advance the model by one step."""
\# This function psuedo-randomly reorders the list of agent objects and
\# then iterates through calling the function passed in as the parameter
self.agents.shuffle\_do("say\_hi")
### Running the Model[#](#running-the-model "Link to this heading")
We now have the pieces of a basic model. The model can be run by creating a model object and calling the step method. The model will run for one step and print the unique\_id of each agent. You may run the model for multiple steps by calling the step method multiple times.
Create the model object, and run it for one step:
starter\_model \= MoneyModel(10)
starter\_model.step()
Hi, I am an agent, you can call me 6.
Hi, I am an agent, you can call me 8.
Hi, I am an agent, you can call me 3.
Hi, I am an agent, you can call me 2.
Hi, I am an agent, you can call me 1.
Hi, I am an agent, you can call me 5.
Hi, I am an agent, you can call me 10.
Hi, I am an agent, you can call me 7.
Hi, I am an agent, you can call me 4.
Hi, I am an agent, you can call me 9.
\# Run this step a few times and see what happens!
starter\_model.step()
\# Notice the order of the agents changes each time.
Hi, I am an agent, you can call me 2.
Hi, I am an agent, you can call me 4.
Hi, I am an agent, you can call me 9.
Hi, I am an agent, you can call me 8.
Hi, I am an agent, you can call me 1.
Hi, I am an agent, you can call me 6.
Hi, I am an agent, you can call me 3.
Hi, I am an agent, you can call me 10.
Hi, I am an agent, you can call me 7.
Hi, I am an agent, you can call me 5.
\# Challenge: Change the seed from None to a number like 42 and see the impact
\# Challenge: Change \`shuffle\_do\` to just \`do\` and see the impact
### Exercise[#](#exercise "Link to this heading")
Modifying the code below to have every agent print out its `wealth` when it is activated.
class MoneyAgent(mesa.Agent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model):
\# Pass the parameters to the parent class.
super().\_\_init\_\_(model)
\# Create the agent's variable and set the initial values.
self.wealth \= 1
def say\_wealth(self):
\# The agent's step will go here.
\# FIXME: need to print the agent's wealth
print("Hi, I am an agent and I am broke!")
Create a model for 12 Agents, and run it for a few steps to see the output.
\# Fixme: Create the model object, and run it
### Agents Exchange[#](#agents-exchange "Link to this heading")
Returning back to the MoneyAgent the actual exchange process is now going to be created.
**Background:** This is where the agent’s behavior as it relates to each step or tick of the model is defined.
**Model-specific information:** In this case, the agent will check its wealth, and if it has money, give one unit of it away to another random agent.
**Code implementation:** The agent’s step method is called by `mesa.Agent.shuffle_do("exchange")`during each step of the model. To allow the agent to choose another agent at random, we use the `model.random` random-number generator. This works just like Python’s `random` module, but if a fixed seed is set when the model is instantiated (see earlier challenge), this allows users to replicate a specific model run later. Once we identify this other agent object we increase their wealth by 1 and decrease this agents wealth by one.
This updates the step function as shown below:
class MoneyAgent(mesa.Agent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model):
\# Pass the parameters to the parent class.
super().\_\_init\_\_(model)
\# Create the agent's variable and set the initial values.
self.wealth \= 1
def exchange(self):
\# Verify agent has some wealth
if self.wealth \> 0:
other\_agent \= self.random.choice(self.model.agents)
if other\_agent is not None:
other\_agent.wealth += 1
self.wealth \-= 1
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n):
super().\_\_init\_\_()
self.num\_agents \= n
\# Create agents
MoneyAgent.create\_agents(model\=self, n\=n)
def step(self):
"""Advance the model by one step."""
\# This function psuedo-randomly reorders the list of agent objects and
\# then iterates through calling the function passed in as the parameter
self.agents.shuffle\_do("exchange")
### Running your first model[#](#running-your-first-model "Link to this heading")
With exchange behavior added, it’s time for the first rudimentary run of the model.
Now let’s create a model with 10 agents, and run it for 30 steps.
model \= MoneyModel(10) \# Tells the model to create 10 agents
for \_ in range(30): \# Runs the model for 30 steps;
model.step()
\# Note: An underscore is common convention for a variable that is not used.
Next, we need to get some data out of the model. Specifically, we want to see the distribution of the agent’s wealth.
We can get the wealth values with list comprehension, and then use seaborn (or another graphics library) to visualize the data in a histogram.
agent\_wealth \= \[a.wealth for a in model.agents\]
\# Create a histogram with seaborn
g \= sns.histplot(agent\_wealth, discrete\=True)
g.set(
title\="Wealth distribution", xlabel\="Wealth", ylabel\="number of agents"
); \# The semicolon is just to avoid printing the object representation

To get a better idea of how a model behaves, we can create multiple model objects and see the distribution that emerges from all of them.
We can do this with a nested for loop:
all\_wealth \= \[\]
\# This runs the model 100 times, each model executing 10 steps.
for \_ in range(100):
\# Run the model
model \= MoneyModel(10)
for \_ in range(30):
model.step()
\# Store the results
for agent in model.agents:
all\_wealth.append(agent.wealth)
\# Use seaborn
g \= sns.histplot(all\_wealth, discrete\=True)
g.set(title\="Wealth distribution", xlabel\="Wealth", ylabel\="number of agents");

This runs 100 instantiations of the model, and runs each for 30 steps.
Notice that we set the histogram bins to be integers (`discrete=True`), since agents can only have whole numbers of wealth.
This distribution looks a lot smoother. By running the model 100 times, we smooth out some of the ‘noise’ of randomness, and get to the model’s overall expected behavior.
This outcome might be surprising. Despite the fact that all agents, on average, give and receive one unit of money every step, the model converges to a state where most agents have a small amount of money and a small number have a lot of money.
### Exercise[#](#id1 "Link to this heading")
Change the above code to see the impact of different model runs, agent populations, and number of steps.
Next Steps[#](#next-steps "Link to this heading")
--------------------------------------------------
Check out the [adding space tutorial](https://mesa.readthedocs.io/latest/tutorials/1_adding_space.html)
on how to build interactive dashboards for your models.
### More Mesa[#](#more-mesa "Link to this heading")
If you are looking for other Mesa models or tools here are some additional resources.
* Example ABMs: Find canonical examples and examples of ABMs demonstrating highlighted features in the [Examples Tab](https://mesa.readthedocs.io/stable/examples.html)
* Expanded Examples: Want to integrate Reinforcement Learning or work on the Traveling Salesman Problem? Checkout [Mesa Examples](https://github.com/projectmesa/mesa-examples/)
* Mesa-Geo: If you need an ABM with Geographic Information Systems (GIS) checkout [Mesa-Geo](https://mesa-geo.readthedocs.io/latest/)
* Mesa Frames: Have a large complex model that you need to speed up, check out [Mesa Frames](https://github.com/projectmesa/mesa-frames)
Happy Modeling
-----------------------------------------------------------
This document is a work in progress. If you see any errors, exclusions or have any problems please contact [us](https://github.com/projectmesa/mesa/issues)
.
\[Comer2014\] Comer, Kenneth W. “Who Goes First? An Examination of the Impact of Activation on Outcome Behavior in AgentBased Models.” George Mason University, 2014. http://mars.gmu.edu/bitstream/handle/1920/9070/Comer\_gmu\_0883E\_10539.pdf
\[Dragulescu2002\] Drăgulescu, Adrian A., and Victor M. Yakovenko. “Statistical Mechanics of Money, Income, and Wealth: A Short Survey.” arXiv Preprint Cond-mat/0211175, 2002. http://arxiv.org/abs/cond-mat/0211175.
On this page
### This Page
* [Show Source](../_sources/tutorials/0_first_model.ipynb.txt)
---
# Collecting Data — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Collecting Data[#](#collecting-data "Link to this heading")
============================================================
The Boltzmann Wealth Model[#](#the-boltzmann-wealth-model "Link to this heading")
----------------------------------------------------------------------------------
If you want to get straight to the tutorial checkout these environment providers:
(with Google Account) [](https://colab.research.google.com/github/projectmesa/mesa/blob/main/docs/tutorials/2_collecting_data.ipynb)
(No Google Account) [](https://mybinder.org/v2/gh/projectmesa/mesa/main?labpath=docs%2Ftutorials%2F2_collecting_data.ipynb)
(This can take 30 seconds to 5 minutes to load)
_If you are running locally, please ensure you have the latest Mesa version installed._
Tutorial Description[#](#tutorial-description "Link to this heading")
----------------------------------------------------------------------
This tutorial extends the Boltzmann wealth model from the [Adding Space tutorial](https://mesa.readthedocs.io/latest/tutorials/1_adding_space.html)
, by adding Mesa’s data collection module.
In this portion, we will collect both model level data and agent level data to better understand the dynamics of our model.
_If you are starting here please see the [Running Your First Model tutorial](https://mesa.readthedocs.io/latest/tutorials/0_first_model.html)
for dependency and start-up instructions_
### IN COLAB? - Run the next cell[#](#in-colab-run-the-next-cell "Link to this heading")
### Import Dependencies[#](#import-dependencies "Link to this heading")
This includes importing of dependencies needed for the tutorial.
\# Has multi-dimensional arrays and matrices.
\# Has a large collection of mathematical functions to operate on these arrays.
import numpy as np
\# Data manipulation and analysis.
import pandas as pd
\# Data visualization tools.
import seaborn as sns
import mesa
\# Import Cell Agent and OrthogonalMooreGrid
from mesa.discrete\_space import CellAgent, OrthogonalMooreGrid
Base Model[#](#base-model "Link to this heading")
--------------------------------------------------
The below provides the base model from which we will add our space functionality.
This is from the [Adding Space tutorial](https://mesa.readthedocs.io/latest/tutorials/1_adding_space.html)
tutorial. If you have any questions about it functionality please review that tutorial.
class MoneyAgent(CellAgent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model, cell):
super().\_\_init\_\_(model)
self.cell \= cell \# Instantiate agent with location (x,y)
self.wealth \= 1
\# Move Function
def move(self):
self.cell \= self.cell.neighborhood.select\_random\_cell()
def give\_money(self):
cellmates \= \[\
a for a in self.cell.agents if a is not self\
\] \# Get all agents in cell
if self.wealth \> 0 and cellmates:
other\_agent \= self.random.choice(cellmates)
other\_agent.wealth += 1
self.wealth \-= 1
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n, width, height, seed\=None):
super().\_\_init\_\_(seed\=seed)
self.num\_agents \= n
\# Instantiate an instance of Moore neighborhood space
self.grid \= OrthogonalMooreGrid(
(width, height), torus\=True, capacity\=10, random\=self.random
)
\# Create agents
agents \= MoneyAgent.create\_agents(
self,
self.num\_agents,
\# Randomly select agents cell
self.random.choices(self.grid.all\_cells.cells, k\=self.num\_agents),
)
def step(self):
self.agents.shuffle\_do("move")
self.agents.do("give\_money")
Let’s create a model with 100 agents on a 10x10 grid, and run it for 20 steps to make sure our base model works.
model \= MoneyModel(100, 10, 10)
for \_ in range(20):
model.step()
\# Let's make sure it worked
print(len(model.agents))
100
Collecting Data[#](#id1 "Link to this heading")
------------------------------------------------
**Background:** So far, at the end of every model run, we’ve had to go and write our own code to get the data out of the model. This has two problems: it isn’t very efficient, and it only gives us end results. If we wanted to know the wealth of each agent at each step, we’d have to add that to the loop of executing steps, and figure out some way to store the data.
Since one of the main goals of agent-based modeling is generating data for analysis, Mesa provides a class which can handle data collection and storage for us and make it easier to analyze.
The data collector stores three categories of data:
* Model-level variables : Model-level collection functions take a model object as an input. Such as a function that computes a dynamic of the whole model (in this case we will compute a measure of wealth inequality based on all agent’s wealth)
* Agent-level variables: Agent-level collection functions take an agent object as an input and is typically the state of an agent attributes, in this case wealth.
* Tables (which are a catch-all for everything else).
**Model-specific information:** We will collect two variables to show Mesa capabilities.
* At the model level, let’s measure the model’s [Gini Coefficient](https://en.wikipedia.org/wiki/Gini_coefficient)
, a measure of wealth inequality.
* At the agent level, we want to collect every agent’s wealth at every step.
**Code implementation:**
Let’s add a DataCollector to the model with [`mesa.DataCollector`](https://github.com/projectmesa/mesa/blob/main/mesa/datacollection.py)
, and collect the agent’s wealth and the gini coefficient at each time step. In the below code each new line of code is described with a comment. These additions are described below.
**Helper Function**
\# Add function for model level collection -_Description:_ Helper function used by the model class to compute the gini coefficient as described previously. -_API:_ N/A
**MoneyModel Class**
\# Instantiate DataCollector
* _Description:_ Create a mesa data collector instance and use keyword arguments (kwargs) `model_reporters` and `agent_reporters` to pass in a dictionary, where the key is the name of the data collected and the value is either function (i.e. computer gini) or an attribute (i.e. “wealth”). If it is an attribute it is passed in as a string.
* _API:_ [Data Collection](https://mesa.readthedocs.io/latest/apis/datacollection.html)
\# Collect data each step
* _Description:_ Call the `collect` method from `DataCollector`. This causes the reporters to collect the data at each step. If this is not put in the step function then the data collector will collect the described information at the end of the model run. If you want to collect the data only on lets say the 5th step, then you can just add an `if` statement to only collect on the fifth step.
* _API:_ [DataCollector.collect](https://mesa.readthedocs.io/latest/apis/datacollection.html)
\# Add function for model level collection
def compute\_gini(model):
agent\_wealths \= \[agent.wealth for agent in model.agents\]
x \= sorted(agent\_wealths)
n \= model.num\_agents
B \= sum(xi \* (n \- i) for i, xi in enumerate(x)) / (n \* sum(x))
return 1 + (1 / n) \- 2 \* B
class MoneyAgent(CellAgent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model, cell):
super().\_\_init\_\_(model)
self.cell \= cell
self.wealth \= 1
def move(self):
self.cell \= self.cell.neighborhood.select\_random\_cell()
def give\_money(self):
cellmates \= \[a for a in self.cell.agents if a is not self\]
if self.wealth \> 0 and cellmates:
other\_agent \= self.random.choice(cellmates)
other\_agent.wealth += 1
self.wealth \-= 1
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n, width, height, seed\=None):
super().\_\_init\_\_(seed\=seed)
self.num\_agents \= n
self.grid \= OrthogonalMooreGrid(
(width, height), torus\=True, capacity\=10, random\=self.random
)
\# Instantiate DataCollector
self.datacollector \= mesa.DataCollector(
model\_reporters\={"Gini": compute\_gini}, agent\_reporters\={"Wealth": "wealth"}
)
\# Create agents
agents \= MoneyAgent.create\_agents(
self,
self.num\_agents,
self.random.choices(self.grid.all\_cells.cells, k\=self.num\_agents),
)
def step(self):
\# Collect data each step
self.datacollector.collect(self)
self.agents.shuffle\_do("move")
self.agents.do("give\_money")
At every step of the model, the datacollector will collect and store the model-level current Gini coefficient, as well as each agent’s wealth, associating each with the current step.
We run the model just as we did above. Now is when an interactive session, especially via a notebook, comes in handy: the DataCollector can export the data it has collected as a pandas\* DataFrame, for easy and interactive analysis.
\*If you are new to Python, please be aware that pandas is already installed as a dependency of Mesa and that [pandas](https://pandas.pydata.org/docs/)
is a “fast, powerful, flexible and easy to use open source data analysis and manipulation tool”. Pandas is a great resource to help analyze the data collected in your models.
model \= MoneyModel(100, 10, 10)
for \_ in range(100):
model.step()
### Analyzing MoneyModel Data[#](#analyzing-moneymodel-data "Link to this heading")
**Code implementation:**
\# Extract MoneyModel data in a Pandas dataframe
* _Description:_ Call `DataCollector.get_model_vars_dataframe()` method to get the model reporters (in this case gini coefficient) from the model object. We the use seaborn (sns) to do a line plot of the data of the model run.
* _API:_ [get\_model\_vars\_dataframe](https://mesa.readthedocs.io/latest/apis/datacollection.html#datacollection.DataCollector.get_model_vars_dataframe)
\# Extract MoneyModel data in a Pandas dataframe
gini \= model.datacollector.get\_model\_vars\_dataframe()
g \= sns.lineplot(data\=gini)
g.set(title\="Gini Coefficient over Time", ylabel\="Gini Coefficient");

### Exercises[#](#exercises "Link to this heading")
* Display just the data to see the format
* Comment on the collect method on the step function and see the impact
* Increase agents and time to see how the plot changes
### Analyzing an MoneyAgent Data[#](#analyzing-an-moneyagent-data "Link to this heading")
**Code implementation:**
\# Extract MoneyAgent data in a Pandas dataframe
* _Description:_ Call `DataCollector.get_model_agent_dataframe()` method to get the agent reporters (in this case agent wealth attribute) from the model object.
* _API:_ [get\_model\_agent\_dataframe](https://mesa.readthedocs.io/latest/apis/datacollection.html#datacollection.DataCollector.get_agent_vars_dataframe)
\# Extract MoneyAgent data in a Pandas dataframe
agent\_wealth \= model.datacollector.get\_agent\_vars\_dataframe()
agent\_wealth.head()
| | | Wealth |
| --- | --- | --- |
| Step | AgentID | |
| --- | --- | --- |
| 1 | 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
| 5 | 1 |
You’ll see that the DataFrame’s index is pairings of model step and agent ID. This is because the data collector stores the data in a dictionary, with the step number as the key, and a dictionary of agent ID and variable value pairs as the value. The data collector then converts this dictionary into a DataFrame, which is why the index is a pair of (model step, agent ID). You can analyze it the way you would any other DataFrame. For example, to get a histogram of agent wealth at the model’s end.
_Note: As the following code is pandas and seaborn we do not provide explanatory text_
last\_step \= agent\_wealth.index.get\_level\_values("Step").max() \# Get the last step
end\_wealth \= agent\_wealth.xs(last\_step, level\="Step")\[\
"Wealth"\
\] \# Get the welath of each agentat the last step
\# Create a histogram of wealth at the last step
g \= sns.histplot(end\_wealth, discrete\=True)
g.set(
title\="Distribution of wealth at the end of simulation",
xlabel\="Wealth",
ylabel\="number of agents",
);

Or to plot the wealth of a given agent (in this example, agent 7):
\# Get the wealth of agent 7 over time
one\_agent\_wealth \= agent\_wealth.xs(7, level\="AgentID")
\# Plot the wealth of agent 7 over time
g \= sns.lineplot(data\=one\_agent\_wealth, x\="Step", y\="Wealth")
g.set(title\="Wealth of agent 7 over time");

You can also plot a reporter of multiple agents over time.
agent\_list \= \[3, 14, 25\]
\# Get the wealth of multiple agents over time
multiple\_agents\_wealth \= agent\_wealth\[\
agent\_wealth.index.get\_level\_values("AgentID").isin(agent\_list)\
\]
\# Plot the wealth of multiple agents over time
g \= sns.lineplot(data\=multiple\_agents\_wealth, x\="Step", y\="Wealth", hue\="AgentID")
g.set(title\="Wealth of agents 3, 14 and 25 over time");

We can also plot the average of all agents, with a 95% confidence interval for that average.
\# Transform the data to a long format
agent\_wealth\_long \= agent\_wealth.T.unstack().reset\_index()
agent\_wealth\_long.columns \= \["Step", "AgentID", "Variable", "Value"\]
agent\_wealth\_long.head(3)
\# Plot the average wealth over time
g \= sns.lineplot(data\=agent\_wealth\_long, x\="Step", y\="Value", errorbar\=("ci", 95))
g.set(title\="Average wealth over time")
\[Text(0.5, 1.0, 'Average wealth over time')\]

Which is exactly 1, as expected in this model, since each agent starts with one wealth unit, and each agent gives one wealth unit to another agent at each step.
You can also use pandas to export the data to a CSV (comma separated value) file, which can be opened by any common spreadsheet application or opened by pandas.
If you do not specify a file path, the file will be saved in the local directory. After you run the code below you will see two files appear (_model\_data.csv_ and _agent\_data.csv_)
\# save the model data (stored in the pandas gini object) to CSV
gini.to\_csv("model\_data.csv")
\# save the agent data (stored in the pandas agent\_wealth object) to CSV
agent\_wealth.to\_csv("agent\_data.csv")
\# Challenge update the model, conduct a batch run with a parameter sweep,
\# and visualize your results
Next Steps[#](#next-steps "Link to this heading")
--------------------------------------------------
Check out the [Agent Management Through AgentSet tutorial](https://mesa.readthedocs.io/latest/tutorials/3_agentset.html)
on effective ways to manage agents.
\[Comer2014\] Comer, Kenneth W. “Who Goes First? An Examination of the Impact of Activation on Outcome Behavior in AgentBased Models.” George Mason University, 2014. http://mars.gmu.edu/bitstream/handle/1920/9070/Comer\_gmu\_0883E\_10539.pdf
\[Dragulescu2002\] Drăgulescu, Adrian A., and Victor M. Yakovenko. “Statistical Mechanics of Money, Income, and Wealth: A Short Survey.” arXiv Preprint Cond-mat/0211175, 2002. http://arxiv.org/abs/cond-mat/0211175.
On this page
### This Page
* [Show Source](../_sources/tutorials/2_collecting_data.ipynb.txt)
---
# Visualization - Basic Dashboard — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Visualization - Basic Dashboard[#](#visualization-basic-dashboard "Link to this heading")
==========================================================================================
The Boltzmann Wealth Model[#](#the-boltzmann-wealth-model "Link to this heading")
----------------------------------------------------------------------------------
If you want to get straight to the tutorial checkout these environment providers:
[](https://mybinder.org/v2/gh/projectmesa/mesa/main?labpath=docs%2Ftutorials%2F4_visualization_basic.ipynb)
(This can take 30 seconds to 5 minutes to load)
Due to conflict with Colab and Solara there are no colab links for this tutorial
_If you are running locally, please ensure you have the latest Mesa version installed._
Tutorial Description[#](#tutorial-description "Link to this heading")
----------------------------------------------------------------------
This tutorial extends the Boltzmann wealth model from the [AgentSet tutorial](https://mesa.readthedocs.io/latest/tutorials/3_agentset.html)
, by adding an interactive dashboard.
In this portion, we will demonstrate how users can employ build a basic dashboard. This is part one of three part series on building interactive dashboards in Mesa.
_If you are starting here please see the [Running Your First Model tutorial](https://mesa.readthedocs.io/latest/tutorials/0_first_model.html)
for dependency and start-up instructions_
### Import Dependencies[#](#import-dependencies "Link to this heading")
This includes importing of dependencies needed for the tutorial.
\# Has multi-dimensional arrays and matrices.
\# Has a large collection of mathematical functions to operate on these arrays.
import numpy as np
\# Data manipulation and analysis.
import pandas as pd
\# Data visualization tools.
import seaborn as sns
import mesa
from mesa.discrete\_space import CellAgent, OrthogonalMooreGrid
from mesa.visualization import SolaraViz, make\_plot\_component, make\_space\_component
Basic Model[#](#basic-model "Link to this heading")
----------------------------------------------------
The following is the basic model we will be using to build the dashboard. This is the same model seen in tutorials 0-3.
def compute\_gini(model):
agent\_wealths \= \[agent.wealth for agent in model.agents\]
x \= sorted(agent\_wealths)
N \= model.num\_agents
B \= sum(xi \* (N \- i) for i, xi in enumerate(x)) / (N \* sum(x))
return 1 + (1 / N) \- 2 \* B
class MoneyAgent(CellAgent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model, cell):
"""initialize a MoneyAgent instance.
Args:
model: A model instance
"""
super().\_\_init\_\_(model)
self.cell \= cell
self.wealth \= 1
def move(self):
"""Move the agent to a random neighboring cell."""
self.cell \= self.cell.neighborhood.select\_random\_cell()
def give\_money(self):
"""Give 1 unit of wealth to a random agent in the same cell."""
cellmates \= \[a for a in self.cell.agents if a is not self\]
if cellmates: \# Only give money if there are other agents present
other \= self.random.choice(cellmates)
other.wealth += 1
self.wealth \-= 1
def step(self):
"""do one step of the agent."""
self.move()
if self.wealth \> 0:
self.give\_money()
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n\=10, width\=10, height\=10, seed\=None):
"""Initialize a MoneyModel instance.
Args:
N: The number of agents.
width: width of the grid.
height: Height of the grid.
"""
super().\_\_init\_\_(seed\=seed)
self.num\_agents \= n
self.grid \= OrthogonalMooreGrid((width, height), random\=self.random)
\# Create agents
MoneyAgent.create\_agents(
self,
self.num\_agents,
self.random.choices(self.grid.all\_cells.cells, k\=self.num\_agents),
)
self.datacollector \= mesa.DataCollector(
model\_reporters\={"Gini": compute\_gini}, agent\_reporters\={"Wealth": "wealth"}
)
self.datacollector.collect(self)
def step(self):
"""do one step of the model"""
self.agents.shuffle\_do("step")
self.datacollector.collect(self)
\# Lets make sure the model works
model \= MoneyModel(100, 10, 10)
for \_ in range(20):
model.step()
data \= model.datacollector.get\_agent\_vars\_dataframe()
\# Use seaborn
g \= sns.histplot(data\["Wealth"\], discrete\=True)
g.set(title\="Wealth distribution", xlabel\="Wealth", ylabel\="number of agents");

### Adding visualization[#](#adding-visualization "Link to this heading")
So far, we’ve built a model, run it, and analyzed some output afterwards. However, one of the advantages of agent-based models is that we can often watch them run step by step, potentially spotting unexpected patterns, behaviors or bugs, or developing new intuitions, hypotheses, or insights. Other times, watching a model run can explain it to an unfamiliar audience better than static explanations. Like many ABM frameworks, Mesa allows you to create an interactive visualization of the model. In this section we’ll walk through creating a visualization using built-in components, and (for advanced users) how to create a new visualization element.
First, a quick explanation of how Mesa’s interactive visualization works. The visualization is done in a browser window or Jupyter instance, using the [Solara](https://solara.dev/)
framework, a pure Python, React-style web framework. Running `solara run app.py` will launch a web server, which runs the model, and displays model detail at each step via a plotting library. Alternatively, you can execute everything inside a Jupyter instance and display it inline.
#### Grid Visualization[#](#grid-visualization "Link to this heading")
Mesa’s grid visualizer works by looping over every cell in a grid, and generating a portrayal for every agent it finds. A portrayal is a dictionary (which can easily be turned into a JSON object) which tells Matplotlib the color and size of the scatterplot markers (each signifying an agent). The only thing we need to provide is a function which takes an agent, and returns a portrayal dictionary. Here’s the simplest one: it’ll draw each agent as a blue, filled circle, with a radius size of 50.
def agent\_portrayal(agent):
return {
"color": "tab:blue",
"size": 50,
}
In addition to the portrayal method, we instantiate the model parameters, some of which are modifiable by user inputs. In this case, the number of agents, N, is specified as a slider of integers.
model\_params \= {
"n": {
"type": "SliderInt",
"value": 50,
"label": "Number of agents:",
"min": 10,
"max": 100,
"step": 1,
},
"width": 10,
"height": 10,
}
Next, we instantiate the visualization object which (by default) displays the grid containing the agents, and timeseries of values computed by the model’s data collector. In this example, we specify the Gini coefficient.
There are 3 buttons:
* the step button, which advances the model by 1 step
* the play button, which advances the model indefinitely until it is paused
* the pause button, which pauses the model
To reset the model, the order of operations are important
1. Stop the model
2. Update the parameters (e.g. move the sliders)
3. Press reset
\# Create initial model instance
money\_model \= MoneyModel(n\=50, width\=10, height\=10) \# keyword arguments
SpaceGraph \= make\_space\_component(agent\_portrayal)
GiniPlot \= make\_plot\_component("Gini")
page \= SolaraViz(
money\_model,
components\=\[SpaceGraph, GiniPlot\],
model\_params\=model\_params,
name\="Boltzmann Wealth Model",
)
\# This is required to render the visualization in the Jupyter notebook
page
Next Steps[#](#next-steps "Link to this heading")
--------------------------------------------------
Check out the next [visualization tutorial dynamic agents](https://mesa.readthedocs.io/latest/tutorials/5_visualization_dynamic_agents.html)
on how to further enhance your interactive dashboard.
\[Comer2014\] Comer, Kenneth W. “Who Goes First? An Examination of the Impact of Activation on Outcome Behavior in AgentBased Models.” George Mason University, 2014. http://mars.gmu.edu/bitstream/handle/1920/9070/Comer\_gmu\_0883E\_10539.pdf
\[Dragulescu2002\] Drăgulescu, Adrian A., and Victor M. Yakovenko. “Statistical Mechanics of Money, Income, and Wealth: A Short Survey.” arXiv Preprint Cond-mat/0211175, 2002. http://arxiv.org/abs/cond-mat/0211175.
On this page
### This Page
* [Show Source](../_sources/tutorials/4_visualization_basic.ipynb.txt)
---
# BatchRunner — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
BatchRunner[#](#batchrunner "Link to this heading")
====================================================
The Boltzmann Wealth Model[#](#the-boltzmann-wealth-model "Link to this heading")
----------------------------------------------------------------------------------
If you want to get straight to the tutorial checkout these environment providers:
(with Google Account) [](https://colab.research.google.com/github/projectmesa/mesa/blob/main/docs/tutorials/7_batch_run.ipynb)
(No Google Account) [](https://mybinder.org/v2/gh/projectmesa/mesa/main?labpath=docs%2Ftutorials%2F7_batch_run.ipynb)
(This can take 30 seconds to 5 minutes to load)
_If you are running locally, please ensure you have the latest Mesa version installed._
Tutorial Description[#](#tutorial-description "Link to this heading")
----------------------------------------------------------------------
This tutorial extends the Boltzmann wealth model from the [Collecting Data tutorial](https://mesa.readthedocs.io/latest/tutorials/2_collecting_data.html)
, by showing how users can use `batch_run` to conduct parameter sweeps of their models.
_If you are starting here please see the [Running Your First Model tutorial](https://mesa.readthedocs.io/latest/tutorials/0_first_model.html)
for dependency and start-up instructions_
### IN COLAB? - Run the next cell[#](#in-colab-run-the-next-cell "Link to this heading")
### Import Dependencies[#](#import-dependencies "Link to this heading")
This includes importing of dependencies needed for the tutorial.
\# Has multi-dimensional arrays and matrices.
\# Has a large collection of mathematical functions to operate on these arrays.
import numpy as np
\# Data manipulation and analysis.
import pandas as pd
\# Data visualization tools.
import seaborn as sns
import mesa
\# Import Cell Agent and OrthogonalMooreGrid
from mesa.discrete\_space import CellAgent, OrthogonalMooreGrid
Base Model[#](#base-model "Link to this heading")
--------------------------------------------------
The below provides the base model from which we will add batch\_run functionality. Of note, this is the same as the [collecting data tutorial](https://mesa.readthedocs.io/latest/tutorials/2_collecting_data.html)
but we add one agent reporter that counts if money is not given to that agent during a time step.
We also added `self.running=True` in the `MoneyModel` class. This allows users to provide a conditional stop attribute (e.g. all sheep and wolves die) as opposed to a step count.)
This is from the [Running Your First Model tutorial](https://mesa.readthedocs.io/latest/tutorials/0_first_model.html)
tutorial. If you have any questions about it functionality please review that tutorial.
def compute\_gini(model):
agent\_wealths \= \[agent.wealth for agent in model.agents\]
x \= sorted(agent\_wealths)
n \= model.num\_agents
B \= sum(xi \* (n \- i) for i, xi in enumerate(x)) / (n \* sum(x))
return 1 + (1 / n) \- 2 \* B
class MoneyAgent(CellAgent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model, cell):
super().\_\_init\_\_(model)
self.cell \= cell
self.wealth \= 1
self.steps\_not\_given \= 0
def move(self):
self.cell \= self.cell.neighborhood.select\_random\_cell()
def give\_money(self):
cellmates \= \[a for a in self.cell.agents if a is not self\]
if len(cellmates) \> 0 and self.wealth \> 0:
other \= self.random.choice(cellmates)
other.wealth += 1
self.wealth \-= 1
self.steps\_not\_given \= 0
else:
self.steps\_not\_given += 1
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n, width, height, seed\=None):
super().\_\_init\_\_(seed\=seed)
self.num\_agents \= n
self.grid \= OrthogonalMooreGrid(
(width, height), torus\=True, capacity\=10, random\=self.random
)
\# Instantiate DataCollector
self.datacollector \= mesa.DataCollector(
model\_reporters\={"Gini": compute\_gini},
agent\_reporters\={"Wealth": "wealth", "Steps\_not\_given": "steps\_not\_given"},
)
self.running \= True
\# Create agents
agents \= MoneyAgent.create\_agents(
self,
self.num\_agents,
self.random.choices(self.grid.all\_cells.cells, k\=self.num\_agents),
)
def step(self):
\# Collect data each step
self.datacollector.collect(self)
self.agents.shuffle\_do("move")
self.agents.do("give\_money")
model \= MoneyModel(100, 10, 10)
for \_ in range(100):
model.step()
gini \= model.datacollector.get\_model\_vars\_dataframe()
g \= sns.lineplot(data\=gini)
g.set(title\="Gini Coefficient over Time", ylabel\="Gini Coefficient");

Batch Run[#](#batch-run "Link to this heading")
------------------------------------------------
Modelers typically won’t run a model just once, but multiple times, with fixed parameters to find the overall distributions the model generates, and with varying parameters to analyze how these variables drive the model’s outputs and behaviors. This is commonly referred to as parameter sweeps. Instead of needing to write nested for-loops for each model, Mesa provides a [`batch_run`](https://mesa.readthedocs.io/latest/apis/batchrunner.html)
function which automates parameter sweeps and allows the model variants to run on multiple processors.
### Batch run parameters[#](#batch-run-parameters "Link to this heading")
We call `batch_run` with the following arguments:
* `model_cls` The model class that is used for the batch run.
* `parameters` A dictionary containing all the parameters of the model class and desired values to use for the batch run as key-value pairs. Each value can either be fixed ( e.g. `{"height": 10, "width": 10}`) or an iterable (e.g. `{"n": range(10, 500, 10)}`). `batch_run` will then generate all possible parameter combinations based on this dictionary and run the model `iterations` times for each combination.
* `number_processes` If not specified, defaults to 1. Set it to `None` to use all the available processors. Note: Multiprocessing does make debugging challenging. If your parameter sweeps are resulting in unexpected errors set `number_processes=1`.
* `iterations` The number of iterations to run each parameter combination for. Optional. If not specified, defaults to 1.
* `data_collection_period` The length of the period (number of steps) after which the model and agent reporters collect data. Optional. If not specified, defaults to -1, i.e. only at the end of each episode.
* `max_steps` The maximum number of time steps after which the model halts. An episode does either end when `self.running` of the model class is set to `False` or when `model.steps == max_steps` is reached. Optional. If not specified, defaults to 1000.
* `display_progress` Display the batch run progress. Optional. If not specified, defaults to `True`.
In the following example, we hold the height and width fixed, and vary the number of agents. We tell the batch runner to run 5 instantiations of the model with each number of agents, and to run each for 100 steps.
We want to keep track of
1. The Gini coefficient value at each time step
2. The individual agent’s wealth development and steps without giving money.
**Important:** Since for the latter, changes at each time step might be interesting, we set `data_collection_period=1`. By default, it only collects data at the end of each episode.
Note: The total number of runs is 100 (20 different populations \* 5 iterations per population).
params \= {"width": 10, "height": 10, "n": range(5, 105, 5)}
results \= mesa.batch\_run(
MoneyModel,
parameters\=params,
iterations\=5,
max\_steps\=100,
number\_processes\=1,
data\_collection\_period\=1,
display\_progress\=True,
)
To further analyze the return of the `batch_run` function, we convert the list of dictionaries to a Pandas DataFrame and print its keys.
### Batch Run Analysis and Visualization[#](#batch-run-analysis-and-visualization "Link to this heading")
results\_df \= pd.DataFrame(results)
print(f"The results have {len(results)} rows.")
print(f"The columns of the data frame are {list(results\_df.keys())}.")
The results have 525100 rows.
The columns of the data frame are \['RunId', 'iteration', 'Step', 'width', 'height', 'n', 'Gini', 'AgentID', 'Wealth', 'Steps\_not\_given'\].
First, we want to take a closer look at how the Gini coefficient at the end of each episode changes as we increase the size of the population. For this, we filter our results to only contain the data of one agent (the Gini coefficient will be the same for the entire population at any time) at the 100th step of each episode and then scatter-plot the values for the Gini coefficient over the the number of agents. Notice there are five values for each population size since we set `iterations=5` when calling the batch run.
\# Filter the results to only contain the data of one agent
\# The Gini coefficient will be the same for the entire population at any time
results\_filtered \= results\_df\[(results\_df.AgentID \== 1) & (results\_df.Step \== 100)\]
results\_filtered\[\["iteration", "n", "Gini"\]\].reset\_index(
drop\=True
).head() \# Create a scatter plot
g \= sns.scatterplot(data\=results\_filtered, x\="n", y\="Gini")
g.set(
xlabel\="number of agents",
ylabel\="Gini coefficient",
title\="Gini coefficient vs. Number of Agents",
);

We can create different kinds of plot from this filtered DataFrame. For example, a point plot with error bars.
\# Create a point plot with error bars
g \= sns.pointplot(data\=results\_filtered, x\="n", y\="Gini", linestyle\="None")
g.figure.set\_size\_inches(8, 4)
g.set(
xlabel\="number of agents",
ylabel\="Gini coefficient",
title\="Gini coefficient vs. number of agents",
);

Secondly, we want to display the agent’s wealth at each time step of one specific episode. To do this, we again filter our large data frame, this time with a fixed number of agents and only for a specific iteration of that population. To print the results, we convert the filtered data frame to a string specifying the desired columns to print.
Pandas has built-in functions to convert to a lot of different data formats. For example, to display as a table in a Jupyter, we can use the `to_html()` function which takes the same arguments as `to_string()` (see commented lines).
\# First, we filter the results
one\_episode\_wealth \= results\_df\[(results\_df.n \== 10) & (results\_df.iteration \== 2)\]
\# Then, print the columns of interest of the filtered data frame
print(
one\_episode\_wealth.to\_string(
index\=False, columns\=\["Step", "AgentID", "Wealth"\], max\_rows\=10
)
)
\# For a prettier display we can also convert the data frame to html
\# Uncomment the two lines below to test in Jupyter
\# from IPython.display import display, HTML
\# display(HTML(one\_episode\_wealth.to\_html(index=False, columns=\['Step',\
\# 'AgentID', 'Wealth'\], max\_rows=25)))
Step AgentID Wealth
0 NaN NaN
1 1.0 1.0
1 2.0 1.0
1 3.0 1.0
1 4.0 1.0
... ... ...
100 6.0 1.0
100 7.0 1.0
100 8.0 2.0
100 9.0 0.0
100 10.0 1.0
Lastly, we want to take a look at the development of the Gini coefficient over the course of one iteration. Filtering and printing looks almost the same as above, only this time we choose a different episode.
results\_one\_episode \= results\_df\[\
(results\_df.n \== 10) & (results\_df.iteration \== 1) & (results\_df.AgentID \== 1)\
\]
print(results\_one\_episode.to\_string(index\=False, columns\=\["Step", "Gini"\], max\_rows\=10))
Step Gini
1 0.0
2 0.0
3 0.0
4 0.0
5 0.0
... ...
96 0.0
97 0.0
98 0.0
99 0.0
100 0.0
Next Steps[#](#next-steps "Link to this heading")
--------------------------------------------------
Check out the [comparing 5 scenarios](https://mesa.readthedocs.io/latest/tutorials/8_comparing_scenarios.html)
on analyzing `batch_run` results.
\[Comer2014\] Comer, Kenneth W. “Who Goes First? An Examination of the Impact of Activation on Outcome Behavior in AgentBased Models.” George Mason University, 2014. http://mars.gmu.edu/bitstream/handle/1920/9070/Comer\_gmu\_0883E\_10539.pdf
\[Dragulescu2002\] Drăgulescu, Adrian A., and Victor M. Yakovenko. “Statistical Mechanics of Money, Income, and Wealth: A Short Survey.” arXiv Preprint Cond-mat/0211175, 2002. http://arxiv.org/abs/cond-mat/0211175.
On this page
### This Page
* [Show Source](../_sources/tutorials/7_batch_run.ipynb.txt)
---
# Best Practices — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Best Practices[#](#best-practices "Link to this heading")
==========================================================
Here are some general principles that have proven helpful for developing models.
Model Layout[#](#model-layout "Link to this heading")
------------------------------------------------------
A model should be contained in a folder named with lower-case letters and underscores, such as `wolf_sheep`. Within that directory:
* `Readme.md` describes the model, how to use it, and any other details.
* `model.py` should contain the model class.
* `agents.py` should contain the agent class(es).
* `app.py` should contain the Solara-based visualization code (optional).
You can add more files as needed, for example:
* `run.py` could contain the code to run the model.
* `batch_run.py` could contain the code to run the model multiple times.
* `analysis.py` could contain any analysis code.
Input data can be stored in a `data` directory, output data in an `output`, processed results in a `results` directory, images in an `images` directory, etc.
All our [examples](examples.html)
follow this layout.
Randomization[#](#randomization "Link to this heading")
--------------------------------------------------------
If your model involves some random choice, you can use the built-in `random` property that many Mesa objects have, including `Model`, `Agent`, and `AgentSet`. This works exactly like the built-in `random` library.
class AwesomeModel(Model):
\# ...
def cool\_method(self):
interesting\_number \= self.random.random()
print(interesting\_number)
class AwesomeAgent(Agent):
\# ...
def \_\_init\_\_(self, unique\_id, model, ...):
super().\_\_init\_\_(unique\_id, model)
\# ...
def my\_method(self):
random\_number \= self.random.randint(0, 100)
`Agent.random` is just a convenient shorthand in the Agent class to `self.model.random`. If you create your own `AgentSet` instances, you have to pass `random` explicitly. Typically, you can simply do, in a Model instance, `my_agentset = AgentSet([], random=self.random)`. This ensures that `my_agentset` uses the same random number generator as the rest of the model.
When a model object is created, its random property is automatically seeded with the current time. The seed determines the sequence of random numbers; if you instantiate a model with the same seed, you will get the same results. To allow you to set the seed, make sure your model has a `seed` argument in its `__init__`.
class AwesomeModel(Model):
def \_\_init\_\_(self, seed\=None):
super().\_\_init\_\_(seed\=seed)
...
def cool\_method(self):
interesting\_number \= self.random.random()
print(interesting\_number)
\>>> model0 \= AwesomeModel(seed\=0)
\>>> model0.\_seed
0
\>>> model0.cool\_method()
0.8444218515250481
\>>> model1 \= AwesomeModel(seed\=0)
\>>> model1.cool\_method()
0.8444218515250481
On this page
### This Page
* [Show Source](_sources/best-practices.md.txt)
---
# Comparing Scenarios — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Comparing Scenarios[#](#comparing-scenarios "Link to this heading")
====================================================================
The Boltzmann Wealth Model[#](#the-boltzmann-wealth-model "Link to this heading")
----------------------------------------------------------------------------------
If you want to get straight to the tutorial checkout these environment providers:
(with Google Account) [](https://colab.research.google.com/github/projectmesa/mesa/blob/main/docs/tutorials/8_comparing_scenarios.ipynb)
(No Google Account) [](https://mybinder.org/v2/gh/projectmesa/mesa/main?labpath=docs%2Ftutorials%2F8_comparing_scenarios.ipynb)
(This can take 30 seconds to 5 minutes to load)
_If you are running locally, please ensure you have the latest Mesa version installed._
Tutorial Description[#](#tutorial-description "Link to this heading")
----------------------------------------------------------------------
This tutorial extends the Boltzmann wealth model from the [Batch Run tutorial](https://mesa.readthedocs.io/latest/tutorials/2_batch_run.html)
, by showing some ways in which users can analyze `batch_run` results.
_If you are starting here please see the [Running Your First Model tutorial](https://mesa.readthedocs.io/latest/tutorials/0_first_model.html)
for dependency and start-up instructions_
### IN COLAB? - Run the next cell[#](#in-colab-run-the-next-cell "Link to this heading")
### Import Dependencies[#](#import-dependencies "Link to this heading")
This includes importing of dependencies needed for the tutorial.
\# Has multi-dimensional arrays and matrices.
\# Has a large collection of mathematical functions to operate on these arrays.
import numpy as np
\# Data manipulation and analysis.
import pandas as pd
\# Data visualization tools.
import seaborn as sns
import mesa
\# Import Cell Agent and OrthogonalMooreGrid
from mesa.discrete\_space import CellAgent, OrthogonalMooreGrid
Base Model[#](#base-model "Link to this heading")
--------------------------------------------------
The below provides the base model from which we conduct a parameter sweep by altering the population parameter and running each variation for 5 scenarios.
This is from the [Batch Run tutorial](https://mesa.readthedocs.io/latest/tutorials/7_batch_run.html)
tutorial. If you have any questions about it functionality please review that tutorial.
def compute\_gini(model):
agent\_wealths \= \[agent.wealth for agent in model.agents\]
x \= sorted(agent\_wealths)
n \= model.num\_agents
B \= sum(xi \* (n \- i) for i, xi in enumerate(x)) / (n \* sum(x))
return 1 + (1 / n) \- 2 \* B
class MoneyAgent(CellAgent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model, cell):
super().\_\_init\_\_(model)
self.cell \= cell
self.wealth \= 1
self.steps\_not\_given \= 0
def move(self):
self.cell \= self.cell.neighborhood.select\_random\_cell()
def give\_money(self):
cellmates \= \[a for a in self.cell.agents if a is not self\]
if len(cellmates) \> 0 and self.wealth \> 0:
other \= self.random.choice(cellmates)
other.wealth += 1
self.wealth \-= 1
self.steps\_not\_given \= 0
else:
self.steps\_not\_given += 1
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n, width, height, seed\=None):
super().\_\_init\_\_(seed\=seed)
self.num\_agents \= n
self.grid \= OrthogonalMooreGrid(
(width, height), torus\=True, capacity\=10, random\=self.random
)
\# Instantiate DataCollector
self.datacollector \= mesa.DataCollector(
model\_reporters\={"Gini": compute\_gini},
agent\_reporters\={"Wealth": "wealth", "Steps\_not\_given": "steps\_not\_given"},
)
self.running \= True
\# Create agents
agents \= MoneyAgent.create\_agents(
self,
self.num\_agents,
self.random.choices(self.grid.all\_cells.cells, k\=self.num\_agents),
)
def step(self):
\# Collect data each step
self.datacollector.collect(self)
self.agents.shuffle\_do("move")
self.agents.do("give\_money")
params \= {"width": 10, "height": 10, "n": range(5, 105, 5)}
results \= mesa.batch\_run(
MoneyModel,
parameters\=params,
iterations\=5,
max\_steps\=100,
number\_processes\=1,
data\_collection\_period\=1,
display\_progress\=True,
)
We will now extract the results into a pandas dataframe.
results\_df \= pd.DataFrame(results)
print(f"The results have {len(results)} rows.")
print(f"The columns of the data frame are {list(results\_df.keys())}.")
The results have 525100 rows.
The columns of the data frame are \['RunId', 'iteration', 'Step', 'width', 'height', 'n', 'Gini', 'AgentID', 'Wealth', 'Steps\_not\_given'\].
### Analyzing model reporters: Comparing 5 scenarios[#](#analyzing-model-reporters-comparing-5-scenarios "Link to this heading")
Other insights might be gathered when we compare the Gini coefficient of different scenarios. For example, we can compare the Gini coefficient of a population with 25 agents to the Gini coefficient of a population with 400 agents. While doing this, we increase the number of iterations to 25 to get a better estimate of the Gini coefficient for each population size and get usable error estimations.
As we look varying the parameters to see the impact on model outcomes, it is critical to again point out that users can set the random seed. Due to the often inherent randomness with ABMs the seed becomes crucial for:
* **Reproducibility** - Being able to replicate the ABM results
* **Sensitivity Analysis** - Identifying how sensitive/robust your model results are to random fluctuations
Treating the seed as an additional parameter and running numerous scenarios allows us to see the impact of randomness on this model.
params \= {"seed": None, "width": 10, "height": 10, "n": \[5, 10, 20, 40, 80\]}
results\_5s \= mesa.batch\_run(
MoneyModel,
parameters\=params,
iterations\=25,
max\_steps\=100,
number\_processes\=1,
data\_collection\_period\=1, \# Need to collect every step
display\_progress\=True,
)
results\_5s\_df \= pd.DataFrame(results\_5s)
We filter the results to only contain the data of one agent
\# The Gini coefficient will be the same for the entire population at any time.
results\_5s\_df\_filtered \= results\_5s\_df\[(results\_5s\_df.AgentID \== 1)\]
results\_5s\_df\_filtered.head(3)
| | RunId | iteration | Step | seed | width | height | n | Gini | AgentID | Wealth | Steps\_not\_given |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 1 | 0 | 0 | 1 | None | 10 | 10 | 5 | 0.0 | 1.0 | 1.0 | 0.0 |
| 6 | 0 | 0 | 2 | None | 10 | 10 | 5 | 0.0 | 1.0 | 1.0 | 1.0 |
| 11 | 0 | 0 | 3 | None | 10 | 10 | 5 | 0.0 | 1.0 | 1.0 | 2.0 |
\# Create a lineplot with error bars
g \= sns.lineplot(
data\=results\_5s\_df,
x\="Step",
y\="Gini",
hue\="n",
errorbar\=("ci", 95),
palette\="tab10",
)
g.figure.set\_size\_inches(8, 4)
plot\_title \= (
"Gini coefficient for different population sizes\\n"
"(mean over 100 runs, with 95% confidence interval)"
)
g.set(title\=plot\_title, ylabel\="Gini coefficient");

In this case it looks like the Gini coefficient increases slower for smaller populations. This can be because of different things, either because the Gini coefficient is a measure of inequality and the smaller the population, the more likely it is that the agents are all in the same wealth class, or because there are less interactions between agents in smaller populations, which means that the wealth of an agent is less likely to change.
### Exercise:[#](#exercise "Link to this heading")
Treat the seed as a parameter and see the impact on the Gini Coefficient
You can also plot the seeds against the Gini Coefficient by changing the “hue” parameter in sns.lineplot function.
### Analyzing agent reporters: Comparing 5 scenarios[#](#analyzing-agent-reporters-comparing-5-scenarios "Link to this heading")
From the agents we collected the wealth and the number of consecutive rounds without a transaction. We can compare the 5 different population sizes by plotting the average number of consecutive rounds without a transaction for each population size.
Note that we’re aggregating multiple times here: First we take the average of all agents for each single replication. Then we plot the averages for all replications, with the error band showing the 95% confidence interval of that first average (over all agents). So this error band is representing the uncertainty of the mean value of the number of consecutive rounds without a transaction for each population size.
\# Calculate the mean of the wealth and the number of consecutive rounds
\# for all agents in each episode.
agg\_results\_df \= (
results\_5s\_df.groupby(\["iteration", "n", "Step"\])
.agg({"Wealth": "mean", "Steps\_not\_given": "mean"})
.reset\_index()
)
agg\_results\_df.head(3)
| | iteration | n | Step | Wealth | Steps\_not\_given |
| --- | --- | --- | --- | --- | --- |
| 0 | 0 | 5 | 0 | NaN | NaN |
| 1 | 0 | 5 | 1 | 1.0 | 0.0 |
| 2 | 0 | 5 | 2 | 1.0 | 1.0 |
\# Create a line plot with error bars
g \= sns.lineplot(
data\=agg\_results\_df, x\="Step", y\="Steps\_not\_given", hue\="n", palette\="tab10"
)
g.figure.set\_size\_inches(8, 4)
g.set(
title\="Average number of consecutive rounds without a transaction for "
"different population sizes\\n(mean with 95% confidence interval)",
ylabel\="Consecutive rounds without a transaction",
);

It can be clearly seen that the lower the number of agents, the higher the number of consecutive rounds without a transaction. This is because the agents have fewer interactions with each other and therefore the wealth of an agent is less likely to change.
### General steps for analyzing results[#](#general-steps-for-analyzing-results "Link to this heading")
Many other analysis are possible based on the policies, scenarios and uncertainties that you might be interested in. In general, you can follow these steps to do your own analysis:
1. Determine which metrics you want to analyse. Add these as model and agent reporters to the datacollector of your model.
2. Determine the input parameters you want to vary. Add these as parameters to the batch\_run function, using ranges or lists to test different values.
3. Determine the hyperparameters of the batch\_run function. Define the number of iterations, the number of processes, the number of steps, the data collection period, etc.
4. Run the batch\_run function and save the results.
5. Transform, filter and aggregate the results to get the data you want to analyze. Make sure it’s in long format, so that each row represents a single value.
6. Choose a plot type, what to plot on the x and y axis, which columns to use for the hue. Seaborn also has an amazing [Example Gallery](https://seaborn.pydata.org/examples/index.html)
.
7. Plot the data and analyze the results.
### Exercise:[#](#id1 "Link to this heading")
Update the model in some new way (e.g. a new agent attribute, a new model reporter), conduct a batch run with a parameter sweep and visualize your results
That is it you have successfully completed Mesa’s Introductory Tutorial
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
### More Mesa[#](#more-mesa "Link to this heading")
If you are looking for other Mesa models or tools here are some additional resources.
* Interactive Dashboard: There is a separate [visualization tutorial](https://mesa.readthedocs.io/latest/tutorials/visualization_tutorial.html)
that will take users through building a dashboard for this model (aka Boltzmann Wealth Model).
* Example ABMs: Find canonical examples and examples of ABMs demonstrating highlighted features in the [Examples Tab](https://mesa.readthedocs.io/stable/examples.html)
* Expanded Examples: Want to integrate Reinforcement Learning or work on the Traveling Salesman Problem? Checkout [Mesa Examples](https://github.com/projectmesa/mesa-examples/)
* Mesa-Geo: If you need an ABM with Geographic Information Systems (GIS) checkout [Mesa-Geo](https://mesa-geo.readthedocs.io/latest/)
* Mesa Frames: Have a large complex model that you need to speed up, check out [Mesa Frames](https://github.com/projectmesa/mesa-frames)
Happy Modeling
-----------------------------------------------------------
This document is a work in progress. If you see any errors, exclusions or have any problems please contact [us](https://github.com/projectmesa/mesa/issues)
.
\[Comer2014\] Comer, Kenneth W. “Who Goes First? An Examination of the Impact of Activation on Outcome Behavior in AgentBased Models.” George Mason University, 2014. http://mars.gmu.edu/bitstream/handle/1920/9070/Comer\_gmu\_0883E\_10539.pdf
\[Dragulescu2002\] Drăgulescu, Adrian A., and Victor M. Yakovenko. “Statistical Mechanics of Money, Income, and Wealth: A Short Survey.” arXiv Preprint Cond-mat/0211175, 2002. http://arxiv.org/abs/cond-mat/0211175.
On this page
### This Page
* [Show Source](../_sources/tutorials/8_comparing_scenarios.ipynb.txt)
---
# Model — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Model[#](#module-mesa.model "Link to this heading")
====================================================
The model class for Mesa framework.
Core Objects: Model
_class_ Model(_\*args: [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")
_, _seed: [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _rng: Generator | BitGenerator | [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| integer | [Sequence](https://docs.python.org/3/library/collections.abc.html#collections.abc.Sequence "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\] | SeedSequence | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _\*\*kwargs: [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")
_)[\[source\]](../_modules/mesa/model.html#Model)
[#](#mesa.model.Model "Link to this definition")
Base class for models in the Mesa ABM library.
This class serves as a foundational structure for creating agent-based models. It includes the basic attributes and methods necessary for initializing and running a simulation model.
running[#](#mesa.model.Model.running "Link to this definition")
A boolean indicating if the model should continue running.
steps[#](#mesa.model.Model.steps "Link to this definition")
the number of times model.step() has been called.
random[#](#mesa.model.Model.random "Link to this definition")
a seeded python.random number generator.
rng[#](#mesa.model.Model.rng "Link to this definition")
a seeded numpy.random.Generator
Notes
Model.agents returns the AgentSet containing all agents registered with the model. Changing the content of the AgentSet directly can result in strange behavior. If you want change the composition of this AgentSet, ensure you operate on a copy.
Create a new model.
Overload this method with the actual code to initialize the model. Always start with super().\_\_init\_\_() to initialize the model object properly.
Parameters:
* **args** – arguments to pass onto super
* **seed** – the seed for the random number generator
* **rng** – Pseudorandom number generator state. When rng is None, a new numpy.random.Generator is created using entropy from the operating system. Types other than numpy.random.Generator are passed to numpy.random.default\_rng to instantiate a Generator.
* **kwargs** – keyword arguments to pass onto super
Notes
you have to pass either seed or rng, but not both.
_property_ agents_: [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
_[#](#mesa.model.Model.agents "Link to this definition")
Provides an AgentSet of all agents in the model, combining agents from all types.
_property_ agent\_types_: [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[type](https://docs.python.org/3/library/functions.html#type "(in Python v3.13)")\
\]_[#](#mesa.model.Model.agent_types "Link to this definition")
Return a list of all unique agent types registered with the model.
_property_ agents\_by\_type_: [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[[type](https://docs.python.org/3/library/functions.html#type "(in Python v3.13)")\
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\], [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")\
\]_[#](#mesa.model.Model.agents_by_type "Link to this definition")
A dictionary where the keys are agent types and the values are the corresponding AgentSets.
register\_agent(_agent_)[\[source\]](../_modules/mesa/model.html#Model.register_agent)
[#](#mesa.model.Model.register_agent "Link to this definition")
Register the agent with the model.
Parameters:
**agent** – The agent to register.
Notes
This method is called automatically by `Agent.__init__`, so there is no need to use this if you are subclassing Agent and calling its super in the `__init__` method.
deregister\_agent(_agent_)[\[source\]](../_modules/mesa/model.html#Model.deregister_agent)
[#](#mesa.model.Model.deregister_agent "Link to this definition")
Deregister the agent with the model.
Parameters:
**agent** – The agent to deregister.
Notes
This method is called automatically by `Agent.remove`
run\_model() → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/model.html#Model.run_model)
[#](#mesa.model.Model.run_model "Link to this definition")
Run the model until the end condition is reached.
Overload as needed.
step() → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/model.html#Model.step)
[#](#mesa.model.Model.step "Link to this definition")
A single step. Fill in here.
reset\_randomizer(_seed: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/model.html#Model.reset_randomizer)
[#](#mesa.model.Model.reset_randomizer "Link to this definition")
Reset the model random number generator.
Parameters:
**seed** – A new seed for the RNG; if None, reset using the current seed
reset\_rng(_rng: Generator | BitGenerator | [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| integer | [Sequence](https://docs.python.org/3/library/collections.abc.html#collections.abc.Sequence "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\] | SeedSequence | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/model.html#Model.reset_rng)
[#](#mesa.model.Model.reset_rng "Link to this definition")
Reset the model random number generator.
Parameters:
**rng** – A new seed for the RNG; if None, reset using the current seed
remove\_all\_agents()[\[source\]](../_modules/mesa/model.html#Model.remove_all_agents)
[#](#mesa.model.Model.remove_all_agents "Link to this definition")
Remove all agents from the model.
Notes
This method calls agent.remove for all agents in the model. If you need to remove agents from e.g., a SingleGrid, you can either explicitly implement your own agent.remove method or clean this up near where you are calling this method.
On this page
### This Page
* [Show Source](../_sources/apis/model.md.txt)
---
# Unknown
\# Getting started Mesa is a modular framework for building, analyzing and visualizing agent-based models. \*\*Agent-based models\*\* are computer simulations involving multiple entities (the agents) acting and interacting with one another based on their programmed behavior. Agents can be used to represent living cells, animals, individual humans, even entire organizations or abstract entities. Sometimes, we may have an understanding of how the individual components of a system behave, and want to see what system-level behaviors and effects emerge from their interaction. Other times, we may have a good idea of how the system overall behaves, and want to figure out what individual behaviors explain it. Or we may want to see how to get agents to cooperate or compete most effectively. Or we may just want to build a cool toy with colorful little dots moving around. ## Tutorials If you want to get a quick start on how to build agent based models with MESA, check the overview and tutorials: - \[Overview of the MESA library\](overview): Learn about the core concepts and components of Mesa. - \[Creating Your First Model\](tutorials/0\_first\_model): Learn how to create your first Mesa model. - \[Adding Space\](tutorials/1\_adding\_space): Learn how to add space to your Mesa model and understand Mesa's space architecture. - \[Collecting Data\](tutorials/2\_collecting\_data): Learn how to collect model level and agent level data with Mesa' DataCollector. - \[AgentSet\](tutorials/3\_agentset): Learn how to more effectively manage agents with Mesa's AgentSet. - \[Basic Visualization\](tutorials/4\_visualization\_basic): Learn how to build an interactive dashboard with Mesa's visualization module. - \[Dynamic Agent Visualization\](tutorials/5\_visualization\_dynamic\_agents): Learn how to dynamically represent your agents in your interactive dashboard. - \[Custom Visualization Components\](tutorials/6\_visualization\_custom): Learn how to add custom visual components to your interactive dashboard. - \[Parameter Sweeps\](tutorials/7\_batch\_run): Learn how to conduct parameter sweeps on multiple processors with Mesa's BatchRunner. - \[Comparing Scenarios\](tutorials/8\_comparing\_scenarios): Think through how to analyze your parameter sweep results to find insight in your Mesa simulations. ## Examples Mesa ships with a collection of example models. These are classic ABMs, so if you are familiar with ABMs and want to get a quick sense of how MESA works, these examples are great place to start. You can find them \[here\](examples). ## Further resources To further explore Mesa and its features, we have the following resources available: ### Best practices - \[Mesa best practices\](best-practices): an overview of tips and guidelines for using MESA. ### API documentation - \[Mesa API reference\](apis): Detailed documentation of Mesa's classes and functions. ### Repository of models built using MESA - \[Mesa Examples repository\](https://github.com/projectmesa/mesa-examples): A collection of example models demonstrating various Mesa features and modeling techniques. ### Migration guide - \[Mesa 3.0 Migration guide\](migration\_guide): If you're upgrading from an earlier version of Mesa, this guide will help you navigate the changes in Mesa 3.0. ### Source Ccode and development - \[Mesa GitHub repository\](https://github.com/projectmesa/mesa): Access the full source code of Mesa, contribute to its development, or report issues. - \[Mesa release notes\](https://github.com/projectmesa/mesa/releases): View the detailed changelog of Mesa, including all past releases and their features. ### Community and support - \[Mesa GitHub Discussions\](https://github.com/projectmesa/mesa/discussions): Join discussions, ask questions, and connect with other Mesa users. - \[Matrix Chat\](https://matrix.to/#/#project-mesa:matrix.org): Real-time chat for quick questions and community interaction. Enjoy modelling with Mesa, and feel free to reach out! \`\`\`{toctree} :hidden: true :maxdepth: 7 Overview Creating Your First Model Adding Space Collecting Data AgentSet Basic Visualization Dynamic Agent Visualization Custom Visualization Components Parameter Sweeps Comparing Scenarios Best Practices \`\`\`
---
# Schelling Segregation Model — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Schelling Segregation Model[#](#schelling-segregation-model "Link to this heading")
====================================================================================
Summary[#](#summary "Link to this heading")
--------------------------------------------
The Schelling segregation model is a classic agent-based model, demonstrating how even a mild preference for similar neighbors can lead to a much higher degree of segregation than we would intuitively expect. The model consists of agents on a square grid, where each grid cell can contain at most one agent. Agents come in two colors: red and blue. They are happy if a certain number of their eight possible neighbors are of the same color, and unhappy otherwise. Unhappy agents will pick a random empty cell to move to each step, until they are happy. The model keeps running until there are no unhappy agents.
By default, the number of similar neighbors the agents need to be happy is set to 3. That means the agents would be perfectly happy with a majority of their neighbors being of a different color (e.g. a Blue agent would be happy with five Red neighbors and three Blue ones). Despite this, the model consistently leads to a high degree of segregation, with most agents ending up with no neighbors of a different color.
How to Run[#](#how-to-run "Link to this heading")
--------------------------------------------------
To run the model interactively, in this directory, run the following command
$ solara run app.py
Then open your browser to [http://127.0.0.1:8765/](http://127.0.0.1:8765/)
and click the Play button.
To view and run some example model analyses, launch the IPython Notebook and open `analysis.ipynb`. Visualizing the analysis also requires [matplotlib](http://matplotlib.org/)
.
How to Run without the GUI[#](#how-to-run-without-the-gui "Link to this heading")
----------------------------------------------------------------------------------
To run the model with the grid displayed as an ASCII text, run `python run_ascii.py` in this directory.
Files[#](#files "Link to this heading")
----------------------------------------
* `model.py`: Contains the Schelling model class
* `agents.py`: Contains the Schelling agent class
* `app.py`: Code for the interactive visualization.
* `analysis.ipynb`: Notebook demonstrating how to run experiments and parameter sweeps on the model.
Further Reading[#](#further-reading "Link to this heading")
------------------------------------------------------------
Schelling’s original paper describing the model:
[Schelling, Thomas C. Dynamic Models of Segregation. Journal of Mathematical Sociology. 1971, Vol. 1, pp 143-186.](https://www.stat.berkeley.edu/~aldous/157/Papers/Schelling_Seg_Models.pdf)
An interactive, browser-based explanation and implementation:
[Parable of the Polygons](http://ncase.me/polygons/)
, by Vi Hart and Nicky Case.
Agents[#](#agents "Link to this heading")
------------------------------------------
from mesa.discrete\_space import CellAgent
class SchellingAgent(CellAgent):
"""Schelling segregation agent."""
def \_\_init\_\_(
self, model, cell, agent\_type: int, homophily: float \= 0.4, radius: int \= 1
) \-> None:
"""Create a new Schelling agent.
Args:
model: The model instance the agent belongs to
agent\_type: Indicator for the agent's type (minority=1, majority=0)
homophily: Minimum number of similar neighbors needed for happiness
radius: Search radius for checking neighbor similarity
"""
super().\_\_init\_\_(model)
self.cell \= cell
self.type \= agent\_type
self.homophily \= homophily
self.radius \= radius
def step(self) \-> None:
"""Determine if agent is happy and move if necessary."""
neighbors \= list(self.cell.get\_neighborhood(radius\=self.radius).agents)
\# Count similar neighbors
similar\_neighbors \= len(\[n for n in neighbors if n.type \== self.type\])
\# Calculate the fraction of similar neighbors
if (valid\_neighbors := len(neighbors)) \> 0:
similarity\_fraction \= similar\_neighbors / valid\_neighbors
else:
\# If there are no neighbors, the similarity fraction is 0
similarity\_fraction \= 0.0
\# Move if unhappy
if similarity\_fraction < self.homophily:
self.cell \= self.model.grid.select\_random\_empty\_cell()
else:
self.model.happy += 1
Model[#](#model "Link to this heading")
----------------------------------------
from mesa import Model
from mesa.datacollection import DataCollector
from mesa.discrete\_space import OrthogonalMooreGrid
from mesa.examples.basic.schelling.agents import SchellingAgent
class Schelling(Model):
"""Model class for the Schelling segregation model."""
def \_\_init\_\_(
self,
height: int \= 20,
width: int \= 20,
density: float \= 0.8,
minority\_pc: float \= 0.5,
homophily: float \= 0.4,
radius: int \= 1,
seed\=None,
):
"""Create a new Schelling model.
Args:
width: Width of the grid
height: Height of the grid
density: Initial chance for a cell to be populated (0-1)
minority\_pc: Chance for an agent to be in minority class (0-1)
homophily: Minimum number of similar neighbors needed for happiness
radius: Search radius for checking neighbor similarity
seed: Seed for reproducibility
"""
super().\_\_init\_\_(seed\=seed)
\# Model parameters
self.density \= density
self.minority\_pc \= minority\_pc
\# Initialize grid
self.grid \= OrthogonalMooreGrid((width, height), random\=self.random, capacity\=1)
\# Track happiness
self.happy \= 0
\# Set up data collection
self.datacollector \= DataCollector(
model\_reporters\={
"happy": "happy",
"pct\_happy": lambda m: (m.happy / len(m.agents)) \* 100
if len(m.agents) \> 0
else 0,
"population": lambda m: len(m.agents),
"minority\_pct": lambda m: (
sum(1 for agent in m.agents if agent.type \== 1)
/ len(m.agents)
\* 100
if len(m.agents) \> 0
else 0
),
},
agent\_reporters\={"agent\_type": "type"},
)
\# Create agents and place them on the grid
for cell in self.grid.all\_cells:
if self.random.random() < self.density:
agent\_type \= 1 if self.random.random() < minority\_pc else 0
SchellingAgent(
self, cell, agent\_type, homophily\=homophily, radius\=radius
)
\# Collect initial state
self.datacollector.collect(self)
def step(self):
"""Run one step of the model."""
self.happy \= 0 \# Reset counter of happy agents
self.agents.shuffle\_do("step") \# Activate all agents in random order
self.datacollector.collect(self) \# Collect data
self.running \= self.happy < len(self.agents) \# Continue until everyone is happy
App[#](#app "Link to this heading")
------------------------------------
import solara
from mesa.examples.basic.schelling.model import Schelling
from mesa.visualization import (
Slider,
SolaraViz,
make\_plot\_component,
make\_space\_component,
)
def get\_happy\_agents(model):
"""Display a text count of how many happy agents there are."""
return solara.Markdown(f"\*\*Happy agents: {model.happy}\*\*")
def agent\_portrayal(agent):
return {"color": "tab:orange" if agent.type \== 0 else "tab:blue"}
model\_params \= {
"seed": {
"type": "InputText",
"value": 42,
"label": "Random Seed",
},
"density": Slider("Agent density", 0.8, 0.1, 1.0, 0.1),
"minority\_pc": Slider("Fraction minority", 0.2, 0.0, 1.0, 0.05),
"homophily": Slider("Homophily", 0.4, 0.0, 1.0, 0.125),
"width": 20,
"height": 20,
}
model1 \= Schelling()
HappyPlot \= make\_plot\_component({"happy": "tab:green"})
page \= SolaraViz(
model1,
components\=\[\
make\_space\_component(agent\_portrayal),\
HappyPlot,\
get\_happy\_agents,\
\],
model\_params\=model\_params,
)
page \# noqa
On this page
### This Page
* [Show Source](../../_sources/examples/basic/schelling.md.txt)
---
# Boids Flockers — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Boids Flockers[#](#boids-flockers "Link to this heading")
==========================================================
Summary[#](#summary "Link to this heading")
--------------------------------------------
An implementation of Craig Reynolds’s Boids flocker model. Agents (simulated birds) try to fly towards the average position of their neighbors and in the same direction as them, while maintaining a minimum distance. This produces flocking behavior.
This model tests Mesa’s continuous space feature, and uses numpy arrays to represent vectors.
How to Run[#](#how-to-run "Link to this heading")
--------------------------------------------------
* To launch the visualization interactively, run `solara run app.py` in this directory.It will automatically open a browser page.
Files[#](#files "Link to this heading")
----------------------------------------
* [model.py](#model.py)
: Ccntains the Boid Model
* [agents.py](#agents.py)
: Contains the Boid agent
* [app.py](#app.py)
: Solara based Visualization code.
Further Reading[#](#further-reading "Link to this heading")
------------------------------------------------------------
The following link can be visited for more information on the boid flockers model: https://cs.stanford.edu/people/eroberts/courses/soco/projects/2008-09/modeling-natural-systems/boids.html
Agents[#](#agents "Link to this heading")
------------------------------------------
"""A Boid (bird-oid) agent for implementing Craig Reynolds's Boids flocking model.
This implementation uses numpy arrays to represent vectors for efficient computation
of flocking behavior.
"""
import numpy as np
from mesa.experimental.continuous\_space import ContinuousSpaceAgent
class Boid(ContinuousSpaceAgent):
"""A Boid-style flocker agent.
The agent follows three behaviors to flock:
- Cohesion: steering towards neighboring agents
- Separation: avoiding getting too close to any other agent
- Alignment: trying to fly in the same direction as neighbors
Boids have a vision that defines the radius in which they look for their
neighbors to flock with. Their speed (a scalar) and direction (a vector)
define their movement. Separation is their desired minimum distance from
any other Boid.
"""
def \_\_init\_\_(
self,
model,
space,
position\=(0, 0),
speed\=1,
direction\=(1, 1),
vision\=1,
separation\=1,
cohere\=0.03,
separate\=0.015,
match\=0.05,
):
"""Create a new Boid flocker agent.
Args:
model: Model instance the agent belongs to
speed: Distance to move per step
direction: numpy vector for the Boid's direction of movement
vision: Radius to look around for nearby Boids
separation: Minimum distance to maintain from other Boids
cohere: Relative importance of matching neighbors' positions (default: 0.03)
separate: Relative importance of avoiding close neighbors (default: 0.015)
match: Relative importance of matching neighbors' directions (default: 0.05)
"""
super().\_\_init\_\_(space, model)
self.position \= position
self.speed \= speed
self.direction \= direction
self.vision \= vision
self.separation \= separation
self.cohere\_factor \= cohere
self.separate\_factor \= separate
self.match\_factor \= match
self.neighbors \= \[\]
self.angle \= 0.0 \# represents the angle at which the boid is moving
def step(self):
"""Get the Boid's neighbors, compute the new vector, and move accordingly."""
neighbors, distances \= self.get\_neighbors\_in\_radius(radius\=self.vision)
self.neighbors \= \[n for n in neighbors if n is not self\]
\# If no neighbors, maintain current direction
if not neighbors:
self.position += self.direction \* self.speed
return
delta \= self.space.calculate\_difference\_vector(self.position, agents\=neighbors)
cohere\_vector \= delta.sum(axis\=0) \* self.cohere\_factor
separation\_vector \= (
\-1 \* delta\[distances < self.separation\].sum(axis\=0) \* self.separate\_factor
)
match\_vector \= (
np.asarray(\[n.direction for n in neighbors\]).sum(axis\=0) \* self.match\_factor
)
\# Update direction based on the three behaviors
self.direction += (cohere\_vector + separation\_vector + match\_vector) / len(
neighbors
)
\# Normalize direction vector
self.direction /= np.linalg.norm(self.direction)
\# Move boid
self.position += self.direction \* self.speed
Model[#](#model "Link to this heading")
----------------------------------------
"""
Boids Flocking Model
\===================
A Mesa implementation of Craig Reynolds's Boids flocker model.
Uses numpy arrays to represent vectors.
"""
import os
import sys
sys.path.insert(0, os.path.abspath("../../../.."))
import numpy as np
from mesa import Model
from mesa.examples.basic.boid\_flockers.agents import Boid
from mesa.experimental.continuous\_space import ContinuousSpace
class BoidFlockers(Model):
"""Flocker model class. Handles agent creation, placement and scheduling."""
def \_\_init\_\_(
self,
population\_size\=100,
width\=100,
height\=100,
speed\=1,
vision\=10,
separation\=2,
cohere\=0.03,
separate\=0.015,
match\=0.05,
seed\=None,
):
"""Create a new Boids Flocking model.
Args:
population\_size: Number of Boids in the simulation (default: 100)
width: Width of the space (default: 100)
height: Height of the space (default: 100)
speed: How fast the Boids move (default: 1)
vision: How far each Boid can see (default: 10)
separation: Minimum distance between Boids (default: 2)
cohere: Weight of cohesion behavior (default: 0.03)
separate: Weight of separation behavior (default: 0.015)
match: Weight of alignment behavior (default: 0.05)
seed: Random seed for reproducibility (default: None)
"""
super().\_\_init\_\_(seed\=seed)
self.agent\_angles \= np.zeros(
population\_size
) \# holds the angle representing the direction of all agents at a given step
\# Set up the space
self.space \= ContinuousSpace(
\[\[0, width\], \[0, height\]\],
torus\=True,
random\=self.random,
n\_agents\=population\_size,
)
\# Create and place the Boid agents
positions \= self.rng.random(size\=(population\_size, 2)) \* self.space.size
directions \= self.rng.uniform(\-1, 1, size\=(population\_size, 2))
Boid.create\_agents(
self,
population\_size,
self.space,
position\=positions,
direction\=directions,
cohere\=cohere,
separate\=separate,
match\=match,
speed\=speed,
vision\=vision,
separation\=separation,
)
\# For tracking statistics
self.average\_heading \= None
self.update\_average\_heading()
\# vectorizing the calculation of angles for all agents
def calculate\_angles(self):
d1 \= np.array(\[agent.direction\[0\] for agent in self.agents\])
d2 \= np.array(\[agent.direction\[1\] for agent in self.agents\])
self.agent\_angles \= np.degrees(np.arctan2(d1, d2))
for agent, angle in zip(self.agents, self.agent\_angles):
agent.angle \= angle
def update\_average\_heading(self):
"""Calculate the average heading (direction) of all Boids."""
if not self.agents:
self.average\_heading \= 0
return
headings \= np.array(\[agent.direction for agent in self.agents\])
mean\_heading \= np.mean(headings, axis\=0)
self.average\_heading \= np.arctan2(mean\_heading\[1\], mean\_heading\[0\])
def step(self):
"""Run one step of the model.
All agents are activated in random order using the AgentSet shuffle\_do method.
"""
self.agents.shuffle\_do("step")
self.update\_average\_heading()
self.calculate\_angles()
App[#](#app "Link to this heading")
------------------------------------
import os
import sys
from matplotlib.markers import MarkerStyle
sys.path.insert(0, os.path.abspath("../../../.."))
from mesa.examples.basic.boid\_flockers.model import BoidFlockers
from mesa.visualization import Slider, SolaraViz, make\_space\_component
\# Pre-compute markers for different angles (e.g., every 10 degrees)
MARKER\_CACHE \= {}
for angle in range(0, 360, 10):
marker \= MarkerStyle(10)
marker.\_transform \= marker.get\_transform().rotate\_deg(angle)
MARKER\_CACHE\[angle\] \= marker
def boid\_draw(agent):
neighbors \= len(agent.neighbors)
\# Calculate the angle
deg \= agent.angle
\# Round to nearest 10 degrees
rounded\_deg \= round(deg / 10) \* 10 % 360
\# using cached markers to speed things up
if neighbors <= 1:
return {"color": "red", "size": 20, "marker": MARKER\_CACHE\[rounded\_deg\]}
elif neighbors \>= 2:
return {"color": "green", "size": 20, "marker": MARKER\_CACHE\[rounded\_deg\]}
model\_params \= {
"seed": {
"type": "InputText",
"value": 42,
"label": "Random Seed",
},
"population\_size": Slider(
label\="Number of boids",
value\=100,
min\=10,
max\=200,
step\=10,
),
"width": 100,
"height": 100,
"speed": Slider(
label\="Speed of Boids",
value\=5,
min\=1,
max\=20,
step\=1,
),
"vision": Slider(
label\="Vision of Bird (radius)",
value\=10,
min\=1,
max\=50,
step\=1,
),
"separation": Slider(
label\="Minimum Separation",
value\=2,
min\=1,
max\=20,
step\=1,
),
}
model \= BoidFlockers()
page \= SolaraViz(
model,
components\=\[make\_space\_component(agent\_portrayal\=boid\_draw, backend\="matplotlib")\],
model\_params\=model\_params,
name\="Boid Flocking Model",
)
page \# noqa
On this page
### This Page
* [Show Source](../../_sources/examples/basic/boid_flockers.md.txt)
---
# Virus on a Network — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Virus on a Network[#](#virus-on-a-network "Link to this heading")
==================================================================
Summary[#](#summary "Link to this heading")
--------------------------------------------
This model is based on the NetLogo model “Virus on Network”. It demonstrates the spread of a virus through a network and follows the SIR model, commonly seen in epidemiology.
The SIR model is one of the simplest compartmental models, and many models are derivatives of this basic form. The model consists of three compartments:
S: The number of susceptible individuals. When a susceptible and an infectious individual come into “infectious contact”, the susceptible individual contracts the disease and transitions to the infectious compartment. I: The number of infectious individuals. These are individuals who have been infected and are capable of infecting susceptible individuals. R for the number of removed (and immune) or deceased individuals. These are individuals who have been infected and have either recovered from the disease and entered the removed compartment, or died. It is assumed that the number of deaths is negligible with respect to the total population. This compartment may also be called “recovered” or “resistant”.
For more information about this model, read the NetLogo’s web page: http://ccl.northwestern.edu/netlogo/models/VirusonaNetwork.
JavaScript library used in this example to render the network: [d3.js](https://d3js.org/)
.
Installation[#](#installation "Link to this heading")
------------------------------------------------------
To install the dependencies use pip and the requirements.txt in this directory. e.g.
$ pip install -r requirements.txt
How to Run[#](#how-to-run "Link to this heading")
--------------------------------------------------
To run the model interactively, in this directory, run the following command
$ solara run app.py
Files[#](#files "Link to this heading")
----------------------------------------
* `model.py`: Contains the agent class, and the overall model class.
* `agents.py`: Contains the agent class.
* `app.py`: Contains the code for the interactive Solara visualization.
Further Reading[#](#further-reading "Link to this heading")
------------------------------------------------------------
The full tutorial describing how the model is built can be found at: https://mesa.readthedocs.io/en/latest/tutorials/intro\_tutorial.html
[Stonedahl, F. and Wilensky, U. (2008). NetLogo Virus on a Network model](http://ccl.northwestern.edu/netlogo/models/VirusonaNetwork)
. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
[Wilensky, U. (1999). NetLogo](http://ccl.northwestern.edu/netlogo/)
Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
Agents[#](#agents "Link to this heading")
------------------------------------------
from enum import Enum
from mesa.discrete\_space import FixedAgent
class State(Enum):
SUSCEPTIBLE \= 0
INFECTED \= 1
RESISTANT \= 2
class VirusAgent(FixedAgent):
"""Individual Agent definition and its properties/interaction methods."""
def \_\_init\_\_(
self,
model,
initial\_state,
virus\_spread\_chance,
virus\_check\_frequency,
recovery\_chance,
gain\_resistance\_chance,
cell,
):
super().\_\_init\_\_(model)
self.state \= initial\_state
self.virus\_spread\_chance \= virus\_spread\_chance
self.virus\_check\_frequency \= virus\_check\_frequency
self.recovery\_chance \= recovery\_chance
self.gain\_resistance\_chance \= gain\_resistance\_chance
self.cell \= cell
def try\_to\_infect\_neighbors(self):
for agent in self.cell.neighborhood.agents:
if (agent.state is State.SUSCEPTIBLE) and (
self.random.random() < self.virus\_spread\_chance
):
agent.state \= State.INFECTED
def try\_gain\_resistance(self):
if self.random.random() < self.gain\_resistance\_chance:
self.state \= State.RESISTANT
def try\_remove\_infection(self):
\# Try to remove
if self.random.random() < self.recovery\_chance:
\# Success
self.state \= State.SUSCEPTIBLE
self.try\_gain\_resistance()
else:
\# Failed
self.state \= State.INFECTED
def check\_situation(self):
if (self.state is State.INFECTED) and (
self.random.random() < self.virus\_check\_frequency
):
self.try\_remove\_infection()
def step(self):
if self.state is State.INFECTED:
self.try\_to\_infect\_neighbors()
self.check\_situation()
Model[#](#model "Link to this heading")
----------------------------------------
import math
import networkx as nx
import mesa
from mesa import Model
from mesa.discrete\_space import CellCollection, Network
from mesa.examples.basic.virus\_on\_network.agents import State, VirusAgent
def number\_state(model, state):
return sum(1 for a in model.grid.all\_cells.agents if a.state is state)
def number\_infected(model):
return number\_state(model, State.INFECTED)
def number\_susceptible(model):
return number\_state(model, State.SUSCEPTIBLE)
def number\_resistant(model):
return number\_state(model, State.RESISTANT)
class VirusOnNetwork(Model):
"""A virus model with some number of agents."""
def \_\_init\_\_(
self,
num\_nodes\=10,
avg\_node\_degree\=3,
initial\_outbreak\_size\=1,
virus\_spread\_chance\=0.4,
virus\_check\_frequency\=0.4,
recovery\_chance\=0.3,
gain\_resistance\_chance\=0.5,
seed\=None,
):
super().\_\_init\_\_(seed\=seed)
prob \= avg\_node\_degree / num\_nodes
graph \= nx.erdos\_renyi\_graph(n\=num\_nodes, p\=prob)
self.grid \= Network(graph, capacity\=1, random\=self.random)
self.initial\_outbreak\_size \= (
initial\_outbreak\_size if initial\_outbreak\_size <= num\_nodes else num\_nodes
)
self.datacollector \= mesa.DataCollector(
{
"Infected": number\_infected,
"Susceptible": number\_susceptible,
"Resistant": number\_resistant,
"R over S": self.resistant\_susceptible\_ratio,
}
)
VirusAgent.create\_agents(
self,
num\_nodes,
State.SUSCEPTIBLE,
virus\_spread\_chance,
virus\_check\_frequency,
recovery\_chance,
gain\_resistance\_chance,
list(self.grid.all\_cells),
)
\# Infect some nodes
infected\_nodes \= CellCollection(
self.random.sample(list(self.grid.all\_cells), self.initial\_outbreak\_size),
random\=self.random,
)
for a in infected\_nodes.agents:
a.state \= State.INFECTED
self.running \= True
self.datacollector.collect(self)
def resistant\_susceptible\_ratio(self):
try:
return number\_state(self, State.RESISTANT) / number\_state(
self, State.SUSCEPTIBLE
)
except ZeroDivisionError:
return math.inf
def step(self):
self.agents.shuffle\_do("step")
\# collect data
self.datacollector.collect(self)
App[#](#app "Link to this heading")
------------------------------------
import math
import solara
from mesa.examples.basic.virus\_on\_network.model import (
State,
VirusOnNetwork,
number\_infected,
)
from mesa.visualization import (
Slider,
SolaraViz,
make\_plot\_component,
make\_space\_component,
)
def agent\_portrayal(agent):
node\_color\_dict \= {
State.INFECTED: "tab:red",
State.SUSCEPTIBLE: "tab:green",
State.RESISTANT: "tab:gray",
}
return {"color": node\_color\_dict\[agent.state\], "size": 10}
def get\_resistant\_susceptible\_ratio(model):
ratio \= model.resistant\_susceptible\_ratio()
ratio\_text \= r"$\\infty$" if ratio is math.inf else f"{ratio:.2f}"
infected\_text \= str(number\_infected(model))
return solara.Markdown(
f"Resistant/Susceptible Ratio: {ratio\_text}
Infected Remaining: {infected\_text}"
)
model\_params \= {
"seed": {
"type": "InputText",
"value": 42,
"label": "Random Seed",
},
"num\_nodes": Slider(
label\="Number of agents",
value\=10,
min\=10,
max\=100,
step\=1,
),
"avg\_node\_degree": Slider(
label\="Avg Node Degree",
value\=3,
min\=3,
max\=8,
step\=1,
),
"initial\_outbreak\_size": Slider(
label\="Initial Outbreak Size",
value\=1,
min\=1,
max\=10,
step\=1,
),
"virus\_spread\_chance": Slider(
label\="Virus Spread Chance",
value\=0.4,
min\=0.0,
max\=1.0,
step\=0.1,
),
"virus\_check\_frequency": Slider(
label\="Virus Check Frequency",
value\=0.4,
min\=0.0,
max\=1.0,
step\=0.1,
),
"recovery\_chance": Slider(
label\="Recovery Chance",
value\=0.3,
min\=0.0,
max\=1.0,
step\=0.1,
),
"gain\_resistance\_chance": Slider(
label\="Gain Resistance Chance",
value\=0.5,
min\=0.0,
max\=1.0,
step\=0.1,
),
}
def post\_process\_lineplot(ax):
ax.set\_ylim(ymin\=0)
ax.set\_ylabel("# people")
ax.legend(bbox\_to\_anchor\=(1.05, 1.0), loc\="upper left")
SpacePlot \= make\_space\_component(agent\_portrayal)
StatePlot \= make\_plot\_component(
{"Infected": "tab:red", "Susceptible": "tab:green", "Resistant": "tab:gray"},
post\_process\=post\_process\_lineplot,
)
model1 \= VirusOnNetwork()
page \= SolaraViz(
model1,
components\=\[\
SpacePlot,\
StatePlot,\
get\_resistant\_susceptible\_ratio,\
\],
model\_params\=model\_params,
name\="Virus Model",
)
page \# noqa
On this page
### This Page
* [Show Source](../../_sources/examples/basic/virus_on_network.md.txt)
---
# Boltzmann Wealth Model (Tutorial) — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Boltzmann Wealth Model (Tutorial)[#](#boltzmann-wealth-model-tutorial "Link to this heading")
==============================================================================================
Summary[#](#summary "Link to this heading")
--------------------------------------------
A simple model of agents exchanging wealth. All agents start with the same amount of money. Every step, each agent with one unit of money or more gives one unit of wealth to another random agent. This is the model described in the [Intro Tutorial](https://mesa.readthedocs.io/en/latest/tutorials/intro_tutorial.html)
, with the completed code.
If you want to go over the step-by-step tutorial, please go and run the [Jupyter Notebook](https://github.com/projectmesa/mesa/blob/main/docs/tutorials/intro_tutorial.ipynb)
. The code here runs the finalized code in the last cells directly.
As the model runs, the distribution of wealth among agents goes from being perfectly uniform (all agents have the same starting wealth), to highly skewed – a small number have high wealth, more have none at all.
How to Run[#](#how-to-run "Link to this heading")
--------------------------------------------------
To follow the tutorial example, launch the Jupyter Notebook and run the code in `Introduction to Mesa Tutorial Code.ipynb` which you can find in the main mesa repo [here](https://github.com/projectmesa/mesa/blob/main/docs/tutorials/intro_tutorial.ipynb)
To launch the interactive server, as described in the [last section of the tutorial](https://mesa.readthedocs.io/en/latest/tutorials/intro_tutorial.html#adding-visualization)
, run:
$ solara run app.py
If your browser doesn’t open automatically, point it to [http://127.0.0.1:8765/](http://127.0.0.1:8765/)
. When the visualization loads, click on the Play button.
Files[#](#files "Link to this heading")
----------------------------------------
* `model.py`: Final version of the model.
* `agents.py`: Final version of the agent.
* `app.py`: Code for the interactive visualization.
Optional[#](#optional "Link to this heading")
----------------------------------------------
An optional visualization is also provided using Streamlit, which is another popular Python library for creating interactive web applications.
To run the Streamlit app, you will need to install the `streamlit` and `altair` libraries:
$ pip install streamlit altair
Then, you can run the Streamlit app using the following command:
$ streamlit run st\_app.py
Further Reading[#](#further-reading "Link to this heading")
------------------------------------------------------------
The full tutorial describing how the model is built can be found at: https://mesa.readthedocs.io/en/latest/tutorials/intro\_tutorial.html
This model is drawn from econophysics and presents a statistical mechanics approach to wealth distribution. Some examples of further reading on the topic can be found at:
[Milakovic, M. A Statistical Equilibrium Model of Wealth Distribution. February, 2001.](https://editorialexpress.com/cgi-bin/conference/download.cgi?db_name=SCE2001&paper_id=214)
[Dragulescu, A and Yakovenko, V. Statistical Mechanics of Money, Income, and Wealth: A Short Survey. November, 2002](http://arxiv.org/pdf/cond-mat/0211175v1.pdf)
Agents[#](#agents "Link to this heading")
------------------------------------------
from mesa.discrete\_space import CellAgent
class MoneyAgent(CellAgent):
"""An agent with fixed initial wealth.
Each agent starts with 1 unit of wealth and can give 1 unit to other agents
if they occupy the same cell.
Attributes:
wealth (int): The agent's current wealth (starts at 1)
"""
def \_\_init\_\_(self, model, cell):
"""Create a new agent.
Args:
model (Model): The model instance that contains the agent
"""
super().\_\_init\_\_(model)
self.cell \= cell
self.wealth \= 1
def move(self):
"""Move the agent to a random neighboring cell."""
self.cell \= self.cell.neighborhood.select\_random\_cell()
def give\_money(self):
"""Give 1 unit of wealth to a random agent in the same cell."""
cellmates \= \[a for a in self.cell.agents if a is not self\]
if cellmates: \# Only give money if there are other agents present
other \= self.random.choice(cellmates)
other.wealth += 1
self.wealth \-= 1
def step(self):
"""Execute one step for the agent:
1. Move to a neighboring cell
2. If wealth > 0, maybe give money to another agent in the same cell
"""
self.move()
if self.wealth \> 0:
self.give\_money()
Model[#](#model "Link to this heading")
----------------------------------------
"""
Boltzmann Wealth Model
\=====================
A simple model of wealth distribution based on the Boltzmann-Gibbs distribution.
Agents move randomly on a grid, giving one unit of wealth to a random neighbor
when they occupy the same cell.
"""
from mesa import Model
from mesa.datacollection import DataCollector
from mesa.discrete\_space import OrthogonalMooreGrid
from mesa.examples.basic.boltzmann\_wealth\_model.agents import MoneyAgent
class BoltzmannWealth(Model):
"""A simple model of an economy where agents exchange currency at random.
All agents begin with one unit of currency, and each time step agents can give
a unit of currency to another agent in the same cell. Over time, this produces
a highly skewed distribution of wealth.
Attributes:
num\_agents (int): Number of agents in the model
grid (MultiGrid): The space in which agents move
running (bool): Whether the model should continue running
datacollector (DataCollector): Collects and stores model data
"""
def \_\_init\_\_(self, n\=100, width\=10, height\=10, seed\=None):
"""Initialize the model.
Args:
n (int, optional): Number of agents. Defaults to 100.
width (int, optional): Grid width. Defaults to 10.
height (int, optional): Grid height. Defaults to 10.
seed (int, optional): Random seed. Defaults to None.
"""
super().\_\_init\_\_(seed\=seed)
self.num\_agents \= n
self.grid \= OrthogonalMooreGrid((width, height), random\=self.random)
\# Set up data collection
self.datacollector \= DataCollector(
model\_reporters\={"Gini": self.compute\_gini},
agent\_reporters\={"Wealth": "wealth"},
)
MoneyAgent.create\_agents(
self,
self.num\_agents,
self.random.choices(self.grid.all\_cells.cells, k\=self.num\_agents),
)
self.running \= True
self.datacollector.collect(self)
def step(self):
self.agents.shuffle\_do("step") \# Activate all agents in random order
self.datacollector.collect(self) \# Collect data
def compute\_gini(self):
"""Calculate the Gini coefficient for the model's current wealth distribution.
The Gini coefficient is a measure of inequality in distributions.
- A Gini of 0 represents complete equality, where all agents have equal wealth.
- A Gini of 1 represents maximal inequality, where one agent has all wealth.
"""
agent\_wealths \= \[agent.wealth for agent in self.agents\]
x \= sorted(agent\_wealths)
n \= self.num\_agents
\# Calculate using the standard formula for Gini coefficient
b \= sum(xi \* (n \- i) for i, xi in enumerate(x)) / (n \* sum(x))
return 1 + (1 / n) \- 2 \* b
App[#](#app "Link to this heading")
------------------------------------
from mesa.examples.basic.boltzmann\_wealth\_model.model import BoltzmannWealth
from mesa.mesa\_logging import INFO, log\_to\_stderr
from mesa.visualization import (
SolaraViz,
make\_plot\_component,
make\_space\_component,
)
log\_to\_stderr(INFO)
def agent\_portrayal(agent):
color \= agent.wealth \# we are using a colormap to translate wealth to color
return {"color": color}
model\_params \= {
"seed": {
"type": "InputText",
"value": 42,
"label": "Random Seed",
},
"n": {
"type": "SliderInt",
"value": 50,
"label": "Number of agents:",
"min": 10,
"max": 100,
"step": 1,
},
"width": 10,
"height": 10,
}
def post\_process(ax):
ax.get\_figure().colorbar(ax.collections\[0\], label\="wealth", ax\=ax)
\# Create initial model instance
model \= BoltzmannWealth(50, 10, 10)
\# Create visualization elements. The visualization elements are solara components
\# that receive the model instance as a "prop" and display it in a certain way.
\# Under the hood these are just classes that receive the model instance.
\# You can also author your own visualization elements, which can also be functions
\# that receive the model instance and return a valid solara component.
SpaceGraph \= make\_space\_component(
agent\_portrayal, cmap\="viridis", vmin\=0, vmax\=10, post\_process\=post\_process
)
GiniPlot \= make\_plot\_component("Gini")
\# Create the SolaraViz page. This will automatically create a server and display the
\# visualization elements in a web browser.
\# Display it using the following command in the example directory:
\# solara run app.py
\# It will automatically update and display any changes made to this file
page \= SolaraViz(
model,
components\=\[SpaceGraph, GiniPlot\],
model\_params\=model\_params,
name\="Boltzmann Wealth Model",
)
page \# noqa
\# In a notebook environment, we can also display the visualization elements directly
\# SpaceGraph(model1)
\# GiniPlot(model1)
\# The plots will be static. If you want to pick up model steps,
\# you have to make the model reactive first
\# reactive\_model = solara.reactive(model1)
\# SpaceGraph(reactive\_model)
\# In a different notebook block:
\# reactive\_model.value.step()
On this page
### This Page
* [Show Source](../../_sources/examples/basic/boltzmann_wealth_model.md.txt)
---
# Visualization - Custom Components — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Visualization - Custom Components[#](#visualization-custom-components "Link to this heading")
==============================================================================================
The Boltzmann Wealth Model[#](#the-boltzmann-wealth-model "Link to this heading")
----------------------------------------------------------------------------------
If you want to get straight to the tutorial checkout these environment providers:
[](https://mybinder.org/v2/gh/projectmesa/mesa/main?labpath=docs%2Ftutorials%2F4_visualization_basic.ipynb)
(This can take 30 seconds to 5 minutes to load)
Due to conflict with Colab and Solara there are no colab links for this tutorial
_If you are running locally, please ensure you have the latest Mesa version installed._
Tutorial Description[#](#tutorial-description "Link to this heading")
----------------------------------------------------------------------
This tutorial extends the Boltzmann wealth model from the [Visualization Basic Dashboard tutorial](https://mesa.readthedocs.io/latest/tutorials/4_visualization_basic.html)
, by adding an interactive dashboard.
In this portion, we will demonstrate how users can employ create dynamic agent representation with their Mesa dashboards. This is part two of three visualization tutorials.
_If you are starting here please see the [Running Your First Model tutorial](https://mesa.readthedocs.io/latest/tutorials/0_first_model.html)
for dependency and start-up instructions_
### Import Dependencies[#](#import-dependencies "Link to this heading")
This includes importing of dependencies needed for the tutorial.
\# Has multi-dimensional arrays and matrices.
\# Has a large collection of mathematical functions to operate on these arrays.
import numpy as np
\# Data manipulation and analysis.
import pandas as pd
\# Data visualization tools.
import seaborn as sns
import mesa
from mesa.discrete\_space import CellAgent, OrthogonalMooreGrid
from mesa.visualization import SolaraViz, make\_plot\_component, make\_space\_component
Basic Model[#](#basic-model "Link to this heading")
----------------------------------------------------
The following is the basic model we will be using to build the dashboard. This is the same model seen in tutorials 0-3.
def compute\_gini(model):
agent\_wealths \= \[agent.wealth for agent in model.agents\]
x \= sorted(agent\_wealths)
N \= model.num\_agents
B \= sum(xi \* (N \- i) for i, xi in enumerate(x)) / (N \* sum(x))
return 1 + (1 / N) \- 2 \* B
class MoneyAgent(CellAgent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model, cell):
"""initialize a MoneyAgent instance.
Args:
model: A model instance
"""
super().\_\_init\_\_(model)
self.cell \= cell
self.wealth \= 1
def move(self):
"""Move the agent to a random neighboring cell."""
self.cell \= self.cell.neighborhood.select\_random\_cell()
def give\_money(self):
"""Give 1 unit of wealth to a random agent in the same cell."""
cellmates \= \[a for a in self.cell.agents if a is not self\]
if cellmates: \# Only give money if there are other agents present
other \= self.random.choice(cellmates)
other.wealth += 1
self.wealth \-= 1
def step(self):
"""do one step of the agent."""
self.move()
if self.wealth \> 0:
self.give\_money()
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n\=10, width\=10, height\=10, seed\=None):
"""Initialize a MoneyModel instance.
Args:
N: The number of agents.
width: width of the grid.
height: Height of the grid.
"""
super().\_\_init\_\_(seed\=seed)
self.num\_agents \= n
self.grid \= OrthogonalMooreGrid((width, height), random\=self.random)
\# Create agents
MoneyAgent.create\_agents(
self,
self.num\_agents,
self.random.choices(self.grid.all\_cells.cells, k\=self.num\_agents),
)
self.datacollector \= mesa.DataCollector(
model\_reporters\={"Gini": compute\_gini}, agent\_reporters\={"Wealth": "wealth"}
)
self.datacollector.collect(self)
def step(self):
"""do one step of the model"""
self.agents.shuffle\_do("step")
self.datacollector.collect(self)
\# Lets make sure the model works
model \= MoneyModel(100, 10, 10)
for \_ in range(20):
model.step()
data \= model.datacollector.get\_agent\_vars\_dataframe()
\# Use seaborn
g \= sns.histplot(data\["Wealth"\], discrete\=True)
g.set(title\="Wealth distribution", xlabel\="Wealth", ylabel\="Number of Agents");

### Adding visualization[#](#adding-visualization "Link to this heading")
So far, we’ve built a model, run it, and analyzed some output afterwards. However, one of the advantages of agent-based models is that we can often watch them run step by step, potentially spotting unexpected patterns, behaviors or bugs, or developing new intuitions, hypotheses, or insights. Other times, watching a model run can explain it to an unfamiliar audience better than static explanations. Like many ABM frameworks, Mesa allows you to create an interactive visualization of the model. In this section we’ll walk through creating a visualization using built-in components, and (for advanced users) how to create a new visualization element.
First, a quick explanation of how Mesa’s interactive visualization works. The visualization is done in a browser window or Jupyter instance, using the [Solara](https://solara.dev/)
framework, a pure Python, React-style web framework. Running `solara run app.py` will launch a web server, which runs the model, and displays model detail at each step via a plotting library. Alternatively, you can execute everything inside a Jupyter instance and display it inline.
_Thanks to @Corvince for all his work creating Mesa’s visualization capability_
Building Custom Components[#](#building-custom-components "Link to this heading")
----------------------------------------------------------------------------------
This section is for users who have a basic familiarity with Python’s Matplotlib plotting library.
If the visualization elements provided by Mesa aren’t enough for you, you can build your own and plug them into the model server.
For this example, let’s build a simple histogram visualization, which can count the number of agents with each value of wealth.
First we need to update our imports
We use Matplotlib in this tutorial, but Mesa also has Altair. If you would like other visualization support like Plotly or Bokeh, please feel free to [contribute](https://github.com/projectmesa/mesa/blob/main/CONTRIBUTING.md)
In addition, due to the way Solara works we need to trigger an update whenever the underlying model changes. For this you need to register an update counter with every component.
import solara
from matplotlib.figure import Figure
from mesa.visualization.utils import update\_counter
Next we provide a function for our agent portrayal and our model parameters.
def agent\_portrayal(agent):
size \= 10
color \= "tab:red"
if agent.wealth \> 0:
size \= 50
color \= "tab:blue"
return {"size": size, "color": color}
model\_params \= {
"n": {
"type": "SliderInt",
"value": 50,
"label": "Number of agents:",
"min": 10,
"max": 100,
"step": 1,
},
"width": 10,
"height": 10,
}
Now we add our custom component. In this case we will build a histogram of agent wealth.
Besides the standard matplotlib code to build a histogram, please notice 3 key features.
1. `@solara.component` this is needed for any compoenent you add
2. `update_counter.get()` this is needed so solara updates the dashboard with your agent based model
3. you must initialize a `figure` using this method instead of `plt.figure()`, for thread safety purpose
@solara.component
def Histogram(model):
update\_counter.get() \# This is required to update the counter
\# Note: you must initialize a figure using this method instead of
\# plt.figure(), for thread safety purpose
fig \= Figure()
ax \= fig.subplots()
wealth\_vals \= \[agent.wealth for agent in model.agents\]
\# Note: you have to use Matplotlib's OOP API instead of plt.hist
\# because plt.hist is not thread-safe.
ax.hist(wealth\_vals, bins\=10)
solara.FigureMatplotlib(fig)
Now we create the model an initialize the visualization
\# Create initial model instance
money\_model \= MoneyModel(n\=50, width\=10, height\=10)
SpaceGraph \= make\_space\_component(agent\_portrayal)
GiniPlot \= make\_plot\_component("Gini")
page \= SolaraViz(
money\_model,
components\=\[SpaceGraph, GiniPlot, Histogram\],
model\_params\=model\_params,
name\="Boltzmann Wealth Model",
)
\# This is required to render the visualization in the Jupyter notebook
page
You can even run the visuals independently by calling it with the model instance
Histogram(money\_model)
Exercise[#](#exercise "Link to this heading")
----------------------------------------------
* Build you own custom component
Next Steps[#](#next-steps "Link to this heading")
--------------------------------------------------
Check out the next [batch run tutorial](https://mesa.readthedocs.io/latest/tutorials/7_batch_run.html)
on how to conduct parameter sweeps and run numerous iterations of your model.
\[Comer2014\] Comer, Kenneth W. “Who Goes First? An Examination of the Impact of Activation on Outcome Behavior in AgentBased Models.” George Mason University, 2014. http://mars.gmu.edu/bitstream/handle/1920/9070/Comer\_gmu\_0883E\_10539.pdf
\[Dragulescu2002\] Drăgulescu, Adrian A., and Victor M. Yakovenko. “Statistical Mechanics of Money, Income, and Wealth: A Short Survey.” arXiv Preprint Cond-mat/0211175, 2002. http://arxiv.org/abs/cond-mat/0211175.
On this page
### This Page
* [Show Source](../_sources/tutorials/6_visualization_custom.ipynb.txt)
---
# Agent — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Agent[#](#module-mesa.agent "Link to this heading")
====================================================
Agent related classes.
Core Objects: Agent and AgentSet.
_class_ Agent(_model: [Model](../mesa.html#mesa.model.Model "mesa.model.Model")
_, _\*args_, _\*\*kwargs_)[\[source\]](../_modules/mesa/agent.html#Agent)
[#](#mesa.agent.Agent "Link to this definition")
Base class for a model agent in Mesa.
model[#](#mesa.agent.Agent.model "Link to this definition")
A reference to the model instance.
Type:
[Model](../mesa.html#mesa.model.Model "mesa.model.Model")
unique\_id[#](#mesa.agent.Agent.unique_id "Link to this definition")
A unique identifier for this agent.
Type:
[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
pos[#](#mesa.agent.Agent.pos "Link to this definition")
A reference to the position where this agent is located.
Type:
Position
Notes
unique\_id is unique relative to a model instance and starts from 1
Create a new agent.
Parameters:
* **model** ([_Model_](../mesa.html#mesa.model.Model "mesa.model.Model")
) – The model instance in which the agent exists.
* **args** – passed on to super
* **kwargs** – passed on to super
Notes
to make proper use of python’s super, in each class remove the arguments and keyword arguments you need and pass on the rest to super
remove() → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/agent.html#Agent.remove)
[#](#mesa.agent.Agent.remove "Link to this definition")
Remove and delete the agent from the model.
Notes
If you need to do additional cleanup when removing an agent by for example removing it from a space, consider extending this method in your own agent class.
step() → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/agent.html#Agent.step)
[#](#mesa.agent.Agent.step "Link to this definition")
A single step of the agent.
_classmethod_ create\_agents(_model: [Model](../mesa.html#mesa.model.Model "mesa.model.Model")
_, _n: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_, _\*args_, _\*\*kwargs_) → [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\][\[source\]](../_modules/mesa/agent.html#Agent.create_agents)
[#](#mesa.agent.Agent.create_agents "Link to this definition")
Create N agents.
Parameters:
* **model** – the model to which the agents belong
* **args** – arguments to pass onto agent instances each arg is either a single object or a sequence of length n
* **n** – the number of agents to create
* **kwargs** – keyword arguments to pass onto agent instances each keyword arg is either a single object or a sequence of length n
Returns:
AgentSet containing the agents created.
_property_ random_: [Random](https://docs.python.org/3/library/random.html#random.Random "(in Python v3.13)")
_[#](#mesa.agent.Agent.random "Link to this definition")
Return a seeded stdlib rng.
_property_ rng_: Generator_[#](#mesa.agent.Agent.rng "Link to this definition")
Return a seeded np.random rng.
_class_ AgentSet(_agents: [Iterable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable "(in Python v3.13)")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\]_, _random: [Random](https://docs.python.org/3/library/random.html#random.Random "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_)[\[source\]](../_modules/mesa/agent.html#AgentSet)
[#](#mesa.agent.AgentSet "Link to this definition")
A collection class that represents an ordered set of agents within an agent-based model (ABM).
This class extends both MutableSet and Sequence, providing set-like functionality with order preservation and sequence operations.
model[#](#mesa.agent.AgentSet.model "Link to this definition")
The ABM model instance to which this AgentSet belongs.
Type:
[Model](../mesa.html#mesa.model.Model "mesa.model.Model")
Notes
The AgentSet maintains weak references to agents, allowing for efficient management of agent lifecycles without preventing garbage collection. It is associated with a specific model instance, enabling interactions with the model’s environment and other agents.The implementation uses a WeakKeyDictionary to store agents, which means that agents not referenced elsewhere in the program may be automatically removed from the AgentSet.
Notes
A UserWarning is issued if random=None. You can resolve this warning by explicitly passing a random number generator. In most cases, this will be the seeded random number generator in the model. So, you would do random=self.random in a Model or Agent instance.
Initializes the AgentSet with a collection of agents and a reference to the model.
Parameters:
* **agents** (_Iterable__\[_[_Agent_](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
_\]_) – An iterable of Agent objects to be included in the set.
* **random** (_Random_) – the random number generator
select(_filter\_func: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
\[\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\], [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")\
\] | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _at\_most: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
\= inf_, _inplace: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _agent\_type: [type](https://docs.python.org/3/library/functions.html#type "(in Python v3.13)")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\] | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_) → [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
[\[source\]](../_modules/mesa/agent.html#AgentSet.select)
[#](#mesa.agent.AgentSet.select "Link to this definition")
Select a subset of agents from the AgentSet based on a filter function and/or quantity limit.
Parameters:
* **filter\_func** (_Callable__\[__\[_[_Agent_](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
_\]__,_ [_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")\
_\]__,_ _optional_) – A function that takes an Agent and returns True if the agent should be included in the result. Defaults to None, meaning no filtering is applied.
* **at\_most** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_|_ [_float_](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
_,_ _optional_) – The maximum amount of agents to select. Defaults to infinity. - If an integer, at most the first number of matching agents are selected. - If a float between 0 and 1, at most that fraction of original the agents are selected.
* **inplace** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_,_ _optional_) – If True, modifies the current AgentSet; otherwise, returns a new AgentSet. Defaults to False.
* **agent\_type** ([_type_](https://docs.python.org/3/library/functions.html#type "(in Python v3.13)")
_\[_[_Agent_](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
_\]__,_ _optional_) – The class type of the agents to select. Defaults to None, meaning no type filtering is applied.
Returns:
A new AgentSet containing the selected agents, unless inplace is True, in which case the current AgentSet is updated.
Return type:
[AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
Notes
* at\_most just return the first n or fraction of agents. To take a random sample, shuffle() beforehand.
* at\_most is an upper limit. When specifying other criteria, the number of agents returned can be smaller.
shuffle(_inplace: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_) → [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
[\[source\]](../_modules/mesa/agent.html#AgentSet.shuffle)
[#](#mesa.agent.AgentSet.shuffle "Link to this definition")
Randomly shuffle the order of agents in the AgentSet.
Parameters:
**inplace** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_,_ _optional_) – If True, shuffles the agents in the current AgentSet; otherwise, returns a new shuffled AgentSet. Defaults to False.
Returns:
A shuffled AgentSet. Returns the current AgentSet if inplace is True.
Return type:
[AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
Note
Using inplace = True is more performant
sort(_key: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
\[\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\], [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\] | [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _ascending: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _inplace: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_) → [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
[\[source\]](../_modules/mesa/agent.html#AgentSet.sort)
[#](#mesa.agent.AgentSet.sort "Link to this definition")
Sort the agents in the AgentSet based on a specified attribute or custom function.
Parameters:
* **key** (_Callable__\[__\[_[_Agent_](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
_\]__,_ _Any__\]_ _|_ [_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
) – A function or attribute name based on which the agents are sorted.
* **ascending** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_,_ _optional_) – If True, the agents are sorted in ascending order. Defaults to False.
* **inplace** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_,_ _optional_) – If True, sorts the agents in the current AgentSet; otherwise, returns a new sorted AgentSet. Defaults to False.
Returns:
A sorted AgentSet. Returns the current AgentSet if inplace is True.
Return type:
[AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
do(_method: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
| [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_, _\*args_, _\*\*kwargs_) → [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
[\[source\]](../_modules/mesa/agent.html#AgentSet.do)
[#](#mesa.agent.AgentSet.do "Link to this definition")
Invoke a method or function on each agent in the AgentSet.
Parameters:
* **method** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_,_ _callable_) –
the callable to do on each agent
* in case of str, the name of the method to call on each agent.
* in case of callable, the function to be called with each agent as first argument
* **\*args** – Variable length argument list passed to the callable being called.
* **\*\*kwargs** – Arbitrary keyword arguments passed to the callable being called.
Returns:
The results of the callable calls if return\_results is True, otherwise the AgentSet itself.
Return type:
[AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
| [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[Any\]
shuffle\_do(_method: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
| [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_, _\*args_, _\*\*kwargs_) → [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
[\[source\]](../_modules/mesa/agent.html#AgentSet.shuffle_do)
[#](#mesa.agent.AgentSet.shuffle_do "Link to this definition")
Shuffle the agents in the AgentSet and then invoke a method or function on each agent.
It’s a fast, optimized version of calling shuffle() followed by do().
map(_method: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
| [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_, _\*args_, _\*\*kwargs_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\][\[source\]](../_modules/mesa/agent.html#AgentSet.map)
[#](#mesa.agent.AgentSet.map "Link to this definition")
Invoke a method or function on each agent in the AgentSet and return the results.
Parameters:
* **method** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_,_ _callable_) –
the callable to apply on each agent
* in case of str, the name of the method to call on each agent.
* in case of callable, the function to be called with each agent as first argument
* **\*args** – Variable length argument list passed to the callable being called.
* **\*\*kwargs** – Arbitrary keyword arguments passed to the callable being called.
Returns:
The results of the callable calls
Return type:
[list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[Any\]
agg(_attribute: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _func: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_) → [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")
[\[source\]](../_modules/mesa/agent.html#AgentSet.agg)
[#](#mesa.agent.AgentSet.agg "Link to this definition")
Aggregate an attribute of all agents in the AgentSet using a specified function.
Parameters:
* **attribute** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
) – The name of the attribute to aggregate.
* **func** (_Callable_) – The function to apply to the attribute values (e.g., min, max, sum, np.mean).
Returns:
The result of applying the function to the attribute values. Often a single value.
Return type:
Any
get(_attr\_names: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _handle\_missing: [Literal](https://docs.python.org/3/library/typing.html#typing.Literal "(in Python v3.13)")
\['error', 'default'\] \= 'error'_, _default\_value: [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")
\= None_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\][\[source\]](../_modules/mesa/agent.html#AgentSet.get)
[#](#mesa.agent.AgentSet.get "Link to this definition")
get(_attr\_names: [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
\]_, _handle\_missing: [Literal](https://docs.python.org/3/library/typing.html#typing.Literal "(in Python v3.13)")
\['error', 'default'\] \= 'error'_, _default\_value: [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")
\= None_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")\
\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\]\]
Retrieve the specified attribute(s) from each agent in the AgentSet.
Parameters:
* **attr\_names** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_|_ [_list_](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
_\[_[_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
_\]_) – The name(s) of the attribute(s) to retrieve from each agent.
* **handle\_missing** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_,_ _optional_) – How to handle missing attributes. Can be: - ‘error’ (default): raises an AttributeError if attribute is missing. - ‘default’: returns the specified default\_value.
* **default\_value** (_Any__,_ _optional_) – The default value to return if ‘handle\_missing’ is set to ‘default’ and the agent does not have the attribute.
Returns:
A list with the attribute value for each agent if attr\_names is a str. list\[list\[Any\]\]: A list with a lists of attribute values for each agent if attr\_names is a list of str.
Return type:
[list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[Any\]
Raises:
* [**AttributeError**](https://docs.python.org/3/library/exceptions.html#AttributeError "(in Python v3.13)")
– If ‘handle\_missing’ is ‘error’ and the agent does not have the specified attribute(s).
* [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)")
– If an unknown ‘handle\_missing’ option is provided.
set(_attr\_name: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _value: [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")
_) → [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
[\[source\]](../_modules/mesa/agent.html#AgentSet.set)
[#](#mesa.agent.AgentSet.set "Link to this definition")
Set a specified attribute to a given value for all agents in the AgentSet.
Parameters:
* **attr\_name** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
) – The name of the attribute to set.
* **value** (_Any_) – The value to set the attribute to.
Returns:
The AgentSet instance itself, after setting the attribute.
Return type:
[AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
add(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_)[\[source\]](../_modules/mesa/agent.html#AgentSet.add)
[#](#mesa.agent.AgentSet.add "Link to this definition")
Add an agent to the AgentSet.
Parameters:
**agent** ([_Agent_](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
) – The agent to add to the set.
Note
This method is an implementation of the abstract method from MutableSet.
discard(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_)[\[source\]](../_modules/mesa/agent.html#AgentSet.discard)
[#](#mesa.agent.AgentSet.discard "Link to this definition")
Remove an agent from the AgentSet if it exists.
This method does not raise an error if the agent is not present.
Parameters:
**agent** ([_Agent_](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
) – The agent to remove from the set.
Note
This method is an implementation of the abstract method from MutableSet.
remove(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_)[\[source\]](../_modules/mesa/agent.html#AgentSet.remove)
[#](#mesa.agent.AgentSet.remove "Link to this definition")
Remove an agent from the AgentSet.
This method raises an error if the agent is not present.
Parameters:
**agent** ([_Agent_](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
) – The agent to remove from the set.
Note
This method is an implementation of the abstract method from MutableSet.
groupby(_by: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
| [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _result\_type: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
\= 'agentset'_) → [GroupBy](../mesa.html#mesa.agent.GroupBy "mesa.agent.GroupBy")
[\[source\]](../_modules/mesa/agent.html#AgentSet.groupby)
[#](#mesa.agent.AgentSet.groupby "Link to this definition")
Group agents by the specified attribute or return from the callable.
Parameters:
* **by** (_Callable__,_ [_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
) –
used to determine what to group agents by
* if `by` is a callable, it will be called for each agent and the return is used for grouping
* if `by` is a str, it should refer to an attribute on the agent and the value of this attribute will be used for grouping
* **result\_type** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_,_ _optional_) – The datatype for the resulting groups {“agentset”, “list”}
Returns:
GroupBy
Notes: There might be performance benefits to using result\_type=’list’ if you don’t need the advanced functionality of an AgentSet.
clear()[#](#mesa.agent.AgentSet.clear "Link to this definition")
This is slow (creates N new iterators!) but effective.
count(_value_) → integer \-- return number of occurrences of value[#](#mesa.agent.AgentSet.count "Link to this definition")
index(_value_\[, _start_\[, _stop_\]\]) → integer \-- return first index of value.[#](#mesa.agent.AgentSet.index "Link to this definition")
Raises ValueError if the value is not present.
Supporting start and stop arguments is optional, but recommended.
isdisjoint(_other_)[#](#mesa.agent.AgentSet.isdisjoint "Link to this definition")
Return True if two sets have a null intersection.
pop()[#](#mesa.agent.AgentSet.pop "Link to this definition")
Return the popped value. Raise KeyError if empty.
_class_ GroupBy(_groups: [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
, [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")\
| [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")\
\]_)[\[source\]](../_modules/mesa/agent.html#GroupBy)
[#](#mesa.agent.GroupBy "Link to this definition")
Helper class for AgentSet.groupby.
groups[#](#mesa.agent.GroupBy.groups "Link to this definition")
A dictionary with the group\_name as key and group as values
Type:
[dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
Initialize a GroupBy instance.
Parameters:
**groups** ([_dict_](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
) – A dictionary with the group\_name as key and group as values
map(_method: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
| [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _\*args_, _\*\*kwargs_) → [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
, [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\][\[source\]](../_modules/mesa/agent.html#GroupBy.map)
[#](#mesa.agent.GroupBy.map "Link to this definition")
Apply the specified callable to each group and return the results.
Parameters:
* **method** (_Callable__,_ [_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
) –
The callable to apply to each group,
* if `method` is a callable, it will be called it will be called with the group as first argument
* if `method` is a str, it should refer to a method on the group
Additional arguments and keyword arguments will be passed on to the callable.
* **args** – arguments to pass to the callable
* **kwargs** – keyword arguments to pass to the callable
Returns:
dict with group\_name as key and the return of the method as value
Notes
this method is useful for methods or functions that do return something. It will break method chaining. For that, use `do` instead.
do(_method: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
| [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _\*args_, _\*\*kwargs_) → [GroupBy](../mesa.html#mesa.agent.GroupBy "mesa.agent.GroupBy")
[\[source\]](../_modules/mesa/agent.html#GroupBy.do)
[#](#mesa.agent.GroupBy.do "Link to this definition")
Apply the specified callable to each group.
Parameters:
* **method** (_Callable__,_ [_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
) –
The callable to apply to each group,
* if `method` is a callable, it will be called it will be called with the group as first argument
* if `method` is a str, it should refer to a method on the group
Additional arguments and keyword arguments will be passed on to the callable.
* **args** – arguments to pass to the callable
* **kwargs** – keyword arguments to pass to the callable
Returns:
the original GroupBy instance
Notes
this method is useful for methods or functions that don’t return anything and/or if you want to chain multiple do calls
count() → [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\][\[source\]](../_modules/mesa/agent.html#GroupBy.count)
[#](#mesa.agent.GroupBy.count "Link to this definition")
Return the count of agents in each group.
Returns:
A dictionary mapping group names to the number of agents in each group.
Return type:
[dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
agg(_attr\_name: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _func: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_) → [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[[Hashable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Hashable "(in Python v3.13)")\
, [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\][\[source\]](../_modules/mesa/agent.html#GroupBy.agg)
[#](#mesa.agent.GroupBy.agg "Link to this definition")
Aggregate the values of a specific attribute across each group using the provided function.
Parameters:
* **attr\_name** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
) – The name of the attribute to aggregate.
* **func** (_Callable_) – The function to apply (e.g., sum, min, max, mean).
Returns:
A dictionary mapping group names to the result of applying the aggregation function.
Return type:
[dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[Hashable, Any\]
On this page
### This Page
* [Show Source](../_sources/apis/agent.md.txt)
---
# Data collection — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Data collection[#](#module-datacollection "Link to this heading")
==================================================================
Mesa Data Collection Module.
DataCollector is meant to provide a simple, standard way to collect data generated by a Mesa model. It collects four types of data: model-level data, agent-level data, agent-type-level data, and tables.
A DataCollector is instantiated with three dictionaries of reporter names and associated variable names or functions for each, one for model-level data, one for agent-level data, and one for agent-type-level data; a fourth dictionary provides table names and columns. Variable names are converted into functions which retrieve attributes of that name.
When the collect() method is called, each model-level function is called, with the model as the argument, and the results associated with the relevant variable. Then the agent-level functions are called on each agent, and the agent-type-level functions are called on each agent of the specified type.
Additionally, other objects can write directly to tables by passing in an appropriate dictionary object for a table row.
The DataCollector then stores the data it collects in dictionaries:
* model\_vars maps each reporter to a list of its values
* tables maps each table to a dictionary, with each column as a key with a list as its value.
* \_agent\_records maps each model step to a list of each agent’s id and its values.
* \_agenttype\_records maps each model step to a dictionary of agent types, each containing a list of each agent’s id and its values.
Finally, DataCollector can create a pandas DataFrame from each collection.
_class_ DataCollector(_model\_reporters\=None_, _agent\_reporters\=None_, _agenttype\_reporters\=None_, _tables\=None_)[\[source\]](../_modules/datacollection.html#DataCollector)
[#](#datacollection.DataCollector "Link to this definition")
Class for collecting data generated by a Mesa model.
A DataCollector is instantiated with dictionaries of names of model-, agent-, and agent-type-level variables to collect, associated with attribute names or functions which actually collect them. When the collect(…) method is called, it collects these attributes and executes these functions one by one and stores the results.
Instantiate a DataCollector with lists of model, agent, and agent-type reporters.
Both model\_reporters, agent\_reporters, and agenttype\_reporters accept a dictionary mapping a variable name to either an attribute name, a function, a method of a class/instance, or a function with parameters placed in a list.
Model reporters can take four types of arguments: 1. Lambda function:
> {“agent\_count”: lambda m: len(m.agents)}
2. Method of a class/instance: {“agent\_count”: self.get\_agent\_count} # self here is a class instance {“agent\_count”: Model.get\_agent\_count} # Model here is a class
3. Class attributes of a model: {“model\_attribute”: “model\_attribute”}
4. Functions with parameters that have been placed in a list: {“Model\_Function”: \[function, \[param\_1, param\_2\]\]}
Agent reporters can similarly take: 1. Attribute name (string) referring to agent’s attribute:
> {“energy”: “energy”}
2. Lambda function: {“energy”: lambda a: a.energy}
3. Method of an agent class/instance: {“agent\_action”: self.do\_action} # self here is an agent class instance {“agent\_action”: Agent.do\_action} # Agent here is a class
4. Functions with parameters placed in a list: {“Agent\_Function”: \[function, \[param\_1, param\_2\]\]}
Agenttype reporters take a dictionary mapping agent types to dictionaries of reporter names and attributes/funcs/methods, similar to agent\_reporters:
> {Wolf: {“energy”: lambda a: a.energy}}
The tables arg accepts a dictionary mapping names of tables to lists of columns. For example, if we want to allow agents to write their age when they are destroyed (to keep track of lifespans), it might look like:
> {“Lifespan”: \[“unique\_id”, “age”\]}
Parameters:
* **model\_reporters** – Dictionary of reporter names and attributes/funcs/methods.
* **agent\_reporters** – Dictionary of reporter names and attributes/funcs/methods.
* **agenttype\_reporters** – Dictionary of agent types to dictionaries of reporter names and attributes/funcs/methods.
* **tables** – Dictionary of table names to lists of column names.
Notes
* If you want to pickle your model you must not use lambda functions.
* If your model includes a large number of agents, it is recommended to use attribute names for the agent reporter, as it will be faster.
collect(_model_)[\[source\]](../_modules/datacollection.html#DataCollector.collect)
[#](#datacollection.DataCollector.collect "Link to this definition")
Collect all the data for the given model object.
add\_table\_row(_table\_name_, _row_, _ignore\_missing\=False_)[\[source\]](../_modules/datacollection.html#DataCollector.add_table_row)
[#](#datacollection.DataCollector.add_table_row "Link to this definition")
Add a row dictionary to a specific table.
Parameters:
* **table\_name** – Name of the table to append a row to.
* **row** – A dictionary of the form {column\_name: value…}
* **ignore\_missing** – If True, fill any missing columns with Nones; if False, throw an error if any columns are missing
get\_model\_vars\_dataframe()[\[source\]](../_modules/datacollection.html#DataCollector.get_model_vars_dataframe)
[#](#datacollection.DataCollector.get_model_vars_dataframe "Link to this definition")
Create a pandas DataFrame from the model variables.
The DataFrame has one column for each model variable, and the index is (implicitly) the model tick.
get\_agent\_vars\_dataframe()[\[source\]](../_modules/datacollection.html#DataCollector.get_agent_vars_dataframe)
[#](#datacollection.DataCollector.get_agent_vars_dataframe "Link to this definition")
Create a pandas DataFrame from the agent variables.
The DataFrame has one column for each variable, with two additional columns for tick and agent\_id.
get\_agenttype\_vars\_dataframe(_agent\_type_)[\[source\]](../_modules/datacollection.html#DataCollector.get_agenttype_vars_dataframe)
[#](#datacollection.DataCollector.get_agenttype_vars_dataframe "Link to this definition")
Create a pandas DataFrame from the agent-type variables for a specific agent type.
The DataFrame has one column for each variable, with two additional columns for tick and agent\_id.
Parameters:
**agent\_type** – The type of agent to get the data for.
get\_table\_dataframe(_table\_name_)[\[source\]](../_modules/datacollection.html#DataCollector.get_table_dataframe)
[#](#datacollection.DataCollector.get_table_dataframe "Link to this definition")
Create a pandas DataFrame from a particular table.
Parameters:
**table\_name** – The name of the table to convert.
On this page
### This Page
* [Show Source](../_sources/apis/datacollection.md.txt)
---
# Epstein Civil Violence Model — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Epstein Civil Violence Model[#](#epstein-civil-violence-model "Link to this heading")
======================================================================================
Summary[#](#summary "Link to this heading")
--------------------------------------------
This model is based on Joshua Epstein’s simulation of how civil unrest grows and is suppressed. Citizen agents wander the grid randomly, and are endowed with individual risk aversion and hardship levels; there is also a universal regime legitimacy value. There are also Cop agents, who work on behalf of the regime. Cops arrest Citizens who are actively rebelling; Citizens decide whether to rebel based on their hardship and the regime legitimacy, and their perceived probability of arrest.
The model generates mass uprising as self-reinforcing processes: if enough agents are rebelling, the probability of any individual agent being arrested is reduced, making more agents more likely to join the uprising. However, the more rebelling Citizens the Cops arrest, the less likely additional agents become to join.
How to Run[#](#how-to-run "Link to this heading")
--------------------------------------------------
To run the model interactively, in this directory, run the following command
$ solara run app.py
Files[#](#files "Link to this heading")
----------------------------------------
* `model.py`: Core model code.
* `agent.py`: Agent classes.
* `app.py`: Sets up the interactive visualization.
* `Epstein Civil Violence.ipynb`: Jupyter notebook conducting some preliminary analysis of the model.
Further Reading[#](#further-reading "Link to this heading")
------------------------------------------------------------
This model is based adapted from:
[Epstein, J. “Modeling civil violence: An agent-based computational approach”, Proceedings of the National Academy of Sciences, Vol. 99, Suppl. 3, May 14, 2002](http://www.pnas.org/content/99/suppl.3/7243.short)
A similar model is also included with NetLogo:
Wilensky, U. (2004). NetLogo Rebellion model. http://ccl.northwestern.edu/netlogo/models/Rebellion. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
Agents[#](#agents "Link to this heading")
------------------------------------------
import math
from enum import Enum
import mesa
class CitizenState(Enum):
ACTIVE \= 1
QUIET \= 2
ARRESTED \= 3
class EpsteinAgent(mesa.discrete\_space.CellAgent):
def update\_neighbors(self):
"""
Look around and see who my neighbors are
"""
self.neighborhood \= self.cell.get\_neighborhood(radius\=self.vision)
self.neighbors \= self.neighborhood.agents
self.empty\_neighbors \= \[c for c in self.neighborhood if c.is\_empty\]
def move(self):
if self.model.movement and self.empty\_neighbors:
new\_pos \= self.random.choice(self.empty\_neighbors)
self.move\_to(new\_pos)
class Citizen(EpsteinAgent):
"""
A member of the general population, may or may not be in active rebellion.
Summary of rule: If grievance - risk > threshold, rebel.
Attributes:
hardship: Agent's 'perceived hardship (i.e., physical or economic
privation).' Exogenous, drawn from U(0,1).
regime\_legitimacy: Agent's perception of regime legitimacy, equal
across agents. Exogenous.
risk\_aversion: Exogenous, drawn from U(0,1).
threshold: if (grievance - (risk\_aversion \* arrest\_probability)) >
threshold, go/remain Active
vision: number of cells in each direction (N, S, E and W) that agent
can inspect
condition: Can be "Quiescent" or "Active;" deterministic function of
greivance, perceived risk, and
grievance: deterministic function of hardship and regime\_legitimacy;
how aggrieved is agent at the regime?
arrest\_probability: agent's assessment of arrest probability, given
rebellion
"""
def \_\_init\_\_(
self, model, regime\_legitimacy, threshold, vision, arrest\_prob\_constant
):
"""
Create a new Citizen.
Args:
model: the model to which the agent belongs
hardship: Agent's 'perceived hardship (i.e., physical or economic
privation).' Exogenous, drawn from U(0,1).
regime\_legitimacy: Agent's perception of regime legitimacy, equal
across agents. Exogenous.
risk\_aversion: Exogenous, drawn from U(0,1).
threshold: if (grievance - (risk\_aversion \* arrest\_probability)) >
threshold, go/remain Active
vision: number of cells in each direction (N, S, E and W) that
agent can inspect. Exogenous.
model: model instance
"""
super().\_\_init\_\_(model)
self.hardship \= self.random.random()
self.risk\_aversion \= self.random.random()
self.regime\_legitimacy \= regime\_legitimacy
self.threshold \= threshold
self.state \= CitizenState.QUIET
self.vision \= vision
self.jail\_sentence \= 0
self.grievance \= self.hardship \* (1 \- self.regime\_legitimacy)
self.arrest\_prob\_constant \= arrest\_prob\_constant
self.arrest\_probability \= None
self.neighborhood \= \[\]
self.neighbors \= \[\]
self.empty\_neighbors \= \[\]
def step(self):
"""
Decide whether to activate, then move if applicable.
"""
if self.jail\_sentence:
self.jail\_sentence \-= 1
return \# no other changes or movements if agent is in jail.
self.update\_neighbors()
self.update\_estimated\_arrest\_probability()
net\_risk \= self.risk\_aversion \* self.arrest\_probability
if (self.grievance \- net\_risk) \> self.threshold:
self.state \= CitizenState.ACTIVE
else:
self.state \= CitizenState.QUIET
self.move()
def update\_estimated\_arrest\_probability(self):
"""
Based on the ratio of cops to actives in my neighborhood, estimate the
p(Arrest | I go active).
"""
cops\_in\_vision \= 0
actives\_in\_vision \= 1 \# citizen counts herself
for neighbor in self.neighbors:
if isinstance(neighbor, Cop):
cops\_in\_vision += 1
elif neighbor.state \== CitizenState.ACTIVE:
actives\_in\_vision += 1
\# there is a body of literature on this equation
\# the round is not in the pnas paper but without it, its impossible to replicate
\# the dynamics shown there.
self.arrest\_probability \= 1 \- math.exp(
\-1 \* self.arrest\_prob\_constant \* round(cops\_in\_vision / actives\_in\_vision)
)
class Cop(EpsteinAgent):
"""
A cop for life. No defection.
Summary of rule: Inspect local vision and arrest a random active agent.
Attributes:
unique\_id: unique int
x, y: Grid coordinates
vision: number of cells in each direction (N, S, E and W) that cop is
able to inspect
"""
def \_\_init\_\_(self, model, vision, max\_jail\_term):
"""
Create a new Cop.
Args:
x, y: Grid coordinates
vision: number of cells in each direction (N, S, E and W) that
agent can inspect. Exogenous.
model: model instance
"""
super().\_\_init\_\_(model)
self.vision \= vision
self.max\_jail\_term \= max\_jail\_term
def step(self):
"""
Inspect local vision and arrest a random active agent. Move if
applicable.
"""
self.update\_neighbors()
active\_neighbors \= \[\]
for agent in self.neighbors:
if isinstance(agent, Citizen) and agent.state \== CitizenState.ACTIVE:
active\_neighbors.append(agent)
if active\_neighbors:
arrestee \= self.random.choice(active\_neighbors)
arrestee.jail\_sentence \= self.random.randint(0, self.max\_jail\_term)
arrestee.state \= CitizenState.ARRESTED
self.move()
Model[#](#model "Link to this heading")
----------------------------------------
import mesa
from mesa.examples.advanced.epstein\_civil\_violence.agents import (
Citizen,
CitizenState,
Cop,
)
class EpsteinCivilViolence(mesa.Model):
"""
Model 1 from "Modeling civil violence: An agent-based computational
approach," by Joshua Epstein.
http://www.pnas.org/content/99/suppl\_3/7243.full
Args:
height: grid height
width: grid width
citizen\_density: approximate % of cells occupied by citizens.
cop\_density: approximate % of cells occupied by cops.
citizen\_vision: number of cells in each direction (N, S, E and W) that
citizen can inspect
cop\_vision: number of cells in each direction (N, S, E and W) that cop
can inspect
legitimacy: (L) citizens' perception of regime legitimacy, equal
across all citizens
max\_jail\_term: (J\_max)
active\_threshold: if (grievance - (risk\_aversion \* arrest\_probability))
> threshold, citizen rebels
arrest\_prob\_constant: set to ensure agents make plausible arrest
probability estimates
movement: binary, whether agents try to move at step end
max\_iters: model may not have a natural stopping point, so we set a
max.
"""
def \_\_init\_\_(
self,
width\=40,
height\=40,
citizen\_density\=0.7,
cop\_density\=0.074,
citizen\_vision\=7,
cop\_vision\=7,
legitimacy\=0.8,
max\_jail\_term\=1000,
active\_threshold\=0.1,
arrest\_prob\_constant\=2.3,
movement\=True,
max\_iters\=1000,
seed\=None,
):
super().\_\_init\_\_(seed\=seed)
self.movement \= movement
self.max\_iters \= max\_iters
self.grid \= mesa.discrete\_space.OrthogonalVonNeumannGrid(
(width, height), capacity\=1, torus\=True, random\=self.random
)
model\_reporters \= {
"active": CitizenState.ACTIVE.name,
"quiet": CitizenState.QUIET.name,
"arrested": CitizenState.ARRESTED.name,
}
agent\_reporters \= {
"jail\_sentence": lambda a: getattr(a, "jail\_sentence", None),
"arrest\_probability": lambda a: getattr(a, "arrest\_probability", None),
}
self.datacollector \= mesa.DataCollector(
model\_reporters\=model\_reporters, agent\_reporters\=agent\_reporters
)
if cop\_density + citizen\_density \> 1:
raise ValueError("Cop density + citizen density must be less than 1")
for cell in self.grid.all\_cells:
klass \= self.random.choices(
\[Citizen, Cop, None\],
cum\_weights\=\[citizen\_density, citizen\_density + cop\_density, 1\],
)\[0\]
if klass \== Cop:
cop \= Cop(self, vision\=cop\_vision, max\_jail\_term\=max\_jail\_term)
cop.move\_to(cell)
elif klass \== Citizen:
citizen \= Citizen(
self,
regime\_legitimacy\=legitimacy,
threshold\=active\_threshold,
vision\=citizen\_vision,
arrest\_prob\_constant\=arrest\_prob\_constant,
)
citizen.move\_to(cell)
self.running \= True
self.\_update\_counts()
self.datacollector.collect(self)
def step(self):
"""
Advance the model by one step and collect data.
"""
self.agents.shuffle\_do("step")
self.\_update\_counts()
self.datacollector.collect(self)
if self.steps \> self.max\_iters:
self.running \= False
def \_update\_counts(self):
"""Helper function for counting nr. of citizens in given state."""
counts \= self.agents\_by\_type\[Citizen\].groupby("state").count()
for state in CitizenState:
setattr(self, state.name, counts.get(state, 0))
App[#](#app "Link to this heading")
------------------------------------
from mesa.examples.advanced.epstein\_civil\_violence.agents import (
Citizen,
CitizenState,
Cop,
)
from mesa.examples.advanced.epstein\_civil\_violence.model import EpsteinCivilViolence
from mesa.visualization import (
Slider,
SolaraViz,
make\_plot\_component,
make\_space\_component,
)
COP\_COLOR \= "#000000"
agent\_colors \= {
CitizenState.ACTIVE: "#FE6100",
CitizenState.QUIET: "#648FFF",
CitizenState.ARRESTED: "#808080",
}
def citizen\_cop\_portrayal(agent):
if agent is None:
return
portrayal \= {
"size": 50,
}
if isinstance(agent, Citizen):
portrayal\["color"\] \= agent\_colors\[agent.state\]
elif isinstance(agent, Cop):
portrayal\["color"\] \= COP\_COLOR
return portrayal
def post\_process(ax):
ax.set\_aspect("equal")
ax.set\_xticks(\[\])
ax.set\_yticks(\[\])
ax.get\_figure().set\_size\_inches(10, 10)
model\_params \= {
"seed": {
"type": "InputText",
"value": 42,
"label": "Random Seed",
},
"height": 40,
"width": 40,
"citizen\_density": Slider("Initial Agent Density", 0.7, 0.0, 0.9, 0.1),
"cop\_density": Slider("Initial Cop Density", 0.04, 0.0, 0.1, 0.01),
"citizen\_vision": Slider("Citizen Vision", 7, 1, 10, 1),
"cop\_vision": Slider("Cop Vision", 7, 1, 10, 1),
"legitimacy": Slider("Government Legitimacy", 0.82, 0.0, 1, 0.01),
"max\_jail\_term": Slider("Max Jail Term", 30, 0, 50, 1),
}
space\_component \= make\_space\_component(
citizen\_cop\_portrayal, post\_process\=post\_process, draw\_grid\=False
)
chart\_component \= make\_plot\_component(
{state.name.lower(): agent\_colors\[state\] for state in CitizenState}
)
epstein\_model \= EpsteinCivilViolence()
page \= SolaraViz(
epstein\_model,
components\=\[space\_component, chart\_component\],
model\_params\=model\_params,
name\="Epstein Civil Violence",
)
page \# noqa
On this page
### This Page
* [Show Source](../../_sources/examples/advanced/epstein_civil_violence.md.txt)
---
# Visualization — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Visualization[#](#visualization "Link to this heading")
========================================================
For a detailed tutorial, please refer to our [Visualization Tutorial](#../tutorials/visualization_tutorial.ipynb)
.
Jupyter Visualization[#](#module-mesa.visualization.solara_viz "Link to this heading")
---------------------------------------------------------------------------------------
Mesa visualization module for creating interactive model visualizations.
This module provides components to create browser- and Jupyter notebook-based visualizations of Mesa models, allowing users to watch models run step-by-step and interact with model parameters.
Key features:
* SolaraViz: Main component for creating visualizations, supporting grid displays and plots
* ModelController: Handles model execution controls (step, play, pause, reset)
* UserInputs: Generates UI elements for adjusting model parameters
The module uses Solara for rendering in Jupyter notebooks or as standalone web applications. It supports various types of visualizations including matplotlib plots, agent grids, and custom visualization components.
Usage:
1. Define an agent\_portrayal function to specify how agents should be displayed
2. Set up model\_params to define adjustable parameters
3. Create a SolaraViz instance with your model, parameters, and desired measures
4. Display the visualization in a Jupyter notebook or run as a Solara app
See the Visualization Tutorial and example models for more details.
split\_model\_params(_model\_params_)[\[source\]](../_modules/mesa/visualization/solara_viz.html#split_model_params)
[#](#mesa.visualization.solara_viz.split_model_params "Link to this definition")
Split model parameters into user-adjustable and fixed parameters.
Parameters:
**model\_params** – Dictionary of all model parameters
Returns:
(user\_adjustable\_params, fixed\_params)
Return type:
[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
check\_param\_is\_fixed(_param_)[\[source\]](../_modules/mesa/visualization/solara_viz.html#check_param_is_fixed)
[#](#mesa.visualization.solara_viz.check_param_is_fixed "Link to this definition")
Check if a parameter is fixed (not user-adjustable).
Parameters:
**param** – Parameter to check
Returns:
True if parameter is fixed, False otherwise
Return type:
[bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
make\_initial\_grid\_layout(_num\_components_)[\[source\]](../_modules/mesa/visualization/solara_viz.html#make_initial_grid_layout)
[#](#mesa.visualization.solara_viz.make_initial_grid_layout "Link to this definition")
Create an initial grid layout for visualization components.
Parameters:
**num\_components** – Number of components to display
Returns:
Initial grid layout configuration
Return type:
[list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
custom solara components.
make\_space\_component(_agent\_portrayal: Callable | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _propertylayer\_portrayal: [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _post\_process: Callable | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _backend: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
\= 'matplotlib'_, _\*\*space\_drawing\_kwargs_) → SpaceMatplotlib | SpaceAltair[\[source\]](../_modules/mesa/visualization/components/__init__.html#make_space_component)
[#](#mesa.visualization.components.__init__.make_space_component "Link to this definition")
Create a Matplotlib-based space visualization component.
Parameters:
* **agent\_portrayal** – Function to portray agents.
* **propertylayer\_portrayal** – Dictionary of PropertyLayer portrayal specifications
* **post\_process** – a callable that will be called with the Axes instance. Allows for fine-tuning plots (e.g., control ticks)
* **backend** – the backend to use {“matplotlib”, “altair”}
* **space\_drawing\_kwargs** – additional keyword arguments to be passed on to the underlying backend specific space drawer function. See the functions for drawing the various spaces for the appropriate backend further details.
Returns:
A function that creates a space component
Return type:
function
make\_plot\_component(_measure: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
| [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
, [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
\] | [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
\] | [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
\]_, _post\_process: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _backend: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
\= 'matplotlib'_, _\*\*plot\_drawing\_kwargs_)[\[source\]](../_modules/mesa/visualization/components/__init__.html#make_plot_component)
[#](#mesa.visualization.components.__init__.make_plot_component "Link to this definition")
Create a plotting function for a specified measure using the specified backend.
Parameters:
* **measure** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_|_ [_dict_](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
_\[_[_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
_,_ [_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
_\]_ _|_ [_list_](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
_\[_[_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
_\]_ _|_ [_tuple_](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
_\[_[_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
_\]_) – Measure(s) to plot.
* **post\_process** – a user-specified callable to do post-processing called with the Axes instance.
* **backend** – the backend to use {“matplotlib”, “altair”}
* **plot\_drawing\_kwargs** – additional keyword arguments to pass onto the backend specific function for making a plotting component
Notes
altair plotting backend is not yet implemented and planned for mesa 3.1.
Returns:
A function that creates a plot component
Return type:
function
User Parameters[#](#module-mesa.visualization.user_param "Link to this heading")
---------------------------------------------------------------------------------
Solara visualization related helper classes.
_class_ UserParam[\[source\]](../_modules/mesa/visualization/user_param.html#UserParam)
[#](#mesa.visualization.user_param.UserParam "Link to this definition")
Bases: [`object`](https://docs.python.org/3/library/functions.html#object "(in Python v3.13)")
UserParam.
maybe\_raise\_error(_param\_type_, _valid_)[\[source\]](../_modules/mesa/visualization/user_param.html#UserParam.maybe_raise_error)
[#](#mesa.visualization.user_param.UserParam.maybe_raise_error "Link to this definition")
_class_ Slider(_label\=''_, _value\=None_, _min\=None_, _max\=None_, _step\=1_, _dtype\=None_)[\[source\]](../_modules/mesa/visualization/user_param.html#Slider)
[#](#mesa.visualization.user_param.Slider "Link to this definition")
Bases: [`UserParam`](#mesa.visualization.user_param.UserParam "mesa.visualization.user_param.UserParam")
A number-based slider input with settable increment.
Example: slider\_option = Slider(“My Slider”, value=123, min=10, max=200, step=0.1)
Parameters:
* **label** – The displayed label in the UI
* **value** – The initial value of the slider
* **min** – The minimum possible value of the slider
* **max** – The maximum possible value of the slider
* **step** – The step between min and max for a range of possible values
* **dtype** – either int or float
Initializes a slider.
Parameters:
* **label** – The displayed label in the UI
* **value** – The initial value of the slider
* **min** – The minimum possible value of the slider
* **max** – The maximum possible value of the slider
* **step** – The step between min and max for a range of possible values
* **dtype** – either int or float
get(_attr_)[\[source\]](../_modules/mesa/visualization/user_param.html#Slider.get)
[#](#mesa.visualization.user_param.Slider.get "Link to this definition")
Matplotlib-based visualizations[#](#module-mesa.visualization.components.matplotlib_components "Link to this heading")
-----------------------------------------------------------------------------------------------------------------------
Matplotlib based solara components for visualization MESA spaces and plots.
make\_space\_matplotlib(_\*args_, _\*\*kwargs_)[\[source\]](../_modules/mesa/visualization/components/matplotlib_components.html#make_space_matplotlib)
[#](#mesa.visualization.components.matplotlib_components.make_space_matplotlib "Link to this definition")
make\_mpl\_space\_component(_agent\_portrayal: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _propertylayer\_portrayal: [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _post\_process: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _\*\*space\_drawing\_kwargs_) → SpaceMatplotlib[\[source\]](../_modules/mesa/visualization/components/matplotlib_components.html#make_mpl_space_component)
[#](#mesa.visualization.components.matplotlib_components.make_mpl_space_component "Link to this definition")
Create a Matplotlib-based space visualization component.
Parameters:
* **agent\_portrayal** – Function to portray agents.
* **propertylayer\_portrayal** – Dictionary of PropertyLayer portrayal specifications
* **post\_process** – a callable that will be called with the Axes instance. Allows for fine tuning plots (e.g., control ticks)
* **space\_drawing\_kwargs** – additional keyword arguments to be passed on to the underlying space drawer function. See the functions for drawing the various spaces for further details.
`agent_portrayal` is called with an agent and should return a dict. Valid fields in this dict are “color”, “size”, “marker”, “zorder”, alpha, linewidths, and edgecolors. Other field are ignored and will result in a user warning.
Returns:
A function that creates a SpaceMatplotlib component
Return type:
function
make\_plot\_measure(_\*args_, _\*\*kwargs_)[\[source\]](../_modules/mesa/visualization/components/matplotlib_components.html#make_plot_measure)
[#](#mesa.visualization.components.matplotlib_components.make_plot_measure "Link to this definition")
make\_mpl\_plot\_component(_measure: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
| [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
, [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
\] | [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
\] | [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
\]_, _post\_process: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _save\_format\='png'_)[\[source\]](../_modules/mesa/visualization/components/matplotlib_components.html#make_mpl_plot_component)
[#](#mesa.visualization.components.matplotlib_components.make_mpl_plot_component "Link to this definition")
Create a plotting function for a specified measure.
Parameters:
* **measure** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_|_ [_dict_](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
_\[_[_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
_,_ [_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
_\]_ _|_ [_list_](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
_\[_[_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
_\]_ _|_ [_tuple_](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
_\[_[_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
_\]_) – Measure(s) to plot.
* **post\_process** – a user-specified callable to do post-processing called with the Axes instance.
* **save\_format** – save format of figure in solara backend
Returns:
A function that creates a PlotMatplotlib component.
Return type:
function
Helper functions for drawing mesa spaces with matplotlib.
These functions are used by the provided matplotlib components, but can also be used to quickly visualize a space with matplotlib for example when creating a mp4 of a movie run or when needing a figure for a paper.
collect\_agent\_data(_space: [SingleGrid](../mesa.html#mesa.space.SingleGrid "mesa.space.SingleGrid")
| [MultiGrid](../mesa.html#mesa.space.MultiGrid "mesa.space.MultiGrid")
| [OrthogonalMooreGrid](discrete_space.html#mesa.discrete_space.grid.OrthogonalMooreGrid "mesa.discrete_space.grid.OrthogonalMooreGrid")
| [OrthogonalVonNeumannGrid](discrete_space.html#mesa.discrete_space.grid.OrthogonalVonNeumannGrid "mesa.discrete_space.grid.OrthogonalVonNeumannGrid")
| [HexSingleGrid](../mesa.html#mesa.space.HexSingleGrid "mesa.space.HexSingleGrid")
| [HexMultiGrid](../mesa.html#mesa.space.HexMultiGrid "mesa.space.HexMultiGrid")
| [HexGrid](discrete_space.html#mesa.discrete_space.grid.HexGrid "mesa.discrete_space.grid.HexGrid")
| [NetworkGrid](../mesa.html#mesa.space.NetworkGrid "mesa.space.NetworkGrid")
| [Network](discrete_space.html#mesa.discrete_space.network.Network "mesa.discrete_space.network.Network")
| [ContinuousSpace](../mesa.html#mesa.space.ContinuousSpace "mesa.space.ContinuousSpace")
| [VoronoiGrid](discrete_space.html#mesa.discrete_space.voronoi.VoronoiGrid "mesa.discrete_space.voronoi.VoronoiGrid")
_, _agent\_portrayal: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_, _color\='tab:blue'_, _size\=25_, _marker\='o'_, _zorder: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_)[\[source\]](../_modules/mesa/visualization/mpl_space_drawing.html#collect_agent_data)
[#](#mesa.visualization.mpl_space_drawing.collect_agent_data "Link to this definition")
Collect the plotting data for all agents in the space.
Parameters:
* **space** – The space containing the Agents.
* **agent\_portrayal** – A callable that is called with the agent and returns a dict
* **color** – default color
* **size** – default size
* **marker** – default marker
* **zorder** – default zorder
agent\_portrayal should return a dict, limited to size (size of marker), color (color of marker), zorder (z-order), marker (marker style), alpha, linewidths, and edgecolors
draw\_space(_space_, _agent\_portrayal: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_, _propertylayer\_portrayal: [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _ax: Axes | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _\*\*space\_drawing\_kwargs_)[\[source\]](../_modules/mesa/visualization/mpl_space_drawing.html#draw_space)
[#](#mesa.visualization.mpl_space_drawing.draw_space "Link to this definition")
Draw a Matplotlib-based visualization of the space.
Parameters:
* **space** – the space of the mesa model
* **agent\_portrayal** – A callable that returns a dict specifying how to show the agent
* **propertylayer\_portrayal** – a dict specifying how to show propertylayer(s)
* **ax** – the axes upon which to draw the plot
* **space\_drawing\_kwargs** – any additional keyword arguments to be passed on to the underlying function for drawing the space.
Returns:
Returns the Axes object with the plot drawn onto it.
`agent_portrayal` is called with an agent and should return a dict. Valid fields in this dict are “color”, “size”, “marker”, “zorder”, alpha, linewidths, and edgecolors. Other field are ignored and will result in a user warning.
draw\_property\_layers(_space_, _propertylayer\_portrayal: [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
, [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")\
\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
, [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\]\]_, _ax: Axes_)[\[source\]](../_modules/mesa/visualization/mpl_space_drawing.html#draw_property_layers)
[#](#mesa.visualization.mpl_space_drawing.draw_property_layers "Link to this definition")
Draw PropertyLayers on the given axes.
Parameters:
* **space** (_mesa.space.\_Grid_) – The space containing the PropertyLayers.
* **propertylayer\_portrayal** ([_dict_](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
) – the key is the name of the layer, the value is a dict with fields specifying how the layer is to be portrayed
* **ax** (_matplotlib.axes.Axes_) – The axes to draw on.
Notes
valid fields in in the inner dict of propertylayer\_portrayal are “alpha”, “vmin”, “vmax”, “color” or “colormap”, and “colorbar” so you can do {“some\_layer”:{“colormap”:’viridis’, ‘alpha’:.25, “colorbar”:False}}
draw\_orthogonal\_grid(_space: [SingleGrid](../mesa.html#mesa.space.SingleGrid "mesa.space.SingleGrid")
| [MultiGrid](../mesa.html#mesa.space.MultiGrid "mesa.space.MultiGrid")
| [OrthogonalMooreGrid](discrete_space.html#mesa.discrete_space.grid.OrthogonalMooreGrid "mesa.discrete_space.grid.OrthogonalMooreGrid")
| [OrthogonalVonNeumannGrid](discrete_space.html#mesa.discrete_space.grid.OrthogonalVonNeumannGrid "mesa.discrete_space.grid.OrthogonalVonNeumannGrid")
_, _agent\_portrayal: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_, _ax: Axes | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _draw\_grid: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= True_, _\*\*kwargs_)[\[source\]](../_modules/mesa/visualization/mpl_space_drawing.html#draw_orthogonal_grid)
[#](#mesa.visualization.mpl_space_drawing.draw_orthogonal_grid "Link to this definition")
Visualize a orthogonal grid.
Parameters:
* **space** – the space to visualize
* **agent\_portrayal** – a callable that is called with the agent and returns a dict
* **ax** – a Matplotlib Axes instance. If none is provided a new figure and ax will be created using plt.subplots
* **draw\_grid** – whether to draw the grid
* **kwargs** – additional keyword arguments passed to ax.scatter
Returns:
Returns the Axes object with the plot drawn onto it.
`agent_portrayal` is called with an agent and should return a dict. Valid fields in this dict are “color”, “size”, “marker”, and “zorder”. Other field are ignored and will result in a user warning.
draw\_hex\_grid(_space: [HexSingleGrid](../mesa.html#mesa.space.HexSingleGrid "mesa.space.HexSingleGrid")
| [HexMultiGrid](../mesa.html#mesa.space.HexMultiGrid "mesa.space.HexMultiGrid")
| [HexGrid](discrete_space.html#mesa.discrete_space.grid.HexGrid "mesa.discrete_space.grid.HexGrid")
_, _agent\_portrayal: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_, _ax: Axes | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _draw\_grid: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= True_, _\*\*kwargs_)[\[source\]](../_modules/mesa/visualization/mpl_space_drawing.html#draw_hex_grid)
[#](#mesa.visualization.mpl_space_drawing.draw_hex_grid "Link to this definition")
Visualize a hex grid.
Parameters:
* **space** – the space to visualize
* **agent\_portrayal** – a callable that is called with the agent and returns a dict
* **ax** – a Matplotlib Axes instance. If none is provided a new figure and ax will be created using plt.subplots
* **draw\_grid** – whether to draw the grid
* **kwargs** – additional keyword arguments passed to ax.scatter
draw\_network(_space: ~mesa.space.NetworkGrid | ~mesa.discrete\_space.network.Network_, _agent\_portrayal: ~collections.abc.Callable_, _ax: ~matplotlib.axes.\_axes.Axes | None \= None_, _draw\_grid: bool \= True_, _layout\_alg=_, _layout\_kwargs=None_, _\*\*kwargs_)[\[source\]](../_modules/mesa/visualization/mpl_space_drawing.html#draw_network)
[#](#mesa.visualization.mpl_space_drawing.draw_network "Link to this definition")
Visualize a network space.
Parameters:
* **space** – the space to visualize
* **agent\_portrayal** – a callable that is called with the agent and returns a dict
* **ax** – a Matplotlib Axes instance. If none is provided a new figure and ax will be created using plt.subplots
* **draw\_grid** – whether to draw the grid
* **layout\_alg** – a networkx layout algorithm or other callable with the same behavior
* **layout\_kwargs** – a dictionary of keyword arguments for the layout algorithm
* **kwargs** – additional keyword arguments passed to ax.scatter
Returns:
Returns the Axes object with the plot drawn onto it.
`agent_portrayal` is called with an agent and should return a dict. Valid fields in this dict are “color”, “size”, “marker”, and “zorder”. Other field are ignored and will result in a user warning.
draw\_continuous\_space(_space: [ContinuousSpace](../mesa.html#mesa.space.ContinuousSpace "mesa.space.ContinuousSpace")
_, _agent\_portrayal: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_, _ax: Axes | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _\*\*kwargs_)[\[source\]](../_modules/mesa/visualization/mpl_space_drawing.html#draw_continuous_space)
[#](#mesa.visualization.mpl_space_drawing.draw_continuous_space "Link to this definition")
Visualize a continuous space.
Parameters:
* **space** – the space to visualize
* **agent\_portrayal** – a callable that is called with the agent and returns a dict
* **ax** – a Matplotlib Axes instance. If none is provided a new figure and ax will be created using plt.subplots
* **kwargs** – additional keyword arguments passed to ax.scatter
Returns:
Returns the Axes object with the plot drawn onto it.
`agent_portrayal` is called with an agent and should return a dict. Valid fields in this dict are “color”, “size”, “marker”, and “zorder”. Other field are ignored and will result in a user warning.
draw\_voronoi\_grid(_space: [VoronoiGrid](discrete_space.html#mesa.discrete_space.voronoi.VoronoiGrid "mesa.discrete_space.voronoi.VoronoiGrid")
_, _agent\_portrayal: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_, _ax: Axes | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _draw\_grid: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= True_, _\*\*kwargs_)[\[source\]](../_modules/mesa/visualization/mpl_space_drawing.html#draw_voronoi_grid)
[#](#mesa.visualization.mpl_space_drawing.draw_voronoi_grid "Link to this definition")
Visualize a voronoi grid.
Parameters:
* **space** – the space to visualize
* **agent\_portrayal** – a callable that is called with the agent and returns a dict
* **ax** – a Matplotlib Axes instance. If none is provided a new figure and ax will be created using plt.subplots
* **draw\_grid** – whether to draw the grid or not
* **kwargs** – additional keyword arguments passed to ax.scatter
Returns:
Returns the Axes object with the plot drawn onto it.
`agent_portrayal` is called with an agent and should return a dict. Valid fields in this dict are “color”, “size”, “marker”, and “zorder”. Other field are ignored and will result in a user warning.
Altair-based visualizations[#](#module-mesa.visualization.components.altair_components "Link to this heading")
---------------------------------------------------------------------------------------------------------------
Altair based solara components for visualization mesa spaces.
make\_space\_altair(_\*args_, _\*\*kwargs_)[\[source\]](../_modules/mesa/visualization/components/altair_components.html#make_space_altair)
[#](#mesa.visualization.components.altair_components.make_space_altair "Link to this definition")
make\_altair\_space(_agent\_portrayal_, _propertylayer\_portrayal\=None_, _post\_process\=None_, _\*\*space\_drawing\_kwargs_)[\[source\]](../_modules/mesa/visualization/components/altair_components.html#make_altair_space)
[#](#mesa.visualization.components.altair_components.make_altair_space "Link to this definition")
Create an Altair-based space visualization component.
Parameters:
* **agent\_portrayal** – Function to portray agents.
* **propertylayer\_portrayal** – Dictionary of PropertyLayer portrayal specifications
* **post\_process** – A user specified callable that will be called with the Chart instance from Altair. Allows for fine tuning plots (e.g., control ticks)
* **space\_drawing\_kwargs** – not yet implemented
`agent_portrayal` is called with an agent and should return a dict. Valid fields in this dict are “color”, “size”, “marker”, and “zorder”. Other field are ignored and will result in a user warning.
Returns:
A function that creates a SpaceMatplotlib component
Return type:
function
chart\_property\_layers(_space_, _propertylayer\_portrayal_, _chart\_width_, _chart\_height_)[\[source\]](../_modules/mesa/visualization/components/altair_components.html#chart_property_layers)
[#](#mesa.visualization.components.altair_components.chart_property_layers "Link to this definition")
Creates Property Layers in the Altair Components.
Parameters:
* **space** – the ContinuousSpace instance
* **propertylayer\_portrayal** – Dictionary of PropertyLayer portrayal specifications
* **chart\_width** – width of the agent chart to maintain consistency with the property charts
* **chart\_height** – height of the agent chart to maintain consistency with the property charts
* **agent\_chart** – the agent chart to layer with the property layers on the grid
Returns:
Altair Chart
Command Console[#](#module-mesa.visualization.command_console "Link to this heading")
--------------------------------------------------------------------------------------
A command console interface for interactive Python code execution in the browser.
This module provides a set of classes and functions to create an interactive Python console that can be embedded in a web browser. It supports command history, multi-line code blocks, and special commands for console management.
Notes
* The console supports multi-line code blocks with proper indentation
* Output is captured and displayed with appropriate formatting
* Error messages are displayed in red with distinct styling
* The console maintains a history of commands and their outputs
_class_ ConsoleEntry(_command: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _output: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
\= ''_, _is\_error: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _is\_continuation: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_)[\[source\]](../_modules/mesa/visualization/command_console.html#ConsoleEntry)
[#](#mesa.visualization.command_console.ConsoleEntry "Link to this definition")
Bases: [`object`](https://docs.python.org/3/library/functions.html#object "(in Python v3.13)")
A class to store command console entries.
command[#](#mesa.visualization.command_console.ConsoleEntry.command "Link to this definition")
The command entered
Type:
[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
output[#](#mesa.visualization.command_console.ConsoleEntry.output "Link to this definition")
The output of the command
Type:
[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
is\_error[#](#mesa.visualization.command_console.ConsoleEntry.is_error "Link to this definition")
Whether the entry represents an error
Type:
[bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
is\_continuation[#](#mesa.visualization.command_console.ConsoleEntry.is_continuation "Link to this definition")
Whether the entry is a continuation of previous command
Type:
[bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
command_: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_[#](#id0 "Link to this definition")
output_: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_ _\= ''_[#](#id1 "Link to this definition")
is\_error_: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_ _\= False_[#](#id2 "Link to this definition")
is\_continuation_: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_ _\= False_[#](#id3 "Link to this definition")
_class_ CaptureOutput[\[source\]](../_modules/mesa/visualization/command_console.html#CaptureOutput)
[#](#mesa.visualization.command_console.CaptureOutput "Link to this definition")
Bases: [`object`](https://docs.python.org/3/library/functions.html#object "(in Python v3.13)")
A context manager for capturing stdout and stderr output.
This class provides a way to capture output that would normally be printed to stdout and stderr during the execution of code within its context.
Initialize the CaptureOutput context manager with empty string buffers.
get\_output()[\[source\]](../_modules/mesa/visualization/command_console.html#CaptureOutput.get_output)
[#](#mesa.visualization.command_console.CaptureOutput.get_output "Link to this definition")
Retrieve and clear the captured output.
Returns:
A pair of strings (stdout\_output, stderr\_output)
Return type:
[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
_class_ InteractiveConsole(_locals\_dict\=None_)[\[source\]](../_modules/mesa/visualization/command_console.html#InteractiveConsole)
[#](#mesa.visualization.command_console.InteractiveConsole "Link to this definition")
Bases: [`InteractiveConsole`](https://docs.python.org/3/library/code.html#code.InteractiveConsole "(in Python v3.13)")
A custom interactive Python console with output capturing capabilities.
This class extends code.InteractiveConsole to provide output capturing functionality when executing Python code interactively.
Parameters:
**locals\_dict** ([_dict_](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
_,_ _optional_) – Dictionary of local variables. Defaults to None.
Initialize the InteractiveConsole with the provided locals dictionary.
push(_line_)[\[source\]](../_modules/mesa/visualization/command_console.html#InteractiveConsole.push)
[#](#mesa.visualization.command_console.InteractiveConsole.push "Link to this definition")
Push a line to the command interpreter and execute it.
This method captures the output of the executed command and returns both the ‘more’ flag and the captured output.
Parameters:
**line** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
) – The line of code to be executed.
Returns:
A tuple containing:
* more (bool): Flag indicating if more input is needed
* str: The captured output from executing the command
Return type:
[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
_class_ ConsoleManager(_model\=None_, _additional\_imports\=None_)[\[source\]](../_modules/mesa/visualization/command_console.html#ConsoleManager)
[#](#mesa.visualization.command_console.ConsoleManager "Link to this definition")
Bases: [`object`](https://docs.python.org/3/library/functions.html#object "(in Python v3.13)")
A console manager for executing Python code interactively.
This class provides functionality to execute Python code in an interactive console environment, maintain command history, and handle multi-line code blocks.
locals\_dict[#](#mesa.visualization.command_console.ConsoleManager.locals_dict "Link to this definition")
Dictionary containing local variables available to the console
Type:
[dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
console[#](#mesa.visualization.command_console.ConsoleManager.console "Link to this definition")
Python’s interactive console instance
Type:
[InteractiveConsole](#mesa.visualization.command_console.InteractiveConsole "mesa.visualization.command_console.InteractiveConsole")
buffer[#](#mesa.visualization.command_console.ConsoleManager.buffer "Link to this definition")
Buffer for storing multi-line code blocks
Type:
[list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
history[#](#mesa.visualization.command_console.ConsoleManager.history "Link to this definition")
List of console entries containing commands and their outputs
Type:
[list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[ConsoleEntry](#mesa.visualization.command_console.ConsoleEntry "mesa.visualization.command_console.ConsoleEntry")\
\]
Special Commands:
1. history : Shows the command history
2. cls : Clears the console screen
3. tips : Shows available console commands and usage tips
Example
\>>> console \= ConsoleManager(model\=my\_model)
\>>> console.execute\_code("print('hello world')", set\_input\_callback)
Initialize the console manager with the provided model and imports.
execute\_code(_code\_line: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _set\_input\_text: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
\[\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
\], [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")\
\]_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/visualization/command_console.html#ConsoleManager.execute_code)
[#](#mesa.visualization.command_console.ConsoleManager.execute_code "Link to this definition")
Execute the provided code line and update the console history.
clear\_console() → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/visualization/command_console.html#ConsoleManager.clear_console)
[#](#mesa.visualization.command_console.ConsoleManager.clear_console "Link to this definition")
Clear the console history and reset the console state.
get\_entries() → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[ConsoleEntry](#mesa.visualization.command_console.ConsoleEntry "mesa.visualization.command_console.ConsoleEntry")\
\][\[source\]](../_modules/mesa/visualization/command_console.html#ConsoleManager.get_entries)
[#](#mesa.visualization.command_console.ConsoleManager.get_entries "Link to this definition")
Get the list of console entries.
prev\_command(_current\_text: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _set\_input\_text: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
\[\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
\], [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")\
\]_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/visualization/command_console.html#ConsoleManager.prev_command)
[#](#mesa.visualization.command_console.ConsoleManager.prev_command "Link to this definition")
Navigate to previous command in history.
next\_command(_set\_input\_text: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
\[\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
\], [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")\
\]_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/visualization/command_console.html#ConsoleManager.next_command)
[#](#mesa.visualization.command_console.ConsoleManager.next_command "Link to this definition")
Navigate to next command in history.
format\_command\_html(_entry_)[\[source\]](../_modules/mesa/visualization/command_console.html#format_command_html)
[#](#mesa.visualization.command_console.format_command_html "Link to this definition")
Format the command part of a console entry as HTML.
format\_output\_html(_entry_)[\[source\]](../_modules/mesa/visualization/command_console.html#format_output_html)
[#](#mesa.visualization.command_console.format_output_html "Link to this definition")
Format the output part of a console entry as HTML.
On this page
### This Page
* [Show Source](../_sources/apis/visualization.md.txt)
---
# Demographic Prisoner’s Dilemma on a Grid — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Demographic Prisoner’s Dilemma on a Grid[#](#demographic-prisoner-s-dilemma-on-a-grid "Link to this heading")
==============================================================================================================
Summary[#](#summary "Link to this heading")
--------------------------------------------
The Demographic Prisoner’s Dilemma is a family of variants on the classic two-player \[Prisoner’s Dilemma\]. The model consists of agents, each with a strategy of either Cooperate or Defect. Each agent’s payoff is based on its strategy and the strategies of its spatial neighbors. After each step of the model, the agents adopt the strategy of their neighbor with the highest total score.
The model payoff table is:
| | Cooperate | Defect |
| --- | --- | --- |
| **Cooperate** | 1, 1 | 0, D |
| **Defect** | D, 0 | 0, 0 |
Where _D_ is the defection bonus, generally set higher than 1. In these runs, the defection bonus is set to $D=1.6$.
The Demographic Prisoner’s Dilemma demonstrates how simple rules can lead to the emergence of widespread cooperation, despite the Defection strategy dominating each individual interaction game. However, it is also interesting for another reason: it is known to be sensitive to the activation regime employed in it.
How to Run[#](#how-to-run "Link to this heading")
--------------------------------------------------
### Web based model simulation[#](#web-based-model-simulation "Link to this heading")
To run the model interactively, run `solara run app.py` in this directory.
### Jupyter Notebook[#](#jupyter-notebook "Link to this heading")
Launch the `Demographic Prisoner's Dilemma Activation Schedule.ipynb` notebook and run the code.
Files[#](#files "Link to this heading")
----------------------------------------
* `agents.py`: contains the agent class.
* `model.py`: contains the model class; the model takes a `activation_order` string as an argument, which determines in which order agents are activated: Sequential, Random or Simultaneous.
* `app.py`: contains the interactive visualization server.
* `Demographic Prisoner's Dilemma Activation Schedule.ipynb`: Jupyter Notebook for running the scheduling experiment. This runs the model three times, one for each activation type, and demonstrates how the activation regime drives the model to different outcomes.
Further Reading[#](#further-reading "Link to this heading")
------------------------------------------------------------
This model is adapted from:
Wilensky, U. (2002). NetLogo PD Basic Evolutionary model. http://ccl.northwestern.edu/netlogo/models/PDBasicEvolutionary. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
The Demographic Prisoner’s Dilemma originates from:
[Epstein, J. Zones of Cooperation in Demographic Prisoner’s Dilemma. 1998.](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.8.8629&rep=rep1&type=pdf)
Agents[#](#agents "Link to this heading")
------------------------------------------
from mesa.discrete\_space import CellAgent
class PDAgent(CellAgent):
"""Agent member of the iterated, spatial prisoner's dilemma model."""
def \_\_init\_\_(self, model, starting\_move\=None, cell\=None):
"""
Create a new Prisoner's Dilemma agent.
Args:
model: model instance
starting\_move: If provided, determines the agent's initial state:
C(ooperating) or D(efecting). Otherwise, random.
"""
super().\_\_init\_\_(model)
self.score \= 0
self.cell \= cell
if starting\_move:
self.move \= starting\_move
else:
self.move \= self.random.choice(\["C", "D"\])
self.next\_move \= None
@property
def is\_cooroperating(self):
return self.move \== "C"
def step(self):
"""Get the best neighbor's move, and change own move accordingly
if better than own score."""
\# neighbors = self.model.grid.get\_neighbors(self.pos, True, include\_center=True)
neighbors \= \[\*list(self.cell.neighborhood.agents), self\]
best\_neighbor \= max(neighbors, key\=lambda a: a.score)
self.next\_move \= best\_neighbor.move
if self.model.activation\_order != "Simultaneous":
self.advance()
def advance(self):
self.move \= self.next\_move
self.score += self.increment\_score()
def increment\_score(self):
neighbors \= self.cell.neighborhood.agents
if self.model.activation\_order \== "Simultaneous":
moves \= \[neighbor.next\_move for neighbor in neighbors\]
else:
moves \= \[neighbor.move for neighbor in neighbors\]
return sum(self.model.payoff\[(self.move, move)\] for move in moves)
Model[#](#model "Link to this heading")
----------------------------------------
import mesa
from mesa.discrete\_space import OrthogonalMooreGrid
from mesa.examples.advanced.pd\_grid.agents import PDAgent
class PdGrid(mesa.Model):
"""Model class for iterated, spatial prisoner's dilemma model."""
activation\_regimes \= \["Sequential", "Random", "Simultaneous"\]
\# This dictionary holds the payoff for this agent,
\# keyed on: (my\_move, other\_move)
payoff \= {("C", "C"): 1, ("C", "D"): 0, ("D", "C"): 1.6, ("D", "D"): 0}
def \_\_init\_\_(
self, width\=50, height\=50, activation\_order\="Random", payoffs\=None, seed\=None
):
"""
Create a new Spatial Prisoners' Dilemma Model.
Args:
width, height: Grid size. There will be one agent per grid cell.
activation\_order: Can be "Sequential", "Random", or "Simultaneous".
Determines the agent activation regime.
payoffs: (optional) Dictionary of (move, neighbor\_move) payoffs.
"""
super().\_\_init\_\_(seed\=seed)
self.activation\_order \= activation\_order
self.grid \= OrthogonalMooreGrid((width, height), torus\=True, random\=self.random)
if payoffs is not None:
self.payoff \= payoffs
PDAgent.create\_agents(
self, len(self.grid.all\_cells.cells), cell\=self.grid.all\_cells.cells
)
self.datacollector \= mesa.DataCollector(
{
"Cooperating\_Agents": lambda m: len(
\[a for a in m.agents if a.move \== "C"\]
)
}
)
self.running \= True
self.datacollector.collect(self)
def step(self):
\# Activate all agents, based on the activation regime
match self.activation\_order:
case "Sequential":
self.agents.do("step")
case "Random":
self.agents.shuffle\_do("step")
case "Simultaneous":
self.agents.do("step")
self.agents.do("advance")
case \_:
raise ValueError(f"Unknown activation order: {self.activation\_order}")
\# Collect data
self.datacollector.collect(self)
def run(self, n):
"""Run the model for n steps."""
for \_ in range(n):
self.step()
App[#](#app "Link to this heading")
------------------------------------
"""
Solara-based visualization for the Spatial Prisoner's Dilemma Model.
"""
from mesa.examples.advanced.pd\_grid.model import PdGrid
from mesa.visualization import (
Slider,
SolaraViz,
make\_plot\_component,
make\_space\_component,
)
def pd\_agent\_portrayal(agent):
"""
Portrayal function for rendering PD agents in the visualization.
"""
return {
"color": "blue" if agent.move \== "C" else "red",
"marker": "s", \# square marker
"size": 25,
}
\# Model parameters
model\_params \= {
"seed": {
"type": "InputText",
"value": 42,
"label": "Random Seed",
},
"width": Slider("Grid Width", value\=50, min\=10, max\=100, step\=1),
"height": Slider("Grid Height", value\=50, min\=10, max\=100, step\=1),
"activation\_order": {
"type": "Select",
"value": "Random",
"values": PdGrid.activation\_regimes,
"label": "Activation Regime",
},
}
\# Create grid visualization component using Altair
grid\_viz \= make\_space\_component(agent\_portrayal\=pd\_agent\_portrayal)
\# Create plot for tracking cooperating agents over time
plot\_component \= make\_plot\_component("Cooperating\_Agents")
\# Initialize model
initial\_model \= PdGrid()
\# Create visualization with all components
page \= SolaraViz(
model\=initial\_model,
components\=\[grid\_viz, plot\_component\],
model\_params\=model\_params,
name\="Spatial Prisoner's Dilemma",
)
page \# noqa B018
On this page
### This Page
* [Show Source](../../_sources/examples/advanced/pd_grid.md.txt)
---
# Discrete Space — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Discrete Space[#](#module-mesa.discrete_space.__init__ "Link to this heading")
===============================================================================
Cell spaces for active, property-rich spatial modeling in Mesa.
Cell spaces extend Mesa’s spatial modeling capabilities by making the space itself active - each position (cell) can have properties and behaviors rather than just containing agents. This enables more sophisticated environmental modeling and agent-environment interactions.
Key components: - Cells: Active positions that can have properties and contain agents - CellAgents: Agents that understand how to interact with cells - Spaces: Different cell organization patterns (grids, networks, etc.) - PropertyLayers: Efficient property storage and manipulation
This is particularly useful for models where the environment plays an active role, like resource growth, pollution diffusion, or infrastructure networks. The cell space system is experimental and under active development.
_class_ Cell(_coordinate: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, ...\]_, _capacity: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _random: [Random](https://docs.python.org/3/library/random.html#random.Random "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_)[\[source\]](../_modules/mesa/discrete_space/cell.html#Cell)
[#](#mesa.discrete_space.__init__.Cell "Link to this definition")
The cell represents a position in a discrete space.
coordinate[#](#mesa.discrete_space.__init__.Cell.coordinate "Link to this definition")
the position of the cell in the discrete space
Type:
Tuple\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]
agents[#](#mesa.discrete_space.__init__.Cell.agents "Link to this definition")
the agents occupying the cell
Type:
List\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\]
capacity[#](#mesa.discrete_space.__init__.Cell.capacity "Link to this definition")
the maximum number of agents that can simultaneously occupy the cell
Type:
[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
random[#](#mesa.discrete_space.__init__.Cell.random "Link to this definition")
the random number generator
Type:
Random
Initialise the cell.
Parameters:
* **coordinate** – coordinates of the cell
* **capacity** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – the capacity of the cell. If None, the capacity is infinite
* **random** (_Random_) – the random number generator to use
add\_agent(_agent: [CellAgent](#mesa.discrete_space.cell_agent.CellAgent "mesa.discrete_space.cell_agent.CellAgent")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/discrete_space/cell.html#Cell.add_agent)
[#](#mesa.discrete_space.__init__.Cell.add_agent "Link to this definition")
Adds an agent to the cell.
Parameters:
**agent** ([_CellAgent_](#mesa.discrete_space.__init__.CellAgent "mesa.discrete_space.__init__.CellAgent")
) – agent to add to this Cell
_property_ agents_: [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[CellAgent](#mesa.discrete_space.cell_agent.CellAgent "mesa.discrete_space.cell_agent.CellAgent")\
\]_[#](#id0 "Link to this definition")
Returns a list of the agents occupying the cell.
connect(_other: [Cell](#mesa.discrete_space.cell.Cell "mesa.discrete_space.cell.Cell")
_, _key: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, ...\] | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/discrete_space/cell.html#Cell.connect)
[#](#mesa.discrete_space.__init__.Cell.connect "Link to this definition")
Connects this cell to another cell.
Parameters:
* **other** ([_Cell_](#mesa.discrete_space.__init__.Cell "mesa.discrete_space.__init__.Cell")
) – other cell to connect to
* **key** (_Tuple__\[_[_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
_,_ _...__\]_) – key for the connection. Should resemble a relative coordinate
disconnect(_other: [Cell](#mesa.discrete_space.cell.Cell "mesa.discrete_space.cell.Cell")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/discrete_space/cell.html#Cell.disconnect)
[#](#mesa.discrete_space.__init__.Cell.disconnect "Link to this definition")
Disconnects this cell from another cell.
Parameters:
**other** ([_Cell_](#mesa.discrete_space.__init__.Cell "mesa.discrete_space.__init__.Cell")
) – other cell to remove from connections
get\_neighborhood(_radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_) → [CellCollection](#mesa.discrete_space.cell_collection.CellCollection "mesa.discrete_space.cell_collection.CellCollection")
\[[Cell](#mesa.discrete_space.cell.Cell "mesa.discrete_space.cell.Cell")\
\][\[source\]](../_modules/mesa/discrete_space/cell.html#Cell.get_neighborhood)
[#](#mesa.discrete_space.__init__.Cell.get_neighborhood "Link to this definition")
Returns a list of all neighboring cells for the given radius.
For getting the direct neighborhood (i.e., radius=1) you can also use the neighborhood property.
Parameters:
* **radius** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – the radius of the neighborhood
* **include\_center** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
) – include the center of the neighborhood
Returns:
a list of all neighboring cells
_property_ is\_empty_: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_[#](#mesa.discrete_space.__init__.Cell.is_empty "Link to this definition")
Returns a bool of the contents of a cell.
_property_ is\_full_: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_[#](#mesa.discrete_space.__init__.Cell.is_full "Link to this definition")
Returns a bool of the contents of a cell.
_property_ neighborhood_: [CellCollection](#mesa.discrete_space.cell_collection.CellCollection "mesa.discrete_space.cell_collection.CellCollection")
\[[Cell](#mesa.discrete_space.cell.Cell "mesa.discrete_space.cell.Cell")\
\]_[\[source\]](../_modules/mesa/discrete_space/cell.html#Cell.neighborhood)
[#](#mesa.discrete_space.__init__.Cell.neighborhood "Link to this definition")
Returns the direct neighborhood of the cell.
This is equivalent to cell.get\_neighborhood(radius=1)
remove\_agent(_agent: [CellAgent](#mesa.discrete_space.cell_agent.CellAgent "mesa.discrete_space.cell_agent.CellAgent")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/discrete_space/cell.html#Cell.remove_agent)
[#](#mesa.discrete_space.__init__.Cell.remove_agent "Link to this definition")
Removes an agent from the cell.
Parameters:
**agent** ([_CellAgent_](#mesa.discrete_space.__init__.CellAgent "mesa.discrete_space.__init__.CellAgent")
) – agent to remove from this cell
_class_ CellAgent(_model: [Model](../mesa.html#mesa.model.Model "mesa.model.Model")
_, _\*args_, _\*\*kwargs_)[\[source\]](../_modules/mesa/discrete_space/cell_agent.html#CellAgent)
[#](#mesa.discrete_space.__init__.CellAgent "Link to this definition")
Cell Agent is an extension of the Agent class and adds behavior for moving in discrete spaces.
cell[#](#mesa.discrete_space.__init__.CellAgent.cell "Link to this definition")
The cell the agent is currently in.
Type:
[Cell](#mesa.discrete_space.__init__.Cell "mesa.discrete_space.__init__.Cell")
Create a new agent.
Parameters:
* **model** ([_Model_](../mesa.html#mesa.model.Model "mesa.model.Model")
) – The model instance in which the agent exists.
* **args** – passed on to super
* **kwargs** – passed on to super
Notes
to make proper use of python’s super, in each class remove the arguments and keyword arguments you need and pass on the rest to super
remove()[\[source\]](../_modules/mesa/discrete_space/cell_agent.html#CellAgent.remove)
[#](#mesa.discrete_space.__init__.CellAgent.remove "Link to this definition")
Remove the agent from the model.
_class_ CellCollection(_cells: Mapping\[T, [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")\
\[[CellAgent](#mesa.discrete_space.__init__.CellAgent "mesa.discrete_space.__init__.CellAgent")\
\]\] | Iterable\[T\]_, _random: Random | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_)[\[source\]](../_modules/mesa/discrete_space/cell_collection.html#CellCollection)
[#](#mesa.discrete_space.__init__.CellCollection "Link to this definition")
An immutable collection of cells.
cells[\[source\]](../_modules/mesa/discrete_space/cell_collection.html#CellCollection.cells)
[#](#mesa.discrete_space.__init__.CellCollection.cells "Link to this definition")
The list of cells this collection represents
Type:
List\[[Cell](#mesa.discrete_space.__init__.Cell "mesa.discrete_space.__init__.Cell")\
\]
agents[#](#mesa.discrete_space.__init__.CellCollection.agents "Link to this definition")
List of agents occupying the cells in this collection
Type:
List\[[CellAgent](#mesa.discrete_space.__init__.CellAgent "mesa.discrete_space.__init__.CellAgent")\
\]
random[#](#mesa.discrete_space.__init__.CellCollection.random "Link to this definition")
The random number generator
Type:
Random
Notes
A UserWarning is issued if random=None. You can resolve this warning by explicitly passing a random number generator. In most cases, this will be the seeded random number generator in the model. So, you would do random=self.random in a Model or Agent instance.
Initialize a CellCollection.
Parameters:
* **cells** – cells to add to the collection
* **random** – a seeded random number generator.
select(_filter\_func: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
\[\[T\], [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")\
\] | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _at\_most: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
\= inf_)[\[source\]](../_modules/mesa/discrete_space/cell_collection.html#CellCollection.select)
[#](#mesa.discrete_space.__init__.CellCollection.select "Link to this definition")
Select cells based on filter function.
Parameters:
* **filter\_func** – filter function
* **at\_most** – The maximum amount of cells to select. Defaults to infinity. - If an integer, at most the first number of matching cells is selected. - If a float between 0 and 1, at most that fraction of original number of cells
Returns:
CellCollection
select\_random\_agent() → [CellAgent](#mesa.discrete_space.__init__.CellAgent "mesa.discrete_space.__init__.CellAgent")
[\[source\]](../_modules/mesa/discrete_space/cell_collection.html#CellCollection.select_random_agent)
[#](#mesa.discrete_space.__init__.CellCollection.select_random_agent "Link to this definition")
Select a random agent.
Returns:
CellAgent instance
select\_random\_cell() → T[\[source\]](../_modules/mesa/discrete_space/cell_collection.html#CellCollection.select_random_cell)
[#](#mesa.discrete_space.__init__.CellCollection.select_random_cell "Link to this definition")
Select a random cell.
_class_ DiscreteSpace(_capacity: int | None \= None_, _cell\_klass: type\[~mesa.discrete\_space.discrete\_space.T\] \= _, _random: ~random.Random | None \= None_)[\[source\]](../_modules/mesa/discrete_space/discrete_space.html#DiscreteSpace)
[#](#mesa.discrete_space.__init__.DiscreteSpace "Link to this definition")
Base class for all discrete spaces.
capacity[#](#mesa.discrete_space.__init__.DiscreteSpace.capacity "Link to this definition")
The capacity of the cells in the discrete space
Type:
[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
all\_cells[\[source\]](../_modules/mesa/discrete_space/discrete_space.html#DiscreteSpace.all_cells)
[#](#mesa.discrete_space.__init__.DiscreteSpace.all_cells "Link to this definition")
The cells composing the discrete space
Type:
[CellCollection](#mesa.discrete_space.__init__.CellCollection "mesa.discrete_space.__init__.CellCollection")
random[#](#mesa.discrete_space.__init__.DiscreteSpace.random "Link to this definition")
The random number generator
Type:
Random
cell\_klass[#](#mesa.discrete_space.__init__.DiscreteSpace.cell_klass "Link to this definition")
the type of cell class
Type:
Type
empties[#](#mesa.discrete_space.__init__.DiscreteSpace.empties "Link to this definition")
collection of all cells that are empty
Type:
[CellCollection](#mesa.discrete_space.__init__.CellCollection "mesa.discrete_space.__init__.CellCollection")
property\_layers[#](#mesa.discrete_space.__init__.DiscreteSpace.property_layers "Link to this definition")
the property layers of the discrete space
Type:
[dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
, [PropertyLayer](#mesa.discrete_space.__init__.PropertyLayer "mesa.discrete_space.__init__.PropertyLayer")\
\]
Notes
A UserWarning is issued if random=None. You can resolve this warning by explicitly passing a random number generator. In most cases, this will be the seeded random number generator in the model. So, you would do random=self.random in a Model or Agent instance.
Instantiate a DiscreteSpace.
Parameters:
* **capacity** – capacity of cells
* **cell\_klass** – base class for all cells
* **random** – random number generator
_property_ agents_: [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
_[#](#mesa.discrete_space.__init__.DiscreteSpace.agents "Link to this definition")
Return an AgentSet with the agents in the space.
_property_ all\_cells[\[source\]](../_modules/mesa/discrete_space/discrete_space.html#DiscreteSpace.all_cells)
[#](#id1 "Link to this definition")
Return all cells in space.
_property_ empties_: [CellCollection](#mesa.discrete_space.cell_collection.CellCollection "mesa.discrete_space.cell_collection.CellCollection")
\[T\]_[#](#id2 "Link to this definition")
Return all empty in spaces.
select\_random\_empty\_cell() → T[\[source\]](../_modules/mesa/discrete_space/discrete_space.html#DiscreteSpace.select_random_empty_cell)
[#](#mesa.discrete_space.__init__.DiscreteSpace.select_random_empty_cell "Link to this definition")
Select random empty cell.
_class_ FixedAgent(_model: [Model](../mesa.html#mesa.model.Model "mesa.model.Model")
_, _\*args_, _\*\*kwargs_)[\[source\]](../_modules/mesa/discrete_space/cell_agent.html#FixedAgent)
[#](#mesa.discrete_space.__init__.FixedAgent "Link to this definition")
A patch in a 2D grid.
Create a new agent.
Parameters:
* **model** ([_Model_](../mesa.html#mesa.model.Model "mesa.model.Model")
) – The model instance in which the agent exists.
* **args** – passed on to super
* **kwargs** – passed on to super
Notes
to make proper use of python’s super, in each class remove the arguments and keyword arguments you need and pass on the rest to super
remove()[\[source\]](../_modules/mesa/discrete_space/cell_agent.html#FixedAgent.remove)
[#](#mesa.discrete_space.__init__.FixedAgent.remove "Link to this definition")
Remove the agent from the model.
_class_ Grid(_dimensions: ~collections.abc.Sequence\[int\], torus: bool \= False, capacity: float | None \= None, random: ~random.Random | None \= None, cell\_klass: type\[~mesa.discrete\_space.grid.T\] \= _)[\[source\]](../_modules/mesa/discrete_space/grid.html#Grid)
[#](#mesa.discrete_space.__init__.Grid "Link to this definition")
Base class for all grid classes.
dimensions[#](#mesa.discrete_space.__init__.Grid.dimensions "Link to this definition")
the dimensions of the grid
Type:
Sequence\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]
torus[#](#mesa.discrete_space.__init__.Grid.torus "Link to this definition")
whether the grid is a torus
Type:
[bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
capacity[#](#mesa.discrete_space.__init__.Grid.capacity "Link to this definition")
the capacity of a grid cell
Type:
[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
random[#](#mesa.discrete_space.__init__.Grid.random "Link to this definition")
the random number generator
Type:
Random
\_try\_random[#](#mesa.discrete_space.__init__.Grid._try_random "Link to this definition")
whether to get empty cell be repeatedly trying random cell
Type:
[bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
Notes
width and height are accessible via properties, higher dimensions can be retrieved via dimensions
Initialise the grid class.
Parameters:
* **dimensions** – the dimensions of the space
* **torus** – whether the space wraps
* **capacity** – capacity of the grid cell
* **random** – a random number generator
* **cell\_klass** – the base class to use for the cells
_property_ height_: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_[#](#mesa.discrete_space.__init__.Grid.height "Link to this definition")
Convenience access to the height of the grid.
select\_random\_empty\_cell() → T[\[source\]](../_modules/mesa/discrete_space/grid.html#Grid.select_random_empty_cell)
[#](#mesa.discrete_space.__init__.Grid.select_random_empty_cell "Link to this definition")
Select random empty cell.
_property_ width_: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_[#](#mesa.discrete_space.__init__.Grid.width "Link to this definition")
Convenience access to the width of the grid.
_class_ Grid2DMovingAgent(_model: [Model](../mesa.html#mesa.model.Model "mesa.model.Model")
_, _\*args_, _\*\*kwargs_)[\[source\]](../_modules/mesa/discrete_space/cell_agent.html#Grid2DMovingAgent)
[#](#mesa.discrete_space.__init__.Grid2DMovingAgent "Link to this definition")
Mixin for moving agents in 2D grids.
Create a new agent.
Parameters:
* **model** ([_Model_](../mesa.html#mesa.model.Model "mesa.model.Model")
) – The model instance in which the agent exists.
* **args** – passed on to super
* **kwargs** – passed on to super
Notes
to make proper use of python’s super, in each class remove the arguments and keyword arguments you need and pass on the rest to super
move(_direction: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _distance: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_)[\[source\]](../_modules/mesa/discrete_space/cell_agent.html#Grid2DMovingAgent.move)
[#](#mesa.discrete_space.__init__.Grid2DMovingAgent.move "Link to this definition")
Move the agent in a cardinal direction.
Parameters:
* **direction** – The cardinal direction to move in.
* **distance** – The distance to move.
_class_ HexGrid(_dimensions: ~collections.abc.Sequence\[int\], torus: bool \= False, capacity: float | None \= None, random: ~random.Random | None \= None, cell\_klass: type\[~mesa.discrete\_space.grid.T\] \= _)[\[source\]](../_modules/mesa/discrete_space/grid.html#HexGrid)
[#](#mesa.discrete_space.__init__.HexGrid "Link to this definition")
A Grid with hexagonal tilling of the space.
Initialise the grid class.
Parameters:
* **dimensions** – the dimensions of the space
* **torus** – whether the space wraps
* **capacity** – capacity of the grid cell
* **random** – a random number generator
* **cell\_klass** – the base class to use for the cells
_class_ Network(_G: ~typing.Any_, _capacity: int | None \= None_, _random: ~random.Random | None \= None_, _cell\_klass: type\[~mesa.discrete\_space.cell.Cell\] \= _)[\[source\]](../_modules/mesa/discrete_space/network.html#Network)
[#](#mesa.discrete_space.__init__.Network "Link to this definition")
A networked discrete space.
A Networked grid.
Parameters:
* **G** – a NetworkX Graph instance.
* **capacity** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – the capacity of the cell
* **random** (_Random_) – a random number generator
* **cell\_klass** ([_type_](https://docs.python.org/3/library/functions.html#type "(in Python v3.13)")
_\[_[_Cell_](#mesa.discrete_space.__init__.Cell "mesa.discrete_space.__init__.Cell")\
_\]_) – The base Cell class to use in the Network
_class_ OrthogonalMooreGrid(_dimensions: ~collections.abc.Sequence\[int\], torus: bool \= False, capacity: float | None \= None, random: ~random.Random | None \= None, cell\_klass: type\[~mesa.discrete\_space.grid.T\] \= _)[\[source\]](../_modules/mesa/discrete_space/grid.html#OrthogonalMooreGrid)
[#](#mesa.discrete_space.__init__.OrthogonalMooreGrid "Link to this definition")
Grid where cells are connected to their 8 neighbors.
Example for two dimensions: directions = \[\
\
> (-1, -1), (-1, 0), (-1, 1), ( 0, -1), ( 0, 1), ( 1, -1), ( 1, 0), ( 1, 1),\
\
\]
Initialise the grid class.
Parameters:
* **dimensions** – the dimensions of the space
* **torus** – whether the space wraps
* **capacity** – capacity of the grid cell
* **random** – a random number generator
* **cell\_klass** – the base class to use for the cells
_class_ OrthogonalVonNeumannGrid(_dimensions: ~collections.abc.Sequence\[int\], torus: bool \= False, capacity: float | None \= None, random: ~random.Random | None \= None, cell\_klass: type\[~mesa.discrete\_space.grid.T\] \= _)[\[source\]](../_modules/mesa/discrete_space/grid.html#OrthogonalVonNeumannGrid)
[#](#mesa.discrete_space.__init__.OrthogonalVonNeumannGrid "Link to this definition")
Grid where cells are connected to their 4 neighbors.
Example for two dimensions: directions = \[\
\
> > (0, -1),\
> \
> (-1, 0), ( 1, 0),\
> \
> (0, 1),\
\
\]
Initialise the grid class.
Parameters:
* **dimensions** – the dimensions of the space
* **torus** – whether the space wraps
* **capacity** – capacity of the grid cell
* **random** – a random number generator
* **cell\_klass** – the base class to use for the cells
_class_ PropertyLayer(_name: str, dimensions: ~collections.abc.Sequence\[int\], default\_value=0.0, dtype=_)[\[source\]](../_modules/mesa/discrete_space/property_layer.html#PropertyLayer)
[#](#mesa.discrete_space.__init__.PropertyLayer "Link to this definition")
A class representing a layer of properties in a two-dimensional grid.
Each cell in the grid can store a value of a specified data type.
name[#](#mesa.discrete_space.__init__.PropertyLayer.name "Link to this definition")
The name of the property layer.
dimensions[#](#mesa.discrete_space.__init__.PropertyLayer.dimensions "Link to this definition")
The width of the grid (number of columns).
data[#](#mesa.discrete_space.__init__.PropertyLayer.data "Link to this definition")
A NumPy array representing the grid data.
Initializes a new PropertyLayer instance.
Parameters:
* **name** – The name of the property layer.
* **dimensions** – the dimensions of the property layer.
* **default\_value** – The default value to initialize each cell in the grid. Should ideally be of the same type as specified by the dtype parameter.
* **dtype** (_data-type__,_ _optional_) – The desired data-type for the grid’s elements. Default is float.
Notes
A UserWarning is raised if the default\_value is not of a type compatible with dtype. The dtype parameter can accept both Python data types (like bool, int or float) and NumPy data types (like np.int64 or np.float64).
aggregate(_operation: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_)[\[source\]](../_modules/mesa/discrete_space/property_layer.html#PropertyLayer.aggregate)
[#](#mesa.discrete_space.__init__.PropertyLayer.aggregate "Link to this definition")
Perform an aggregate operation (e.g., sum, mean) on a property across all cells.
Parameters:
**operation** – A function to apply. Can be a lambda function or a NumPy ufunc.
_classmethod_ from\_data(_name: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _data: ndarray_)[\[source\]](../_modules/mesa/discrete_space/property_layer.html#PropertyLayer.from_data)
[#](#mesa.discrete_space.__init__.PropertyLayer.from_data "Link to this definition")
Create a property layer from a NumPy array.
Parameters:
* **name** – The name of the property layer.
* **data** – A NumPy array representing the grid data.
modify\_cells(_operation: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_, _value\=None_, _condition: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_)[\[source\]](../_modules/mesa/discrete_space/property_layer.html#PropertyLayer.modify_cells)
[#](#mesa.discrete_space.__init__.PropertyLayer.modify_cells "Link to this definition")
Modify cells using an operation, which can be a lambda function or a NumPy ufunc.
If a NumPy ufunc is used, an additional value should be provided.
Parameters:
* **operation** – A function to apply. Can be a lambda function or a NumPy ufunc.
* **value** – The value to be used if the operation is a NumPy ufunc. Ignored for lambda functions.
* **condition** – (Optional) A callable that returns a boolean array when applied to the data.
select\_cells(_condition: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_, _return\_list\=True_)[\[source\]](../_modules/mesa/discrete_space/property_layer.html#PropertyLayer.select_cells)
[#](#mesa.discrete_space.__init__.PropertyLayer.select_cells "Link to this definition")
Find cells that meet a specified condition using NumPy’s boolean indexing, in-place.
Parameters:
* **condition** – A callable that returns a boolean array when applied to the data.
* **return\_list** – (Optional) If True, return a list of (x, y) tuples. Otherwise, return a boolean array.
Returns:
A list of (x, y) tuples or a boolean array.
set\_cells(_value_, _condition: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_)[\[source\]](../_modules/mesa/discrete_space/property_layer.html#PropertyLayer.set_cells)
[#](#mesa.discrete_space.__init__.PropertyLayer.set_cells "Link to this definition")
Perform a batch update either on the entire grid or conditionally, in-place.
Parameters:
* **value** – The value to be used for the update.
* **condition** – (Optional) A callable that returns a boolean array when applied to the data.
_class_ VoronoiGrid(_centroids\_coordinates: ~collections.abc.Sequence\[~collections.abc.Sequence\[float\]\], capacity: float | None \= None, random: ~random.Random | None \= None, cell\_klass: type\[~mesa.discrete\_space.cell.Cell\] \= , capacity\_function: callable \= _)[\[source\]](../_modules/mesa/discrete_space/voronoi.html#VoronoiGrid)
[#](#mesa.discrete_space.__init__.VoronoiGrid "Link to this definition")
Voronoi meshed GridSpace.
A Voronoi Tessellation Grid.
Given a set of points, this class creates a grid where a cell is centered in each point, its neighbors are given by Voronoi Tessellation cells neighbors and the capacity by the polygon area.
Parameters:
* **centroids\_coordinates** – coordinates of centroids to build the tessellation space
* **capacity** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – capacity of the cells in the discrete space
* **random** (_Random_) – random number generator
* **cell\_klass** ([_type_](https://docs.python.org/3/library/functions.html#type "(in Python v3.13)")
_\[_[_Cell_](#mesa.discrete_space.__init__.Cell "mesa.discrete_space.__init__.Cell")\
_\]_) – type of cell class
* **capacity\_function** (_Callable_) – function to compute (int) capacity according to (float) area
Cells are positions in space that can have properties and contain agents.
A cell represents a location that can: - Have properties (like temperature or resources) - Track and limit the agents it contains - Connect to neighboring cells - Provide neighborhood information
Cells form the foundation of the cell space system, enabling rich spatial environments where both location properties and agent behaviors matter. They’re useful for modeling things like varying terrain, infrastructure capacity, or environmental conditions.
_class_ Cell(_coordinate: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, ...\]_, _capacity: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _random: [Random](https://docs.python.org/3/library/random.html#random.Random "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_)[\[source\]](../_modules/mesa/discrete_space/cell.html#Cell)
[#](#mesa.discrete_space.cell.Cell "Link to this definition")
The cell represents a position in a discrete space.
coordinate[#](#mesa.discrete_space.cell.Cell.coordinate "Link to this definition")
the position of the cell in the discrete space
Type:
Tuple\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]
agents[#](#mesa.discrete_space.cell.Cell.agents "Link to this definition")
the agents occupying the cell
Type:
List\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\]
capacity[#](#mesa.discrete_space.cell.Cell.capacity "Link to this definition")
the maximum number of agents that can simultaneously occupy the cell
Type:
[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
random[#](#mesa.discrete_space.cell.Cell.random "Link to this definition")
the random number generator
Type:
Random
Initialise the cell.
Parameters:
* **coordinate** – coordinates of the cell
* **capacity** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – the capacity of the cell. If None, the capacity is infinite
* **random** (_Random_) – the random number generator to use
connect(_other: [Cell](#mesa.discrete_space.cell.Cell "mesa.discrete_space.cell.Cell")
_, _key: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, ...\] | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/discrete_space/cell.html#Cell.connect)
[#](#mesa.discrete_space.cell.Cell.connect "Link to this definition")
Connects this cell to another cell.
Parameters:
* **other** ([_Cell_](#mesa.discrete_space.cell.Cell "mesa.discrete_space.cell.Cell")
) – other cell to connect to
* **key** (_Tuple__\[_[_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
_,_ _...__\]_) – key for the connection. Should resemble a relative coordinate
disconnect(_other: [Cell](#mesa.discrete_space.cell.Cell "mesa.discrete_space.cell.Cell")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/discrete_space/cell.html#Cell.disconnect)
[#](#mesa.discrete_space.cell.Cell.disconnect "Link to this definition")
Disconnects this cell from another cell.
Parameters:
**other** ([_Cell_](#mesa.discrete_space.cell.Cell "mesa.discrete_space.cell.Cell")
) – other cell to remove from connections
add\_agent(_agent: [CellAgent](#mesa.discrete_space.cell_agent.CellAgent "mesa.discrete_space.cell_agent.CellAgent")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/discrete_space/cell.html#Cell.add_agent)
[#](#mesa.discrete_space.cell.Cell.add_agent "Link to this definition")
Adds an agent to the cell.
Parameters:
**agent** ([_CellAgent_](#mesa.discrete_space.__init__.CellAgent "mesa.discrete_space.__init__.CellAgent")
) – agent to add to this Cell
remove\_agent(_agent: [CellAgent](#mesa.discrete_space.cell_agent.CellAgent "mesa.discrete_space.cell_agent.CellAgent")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/discrete_space/cell.html#Cell.remove_agent)
[#](#mesa.discrete_space.cell.Cell.remove_agent "Link to this definition")
Removes an agent from the cell.
Parameters:
**agent** ([_CellAgent_](#mesa.discrete_space.__init__.CellAgent "mesa.discrete_space.__init__.CellAgent")
) – agent to remove from this cell
_property_ is\_empty_: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_[#](#mesa.discrete_space.cell.Cell.is_empty "Link to this definition")
Returns a bool of the contents of a cell.
_property_ is\_full_: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_[#](#mesa.discrete_space.cell.Cell.is_full "Link to this definition")
Returns a bool of the contents of a cell.
_property_ agents_: [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[CellAgent](#mesa.discrete_space.cell_agent.CellAgent "mesa.discrete_space.cell_agent.CellAgent")\
\]_[#](#id3 "Link to this definition")
Returns a list of the agents occupying the cell.
_property_ neighborhood_: [CellCollection](#mesa.discrete_space.cell_collection.CellCollection "mesa.discrete_space.cell_collection.CellCollection")
\[[Cell](#mesa.discrete_space.cell.Cell "mesa.discrete_space.cell.Cell")\
\]_[\[source\]](../_modules/mesa/discrete_space/cell.html#Cell.neighborhood)
[#](#mesa.discrete_space.cell.Cell.neighborhood "Link to this definition")
Returns the direct neighborhood of the cell.
This is equivalent to cell.get\_neighborhood(radius=1)
get\_neighborhood(_radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_) → [CellCollection](#mesa.discrete_space.cell_collection.CellCollection "mesa.discrete_space.cell_collection.CellCollection")
\[[Cell](#mesa.discrete_space.cell.Cell "mesa.discrete_space.cell.Cell")\
\][\[source\]](../_modules/mesa/discrete_space/cell.html#Cell.get_neighborhood)
[#](#mesa.discrete_space.cell.Cell.get_neighborhood "Link to this definition")
Returns a list of all neighboring cells for the given radius.
For getting the direct neighborhood (i.e., radius=1) you can also use the neighborhood property.
Parameters:
* **radius** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – the radius of the neighborhood
* **include\_center** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
) – include the center of the neighborhood
Returns:
a list of all neighboring cells
Agents that understand how to exist in and move through cell spaces.
Provides specialized agent classes that handle cell occupation, movement, and proper registration: - CellAgent: Mobile agents that can move between cells - FixedAgent: Immobile agents permanently fixed to cells - Grid2DMovingAgent: Agents with grid-specific movement capabilities
These classes ensure consistent agent-cell relationships and proper state management as agents move through the space. They can be used directly or as examples for creating custom cell-aware agents.
_class_ HasCellProtocol(_\*args_, _\*\*kwargs_)[\[source\]](../_modules/mesa/discrete_space/cell_agent.html#HasCellProtocol)
[#](#mesa.discrete_space.cell_agent.HasCellProtocol "Link to this definition")
Protocol for discrete space cell holders.
_class_ HasCell[\[source\]](../_modules/mesa/discrete_space/cell_agent.html#HasCell)
[#](#mesa.discrete_space.cell_agent.HasCell "Link to this definition")
Descriptor for cell movement behavior.
_class_ BasicMovement[\[source\]](../_modules/mesa/discrete_space/cell_agent.html#BasicMovement)
[#](#mesa.discrete_space.cell_agent.BasicMovement "Link to this definition")
Mixin for moving agents in discrete space.
move\_to(_cell: [Cell](#mesa.discrete_space.__init__.Cell "mesa.discrete_space.__init__.Cell")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/discrete_space/cell_agent.html#BasicMovement.move_to)
[#](#mesa.discrete_space.cell_agent.BasicMovement.move_to "Link to this definition")
Move to a new cell.
move\_relative(_direction: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, ...\]_)[\[source\]](../_modules/mesa/discrete_space/cell_agent.html#BasicMovement.move_relative)
[#](#mesa.discrete_space.cell_agent.BasicMovement.move_relative "Link to this definition")
Move to a cell relative to the current cell.
Parameters:
**direction** – The direction to move in.
_class_ FixedCell[\[source\]](../_modules/mesa/discrete_space/cell_agent.html#FixedCell)
[#](#mesa.discrete_space.cell_agent.FixedCell "Link to this definition")
Mixin for agents that are fixed to a cell.
_class_ CellAgent(_model: [Model](../mesa.html#mesa.model.Model "mesa.model.Model")
_, _\*args_, _\*\*kwargs_)[\[source\]](../_modules/mesa/discrete_space/cell_agent.html#CellAgent)
[#](#mesa.discrete_space.cell_agent.CellAgent "Link to this definition")
Cell Agent is an extension of the Agent class and adds behavior for moving in discrete spaces.
cell[#](#mesa.discrete_space.cell_agent.CellAgent.cell "Link to this definition")
The cell the agent is currently in.
Type:
[Cell](#mesa.discrete_space.__init__.Cell "mesa.discrete_space.__init__.Cell")
Create a new agent.
Parameters:
* **model** ([_Model_](../mesa.html#mesa.model.Model "mesa.model.Model")
) – The model instance in which the agent exists.
* **args** – passed on to super
* **kwargs** – passed on to super
Notes
to make proper use of python’s super, in each class remove the arguments and keyword arguments you need and pass on the rest to super
remove()[\[source\]](../_modules/mesa/discrete_space/cell_agent.html#CellAgent.remove)
[#](#mesa.discrete_space.cell_agent.CellAgent.remove "Link to this definition")
Remove the agent from the model.
_class_ FixedAgent(_model: [Model](../mesa.html#mesa.model.Model "mesa.model.Model")
_, _\*args_, _\*\*kwargs_)[\[source\]](../_modules/mesa/discrete_space/cell_agent.html#FixedAgent)
[#](#mesa.discrete_space.cell_agent.FixedAgent "Link to this definition")
A patch in a 2D grid.
Create a new agent.
Parameters:
* **model** ([_Model_](../mesa.html#mesa.model.Model "mesa.model.Model")
) – The model instance in which the agent exists.
* **args** – passed on to super
* **kwargs** – passed on to super
Notes
to make proper use of python’s super, in each class remove the arguments and keyword arguments you need and pass on the rest to super
remove()[\[source\]](../_modules/mesa/discrete_space/cell_agent.html#FixedAgent.remove)
[#](#mesa.discrete_space.cell_agent.FixedAgent.remove "Link to this definition")
Remove the agent from the model.
_class_ Grid2DMovingAgent(_model: [Model](../mesa.html#mesa.model.Model "mesa.model.Model")
_, _\*args_, _\*\*kwargs_)[\[source\]](../_modules/mesa/discrete_space/cell_agent.html#Grid2DMovingAgent)
[#](#mesa.discrete_space.cell_agent.Grid2DMovingAgent "Link to this definition")
Mixin for moving agents in 2D grids.
Create a new agent.
Parameters:
* **model** ([_Model_](../mesa.html#mesa.model.Model "mesa.model.Model")
) – The model instance in which the agent exists.
* **args** – passed on to super
* **kwargs** – passed on to super
Notes
to make proper use of python’s super, in each class remove the arguments and keyword arguments you need and pass on the rest to super
move(_direction: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _distance: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_)[\[source\]](../_modules/mesa/discrete_space/cell_agent.html#Grid2DMovingAgent.move)
[#](#mesa.discrete_space.cell_agent.Grid2DMovingAgent.move "Link to this definition")
Move the agent in a cardinal direction.
Parameters:
* **direction** – The cardinal direction to move in.
* **distance** – The distance to move.
Collection class for managing and querying groups of cells.
The CellCollection class provides a consistent interface for operating on multiple cells, supporting: - Filtering and selecting cells based on conditions - Random cell and agent selection - Access to contained agents - Group operations
This is useful for implementing area effects, zones, or any operation that needs to work with multiple cells as a unit. The collection handles efficient iteration and agent access across cells. The class is used throughout the cell space implementation to represent neighborhoods, selections, and other cell groupings.
_class_ CellCollection(_cells: Mapping\[T, [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")\
\[[CellAgent](#mesa.discrete_space.__init__.CellAgent "mesa.discrete_space.__init__.CellAgent")\
\]\] | Iterable\[T\]_, _random: Random | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_)[\[source\]](../_modules/mesa/discrete_space/cell_collection.html#CellCollection)
[#](#mesa.discrete_space.cell_collection.CellCollection "Link to this definition")
An immutable collection of cells.
cells[\[source\]](../_modules/mesa/discrete_space/cell_collection.html#CellCollection.cells)
[#](#mesa.discrete_space.cell_collection.CellCollection.cells "Link to this definition")
The list of cells this collection represents
Type:
List\[[Cell](#mesa.discrete_space.__init__.Cell "mesa.discrete_space.__init__.Cell")\
\]
agents[#](#mesa.discrete_space.cell_collection.CellCollection.agents "Link to this definition")
List of agents occupying the cells in this collection
Type:
List\[[CellAgent](#mesa.discrete_space.__init__.CellAgent "mesa.discrete_space.__init__.CellAgent")\
\]
random[#](#mesa.discrete_space.cell_collection.CellCollection.random "Link to this definition")
The random number generator
Type:
Random
Notes
A UserWarning is issued if random=None. You can resolve this warning by explicitly passing a random number generator. In most cases, this will be the seeded random number generator in the model. So, you would do random=self.random in a Model or Agent instance.
Initialize a CellCollection.
Parameters:
* **cells** – cells to add to the collection
* **random** – a seeded random number generator.
select\_random\_cell() → T[\[source\]](../_modules/mesa/discrete_space/cell_collection.html#CellCollection.select_random_cell)
[#](#mesa.discrete_space.cell_collection.CellCollection.select_random_cell "Link to this definition")
Select a random cell.
select\_random\_agent() → [CellAgent](#mesa.discrete_space.__init__.CellAgent "mesa.discrete_space.__init__.CellAgent")
[\[source\]](../_modules/mesa/discrete_space/cell_collection.html#CellCollection.select_random_agent)
[#](#mesa.discrete_space.cell_collection.CellCollection.select_random_agent "Link to this definition")
Select a random agent.
Returns:
CellAgent instance
select(_filter\_func: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
\[\[T\], [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")\
\] | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _at\_most: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
\= inf_)[\[source\]](../_modules/mesa/discrete_space/cell_collection.html#CellCollection.select)
[#](#mesa.discrete_space.cell_collection.CellCollection.select "Link to this definition")
Select cells based on filter function.
Parameters:
* **filter\_func** – filter function
* **at\_most** – The maximum amount of cells to select. Defaults to infinity. - If an integer, at most the first number of matching cells is selected. - If a float between 0 and 1, at most that fraction of original number of cells
Returns:
CellCollection
Base class for building cell-based spatial environments.
DiscreteSpace provides the core functionality needed by all cell-based spaces: - Cell creation and tracking - Agent-cell relationship management - Property layer support - Random selection capabilities - Capacity management
This serves as the foundation for specific space implementations like grids and networks, ensuring consistent behavior and shared functionality across different space types. All concrete cell space implementations (grids, networks, etc.) inherit from this class.
_class_ DiscreteSpace(_capacity: int | None \= None_, _cell\_klass: type\[~mesa.discrete\_space.discrete\_space.T\] \= _, _random: ~random.Random | None \= None_)[\[source\]](../_modules/mesa/discrete_space/discrete_space.html#DiscreteSpace)
[#](#mesa.discrete_space.discrete_space.DiscreteSpace "Link to this definition")
Base class for all discrete spaces.
capacity[#](#mesa.discrete_space.discrete_space.DiscreteSpace.capacity "Link to this definition")
The capacity of the cells in the discrete space
Type:
[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
all\_cells[\[source\]](../_modules/mesa/discrete_space/discrete_space.html#DiscreteSpace.all_cells)
[#](#mesa.discrete_space.discrete_space.DiscreteSpace.all_cells "Link to this definition")
The cells composing the discrete space
Type:
[CellCollection](#mesa.discrete_space.__init__.CellCollection "mesa.discrete_space.__init__.CellCollection")
random[#](#mesa.discrete_space.discrete_space.DiscreteSpace.random "Link to this definition")
The random number generator
Type:
Random
cell\_klass[#](#mesa.discrete_space.discrete_space.DiscreteSpace.cell_klass "Link to this definition")
the type of cell class
Type:
Type
empties[#](#mesa.discrete_space.discrete_space.DiscreteSpace.empties "Link to this definition")
collection of all cells that are empty
Type:
[CellCollection](#mesa.discrete_space.__init__.CellCollection "mesa.discrete_space.__init__.CellCollection")
property\_layers[#](#mesa.discrete_space.discrete_space.DiscreteSpace.property_layers "Link to this definition")
the property layers of the discrete space
Type:
[dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
, [PropertyLayer](#mesa.discrete_space.__init__.PropertyLayer "mesa.discrete_space.__init__.PropertyLayer")\
\]
Notes
A UserWarning is issued if random=None. You can resolve this warning by explicitly passing a random number generator. In most cases, this will be the seeded random number generator in the model. So, you would do random=self.random in a Model or Agent instance.
Instantiate a DiscreteSpace.
Parameters:
* **capacity** – capacity of cells
* **cell\_klass** – base class for all cells
* **random** – random number generator
_property_ agents_: [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
_[#](#mesa.discrete_space.discrete_space.DiscreteSpace.agents "Link to this definition")
Return an AgentSet with the agents in the space.
_property_ all\_cells[\[source\]](../_modules/mesa/discrete_space/discrete_space.html#DiscreteSpace.all_cells)
[#](#id4 "Link to this definition")
Return all cells in space.
_property_ empties_: [CellCollection](#mesa.discrete_space.cell_collection.CellCollection "mesa.discrete_space.cell_collection.CellCollection")
\[T\]_[#](#id5 "Link to this definition")
Return all empty in spaces.
select\_random\_empty\_cell() → T[\[source\]](../_modules/mesa/discrete_space/discrete_space.html#DiscreteSpace.select_random_empty_cell)
[#](#mesa.discrete_space.discrete_space.DiscreteSpace.select_random_empty_cell "Link to this definition")
Select random empty cell.
Grid-based cell space implementations with different connection patterns.
Provides several grid types for organizing cells: - OrthogonalMooreGrid: 8 neighbors in 2D, (3^n)-1 in nD - OrthogonalVonNeumannGrid: 4 neighbors in 2D, 2n in nD - HexGrid: 6 neighbors in hexagonal pattern (2D only)
Each grid type supports optional wrapping (torus) and cell capacity limits. Choose based on how movement and connectivity should work in your model - Moore for unrestricted movement, Von Neumann for orthogonal-only movement, or Hex for more uniform distances.
pickle\_gridcell(_obj_)[\[source\]](../_modules/mesa/discrete_space/grid.html#pickle_gridcell)
[#](#mesa.discrete_space.grid.pickle_gridcell "Link to this definition")
Helper function for pickling GridCell instances.
unpickle\_gridcell(_parent_, _fields_)[\[source\]](../_modules/mesa/discrete_space/grid.html#unpickle_gridcell)
[#](#mesa.discrete_space.grid.unpickle_gridcell "Link to this definition")
Helper function for unpickling GridCell instances.
_class_ Grid(_dimensions: ~collections.abc.Sequence\[int\], torus: bool \= False, capacity: float | None \= None, random: ~random.Random | None \= None, cell\_klass: type\[~mesa.discrete\_space.grid.T\] \= _)[\[source\]](../_modules/mesa/discrete_space/grid.html#Grid)
[#](#mesa.discrete_space.grid.Grid "Link to this definition")
Base class for all grid classes.
dimensions[#](#mesa.discrete_space.grid.Grid.dimensions "Link to this definition")
the dimensions of the grid
Type:
Sequence\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]
torus[#](#mesa.discrete_space.grid.Grid.torus "Link to this definition")
whether the grid is a torus
Type:
[bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
capacity[#](#mesa.discrete_space.grid.Grid.capacity "Link to this definition")
the capacity of a grid cell
Type:
[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
random[#](#mesa.discrete_space.grid.Grid.random "Link to this definition")
the random number generator
Type:
Random
\_try\_random[#](#mesa.discrete_space.grid.Grid._try_random "Link to this definition")
whether to get empty cell be repeatedly trying random cell
Type:
[bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
Notes
width and height are accessible via properties, higher dimensions can be retrieved via dimensions
Initialise the grid class.
Parameters:
* **dimensions** – the dimensions of the space
* **torus** – whether the space wraps
* **capacity** – capacity of the grid cell
* **random** – a random number generator
* **cell\_klass** – the base class to use for the cells
_property_ width_: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_[#](#mesa.discrete_space.grid.Grid.width "Link to this definition")
Convenience access to the width of the grid.
_property_ height_: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_[#](#mesa.discrete_space.grid.Grid.height "Link to this definition")
Convenience access to the height of the grid.
select\_random\_empty\_cell() → T[\[source\]](../_modules/mesa/discrete_space/grid.html#Grid.select_random_empty_cell)
[#](#mesa.discrete_space.grid.Grid.select_random_empty_cell "Link to this definition")
Select random empty cell.
_class_ OrthogonalMooreGrid(_dimensions: ~collections.abc.Sequence\[int\], torus: bool \= False, capacity: float | None \= None, random: ~random.Random | None \= None, cell\_klass: type\[~mesa.discrete\_space.grid.T\] \= _)[\[source\]](../_modules/mesa/discrete_space/grid.html#OrthogonalMooreGrid)
[#](#mesa.discrete_space.grid.OrthogonalMooreGrid "Link to this definition")
Grid where cells are connected to their 8 neighbors.
Example for two dimensions: directions = \[\
\
> (-1, -1), (-1, 0), (-1, 1), ( 0, -1), ( 0, 1), ( 1, -1), ( 1, 0), ( 1, 1),\
\
\]
Initialise the grid class.
Parameters:
* **dimensions** – the dimensions of the space
* **torus** – whether the space wraps
* **capacity** – capacity of the grid cell
* **random** – a random number generator
* **cell\_klass** – the base class to use for the cells
_class_ OrthogonalVonNeumannGrid(_dimensions: ~collections.abc.Sequence\[int\], torus: bool \= False, capacity: float | None \= None, random: ~random.Random | None \= None, cell\_klass: type\[~mesa.discrete\_space.grid.T\] \= _)[\[source\]](../_modules/mesa/discrete_space/grid.html#OrthogonalVonNeumannGrid)
[#](#mesa.discrete_space.grid.OrthogonalVonNeumannGrid "Link to this definition")
Grid where cells are connected to their 4 neighbors.
Example for two dimensions: directions = \[\
\
> > (0, -1),\
> \
> (-1, 0), ( 1, 0),\
> \
> (0, 1),\
\
\]
Initialise the grid class.
Parameters:
* **dimensions** – the dimensions of the space
* **torus** – whether the space wraps
* **capacity** – capacity of the grid cell
* **random** – a random number generator
* **cell\_klass** – the base class to use for the cells
_class_ HexGrid(_dimensions: ~collections.abc.Sequence\[int\], torus: bool \= False, capacity: float | None \= None, random: ~random.Random | None \= None, cell\_klass: type\[~mesa.discrete\_space.grid.T\] \= _)[\[source\]](../_modules/mesa/discrete_space/grid.html#HexGrid)
[#](#mesa.discrete_space.grid.HexGrid "Link to this definition")
A Grid with hexagonal tilling of the space.
Initialise the grid class.
Parameters:
* **dimensions** – the dimensions of the space
* **torus** – whether the space wraps
* **capacity** – capacity of the grid cell
* **random** – a random number generator
* **cell\_klass** – the base class to use for the cells
Network-based cell space using arbitrary connection patterns.
Creates spaces where cells connect based on network relationships rather than spatial proximity. Built on NetworkX graphs, this enables: - Arbitrary connectivity patterns between cells - Graph-based neighborhood definitions - Logical rather than physical distances - Dynamic connectivity changes - Integration with NetworkX’s graph algorithms
Useful for modeling systems like social networks, transportation systems, or any environment where connectivity matters more than physical location.
_class_ Network(_G: ~typing.Any_, _capacity: int | None \= None_, _random: ~random.Random | None \= None_, _cell\_klass: type\[~mesa.discrete\_space.cell.Cell\] \= _)[\[source\]](../_modules/mesa/discrete_space/network.html#Network)
[#](#mesa.discrete_space.network.Network "Link to this definition")
A networked discrete space.
A Networked grid.
Parameters:
* **G** – a NetworkX Graph instance.
* **capacity** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – the capacity of the cell
* **random** (_Random_) – a random number generator
* **cell\_klass** ([_type_](https://docs.python.org/3/library/functions.html#type "(in Python v3.13)")
_\[_[_Cell_](#mesa.discrete_space.__init__.Cell "mesa.discrete_space.__init__.Cell")\
_\]_) – The base Cell class to use in the Network
Cell spaces based on Voronoi tessellation around seed points.
Creates irregular spatial divisions by building cells around seed points, where each cell contains the area closer to its seed than any other. Features: - Organic-looking spaces from point sets - Automatic neighbor determination - Area-based cell capacities - Natural regional divisions
Useful for models requiring irregular but mathematically meaningful spatial divisions, like territories, service areas, or natural regions.
_class_ Delaunay(_center: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\= (0, 0)_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 9999_)[\[source\]](../_modules/mesa/discrete_space/voronoi.html#Delaunay)
[#](#mesa.discrete_space.voronoi.Delaunay "Link to this definition")
Class to compute a Delaunay triangulation in 2D.
ref: [jmespadero/pyDelaunay2D](http://github.com/jmespadero/pyDelaunay2D)
Init and create a new frame to contain the triangulation.
Parameters:
* **center** – Optional position for the center of the frame. Default (0,0)
* **radius** – Optional distance from corners to the center.
add\_point(_point: [Sequence](https://docs.python.org/3/library/collections.abc.html#collections.abc.Sequence "(in Python v3.13)")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/discrete_space/voronoi.html#Delaunay.add_point)
[#](#mesa.discrete_space.voronoi.Delaunay.add_point "Link to this definition")
Add a point to the current DT, and refine it using Bowyer-Watson.
export\_triangles() → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
[\[source\]](../_modules/mesa/discrete_space/voronoi.html#Delaunay.export_triangles)
[#](#mesa.discrete_space.voronoi.Delaunay.export_triangles "Link to this definition")
Export the current list of Delaunay triangles.
export\_voronoi\_regions()[\[source\]](../_modules/mesa/discrete_space/voronoi.html#Delaunay.export_voronoi_regions)
[#](#mesa.discrete_space.voronoi.Delaunay.export_voronoi_regions "Link to this definition")
Export coordinates and regions of Voronoi diagram as indexed data.
_class_ VoronoiGrid(_centroids\_coordinates: ~collections.abc.Sequence\[~collections.abc.Sequence\[float\]\], capacity: float | None \= None, random: ~random.Random | None \= None, cell\_klass: type\[~mesa.discrete\_space.cell.Cell\] \= , capacity\_function: callable \= _)[\[source\]](../_modules/mesa/discrete_space/voronoi.html#VoronoiGrid)
[#](#mesa.discrete_space.voronoi.VoronoiGrid "Link to this definition")
Voronoi meshed GridSpace.
A Voronoi Tessellation Grid.
Given a set of points, this class creates a grid where a cell is centered in each point, its neighbors are given by Voronoi Tessellation cells neighbors and the capacity by the polygon area.
Parameters:
* **centroids\_coordinates** – coordinates of centroids to build the tessellation space
* **capacity** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – capacity of the cells in the discrete space
* **random** (_Random_) – random number generator
* **cell\_klass** ([_type_](https://docs.python.org/3/library/functions.html#type "(in Python v3.13)")
_\[_[_Cell_](#mesa.discrete_space.__init__.Cell "mesa.discrete_space.__init__.Cell")\
_\]_) – type of cell class
* **capacity\_function** (_Callable_) – function to compute (int) capacity according to (float) area
On this page
### This Page
* [Show Source](../_sources/apis/discrete_space.md.txt)
---
# Spaces — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Spaces[#](#module-mesa.space "Link to this heading")
=====================================================
Mesa Space Module.
Objects used to add a spatial component to a model.
Note
All Grid classes (`_Grid`, [`SingleGrid`](../mesa.html#mesa.space.SingleGrid "mesa.space.SingleGrid")
, [`MultiGrid`](../mesa.html#mesa.space.MultiGrid "mesa.space.MultiGrid")
, `HexGrid`, etc.) are now in maintenance-only mode. While these classes remain fully supported, new development occurs in the experimental cell space module (`mesa.discrete_space`).
The [`PropertyLayer`](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")
and [`ContinuousSpace`](../mesa.html#mesa.space.ContinuousSpace "mesa.space.ContinuousSpace")
classes remain fully supported and actively developed.
Classes[#](#classes "Link to this heading")
--------------------------------------------
* PropertyLayer: A data layer that can be added to Grids to store cell properties
* SingleGrid: a Grid which strictly enforces one agent per cell.
* MultiGrid: a Grid where each cell can contain a set of agents.
* HexGrid: a Grid to handle hexagonal neighbors.
* ContinuousSpace: a two-dimensional space where each agent has an arbitrary position of float’s.
* NetworkGrid: a network where each node contains zero or more agents.
accept\_tuple\_argument(_wrapped\_function: F_) → F[\[source\]](../_modules/mesa/space.html#accept_tuple_argument)
[#](#mesa.space.accept_tuple_argument "Link to this definition")
Decorator to allow grid methods that take a list of (x, y) coord tuples to also handle a single position.
Tuples are wrapped in a single-item list rather than forcing user to do it.
is\_integer(_x: [Real](https://docs.python.org/3/library/numbers.html#numbers.Real "(in Python v3.13)")
_) → [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
[\[source\]](../_modules/mesa/space.html#is_integer)
[#](#mesa.space.is_integer "Link to this definition")
Check if x is either a CPython integer or Numpy integer.
warn\_if\_agent\_has\_position\_already(_placement\_func_)[\[source\]](../_modules/mesa/space.html#warn_if_agent_has_position_already)
[#](#mesa.space.warn_if_agent_has_position_already "Link to this definition")
Decorator to give warning if agent has position already set.
is\_single\_argument\_function(_function_)[\[source\]](../_modules/mesa/space.html#is_single_argument_function)
[#](#mesa.space.is_single_argument_function "Link to this definition")
Check if a function is a single argument function.
_class_ PropertyLayer(_name: str_, _width: int_, _height: int_, _default\_value_, _dtype=_)[\[source\]](../_modules/mesa/space.html#PropertyLayer)
[#](#mesa.space.PropertyLayer "Link to this definition")
A class representing a layer of properties in a two-dimensional grid.
Each cell in the grid can store a value of a specified data type.
name[#](#mesa.space.PropertyLayer.name "Link to this definition")
The name of the property layer.
Type:
[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
width[#](#mesa.space.PropertyLayer.width "Link to this definition")
The width of the grid (number of columns).
Type:
[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
height[#](#mesa.space.PropertyLayer.height "Link to this definition")
The height of the grid (number of rows).
Type:
[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
data[#](#mesa.space.PropertyLayer.data "Link to this definition")
A NumPy array representing the grid data.
Type:
numpy.ndarray
Initializes a new PropertyLayer instance.
Parameters:
* **name** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
) – The name of the property layer.
* **width** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – The width of the grid (number of columns). Must be a positive integer.
* **height** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – The height of the grid (number of rows). Must be a positive integer.
* **default\_value** – The default value to initialize each cell in the grid. Should ideally be of the same type as specified by the dtype parameter.
* **dtype** (_data-type__,_ _optional_) – The desired data-type for the grid’s elements. Default is np.float64.
Raises:
[**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)")
– If width or height is not a positive integer.
Notes
A UserWarning is raised if the default\_value is not of a type compatible with dtype. The dtype parameter can accept both Python data types (like bool, int or float) and NumPy data types (like np.int64 or np.float64). Using NumPy data types is recommended (except for bool) for better control over the precision and efficiency of data storage and computations, especially in cases of large data volumes or specialized numerical operations.
set\_cell(_position: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _value_)[\[source\]](../_modules/mesa/space.html#PropertyLayer.set_cell)
[#](#mesa.space.PropertyLayer.set_cell "Link to this definition")
Update a single cell’s value in-place.
set\_cells(_value_, _condition\=None_)[\[source\]](../_modules/mesa/space.html#PropertyLayer.set_cells)
[#](#mesa.space.PropertyLayer.set_cells "Link to this definition")
Perform a batch update either on the entire grid or conditionally, in-place.
Parameters:
* **value** – The value to be used for the update.
* **condition** – (Optional) A callable (like a lambda function or a NumPy ufunc) that returns a boolean array when applied to the data.
modify\_cell(_position: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _operation_, _value\=None_)[\[source\]](../_modules/mesa/space.html#PropertyLayer.modify_cell)
[#](#mesa.space.PropertyLayer.modify_cell "Link to this definition")
Modify a single cell using an operation, which can be a lambda function or a NumPy ufunc.
If a NumPy ufunc is used, an additional value should be provided.
Parameters:
* **position** – The grid coordinates of the cell to modify.
* **operation** – A function to apply. Can be a lambda function or a NumPy ufunc.
* **value** – The value to be used if the operation is a NumPy ufunc. Ignored for lambda functions.
modify\_cells(_operation_, _value\=None_, _condition\_function\=None_)[\[source\]](../_modules/mesa/space.html#PropertyLayer.modify_cells)
[#](#mesa.space.PropertyLayer.modify_cells "Link to this definition")
Modify cells using an operation, which can be a lambda function or a NumPy ufunc.
If a NumPy ufunc is used, an additional value should be provided.
Parameters:
* **operation** – A function to apply. Can be a lambda function or a NumPy ufunc.
* **value** – The value to be used if the operation is a NumPy ufunc. Ignored for lambda functions.
* **condition\_function** – (Optional) A callable that returns a boolean array when applied to the data.
select\_cells(_condition_, _return\_list\=True_)[\[source\]](../_modules/mesa/space.html#PropertyLayer.select_cells)
[#](#mesa.space.PropertyLayer.select_cells "Link to this definition")
Find cells that meet a specified condition using NumPy’s boolean indexing, in-place.
Parameters:
* **condition** – A callable that returns a boolean array when applied to the data.
* **return\_list** – (Optional) If True, return a list of (x, y) tuples. Otherwise, return a boolean array.
Returns:
A list of (x, y) tuples or a boolean array.
aggregate\_property(_operation_)[\[source\]](../_modules/mesa/space.html#PropertyLayer.aggregate_property)
[#](#mesa.space.PropertyLayer.aggregate_property "Link to this definition")
Perform an aggregate operation (e.g., sum, mean) on a property across all cells.
Parameters:
**operation** – A function to apply. Can be a lambda function or a NumPy ufunc.
_class_ SingleGrid(_width: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_, _height: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_, _torus: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_, _property\_layers: [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
| [PropertyLayer](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")
| [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[PropertyLayer](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")\
\] \= None_)[\[source\]](../_modules/mesa/space.html#SingleGrid)
[#](#mesa.space.SingleGrid "Link to this definition")
Rectangular grid where each cell contains exactly at most one agent.
Grid cells are indexed by \[x, y\], where \[0, 0\] is assumed to be the bottom-left and \[width-1, height-1\] is the top-right. If a grid is toroidal, the top and bottom, and left and right, edges wrap to each other.
This class provides a property empties that returns a set of coordinates for all empty cells in the grid. It is automatically updated whenever agents are added or removed from the grid. The empties property should be used for efficient access to current empty cells rather than manually iterating over the grid to check for emptiness.
Properties:
width, height: The grid’s width and height. torus: Boolean which determines whether to treat the grid as a torus. empties: Returns a set of (x, y) tuples for all empty cells. This set is
> maintained internally and provides a performant way to query the grid for empty spaces.
Initializes a new \_PropertyGrid instance with specified dimensions and optional property layers.
Parameters:
* **width** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – The width of the grid (number of columns).
* **height** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – The height of the grid (number of rows).
* **torus** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
) – A boolean indicating if the grid should behave like a torus.
* **property\_layers** (_None_ _|_ [_PropertyLayer_](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")
_|_ [_list_](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
_\[_[_PropertyLayer_](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")\
_\]__,_ _optional_) – A single PropertyLayer instance, a list of PropertyLayer instances, or None to initialize without any property layers.
Raises:
[**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)")
– If a property layer’s dimensions do not match the grid dimensions.
remove\_agent(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/space.html#SingleGrid.remove_agent)
[#](#mesa.space.SingleGrid.remove_agent "Link to this definition")
Remove the agent from the grid and set its pos attribute to None.
add\_property\_layer(_property\_layer: [PropertyLayer](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")
_)[#](#mesa.space.SingleGrid.add_property_layer "Link to this definition")
Adds a new property layer to the grid.
Parameters:
**property\_layer** ([_PropertyLayer_](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")
) – The PropertyLayer instance to be added to the grid.
Raises:
* [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)")
– If a property layer with the same name already exists in the grid.
* [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)")
– If the dimensions of the property layer do not match the grid’s dimensions.
_property_ agents_: [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
_[#](#mesa.space.SingleGrid.agents "Link to this definition")
Return an AgentSet with the agents in the space.
coord\_iter() → [Iterator](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator "(in Python v3.13)")
\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")\
, [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]\]\][#](#mesa.space.SingleGrid.coord_iter "Link to this definition")
An iterator that returns positions as well as cell contents.
_static_ default\_val() → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[#](#mesa.space.SingleGrid.default_val "Link to this definition")
Default value for new cell elements.
_property_ empty\_mask_: ndarray_[#](#mesa.space.SingleGrid.empty_mask "Link to this definition")
Returns a boolean mask indicating empty cells on the grid.
exists\_empty\_cells() → [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
[#](#mesa.space.SingleGrid.exists_empty_cells "Link to this definition")
Return True if any cells empty else False.
get\_neighborhood(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _moore: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [Sequence](https://docs.python.org/3/library/collections.abc.html#collections.abc.Sequence "(in Python v3.13)")
\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]\][#](#mesa.space.SingleGrid.get_neighborhood "Link to this definition")
Return a list of cells that are in the neighborhood of a certain point.
Parameters:
* **pos** – Coordinate tuple for the neighborhood to get.
* **moore** – If True, return Moore neighborhood (including diagonals) If False, return Von Neumann neighborhood (exclude diagonals)
* **include\_center** – If True, return the (x, y) cell as well. Otherwise, return surrounding cells only.
* **radius** – radius, in cells, of neighborhood to get.
Returns:
A list of coordinate tuples representing the neighborhood; With radius 1, at most 9 if Moore, 5 if Von Neumann (8 and 4 if not including the center).
get\_neighborhood\_mask(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _moore: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_) → ndarray[#](#mesa.space.SingleGrid.get_neighborhood_mask "Link to this definition")
Generate a boolean mask representing the neighborhood.
Helper method for select\_cells\_multi\_properties() and move\_agent\_to\_random\_cell()
Parameters:
* **pos** (_Coordinate_) – Center of the neighborhood.
* **moore** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
) – True for Moore neighborhood, False for Von Neumann.
* **include\_center** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
) – Include the central cell in the neighborhood.
* **radius** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – The radius of the neighborhood.
Returns:
A boolean mask representing the neighborhood.
Return type:
np.ndarray
get\_neighbors(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _moore: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\][#](#mesa.space.SingleGrid.get_neighbors "Link to this definition")
Return a list of neighbors to a certain point.
Parameters:
* **pos** – Coordinate tuple for the neighborhood to get.
* **moore** –
If True, return Moore neighborhood
(including diagonals)
If False, return Von Neumann neighborhood
(exclude diagonals)
* **include\_center** – If True, return the (x, y) cell as well. Otherwise, return surrounding cells only.
* **radius** – radius, in cells, of neighborhood to get.
Returns:
A list of non-None objects in the given neighborhood; at most 9 if Moore, 5 if Von-Neumann (8 and 4 if not including the center).
is\_cell\_empty(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_) → [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
[#](#mesa.space.SingleGrid.is_cell_empty "Link to this definition")
Returns a bool of the contents of a cell.
iter\_neighborhood(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _moore: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [Iterator](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator "(in Python v3.13)")
\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]\][#](#mesa.space.SingleGrid.iter_neighborhood "Link to this definition")
Return an iterator over cell coordinates that are in the neighborhood of a certain point.
Parameters:
* **pos** – Coordinate tuple for the neighborhood to get.
* **moore** –
If True, return Moore neighborhood
(including diagonals)
If False, return Von Neumann neighborhood
(exclude diagonals)
* **include\_center** – If True, return the (x, y) cell as well. Otherwise, return surrounding cells only.
* **radius** – radius, in cells, of neighborhood to get.
Returns:
An iterator of coordinate tuples representing the neighborhood. For example with radius 1, it will return list with number of elements equals at most 9 (8) if Moore, 5 (4) if Von Neumann (if not including the center).
iter\_neighbors(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _moore: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [Iterator](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator "(in Python v3.13)")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\][#](#mesa.space.SingleGrid.iter_neighbors "Link to this definition")
Return an iterator over neighbors to a certain point.
Parameters:
* **pos** – Coordinates for the neighborhood to get.
* **moore** –
If True, return Moore neighborhood
(including diagonals)
If False, return Von Neumann neighborhood
(exclude diagonals)
* **include\_center** – If True, return the (x, y) cell as well. Otherwise, return surrounding cells only.
* **radius** – radius, in cells, of neighborhood to get.
Returns:
An iterator of non-None objects in the given neighborhood; at most 9 if Moore, 5 if Von-Neumann (8 and 4 if not including the center).
move\_agent(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_, _pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[#](#mesa.space.SingleGrid.move_agent "Link to this definition")
Move an agent from its current position to a new position.
Parameters:
* **agent** – Agent object to move. Assumed to have its current location stored in a ‘pos’ tuple.
* **pos** – Tuple of new position to move the agent to.
move\_agent\_to\_one\_of(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_, _pos: [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]\]_, _selection: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
\= 'random'_, _handle\_empty: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[#](#mesa.space.SingleGrid.move_agent_to_one_of "Link to this definition")
Move an agent to one of the given positions.
Parameters:
* **agent** – Agent object to move. Assumed to have its current location stored in a ‘pos’ tuple.
* **pos** – List of possible positions.
* **selection** – String, either “random” (default) or “closest”. If “closest” is selected and multiple cells are the same distance, one is chosen randomly.
* **handle\_empty** – String, either “warning”, “error” or None (default). If “warning” or “error” is selected and no positions are given (an empty list), a warning or error is raised respectively.
move\_to\_empty(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[#](#mesa.space.SingleGrid.move_to_empty "Link to this definition")
Moves agent to a random empty cell, vacating agent’s old cell.
out\_of\_bounds(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_) → [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
[#](#mesa.space.SingleGrid.out_of_bounds "Link to this definition")
Determines whether position is off the grid, returns the out of bounds coordinate.
remove\_property\_layer(_property\_name: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_)[#](#mesa.space.SingleGrid.remove_property_layer "Link to this definition")
Removes a property layer from the grid by its name.
Parameters:
**property\_name** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
) – The name of the property layer to be removed.
Raises:
[**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)")
– If a property layer with the given name does not exist in the grid.
select\_cells(_conditions: [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _extreme\_values: [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _masks: ndarray | [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[ndarray\] \= None_, _only\_empty: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _return\_list: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= True_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]\] | ndarray[#](#mesa.space.SingleGrid.select_cells "Link to this definition")
Select cells based on property conditions, extreme values, and/or masks, with an option to only select empty cells.
Parameters:
* **conditions** ([_dict_](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
) – A dictionary where keys are property names and values are callables that return a boolean when applied.
* **extreme\_values** ([_dict_](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
) – A dictionary where keys are property names and values are either ‘highest’ or ‘lowest’.
* **masks** (_np.ndarray_ _|_ [_list_](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
_\[__np.ndarray__\]__,_ _optional_) – A mask or list of masks to restrict the selection.
* **only\_empty** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_,_ _optional_) – If True, only select cells that are empty. Default is False.
* **return\_list** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_,_ _optional_) – If True, return a list of coordinates, otherwise return a mask.
Returns:
Coordinates where conditions are satisfied or the combined mask.
Return type:
Union\[[list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")\
\[Coordinate\], np.ndarray\]
swap\_pos(_agent\_a: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_, _agent\_b: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[#](#mesa.space.SingleGrid.swap_pos "Link to this definition")
Swap agents positions.
torus\_adj(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_) → [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\][#](#mesa.space.SingleGrid.torus_adj "Link to this definition")
Convert coordinate, handling torus looping.
_class_ MultiGrid(_width: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_, _height: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_, _torus: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_, _property\_layers: [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
| [PropertyLayer](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")
| [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[PropertyLayer](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")\
\] \= None_)[\[source\]](../_modules/mesa/space.html#MultiGrid)
[#](#mesa.space.MultiGrid "Link to this definition")
Rectangular grid where each cell can contain more than one agent.
Grid cells are indexed by \[x, y\], where \[0, 0\] is assumed to be at bottom-left and \[width-1, height-1\] is the top-right. If a grid is toroidal, the top and bottom, and left and right, edges wrap to each other.
This class maintains an empties property, which is a set of coordinates for all cells that currently contain no agents. This property is updated automatically as agents are added to or removed from the grid.
Properties:
width, height: The grid’s width and height. torus: Boolean which determines whether to treat the grid as a torus. empties: Returns a set of (x, y) tuples for all empty cells.
Initializes a new \_PropertyGrid instance with specified dimensions and optional property layers.
Parameters:
* **width** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – The width of the grid (number of columns).
* **height** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – The height of the grid (number of rows).
* **torus** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
) – A boolean indicating if the grid should behave like a torus.
* **property\_layers** (_None_ _|_ [_PropertyLayer_](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")
_|_ [_list_](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
_\[_[_PropertyLayer_](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")\
_\]__,_ _optional_) – A single PropertyLayer instance, a list of PropertyLayer instances, or None to initialize without any property layers.
Raises:
[**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)")
– If a property layer’s dimensions do not match the grid dimensions.
_static_ default\_val() → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\][\[source\]](../_modules/mesa/space.html#MultiGrid.default_val)
[#](#mesa.space.MultiGrid.default_val "Link to this definition")
Default value for new cell elements.
remove\_agent(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/space.html#MultiGrid.remove_agent)
[#](#mesa.space.MultiGrid.remove_agent "Link to this definition")
Remove the agent from the given location and set its pos attribute to None.
iter\_neighbors(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _moore: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [Iterator](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator "(in Python v3.13)")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\][\[source\]](../_modules/mesa/space.html#MultiGrid.iter_neighbors)
[#](#mesa.space.MultiGrid.iter_neighbors "Link to this definition")
Return an iterator over neighbors to a certain point.
Parameters:
* **pos** – Coordinates for the neighborhood to get.
* **moore** –
If True, return Moore neighborhood
(including diagonals)
If False, return Von Neumann neighborhood
(exclude diagonals)
* **include\_center** – If True, return the (x, y) cell as well. Otherwise, return surrounding cells only.
* **radius** – radius, in cells, of neighborhood to get.
Returns:
An iterator of non-None objects in the given neighborhood; at most 9 if Moore, 5 if Von-Neumann (8 and 4 if not including the center).
add\_property\_layer(_property\_layer: [PropertyLayer](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")
_)[#](#mesa.space.MultiGrid.add_property_layer "Link to this definition")
Adds a new property layer to the grid.
Parameters:
**property\_layer** ([_PropertyLayer_](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")
) – The PropertyLayer instance to be added to the grid.
Raises:
* [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)")
– If a property layer with the same name already exists in the grid.
* [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)")
– If the dimensions of the property layer do not match the grid’s dimensions.
_property_ agents_: [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
_[#](#mesa.space.MultiGrid.agents "Link to this definition")
Return an AgentSet with the agents in the space.
coord\_iter() → [Iterator](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator "(in Python v3.13)")
\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")\
, [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]\]\][#](#mesa.space.MultiGrid.coord_iter "Link to this definition")
An iterator that returns positions as well as cell contents.
_property_ empty\_mask_: ndarray_[#](#mesa.space.MultiGrid.empty_mask "Link to this definition")
Returns a boolean mask indicating empty cells on the grid.
exists\_empty\_cells() → [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
[#](#mesa.space.MultiGrid.exists_empty_cells "Link to this definition")
Return True if any cells empty else False.
get\_neighborhood(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _moore: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [Sequence](https://docs.python.org/3/library/collections.abc.html#collections.abc.Sequence "(in Python v3.13)")
\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]\][#](#mesa.space.MultiGrid.get_neighborhood "Link to this definition")
Return a list of cells that are in the neighborhood of a certain point.
Parameters:
* **pos** – Coordinate tuple for the neighborhood to get.
* **moore** – If True, return Moore neighborhood (including diagonals) If False, return Von Neumann neighborhood (exclude diagonals)
* **include\_center** – If True, return the (x, y) cell as well. Otherwise, return surrounding cells only.
* **radius** – radius, in cells, of neighborhood to get.
Returns:
A list of coordinate tuples representing the neighborhood; With radius 1, at most 9 if Moore, 5 if Von Neumann (8 and 4 if not including the center).
get\_neighborhood\_mask(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _moore: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_) → ndarray[#](#mesa.space.MultiGrid.get_neighborhood_mask "Link to this definition")
Generate a boolean mask representing the neighborhood.
Helper method for select\_cells\_multi\_properties() and move\_agent\_to\_random\_cell()
Parameters:
* **pos** (_Coordinate_) – Center of the neighborhood.
* **moore** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
) – True for Moore neighborhood, False for Von Neumann.
* **include\_center** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
) – Include the central cell in the neighborhood.
* **radius** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – The radius of the neighborhood.
Returns:
A boolean mask representing the neighborhood.
Return type:
np.ndarray
get\_neighbors(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _moore: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\][#](#mesa.space.MultiGrid.get_neighbors "Link to this definition")
Return a list of neighbors to a certain point.
Parameters:
* **pos** – Coordinate tuple for the neighborhood to get.
* **moore** –
If True, return Moore neighborhood
(including diagonals)
If False, return Von Neumann neighborhood
(exclude diagonals)
* **include\_center** – If True, return the (x, y) cell as well. Otherwise, return surrounding cells only.
* **radius** – radius, in cells, of neighborhood to get.
Returns:
A list of non-None objects in the given neighborhood; at most 9 if Moore, 5 if Von-Neumann (8 and 4 if not including the center).
is\_cell\_empty(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_) → [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
[#](#mesa.space.MultiGrid.is_cell_empty "Link to this definition")
Returns a bool of the contents of a cell.
iter\_neighborhood(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _moore: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [Iterator](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator "(in Python v3.13)")
\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]\][#](#mesa.space.MultiGrid.iter_neighborhood "Link to this definition")
Return an iterator over cell coordinates that are in the neighborhood of a certain point.
Parameters:
* **pos** – Coordinate tuple for the neighborhood to get.
* **moore** –
If True, return Moore neighborhood
(including diagonals)
If False, return Von Neumann neighborhood
(exclude diagonals)
* **include\_center** – If True, return the (x, y) cell as well. Otherwise, return surrounding cells only.
* **radius** – radius, in cells, of neighborhood to get.
Returns:
An iterator of coordinate tuples representing the neighborhood. For example with radius 1, it will return list with number of elements equals at most 9 (8) if Moore, 5 (4) if Von Neumann (if not including the center).
move\_agent(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_, _pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[#](#mesa.space.MultiGrid.move_agent "Link to this definition")
Move an agent from its current position to a new position.
Parameters:
* **agent** – Agent object to move. Assumed to have its current location stored in a ‘pos’ tuple.
* **pos** – Tuple of new position to move the agent to.
move\_agent\_to\_one\_of(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_, _pos: [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]\]_, _selection: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
\= 'random'_, _handle\_empty: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[#](#mesa.space.MultiGrid.move_agent_to_one_of "Link to this definition")
Move an agent to one of the given positions.
Parameters:
* **agent** – Agent object to move. Assumed to have its current location stored in a ‘pos’ tuple.
* **pos** – List of possible positions.
* **selection** – String, either “random” (default) or “closest”. If “closest” is selected and multiple cells are the same distance, one is chosen randomly.
* **handle\_empty** – String, either “warning”, “error” or None (default). If “warning” or “error” is selected and no positions are given (an empty list), a warning or error is raised respectively.
move\_to\_empty(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[#](#mesa.space.MultiGrid.move_to_empty "Link to this definition")
Moves agent to a random empty cell, vacating agent’s old cell.
out\_of\_bounds(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_) → [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
[#](#mesa.space.MultiGrid.out_of_bounds "Link to this definition")
Determines whether position is off the grid, returns the out of bounds coordinate.
remove\_property\_layer(_property\_name: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_)[#](#mesa.space.MultiGrid.remove_property_layer "Link to this definition")
Removes a property layer from the grid by its name.
Parameters:
**property\_name** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
) – The name of the property layer to be removed.
Raises:
[**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)")
– If a property layer with the given name does not exist in the grid.
select\_cells(_conditions: [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _extreme\_values: [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _masks: ndarray | [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[ndarray\] \= None_, _only\_empty: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _return\_list: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= True_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]\] | ndarray[#](#mesa.space.MultiGrid.select_cells "Link to this definition")
Select cells based on property conditions, extreme values, and/or masks, with an option to only select empty cells.
Parameters:
* **conditions** ([_dict_](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
) – A dictionary where keys are property names and values are callables that return a boolean when applied.
* **extreme\_values** ([_dict_](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
) – A dictionary where keys are property names and values are either ‘highest’ or ‘lowest’.
* **masks** (_np.ndarray_ _|_ [_list_](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
_\[__np.ndarray__\]__,_ _optional_) – A mask or list of masks to restrict the selection.
* **only\_empty** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_,_ _optional_) – If True, only select cells that are empty. Default is False.
* **return\_list** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_,_ _optional_) – If True, return a list of coordinates, otherwise return a mask.
Returns:
Coordinates where conditions are satisfied or the combined mask.
Return type:
Union\[[list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")\
\[Coordinate\], np.ndarray\]
swap\_pos(_agent\_a: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_, _agent\_b: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[#](#mesa.space.MultiGrid.swap_pos "Link to this definition")
Swap agents positions.
torus\_adj(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_) → [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\][#](#mesa.space.MultiGrid.torus_adj "Link to this definition")
Convert coordinate, handling torus looping.
_class_ HexSingleGrid(_width: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_, _height: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_, _torus: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_, _property\_layers: [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
| [PropertyLayer](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")
| [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[PropertyLayer](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")\
\] \= None_)[\[source\]](../_modules/mesa/space.html#HexSingleGrid)
[#](#mesa.space.HexSingleGrid "Link to this definition")
Hexagonal SingleGrid: a SingleGrid where neighbors are computed according to a hexagonal tiling of the grid.
Functions according to odd-q rules. See [http://www.redblobgames.com/grids/hexagons/#coordinates](http://www.redblobgames.com/grids/hexagons/#coordinates)
for more.
This class also maintains an empties property, similar to SingleGrid, which provides a set of coordinates for all empty hexagonal cells.
Properties:
width, height: The grid’s width and height. torus: Boolean which determines whether to treat the grid as a torus. empties: Returns a set of hexagonal coordinates for all empty cells.
Initializes a new \_PropertyGrid instance with specified dimensions and optional property layers.
Parameters:
* **width** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – The width of the grid (number of columns).
* **height** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – The height of the grid (number of rows).
* **torus** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
) – A boolean indicating if the grid should behave like a torus.
* **property\_layers** (_None_ _|_ [_PropertyLayer_](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")
_|_ [_list_](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
_\[_[_PropertyLayer_](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")\
_\]__,_ _optional_) – A single PropertyLayer instance, a list of PropertyLayer instances, or None to initialize without any property layers.
Raises:
[**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)")
– If a property layer’s dimensions do not match the grid dimensions.
add\_property\_layer(_property\_layer: [PropertyLayer](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")
_)[#](#mesa.space.HexSingleGrid.add_property_layer "Link to this definition")
Adds a new property layer to the grid.
Parameters:
**property\_layer** ([_PropertyLayer_](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")
) – The PropertyLayer instance to be added to the grid.
Raises:
* [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)")
– If a property layer with the same name already exists in the grid.
* [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)")
– If the dimensions of the property layer do not match the grid’s dimensions.
_property_ agents_: [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
_[#](#mesa.space.HexSingleGrid.agents "Link to this definition")
Return an AgentSet with the agents in the space.
coord\_iter() → [Iterator](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator "(in Python v3.13)")
\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")\
, [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]\]\][#](#mesa.space.HexSingleGrid.coord_iter "Link to this definition")
An iterator that returns positions as well as cell contents.
_static_ default\_val() → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[#](#mesa.space.HexSingleGrid.default_val "Link to this definition")
Default value for new cell elements.
_property_ empty\_mask_: ndarray_[#](#mesa.space.HexSingleGrid.empty_mask "Link to this definition")
Returns a boolean mask indicating empty cells on the grid.
exists\_empty\_cells() → [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
[#](#mesa.space.HexSingleGrid.exists_empty_cells "Link to this definition")
Return True if any cells empty else False.
get\_neighborhood(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]\][#](#mesa.space.HexSingleGrid.get_neighborhood "Link to this definition")
Return a list of coordinates that are in the neighborhood of a certain point.
To calculate the neighborhood for a HexGrid the parity of the x coordinate of the point is important, the neighborhood can be sketched as:
> Always: (0,-), (0,+) When x is even: (-,+), (-,0), (+,+), (+,0) When x is odd: (-,0), (-,-), (+,0), (+,-)
Parameters:
* **pos** – Coordinate tuple for the neighborhood to get.
* **include\_center** – If True, return the (x, y) cell as well. Otherwise, return surrounding cells only.
* **radius** – radius, in cells, of neighborhood to get.
Returns:
A list of coordinate tuples representing the neighborhood. For example with radius 1, it will return list with number of elements equals at most 9 (8) if Moore, 5 (4) if Von Neumann (if not including the center).
get\_neighborhood\_mask(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _moore: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_) → ndarray[#](#mesa.space.HexSingleGrid.get_neighborhood_mask "Link to this definition")
Generate a boolean mask representing the neighborhood.
Helper method for select\_cells\_multi\_properties() and move\_agent\_to\_random\_cell()
Parameters:
* **pos** (_Coordinate_) – Center of the neighborhood.
* **moore** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
) – True for Moore neighborhood, False for Von Neumann.
* **include\_center** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
) – Include the central cell in the neighborhood.
* **radius** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – The radius of the neighborhood.
Returns:
A boolean mask representing the neighborhood.
Return type:
np.ndarray
get\_neighbors(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\][#](#mesa.space.HexSingleGrid.get_neighbors "Link to this definition")
Return a list of neighbors to a certain point.
Parameters:
* **pos** – Coordinate tuple for the neighborhood to get.
* **include\_center** – If True, return the (x, y) cell as well. Otherwise, return surrounding cells only.
* **radius** – radius, in cells, of neighborhood to get.
Returns:
A list of non-None objects in the given neighborhood
is\_cell\_empty(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_) → [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
[#](#mesa.space.HexSingleGrid.is_cell_empty "Link to this definition")
Returns a bool of the contents of a cell.
iter\_neighborhood(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [Iterator](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator "(in Python v3.13)")
\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]\][#](#mesa.space.HexSingleGrid.iter_neighborhood "Link to this definition")
Return an iterator over cell coordinates that are in the neighborhood of a certain point.
Parameters:
* **pos** – Coordinate tuple for the neighborhood to get.
* **include\_center** – If True, return the (x, y) cell as well. Otherwise, return surrounding cells only.
* **radius** – radius, in cells, of neighborhood to get.
Returns:
An iterator of coordinate tuples representing the neighborhood.
iter\_neighbors(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [Iterator](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator "(in Python v3.13)")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\][#](#mesa.space.HexSingleGrid.iter_neighbors "Link to this definition")
Return an iterator over neighbors to a certain point.
Parameters:
* **pos** – Coordinates for the neighborhood to get.
* **include\_center** – If True, return the (x, y) cell as well. Otherwise, return surrounding cells only.
* **radius** – radius, in cells, of neighborhood to get.
Returns:
An iterator of non-None objects in the given neighborhood
move\_agent(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_, _pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[#](#mesa.space.HexSingleGrid.move_agent "Link to this definition")
Move an agent from its current position to a new position.
Parameters:
* **agent** – Agent object to move. Assumed to have its current location stored in a ‘pos’ tuple.
* **pos** – Tuple of new position to move the agent to.
move\_agent\_to\_one\_of(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_, _pos: [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]\]_, _selection: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
\= 'random'_, _handle\_empty: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[#](#mesa.space.HexSingleGrid.move_agent_to_one_of "Link to this definition")
Move an agent to one of the given positions.
Parameters:
* **agent** – Agent object to move. Assumed to have its current location stored in a ‘pos’ tuple.
* **pos** – List of possible positions.
* **selection** – String, either “random” (default) or “closest”. If “closest” is selected and multiple cells are the same distance, one is chosen randomly.
* **handle\_empty** – String, either “warning”, “error” or None (default). If “warning” or “error” is selected and no positions are given (an empty list), a warning or error is raised respectively.
move\_to\_empty(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[#](#mesa.space.HexSingleGrid.move_to_empty "Link to this definition")
Moves agent to a random empty cell, vacating agent’s old cell.
out\_of\_bounds(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_) → [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
[#](#mesa.space.HexSingleGrid.out_of_bounds "Link to this definition")
Determines whether position is off the grid, returns the out of bounds coordinate.
remove\_agent(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[#](#mesa.space.HexSingleGrid.remove_agent "Link to this definition")
Remove the agent from the grid and set its pos attribute to None.
remove\_property\_layer(_property\_name: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_)[#](#mesa.space.HexSingleGrid.remove_property_layer "Link to this definition")
Removes a property layer from the grid by its name.
Parameters:
**property\_name** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
) – The name of the property layer to be removed.
Raises:
[**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)")
– If a property layer with the given name does not exist in the grid.
select\_cells(_conditions: [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _extreme\_values: [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _masks: ndarray | [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[ndarray\] \= None_, _only\_empty: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _return\_list: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= True_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]\] | ndarray[#](#mesa.space.HexSingleGrid.select_cells "Link to this definition")
Select cells based on property conditions, extreme values, and/or masks, with an option to only select empty cells.
Parameters:
* **conditions** ([_dict_](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
) – A dictionary where keys are property names and values are callables that return a boolean when applied.
* **extreme\_values** ([_dict_](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
) – A dictionary where keys are property names and values are either ‘highest’ or ‘lowest’.
* **masks** (_np.ndarray_ _|_ [_list_](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
_\[__np.ndarray__\]__,_ _optional_) – A mask or list of masks to restrict the selection.
* **only\_empty** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_,_ _optional_) – If True, only select cells that are empty. Default is False.
* **return\_list** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_,_ _optional_) – If True, return a list of coordinates, otherwise return a mask.
Returns:
Coordinates where conditions are satisfied or the combined mask.
Return type:
Union\[[list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")\
\[Coordinate\], np.ndarray\]
swap\_pos(_agent\_a: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_, _agent\_b: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[#](#mesa.space.HexSingleGrid.swap_pos "Link to this definition")
Swap agents positions.
torus\_adj(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_) → [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\][#](#mesa.space.HexSingleGrid.torus_adj "Link to this definition")
Convert coordinate, handling torus looping.
_class_ HexMultiGrid(_width: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_, _height: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_, _torus: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_, _property\_layers: [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
| [PropertyLayer](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")
| [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[PropertyLayer](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")\
\] \= None_)[\[source\]](../_modules/mesa/space.html#HexMultiGrid)
[#](#mesa.space.HexMultiGrid "Link to this definition")
Hexagonal MultiGrid: a MultiGrid where neighbors are computed according to a hexagonal tiling of the grid.
Functions according to odd-q rules. See [http://www.redblobgames.com/grids/hexagons/#coordinates](http://www.redblobgames.com/grids/hexagons/#coordinates)
for more.
Similar to the standard MultiGrid, this class maintains an empties property, which is a set of coordinates for all hexagonal cells that currently contain no agents. This property is updated automatically as agents are added to or removed from the grid.
Properties:
width, height: The grid’s width and height. torus: Boolean which determines whether to treat the grid as a torus. empties: Returns a set of hexagonal coordinates for all empty cells.
Initializes a new \_PropertyGrid instance with specified dimensions and optional property layers.
Parameters:
* **width** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – The width of the grid (number of columns).
* **height** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – The height of the grid (number of rows).
* **torus** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
) – A boolean indicating if the grid should behave like a torus.
* **property\_layers** (_None_ _|_ [_PropertyLayer_](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")
_|_ [_list_](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
_\[_[_PropertyLayer_](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")\
_\]__,_ _optional_) – A single PropertyLayer instance, a list of PropertyLayer instances, or None to initialize without any property layers.
Raises:
[**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)")
– If a property layer’s dimensions do not match the grid dimensions.
add\_property\_layer(_property\_layer: [PropertyLayer](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")
_)[#](#mesa.space.HexMultiGrid.add_property_layer "Link to this definition")
Adds a new property layer to the grid.
Parameters:
**property\_layer** ([_PropertyLayer_](../mesa.html#mesa.space.PropertyLayer "mesa.space.PropertyLayer")
) – The PropertyLayer instance to be added to the grid.
Raises:
* [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)")
– If a property layer with the same name already exists in the grid.
* [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)")
– If the dimensions of the property layer do not match the grid’s dimensions.
_property_ agents_: [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
_[#](#mesa.space.HexMultiGrid.agents "Link to this definition")
Return an AgentSet with the agents in the space.
coord\_iter() → [Iterator](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator "(in Python v3.13)")
\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")\
, [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]\]\][#](#mesa.space.HexMultiGrid.coord_iter "Link to this definition")
An iterator that returns positions as well as cell contents.
_static_ default\_val() → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\][#](#mesa.space.HexMultiGrid.default_val "Link to this definition")
Default value for new cell elements.
_property_ empty\_mask_: ndarray_[#](#mesa.space.HexMultiGrid.empty_mask "Link to this definition")
Returns a boolean mask indicating empty cells on the grid.
exists\_empty\_cells() → [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
[#](#mesa.space.HexMultiGrid.exists_empty_cells "Link to this definition")
Return True if any cells empty else False.
get\_neighborhood(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]\][#](#mesa.space.HexMultiGrid.get_neighborhood "Link to this definition")
Return a list of coordinates that are in the neighborhood of a certain point.
To calculate the neighborhood for a HexGrid the parity of the x coordinate of the point is important, the neighborhood can be sketched as:
> Always: (0,-), (0,+) When x is even: (-,+), (-,0), (+,+), (+,0) When x is odd: (-,0), (-,-), (+,0), (+,-)
Parameters:
* **pos** – Coordinate tuple for the neighborhood to get.
* **include\_center** – If True, return the (x, y) cell as well. Otherwise, return surrounding cells only.
* **radius** – radius, in cells, of neighborhood to get.
Returns:
A list of coordinate tuples representing the neighborhood. For example with radius 1, it will return list with number of elements equals at most 9 (8) if Moore, 5 (4) if Von Neumann (if not including the center).
get\_neighborhood\_mask(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _moore: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_) → ndarray[#](#mesa.space.HexMultiGrid.get_neighborhood_mask "Link to this definition")
Generate a boolean mask representing the neighborhood.
Helper method for select\_cells\_multi\_properties() and move\_agent\_to\_random\_cell()
Parameters:
* **pos** (_Coordinate_) – Center of the neighborhood.
* **moore** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
) – True for Moore neighborhood, False for Von Neumann.
* **include\_center** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
) – Include the central cell in the neighborhood.
* **radius** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – The radius of the neighborhood.
Returns:
A boolean mask representing the neighborhood.
Return type:
np.ndarray
get\_neighbors(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\][#](#mesa.space.HexMultiGrid.get_neighbors "Link to this definition")
Return a list of neighbors to a certain point.
Parameters:
* **pos** – Coordinate tuple for the neighborhood to get.
* **include\_center** – If True, return the (x, y) cell as well. Otherwise, return surrounding cells only.
* **radius** – radius, in cells, of neighborhood to get.
Returns:
A list of non-None objects in the given neighborhood
is\_cell\_empty(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_) → [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
[#](#mesa.space.HexMultiGrid.is_cell_empty "Link to this definition")
Returns a bool of the contents of a cell.
iter\_neighborhood(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [Iterator](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator "(in Python v3.13)")
\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]\][#](#mesa.space.HexMultiGrid.iter_neighborhood "Link to this definition")
Return an iterator over cell coordinates that are in the neighborhood of a certain point.
Parameters:
* **pos** – Coordinate tuple for the neighborhood to get.
* **include\_center** – If True, return the (x, y) cell as well. Otherwise, return surrounding cells only.
* **radius** – radius, in cells, of neighborhood to get.
Returns:
An iterator of coordinate tuples representing the neighborhood.
iter\_neighbors(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [Iterator](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator "(in Python v3.13)")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\][#](#mesa.space.HexMultiGrid.iter_neighbors "Link to this definition")
Return an iterator over neighbors to a certain point.
Parameters:
* **pos** – Coordinates for the neighborhood to get.
* **include\_center** – If True, return the (x, y) cell as well. Otherwise, return surrounding cells only.
* **radius** – radius, in cells, of neighborhood to get.
Returns:
An iterator of non-None objects in the given neighborhood
move\_agent(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_, _pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[#](#mesa.space.HexMultiGrid.move_agent "Link to this definition")
Move an agent from its current position to a new position.
Parameters:
* **agent** – Agent object to move. Assumed to have its current location stored in a ‘pos’ tuple.
* **pos** – Tuple of new position to move the agent to.
move\_agent\_to\_one\_of(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_, _pos: [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]\]_, _selection: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
\= 'random'_, _handle\_empty: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[#](#mesa.space.HexMultiGrid.move_agent_to_one_of "Link to this definition")
Move an agent to one of the given positions.
Parameters:
* **agent** – Agent object to move. Assumed to have its current location stored in a ‘pos’ tuple.
* **pos** – List of possible positions.
* **selection** – String, either “random” (default) or “closest”. If “closest” is selected and multiple cells are the same distance, one is chosen randomly.
* **handle\_empty** – String, either “warning”, “error” or None (default). If “warning” or “error” is selected and no positions are given (an empty list), a warning or error is raised respectively.
move\_to\_empty(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[#](#mesa.space.HexMultiGrid.move_to_empty "Link to this definition")
Moves agent to a random empty cell, vacating agent’s old cell.
out\_of\_bounds(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_) → [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
[#](#mesa.space.HexMultiGrid.out_of_bounds "Link to this definition")
Determines whether position is off the grid, returns the out of bounds coordinate.
remove\_agent(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[#](#mesa.space.HexMultiGrid.remove_agent "Link to this definition")
Remove the agent from the given location and set its pos attribute to None.
remove\_property\_layer(_property\_name: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_)[#](#mesa.space.HexMultiGrid.remove_property_layer "Link to this definition")
Removes a property layer from the grid by its name.
Parameters:
**property\_name** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
) – The name of the property layer to be removed.
Raises:
[**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)")
– If a property layer with the given name does not exist in the grid.
select\_cells(_conditions: [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _extreme\_values: [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _masks: ndarray | [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[ndarray\] \= None_, _only\_empty: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _return\_list: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= True_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]\] | ndarray[#](#mesa.space.HexMultiGrid.select_cells "Link to this definition")
Select cells based on property conditions, extreme values, and/or masks, with an option to only select empty cells.
Parameters:
* **conditions** ([_dict_](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
) – A dictionary where keys are property names and values are callables that return a boolean when applied.
* **extreme\_values** ([_dict_](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
) – A dictionary where keys are property names and values are either ‘highest’ or ‘lowest’.
* **masks** (_np.ndarray_ _|_ [_list_](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
_\[__np.ndarray__\]__,_ _optional_) – A mask or list of masks to restrict the selection.
* **only\_empty** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_,_ _optional_) – If True, only select cells that are empty. Default is False.
* **return\_list** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_,_ _optional_) – If True, return a list of coordinates, otherwise return a mask.
Returns:
Coordinates where conditions are satisfied or the combined mask.
Return type:
Union\[[list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")\
\[Coordinate\], np.ndarray\]
swap\_pos(_agent\_a: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_, _agent\_b: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[#](#mesa.space.HexMultiGrid.swap_pos "Link to this definition")
Swap agents positions.
torus\_adj(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_) → [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\][#](#mesa.space.HexMultiGrid.torus_adj "Link to this definition")
Convert coordinate, handling torus looping.
_class_ ContinuousSpace(_x\_max: [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
_, _y\_max: [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
_, _torus: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_, _x\_min: [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
\= 0_, _y\_min: [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
\= 0_)[\[source\]](../_modules/mesa/space.html#ContinuousSpace)
[#](#mesa.space.ContinuousSpace "Link to this definition")
Continuous space where each agent can have an arbitrary position.
Assumes that all agents have a pos property storing their position as an (x, y) tuple.
This class uses a numpy array internally to store agents in order to speed up neighborhood lookups. This array is calculated on the first neighborhood lookup, and is updated if agents are added or removed.
The concept of ‘empty cells’ is not directly applicable in continuous space, as positions are not discretized.
Create a new continuous space.
Parameters:
* **x\_max** – the maximum x-coordinate
* **y\_max** – the maximum y-coordinate.
* **torus** – Boolean for whether the edges loop around.
* **x\_min** – (default 0) If provided, set the minimum x -coordinate for the space. Below them, values loop to the other edge (if torus=True) or raise an exception.
* **y\_min** – (default 0) If provided, set the minimum y -coordinate for the space. Below them, values loop to the other edge (if torus=True) or raise an exception.
_property_ agents_: [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
_[#](#mesa.space.ContinuousSpace.agents "Link to this definition")
Return an AgentSet with the agents in the space.
move\_agent(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_, _pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
, [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
\] | ndarray\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, ...\], dtype\[[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
\]\]_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/space.html#ContinuousSpace.move_agent)
[#](#mesa.space.ContinuousSpace.move_agent "Link to this definition")
Move an agent from its current position to a new position.
Parameters:
* **agent** – The agent object to move.
* **pos** – Coordinate tuple to move the agent to.
remove\_agent(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/space.html#ContinuousSpace.remove_agent)
[#](#mesa.space.ContinuousSpace.remove_agent "Link to this definition")
Remove an agent from the space.
Parameters:
**agent** – The agent object to remove
get\_neighbors(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
, [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
\] | ndarray\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, ...\], dtype\[[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
\]\]_, _radius: [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= True_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\][\[source\]](../_modules/mesa/space.html#ContinuousSpace.get_neighbors)
[#](#mesa.space.ContinuousSpace.get_neighbors "Link to this definition")
Get all agents within a certain radius.
Parameters:
* **pos** – (x,y) coordinate tuple to center the search at.
* **radius** – Get all the objects within this distance of the center.
* **include\_center** – If True, include an object at the _exact_ provided coordinates. i.e. if you are searching for the neighbors of a given agent, True will include that agent in the results.
Notes
If 1 or more agents are located on pos, include\_center=False will remove all these agents from the results. So, if you really want to get the neighbors of a given agent, you should set include\_center=True, and then filter the list of agents to remove the given agent (i.e., self when calling it from an agent).
get\_heading(_pos\_1: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
, [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
\] | ndarray\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, ...\], dtype\[[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
\]\]_, _pos\_2: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
, [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
\] | ndarray\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, ...\], dtype\[[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
\]\]_) → [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
, [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
\] | ndarray\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, ...\], dtype\[[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
\]\][\[source\]](../_modules/mesa/space.html#ContinuousSpace.get_heading)
[#](#mesa.space.ContinuousSpace.get_heading "Link to this definition")
Get the heading vector between two points, accounting for toroidal space.
It is possible to calculate the heading angle by applying the atan2 function to the result.
Parameters:
* **pos\_1** – Coordinate tuples for both points.
* **pos\_2** – Coordinate tuples for both points.
get\_distance(_pos\_1: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
, [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
\] | ndarray\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, ...\], dtype\[[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
\]\]_, _pos\_2: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
, [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
\] | ndarray\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, ...\], dtype\[[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
\]\]_) → [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
[\[source\]](../_modules/mesa/space.html#ContinuousSpace.get_distance)
[#](#mesa.space.ContinuousSpace.get_distance "Link to this definition")
Get the distance between two point, accounting for toroidal space.
Parameters:
* **pos\_1** – Coordinate tuples for point1.
* **pos\_2** – Coordinate tuples for point2.
torus\_adj(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
, [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
\] | ndarray\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, ...\], dtype\[[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
\]\]_) → [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
, [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
\] | ndarray\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, ...\], dtype\[[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
\]\][\[source\]](../_modules/mesa/space.html#ContinuousSpace.torus_adj)
[#](#mesa.space.ContinuousSpace.torus_adj "Link to this definition")
Adjust coordinates to handle torus looping.
If the coordinate is out-of-bounds and the space is toroidal, return the corresponding point within the space. If the space is not toroidal, raise an exception.
Parameters:
**pos** – Coordinate tuple to convert.
out\_of\_bounds(_pos: [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
, [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
\] | ndarray\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
, ...\], dtype\[[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
\]\]_) → [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
[\[source\]](../_modules/mesa/space.html#ContinuousSpace.out_of_bounds)
[#](#mesa.space.ContinuousSpace.out_of_bounds "Link to this definition")
Check if a point is out of bounds.
_class_ NetworkGrid(_g: [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")
_)[\[source\]](../_modules/mesa/space.html#NetworkGrid)
[#](#mesa.space.NetworkGrid "Link to this definition")
Network Grid where each node contains zero or more agents.
Create a new network.
Parameters:
**g** – a NetworkX graph instance.
_property_ agents_: [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
_[#](#mesa.space.NetworkGrid.agents "Link to this definition")
Return an AgentSet with the agents in the space.
_static_ default\_val() → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
[\[source\]](../_modules/mesa/space.html#NetworkGrid.default_val)
[#](#mesa.space.NetworkGrid.default_val "Link to this definition")
Default value for a new node.
get\_neighborhood(_node\_id: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\][\[source\]](../_modules/mesa/space.html#NetworkGrid.get_neighborhood)
[#](#mesa.space.NetworkGrid.get_neighborhood "Link to this definition")
Get all adjacent nodes within a certain radius.
Parameters:
* **node\_id** – node id for which to get neighborhood
* **include\_center** – boolean to include node itself or not
* **radius** – size of neighborhood
Returns:
a list
get\_neighbors(_node\_id: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_, _include\_center: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _radius: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\][\[source\]](../_modules/mesa/space.html#NetworkGrid.get_neighbors)
[#](#mesa.space.NetworkGrid.get_neighbors "Link to this definition")
Get all agents in adjacent nodes (within a certain radius).
Parameters:
* **node\_id** – node id for which to get neighbors
* **include\_center** – whether to include node itself or not
* **radius** – size of neighborhood in which to find neighbors
Returns:
list of agents in neighborhood.
move\_agent(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_, _node\_id: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/space.html#NetworkGrid.move_agent)
[#](#mesa.space.NetworkGrid.move_agent "Link to this definition")
Move an agent from its current node to a new node.
Parameters:
* **agent** – agent instance
* **node\_id** – id of node
remove\_agent(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/space.html#NetworkGrid.remove_agent)
[#](#mesa.space.NetworkGrid.remove_agent "Link to this definition")
Remove the agent from the network and set its pos attribute to None.
Parameters:
**agent** – agent instance
is\_cell\_empty(_node\_id: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_) → [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
[\[source\]](../_modules/mesa/space.html#NetworkGrid.is_cell_empty)
[#](#mesa.space.NetworkGrid.is_cell_empty "Link to this definition")
Returns a bool of the contents of a cell.
Parameters:
**node\_id** – id of node
get\_cell\_list\_contents(_cell\_list: [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\][\[source\]](../_modules/mesa/space.html#NetworkGrid.get_cell_list_contents)
[#](#mesa.space.NetworkGrid.get_cell_list_contents "Link to this definition")
Returns a list of the agents contained in the nodes identified in cell\_list.
Nodes with empty content are excluded.
Parameters:
**cell\_list** – list of cell ids.
Returns:
list of the agents contained in the nodes identified in cell\_list.
get\_all\_cell\_contents() → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\][\[source\]](../_modules/mesa/space.html#NetworkGrid.get_all_cell_contents)
[#](#mesa.space.NetworkGrid.get_all_cell_contents "Link to this definition")
Returns a list of all the agents in the network.
iter\_cell\_list\_contents(_cell\_list: [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\]_) → [Iterator](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator "(in Python v3.13)")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\][\[source\]](../_modules/mesa/space.html#NetworkGrid.iter_cell_list_contents)
[#](#mesa.space.NetworkGrid.iter_cell_list_contents "Link to this definition")
Returns an iterator of the agents contained in the nodes identified in cell\_list.
Nodes with empty content are excluded.
Parameters:
**cell\_list** – list of cell ids.
Returns:
iterator of the agents contained in the nodes identified in cell\_list.
On this page
### This Page
* [Show Source](../_sources/apis/space.md.txt)
---
# Experimental — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Experimental[#](#experimental "Link to this heading")
======================================================
This namespace contains experimental features. These are under development, and their API is not necessarily stable.
Devs[#](#module-experimental.devs.eventlist "Link to this heading")
--------------------------------------------------------------------
Core event management functionality for Mesa’s discrete event simulation system.
This module provides the foundational data structures and classes needed for event-based simulation in Mesa. The EventList class is a priority queue implementation that maintains simulation events in chronological order while respecting event priorities. Key features:
* Priority-based event ordering
* Weak references to prevent memory leaks from canceled events
* Efficient event insertion and removal using a heap queue
* Support for event cancellation without breaking the heap structure
The module contains three main components: - Priority: An enumeration defining event priority levels (HIGH, DEFAULT, LOW) - SimulationEvent: A class representing individual events with timing and execution details - EventList: A heap-based priority queue managing the chronological ordering of events
The implementation supports both pure discrete event simulation and hybrid approaches combining agent-based modeling with event scheduling.
_class_ Priority(_\*values_)[\[source\]](../_modules/experimental/devs/eventlist.html#Priority)
[#](#experimental.devs.eventlist.Priority "Link to this definition")
Enumeration of priority levels.
_class_ SimulationEvent(_time: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
_, _function: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_, _priority: [Priority](#experimental.devs.eventlist.Priority "experimental.devs.eventlist.Priority")
\= Priority.DEFAULT_, _function\_args: [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\] | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _function\_kwargs: [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
, [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\] | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_)[\[source\]](../_modules/experimental/devs/eventlist.html#SimulationEvent)
[#](#experimental.devs.eventlist.SimulationEvent "Link to this definition")
A simulation event.
The callable is wrapped using weakref, so there is no need to explicitly cancel event if e.g., an agent is removed from the simulation.
time[#](#experimental.devs.eventlist.SimulationEvent.time "Link to this definition")
The simulation time of the event
Type:
[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
fn[#](#experimental.devs.eventlist.SimulationEvent.fn "Link to this definition")
The function to execute for this event
Type:
Callable
priority[#](#experimental.devs.eventlist.SimulationEvent.priority "Link to this definition")
The priority of the event
Type:
[Priority](#experimental.devs.eventlist.Priority "experimental.devs.eventlist.Priority")
unique\_id[#](#experimental.devs.eventlist.SimulationEvent.unique_id "Link to this definition")
Type:
[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
function\_args[#](#experimental.devs.eventlist.SimulationEvent.function_args "Link to this definition")
Argument for the function
Type:
[list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[Any\]
function\_kwargs[#](#experimental.devs.eventlist.SimulationEvent.function_kwargs "Link to this definition")
Keyword arguments for the function
Type:
Dict\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
, Any\]
Notes
simulation events use a weak reference to the callable. Therefore, you cannot pass a lambda function in fn. A simulation event where the callable no longer exists (e.g., because the agent has been removed from the model) will fail silently.
Initialize a simulation event.
Parameters:
* **time** – the instant of time of the simulation event
* **function** – the callable to invoke
* **priority** – the priority of the event
* **function\_args** – arguments for callable
* **function\_kwargs** – keyword arguments for the callable
execute()[\[source\]](../_modules/experimental/devs/eventlist.html#SimulationEvent.execute)
[#](#experimental.devs.eventlist.SimulationEvent.execute "Link to this definition")
Execute this event.
cancel() → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/experimental/devs/eventlist.html#SimulationEvent.cancel)
[#](#experimental.devs.eventlist.SimulationEvent.cancel "Link to this definition")
Cancel this event.
_class_ EventList[\[source\]](../_modules/experimental/devs/eventlist.html#EventList)
[#](#experimental.devs.eventlist.EventList "Link to this definition")
An event list.
This is a heap queue sorted list of events. Events are always removed from the left, so heapq is a performant and appropriate data structure. Events are sorted based on their time stamp, their priority, and their unique\_id as a tie-breaker, guaranteeing a complete ordering.
Initialize an event list.
add\_event(_event: [SimulationEvent](#experimental.devs.eventlist.SimulationEvent "experimental.devs.eventlist.SimulationEvent")
_)[\[source\]](../_modules/experimental/devs/eventlist.html#EventList.add_event)
[#](#experimental.devs.eventlist.EventList.add_event "Link to this definition")
Add the event to the event list.
Parameters:
**event** ([_SimulationEvent_](#experimental.devs.eventlist.SimulationEvent "experimental.devs.eventlist.SimulationEvent")
) – The event to be added
peak\_ahead(_n: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[SimulationEvent](#experimental.devs.eventlist.SimulationEvent "experimental.devs.eventlist.SimulationEvent")\
\][\[source\]](../_modules/experimental/devs/eventlist.html#EventList.peak_ahead)
[#](#experimental.devs.eventlist.EventList.peak_ahead "Link to this definition")
Look at the first n non-canceled event in the event list.
Parameters:
**n** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – The number of events to look ahead
Returns:
list\[SimulationEvent\]
Raises:
[**IndexError**](https://docs.python.org/3/library/exceptions.html#IndexError "(in Python v3.13)")
– If the eventlist is empty
Notes
this method can return a list shorted then n if the number of non-canceled events on the event list is less than n.
pop\_event() → [SimulationEvent](#experimental.devs.eventlist.SimulationEvent "experimental.devs.eventlist.SimulationEvent")
[\[source\]](../_modules/experimental/devs/eventlist.html#EventList.pop_event)
[#](#experimental.devs.eventlist.EventList.pop_event "Link to this definition")
Pop the first element from the event list.
is\_empty() → [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
[\[source\]](../_modules/experimental/devs/eventlist.html#EventList.is_empty)
[#](#experimental.devs.eventlist.EventList.is_empty "Link to this definition")
Return whether the event list is empty.
remove(_event: [SimulationEvent](#experimental.devs.eventlist.SimulationEvent "experimental.devs.eventlist.SimulationEvent")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/experimental/devs/eventlist.html#EventList.remove)
[#](#experimental.devs.eventlist.EventList.remove "Link to this definition")
Remove an event from the event list.
Parameters:
**event** ([_SimulationEvent_](#experimental.devs.eventlist.SimulationEvent "experimental.devs.eventlist.SimulationEvent")
) – The event to be removed
clear()[\[source\]](../_modules/experimental/devs/eventlist.html#EventList.clear)
[#](#experimental.devs.eventlist.EventList.clear "Link to this definition")
Clear the event list.
Simulator implementations for different time advancement approaches in Mesa.
This module provides simulator classes that control how simulation time advances and how events are executed. It supports both discrete-time and continuous-time simulations through three main classes:
* Simulator: Base class defining the core simulation control interface
* ABMSimulator: A simulator for agent-based models that combines fixed time steps with event scheduling. Uses integer time units and automatically schedules model.step()
* DEVSimulator: A pure discrete event simulator using floating-point time units for continuous time simulation
Key features: - Flexible time units (integer or float) - Event scheduling using absolute or relative times - Priority-based event execution - Support for running simulations for specific durations or until specific end times
The simulators enable Mesa models to use traditional time-step based approaches, pure event-driven approaches, or hybrid combinations of both.
_class_ Simulator(_time\_unit: [type](https://docs.python.org/3/library/functions.html#type "(in Python v3.13)")
_, _start\_time: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
_)[\[source\]](../_modules/experimental/devs/simulator.html#Simulator)
[#](#experimental.devs.simulator.Simulator "Link to this definition")
The Simulator controls the time advancement of the model.
The simulator uses next event time progression to advance the simulation time, and execute the next event
event\_list[#](#experimental.devs.simulator.Simulator.event_list "Link to this definition")
The list of events to execute
Type:
[EventList](#experimental.devs.eventlist.EventList "experimental.devs.eventlist.EventList")
time[#](#experimental.devs.simulator.Simulator.time "Link to this definition")
The current simulation time
Type:
[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
| [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
time\_unit[#](#experimental.devs.simulator.Simulator.time_unit "Link to this definition")
The unit of the simulation time
Type:
[type](https://docs.python.org/3/library/functions.html#type "(in Python v3.13)")
model[#](#experimental.devs.simulator.Simulator.model "Link to this definition")
The model to simulate
Type:
[Model](../mesa.html#mesa.model.Model "mesa.model.Model")
Initialize a Simulator instance.
Parameters:
* **time\_unit** – type of the smulaiton time
* **start\_time** – the starttime of the simulator
setup(_model: [Model](../mesa.html#mesa.model.Model "mesa.model.Model")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/experimental/devs/simulator.html#Simulator.setup)
[#](#experimental.devs.simulator.Simulator.setup "Link to this definition")
Set up the simulator with the model to simulate.
Parameters:
**model** ([_Model_](../mesa.html#mesa.model.Model "mesa.model.Model")
) – The model to simulate
Raises:
* **Exception if simulator.time is not equal to simulator.starttime** –
* **Exception if event list is not empty** –
reset()[\[source\]](../_modules/experimental/devs/simulator.html#Simulator.reset)
[#](#experimental.devs.simulator.Simulator.reset "Link to this definition")
Reset the simulator by clearing the event list and removing the model to simulate.
run\_until(_end\_time: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/experimental/devs/simulator.html#Simulator.run_until)
[#](#experimental.devs.simulator.Simulator.run_until "Link to this definition")
Run the simulator until the end time.
Parameters:
**end\_time** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_|_ [_float_](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
) – The end time for stopping the simulator
Raises:
**Exception if simulator.setup****(****)** **has not yet been called** –
run\_next\_event()[\[source\]](../_modules/experimental/devs/simulator.html#Simulator.run_next_event)
[#](#experimental.devs.simulator.Simulator.run_next_event "Link to this definition")
Execute the next event.
Raises:
**Exception if simulator.setup****(****)** **has not yet been called** –
run\_for(_time\_delta: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
_)[\[source\]](../_modules/experimental/devs/simulator.html#Simulator.run_for)
[#](#experimental.devs.simulator.Simulator.run_for "Link to this definition")
Run the simulator for the specified time delta.
Parameters:
**time\_delta** ([_float_](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
_|_ [_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – The time delta. The simulator is run from the current time to the current time plus the time delta
schedule\_event\_now(_function: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_, _priority: [Priority](#experimental.devs.eventlist.Priority "experimental.devs.eventlist.Priority")
\= Priority.DEFAULT_, _function\_args: [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\] | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _function\_kwargs: [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
, [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\] | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_) → [SimulationEvent](#experimental.devs.eventlist.SimulationEvent "experimental.devs.eventlist.SimulationEvent")
[\[source\]](../_modules/experimental/devs/simulator.html#Simulator.schedule_event_now)
[#](#experimental.devs.simulator.Simulator.schedule_event_now "Link to this definition")
Schedule event for the current time instant.
Parameters:
* **function** (_Callable_) – The callable to execute for this event
* **priority** ([_Priority_](#experimental.devs.eventlist.Priority "experimental.devs.eventlist.Priority")
) – the priority of the event, optional
* **function\_args** (_List__\[__Any__\]_) – list of arguments for function
* **function\_kwargs** (_Dict__\[_[_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
_,_ _Any__\]_) – dict of keyword arguments for function
Returns:
the simulation event that is scheduled
Return type:
[SimulationEvent](#experimental.devs.eventlist.SimulationEvent "experimental.devs.eventlist.SimulationEvent")
schedule\_event\_absolute(_function: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_, _time: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
_, _priority: [Priority](#experimental.devs.eventlist.Priority "experimental.devs.eventlist.Priority")
\= Priority.DEFAULT_, _function\_args: [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\] | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _function\_kwargs: [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
, [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\] | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_) → [SimulationEvent](#experimental.devs.eventlist.SimulationEvent "experimental.devs.eventlist.SimulationEvent")
[\[source\]](../_modules/experimental/devs/simulator.html#Simulator.schedule_event_absolute)
[#](#experimental.devs.simulator.Simulator.schedule_event_absolute "Link to this definition")
Schedule event for the specified time instant.
Parameters:
* **function** (_Callable_) – The callable to execute for this event
* **time** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_|_ [_float_](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
) – the time for which to schedule the event
* **priority** ([_Priority_](#experimental.devs.eventlist.Priority "experimental.devs.eventlist.Priority")
) – the priority of the event, optional
* **function\_args** (_List__\[__Any__\]_) – list of arguments for function
* **function\_kwargs** (_Dict__\[_[_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
_,_ _Any__\]_) – dict of keyword arguments for function
Returns:
the simulation event that is scheduled
Return type:
[SimulationEvent](#experimental.devs.eventlist.SimulationEvent "experimental.devs.eventlist.SimulationEvent")
schedule\_event\_relative(_function: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_, _time\_delta: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
_, _priority: [Priority](#experimental.devs.eventlist.Priority "experimental.devs.eventlist.Priority")
\= Priority.DEFAULT_, _function\_args: [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\] | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _function\_kwargs: [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
, [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\] | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_) → [SimulationEvent](#experimental.devs.eventlist.SimulationEvent "experimental.devs.eventlist.SimulationEvent")
[\[source\]](../_modules/experimental/devs/simulator.html#Simulator.schedule_event_relative)
[#](#experimental.devs.simulator.Simulator.schedule_event_relative "Link to this definition")
Schedule event for the current time plus the time delta.
Parameters:
* **function** (_Callable_) – The callable to execute for this event
* **time\_delta** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_|_ [_float_](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
) – the time delta
* **priority** ([_Priority_](#experimental.devs.eventlist.Priority "experimental.devs.eventlist.Priority")
) – the priority of the event, optional
* **function\_args** (_List__\[__Any__\]_) – list of arguments for function
* **function\_kwargs** (_Dict__\[_[_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
_,_ _Any__\]_) – dict of keyword arguments for function
Returns:
the simulation event that is scheduled
Return type:
[SimulationEvent](#experimental.devs.eventlist.SimulationEvent "experimental.devs.eventlist.SimulationEvent")
cancel\_event(_event: [SimulationEvent](#experimental.devs.eventlist.SimulationEvent "experimental.devs.eventlist.SimulationEvent")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/experimental/devs/simulator.html#Simulator.cancel_event)
[#](#experimental.devs.simulator.Simulator.cancel_event "Link to this definition")
Remove the event from the event list.
Parameters:
**event** ([_SimulationEvent_](#experimental.devs.eventlist.SimulationEvent "experimental.devs.eventlist.SimulationEvent")
) – The simulation event to remove
_class_ ABMSimulator[\[source\]](../_modules/experimental/devs/simulator.html#ABMSimulator)
[#](#experimental.devs.simulator.ABMSimulator "Link to this definition")
This simulator uses incremental time progression, while allowing for additional event scheduling.
The basic time unit of this simulator is an integer. It schedules model.step for each tick with the highest priority. This implies that by default, model.step is the first event executed at a specific tick. In addition, discrete event scheduling, using integer as the time unit is fully supported, paving the way for hybrid ABM-DEVS simulations.
Initialize a ABM simulator.
setup(_model_)[\[source\]](../_modules/experimental/devs/simulator.html#ABMSimulator.setup)
[#](#experimental.devs.simulator.ABMSimulator.setup "Link to this definition")
Set up the simulator with the model to simulate.
Parameters:
**model** ([_Model_](../mesa.html#mesa.model.Model "mesa.model.Model")
) – The model to simulate
check\_time\_unit(_time_) → [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
[\[source\]](../_modules/experimental/devs/simulator.html#ABMSimulator.check_time_unit)
[#](#experimental.devs.simulator.ABMSimulator.check_time_unit "Link to this definition")
Check whether the time is of the correct unit.
Parameters:
**time** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_|_ [_float_](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
) – the time
Returns:
whether the time is of the correct unit
Return type:
[bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
schedule\_event\_next\_tick(_function: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_, _priority: [Priority](#experimental.devs.eventlist.Priority "experimental.devs.eventlist.Priority")
\= Priority.DEFAULT_, _function\_args: [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\] | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _function\_kwargs: [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
, [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\] | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_) → [SimulationEvent](#experimental.devs.eventlist.SimulationEvent "experimental.devs.eventlist.SimulationEvent")
[\[source\]](../_modules/experimental/devs/simulator.html#ABMSimulator.schedule_event_next_tick)
[#](#experimental.devs.simulator.ABMSimulator.schedule_event_next_tick "Link to this definition")
Schedule a SimulationEvent for the next tick.
Parameters:
* **function** (_Callable_) – the callable to execute
* **priority** ([_Priority_](#experimental.devs.eventlist.Priority "experimental.devs.eventlist.Priority")
) – the priority of the event
* **function\_args** (_List__\[__Any__\]_) – List of arguments to pass to the callable
* **function\_kwargs** (_Dict__\[_[_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
_,_ _Any__\]_) – List of keyword arguments to pass to the callable
run\_until(_end\_time: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/experimental/devs/simulator.html#ABMSimulator.run_until)
[#](#experimental.devs.simulator.ABMSimulator.run_until "Link to this definition")
Run the simulator up to and included the specified end time.
Parameters:
**end\_time** ([_float_](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
_|_ [_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
) – The end\_time delta. The simulator is until the specified end time
Raises:
**Exception if simulator.setup****(****)** **has not yet been called** –
_class_ DEVSimulator[\[source\]](../_modules/experimental/devs/simulator.html#DEVSimulator)
[#](#experimental.devs.simulator.DEVSimulator "Link to this definition")
A simulator where the unit of time is a float.
Can be used for full-blown discrete event simulating using event scheduling.
Initialize a DEVS simulator.
check\_time\_unit(_time_) → [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
[\[source\]](../_modules/experimental/devs/simulator.html#DEVSimulator.check_time_unit)
[#](#experimental.devs.simulator.DEVSimulator.check_time_unit "Link to this definition")
Check whether the time is of the correct unit.
Parameters:
**time** ([_float_](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
) – the time
Returns: bool: whether the time is of the correct unit
Continuous Space[#](#module-experimental.continuous_space.continuous_space "Link to this heading")
---------------------------------------------------------------------------------------------------
A Continuous Space class.
_class_ ContinuousSpace(_dimensions: [Buffer](https://docs.python.org/3/library/collections.abc.html#collections.abc.Buffer "(in Python v3.13)")
| \_SupportsArray\[dtype\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\]\] | \_NestedSequence\[\_SupportsArray\[dtype\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\]\]\] | [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
| [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
| [complex](https://docs.python.org/3/library/functions.html#complex "(in Python v3.13)")
| [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
| [bytes](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.13)")
| \_NestedSequence\[[bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")\
| [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
| [complex](https://docs.python.org/3/library/functions.html#complex "(in Python v3.13)")\
| [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
| [bytes](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.13)")\
\]_, _torus: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _random: [Random](https://docs.python.org/3/library/random.html#random.Random "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _n\_agents: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 100_)[\[source\]](../_modules/experimental/continuous_space/continuous_space.html#ContinuousSpace)
[#](#experimental.continuous_space.continuous_space.ContinuousSpace "Link to this definition")
Continuous space where each agent can have an arbitrary position.
Create a new continuous space.
Parameters:
* **dimensions** – a numpy array like object where each row specifies the minimum and maximum value of that dimension.
* **torus** – boolean for whether the space wraps around or not
* **random** – a seeded stdlib random.Random instance
* **n\_agents** – the expected number of agents in the space
Internally, a numpy array is used to store the positions of all agents. This is resized if needed, but you can control the initial size explicitly by passing n\_agents.
_property_ agents_: [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
_[#](#experimental.continuous_space.continuous_space.ContinuousSpace.agents "Link to this definition")
Return an AgentSet with the agents in the space.
calculate\_difference\_vector(_point: ndarray_, _agents\=None_) → ndarray[\[source\]](../_modules/experimental/continuous_space/continuous_space.html#ContinuousSpace.calculate_difference_vector)
[#](#experimental.continuous_space.continuous_space.ContinuousSpace.calculate_difference_vector "Link to this definition")
Calculate the difference vector between the point and all agenents.
Parameters:
* **point** – the point to calculate the difference vector for
* **agents** – the agents to calculate the difference vector of point with. By default, all agents are considered.
calculate\_distances(_point: [Buffer](https://docs.python.org/3/library/collections.abc.html#collections.abc.Buffer "(in Python v3.13)")
| \_SupportsArray\[dtype\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\]\] | \_NestedSequence\[\_SupportsArray\[dtype\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\]\]\] | [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
| [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
| [complex](https://docs.python.org/3/library/functions.html#complex "(in Python v3.13)")
| [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
| [bytes](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.13)")
| \_NestedSequence\[[bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")\
| [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
| [complex](https://docs.python.org/3/library/functions.html#complex "(in Python v3.13)")\
| [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
| [bytes](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.13)")\
\]_, _agents: [Iterable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable "(in Python v3.13)")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\] | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _\*\*kwargs_) → [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[ndarray, [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")\
\][\[source\]](../_modules/experimental/continuous_space/continuous_space.html#ContinuousSpace.calculate_distances)
[#](#experimental.continuous_space.continuous_space.ContinuousSpace.calculate_distances "Link to this definition")
Calculate the distance between the point and all agents.
Parameters:
* **point** – the point to calculate the difference vector for
* **agents** – the agents to calculate the difference vector of point with. By default, all agents are considered.
* **kwargs** – any additional keyword arguments are passed to scipy’s cdist, which is used only if torus is False. This allows for non-Euclidian distance measures.
get\_agents\_in\_radius(_point: [Buffer](https://docs.python.org/3/library/collections.abc.html#collections.abc.Buffer "(in Python v3.13)")
| \_SupportsArray\[dtype\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\]\] | \_NestedSequence\[\_SupportsArray\[dtype\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\]\]\] | [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
| [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
| [complex](https://docs.python.org/3/library/functions.html#complex "(in Python v3.13)")
| [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
| [bytes](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.13)")
| \_NestedSequence\[[bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")\
| [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
| [complex](https://docs.python.org/3/library/functions.html#complex "(in Python v3.13)")\
| [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
| [bytes](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.13)")\
\]_, _radius: [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
| [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")\
, ndarray\][\[source\]](../_modules/experimental/continuous_space/continuous_space.html#ContinuousSpace.get_agents_in_radius)
[#](#experimental.continuous_space.continuous_space.ContinuousSpace.get_agents_in_radius "Link to this definition")
Return the agents and their distances within a radius for the point.
get\_k\_nearest\_agents(_point: [Buffer](https://docs.python.org/3/library/collections.abc.html#collections.abc.Buffer "(in Python v3.13)")
| \_SupportsArray\[dtype\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\]\] | \_NestedSequence\[\_SupportsArray\[dtype\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\]\]\] | [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
| [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
| [complex](https://docs.python.org/3/library/functions.html#complex "(in Python v3.13)")
| [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
| [bytes](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.13)")
| \_NestedSequence\[[bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")\
| [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
| [complex](https://docs.python.org/3/library/functions.html#complex "(in Python v3.13)")\
| [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
| [bytes](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.13)")\
\]_, _k: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")\
, ndarray\][\[source\]](../_modules/experimental/continuous_space/continuous_space.html#ContinuousSpace.get_k_nearest_agents)
[#](#experimental.continuous_space.continuous_space.ContinuousSpace.get_k_nearest_agents "Link to this definition")
Return the k nearest agents and their distances to the point.
Notes
This method returns exactly k agents, ignoring ties. In case of ties, the earlier an agent is inserted the higher it will rank.
in\_bounds(_point: [Buffer](https://docs.python.org/3/library/collections.abc.html#collections.abc.Buffer "(in Python v3.13)")
| \_SupportsArray\[dtype\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\]\] | \_NestedSequence\[\_SupportsArray\[dtype\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\]\]\] | [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
| [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
| [complex](https://docs.python.org/3/library/functions.html#complex "(in Python v3.13)")
| [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
| [bytes](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.13)")
| \_NestedSequence\[[bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")\
| [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
| [complex](https://docs.python.org/3/library/functions.html#complex "(in Python v3.13)")\
| [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
| [bytes](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.13)")\
\]_) → [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
[\[source\]](../_modules/experimental/continuous_space/continuous_space.html#ContinuousSpace.in_bounds)
[#](#experimental.continuous_space.continuous_space.ContinuousSpace.in_bounds "Link to this definition")
Check if point is inside the bounds of the space.
torus\_correct(_point: [Buffer](https://docs.python.org/3/library/collections.abc.html#collections.abc.Buffer "(in Python v3.13)")
| \_SupportsArray\[dtype\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\]\] | \_NestedSequence\[\_SupportsArray\[dtype\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\]\]\] | [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
| [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
| [complex](https://docs.python.org/3/library/functions.html#complex "(in Python v3.13)")
| [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
| [bytes](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.13)")
| \_NestedSequence\[[bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")\
| [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")\
| [complex](https://docs.python.org/3/library/functions.html#complex "(in Python v3.13)")\
| [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
| [bytes](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.13)")\
\]_) → ndarray[\[source\]](../_modules/experimental/continuous_space/continuous_space.html#ContinuousSpace.torus_correct)
[#](#experimental.continuous_space.continuous_space.ContinuousSpace.torus_correct "Link to this definition")
Apply a torus correction to the point.
Continuous space agents.
_class_ HasPositionProtocol(_\*args_, _\*\*kwargs_)[\[source\]](../_modules/experimental/continuous_space/continuous_space_agents.html#HasPositionProtocol)
[#](#experimental.continuous_space.continuous_space_agents.HasPositionProtocol "Link to this definition")
Protocol for continuous space position holders.
_class_ ContinuousSpaceAgent(_space: ContinuousSpace_, _model_)[\[source\]](../_modules/experimental/continuous_space/continuous_space_agents.html#ContinuousSpaceAgent)
[#](#experimental.continuous_space.continuous_space_agents.ContinuousSpaceAgent "Link to this definition")
A continuous space agent.
space[#](#experimental.continuous_space.continuous_space_agents.ContinuousSpaceAgent.space "Link to this definition")
the continuous space in which the agent is located
Type:
[ContinuousSpace](#experimental.continuous_space.continuous_space.ContinuousSpace "experimental.continuous_space.continuous_space.ContinuousSpace")
position[#](#experimental.continuous_space.continuous_space_agents.ContinuousSpaceAgent.position "Link to this definition")
the position of the agent
Type:
np.ndarray
Initialize a continuous space agent.
Parameters:
* **space** – the continuous space in which the agent is located
* **model** – the model to which the agent belongs
_property_ position_: ndarray_[#](#id0 "Link to this definition")
Position of the agent.
remove() → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/experimental/continuous_space/continuous_space_agents.html#ContinuousSpaceAgent.remove)
[#](#experimental.continuous_space.continuous_space_agents.ContinuousSpaceAgent.remove "Link to this definition")
Remove and delete the agent from the model and continuous space.
get\_neighbors\_in\_radius(_radius: [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
| [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")\
, ndarray\][\[source\]](../_modules/experimental/continuous_space/continuous_space_agents.html#ContinuousSpaceAgent.get_neighbors_in_radius)
[#](#experimental.continuous_space.continuous_space_agents.ContinuousSpaceAgent.get_neighbors_in_radius "Link to this definition")
Get neighbors within radius.
Parameters:
**radius** – radius within which to look for neighbors
get\_nearest\_neighbors(_k: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_) → [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")
\[[list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")\
, ndarray\][\[source\]](../_modules/experimental/continuous_space/continuous_space_agents.html#ContinuousSpaceAgent.get_nearest_neighbors)
[#](#experimental.continuous_space.continuous_space_agents.ContinuousSpaceAgent.get_nearest_neighbors "Link to this definition")
Get neighbors within radius.
Parameters:
**k** – the number of nearest neighbors to return
On this page
### This Page
* [Show Source](../_sources/apis/experimental.md.txt)
---
# Documentation page not found
- Read the Docs
[mesa.readthedocs.io](/)
The documentation page you requested does not exist or may have been removed.
Hosted by [](//readthedocs.org/)
---
# Unknown
{ "cells": \[ { "cell\_type": "markdown", "metadata": {}, "source": \[ "# Adding Space\\n", "\\n", "### The Boltzmann Wealth Model " \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "If you want to get straight to the tutorial checkout these environment providers: \
\\n", "(with Google Account) \[!\[Colab\](https://colab.research.google.com/assets/colab-badge.svg)\](https://colab.research.google.com/github/projectmesa/mesa/blob/main/docs/tutorials/1\_adding\_space.ipynb) \
\\n", "(no Google Account) \[!\[Binder\](https://mybinder.org/badge\_logo.svg)\](https://mybinder.org/v2/gh/projectmesa/mesa/main?labpath=docs%2Ftutorials%2F1\_adding\_space.ipynb) (This can take 30 seconds to 5 minutes to load)\\n", "\\n", "\*If you are running locally, please ensure you have the latest Mesa version installed.\*\\n", "\\n", "## Tutorial Description\\n", "\\n", "This tutorial extends the Boltzmann wealth model from the \[Running Your First Model tutorial\](https://mesa.readthedocs.io/latest/tutorials/0\_first\_model.html), by adding Mesa's discrete space module. \\n", "\\n", "In this portion, \`MoneyAgent\`s will move in a two dimensional grid, made up of discrete cells and randomly exchange money with other agents. \\n", "\\n", "\*If you are starting here please see the \[Running Your First Model tutorial\](https://mesa.readthedocs.io/latest/tutorials/0\_first\_model.html) for dependency and start-up instructions\*" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### IN COLAB? - Run the next cell " \] }, { "cell\_type": "raw", "metadata": { "vscode": { "languageId": "raw" } }, "source": \[ "%pip install --quiet mesa\[rec\]" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Import Dependencies\\n", "This includes importing of dependencies needed for the tutorial." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "outputs": \[\], "source": \[ "# Has multi-dimensional arrays and matrices.\\n", "# Has a large collection of mathematical functions to operate on these arrays.\\n", "import numpy as np\\n", "\\n", "# Data manipulation and analysis.\\n", "import pandas as pd\\n", "\\n", "# Data visualization tools.\\n", "import seaborn as sns\\n", "\\n", "import mesa" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Base Model\\n", "\\n", "The below provides the base model from which we will add our space functionality. \\n", "\\n", "This is from the \[Running Your First Model tutorial\](https://mesa.readthedocs.io/latest/tutorials/0\_first\_model.html) tutorial. If you have any questions about it functionality please review that tutorial." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "class MoneyAgent(mesa.Agent):\\n", " \\"\\"\\"An agent with fixed initial wealth.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, model):\\n", " # Pass the parameters to the parent class.\\n", " super().\_\_init\_\_(model)\\n", "\\n", " # Create the agent's variable and set the initial values.\\n", " self.wealth = 1\\n", "\\n", " def exchange(self):\\n", " # Verify agent has some wealth\\n", " if self.wealth > 0:\\n", " other\_agent = self.random.choice(self.model.agents)\\n", " if other\_agent is not None:\\n", " other\_agent.wealth += 1\\n", " self.wealth -= 1\\n", "\\n", "\\n", "class MoneyModel(mesa.Model):\\n", " \\"\\"\\"A model with some number of agents.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, n):\\n", " super().\_\_init\_\_()\\n", " self.num\_agents = n\\n", "\\n", " # Create agents\\n", " MoneyAgent.create\_agents(model=self, n=n)\\n", "\\n", " def step(self):\\n", " \\"\\"\\"Advance the model by one step.\\"\\"\\"\\n", " # This function psuedo-randomly reorders the list of agent objects and\\n", " # then iterates through calling the function passed in as the parameter\\n", " self.agents.shuffle\_do(\\"exchange\\")" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "# Execute the model\\n", "model = MoneyModel(10)\\n", "model.step()\\n", "# Make sure it worked\\n", "print(f\\"You have {len(model.agents)} agents.\\")" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Adding space\\n", "\\n", "\*\*Background:\*\* Due to the complex dynamics of space and movement, Mesa offers a wide range space options and has built a structure to allow for the addition of even more spaces or custom user space creation. (Please contribute to Mesa if you develop a new space that can add to user options.)\\n", "\\n", "The two main approaches to space are discrete space (think cells or nodes that agents occupy) and continuous space (agents can occupy any location(s) in a three-dimensional space). Continuous space is still experimental as we continue to develop it.\\n", "\\n", "\*\*Overview of Discrete Space:\*\* For this tutorial we will be using discrete space in the classic cartesian coordinated system. As indicated in the diagram discrete space is made up of two modules. Cells and Cell Agents. \\n", "\\n", "\*\*Cells:\*\*\\n", "The cell class represents a location that can:\\n", "- Have properties (like temperature or resources)\\n", "- Track and limit the agents it contains\\n", "- Connect to neighboring cells\\n", "- Provide neighborhood information\\n", "\\n", "Cells form the foundation of the cell space system, enabling rich spatial environments where both location properties and agent behaviors matter. They're useful for modeling things like varying terrain, infrastructure capacity, or environmental conditions.\\n", "\\n", "\*\*Cell Agents:\*\*\\n", "Agents that understand how to exist in and move through cell spaces.\\n", "\\n", "Cell Agents are specialized agent classes that handle cell occupation, movement, and proper registration:\\n", "- \`CellAgent\`: Mobile agents that can move between cells\\n", "- \`FixedAgent\`: Immobile agents permanently fixed to cells\\n", "- \`Grid2DMovingAgent\`: Agents with grid-specific movement capabilities\\n", "\\n", "These classes ensure consistent agent-cell relationships and proper state management as agents move through the space. They can be used directly or as examples for creating custom cell-aware agents.\\n", "\\n", "From these basic building blocks we can then add features to allow for different types of spaces and behaviors. To keep this tutorial concise we will not go through all of them, however, the current layout of discrete space is below as well as the different support modules. To find out more about the other options and what they can do, check out the \[Discrete Space API\](https://mesa.readthedocs.io/latest/apis/discrete\_space.html)\\n", "\\n", " \
\
\\n", "!\[Discerete Space Diagram\](../images/Discrete\_Space.drawio.png)\\n", " \
\\n", "\\n", "\*A big thanks to maintainer qualquel and his creation of this exceptional space dynamic.\*" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "\\n", "\*\*Model-specific information:\*\* In addition to using discrete space, the agents will access their \[Moore neighborhood\](https://en.wikipedia.org/wiki/Moore\_neighborhood). A Moore neighborhood means agents can interact with 8 neighbors. Instead of giving their unit of money to any random agent, they'll give it to an agent on the same cell. For the Money model multiple agents can be in the same spaces and since they are on a torus the agents on the left side can exchange money with agent on the right. Agents on the top can exchange with agents on the bottom." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "#### Code Implementation\\n", "\\n", "To ensure we give our agents discrete space functionality we now instantiate our \`MoneyAgent\`s as \`CellAgent\`s. \`Cell Agent\` is a subclass to Mesa's \`Agent\` class that is specifically built to interact and move within the \`discrete space\` module. \\n", "\\n", "Below highlights each of the changes to the base code to add space and movement of agents. \\n", "\\n", "\*\*Imports\*\* \
\\n", "\\\\# Import Cell Agent and OrthogonalMooreGrid\\n", "- \*Description:\* Import the cell agent class and a specific grid construct the OrthognalMooreGrid.\\n", "- \*API\*: \[CellAgent\](https://mesa.readthedocs.io/latest/apis/discrete\_space.html#mesa.discrete\_space.\_\_init\_\_.CellAgent) and \[OrthogonalMooreGrid\](https://mesa.readthedocs.io/latest/apis/discrete\_space.html#mesa.discrete\_space.grid.OrthogonalMooreGrid)\\n", "\\n", "\*\*MoneyAgent Class\*\* \
\\n", "\\\\# Instantiate MoneyAgent as CellAgent\\n", "- \*Description:\* \`MoneyAgent\` inherits \`CellAgent\`, a subclass of \`Agent\`.\\n", "- \*API\*: \[CellAgent\](https://mesa.readthedocs.io/latest/apis/discrete\_space.html#mesa.discrete\_space.\_\_init\_\_.CellAgent)\\n", "\\n", "\\\\# Instantiate agent with location (x,y)\\n", "- \*Description:\* Pass the cell object as a parameter to the agent to give the agent a location\\n", "- \*API\*: N/A\\n", "\\n", "\\\\# Move function\\n", "- \*Description:\* Update the agents cell through methods in Mesa's discrete\_space module \`neighborhood\`, which defaults to radius one and \`select\_random\_cell\` which selects a random cell for the provided neighborhood \\n", "- \*API\*: \[neighborhood\](https://mesa.readthedocs.io/latest/apis/discrete\_space.html#mesa.discrete\_space.\_\_init\_\_.Cell.neighborhood) and \[select\_random\_cell\](https://mesa.readthedocs.io/latest/apis/discrete\_space.html#mesa.discrete\_space.\_\_init\_\_.CellCollection.select\_random\_cell)\\n", "\\n", "\*\*MoneyModel Class\*\* \
\\n", "\\\\# Instantiate an instance of Moore neighborhood space\\n", "- \*Description:\* Instantiate a OrthgonalMooreGrid as \`self.grid\` with passing in the parameters width and height as a tuple, torus as True, a cell capacity of 5 agents, and the models random seed to the discrete space \\n", "- \*API\*: \[OrthogonalMooreGrid\](https://mesa.readthedocs.io/latest/apis/discrete\_space.html#mesa.discrete\_space.grid.OrthogonalMooreGrid)\\n", "\\n", "\\\\# Randomly select agents cell\\n", "- \*Description:\* Use Python's \`random.choices\` and pass in all cells with discrete space all\_cells properties and the number of choices \`k\` to assign each agent a location. \\n", "- \*API\*: \[random.choices\](https://docs.python.org/3/library/random.html#random.choices) and \[all\_cells\](https://mesa.readthedocs.io/latest/apis/discrete\_space.html#id1)" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "# Import Cell Agent and OrthogonalMooreGrid\\n", "from mesa.discrete\_space import CellAgent, OrthogonalMooreGrid\\n", "\\n", "\\n", "# Instantiate MoneyAgent as CellAgent\\n", "class MoneyAgent(CellAgent):\\n", " \\"\\"\\"An agent with fixed initial wealth.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, model, cell):\\n", " super().\_\_init\_\_(model)\\n", " self.cell = cell # Instantiate agent with location (x,y)\\n", " self.wealth = 1\\n", "\\n", " # Move Function\\n", " def move(self):\\n", " self.cell = self.cell.neighborhood.select\_random\_cell()\\n", "\\n", " def give\_money(self):\\n", " cellmates = \[\\n", " a for a in self.cell.agents if a is not self\\n", " \] # Get all agents in cell\\n", "\\n", " if self.wealth > 0 and cellmates:\\n", " other\_agent = self.random.choice(cellmates)\\n", " other\_agent.wealth += 1\\n", " self.wealth -= 1\\n", "\\n", "\\n", "class MoneyModel(mesa.Model):\\n", " \\"\\"\\"A model with some number of agents.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, n, width, height, seed=None):\\n", " super().\_\_init\_\_(seed=seed)\\n", " self.num\_agents = n\\n", " # Instantiate an instance of Moore neighborhood space\\n", " self.grid = OrthogonalMooreGrid(\\n", " (width, height), torus=True, capacity=10, random=self.random\\n", " )\\n", "\\n", " # Create agents\\n", " agents = MoneyAgent.create\_agents(\\n", " self,\\n", " self.num\_agents,\\n", " # Randomly select agents cell\\n", " self.random.choices(self.grid.all\_cells.cells, k=self.num\_agents),\\n", " )\\n", "\\n", " def step(self):\\n", " self.agents.shuffle\_do(\\"move\\")\\n", " self.agents.do(\\"give\_money\\")" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "Let's create a model with 100 agents on a 10x10 grid, and run it for 20 steps." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "model = MoneyModel(100, 10, 10)\\n", "for \_ in range(20):\\n", " model.step()" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "Now let's use seaborn and numpy to visualize the number of agents residing in each cell. To do that, we create a numpy array of the same size as the grid, filled with zeros. \\n", "\\n", "Then again use \`all\_cells\` to loop over every cell in the grid, giving us each cell's position (cell coordinate attribute) and its contents (cell agent attribute). \\n", "\\n", "\[Cell API\](https://mesa.readthedocs.io/latest/apis/discrete\_space.html#mesa.discrete\_space.\_\_init\_\_.Cell)" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "agent\_counts = np.zeros((model.grid.width, model.grid.height))\\n", "\\n", "for cell in model.grid.all\_cells:\\n", " agent\_counts\[cell.coordinate\] = len(cell.agents)\\n", "# Plot using seaborn, with a visual size of 5x5\\n", "g = sns.heatmap(agent\_counts, cmap=\\"viridis\\", annot=True, cbar=False, square=True)\\n", "g.figure.set\_size\_inches(5, 5)\\n", "g.set(title=\\"Number of agents on each cell of the grid\\");" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Exercises\\n", "- Change the size of the grid\\n", "- Change the capacity of the cells\\n", "- Try a different grid space like OrthognalVonNeumann, Network, or Voronoi" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Next Steps\\n", "\\n", "Check out the \[collecting data tutorial\](https://mesa.readthedocs.io/latest/tutorials/2\_collecting\_data\_tutorial.html) on how to collect data form your model." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "\[Comer2014\] Comer, Kenneth W. “Who Goes First? An Examination of the Impact of Activation on Outcome Behavior in AgentBased Models.” George Mason University, 2014. http://mars.gmu.edu/bitstream/handle/1920/9070/Comer\_gmu\_0883E\_10539.pdf\\n", "\\n", "\[Dragulescu2002\] Drăgulescu, Adrian A., and Victor M. Yakovenko. “Statistical Mechanics of Money, Income, and Wealth: A Short Survey.” arXiv Preprint Cond-mat/0211175, 2002. http://arxiv.org/abs/cond-mat/0211175." \] } \], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display\_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language\_info": { "codemirror\_mode": { "name": "ipython", "version": 3 }, "file\_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert\_exporter": "python", "pygments\_lexer": "ipython3", "version": "3.12.5" }, "widgets": { "state": {}, "version": "1.1.2" } }, "nbformat": 4, "nbformat\_minor": 4 }
---
# Conway’s Game Of “Life” — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Conway’s Game Of “Life”[#](#conway-s-game-of-life "Link to this heading")
==========================================================================
Summary[#](#summary "Link to this heading")
--------------------------------------------
[The Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life)
, also known simply as “Life”, is a cellular automaton devised by the British mathematician John Horton Conway in 1970.
The “game” is a zero-player game, meaning that its evolution is determined by its initial state, requiring no further input by a human. One interacts with the Game of “Life” by creating an initial configuration and observing how it evolves, or, for advanced “players”, by creating patterns with particular properties.
How to Run[#](#how-to-run "Link to this heading")
--------------------------------------------------
To run the model interactively you can use either the streamlit or solara version. For solara, you use
$ solara run app.py
For streamlit, you need
$ streamlit run st\_app.py
This will open your browser and show you the controls. You can start the model by hitting the run button.
Files[#](#files "Link to this heading")
----------------------------------------
* `agents.py`: Defines the behavior of an individual cell, which can be in two states: DEAD or ALIVE.
* `model.py`: Defines the model itself, initialized with a random configuration of alive and dead cells.
* `app.py`: Defines an interactive visualization using solara.
* `st_app.py`: Defines an interactive visualization using Streamlit.
Optional[#](#optional "Link to this heading")
----------------------------------------------
* For the streamlit version, you need to have streamlit installed (can be done via pip install streamlit)
Further Reading[#](#further-reading "Link to this heading")
------------------------------------------------------------
[Conway’s Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life)
Agents[#](#agents "Link to this heading")
------------------------------------------
from mesa.discrete\_space import FixedAgent
class Cell(FixedAgent):
"""Represents a single ALIVE or DEAD cell in the simulation."""
DEAD \= 0
ALIVE \= 1
@property
def x(self):
return self.cell.coordinate\[0\]
@property
def y(self):
return self.cell.coordinate\[1\]
def \_\_init\_\_(self, model, cell, init\_state\=DEAD):
"""Create a cell, in the given state, at the given x, y position."""
super().\_\_init\_\_(model)
self.cell \= cell
self.state \= init\_state
self.\_next\_state \= None
@property
def is\_alive(self):
return self.state \== self.ALIVE
@property
def neighbors(self):
return self.cell.neighborhood.agents
def determine\_state(self):
"""Compute if the cell will be dead or alive at the next tick. This is
based on the number of alive or dead neighbors. The state is not
changed here, but is just computed and stored in self.\_nextState,
because our current state may still be necessary for our neighbors
to calculate their next state.
"""
\# Get the neighbors and apply the rules on whether to be alive or dead
\# at the next tick.
live\_neighbors \= sum(neighbor.is\_alive for neighbor in self.neighbors)
\# Assume nextState is unchanged, unless changed below.
self.\_next\_state \= self.state
if self.is\_alive:
if live\_neighbors < 2 or live\_neighbors \> 3:
self.\_next\_state \= self.DEAD
else:
if live\_neighbors \== 3:
self.\_next\_state \= self.ALIVE
def assume\_state(self):
"""Set the state to the new computed state -- computed in step()."""
self.state \= self.\_next\_state
Model[#](#model "Link to this heading")
----------------------------------------
from mesa import Model
from mesa.discrete\_space import OrthogonalMooreGrid
from mesa.examples.basic.conways\_game\_of\_life.agents import Cell
class ConwaysGameOfLife(Model):
"""Represents the 2-dimensional array of cells in Conway's Game of Life."""
def \_\_init\_\_(self, width\=50, height\=50, initial\_fraction\_alive\=0.2, seed\=None):
"""Create a new playing area of (width, height) cells."""
super().\_\_init\_\_(seed\=seed)
\# Use a simple grid, where edges wrap around.
self.grid \= OrthogonalMooreGrid((width, height), capacity\=1, torus\=True)
\# Place a cell at each location, with some initialized to
\# ALIVE and some to DEAD.
for cell in self.grid.all\_cells:
Cell(
self,
cell,
init\_state\=Cell.ALIVE
if self.random.random() < initial\_fraction\_alive
else Cell.DEAD,
)
self.running \= True
def step(self):
"""Perform the model step in two stages:
- First, all cells assume their next state (whether they will be dead or alive)
- Then, all cells change state to their next state.
"""
self.agents.do("determine\_state")
self.agents.do("assume\_state")
App[#](#app "Link to this heading")
------------------------------------
from mesa.examples.basic.conways\_game\_of\_life.model import ConwaysGameOfLife
from mesa.visualization import (
SolaraViz,
make\_space\_component,
)
def agent\_portrayal(agent):
return {
"color": "white" if agent.state \== 0 else "black",
"marker": "s",
"size": 25,
}
def post\_process(ax):
ax.set\_aspect("equal")
ax.set\_xticks(\[\])
ax.set\_yticks(\[\])
model\_params \= {
"seed": {
"type": "InputText",
"value": 42,
"label": "Random Seed",
},
"width": {
"type": "SliderInt",
"value": 50,
"label": "Width",
"min": 5,
"max": 60,
"step": 1,
},
"height": {
"type": "SliderInt",
"value": 50,
"label": "Height",
"min": 5,
"max": 60,
"step": 1,
},
"initial\_fraction\_alive": {
"type": "SliderFloat",
"value": 0.2,
"label": "Cells initially alive",
"min": 0,
"max": 1,
"step": 0.01,
},
}
\# Create initial model instance
model1 \= ConwaysGameOfLife()
\# Create visualization elements. The visualization elements are solara components
\# that receive the model instance as a "prop" and display it in a certain way.
\# Under the hood these are just classes that receive the model instance.
\# You can also author your own visualization elements, which can also be functions
\# that receive the model instance and return a valid solara component.
SpaceGraph \= make\_space\_component(
agent\_portrayal, post\_process\=post\_process, draw\_grid\=False
)
\# Create the SolaraViz page. This will automatically create a server and display the
\# visualization elements in a web browser.
\# Display it using the following command in the example directory:
\# solara run app.py
\# It will automatically update and display any changes made to this file
page \= SolaraViz(
model1,
components\=\[SpaceGraph\],
model\_params\=model\_params,
name\="Game of Life",
)
page \# noqa
On this page
### This Page
* [Show Source](../../_sources/examples/basic/conways_game_of_life.md.txt)
---
# Batchrunner — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Batchrunner[#](#module-batchrunner "Link to this heading")
===========================================================
batchrunner for running a factorial experiment design over a model.
To take advantage of parallel execution of experiments, batch\_run uses multiprocessing if `number_processes` is larger than 1. It is strongly advised to only run in parallel using a normal python file (so don’t try to do it in a jupyter notebook). This is because Jupyter notebooks have a different execution model that can cause issues with Python’s multiprocessing module, especially on Windows. The main problems include the lack of a traditional \_\_main\_\_ entry point, serialization issues, and potential deadlocks.
Moreover, best practice when using multiprocessing is to put the code inside an `if __name__ == '__main__':` code black as shown below:
from mesa.batchrunner import batch\_run
params \= {"width": 10, "height": 10, "N": range(10, 500, 10)}
if \_\_name\_\_ \== '\_\_main\_\_':
results \= batch\_run(
MoneyModel,
parameters\=params,
iterations\=5,
max\_steps\=100,
number\_processes\=None,
data\_collection\_period\=1,
display\_progress\=True,
)
batch\_run(_model\_cls: [type](https://docs.python.org/3/library/functions.html#type "(in Python v3.13)")
\[[Model](../mesa.html#mesa.model.Model "mesa.model.Model")\
\]_, _parameters: [Mapping](https://docs.python.org/3/library/collections.abc.html#collections.abc.Mapping "(in Python v3.13)")
\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
, [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
| [Iterable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable "(in Python v3.13)")\
\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\]\]_, _number\_processes: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= 1_, _iterations: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1_, _data\_collection\_period: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= \-1_, _max\_steps: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
\= 1000_, _display\_progress: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= True_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")\
\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
, [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\]\][\[source\]](../_modules/batchrunner.html#batch_run)
[#](#batchrunner.batch_run "Link to this definition")
Batch run a mesa model with a set of parameter values.
Parameters:
* **model\_cls** (_Type__\[_[_Model_](../mesa.html#mesa.model.Model "mesa.model.Model")\
_\]_) – The model class to batch-run
* **parameters** (_Mapping__\[_[_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
_,_ _Union__\[__Any__,_ _Iterable__\[__Any__\]__\]__\]_) – Dictionary with model parameters over which to run the model. You can either pass single values or iterables.
* **number\_processes** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_,_ _optional_) – Number of processes used, by default 1. Set this to None if you want to use all CPUs.
* **iterations** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_,_ _optional_) – Number of iterations for each parameter combination, by default 1
* **data\_collection\_period** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_,_ _optional_) – Number of steps after which data gets collected, by default -1 (end of episode)
* **max\_steps** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_,_ _optional_) – Maximum number of model steps after which the model halts, by default 1000
* **display\_progress** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_,_ _optional_) – Display batch run process, by default True
Returns:
List\[Dict\[str, Any\]\]
Notes
batch\_run assumes the model has a datacollector attribute that has a DataCollector object initialized.
On this page
### This Page
* [Show Source](../_sources/apis/batchrunner.md.txt)
---
# Wolf-Sheep Predation Model — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Wolf-Sheep Predation Model[#](#wolf-sheep-predation-model "Link to this heading")
==================================================================================
Summary[#](#summary "Link to this heading")
--------------------------------------------
A simple ecological model, consisting of three agent types: wolves, sheep, and grass. The wolves and the sheep wander around the grid at random. Wolves and sheep both expend energy moving around, and replenish it by eating. Sheep eat grass, and wolves eat sheep if they end up on the same grid cell.
If wolves and sheep have enough energy, they reproduce, creating a new wolf or sheep (in this simplified model, only one parent is needed for reproduction). The grass on each cell regrows at a constant rate. If any wolves and sheep run out of energy, they die.
The model is tests and demonstrates several Mesa concepts and features:
* MultiGrid
* Multiple agent types (wolves, sheep, grass)
* Overlay arbitrary text (wolf’s energy) on agent’s shapes while drawing on CanvasGrid
* Agents inheriting a behavior (random movement) from an abstract parent
* Writing a model composed of multiple files.
* Dynamically adding and removing agents from the schedule
Installation[#](#installation "Link to this heading")
------------------------------------------------------
To install the dependencies use pip and the requirements.txt in this directory. e.g.
# First, we clone the Mesa repo
$ git clone https://github.com/projectmesa/mesa.git
$ cd mesa
# Then we cd to the example directory
$ cd examples/wolf\_sheep
$ pip install -r requirements.txt
How to Run[#](#how-to-run "Link to this heading")
--------------------------------------------------
To run the model interactively, run `mesa runserver` in this directory. e.g.
$ mesa runserver
Then open your browser to [http://127.0.0.1:8521/](http://127.0.0.1:8521/)
and press Reset, then Run.
Files[#](#files "Link to this heading")
----------------------------------------
* `wolf_sheep/random_walk.py`: This defines the `RandomWalker` agent, which implements the behavior of moving randomly across a grid, one cell at a time. Both the Wolf and Sheep agents will inherit from it.
* `wolf_sheep/test_random_walk.py`: Defines a simple model and a text-only visualization intended to make sure the RandomWalk class was working as expected. This doesn’t actually model anything, but serves as an ad-hoc unit test. To run it, `cd` into the `wolf_sheep` directory and run `python test_random_walk.py`. You’ll see a series of ASCII grids, one per model step, with each cell showing a count of the number of agents in it.
* `wolf_sheep/agents.py`: Defines the Wolf, Sheep, and GrassPatch agent classes.
* `wolf_sheep/scheduler.py`: Defines a custom variant on the RandomActivationByType scheduler, where we can define filters for the `get_type_count` function.
* `wolf_sheep/model.py`: Defines the Wolf-Sheep Predation model itself
* `wolf_sheep/server.py`: Sets up the interactive visualization server
* `run.py`: Launches a model visualization server.
Further Reading[#](#further-reading "Link to this heading")
------------------------------------------------------------
This model is closely based on the NetLogo Wolf-Sheep Predation Model:
Wilensky, U. (1997). NetLogo Wolf Sheep Predation model. http://ccl.northwestern.edu/netlogo/models/WolfSheepPredation. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
See also the [Lotka–Volterra equations](https://en.wikipedia.org/wiki/Lotka%E2%80%93Volterra_equations)
for an example of a classic differential-equation model with similar dynamics.
Agents[#](#agents "Link to this heading")
------------------------------------------
from mesa.discrete\_space import CellAgent, FixedAgent
class Animal(CellAgent):
"""The base animal class."""
def \_\_init\_\_(
self, model, energy\=8, p\_reproduce\=0.04, energy\_from\_food\=4, cell\=None
):
"""Initialize an animal.
Args:
model: Model instance
energy: Starting amount of energy
p\_reproduce: Probability of reproduction (asexual)
energy\_from\_food: Energy obtained from 1 unit of food
cell: Cell in which the animal starts
"""
super().\_\_init\_\_(model)
self.energy \= energy
self.p\_reproduce \= p\_reproduce
self.energy\_from\_food \= energy\_from\_food
self.cell \= cell
def spawn\_offspring(self):
"""Create offspring by splitting energy and creating new instance."""
self.energy /= 2
self.\_\_class\_\_(
self.model,
self.energy,
self.p\_reproduce,
self.energy\_from\_food,
self.cell,
)
def feed(self):
"""Abstract method to be implemented by subclasses."""
def step(self):
"""Execute one step of the animal's behavior."""
\# Move to random neighboring cell
self.move()
self.energy \-= 1
\# Try to feed
self.feed()
\# Handle death and reproduction
if self.energy < 0:
self.remove()
elif self.random.random() < self.p\_reproduce:
self.spawn\_offspring()
class Sheep(Animal):
"""A sheep that walks around, reproduces (asexually) and gets eaten."""
def feed(self):
"""If possible, eat grass at current location."""
grass\_patch \= next(
obj for obj in self.cell.agents if isinstance(obj, GrassPatch)
)
if grass\_patch.fully\_grown:
self.energy += self.energy\_from\_food
grass\_patch.fully\_grown \= False
def move(self):
"""Move towards a cell where there isn't a wolf, and preferably with grown grass."""
cells\_without\_wolves \= self.cell.neighborhood.select(
lambda cell: not any(isinstance(obj, Wolf) for obj in cell.agents)
)
\# If all surrounding cells have wolves, stay put
if len(cells\_without\_wolves) \== 0:
return
\# Among safe cells, prefer those with grown grass
cells\_with\_grass \= cells\_without\_wolves.select(
lambda cell: any(
isinstance(obj, GrassPatch) and obj.fully\_grown for obj in cell.agents
)
)
\# Move to a cell with grass if available, otherwise move to any safe cell
target\_cells \= (
cells\_with\_grass if len(cells\_with\_grass) \> 0 else cells\_without\_wolves
)
self.cell \= target\_cells.select\_random\_cell()
class Wolf(Animal):
"""A wolf that walks around, reproduces (asexually) and eats sheep."""
def feed(self):
"""If possible, eat a sheep at current location."""
sheep \= \[obj for obj in self.cell.agents if isinstance(obj, Sheep)\]
if sheep: \# If there are any sheep present
sheep\_to\_eat \= self.random.choice(sheep)
self.energy += self.energy\_from\_food
sheep\_to\_eat.remove()
def move(self):
"""Move to a neighboring cell, preferably one with sheep."""
cells\_with\_sheep \= self.cell.neighborhood.select(
lambda cell: any(isinstance(obj, Sheep) for obj in cell.agents)
)
target\_cells \= (
cells\_with\_sheep if len(cells\_with\_sheep) \> 0 else self.cell.neighborhood
)
self.cell \= target\_cells.select\_random\_cell()
class GrassPatch(FixedAgent):
"""A patch of grass that grows at a fixed rate and can be eaten by sheep."""
@property
def fully\_grown(self):
"""Whether the grass patch is fully grown."""
return self.\_fully\_grown
@fully\_grown.setter
def fully\_grown(self, value: bool) \-> None:
"""Set grass growth state and schedule regrowth if eaten."""
self.\_fully\_grown \= value
if not value: \# If grass was just eaten
self.model.simulator.schedule\_event\_relative(
setattr,
self.grass\_regrowth\_time,
function\_args\=\[self, "fully\_grown", True\],
)
def \_\_init\_\_(self, model, countdown, grass\_regrowth\_time, cell):
"""Create a new patch of grass.
Args:
model: Model instance
countdown: Time until grass is fully grown again
grass\_regrowth\_time: Time needed to regrow after being eaten
cell: Cell to which this grass patch belongs
"""
super().\_\_init\_\_(model)
self.\_fully\_grown \= countdown \== 0
self.grass\_regrowth\_time \= grass\_regrowth\_time
self.cell \= cell
\# Schedule initial growth if not fully grown
if not self.fully\_grown:
self.model.simulator.schedule\_event\_relative(
setattr, countdown, function\_args\=\[self, "fully\_grown", True\]
)
Model[#](#model "Link to this heading")
----------------------------------------
"""
Wolf-Sheep Predation Model
\================================
Replication of the model found in NetLogo:
Wilensky, U. (1997). NetLogo Wolf Sheep Predation model.
http://ccl.northwestern.edu/netlogo/models/WolfSheepPredation.
Center for Connected Learning and Computer-Based Modeling,
Northwestern University, Evanston, IL.
"""
import math
from mesa import Model
from mesa.datacollection import DataCollector
from mesa.discrete\_space import OrthogonalVonNeumannGrid
from mesa.examples.advanced.wolf\_sheep.agents import GrassPatch, Sheep, Wolf
from mesa.experimental.devs import ABMSimulator
class WolfSheep(Model):
"""Wolf-Sheep Predation Model.
A model for simulating wolf and sheep (predator-prey) ecosystem modelling.
"""
description \= (
"A model for simulating wolf and sheep (predator-prey) ecosystem modelling."
)
def \_\_init\_\_(
self,
width\=20,
height\=20,
initial\_sheep\=100,
initial\_wolves\=50,
sheep\_reproduce\=0.04,
wolf\_reproduce\=0.05,
wolf\_gain\_from\_food\=20,
grass\=True,
grass\_regrowth\_time\=30,
sheep\_gain\_from\_food\=4,
seed\=None,
simulator: ABMSimulator \= None,
):
"""Create a new Wolf-Sheep model with the given parameters.
Args:
height: Height of the grid
width: Width of the grid
initial\_sheep: Number of sheep to start with
initial\_wolves: Number of wolves to start with
sheep\_reproduce: Probability of each sheep reproducing each step
wolf\_reproduce: Probability of each wolf reproducing each step
wolf\_gain\_from\_food: Energy a wolf gains from eating a sheep
grass: Whether to have the sheep eat grass for energy
grass\_regrowth\_time: How long it takes for a grass patch to regrow
once it is eaten
sheep\_gain\_from\_food: Energy sheep gain from grass, if enabled
seed: Random seed
simulator: ABMSimulator instance for event scheduling
"""
super().\_\_init\_\_(seed\=seed)
self.simulator \= simulator
self.simulator.setup(self)
\# Initialize model parameters
self.height \= height
self.width \= width
self.grass \= grass
\# Create grid using experimental cell space
self.grid \= OrthogonalVonNeumannGrid(
\[self.height, self.width\],
torus\=True,
capacity\=math.inf,
random\=self.random,
)
\# Set up data collection
model\_reporters \= {
"Wolves": lambda m: len(m.agents\_by\_type\[Wolf\]),
"Sheep": lambda m: len(m.agents\_by\_type\[Sheep\]),
}
if grass:
model\_reporters\["Grass"\] \= lambda m: len(
m.agents\_by\_type\[GrassPatch\].select(lambda a: a.fully\_grown)
)
self.datacollector \= DataCollector(model\_reporters)
\# Create sheep:
Sheep.create\_agents(
self,
initial\_sheep,
energy\=self.rng.random((initial\_sheep,)) \* 2 \* sheep\_gain\_from\_food,
p\_reproduce\=sheep\_reproduce,
energy\_from\_food\=sheep\_gain\_from\_food,
cell\=self.random.choices(self.grid.all\_cells.cells, k\=initial\_sheep),
)
\# Create Wolves:
Wolf.create\_agents(
self,
initial\_wolves,
energy\=self.rng.random((initial\_wolves,)) \* 2 \* wolf\_gain\_from\_food,
p\_reproduce\=wolf\_reproduce,
energy\_from\_food\=wolf\_gain\_from\_food,
cell\=self.random.choices(self.grid.all\_cells.cells, k\=initial\_wolves),
)
\# Create grass patches if enabled
if grass:
possibly\_fully\_grown \= \[True, False\]
for cell in self.grid:
fully\_grown \= self.random.choice(possibly\_fully\_grown)
countdown \= (
0 if fully\_grown else self.random.randrange(0, grass\_regrowth\_time)
)
GrassPatch(self, countdown, grass\_regrowth\_time, cell)
\# Collect initial data
self.running \= True
self.datacollector.collect(self)
def step(self):
"""Execute one step of the model."""
\# First activate all sheep, then all wolves, both in random order
self.agents\_by\_type\[Sheep\].shuffle\_do("step")
self.agents\_by\_type\[Wolf\].shuffle\_do("step")
\# Collect data
self.datacollector.collect(self)
App[#](#app "Link to this heading")
------------------------------------
from mesa.examples.advanced.wolf\_sheep.agents import GrassPatch, Sheep, Wolf
from mesa.examples.advanced.wolf\_sheep.model import WolfSheep
from mesa.experimental.devs import ABMSimulator
from mesa.visualization import (
CommandConsole,
Slider,
SolaraViz,
make\_plot\_component,
make\_space\_component,
)
def wolf\_sheep\_portrayal(agent):
if agent is None:
return
portrayal \= {
"size": 25,
}
if isinstance(agent, Wolf):
portrayal\["color"\] \= "tab:red"
portrayal\["marker"\] \= "o"
portrayal\["zorder"\] \= 2
elif isinstance(agent, Sheep):
portrayal\["color"\] \= "tab:cyan"
portrayal\["marker"\] \= "o"
portrayal\["zorder"\] \= 2
elif isinstance(agent, GrassPatch):
if agent.fully\_grown:
portrayal\["color"\] \= "tab:green"
else:
portrayal\["color"\] \= "tab:brown"
portrayal\["marker"\] \= "s"
portrayal\["size"\] \= 75
return portrayal
model\_params \= {
"seed": {
"type": "InputText",
"value": 42,
"label": "Random Seed",
},
"grass": {
"type": "Select",
"value": True,
"values": \[True, False\],
"label": "grass regrowth enabled?",
},
"grass\_regrowth\_time": Slider("Grass Regrowth Time", 20, 1, 50),
"initial\_sheep": Slider("Initial Sheep Population", 100, 10, 300),
"sheep\_reproduce": Slider("Sheep Reproduction Rate", 0.04, 0.01, 1.0, 0.01),
"initial\_wolves": Slider("Initial Wolf Population", 10, 5, 100),
"wolf\_reproduce": Slider(
"Wolf Reproduction Rate",
0.05,
0.01,
1.0,
0.01,
),
"wolf\_gain\_from\_food": Slider("Wolf Gain From Food Rate", 20, 1, 50),
"sheep\_gain\_from\_food": Slider("Sheep Gain From Food", 4, 1, 10),
}
def post\_process\_space(ax):
ax.set\_aspect("equal")
ax.set\_xticks(\[\])
ax.set\_yticks(\[\])
def post\_process\_lines(ax):
ax.legend(loc\="center left", bbox\_to\_anchor\=(1, 0.9))
space\_component \= make\_space\_component(
wolf\_sheep\_portrayal, draw\_grid\=False, post\_process\=post\_process\_space
)
lineplot\_component \= make\_plot\_component(
{"Wolves": "tab:orange", "Sheep": "tab:cyan", "Grass": "tab:green"},
post\_process\=post\_process\_lines,
)
simulator \= ABMSimulator()
model \= WolfSheep(simulator\=simulator, grass\=True)
page \= SolaraViz(
model,
components\=\[space\_component, lineplot\_component, CommandConsole\],
model\_params\=model\_params,
name\="Wolf Sheep",
simulator\=simulator,
)
page \# noqa
On this page
### This Page
* [Show Source](../../_sources/examples/advanced/wolf_sheep.md.txt)
---
# Unknown
\# APIs \`\`\`{toctree} :maxdepth: 3 model agent time space discrete\_space datacollection batchrunner visualization logging experimental \`\`\`
---
# Unknown
\## Overview of the MESA library Mesa is modular, meaning that its modeling, analysis and visualization components are kept separate but intended to work together. The modules are grouped into three categories: 1. \*\*Modeling:\*\* Classes used to build the models themselves: a model and agent classes, space for them to move around in, and built-in functionality for managing agents. 2. \*\*Analysis:\*\* Tools to collect data generated from your model, or to run it multiple times with different parameter values. 3. \*\*Visualization:\*\* Classes to create and launch an interactive model visualization, using a browser-based interface. ### Modeling modules Most models consist of one class to represent the model itself and one or more classes for agents. Mesa provides built-in functionality for managing agents and their interactions. These are implemented in Mesa's modeling modules: - \[mesa.model\](apis/model) - \[mesa.agent\](apis/agent) - \[mesa.space\](apis/space) The skeleton of a model might look like this: \`\`\`python import mesa class MyAgent(mesa.Agent): def \_\_init\_\_(self, model, age): super().\_\_init\_\_(model) self.age = age def step(self): self.age += 1 print(f"Agent {self.unique\_id} now is {self.age} years old") # Whatever else the agent does when activated class MyModel(mesa.Model): def \_\_init\_\_(self, n\_agents): super().\_\_init\_\_() self.grid = mesa.space.MultiGrid(10, 10, torus=True) for \_ in range(n\_agents): initial\_age = self.random.randint(0, 80) a = MyAgent(self, initial\_age) coords = (self.random.randrange(0, 10), self.random.randrange(0, 10)) self.grid.place\_agent(a, coords) def step(self): self.agents.shuffle\_do("step") \`\`\` ### Spaces in Mesa Mesa provides several types of spaces where agents can exist and interact: #### Discrete Spaces Mesa implements discrete spaces using a doubly-linked structure where each cell maintains connections to its neighbors. Available variants include: 1. \*\*Grid-based Spaces:\*\* \`\`\`python # Create a Von Neumann grid (4 neighbors per cell) grid = mesa.space.OrthogonalVonNeumannGrid((width, height), torus=False) # Create a Moore grid (8 neighbors per cell) grid = mesa.space.OrthogonalMooreGrid((width, height), torus=True) # Create a hexagonal grid grid = mesa.space.HexGrid((width, height), torus=False) \`\`\` 2. \*\*Network Space:\*\* \`\`\`python # Create a network-based space network = mesa.space.NetworkGrid(network) \`\`\` 3. \*\*Voronoi Space:\*\* \`\`\`python # Create an irregular tessellation mesh = mesa.space.VoronoiMesh(points) \`\`\` #### Property Layers Discrete spaces support PropertyLayers - efficient numpy-based arrays for storing cell-level properties: \`\`\`python # Create and use a property layer grid.create\_property\_layer("elevation", default\_value=10) high\_ground = grid.elevation.select\_cells(lambda x: x > 50) \`\`\` #### Continuous Space For models requiring continuous movement: \`\`\`python # Create a continuous space space = mesa.space.ContinuousSpace(x\_max, y\_max, torus=True) # Move an agent to specific coordinates space.move\_agent(agent, (new\_x, new\_y)) \`\`\` ### Time Advancement and Agent Activation Mesa supports multiple approaches to advancing time and activating agents: #### Basic Time Steps The simplest approach runs the model for a specified number of steps: \`\`\`python model = MyModel(seed=42) for \_ in range(100): model.step() \`\`\` #### Agent Activation Patterns Mesa 3.0 provides flexible agent activation through the AgentSet API: \`\`\`python # Sequential activation model.agents.do("step") # Random activation model.agents.shuffle\_do("step") # Multi-stage activation for stage in \["move", "eat", "reproduce"\]: model.agents.do(stage) # Activation by agent type for klass in model.agent\_types: model.agents\_by\_type\[klass\].do("step") \`\`\` #### Event-Based Scheduling Mesa also supports event-based time progression (experimental): \`\`\`python # Pure event-based simulator = mesa.experimental.DiscreteEventSimulator() model = MyModel(seed=42, simulator=simulator) simulator.schedule\_event\_relative(some\_function, 3.1415) # Hybrid time-step and event scheduling model = MyModel(seed=42, simulator=mesa.experimental.ABMSimulator()) model.simulator.schedule\_event\_next\_tick(some\_function) \`\`\` ### AgentSet and model.agents Mesa 3.0 makes \`model.agents\` and the AgentSet class central in managing and activating agents. #### model.agents \`model.agents\` is an AgentSet containing all agents in the model. It's automatically updated when agents are added or removed: \`\`\`python # Get total number of agents num\_agents = len(model.agents) # Iterate over all agents for agent in model.agents: print(agent.unique\_id) \`\`\` #### AgentSet Functionality AgentSet offers several methods for efficient agent management: 1. \*\*Selecting\*\*: Filter agents based on criteria. \`\`\`python high\_energy\_agents = model.agents.select(lambda a: a.energy > 50) \`\`\` 2. \*\*Shuffling and Sorting\*\*: Randomize or order agents. \`\`\`python shuffled\_agents = model.agents.shuffle() sorted\_agents = model.agents.sort(key="energy", ascending=False) \`\`\` 3. \*\*Applying methods\*\*: Execute methods on all agents. \`\`\`python model.agents.do("step") model.agents.shuffle\_do("move") # Shuffle then apply method \`\`\` 4. \*\*Aggregating\*\*: Compute aggregate values across agents. \`\`\`python avg\_energy = model.agents.agg("energy", func=np.mean) \`\`\` 5. \*\*Grouping\*\*: Group agents by attributes. \`\`\`python grouped\_agents = model.agents.groupby("species") for \_, agent\_group in grouped\_agents: agent\_group.shuffle\_do() species\_counts = grouped\_agents.count() mean\_age\_by\_group = grouped\_agents.agg("age", np.mean) \`\`\` \`model.agents\` can also be accessed within a model instance using \`self.agents\`. These are just some examples of using the AgentSet, there are many more possibilities, see the \[AgentSet API docs\](apis/agent). ### Analysis modules If you're using modeling for research, you'll want a way to collect the data each model run generates. You'll probably also want to run the model multiple times, to see how some output changes with different parameters. Data collection and batch running are implemented in the appropriately-named analysis modules: - \[mesa.datacollection\](apis/datacollection) - \[mesa.batchrunner\](apis/batchrunner) You'd add a data collector to the model like this: \`\`\`python import mesa import numpy as np # ... class MyModel(mesa.Model): def \_\_init\_\_(self, n\_agents): super().\_\_init\_\_() # ... (model initialization code) self.datacollector = mesa.DataCollector( model\_reporters={"mean\_age": lambda m: m.agents.agg("age", np.mean)}, agent\_reporters={"age": "age"} ) def step(self): self.agents.shuffle\_do("step") self.datacollector.collect(self) \`\`\` The data collector will collect the specified model- and agent-level data at each step of the model. After you're done running it, you can extract the data as a \[pandas\](http://pandas.pydata.org/) DataFrame: \`\`\`python model = MyModel(5) for t in range(10): model.step() model\_df = model.datacollector.get\_model\_vars\_dataframe() agent\_df = model.datacollector.get\_agent\_vars\_dataframe() \`\`\` To batch-run the model while varying, for example, the n\_agents parameter, you'd use the \[\`batch\_run\`\](apis/batchrunner) function: \`\`\`python import mesa parameters = {"n\_agents": range(1, 6)} results = mesa.batch\_run( MyModel, parameters, iterations=5, max\_steps=100, data\_collection\_period=1, number\_processes=1 # Change to use multiple CPU cores for parallel execution ) \`\`\` The results are returned as a list of dictionaries, which can be easily converted to a pandas DataFrame for further analysis. ### Visualization Mesa now uses a new browser-based visualization system called SolaraViz. This allows for interactive, customizable visualizations of your models. Note: SolaraViz is experimental and still in active development in Mesa 3.x. While we attempt to minimize them, there might be API breaking changes in minor releases. > \*\*Note:\*\* SolaraViz instantiates new models using \`\*\*model\_parameters.value\`, so all model inputs must be keyword arguments. Ensure your model's \`\_\_init\_\_\` method accepts keyword arguments matching the \`model\_params\` keys. \`\`\`python class MyModel(Model): def \_\_init\_\_(self, n\_agents=10, seed=None): super().\_\_init\_\_(seed=seed) # Initialize the model with N agents \`\`\` The core functionality for building your own visualizations resides in the \[\`mesa.visualization\`\](apis/visualization) namespace. Here's a basic example of how to set up a visualization: \`\`\`python from mesa.visualization import SolaraViz, make\_space\_component, make\_plot\_component def agent\_portrayal(agent): return {"color": "blue", "size": 50} model\_params = { "N": { "type": "SliderInt", "value": 50, "label": "Number of agents:", "min": 10, "max": 100, "step": 1, } } page = SolaraViz( MyModel, \[ make\_space\_component(agent\_portrayal), make\_plot\_component("mean\_age") \], model\_params=model\_params ) page \`\`\` This will create an interactive visualization of your model, including: - A grid visualization of agents - A plot of a model metric over time - A slider to adjust the number of agents \`\`\`{toctree} :hidden: true :maxdepth: 7 Overview Creating Your First Model Adding Space Collecting Data AgentSet Basic Visualization Dynamic Agent Visualization Custom Visualization Components Parameter Sweeps Comparing Scenarios Best Practices \`\`\`
---
# Documentation page not found
- Read the Docs
[mesa.readthedocs.io](/)
The documentation page you requested does not exist or may have been removed.
Hosted by [](//readthedocs.org/)
---
# Mesa Extensions Overview — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Mesa Extensions Overview[#](#mesa-extensions-overview "Link to this heading")
==============================================================================
This contains an overview of Mesa Extensions. Mesa’s extensibility is a key feature that allows users to enhance functionality, improve scalability, and foster innovation in agent-based modeling.
Mesa-Geo 🌍[#](#mesa-geo "Link to this heading")
-------------------------------------------------
**Field:** Geographic Information Systems (GIS)
* * *
**Description:** Mesa-Geo is an extension of the Mesa framework designed to facilitate working with geographic data in agent-based modeling. It introduces a **GeoSpace** to host **GeoAgents**, which are enhanced agents that include a `geometry` attribute ([a Shapely object](https://shapely.readthedocs.io/en/latest/manual.html)
) and a `crs` attribute (Coordinate Reference System). These attributes enable the integration of geographic and spatial data into simulations. Geometries can be defined manually using Shapely or imported from various sources, such as vector data files (e.g., shapefiles), GeoJSON objects, or GeoPandas GeoDataFrames.
* * *
**Key Features:**
* **Spatial Reference Systems Support:** Mesa-Geo handles coordinate reference systems (CRS), which is essential for working with geographic data in various projections.
* **Geometric Operations Support:** Mesa-Geo utilizes Shapely, which provides robust tools for creating and manipulating geometric shapes like points, polygons, and lines.
* **Topological Operations Support:** Functions for analyzing spatial relationships between geometries.
* * *
**Author(s):** Wang Boyu
* * *
**Additional Resources:** For more information, visit the official [Mesa-Geo repository](https://github.com/projectmesa/mesa-geo?tab=readme-ov-file)
.
* * *
Mesa Examples 📊[#](#mesa-examples "Link to this heading")
-----------------------------------------------------------
**Description:** Mesa Examples provide a collection of models and use cases demonstrating the features and capabilities of the Mesa framework for agent-based modeling. These examples include core and user-submitted models covering a variety of domains like grid spaces, networks, visualization, and GIS.
* * *
**Key Features:**
* **Core Examples:** Fully tested and updated models included directly with the Mesa framework.
* **User Examples:** Community-contributed models showcasing advanced and diverse use cases.
* **Extensive Coverage:** Examples for grid spaces, GIS integration, networks, visualization, and more.
* **Easy Access:** Available directly from the Mesa package or via installation from the repository.
* * *
**Author(s):** Contributions from the Mesa developer community.
* * *
**Examples Include:**
* **Grid Space:** Models like Bank Reserves, Conway’s Game of Life, and Forest Fire.
* **GIS:** GeoSchelling Models, Urban Growth, and Population Models.
* **Network:** Boltzmann Wealth Model and Ant System for the Traveling Salesman Problem.
* **Visualization:** Charting tools and grid displays.
* * *
**For More Information:** For more Detail, Visit the [Mesa Examples Repository](https://github.com/projectmesa/mesa/tree/main/mesa/examples)
.
* * *
**Mesa-Frames** 🚀[#](#mesa-frames "Link to this heading")
-----------------------------------------------------------
**Description:** Mesa-Frames is an extension of the Mesa framework designed to handle complex simulations with thousands of agents. By utilizing DataFrames (pandas or Polars), it enhances scalability and performance while maintaining a syntax similar to Mesa.
* * *
**Key Features:**
* **Enhanced Performance:** Uses DataFrames for SIMD processing and vectorized functions to speed up simulations.
* **Backend Support:** Supports `pandas` (ease of use) and `Polars` (performance innovations with Rust-based backend).
* **Seamless Integration:** Maintains a similar API and functionality as the base Mesa framework for easier adoption.
* **In-Place Operations:** Functional programming and fast memory-efficient copy methods.
* **Future Plans:** GPU functionality, automatic model vectorization, and backend-independent AgentSet class.
* * *
**Usage:**
* Define agents using `AgentSetPandas` or `AgentSetPolars`.
* Implement models by subclassing `ModelDF`.
* Perform vectorized operations to enhance simulation performance.
* * *
**Author(s):** Developed and maintained by the Mesa development community.
* * *
**License:** Distributed under the MIT License.
* * *
**More Information:** Visit the [GitHub Repository](https://github.com/projectmesa/mesa-frames)
.
* * *
On this page
### This Page
* [Show Source](_sources/mesa_extension.md.txt)
---
# Sugarscape Constant Growback Model with Traders — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Sugarscape Constant Growback Model with Traders[#](#sugarscape-constant-growback-model-with-traders "Link to this heading")
============================================================================================================================
Summary[#](#summary "Link to this heading")
--------------------------------------------
This is Epstein & Axtell’s Sugarscape model with Traders, a detailed description is in Chapter four of _Growing Artificial Societies: Social Science from the Bottom Up (1996)_. The model shows an emergent price equilibrium can happen via a decentralized dynamics.
This code generally matches the code in the Complexity Explorer Tutorial, but in `.py` instead of `.ipynb` format.
### Agents:[#](#agents "Link to this heading")
* **Resource**: Resource agents grow back at one unit of sugar and spice per time step up to a specified max amount and can be harvested and traded by the trader agents. (if you do the interactive run, the color will be green if the resource agent has a bigger amount of sugar, or yellow if it has a bigger amount of spice)
* **Traders**: Trader agents have the following attributes: (1) metabolism for sugar, (2) metabolism for spice, (3) vision, (4) initial sugar endowment and (5) initial spice endowment. The traverse the landscape harvesting sugar and spice and trading with other agents. If they run out of sugar or spice then they are removed from the model. (red circle if you do the interactive run)
The trader agents traverse the landscape according to rule **M**:
* Look out as far as vision permits in the four principal lattice directions and identify the unoccupied site(s).
* Considering only unoccupied sites find the nearest position that produces the most welfare using the Cobb-Douglas function.
* Move to the new position
* Collect all the resources (sugar and spice) at that location (Epstein and Axtell, 1996, p. 99)
The traders trade according to rule **T**:
* Agents and potential trade partner compute their marginal rates of substitution (MRS), if they are equal _end_.
* Exchange resources, with spice flowing from the agent with the higher MRS to the agent with the lower MRS and sugar flowing the opposite direction.
* The price (p) is calculated by taking the geometric mean of the agents’ MRS.
* If p > 1 then p units of spice are traded for 1 unit of sugar; if p < 1 then 1/p units of sugar for 1 unit of spice
* The trade occurs if it will (a) make both agent better off (increases MRS) and (b) does not cause the agents’ MRS to cross over one another otherwise _end_.
* This process then repeats until an _end_ condition is met. (Epstein and Axtell, 1996, p. 105)
The model demonstrates several Mesa concepts and features:
* OrthogonalMooreGrid
* Multiple agent types (traders, sugar, spice)
* Dynamically removing agents from the grid and schedule when they die
* Data Collection at the model and agent level
* custom solara matplotlib space visualization
How to Run[#](#how-to-run "Link to this heading")
--------------------------------------------------
To run the model interactively:
$ solara run app.py
Then open your browser to [http://127.0.0.1:8521/](http://127.0.0.1:8521/)
and press Reset, then Run.
Files[#](#files "Link to this heading")
----------------------------------------
* `model.py`: The Sugarscape Constant Growback with Traders model.
* `agents.py`: Defines the Trader agent class and the Resource agent class which contains an amount of sugar and spice.
* `app.py`: Runs a visualization server via Solara (`solara run app.py`).
* `sugar_map.txt`: Provides sugar and spice landscape in raster type format.
* `tests.py`: Has tests to ensure that the model reproduces the results in shown in Growing Artificial Societies.
Additional Resources[#](#additional-resources "Link to this heading")
----------------------------------------------------------------------
* [Growing Artificial Societies](https://mitpress.mit.edu/9780262550253/growing-artificial-societies/)
* [Complexity Explorer Sugarscape with Traders Tutorial](https://www.complexityexplorer.org/courses/172-agent-based-models-with-python-an-introduction-to-mesa)
Agents[#](#id1 "Link to this heading")
---------------------------------------
import math
from mesa.discrete\_space import CellAgent
\# Helper function
def get\_distance(cell\_1, cell\_2):
"""
Calculate the Euclidean distance between two positions
used in trade.move()
"""
x1, y1 \= cell\_1.coordinate
x2, y2 \= cell\_2.coordinate
dx \= x1 \- x2
dy \= y1 \- y2
return math.sqrt(dx\*\*2 + dy\*\*2)
class Trader(CellAgent):
"""
Trader:
- has a metabolism of sugar and spice
- harvest and trade sugar and spice to survive
"""
def \_\_init\_\_(
self,
model,
cell,
sugar\=0,
spice\=0,
metabolism\_sugar\=0,
metabolism\_spice\=0,
vision\=0,
):
super().\_\_init\_\_(model)
self.cell \= cell
self.sugar \= sugar
self.spice \= spice
self.metabolism\_sugar \= metabolism\_sugar
self.metabolism\_spice \= metabolism\_spice
self.vision \= vision
self.prices \= \[\]
self.trade\_partners \= \[\]
def get\_trader(self, cell):
"""
helper function used in self.trade\_with\_neighbors()
"""
for agent in cell.agents:
if isinstance(agent, Trader):
return agent
def calculate\_welfare(self, sugar, spice):
"""
helper function
part 2 self.move()
self.trade()
"""
\# calculate total resources
m\_total \= self.metabolism\_sugar + self.metabolism\_spice
\# Cobb-Douglas functional form; starting on p. 97
\# on Growing Artificial Societies
return sugar \*\* (self.metabolism\_sugar / m\_total) \* spice \*\* (
self.metabolism\_spice / m\_total
)
def is\_starved(self):
"""
Helper function for self.maybe\_die()
"""
return (self.sugar <= 0) or (self.spice <= 0)
def calculate\_MRS(self, sugar, spice):
"""
Helper function for
- self.trade()
- self.maybe\_self\_spice()
Determines what trader agent needs and can give up
"""
return (spice / self.metabolism\_spice) / (sugar / self.metabolism\_sugar)
def calculate\_sell\_spice\_amount(self, price):
"""
helper function for self.maybe\_sell\_spice() which is called from
self.trade()
"""
if price \>= 1:
sugar \= 1
spice \= int(price)
else:
sugar \= int(1 / price)
spice \= 1
return sugar, spice
def sell\_spice(self, other, sugar, spice):
"""
used in self.maybe\_sell\_spice()
exchanges sugar and spice between traders
"""
self.sugar += sugar
other.sugar \-= sugar
self.spice \-= spice
other.spice += spice
def maybe\_sell\_spice(self, other, price, welfare\_self, welfare\_other):
"""
helper function for self.trade()
"""
sugar\_exchanged, spice\_exchanged \= self.calculate\_sell\_spice\_amount(price)
\# Assess new sugar and spice amount - what if change did occur
self\_sugar \= self.sugar + sugar\_exchanged
other\_sugar \= other.sugar \- sugar\_exchanged
self\_spice \= self.spice \- spice\_exchanged
other\_spice \= other.spice + spice\_exchanged
\# double check to ensure agents have resources
if (
(self\_sugar <= 0)
or (other\_sugar <= 0)
or (self\_spice <= 0)
or (other\_spice <= 0)
):
return False
\# trade criteria #1 - are both agents better off?
both\_agents\_better\_off \= (
welfare\_self < self.calculate\_welfare(self\_sugar, self\_spice)
) and (welfare\_other < other.calculate\_welfare(other\_sugar, other\_spice))
\# trade criteria #2 is their mrs crossing with potential trade
mrs\_not\_crossing \= self.calculate\_MRS(
self\_sugar, self\_spice
) \> other.calculate\_MRS(other\_sugar, other\_spice)
if not (both\_agents\_better\_off and mrs\_not\_crossing):
return False
\# criteria met, execute trade
self.sell\_spice(other, sugar\_exchanged, spice\_exchanged)
return True
def trade(self, other):
"""
helper function used in trade\_with\_neighbors()
other is a trader agent object
"""
\# sanity check to verify code is working as expected
assert self.sugar \> 0
assert self.spice \> 0
assert other.sugar \> 0
assert other.spice \> 0
\# calculate marginal rate of substitution in Growing Artificial Societies p. 101
mrs\_self \= self.calculate\_MRS(self.sugar, self.spice)
mrs\_other \= other.calculate\_MRS(other.sugar, other.spice)
\# calculate each agents welfare
welfare\_self \= self.calculate\_welfare(self.sugar, self.spice)
welfare\_other \= other.calculate\_welfare(other.sugar, other.spice)
if math.isclose(mrs\_self, mrs\_other):
return
\# calculate price
price \= math.sqrt(mrs\_self \* mrs\_other)
if mrs\_self \> mrs\_other:
\# self is a sugar buyer, spice seller
sold \= self.maybe\_sell\_spice(other, price, welfare\_self, welfare\_other)
\# no trade - criteria not met
if not sold:
return
else:
\# self is a spice buyer, sugar seller
sold \= other.maybe\_sell\_spice(self, price, welfare\_other, welfare\_self)
\# no trade - criteria not met
if not sold:
return
\# Capture data
self.prices.append(price)
self.trade\_partners.append(other.unique\_id)
\# continue trading
self.trade(other)
######################################################################
\# #
\# MAIN TRADE FUNCTIONS #
\# #
######################################################################
def move(self):
"""
Function for trader agent to identify optimal move for each step in 4 parts
1 - identify all possible moves
2 - determine which move maximizes welfare
3 - find closest best option
4 - move
"""
\# 1. identify all possible moves
neighboring\_cells \= \[\
cell\
for cell in self.cell.get\_neighborhood(self.vision, include\_center\=True)\
if cell.is\_empty\
\]
\# 2. determine which move maximizes welfare
welfares \= \[\
self.calculate\_welfare(\
self.sugar + cell.sugar,\
self.spice + cell.spice,\
)\
for cell in neighboring\_cells\
\]
\# 3. Find closest best option
\# find the highest welfare in welfares
max\_welfare \= max(welfares)
\# get the index of max welfare cells
\# fixme: rewrite using enumerate and single loop
candidate\_indices \= \[\
i for i in range(len(welfares)) if math.isclose(welfares\[i\], max\_welfare)\
\]
\# convert index to positions of those cells
candidates \= \[neighboring\_cells\[i\] for i in candidate\_indices\]
min\_dist \= min(get\_distance(self.cell, cell) for cell in candidates)
final\_candidates \= \[\
cell\
for cell in candidates\
if math.isclose(get\_distance(self.cell, cell), min\_dist, rel\_tol\=1e-02)\
\]
\# 4. Move Agent
self.cell \= self.random.choice(final\_candidates)
def eat(self):
self.sugar += self.cell.sugar
self.cell.sugar \= 0
self.sugar \-= self.metabolism\_sugar
self.spice += self.cell.spice
self.cell.spice \= 0
self.spice \-= self.metabolism\_spice
def maybe\_die(self):
"""
Function to remove Traders who have consumed all their sugar or spice
"""
if self.is\_starved():
self.remove()
def trade\_with\_neighbors(self):
"""
Function for trader agents to decide who to trade with in three parts
1- identify neighbors who can trade
2- trade (2 sessions)
3- collect data
"""
\# iterate through traders in neighboring cells and trade
for a in self.cell.get\_neighborhood(radius\=self.vision).agents:
self.trade(a)
return
Model[#](#model "Link to this heading")
----------------------------------------
from pathlib import Path
import numpy as np
import mesa
from mesa.discrete\_space import OrthogonalVonNeumannGrid
from mesa.discrete\_space.property\_layer import PropertyLayer
from mesa.examples.advanced.sugarscape\_g1mt.agents import Trader
\# Helper Functions
def flatten(list\_of\_lists):
"""
helper function for model datacollector for trade price
collapses agent price list into one list
"""
return \[item for sublist in list\_of\_lists for item in sublist\]
def geometric\_mean(list\_of\_prices):
"""
find the geometric mean of a list of prices
"""
return np.exp(np.log(list\_of\_prices).mean())
def get\_trade(agent):
"""
For agent reporters in data collector
return list of trade partners and None for other agents
"""
if isinstance(agent, Trader):
return agent.trade\_partners
else:
return None
class SugarscapeG1mt(mesa.Model):
"""
Manager class to run Sugarscape with Traders
"""
def \_\_init\_\_(
self,
width\=50,
height\=50,
initial\_population\=200,
endowment\_min\=25,
endowment\_max\=50,
metabolism\_min\=1,
metabolism\_max\=5,
vision\_min\=1,
vision\_max\=5,
enable\_trade\=True,
seed\=None,
):
super().\_\_init\_\_(seed\=seed)
\# Initiate width and height of sugarscape
self.width \= width
self.height \= height
\# Initiate population attributes
self.enable\_trade \= enable\_trade
self.running \= True
\# initiate mesa grid class
self.grid \= OrthogonalVonNeumannGrid(
(self.width, self.height), torus\=False, random\=self.random
)
\# initiate datacollector
self.datacollector \= mesa.DataCollector(
model\_reporters\={
"#Traders": lambda m: len(m.agents),
"Trade Volume": lambda m: sum(len(a.trade\_partners) for a in m.agents),
"Price": lambda m: geometric\_mean(
flatten(\[a.prices for a in m.agents\])
),
},
agent\_reporters\={"Trade Network": lambda a: get\_trade(a)},
)
\# read in landscape file from supplementary material
self.sugar\_distribution \= np.genfromtxt(Path(\_\_file\_\_).parent / "sugar-map.txt")
self.spice\_distribution \= np.flip(self.sugar\_distribution, 1)
self.grid.add\_property\_layer(
PropertyLayer.from\_data("sugar", self.sugar\_distribution)
)
self.grid.add\_property\_layer(
PropertyLayer.from\_data("spice", self.spice\_distribution)
)
Trader.create\_agents(
self,
initial\_population,
self.random.choices(self.grid.all\_cells.cells, k\=initial\_population),
sugar\=self.rng.integers(
endowment\_min, endowment\_max, (initial\_population,), endpoint\=True
),
spice\=self.rng.integers(
endowment\_min, endowment\_max, (initial\_population,), endpoint\=True
),
metabolism\_sugar\=self.rng.integers(
metabolism\_min, metabolism\_max, (initial\_population,), endpoint\=True
),
metabolism\_spice\=self.rng.integers(
metabolism\_min, metabolism\_max, (initial\_population,), endpoint\=True
),
vision\=self.rng.integers(
vision\_min, vision\_max, (initial\_population,), endpoint\=True
),
)
def step(self):
"""
Unique step function that does staged activation of sugar and spice
and then randomly activates traders
"""
\# step Resource agents
self.grid.sugar.data \= np.minimum(
self.grid.sugar.data + 1, self.sugar\_distribution
)
self.grid.spice.data \= np.minimum(
self.grid.spice.data + 1, self.spice\_distribution
)
\# step trader agents
\# to account for agent death and removal we need a separate data structure to
\# iterate
trader\_shuffle \= self.agents\_by\_type\[Trader\].shuffle()
for agent in trader\_shuffle:
agent.prices \= \[\]
agent.trade\_partners \= \[\]
agent.move()
agent.eat()
agent.maybe\_die()
if not self.enable\_trade:
\# If trade is not enabled, return early
self.datacollector.collect(self)
return
trader\_shuffle \= self.agents\_by\_type\[Trader\].shuffle()
for agent in trader\_shuffle:
agent.trade\_with\_neighbors()
\# collect model level data
\# fixme we can already collect agent class data
\# fixme, we don't have resource agents anymore so this can be done simpler
self.datacollector.collect(self)
"""
Mesa is working on updating datacollector agent reporter
so it can collect information on specific agents from
mesa.time.RandomActivationByType.
Please see issue #1419 at
https://github.com/projectmesa/mesa/issues/1419
(contributions welcome)
Below is one way to update agent\_records to get specific Trader agent data
"""
\# Need to remove excess data
\# Create local variable to store trade data
agent\_trades \= self.datacollector.\_agent\_records\[self.steps\]
\# Get rid of all None to reduce data storage needs
agent\_trades \= \[agent for agent in agent\_trades if agent\[2\] is not None\]
\# Reassign the dictionary value with lean trade data
self.datacollector.\_agent\_records\[self.steps\] \= agent\_trades
def run\_model(self, step\_count\=1000):
for \_ in range(step\_count):
self.step()
App[#](#app "Link to this heading")
------------------------------------
from mesa.examples.advanced.sugarscape\_g1mt.model import SugarscapeG1mt
from mesa.visualization import Slider, SolaraViz, make\_plot\_component
from mesa.visualization.components.matplotlib\_components import make\_mpl\_space\_component
def agent\_portrayal(agent):
return {"marker": "o", "color": "red", "size": 10}
propertylayer\_portrayal \= {
"sugar": {"color": "blue", "alpha": 0.8, "colorbar": True, "vmin": 0, "vmax": 10},
"spice": {"color": "red", "alpha": 0.8, "colorbar": True, "vmin": 0, "vmax": 10},
}
sugarscape\_space \= make\_mpl\_space\_component(
agent\_portrayal\=agent\_portrayal,
propertylayer\_portrayal\=propertylayer\_portrayal,
post\_process\=None,
draw\_grid\=False,
)
model\_params \= {
"seed": {
"type": "InputText",
"value": 42,
"label": "Random Seed",
},
"width": 50,
"height": 50,
\# Population parameters
"initial\_population": Slider(
"Initial Population", value\=200, min\=50, max\=500, step\=10
),
\# Agent endowment parameters
"endowment\_min": Slider("Min Initial Endowment", value\=25, min\=5, max\=30, step\=1),
"endowment\_max": Slider("Max Initial Endowment", value\=50, min\=30, max\=100, step\=1),
\# Metabolism parameters
"metabolism\_min": Slider("Min Metabolism", value\=1, min\=1, max\=3, step\=1),
"metabolism\_max": Slider("Max Metabolism", value\=5, min\=3, max\=8, step\=1),
\# Vision parameters
"vision\_min": Slider("Min Vision", value\=1, min\=1, max\=3, step\=1),
"vision\_max": Slider("Max Vision", value\=5, min\=3, max\=8, step\=1),
\# Trade parameter
"enable\_trade": {"type": "Checkbox", "value": True, "label": "Enable Trading"},
}
model \= SugarscapeG1mt()
page \= SolaraViz(
model,
components\=\[\
sugarscape\_space,\
make\_plot\_component("#Traders"),\
make\_plot\_component("Price"),\
\],
model\_params\=model\_params,
name\="Sugarscape {G1, M, T}",
play\_interval\=150,
)
page \# noqa
On this page
### This Page
* [Show Source](../../_sources/examples/advanced/sugarscape_g1mt.md.txt)
---
# Unknown
\# Mesa Core Examples This repository contains a curated set of classic agent-based models implemented using Mesa. These core examples are maintained by the Mesa development team and serve as both demonstrations of Mesa's capabilities and starting points for your own models. ## Overview The examples are categorized into two groups: 1. \*\*Basic Examples\*\* - Simpler models that use only stable Mesa features; ideal for beginners 2. \*\*Advanced Examples\*\* - More complex models that demonstrate additional concepts and may use some experimental features > \*\*Note:\*\* Looking for more examples? Visit the \[mesa-examples\](https://github.com/projectmesa/mesa-examples) repository for user-contributed models and showcases. ## Basic Examples The basic examples are relatively simple and only use stable Mesa features. They are good starting points for learning how to use Mesa. ### \[Boltzmann Wealth Model\](examples/basic/boltzmann\_wealth\_model) Completed code to go along with the \[tutorial\](https://mesa.readthedocs.io/latest/tutorials/intro\_tutorial.html) on making a simple model of how a highly-skewed wealth distribution can emerge from simple rules. ### \[Boids Flockers Model\](examples/basic/boid\_flockers) \[Boids\](https://en.wikipedia.org/wiki/Boids)-style flocking model, demonstrating the use of agents moving through a continuous space following direction vectors. ### \[Conway's Game of Life\](examples/basic/conways\_game\_of\_life) Implementation of \[Conway's Game of Life\](https://en.wikipedia.org/wiki/Conway%27s\_Game\_of\_Life), a cellular automata where simple rules can give rise to complex patterns. ### \[Schelling Segregation Model\](examples/basic/schelling) Mesa implementation of the classic \[Schelling segregation\](http://nifty.stanford.edu/2014/mccown-schelling-model-segregation/) model. ### \[Virus on a Network Model\](examples/basic/virus\_on\_network) This model is based on the NetLogo \[Virus on a Network\](https://ccl.northwestern.edu/netlogo/models/VirusonaNetwork) model. ## Advanced Examples The advanced examples are more complex and may use experimental Mesa features. They are good starting points for learning how to build more complex models. ### \[Epstein Civil Violence Model\](examples/advanced/epstein\_civil\_violence) Joshua Epstein's \[model\](https://www.pnas.org/doi/10.1073/pnas.092080199) of how a decentralized uprising can be suppressed or reach a critical mass of support. ### \[Demographic Prisoner's Dilemma on a Grid\](examples/advanced/pd\_grid) Grid-based demographic prisoner's dilemma model, demonstrating how simple rules can lead to the emergence of widespread cooperation -- and how a model activation regime can change its outcome. ### \[Sugarscape Model with Traders\](examples/advanced/sugarscape\_g1mt) This is Epstein & Axtell's Sugarscape model with Traders, a detailed description is in Chapter four of \*Growing Artificial Societies: Social Science from the Bottom Up (1996)\*. The model shows how emergent price equilibrium can happen via decentralized dynamics. ### \[Wolf-Sheep Predation Model\](examples/advanced/wolf\_sheep) Implementation of an ecological model of predation and reproduction, based on the NetLogo \[Wolf Sheep Predation\](http://ccl.northwestern.edu/netlogo/models/WolfSheepPredation) model. \`\`\`{toctree} :hidden: true :maxdepth: 2 schelling boid flockers virus on network boltzmann wealth model conways game of life epstein civil violence pd grid wolf sheep sugarscape g1mt \`\`\`
---
# Unknown
{ "cells": \[ { "cell\_type": "markdown", "metadata": {}, "source": \[ "# Visualization - Dynamic Agents\\n", "\\n", "### The Boltzmann Wealth Model " \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "If you want to get straight to the tutorial checkout these environment providers: \
\\n", "\[!\[Binder\](https://mybinder.org/badge\_logo.svg)\](https://mybinder.org/v2/gh/projectmesa/mesa/main?labpath=docs%2Ftutorials%2F4\_visualization\_basic.ipynb) (This can take 30 seconds to 5 minutes to load)\\n", "\\n", "Due to conflict with Colab and Solara there are no colab links for this tutorial\\n", "\\n", "\*If you are running locally, please ensure you have the latest Mesa version installed.\*\\n", "\\n", "## Tutorial Description\\n", "\\n", "This tutorial extends the Boltzmann wealth model from the \[Visualization Basic Dashboard tutorial\](https://mesa.readthedocs.io/latest/tutorials/4\_visualization\_basic.html), by adding an interactive dashboard. \\n", "\\n", "In this portion, we will demonstrate how users can employ create dynamic agent representation with their Mesa dashboards. This is part two of three visualization tutorials. \\n", "\\n", "\*If you are starting here please see the \[Running Your First Model tutorial\](https://mesa.readthedocs.io/latest/tutorials/0\_first\_model.html) for dependency and start-up instructions\*" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Import Dependencies\\n", "This includes importing of dependencies needed for the tutorial." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "outputs": \[\], "source": \[ "# Has multi-dimensional arrays and matrices.\\n", "# Has a large collection of mathematical functions to operate on these arrays.\\n", "import numpy as np\\n", "\\n", "# Data manipulation and analysis.\\n", "import pandas as pd\\n", "\\n", "# Data visualization tools.\\n", "import seaborn as sns\\n", "\\n", "import mesa\\n", "from mesa.discrete\_space import CellAgent, OrthogonalMooreGrid\\n", "from mesa.visualization import SolaraViz, make\_plot\_component, make\_space\_component" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Basic Model\\n", "\\n", "The following is the basic model we will be using to build the dashboard. This is the same model seen in tutorials 0-3. " \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "def compute\_gini(model):\\n", " agent\_wealths = \[agent.wealth for agent in model.agents\]\\n", " x = sorted(agent\_wealths)\\n", " N = model.num\_agents\\n", " B = sum(xi \* (N - i) for i, xi in enumerate(x)) / (N \* sum(x))\\n", " return 1 + (1 / N) - 2 \* B\\n", "\\n", "\\n", "class MoneyAgent(CellAgent):\\n", " \\"\\"\\"An agent with fixed initial wealth.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, model, cell):\\n", " \\"\\"\\"initialize a MoneyAgent instance.\\n", "\\n", " Args:\\n", " model: A model instance\\n", " \\"\\"\\"\\n", " super().\_\_init\_\_(model)\\n", " self.cell = cell\\n", " self.wealth = 1\\n", "\\n", " def move(self):\\n", " \\"\\"\\"Move the agent to a random neighboring cell.\\"\\"\\"\\n", " self.cell = self.cell.neighborhood.select\_random\_cell()\\n", "\\n", " def give\_money(self):\\n", " \\"\\"\\"Give 1 unit of wealth to a random agent in the same cell.\\"\\"\\"\\n", " cellmates = \[a for a in self.cell.agents if a is not self\]\\n", "\\n", " if cellmates: # Only give money if there are other agents present\\n", " other = self.random.choice(cellmates)\\n", " other.wealth += 1\\n", " self.wealth -= 1\\n", "\\n", " def step(self):\\n", " \\"\\"\\"do one step of the agent.\\"\\"\\"\\n", " self.move()\\n", " if self.wealth > 0:\\n", " self.give\_money()\\n", "\\n", "\\n", "class MoneyModel(mesa.Model):\\n", " \\"\\"\\"A model with some number of agents.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, n=10, width=10, height=10, seed=None):\\n", " \\"\\"\\"Initialize a MoneyModel instance.\\n", "\\n", " Args:\\n", " N: The number of agents.\\n", " width: width of the grid.\\n", " height: Height of the grid.\\n", " \\"\\"\\"\\n", " super().\_\_init\_\_(seed=seed)\\n", " self.num\_agents = n\\n", " self.grid = OrthogonalMooreGrid((width, height), random=self.random)\\n", "\\n", " # Create agents\\n", " MoneyAgent.create\_agents(\\n", " self,\\n", " self.num\_agents,\\n", " self.random.choices(self.grid.all\_cells.cells, k=self.num\_agents),\\n", " )\\n", "\\n", " self.datacollector = mesa.DataCollector(\\n", " model\_reporters={\\"Gini\\": compute\_gini}, agent\_reporters={\\"Wealth\\": \\"wealth\\"}\\n", " )\\n", " self.datacollector.collect(self)\\n", "\\n", " def step(self):\\n", " \\"\\"\\"do one step of the model\\"\\"\\"\\n", " self.agents.shuffle\_do(\\"step\\")\\n", " self.datacollector.collect(self)" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "# Lets make sure the model works\\n", "model = MoneyModel(100, 10, 10)\\n", "for \_ in range(20):\\n", " model.step()\\n", "\\n", "\\n", "data = model.datacollector.get\_agent\_vars\_dataframe()\\n", "# Use seaborn\\n", "g = sns.histplot(data\[\\"Wealth\\"\], discrete=True)\\n", "g.set(title=\\"Wealth distribution\\", xlabel=\\"Wealth\\", ylabel=\\"number of agents\\");" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Adding visualization\\n", "\\n", "So far, we've built a model, run it, and analyzed some output afterwards. However, one of the advantages of agent-based models is that we can often watch them run step by step, potentially spotting unexpected patterns, behaviors or bugs, or developing new intuitions, hypotheses, or insights. Other times, watching a model run can explain it to an unfamiliar audience better than static explanations. Like many ABM frameworks, Mesa allows you to create an interactive visualization of the model. In this section we'll walk through creating a visualization using built-in components, and (for advanced users) how to create a new visualization element.\\n", "\\n", "First, a quick explanation of how Mesa's interactive visualization works. The visualization is done in a browser window or Jupyter instance, using the \[Solara\](https://solara.dev/) framework, a pure Python, React-style web framework. Running \`solara run app.py\` will launch a web server, which runs the model, and displays model detail at each step via a plotting library. Alternatively, you can execute everything inside a Jupyter instance and display it inline." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Dynamic Agent Representation\\n", "\\n", "In the first visualization, all we could see is the agents moving around -- but not how much money they had, or anything else of interest. In this tutorial let's change it so that agents are represented by the units of wealth they have. So those who are broke (wealth 0) are drawn in red, smaller. \\n", "\\n", "As Mesa is open source, it is important to point out that currently, we can't direct the drawing order of the circles, so a broke agent may be overshadowed by a wealthy agent. If you have some ideas, please feel free to \[contribute\](https://github.com/projectmesa/mesa/blob/main/CONTRIBUTING.md). \\n", "\\n", "In addition to size and color, an agent's shape can also be customized when using the default drawer. The allowed values for shapes can be found \[here\](https://matplotlib.org/stable/api/markers\_api.html).\\n", "\\n", "To do this, we go back to our \`agent\_portrayal\` code and add some code to change the portrayal based on the agent properties and launch the server again." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "def agent\_portrayal(agent):\\n", " size = 10\\n", " color = \\"tab:red\\"\\n", " if agent.wealth > 0:\\n", " size = 50\\n", " color = \\"tab:blue\\"\\n", " return {\\"size\\": size, \\"color\\": color}" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "As like last time we then instantiate the model parameters, some of which are modifiable by user inputs. In this case, the number of agents, N, is specified as a slider of integers." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "model\_params = {\\n", " \\"n\\": {\\n", " \\"type\\": \\"SliderInt\\",\\n", " \\"value\\": 50,\\n", " \\"label\\": \\"Number of agents:\\",\\n", " \\"min\\": 10,\\n", " \\"max\\": 100,\\n", " \\"step\\": 1,\\n", " },\\n", " \\"width\\": 10,\\n", " \\"height\\": 10,\\n", "}" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "Then just like last time we instantiate the visualization object which (by default) displays the grid containing the agents, and timeseries of values computed by the model's data collector. In this example, we specify the Gini coefficient.\\n", "\\n", "There are 3 buttons:\\n", "- the step button, which advances the model by 1 step\\n", "- the play button, which advances the model indefinitely until it is paused\\n", "- the pause button, which pauses the model\\n", "\\n", "To reset the model, the order of operations are important\\n", "1. Stop the model\\n", "2. Update the parameters (e.g. move the sliders)\\n", "3. Press reset " \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "# Create initial model instance\\n", "money\_model = MoneyModel(n=50, width=10, height=10)\\n", "\\n", "SpaceGraph = make\_space\_component(agent\_portrayal)\\n", "GiniPlot = make\_plot\_component(\\"Gini\\")\\n", "\\n", "page = SolaraViz(\\n", " money\_model,\\n", " components=\[SpaceGraph, GiniPlot\],\\n", " model\_params=model\_params,\\n", " name=\\"Boltzmann Wealth Model\\",\\n", ")\\n", "# This is required to render the visualization in the Jupyter notebook\\n", "page" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Exercise\\n", "\\n", "- Change the agent representations, such as squares, triangles or even .pngs" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Next Steps\\n", "\\n", "Check out the next \[visualization tutorial custom components\](https://mesa.readthedocs.io/latest/tutorials/6\_visualization\_custom.html) on how to further enahnce your interactive dashboard." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "\[Comer2014\] Comer, Kenneth W. “Who Goes First? An Examination of the Impact of Activation on Outcome Behavior in AgentBased Models.” George Mason University, 2014. http://mars.gmu.edu/bitstream/handle/1920/9070/Comer\_gmu\_0883E\_10539.pdf\\n", "\\n", "\[Dragulescu2002\] Drăgulescu, Adrian A., and Victor M. Yakovenko. “Statistical Mechanics of Money, Income, and Wealth: A Short Survey.” arXiv Preprint Cond-mat/0211175, 2002. http://arxiv.org/abs/cond-mat/0211175." \] } \], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display\_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language\_info": { "codemirror\_mode": { "name": "ipython", "version": 3 }, "file\_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert\_exporter": "python", "pygments\_lexer": "ipython3", "version": "3.12.5" }, "widgets": { "state": {}, "version": "1.1.2" } }, "nbformat": 4, "nbformat\_minor": 4 }
---
# Mesa Core Examples — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Mesa Core Examples[#](#mesa-core-examples "Link to this heading")
==================================================================
This repository contains a curated set of classic agent-based models implemented using Mesa. These core examples are maintained by the Mesa development team and serve as both demonstrations of Mesa’s capabilities and starting points for your own models.
Overview[#](#overview "Link to this heading")
----------------------------------------------
The examples are categorized into two groups:
1. **Basic Examples** - Simpler models that use only stable Mesa features; ideal for beginners
2. **Advanced Examples** - More complex models that demonstrate additional concepts and may use some experimental features
> **Note:** Looking for more examples? Visit the [mesa-examples](https://github.com/projectmesa/mesa-examples)
> repository for user-contributed models and showcases.
Basic Examples[#](#basic-examples "Link to this heading")
----------------------------------------------------------
The basic examples are relatively simple and only use stable Mesa features. They are good starting points for learning how to use Mesa.
### [Boltzmann Wealth Model](examples/basic/boltzmann_wealth_model.html)
[#](#boltzmann-wealth-model "Link to this heading")
Completed code to go along with the [tutorial](https://mesa.readthedocs.io/latest/tutorials/intro_tutorial.html)
on making a simple model of how a highly-skewed wealth distribution can emerge from simple rules.
### [Boids Flockers Model](examples/basic/boid_flockers.html)
[#](#boids-flockers-model "Link to this heading")
[Boids](https://en.wikipedia.org/wiki/Boids)
\-style flocking model, demonstrating the use of agents moving through a continuous space following direction vectors.
### [Conway’s Game of Life](examples/basic/conways_game_of_life.html)
[#](#conway-s-game-of-life "Link to this heading")
Implementation of [Conway’s Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life)
, a cellular automata where simple rules can give rise to complex patterns.
### [Schelling Segregation Model](examples/basic/schelling.html)
[#](#schelling-segregation-model "Link to this heading")
Mesa implementation of the classic [Schelling segregation](http://nifty.stanford.edu/2014/mccown-schelling-model-segregation/)
model.
### [Virus on a Network Model](examples/basic/virus_on_network.html)
[#](#virus-on-a-network-model "Link to this heading")
This model is based on the NetLogo [Virus on a Network](https://ccl.northwestern.edu/netlogo/models/VirusonaNetwork)
model.
Advanced Examples[#](#advanced-examples "Link to this heading")
----------------------------------------------------------------
The advanced examples are more complex and may use experimental Mesa features. They are good starting points for learning how to build more complex models.
### [Epstein Civil Violence Model](examples/advanced/epstein_civil_violence.html)
[#](#epstein-civil-violence-model "Link to this heading")
Joshua Epstein’s [model](https://www.pnas.org/doi/10.1073/pnas.092080199)
of how a decentralized uprising can be suppressed or reach a critical mass of support.
### [Demographic Prisoner’s Dilemma on a Grid](examples/advanced/pd_grid.html)
[#](#demographic-prisoner-s-dilemma-on-a-grid "Link to this heading")
Grid-based demographic prisoner’s dilemma model, demonstrating how simple rules can lead to the emergence of widespread cooperation – and how a model activation regime can change its outcome.
### [Sugarscape Model with Traders](examples/advanced/sugarscape_g1mt.html)
[#](#sugarscape-model-with-traders "Link to this heading")
This is Epstein & Axtell’s Sugarscape model with Traders, a detailed description is in Chapter four of _Growing Artificial Societies: Social Science from the Bottom Up (1996)_. The model shows how emergent price equilibrium can happen via decentralized dynamics.
### [Wolf-Sheep Predation Model](examples/advanced/wolf_sheep.html)
[#](#wolf-sheep-predation-model "Link to this heading")
Implementation of an ecological model of predation and reproduction, based on the NetLogo [Wolf Sheep Predation](http://ccl.northwestern.edu/netlogo/models/WolfSheepPredation)
model.
On this page
### This Page
* [Show Source](_sources/examples.md.txt)
---
# Unknown
\# Mesa Migration guide This guide contains breaking changes between major Mesa versions and how to resolve them. Non-breaking changes aren't included, for those see our \[Release history\](https://github.com/projectmesa/mesa/releases). ## Mesa 3.0 Mesa 3.0 introduces significant changes to core functionalities, including agent and model initialization, scheduling, and visualization. The guide below outlines these changes and provides instructions for migrating your existing Mesa projects to version 3.0. \_This guide is a work in progress. The development of it is tracked in \[Issue #2233\](https://github.com/projectmesa/mesa/issues/2233).\_ ### Upgrade strategy We recommend the following upgrade strategy: - Update to the latest Mesa 2.x release (\`mesa<3\`). - Update to the latest Mesa 3.0.x release (\`mesa<3.1\`). - Update to the latest Mesa 3.x release (\`mesa<4\`). With each update, resolve all errors and warnings, before updating to the next one. ### Reserved and private variables \#### Reserved variables Currently, we have reserved the following variables: - Model: \`agents\`, \`current\_id\`, \`random\`, \`running\`, \`steps\`, \`time\`. - Agent: \`unique\_id\`, \`model\`. You can use (read) any reserved variable, but Mesa may update them automatically and rely on them, so modify/update at your own risk. #### Private variables Any variables starting with an underscore (\`\_\`) are considered private and for Mesa's internal use. We might use any of those. Modifying or overwriting any private variable is at your own risk. - Ref: \[Discussion #2230\](https://github.com/projectmesa/mesa/discussions/2230), \[PR #2225\](https://github.com/projectmesa/mesa/pull/2225) ### Removal of \`mesa.flat\` namespace The \`mesa.flat\` namespace is removed. Use the full namespace for your imports. - Ref: \[PR #2091\](https://github.com/projectmesa/mesa/pull/2091) ### Mandatory Model initialization with \`super().\_\_init\_\_()\` In Mesa 3.0, it is now mandatory to call \`super().\_\_init\_\_()\` when initializing your model class. This ensures that all necessary Mesa model variables are correctly set up and agents are properly added to the model. If you want to control the seed of the random number generator, you have to pass this as a keyword argument to super as shown below. Make sure all your model classes explicitly call \`super().\_\_init\_\_()\` in their \`\_\_init\_\_\` method: \`\`\`python class MyModel(mesa.Model): def \_\_init\_\_(self, some\_arg\_I\_need, seed=None, some\_kwarg\_I\_need=True): super().\_\_init\_\_(seed=seed) # Calling super is now required, passing seed is highly recommended # Your model initialization code here # this code uses some\_arg\_I\_need and my\_init\_kwarg \`\`\` This change ensures that all Mesa models are properly initialized, which is crucial for: - Correctly adding agents to the model - Setting up other essential Mesa model variables - Maintaining consistency across all models If you forget to call \`super().\_\_init\_\_()\`, you'll now see this error: \`\`\` RuntimeError: The Mesa Model class was not initialized. You must explicitly initialize the Model by calling super().\_\_init\_\_() on initialization. \`\`\` - Ref: \[PR #2218\](https://github.com/projectmesa/mesa/pull/2218), \[PR #1928\](https://github.com/projectmesa/mesa/pull/1928), Mesa-examples \[PR #83\](https://github.com/projectmesa/mesa-examples/pull/83) ### Automatic assignment of \`unique\_id\` to Agents In Mesa 3.0, \`unique\_id\` for agents is now automatically assigned, simplifying agent creation and ensuring unique IDs across all agents in a model. 1. Remove \`unique\_id\` from agent initialization: \`\`\`python # Old agent = MyAgent(unique\_id=unique\_id, model=self, ...) agent = MyAgent(unique\_id, self, ...) agent = MyAgent(self.next\_id(), self, ...) # New agent = MyAgent(model=self, ...) agent = MyAgent(self, ...) \`\`\` 2. Remove \`unique\_id\` from Agent super() call: \`\`\`python # Old class MyAgent(Agent): def \_\_init\_\_(self, unique\_id, model, ...): super().\_\_init\_\_(unique\_id, model) # New class MyAgent(Agent): def \_\_init\_\_(self, model, ...): super().\_\_init\_\_(model) \`\`\` 3. Important notes: - \`unique\_id\` is now automatically assigned relative to a Model instance and starts from 1 - \`Model.next\_id()\` is removed - If you previously used custom \`unique\_id\` values, store that information in a separate attribute - Ref: \[PR #2226\](https://github.com/projectmesa/mesa/pull/2226), \[PR #2260\](https://github.com/projectmesa/mesa/pull/2260), Mesa-examples \[PR #194\](https://github.com/projectmesa/mesa-examples/pull/194), \[Issue #2213\](https://github.com/projectmesa/mesa/issues/2213) ### AgentSet and \`Model.agents\` In Mesa 3.0, the Model class internally manages agents using several data structures: - \`self.\_agents\`: A dictionary containing hard references to all agents, indexed by their \`unique\_id\`. - \`self.\_agents\_by\_type\`: A dictionary of AgentSets, organizing agents by their type. - \`self.\_all\_agents\`: An AgentSet containing all agents in the model. These internal structures are used to efficiently manage and access agents. Users should interact with agents through the public \`model.agents\` property, which returns the \`self.\_all\_agents\` AgentSet. #### \`Model.agents\` - Attempting to set \`model.agents\` now raises an \`AttributeError\` instead of a warning. This attribute is reserved for internal use by Mesa. - If you were previously setting \`model.agents\` in your code, you must update it to use a different attribute name for custom agent storage. For example, replace: \`\`\`python model.agents = my\_custom\_agents \`\`\` With: \`\`\`python model.custom\_agents = my\_custom\_agents \`\`\` ### Time and schedulers \#### Automatic increase of the \`steps\` counter The \`steps\` counter is now automatically increased. With each call to \`Model.steps()\` it's increased by 1, at the beginning of the step. You can access it by \`Model.steps\`, and it's internally in the datacollector, batchrunner and the visualisation. - Ref: \[PR #2223\](https://github.com/projectmesa/mesa/pull/2223), Mesa-examples \[PR #161\](https://github.com/projectmesa/mesa-examples/pull/161) #### Removal of \`Model.\_time\` and rename \`.\_steps\` - \`Model.\_time\` is removed. You can define your own time variable if needed. - \`Model.\_steps\` steps is renamed to \`Model.steps\`. #### Removal of \`Model.\_advance\_time()\` - The \`Model.\_advance\_time()\` method is removed. This now happens automatically. #### Replacing Schedulers with AgentSet functionality The whole Time module in Mesa is deprecated and will be removed in Mesa 3.1. All schedulers should be replaced with AgentSet functionality and the internal \`Model.steps\` counter. This allows much more flexibility in how to activate Agents and makes it explicit what's done exactly. Here's how to replace each scheduler: ##### BaseScheduler Replace: \`\`\`python self.schedule = BaseScheduler(self) self.schedule.step() \`\`\` With: \`\`\`python self.agents.do("step") \`\`\` ##### RandomActivation Replace: \`\`\`python self.schedule = RandomActivation(self) self.schedule.step() \`\`\` With: \`\`\`python self.agents.shuffle\_do("step") \`\`\` ##### SimultaneousActivation Replace: \`\`\`python self.schedule = SimultaneousActivation(self) self.schedule.step() \`\`\` With: \`\`\`python self.agents.do("step") self.agents.do("advance") \`\`\` ##### StagedActivation Replace: \`\`\`python self.schedule = StagedActivation(self, \["stage1", "stage2", "stage3"\]) self.schedule.step() \`\`\` With: \`\`\`python for stage in \["stage1", "stage2", "stage3"\]: self.agents.do(stage) \`\`\` If you were using the \`shuffle\` and/or \`shuffle\_between\_stages\` options: \`\`\`python stages = \["stage1", "stage2", "stage3"\] if shuffle: self.random.shuffle(stages) for stage in stages: if shuffle\_between\_stages: self.agents.shuffle\_do(stage) else: self.agents.do(stage) \`\`\` ##### RandomActivationByType Replace: \`\`\`python self.schedule = RandomActivationByType(self) self.schedule.step() \`\`\` With: \`\`\`python for agent\_class in self.agent\_types: self.agents\_by\_type\[agent\_class\].shuffle\_do("step") \`\`\` ###### Replacing \`step\_type\` The \`RandomActivationByType\` scheduler had a \`step\_type\` method that allowed stepping only agents of a specific type. To replicate this functionality using AgentSet: Replace: \`\`\`python self.schedule.step\_type(AgentType) \`\`\` With: \`\`\`python self.agents\_by\_type\[AgentType\].shuffle\_do("step") \`\`\` ##### General Notes 1. The \`Model.steps\` counter is now automatically incremented. You don't need to manage it manually. 2. If you were using \`self.schedule.agents\`, replace it with \`self.agents\`. 3. If you were using \`self.schedule.get\_agent\_count()\`, replace it with \`len(self.agents)\`. 4. If you were using \`self.schedule.agents\_by\_type\`, replace it with \`self.agents\_by\_type\`. 5. Agents are now automatically added to or removed from the model's \`AgentSet\` (\`model.agents\`) when they are created or deleted, eliminating the need to manually call \`self.schedule.add()\` or \`self.schedule.remove()\`. - However, you still need to explicitly remove the Agent itself by using \`Agent.remove()\`. Typically, this means: - Replace \`self.schedule.remove(agent)\` with \`agent.remove()\` in the Model. - Replace \`self.model.schedule.remove(self)\` with \`self.remove()\` within the Agent. From now on you're now not bound by 5 distinct schedulers, but can mix and match any combination of AgentSet methods (\`do\`, \`shuffle\`, \`select\`, etc.) to get the desired Agent activation. Ref: Original discussion \[#1912\](https://github.com/projectmesa/mesa/discussions/1912), decision discussion \[#2231\](https://github.com/projectmesa/mesa/discussions/2231), example updates \[#183\](https://github.com/projectmesa/mesa-examples/pull/183) and \[#201\](https://github.com/projectmesa/mesa-examples/pull/201), PR \[#2306\](https://github.com/projectmesa/mesa/pull/2306) ### Visualisation Mesa has adopted a new API for our frontend. If you already migrated to the experimental new SolaraViz you can still use the import from mesa.experimental. Otherwise here is a list of things you need to change. > \*\*Note:\*\* SolaraViz is experimental and still in active development for Mesa 3.0. While we attempt to minimize them, there might be API breaking changes between Mesa 3.0 and 3.1. There won't be breaking changes between Mesa 3.0.x patch releases. #### Model Initialization Previously SolaraViz was initialized by providing a \`model\_cls\` and a \`model\_params\`. This has changed to expect a model instance \`model\`. You can still provide (user-settable) \`model\_params\`, but only if users should be able to change them. It is now also possible to pass in a "reactive model" by first calling \`model = solara.reactive(model)\`. This is useful for notebook environments. It allows you to pass the model to the SolaraViz Module, but continue to use the model. For example calling \`model.value.step()\` (notice the extra .value) will automatically update the plots. This currently only automatically works for the step method, you can force visualization updates by calling \`model.value.force\_update()\`. ### Model Initialization with Keyword Arguments With the introduction of SolaraViz in Mesa 3.0, models are now instantiated using \`\*\*model\_parameters.value\`. This means all inputs for initializing a new model must be keyword arguments. Ensure your model's \`\_\_init\_\_\` method accepts keyword arguments matching the keys in \`model\_params\`. \`\`\`python class MyModel(mesa.Model): def \_\_init\_\_(self, n\_agents=10, seed=None): super().\_\_init\_\_(seed=seed) # Initialize the model with N agents \`\`\` #### Default space visualization Previously we included a default space drawer that you could configure with an \`agent\_portrayal\` function. You now have to explicitly create a space drawer with the \`agent\_portrayal\` function \`\`\`python # old from mesa.experimental import SolaraViz SolaraViz(model\_cls, model\_params, agent\_portrayal=agent\_portrayal) # new from mesa.visualization import SolaraViz, make\_space\_component SolaraViz(model, components=\[make\_space\_component(agent\_portrayal)\]) \`\`\` #### Plotting "measures" "Measure" plots also need to be made explicit here. Previously, measure could either be 1) A function that receives a model and returns a solara component or 2) A string or list of string of variables that are collected by the datacollector and are to be plotted as a line plot. 1) still works, but you can pass that function to "components" directly. 2) needs to explicitly call the \`make\_plot\_measure()\`function. \`\`\`python # old from mesa.experimental import SolaraViz def make\_plot(model): ... SolaraViz(model\_cls, model\_params, measures=\[make\_plot, "foo", \["bar", "baz"\]\]) # new from mesa.visualization import SolaraViz, make\_plot\_component SolaraViz(model, components=\[make\_plot, make\_plot\_component("foo"), make\_plot\_component("bar", "baz")\]) \`\`\` #### Plotting text To plot model-dependent text the experimental SolaraViz provided a \`make\_text\` function that wraps another functions that receives the model and turns its string return value into a solara text component. Again, this other function can now be passed directly to the new SolaraViz components array. It is okay if your function just returns a string. \`\`\`python # old from mesa.experimental import SolaraViz, make\_text def show\_steps(model): return f"Steps: {model.steps}" SolaraViz(model\_cls, model\_params, measures=make\_text(show\_steps)) # new from mesa.visualisation import SolaraViz def show\_steps(model): return f"Steps: {model.steps}" SolaraViz(model, components=\[show\_steps\]) \`\`\` ### Other changes #### Removal of Model.initialize\_data\_collector The \`initialize\_data\_collector\` in the Model class is removed. In the Model class, replace: Replace: \`\`\`python self.initialize\_data\_collector(...) \`\`\` With: \`\`\`python self.datacollector = DataCollector(...) \`\`\` - Ref: \[PR #2327\](https://github.com/projectmesa/mesa/pull/2327), Mesa-examples \[PR #208\](https://github.com/projectmesa/mesa-examples/pull/208))
---
# Index — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Index
=====
[**\_**](#_)
| [**A**](#A)
| [**B**](#B)
| [**C**](#C)
| [**D**](#D)
| [**E**](#E)
| [**F**](#F)
| [**G**](#G)
| [**H**](#H)
| [**I**](#I)
| [**L**](#L)
| [**M**](#M)
| [**N**](#N)
| [**O**](#O)
| [**P**](#P)
| [**R**](#R)
| [**S**](#S)
| [**T**](#T)
| [**U**](#U)
| [**V**](#V)
| [**W**](#W)
\_
--
* [\_try\_random (Grid attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.Grid._try_random)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.grid.Grid._try_random)
A
-
| | |
| --- | --- |
| * [ABMSimulator (class in experimental.devs.simulator)](apis/experimental.html#experimental.devs.simulator.ABMSimulator)
* [accept\_tuple\_argument() (in module mesa.space)](apis/space.html#mesa.space.accept_tuple_argument)
, [\[1\]](mesa.html#mesa.space.accept_tuple_argument)
* [add() (AgentSet method)](apis/agent.html#mesa.agent.AgentSet.add)
, [\[1\]](mesa.html#mesa.agent.AgentSet.add)
* [add\_agent() (Cell method)](apis/discrete_space.html#mesa.discrete_space.__init__.Cell.add_agent)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell.Cell.add_agent)
* [add\_event() (EventList method)](apis/experimental.html#experimental.devs.eventlist.EventList.add_event)
* [add\_point() (Delaunay method)](apis/discrete_space.html#mesa.discrete_space.voronoi.Delaunay.add_point)
* [add\_property\_layer() (HexMultiGrid method)](apis/space.html#mesa.space.HexMultiGrid.add_property_layer)
* [(HexSingleGrid method)](apis/space.html#mesa.space.HexSingleGrid.add_property_layer)
* [(MultiGrid method)](apis/space.html#mesa.space.MultiGrid.add_property_layer)
* [(SingleGrid method)](apis/space.html#mesa.space.SingleGrid.add_property_layer)
* [add\_table\_row() (DataCollector method)](apis/datacollection.html#datacollection.DataCollector.add_table_row)
, [\[1\]](mesa.html#mesa.DataCollector.add_table_row)
, [\[2\]](mesa.html#mesa.datacollection.DataCollector.add_table_row)
* [advance() (Agent method)](mesa.html#mesa.Agent.advance)
, [\[1\]](mesa.html#mesa.agent.Agent.advance)
* [Agent (class in mesa)](mesa.html#mesa.Agent)
* [(class in mesa.agent)](apis/agent.html#mesa.agent.Agent)
, [\[1\]](mesa.html#mesa.agent.Agent)
* [agent\_types (Model property)](apis/model.html#mesa.model.Model.agent_types)
, [\[1\]](mesa.html#mesa.Model.agent_types)
, [\[2\]](mesa.html#mesa.model.Model.agent_types)
* [agents (Cell attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.Cell.agents)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell.Cell.agents)
* [(Cell property)](apis/discrete_space.html#id0)
, [\[1\]](apis/discrete_space.html#id3)
* [(CellCollection attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.CellCollection.agents)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell_collection.CellCollection.agents)
* [(ContinuousSpace property)](apis/experimental.html#experimental.continuous_space.continuous_space.ContinuousSpace.agents)
, [\[1\]](apis/space.html#mesa.space.ContinuousSpace.agents)
, [\[2\]](mesa.html#mesa.space.ContinuousSpace.agents)
* [(DiscreteSpace property)](apis/discrete_space.html#mesa.discrete_space.__init__.DiscreteSpace.agents)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.discrete_space.DiscreteSpace.agents)
* [(HexMultiGrid property)](apis/space.html#mesa.space.HexMultiGrid.agents)
* [(HexSingleGrid property)](apis/space.html#mesa.space.HexSingleGrid.agents)
* [(Model property)](apis/model.html#mesa.model.Model.agents)
, [\[1\]](mesa.html#mesa.Model.agents)
, [\[2\]](mesa.html#mesa.model.Model.agents)
* [(MultiGrid property)](apis/space.html#mesa.space.MultiGrid.agents)
* [(NetworkGrid property)](apis/space.html#mesa.space.NetworkGrid.agents)
, [\[1\]](mesa.html#mesa.space.NetworkGrid.agents)
* [(SingleGrid property)](apis/space.html#mesa.space.SingleGrid.agents) | * [agents\_by\_type (Model property)](apis/model.html#mesa.model.Model.agents_by_type)
, [\[1\]](mesa.html#mesa.Model.agents_by_type)
, [\[2\]](mesa.html#mesa.model.Model.agents_by_type)
* [AgentSet (class in mesa.agent)](apis/agent.html#mesa.agent.AgentSet)
, [\[1\]](mesa.html#mesa.agent.AgentSet)
* [agg() (AgentSet method)](apis/agent.html#mesa.agent.AgentSet.agg)
, [\[1\]](mesa.html#mesa.agent.AgentSet.agg)
* [(GroupBy method)](apis/agent.html#mesa.agent.GroupBy.agg)
, [\[1\]](mesa.html#mesa.agent.GroupBy.agg)
* [aggregate() (PropertyLayer method)](apis/discrete_space.html#mesa.discrete_space.__init__.PropertyLayer.aggregate)
* [aggregate\_property() (PropertyLayer method)](apis/space.html#mesa.space.PropertyLayer.aggregate_property)
, [\[1\]](mesa.html#mesa.space.PropertyLayer.aggregate_property)
* [all\_cells (DiscreteSpace attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.DiscreteSpace.all_cells)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.discrete_space.DiscreteSpace.all_cells)
* [(DiscreteSpace property)](apis/discrete_space.html#id1)
, [\[1\]](apis/discrete_space.html#id4) |
B
-
| | |
| --- | --- |
| * [BasicMovement (class in mesa.discrete\_space.cell\_agent)](apis/discrete_space.html#mesa.discrete_space.cell_agent.BasicMovement)
* [batch\_run() (in module batchrunner)](apis/batchrunner.html#batchrunner.batch_run)
* [(in module mesa)](mesa.html#mesa.batch_run)
* [(in module mesa.batchrunner)](mesa.html#mesa.batchrunner.batch_run) | * batchrunner
* [module](apis/batchrunner.html#module-batchrunner)
* [buffer (ConsoleManager attribute)](apis/visualization.html#mesa.visualization.command_console.ConsoleManager.buffer) |
C
-
| | |
| --- | --- |
| * [calculate\_difference\_vector() (ContinuousSpace method)](apis/experimental.html#experimental.continuous_space.continuous_space.ContinuousSpace.calculate_difference_vector)
* [calculate\_distances() (ContinuousSpace method)](apis/experimental.html#experimental.continuous_space.continuous_space.ContinuousSpace.calculate_distances)
* [cancel() (SimulationEvent method)](apis/experimental.html#experimental.devs.eventlist.SimulationEvent.cancel)
* [cancel\_event() (Simulator method)](apis/experimental.html#experimental.devs.simulator.Simulator.cancel_event)
* [capacity (Cell attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.Cell.capacity)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell.Cell.capacity)
* [(DiscreteSpace attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.DiscreteSpace.capacity)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.discrete_space.DiscreteSpace.capacity)
* [(Grid attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.Grid.capacity)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.grid.Grid.capacity)
* [CaptureOutput (class in mesa.visualization.command\_console)](apis/visualization.html#mesa.visualization.command_console.CaptureOutput)
* [cell (CellAgent attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.CellAgent.cell)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell_agent.CellAgent.cell)
* [Cell (class in mesa.discrete\_space.\_\_init\_\_)](apis/discrete_space.html#mesa.discrete_space.__init__.Cell)
* [(class in mesa.discrete\_space.cell)](apis/discrete_space.html#mesa.discrete_space.cell.Cell)
* [cell\_klass (DiscreteSpace attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.DiscreteSpace.cell_klass)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.discrete_space.DiscreteSpace.cell_klass)
* [CellAgent (class in mesa.discrete\_space.\_\_init\_\_)](apis/discrete_space.html#mesa.discrete_space.__init__.CellAgent)
* [(class in mesa.discrete\_space.cell\_agent)](apis/discrete_space.html#mesa.discrete_space.cell_agent.CellAgent)
* [CellCollection (class in mesa.discrete\_space.\_\_init\_\_)](apis/discrete_space.html#mesa.discrete_space.__init__.CellCollection)
* [(class in mesa.discrete\_space.cell\_collection)](apis/discrete_space.html#mesa.discrete_space.cell_collection.CellCollection)
* [cells (CellCollection attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.CellCollection.cells)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell_collection.CellCollection.cells)
* [chart\_property\_layers() (in module mesa.visualization.components.altair\_components)](apis/visualization.html#mesa.visualization.components.altair_components.chart_property_layers)
* [check\_param\_is\_fixed() (in module mesa.visualization.solara\_viz)](apis/visualization.html#mesa.visualization.solara_viz.check_param_is_fixed)
* [check\_time\_unit() (ABMSimulator method)](apis/experimental.html#experimental.devs.simulator.ABMSimulator.check_time_unit)
* [(DEVSimulator method)](apis/experimental.html#experimental.devs.simulator.DEVSimulator.check_time_unit) | * [clear() (AgentSet method)](apis/agent.html#mesa.agent.AgentSet.clear)
* [(EventList method)](apis/experimental.html#experimental.devs.eventlist.EventList.clear)
* [clear\_console() (ConsoleManager method)](apis/visualization.html#mesa.visualization.command_console.ConsoleManager.clear_console)
* [collect() (DataCollector method)](apis/datacollection.html#datacollection.DataCollector.collect)
, [\[1\]](mesa.html#mesa.DataCollector.collect)
, [\[2\]](mesa.html#mesa.datacollection.DataCollector.collect)
* [collect\_agent\_data() (in module mesa.visualization.mpl\_space\_drawing)](apis/visualization.html#mesa.visualization.mpl_space_drawing.collect_agent_data)
* [command (ConsoleEntry attribute)](apis/visualization.html#id0)
, [\[1\]](apis/visualization.html#mesa.visualization.command_console.ConsoleEntry.command)
* [connect() (Cell method)](apis/discrete_space.html#mesa.discrete_space.__init__.Cell.connect)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell.Cell.connect)
* [console (ConsoleManager attribute)](apis/visualization.html#mesa.visualization.command_console.ConsoleManager.console)
* [ConsoleEntry (class in mesa.visualization.command\_console)](apis/visualization.html#mesa.visualization.command_console.ConsoleEntry)
* [ConsoleManager (class in mesa.visualization.command\_console)](apis/visualization.html#mesa.visualization.command_console.ConsoleManager)
* [ContinuousSpace (class in experimental.continuous\_space.continuous\_space)](apis/experimental.html#experimental.continuous_space.continuous_space.ContinuousSpace)
* [(class in mesa.space)](apis/space.html#mesa.space.ContinuousSpace)
, [\[1\]](mesa.html#mesa.space.ContinuousSpace)
* [ContinuousSpaceAgent (class in experimental.continuous\_space.continuous\_space\_agents)](apis/experimental.html#experimental.continuous_space.continuous_space_agents.ContinuousSpaceAgent)
* [coord\_iter() (HexMultiGrid method)](apis/space.html#mesa.space.HexMultiGrid.coord_iter)
* [(HexSingleGrid method)](apis/space.html#mesa.space.HexSingleGrid.coord_iter)
* [(MultiGrid method)](apis/space.html#mesa.space.MultiGrid.coord_iter)
* [(SingleGrid method)](apis/space.html#mesa.space.SingleGrid.coord_iter)
* [coordinate (Cell attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.Cell.coordinate)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell.Cell.coordinate)
* [count() (AgentSet method)](apis/agent.html#mesa.agent.AgentSet.count)
* [(GroupBy method)](apis/agent.html#mesa.agent.GroupBy.count)
, [\[1\]](mesa.html#mesa.agent.GroupBy.count)
* [create\_agents() (Agent class method)](apis/agent.html#mesa.agent.Agent.create_agents)
, [\[1\]](mesa.html#mesa.Agent.create_agents)
, [\[2\]](mesa.html#mesa.agent.Agent.create_agents) |
D
-
| | |
| --- | --- |
| * [data (PropertyLayer attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.PropertyLayer.data)
, [\[1\]](apis/space.html#mesa.space.PropertyLayer.data)
, [\[2\]](mesa.html#mesa.space.PropertyLayer.data)
* datacollection
* [module](apis/datacollection.html#module-datacollection)
* [DataCollector (class in datacollection)](apis/datacollection.html#datacollection.DataCollector)
* [(class in mesa)](mesa.html#mesa.DataCollector)
* [(class in mesa.datacollection)](mesa.html#mesa.datacollection.DataCollector)
* [default\_val() (HexMultiGrid static method)](apis/space.html#mesa.space.HexMultiGrid.default_val)
* [(HexSingleGrid static method)](apis/space.html#mesa.space.HexSingleGrid.default_val)
* [(MultiGrid static method)](apis/space.html#mesa.space.MultiGrid.default_val)
, [\[1\]](mesa.html#mesa.space.MultiGrid.default_val)
* [(NetworkGrid static method)](apis/space.html#mesa.space.NetworkGrid.default_val)
, [\[1\]](mesa.html#mesa.space.NetworkGrid.default_val)
* [(SingleGrid static method)](apis/space.html#mesa.space.SingleGrid.default_val)
* [Delaunay (class in mesa.discrete\_space.voronoi)](apis/discrete_space.html#mesa.discrete_space.voronoi.Delaunay)
* [deregister\_agent() (Model method)](apis/model.html#mesa.model.Model.deregister_agent)
, [\[1\]](mesa.html#mesa.Model.deregister_agent)
, [\[2\]](mesa.html#mesa.model.Model.deregister_agent)
* [DEVSimulator (class in experimental.devs.simulator)](apis/experimental.html#experimental.devs.simulator.DEVSimulator) | * [dimensions (Grid attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.Grid.dimensions)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.grid.Grid.dimensions)
* [(PropertyLayer attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.PropertyLayer.dimensions)
* [discard() (AgentSet method)](apis/agent.html#mesa.agent.AgentSet.discard)
, [\[1\]](mesa.html#mesa.agent.AgentSet.discard)
* [disconnect() (Cell method)](apis/discrete_space.html#mesa.discrete_space.__init__.Cell.disconnect)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell.Cell.disconnect)
* [DiscreteSpace (class in mesa.discrete\_space.\_\_init\_\_)](apis/discrete_space.html#mesa.discrete_space.__init__.DiscreteSpace)
* [(class in mesa.discrete\_space.discrete\_space)](apis/discrete_space.html#mesa.discrete_space.discrete_space.DiscreteSpace)
* [do() (AgentSet method)](apis/agent.html#mesa.agent.AgentSet.do)
, [\[1\]](mesa.html#mesa.agent.AgentSet.do)
* [(GroupBy method)](apis/agent.html#mesa.agent.GroupBy.do)
, [\[1\]](mesa.html#mesa.agent.GroupBy.do)
* [draw\_continuous\_space() (in module mesa.visualization.mpl\_space\_drawing)](apis/visualization.html#mesa.visualization.mpl_space_drawing.draw_continuous_space)
* [draw\_hex\_grid() (in module mesa.visualization.mpl\_space\_drawing)](apis/visualization.html#mesa.visualization.mpl_space_drawing.draw_hex_grid)
* [draw\_network() (in module mesa.visualization.mpl\_space\_drawing)](apis/visualization.html#mesa.visualization.mpl_space_drawing.draw_network)
* [draw\_orthogonal\_grid() (in module mesa.visualization.mpl\_space\_drawing)](apis/visualization.html#mesa.visualization.mpl_space_drawing.draw_orthogonal_grid)
* [draw\_property\_layers() (in module mesa.visualization.mpl\_space\_drawing)](apis/visualization.html#mesa.visualization.mpl_space_drawing.draw_property_layers)
* [draw\_space() (in module mesa.visualization.mpl\_space\_drawing)](apis/visualization.html#mesa.visualization.mpl_space_drawing.draw_space)
* [draw\_voronoi\_grid() (in module mesa.visualization.mpl\_space\_drawing)](apis/visualization.html#mesa.visualization.mpl_space_drawing.draw_voronoi_grid) |
E
-
| | |
| --- | --- |
| * [empties (DiscreteSpace attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.DiscreteSpace.empties)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.discrete_space.DiscreteSpace.empties)
* [(DiscreteSpace property)](apis/discrete_space.html#id2)
, [\[1\]](apis/discrete_space.html#id5)
* [empty\_mask (HexMultiGrid property)](apis/space.html#mesa.space.HexMultiGrid.empty_mask)
* [(HexSingleGrid property)](apis/space.html#mesa.space.HexSingleGrid.empty_mask)
* [(MultiGrid property)](apis/space.html#mesa.space.MultiGrid.empty_mask)
* [(SingleGrid property)](apis/space.html#mesa.space.SingleGrid.empty_mask)
* [event\_list (Simulator attribute)](apis/experimental.html#experimental.devs.simulator.Simulator.event_list)
* [EventList (class in experimental.devs.eventlist)](apis/experimental.html#experimental.devs.eventlist.EventList)
* [execute() (SimulationEvent method)](apis/experimental.html#experimental.devs.eventlist.SimulationEvent.execute)
* [execute\_code() (ConsoleManager method)](apis/visualization.html#mesa.visualization.command_console.ConsoleManager.execute_code)
* [exists\_empty\_cells() (HexMultiGrid method)](apis/space.html#mesa.space.HexMultiGrid.exists_empty_cells)
* [(HexSingleGrid method)](apis/space.html#mesa.space.HexSingleGrid.exists_empty_cells)
* [(MultiGrid method)](apis/space.html#mesa.space.MultiGrid.exists_empty_cells)
* [(SingleGrid method)](apis/space.html#mesa.space.SingleGrid.exists_empty_cells) | * experimental.continuous\_space.continuous\_space
* [module](apis/experimental.html#module-experimental.continuous_space.continuous_space)
* experimental.continuous\_space.continuous\_space\_agents
* [module](apis/experimental.html#module-experimental.continuous_space.continuous_space_agents)
* experimental.devs.eventlist
* [module](apis/experimental.html#module-experimental.devs.eventlist)
* experimental.devs.simulator
* [module](apis/experimental.html#module-experimental.devs.simulator)
* [export\_triangles() (Delaunay method)](apis/discrete_space.html#mesa.discrete_space.voronoi.Delaunay.export_triangles)
* [export\_voronoi\_regions() (Delaunay method)](apis/discrete_space.html#mesa.discrete_space.voronoi.Delaunay.export_voronoi_regions) |
F
-
| | |
| --- | --- |
| * [FixedAgent (class in mesa.discrete\_space.\_\_init\_\_)](apis/discrete_space.html#mesa.discrete_space.__init__.FixedAgent)
* [(class in mesa.discrete\_space.cell\_agent)](apis/discrete_space.html#mesa.discrete_space.cell_agent.FixedAgent)
* [FixedCell (class in mesa.discrete\_space.cell\_agent)](apis/discrete_space.html#mesa.discrete_space.cell_agent.FixedCell)
* [fn (SimulationEvent attribute)](apis/experimental.html#experimental.devs.eventlist.SimulationEvent.fn)
* [format\_command\_html() (in module mesa.visualization.command\_console)](apis/visualization.html#mesa.visualization.command_console.format_command_html) | * [format\_output\_html() (in module mesa.visualization.command\_console)](apis/visualization.html#mesa.visualization.command_console.format_output_html)
* [from\_data() (PropertyLayer class method)](apis/discrete_space.html#mesa.discrete_space.__init__.PropertyLayer.from_data)
* [function\_args (SimulationEvent attribute)](apis/experimental.html#experimental.devs.eventlist.SimulationEvent.function_args)
* [function\_kwargs (SimulationEvent attribute)](apis/experimental.html#experimental.devs.eventlist.SimulationEvent.function_kwargs)
* [function\_logger() (in module mesa.mesa\_logging)](apis/mesa_logging.html#mesa.mesa_logging.function_logger) |
G
-
| | |
| --- | --- |
| * [get() (AgentSet method)](apis/agent.html#mesa.agent.AgentSet.get)
, [\[1\]](mesa.html#mesa.agent.AgentSet.get)
* [(Slider method)](apis/visualization.html#mesa.visualization.user_param.Slider.get)
* [get\_agent\_vars\_dataframe() (DataCollector method)](apis/datacollection.html#datacollection.DataCollector.get_agent_vars_dataframe)
, [\[1\]](mesa.html#mesa.DataCollector.get_agent_vars_dataframe)
, [\[2\]](mesa.html#mesa.datacollection.DataCollector.get_agent_vars_dataframe)
* [get\_agents\_in\_radius() (ContinuousSpace method)](apis/experimental.html#experimental.continuous_space.continuous_space.ContinuousSpace.get_agents_in_radius)
* [get\_agenttype\_vars\_dataframe() (DataCollector method)](apis/datacollection.html#datacollection.DataCollector.get_agenttype_vars_dataframe)
, [\[1\]](mesa.html#mesa.DataCollector.get_agenttype_vars_dataframe)
, [\[2\]](mesa.html#mesa.datacollection.DataCollector.get_agenttype_vars_dataframe)
* [get\_all\_cell\_contents() (NetworkGrid method)](apis/space.html#mesa.space.NetworkGrid.get_all_cell_contents)
, [\[1\]](mesa.html#mesa.space.NetworkGrid.get_all_cell_contents)
* [get\_cell\_list\_contents() (NetworkGrid method)](apis/space.html#mesa.space.NetworkGrid.get_cell_list_contents)
, [\[1\]](mesa.html#mesa.space.NetworkGrid.get_cell_list_contents)
* [get\_distance() (ContinuousSpace method)](apis/space.html#mesa.space.ContinuousSpace.get_distance)
, [\[1\]](mesa.html#mesa.space.ContinuousSpace.get_distance)
* [get\_entries() (ConsoleManager method)](apis/visualization.html#mesa.visualization.command_console.ConsoleManager.get_entries)
* [get\_heading() (ContinuousSpace method)](apis/space.html#mesa.space.ContinuousSpace.get_heading)
, [\[1\]](mesa.html#mesa.space.ContinuousSpace.get_heading)
* [get\_k\_nearest\_agents() (ContinuousSpace method)](apis/experimental.html#experimental.continuous_space.continuous_space.ContinuousSpace.get_k_nearest_agents)
* [get\_model\_vars\_dataframe() (DataCollector method)](apis/datacollection.html#datacollection.DataCollector.get_model_vars_dataframe)
, [\[1\]](mesa.html#mesa.DataCollector.get_model_vars_dataframe)
, [\[2\]](mesa.html#mesa.datacollection.DataCollector.get_model_vars_dataframe)
* [get\_module\_logger() (in module mesa.mesa\_logging)](apis/mesa_logging.html#mesa.mesa_logging.get_module_logger)
* [get\_nearest\_neighbors() (ContinuousSpaceAgent method)](apis/experimental.html#experimental.continuous_space.continuous_space_agents.ContinuousSpaceAgent.get_nearest_neighbors)
* [get\_neighborhood() (Cell method)](apis/discrete_space.html#mesa.discrete_space.__init__.Cell.get_neighborhood)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell.Cell.get_neighborhood)
* [(HexMultiGrid method)](apis/space.html#mesa.space.HexMultiGrid.get_neighborhood)
* [(HexSingleGrid method)](apis/space.html#mesa.space.HexSingleGrid.get_neighborhood)
* [(MultiGrid method)](apis/space.html#mesa.space.MultiGrid.get_neighborhood)
* [(NetworkGrid method)](apis/space.html#mesa.space.NetworkGrid.get_neighborhood)
, [\[1\]](mesa.html#mesa.space.NetworkGrid.get_neighborhood)
* [(SingleGrid method)](apis/space.html#mesa.space.SingleGrid.get_neighborhood)
* [get\_neighborhood\_mask() (HexMultiGrid method)](apis/space.html#mesa.space.HexMultiGrid.get_neighborhood_mask)
* [(HexSingleGrid method)](apis/space.html#mesa.space.HexSingleGrid.get_neighborhood_mask)
* [(MultiGrid method)](apis/space.html#mesa.space.MultiGrid.get_neighborhood_mask)
* [(SingleGrid method)](apis/space.html#mesa.space.SingleGrid.get_neighborhood_mask) | * [get\_neighbors() (ContinuousSpace method)](apis/space.html#mesa.space.ContinuousSpace.get_neighbors)
, [\[1\]](mesa.html#mesa.space.ContinuousSpace.get_neighbors)
* [(HexMultiGrid method)](apis/space.html#mesa.space.HexMultiGrid.get_neighbors)
* [(HexSingleGrid method)](apis/space.html#mesa.space.HexSingleGrid.get_neighbors)
* [(MultiGrid method)](apis/space.html#mesa.space.MultiGrid.get_neighbors)
* [(NetworkGrid method)](apis/space.html#mesa.space.NetworkGrid.get_neighbors)
, [\[1\]](mesa.html#mesa.space.NetworkGrid.get_neighbors)
* [(SingleGrid method)](apis/space.html#mesa.space.SingleGrid.get_neighbors)
* [get\_neighbors\_in\_radius() (ContinuousSpaceAgent method)](apis/experimental.html#experimental.continuous_space.continuous_space_agents.ContinuousSpaceAgent.get_neighbors_in_radius)
* [get\_output() (CaptureOutput method)](apis/visualization.html#mesa.visualization.command_console.CaptureOutput.get_output)
* [get\_rootlogger() (in module mesa.mesa\_logging)](apis/mesa_logging.html#mesa.mesa_logging.get_rootlogger)
* [get\_table\_dataframe() (DataCollector method)](apis/datacollection.html#datacollection.DataCollector.get_table_dataframe)
, [\[1\]](mesa.html#mesa.DataCollector.get_table_dataframe)
, [\[2\]](mesa.html#mesa.datacollection.DataCollector.get_table_dataframe)
* [Grid (class in mesa.discrete\_space.\_\_init\_\_)](apis/discrete_space.html#mesa.discrete_space.__init__.Grid)
* [(class in mesa.discrete\_space.grid)](apis/discrete_space.html#mesa.discrete_space.grid.Grid)
* [grid (MultiGrid attribute)](mesa.html#mesa.space.MultiGrid.grid)
* [Grid2DMovingAgent (class in mesa.discrete\_space.\_\_init\_\_)](apis/discrete_space.html#mesa.discrete_space.__init__.Grid2DMovingAgent)
* [(class in mesa.discrete\_space.cell\_agent)](apis/discrete_space.html#mesa.discrete_space.cell_agent.Grid2DMovingAgent)
* [GroupBy (class in mesa.agent)](apis/agent.html#mesa.agent.GroupBy)
, [\[1\]](mesa.html#mesa.agent.GroupBy)
* [groupby() (AgentSet method)](apis/agent.html#mesa.agent.AgentSet.groupby)
, [\[1\]](mesa.html#mesa.agent.AgentSet.groupby)
* [groups (GroupBy attribute)](apis/agent.html#mesa.agent.GroupBy.groups)
, [\[1\]](mesa.html#mesa.agent.GroupBy.groups) |
H
-
| | |
| --- | --- |
| * [HasCell (class in mesa.discrete\_space.cell\_agent)](apis/discrete_space.html#mesa.discrete_space.cell_agent.HasCell)
* [HasCellProtocol (class in mesa.discrete\_space.cell\_agent)](apis/discrete_space.html#mesa.discrete_space.cell_agent.HasCellProtocol)
* [HasPositionProtocol (class in experimental.continuous\_space.continuous\_space\_agents)](apis/experimental.html#experimental.continuous_space.continuous_space_agents.HasPositionProtocol)
* [height (Grid property)](apis/discrete_space.html#mesa.discrete_space.__init__.Grid.height)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.grid.Grid.height)
* [(PropertyLayer attribute)](apis/space.html#mesa.space.PropertyLayer.height)
, [\[1\]](mesa.html#mesa.space.PropertyLayer.height) | * [HexGrid (class in mesa.discrete\_space.\_\_init\_\_)](apis/discrete_space.html#mesa.discrete_space.__init__.HexGrid)
* [(class in mesa.discrete\_space.grid)](apis/discrete_space.html#mesa.discrete_space.grid.HexGrid)
* [HexMultiGrid (class in mesa.space)](apis/space.html#mesa.space.HexMultiGrid)
, [\[1\]](mesa.html#mesa.space.HexMultiGrid)
* [HexSingleGrid (class in mesa.space)](apis/space.html#mesa.space.HexSingleGrid)
, [\[1\]](mesa.html#mesa.space.HexSingleGrid)
* [history (ConsoleManager attribute)](apis/visualization.html#mesa.visualization.command_console.ConsoleManager.history) |
I
-
| | |
| --- | --- |
| * [in\_bounds() (ContinuousSpace method)](apis/experimental.html#experimental.continuous_space.continuous_space.ContinuousSpace.in_bounds)
* [index() (AgentSet method)](apis/agent.html#mesa.agent.AgentSet.index)
* [InteractiveConsole (class in mesa.visualization.command\_console)](apis/visualization.html#mesa.visualization.command_console.InteractiveConsole)
* [is\_cell\_empty() (HexMultiGrid method)](apis/space.html#mesa.space.HexMultiGrid.is_cell_empty)
* [(HexSingleGrid method)](apis/space.html#mesa.space.HexSingleGrid.is_cell_empty)
* [(MultiGrid method)](apis/space.html#mesa.space.MultiGrid.is_cell_empty)
* [(NetworkGrid method)](apis/space.html#mesa.space.NetworkGrid.is_cell_empty)
, [\[1\]](mesa.html#mesa.space.NetworkGrid.is_cell_empty)
* [(SingleGrid method)](apis/space.html#mesa.space.SingleGrid.is_cell_empty)
* [is\_continuation (ConsoleEntry attribute)](apis/visualization.html#id3)
, [\[1\]](apis/visualization.html#mesa.visualization.command_console.ConsoleEntry.is_continuation)
* [is\_empty (Cell property)](apis/discrete_space.html#mesa.discrete_space.__init__.Cell.is_empty)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell.Cell.is_empty)
* [is\_empty() (EventList method)](apis/experimental.html#experimental.devs.eventlist.EventList.is_empty)
* [is\_error (ConsoleEntry attribute)](apis/visualization.html#id2)
, [\[1\]](apis/visualization.html#mesa.visualization.command_console.ConsoleEntry.is_error)
* [is\_full (Cell property)](apis/discrete_space.html#mesa.discrete_space.__init__.Cell.is_full)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell.Cell.is_full) | * [is\_integer() (in module mesa.space)](apis/space.html#mesa.space.is_integer)
, [\[1\]](mesa.html#mesa.space.is_integer)
* [is\_single\_argument\_function() (in module mesa.space)](apis/space.html#mesa.space.is_single_argument_function)
, [\[1\]](mesa.html#mesa.space.is_single_argument_function)
* [isdisjoint() (AgentSet method)](apis/agent.html#mesa.agent.AgentSet.isdisjoint)
* [iter\_cell\_list\_contents() (MultiGrid method)](mesa.html#mesa.space.MultiGrid.iter_cell_list_contents)
* [(NetworkGrid method)](apis/space.html#mesa.space.NetworkGrid.iter_cell_list_contents)
, [\[1\]](mesa.html#mesa.space.NetworkGrid.iter_cell_list_contents)
* [iter\_neighborhood() (HexMultiGrid method)](apis/space.html#mesa.space.HexMultiGrid.iter_neighborhood)
* [(HexSingleGrid method)](apis/space.html#mesa.space.HexSingleGrid.iter_neighborhood)
* [(MultiGrid method)](apis/space.html#mesa.space.MultiGrid.iter_neighborhood)
* [(SingleGrid method)](apis/space.html#mesa.space.SingleGrid.iter_neighborhood)
* [iter\_neighbors() (HexMultiGrid method)](apis/space.html#mesa.space.HexMultiGrid.iter_neighbors)
* [(HexSingleGrid method)](apis/space.html#mesa.space.HexSingleGrid.iter_neighbors)
* [(MultiGrid method)](apis/space.html#mesa.space.MultiGrid.iter_neighbors)
, [\[1\]](mesa.html#mesa.space.MultiGrid.iter_neighbors)
* [(SingleGrid method)](apis/space.html#mesa.space.SingleGrid.iter_neighbors) |
L
-
| | |
| --- | --- |
| * [locals\_dict (ConsoleManager attribute)](apis/visualization.html#mesa.visualization.command_console.ConsoleManager.locals_dict) | * [log\_to\_stderr() (in module mesa.mesa\_logging)](apis/mesa_logging.html#mesa.mesa_logging.log_to_stderr) |
M
-
| | |
| --- | --- |
| * [make\_altair\_space() (in module mesa.visualization.components.altair\_components)](apis/visualization.html#mesa.visualization.components.altair_components.make_altair_space)
* [make\_initial\_grid\_layout() (in module mesa.visualization.solara\_viz)](apis/visualization.html#mesa.visualization.solara_viz.make_initial_grid_layout)
* [make\_mpl\_plot\_component() (in module mesa.visualization.components.matplotlib\_components)](apis/visualization.html#mesa.visualization.components.matplotlib_components.make_mpl_plot_component)
* [make\_mpl\_space\_component() (in module mesa.visualization.components.matplotlib\_components)](apis/visualization.html#mesa.visualization.components.matplotlib_components.make_mpl_space_component)
* [make\_plot\_component() (in module mesa.visualization.components.\_\_init\_\_)](apis/visualization.html#mesa.visualization.components.__init__.make_plot_component)
* [make\_plot\_measure() (in module mesa.visualization.components.matplotlib\_components)](apis/visualization.html#mesa.visualization.components.matplotlib_components.make_plot_measure)
* [make\_space\_altair() (in module mesa.visualization.components.altair\_components)](apis/visualization.html#mesa.visualization.components.altair_components.make_space_altair)
* [make\_space\_component() (in module mesa.visualization.components.\_\_init\_\_)](apis/visualization.html#mesa.visualization.components.__init__.make_space_component)
* [make\_space\_matplotlib() (in module mesa.visualization.components.matplotlib\_components)](apis/visualization.html#mesa.visualization.components.matplotlib_components.make_space_matplotlib)
* [map() (AgentSet method)](apis/agent.html#mesa.agent.AgentSet.map)
, [\[1\]](mesa.html#mesa.agent.AgentSet.map)
* [(GroupBy method)](apis/agent.html#mesa.agent.GroupBy.map)
, [\[1\]](mesa.html#mesa.agent.GroupBy.map)
* [maybe\_raise\_error() (UserParam method)](apis/visualization.html#mesa.visualization.user_param.UserParam.maybe_raise_error)
* mesa
* [module](mesa.html#module-mesa)
* mesa.agent
* [module](apis/agent.html#module-mesa.agent)
, [\[1\]](mesa.html#module-mesa.agent)
* mesa.batchrunner
* [module](mesa.html#module-mesa.batchrunner)
* mesa.datacollection
* [module](mesa.html#module-mesa.datacollection)
* mesa.discrete\_space.\_\_init\_\_
* [module](apis/discrete_space.html#module-mesa.discrete_space.__init__)
* mesa.discrete\_space.cell
* [module](apis/discrete_space.html#module-mesa.discrete_space.cell)
* mesa.discrete\_space.cell\_agent
* [module](apis/discrete_space.html#module-mesa.discrete_space.cell_agent)
* mesa.discrete\_space.cell\_collection
* [module](apis/discrete_space.html#module-mesa.discrete_space.cell_collection)
* mesa.discrete\_space.discrete\_space
* [module](apis/discrete_space.html#module-mesa.discrete_space.discrete_space)
* mesa.discrete\_space.grid
* [module](apis/discrete_space.html#module-mesa.discrete_space.grid)
* mesa.discrete\_space.network
* [module](apis/discrete_space.html#module-mesa.discrete_space.network)
* mesa.discrete\_space.voronoi
* [module](apis/discrete_space.html#module-mesa.discrete_space.voronoi)
* mesa.mesa\_logging
* [module](apis/mesa_logging.html#module-mesa.mesa_logging)
* mesa.model
* [module](apis/model.html#module-mesa.model)
, [\[1\]](mesa.html#module-mesa.model)
* mesa.space
* [module](apis/space.html#module-mesa.space)
, [\[1\]](mesa.html#module-mesa.space)
* mesa.visualization.command\_console
* [module](apis/visualization.html#module-mesa.visualization.command_console)
* mesa.visualization.components.\_\_init\_\_
* [module](apis/visualization.html#module-mesa.visualization.components.__init__)
* mesa.visualization.components.altair\_components
* [module](apis/visualization.html#module-mesa.visualization.components.altair_components)
* mesa.visualization.components.matplotlib\_components
* [module](apis/visualization.html#module-mesa.visualization.components.matplotlib_components)
* mesa.visualization.mpl\_space\_drawing
* [module](apis/visualization.html#module-mesa.visualization.mpl_space_drawing)
* mesa.visualization.solara\_viz
* [module](apis/visualization.html#module-mesa.visualization.solara_viz)
* mesa.visualization.user\_param
* [module](apis/visualization.html#module-mesa.visualization.user_param) | * [method\_logger() (in module mesa.mesa\_logging)](apis/mesa_logging.html#mesa.mesa_logging.method_logger)
* [model (Agent attribute)](apis/agent.html#mesa.agent.Agent.model)
, [\[1\]](mesa.html#mesa.Agent.model)
, [\[2\]](mesa.html#mesa.agent.Agent.model)
* [(AgentSet attribute)](apis/agent.html#mesa.agent.AgentSet.model)
, [\[1\]](mesa.html#mesa.agent.AgentSet.model)
* [Model (class in mesa)](mesa.html#mesa.Model)
* [(class in mesa.model)](apis/model.html#mesa.model.Model)
, [\[1\]](mesa.html#mesa.model.Model)
* [model (Simulator attribute)](apis/experimental.html#experimental.devs.simulator.Simulator.model)
* [modify\_cell() (PropertyLayer method)](apis/space.html#mesa.space.PropertyLayer.modify_cell)
, [\[1\]](mesa.html#mesa.space.PropertyLayer.modify_cell)
* [modify\_cells() (PropertyLayer method)](apis/discrete_space.html#mesa.discrete_space.__init__.PropertyLayer.modify_cells)
, [\[1\]](apis/space.html#mesa.space.PropertyLayer.modify_cells)
, [\[2\]](mesa.html#mesa.space.PropertyLayer.modify_cells)
* module
* [batchrunner](apis/batchrunner.html#module-batchrunner)
* [datacollection](apis/datacollection.html#module-datacollection)
* [experimental.continuous\_space.continuous\_space](apis/experimental.html#module-experimental.continuous_space.continuous_space)
* [experimental.continuous\_space.continuous\_space\_agents](apis/experimental.html#module-experimental.continuous_space.continuous_space_agents)
* [experimental.devs.eventlist](apis/experimental.html#module-experimental.devs.eventlist)
* [experimental.devs.simulator](apis/experimental.html#module-experimental.devs.simulator)
* [mesa](mesa.html#module-mesa)
* [mesa.agent](apis/agent.html#module-mesa.agent)
, [\[1\]](mesa.html#module-mesa.agent)
* [mesa.batchrunner](mesa.html#module-mesa.batchrunner)
* [mesa.datacollection](mesa.html#module-mesa.datacollection)
* [mesa.discrete\_space.\_\_init\_\_](apis/discrete_space.html#module-mesa.discrete_space.__init__)
* [mesa.discrete\_space.cell](apis/discrete_space.html#module-mesa.discrete_space.cell)
* [mesa.discrete\_space.cell\_agent](apis/discrete_space.html#module-mesa.discrete_space.cell_agent)
* [mesa.discrete\_space.cell\_collection](apis/discrete_space.html#module-mesa.discrete_space.cell_collection)
* [mesa.discrete\_space.discrete\_space](apis/discrete_space.html#module-mesa.discrete_space.discrete_space)
* [mesa.discrete\_space.grid](apis/discrete_space.html#module-mesa.discrete_space.grid)
* [mesa.discrete\_space.network](apis/discrete_space.html#module-mesa.discrete_space.network)
* [mesa.discrete\_space.voronoi](apis/discrete_space.html#module-mesa.discrete_space.voronoi)
* [mesa.mesa\_logging](apis/mesa_logging.html#module-mesa.mesa_logging)
* [mesa.model](apis/model.html#module-mesa.model)
, [\[1\]](mesa.html#module-mesa.model)
* [mesa.space](apis/space.html#module-mesa.space)
, [\[1\]](mesa.html#module-mesa.space)
* [mesa.visualization.command\_console](apis/visualization.html#module-mesa.visualization.command_console)
* [mesa.visualization.components.\_\_init\_\_](apis/visualization.html#module-mesa.visualization.components.__init__)
* [mesa.visualization.components.altair\_components](apis/visualization.html#module-mesa.visualization.components.altair_components)
* [mesa.visualization.components.matplotlib\_components](apis/visualization.html#module-mesa.visualization.components.matplotlib_components)
* [mesa.visualization.mpl\_space\_drawing](apis/visualization.html#module-mesa.visualization.mpl_space_drawing)
* [mesa.visualization.solara\_viz](apis/visualization.html#module-mesa.visualization.solara_viz)
* [mesa.visualization.user\_param](apis/visualization.html#module-mesa.visualization.user_param)
* [move() (Grid2DMovingAgent method)](apis/discrete_space.html#mesa.discrete_space.__init__.Grid2DMovingAgent.move)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell_agent.Grid2DMovingAgent.move)
* [move\_agent() (ContinuousSpace method)](apis/space.html#mesa.space.ContinuousSpace.move_agent)
, [\[1\]](mesa.html#mesa.space.ContinuousSpace.move_agent)
* [(HexMultiGrid method)](apis/space.html#mesa.space.HexMultiGrid.move_agent)
* [(HexSingleGrid method)](apis/space.html#mesa.space.HexSingleGrid.move_agent)
* [(MultiGrid method)](apis/space.html#mesa.space.MultiGrid.move_agent)
* [(NetworkGrid method)](apis/space.html#mesa.space.NetworkGrid.move_agent)
, [\[1\]](mesa.html#mesa.space.NetworkGrid.move_agent)
* [(SingleGrid method)](apis/space.html#mesa.space.SingleGrid.move_agent)
* [move\_agent\_to\_one\_of() (HexMultiGrid method)](apis/space.html#mesa.space.HexMultiGrid.move_agent_to_one_of)
* [(HexSingleGrid method)](apis/space.html#mesa.space.HexSingleGrid.move_agent_to_one_of)
* [(MultiGrid method)](apis/space.html#mesa.space.MultiGrid.move_agent_to_one_of)
* [(SingleGrid method)](apis/space.html#mesa.space.SingleGrid.move_agent_to_one_of)
* [move\_relative() (BasicMovement method)](apis/discrete_space.html#mesa.discrete_space.cell_agent.BasicMovement.move_relative)
* [move\_to() (BasicMovement method)](apis/discrete_space.html#mesa.discrete_space.cell_agent.BasicMovement.move_to)
* [move\_to\_empty() (HexMultiGrid method)](apis/space.html#mesa.space.HexMultiGrid.move_to_empty)
* [(HexSingleGrid method)](apis/space.html#mesa.space.HexSingleGrid.move_to_empty)
* [(MultiGrid method)](apis/space.html#mesa.space.MultiGrid.move_to_empty)
* [(SingleGrid method)](apis/space.html#mesa.space.SingleGrid.move_to_empty)
* [MultiGrid (class in mesa.space)](apis/space.html#mesa.space.MultiGrid)
, [\[1\]](mesa.html#mesa.space.MultiGrid) |
N
-
| | |
| --- | --- |
| * [name (PropertyLayer attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.PropertyLayer.name)
, [\[1\]](apis/space.html#mesa.space.PropertyLayer.name)
, [\[2\]](mesa.html#mesa.space.PropertyLayer.name)
* [neighborhood (Cell property)](apis/discrete_space.html#mesa.discrete_space.__init__.Cell.neighborhood)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell.Cell.neighborhood)
* [Network (class in mesa.discrete\_space.\_\_init\_\_)](apis/discrete_space.html#mesa.discrete_space.__init__.Network)
* [(class in mesa.discrete\_space.network)](apis/discrete_space.html#mesa.discrete_space.network.Network) | * [NetworkGrid (class in mesa.space)](apis/space.html#mesa.space.NetworkGrid)
, [\[1\]](mesa.html#mesa.space.NetworkGrid)
* [next\_command() (ConsoleManager method)](apis/visualization.html#mesa.visualization.command_console.ConsoleManager.next_command) |
O
-
| | |
| --- | --- |
| * [OrthogonalMooreGrid (class in mesa.discrete\_space.\_\_init\_\_)](apis/discrete_space.html#mesa.discrete_space.__init__.OrthogonalMooreGrid)
* [(class in mesa.discrete\_space.grid)](apis/discrete_space.html#mesa.discrete_space.grid.OrthogonalMooreGrid)
* [OrthogonalVonNeumannGrid (class in mesa.discrete\_space.\_\_init\_\_)](apis/discrete_space.html#mesa.discrete_space.__init__.OrthogonalVonNeumannGrid)
* [(class in mesa.discrete\_space.grid)](apis/discrete_space.html#mesa.discrete_space.grid.OrthogonalVonNeumannGrid)
* [out\_of\_bounds() (ContinuousSpace method)](apis/space.html#mesa.space.ContinuousSpace.out_of_bounds)
, [\[1\]](mesa.html#mesa.space.ContinuousSpace.out_of_bounds)
* [(HexMultiGrid method)](apis/space.html#mesa.space.HexMultiGrid.out_of_bounds)
* [(HexSingleGrid method)](apis/space.html#mesa.space.HexSingleGrid.out_of_bounds)
* [(MultiGrid method)](apis/space.html#mesa.space.MultiGrid.out_of_bounds)
* [(SingleGrid method)](apis/space.html#mesa.space.SingleGrid.out_of_bounds) | * [output (ConsoleEntry attribute)](apis/visualization.html#id1)
, [\[1\]](apis/visualization.html#mesa.visualization.command_console.ConsoleEntry.output) |
P
-
| | |
| --- | --- |
| * [peak\_ahead() (EventList method)](apis/experimental.html#experimental.devs.eventlist.EventList.peak_ahead)
* [pickle\_gridcell() (in module mesa.discrete\_space.grid)](apis/discrete_space.html#mesa.discrete_space.grid.pickle_gridcell)
* [place\_agent() (ContinuousSpace method)](mesa.html#mesa.space.ContinuousSpace.place_agent)
* [(MultiGrid method)](mesa.html#mesa.space.MultiGrid.place_agent)
* [(NetworkGrid method)](mesa.html#mesa.space.NetworkGrid.place_agent)
* [(SingleGrid method)](mesa.html#mesa.space.SingleGrid.place_agent)
* [pop() (AgentSet method)](apis/agent.html#mesa.agent.AgentSet.pop)
* [pop\_event() (EventList method)](apis/experimental.html#experimental.devs.eventlist.EventList.pop_event)
* [pos (Agent attribute)](apis/agent.html#mesa.agent.Agent.pos)
, [\[1\]](mesa.html#mesa.Agent.pos)
, [\[2\]](mesa.html#mesa.agent.Agent.pos) | * [position (ContinuousSpaceAgent attribute)](apis/experimental.html#experimental.continuous_space.continuous_space_agents.ContinuousSpaceAgent.position)
* [(ContinuousSpaceAgent property)](apis/experimental.html#id0)
* [prev\_command() (ConsoleManager method)](apis/visualization.html#mesa.visualization.command_console.ConsoleManager.prev_command)
* [Priority (class in experimental.devs.eventlist)](apis/experimental.html#experimental.devs.eventlist.Priority)
* [priority (SimulationEvent attribute)](apis/experimental.html#experimental.devs.eventlist.SimulationEvent.priority)
* [property\_layers (DiscreteSpace attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.DiscreteSpace.property_layers)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.discrete_space.DiscreteSpace.property_layers)
* [PropertyLayer (class in mesa.discrete\_space.\_\_init\_\_)](apis/discrete_space.html#mesa.discrete_space.__init__.PropertyLayer)
* [(class in mesa.space)](apis/space.html#mesa.space.PropertyLayer)
, [\[1\]](mesa.html#mesa.space.PropertyLayer)
* [push() (InteractiveConsole method)](apis/visualization.html#mesa.visualization.command_console.InteractiveConsole.push) |
R
-
| | |
| --- | --- |
| * [random (Agent property)](apis/agent.html#mesa.agent.Agent.random)
, [\[1\]](mesa.html#mesa.Agent.random)
, [\[2\]](mesa.html#mesa.agent.Agent.random)
* [(Cell attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.Cell.random)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell.Cell.random)
* [(CellCollection attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.CellCollection.random)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell_collection.CellCollection.random)
* [(DiscreteSpace attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.DiscreteSpace.random)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.discrete_space.DiscreteSpace.random)
* [(Grid attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.Grid.random)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.grid.Grid.random)
* [(Model attribute)](apis/model.html#mesa.model.Model.random)
, [\[1\]](mesa.html#mesa.Model.random)
, [\[2\]](mesa.html#mesa.model.Model.random)
* [register\_agent() (Model method)](apis/model.html#mesa.model.Model.register_agent)
, [\[1\]](mesa.html#mesa.Model.register_agent)
, [\[2\]](mesa.html#mesa.model.Model.register_agent)
* [remove() (Agent method)](apis/agent.html#mesa.agent.Agent.remove)
, [\[1\]](mesa.html#mesa.Agent.remove)
, [\[2\]](mesa.html#mesa.agent.Agent.remove)
* [(AgentSet method)](apis/agent.html#mesa.agent.AgentSet.remove)
, [\[1\]](mesa.html#mesa.agent.AgentSet.remove)
* [(CellAgent method)](apis/discrete_space.html#mesa.discrete_space.__init__.CellAgent.remove)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell_agent.CellAgent.remove)
* [(ContinuousSpaceAgent method)](apis/experimental.html#experimental.continuous_space.continuous_space_agents.ContinuousSpaceAgent.remove)
* [(EventList method)](apis/experimental.html#experimental.devs.eventlist.EventList.remove)
* [(FixedAgent method)](apis/discrete_space.html#mesa.discrete_space.__init__.FixedAgent.remove)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell_agent.FixedAgent.remove)
* [remove\_agent() (Cell method)](apis/discrete_space.html#mesa.discrete_space.__init__.Cell.remove_agent)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell.Cell.remove_agent)
* [(ContinuousSpace method)](apis/space.html#mesa.space.ContinuousSpace.remove_agent)
, [\[1\]](mesa.html#mesa.space.ContinuousSpace.remove_agent)
* [(HexMultiGrid method)](apis/space.html#mesa.space.HexMultiGrid.remove_agent)
* [(HexSingleGrid method)](apis/space.html#mesa.space.HexSingleGrid.remove_agent)
* [(MultiGrid method)](apis/space.html#mesa.space.MultiGrid.remove_agent)
, [\[1\]](mesa.html#mesa.space.MultiGrid.remove_agent)
* [(NetworkGrid method)](apis/space.html#mesa.space.NetworkGrid.remove_agent)
, [\[1\]](mesa.html#mesa.space.NetworkGrid.remove_agent)
* [(SingleGrid method)](apis/space.html#mesa.space.SingleGrid.remove_agent)
, [\[1\]](mesa.html#mesa.space.SingleGrid.remove_agent) | * [remove\_all\_agents() (Model method)](apis/model.html#mesa.model.Model.remove_all_agents)
, [\[1\]](mesa.html#mesa.Model.remove_all_agents)
, [\[2\]](mesa.html#mesa.model.Model.remove_all_agents)
* [remove\_property\_layer() (HexMultiGrid method)](apis/space.html#mesa.space.HexMultiGrid.remove_property_layer)
* [(HexSingleGrid method)](apis/space.html#mesa.space.HexSingleGrid.remove_property_layer)
* [(MultiGrid method)](apis/space.html#mesa.space.MultiGrid.remove_property_layer)
* [(SingleGrid method)](apis/space.html#mesa.space.SingleGrid.remove_property_layer)
* [reset() (Simulator method)](apis/experimental.html#experimental.devs.simulator.Simulator.reset)
* [reset\_randomizer() (Model method)](apis/model.html#mesa.model.Model.reset_randomizer)
, [\[1\]](mesa.html#mesa.Model.reset_randomizer)
, [\[2\]](mesa.html#mesa.model.Model.reset_randomizer)
* [reset\_rng() (Model method)](apis/model.html#mesa.model.Model.reset_rng)
, [\[1\]](mesa.html#mesa.Model.reset_rng)
, [\[2\]](mesa.html#mesa.model.Model.reset_rng)
* [rng (Agent property)](apis/agent.html#mesa.agent.Agent.rng)
, [\[1\]](mesa.html#mesa.Agent.rng)
, [\[2\]](mesa.html#mesa.agent.Agent.rng)
* [(Model attribute)](apis/model.html#mesa.model.Model.rng)
, [\[1\]](mesa.html#mesa.Model.rng)
, [\[2\]](mesa.html#mesa.model.Model.rng)
* [run\_for() (Simulator method)](apis/experimental.html#experimental.devs.simulator.Simulator.run_for)
* [run\_model() (Model method)](apis/model.html#mesa.model.Model.run_model)
, [\[1\]](mesa.html#mesa.Model.run_model)
, [\[2\]](mesa.html#mesa.model.Model.run_model)
* [run\_next\_event() (Simulator method)](apis/experimental.html#experimental.devs.simulator.Simulator.run_next_event)
* [run\_until() (ABMSimulator method)](apis/experimental.html#experimental.devs.simulator.ABMSimulator.run_until)
* [(Simulator method)](apis/experimental.html#experimental.devs.simulator.Simulator.run_until)
* [running (Model attribute)](apis/model.html#mesa.model.Model.running)
, [\[1\]](mesa.html#mesa.Model.running)
, [\[2\]](mesa.html#mesa.model.Model.running) |
S
-
| | |
| --- | --- |
| * [schedule\_event\_absolute() (Simulator method)](apis/experimental.html#experimental.devs.simulator.Simulator.schedule_event_absolute)
* [schedule\_event\_next\_tick() (ABMSimulator method)](apis/experimental.html#experimental.devs.simulator.ABMSimulator.schedule_event_next_tick)
* [schedule\_event\_now() (Simulator method)](apis/experimental.html#experimental.devs.simulator.Simulator.schedule_event_now)
* [schedule\_event\_relative() (Simulator method)](apis/experimental.html#experimental.devs.simulator.Simulator.schedule_event_relative)
* [select() (AgentSet method)](apis/agent.html#mesa.agent.AgentSet.select)
, [\[1\]](mesa.html#mesa.agent.AgentSet.select)
* [(CellCollection method)](apis/discrete_space.html#mesa.discrete_space.__init__.CellCollection.select)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell_collection.CellCollection.select)
* [select\_cells() (HexMultiGrid method)](apis/space.html#mesa.space.HexMultiGrid.select_cells)
* [(HexSingleGrid method)](apis/space.html#mesa.space.HexSingleGrid.select_cells)
* [(MultiGrid method)](apis/space.html#mesa.space.MultiGrid.select_cells)
* [(PropertyLayer method)](apis/discrete_space.html#mesa.discrete_space.__init__.PropertyLayer.select_cells)
, [\[1\]](apis/space.html#mesa.space.PropertyLayer.select_cells)
, [\[2\]](mesa.html#mesa.space.PropertyLayer.select_cells)
* [(SingleGrid method)](apis/space.html#mesa.space.SingleGrid.select_cells)
* [select\_random\_agent() (CellCollection method)](apis/discrete_space.html#mesa.discrete_space.__init__.CellCollection.select_random_agent)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell_collection.CellCollection.select_random_agent)
* [select\_random\_cell() (CellCollection method)](apis/discrete_space.html#mesa.discrete_space.__init__.CellCollection.select_random_cell)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.cell_collection.CellCollection.select_random_cell)
* [select\_random\_empty\_cell() (DiscreteSpace method)](apis/discrete_space.html#mesa.discrete_space.__init__.DiscreteSpace.select_random_empty_cell)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.discrete_space.DiscreteSpace.select_random_empty_cell)
* [(Grid method)](apis/discrete_space.html#mesa.discrete_space.__init__.Grid.select_random_empty_cell)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.grid.Grid.select_random_empty_cell)
* [set() (AgentSet method)](apis/agent.html#mesa.agent.AgentSet.set)
, [\[1\]](mesa.html#mesa.agent.AgentSet.set)
* [set\_cell() (PropertyLayer method)](apis/space.html#mesa.space.PropertyLayer.set_cell)
, [\[1\]](mesa.html#mesa.space.PropertyLayer.set_cell)
* [set\_cells() (PropertyLayer method)](apis/discrete_space.html#mesa.discrete_space.__init__.PropertyLayer.set_cells)
, [\[1\]](apis/space.html#mesa.space.PropertyLayer.set_cells)
, [\[2\]](mesa.html#mesa.space.PropertyLayer.set_cells) | * [setup() (ABMSimulator method)](apis/experimental.html#experimental.devs.simulator.ABMSimulator.setup)
* [(Simulator method)](apis/experimental.html#experimental.devs.simulator.Simulator.setup)
* [shuffle() (AgentSet method)](apis/agent.html#mesa.agent.AgentSet.shuffle)
, [\[1\]](mesa.html#mesa.agent.AgentSet.shuffle)
* [shuffle\_do() (AgentSet method)](apis/agent.html#mesa.agent.AgentSet.shuffle_do)
, [\[1\]](mesa.html#mesa.agent.AgentSet.shuffle_do)
* [SimulationEvent (class in experimental.devs.eventlist)](apis/experimental.html#experimental.devs.eventlist.SimulationEvent)
* [Simulator (class in experimental.devs.simulator)](apis/experimental.html#experimental.devs.simulator.Simulator)
* [SingleGrid (class in mesa.space)](apis/space.html#mesa.space.SingleGrid)
, [\[1\]](mesa.html#mesa.space.SingleGrid)
* [Slider (class in mesa.visualization.user\_param)](apis/visualization.html#mesa.visualization.user_param.Slider)
* [sort() (AgentSet method)](apis/agent.html#mesa.agent.AgentSet.sort)
, [\[1\]](mesa.html#mesa.agent.AgentSet.sort)
* [space (ContinuousSpaceAgent attribute)](apis/experimental.html#experimental.continuous_space.continuous_space_agents.ContinuousSpaceAgent.space)
* [split\_model\_params() (in module mesa.visualization.solara\_viz)](apis/visualization.html#mesa.visualization.solara_viz.split_model_params)
* [step() (Agent method)](apis/agent.html#mesa.agent.Agent.step)
, [\[1\]](mesa.html#mesa.Agent.step)
, [\[2\]](mesa.html#mesa.agent.Agent.step)
* [(Model method)](apis/model.html#mesa.model.Model.step)
, [\[1\]](mesa.html#mesa.Model.step)
, [\[2\]](mesa.html#mesa.model.Model.step)
* [steps (Model attribute)](apis/model.html#mesa.model.Model.steps)
, [\[1\]](mesa.html#mesa.Model.steps)
, [\[2\]](mesa.html#mesa.model.Model.steps)
* [swap\_pos() (HexMultiGrid method)](apis/space.html#mesa.space.HexMultiGrid.swap_pos)
* [(HexSingleGrid method)](apis/space.html#mesa.space.HexSingleGrid.swap_pos)
* [(MultiGrid method)](apis/space.html#mesa.space.MultiGrid.swap_pos)
* [(SingleGrid method)](apis/space.html#mesa.space.SingleGrid.swap_pos) |
T
-
| | |
| --- | --- |
| * [time (SimulationEvent attribute)](apis/experimental.html#experimental.devs.eventlist.SimulationEvent.time)
* [(Simulator attribute)](apis/experimental.html#experimental.devs.simulator.Simulator.time)
* [time\_unit (Simulator attribute)](apis/experimental.html#experimental.devs.simulator.Simulator.time_unit)
* [torus (Grid attribute)](apis/discrete_space.html#mesa.discrete_space.__init__.Grid.torus)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.grid.Grid.torus)
* [torus\_adj() (ContinuousSpace method)](apis/space.html#mesa.space.ContinuousSpace.torus_adj)
, [\[1\]](mesa.html#mesa.space.ContinuousSpace.torus_adj)
* [(HexMultiGrid method)](apis/space.html#mesa.space.HexMultiGrid.torus_adj)
* [(HexSingleGrid method)](apis/space.html#mesa.space.HexSingleGrid.torus_adj)
* [(MultiGrid method)](apis/space.html#mesa.space.MultiGrid.torus_adj)
* [(SingleGrid method)](apis/space.html#mesa.space.SingleGrid.torus_adj) | * [torus\_correct() (ContinuousSpace method)](apis/experimental.html#experimental.continuous_space.continuous_space.ContinuousSpace.torus_correct) |
U
-
| | |
| --- | --- |
| * [ufunc\_requires\_additional\_input() (in module mesa.space)](mesa.html#mesa.space.ufunc_requires_additional_input)
* [unique\_id (Agent attribute)](apis/agent.html#mesa.agent.Agent.unique_id)
, [\[1\]](mesa.html#mesa.Agent.unique_id)
, [\[2\]](mesa.html#mesa.agent.Agent.unique_id)
* [(SimulationEvent attribute)](apis/experimental.html#experimental.devs.eventlist.SimulationEvent.unique_id) | * [unpickle\_gridcell() (in module mesa.discrete\_space.grid)](apis/discrete_space.html#mesa.discrete_space.grid.unpickle_gridcell)
* [UserParam (class in mesa.visualization.user\_param)](apis/visualization.html#mesa.visualization.user_param.UserParam) |
V
-
* [VoronoiGrid (class in mesa.discrete\_space.\_\_init\_\_)](apis/discrete_space.html#mesa.discrete_space.__init__.VoronoiGrid)
* [(class in mesa.discrete\_space.voronoi)](apis/discrete_space.html#mesa.discrete_space.voronoi.VoronoiGrid)
W
-
| | |
| --- | --- |
| * [warn\_if\_agent\_has\_position\_already() (in module mesa.space)](apis/space.html#mesa.space.warn_if_agent_has_position_already)
, [\[1\]](mesa.html#mesa.space.warn_if_agent_has_position_already) | * [width (Grid property)](apis/discrete_space.html#mesa.discrete_space.__init__.Grid.width)
, [\[1\]](apis/discrete_space.html#mesa.discrete_space.grid.Grid.width)
* [(PropertyLayer attribute)](apis/space.html#mesa.space.PropertyLayer.width)
, [\[1\]](mesa.html#mesa.space.PropertyLayer.width) |
---
# Unknown
{ "cells": \[ { "cell\_type": "markdown", "metadata": {}, "source": \[ "# Collecting Data\\n", "\\n", "### The Boltzmann Wealth Model " \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "If you want to get straight to the tutorial checkout these environment providers: \
\\n", "(with Google Account) \[!\[Colab\](https://colab.research.google.com/assets/colab-badge.svg)\](https://colab.research.google.com/github/projectmesa/mesa/blob/main/docs/tutorials/2\_collecting\_data.ipynb) \
\\n", "(No Google Account) \[!\[Binder\](https://mybinder.org/badge\_logo.svg)\](https://mybinder.org/v2/gh/projectmesa/mesa/main?labpath=docs%2Ftutorials%2F2\_collecting\_data.ipynb) (This can take 30 seconds to 5 minutes to load)\\n", "\\n", "\*If you are running locally, please ensure you have the latest Mesa version installed.\*\\n", "\\n", "## Tutorial Description\\n", "\\n", "This tutorial extends the Boltzmann wealth model from the \[Adding Space tutorial\](https://mesa.readthedocs.io/latest/tutorials/1\_adding\_space.html), by adding Mesa's data collection module. \\n", "\\n", "In this portion, we will collect both model level data and agent level data to better understand the dynamics of our model. \\n", "\\n", "\*If you are starting here please see the \[Running Your First Model tutorial\](https://mesa.readthedocs.io/latest/tutorials/0\_first\_model.html) for dependency and start-up instructions\*" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### IN COLAB? - Run the next cell " \] }, { "cell\_type": "raw", "metadata": { "vscode": { "languageId": "raw" } }, "source": \[ "%pip install --quiet mesa\[rec\]" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Import Dependencies\\n", "This includes importing of dependencies needed for the tutorial." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "outputs": \[\], "source": \[ "# Has multi-dimensional arrays and matrices.\\n", "# Has a large collection of mathematical functions to operate on these arrays.\\n", "import numpy as np\\n", "\\n", "# Data manipulation and analysis.\\n", "import pandas as pd\\n", "\\n", "# Data visualization tools.\\n", "import seaborn as sns\\n", "\\n", "import mesa\\n", "\\n", "# Import Cell Agent and OrthogonalMooreGrid\\n", "from mesa.discrete\_space import CellAgent, OrthogonalMooreGrid" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Base Model\\n", "\\n", "The below provides the base model from which we will add our space functionality. \\n", "\\n", "This is from the \[Adding Space tutorial\](https://mesa.readthedocs.io/latest/tutorials/1\_adding\_space.html) tutorial. If you have any questions about it functionality please review that tutorial." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "class MoneyAgent(CellAgent):\\n", " \\"\\"\\"An agent with fixed initial wealth.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, model, cell):\\n", " super().\_\_init\_\_(model)\\n", " self.cell = cell # Instantiate agent with location (x,y)\\n", " self.wealth = 1\\n", "\\n", " # Move Function\\n", " def move(self):\\n", " self.cell = self.cell.neighborhood.select\_random\_cell()\\n", "\\n", " def give\_money(self):\\n", " cellmates = \[\\n", " a for a in self.cell.agents if a is not self\\n", " \] # Get all agents in cell\\n", "\\n", " if self.wealth > 0 and cellmates:\\n", " other\_agent = self.random.choice(cellmates)\\n", " other\_agent.wealth += 1\\n", " self.wealth -= 1\\n", "\\n", "\\n", "class MoneyModel(mesa.Model):\\n", " \\"\\"\\"A model with some number of agents.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, n, width, height, seed=None):\\n", " super().\_\_init\_\_(seed=seed)\\n", " self.num\_agents = n\\n", " # Instantiate an instance of Moore neighborhood space\\n", " self.grid = OrthogonalMooreGrid(\\n", " (width, height), torus=True, capacity=10, random=self.random\\n", " )\\n", "\\n", " # Create agents\\n", " agents = MoneyAgent.create\_agents(\\n", " self,\\n", " self.num\_agents,\\n", " # Randomly select agents cell\\n", " self.random.choices(self.grid.all\_cells.cells, k=self.num\_agents),\\n", " )\\n", "\\n", " def step(self):\\n", " self.agents.shuffle\_do(\\"move\\")\\n", " self.agents.do(\\"give\_money\\")" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "Let's create a model with 100 agents on a 10x10 grid, and run it for 20 steps to make sure our base model works." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "model = MoneyModel(100, 10, 10)\\n", "for \_ in range(20):\\n", " model.step()\\n", "# Let's make sure it worked\\n", "print(len(model.agents))" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Collecting Data\\n", "\\n", "\*\*Background:\*\* So far, at the end of every model run, we've had to go and write our own code to get the data out of the model. This has two problems: it isn't very efficient, and it only gives us end results. If we wanted to know the wealth of each agent at each step, we'd have to add that to the loop of executing steps, and figure out some way to store the data.\\n", "\\n", "Since one of the main goals of agent-based modeling is generating data for analysis, Mesa provides a class which can handle data collection and storage for us and make it easier to analyze.\\n", "\\n", "The data collector stores three categories of data: \\n", " - Model-level variables : Model-level collection functions take a model object as an input. Such as a function that computes a dynamic of the whole model (in this case we will compute a measure of wealth inequality based on all agent's wealth)\\n", " - Agent-level variables: Agent-level collection functions take an agent object as an input and is typically the state of an agent attributes, in this case wealth.\\n", " - Tables (which are a catch-all for everything else). \\n", "\\n", "\*\*Model-specific information:\*\* We will collect two variables to show Mesa capabilities. \\n", "- At the model level, let's measure the model's \[Gini Coefficient\](https://en.wikipedia.org/wiki/Gini\_coefficient), a measure of wealth inequality.\\n", "- At the agent level, we want to collect every agent's wealth at every step. " \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "\*\*Code implementation:\*\*\\n", "\\n", "Let's add a DataCollector to the model with \[\`mesa.DataCollector\`\](https://github.com/projectmesa/mesa/blob/main/mesa/datacollection.py), and collect the agent's wealth and the gini coefficient at each time step. In the below code each new line of code is described with a comment. These additions are described below. \\n", "\\n", "\*\*Helper Function\*\* \
\\n", "\\\\# Add function for model level collection\\n", "-\*Description:\* Helper function used by the model class to compute the gini coefficient as described previously. \\n", "-\*API:\* N/A\\n", "\\n", "\*\*MoneyModel Class\*\* \
\\n", "\\\\# Instantiate DataCollector\\n", "- \*Description:\* Create a mesa data collector instance and use keyword arguments (kwargs) \`model\_reporters\` and \`agent\_reporters\` to pass in a dictionary, where the key is the name of the data collected and the value is either function (i.e. computer gini) or an attribute (i.e. \\"wealth\\"). If it is an attribute it is passed in as a string. \\n", "- \*API:\* \[Data Collection\](https://mesa.readthedocs.io/latest/apis/datacollection.html)\\n", "\\n", "\\\\# Collect data each step\\n", "- \*Description:\* Call the \`collect\` method from \`DataCollector\`. This causes the reporters to collect the data at each step. If this is not put in the step function then the data collector will collect the described information at the end of the model run. If you want to collect the data only on lets say the 5th step, then you can just add an \`if\` statement to only collect on the fifth step.\\n", "- \*API:\* \[DataCollector.collect\](https://mesa.readthedocs.io/latest/apis/datacollection.html)" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "# Add function for model level collection\\n", "def compute\_gini(model):\\n", " agent\_wealths = \[agent.wealth for agent in model.agents\]\\n", " x = sorted(agent\_wealths)\\n", " n = model.num\_agents\\n", " B = sum(xi \* (n - i) for i, xi in enumerate(x)) / (n \* sum(x))\\n", " return 1 + (1 / n) - 2 \* B\\n", "\\n", "\\n", "class MoneyAgent(CellAgent):\\n", " \\"\\"\\"An agent with fixed initial wealth.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, model, cell):\\n", " super().\_\_init\_\_(model)\\n", " self.cell = cell\\n", " self.wealth = 1\\n", "\\n", " def move(self):\\n", " self.cell = self.cell.neighborhood.select\_random\_cell()\\n", "\\n", " def give\_money(self):\\n", " cellmates = \[a for a in self.cell.agents if a is not self\]\\n", "\\n", " if self.wealth > 0 and cellmates:\\n", " other\_agent = self.random.choice(cellmates)\\n", " other\_agent.wealth += 1\\n", " self.wealth -= 1\\n", "\\n", "\\n", "class MoneyModel(mesa.Model):\\n", " \\"\\"\\"A model with some number of agents.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, n, width, height, seed=None):\\n", " super().\_\_init\_\_(seed=seed)\\n", " self.num\_agents = n\\n", " self.grid = OrthogonalMooreGrid(\\n", " (width, height), torus=True, capacity=10, random=self.random\\n", " )\\n", " # Instantiate DataCollector\\n", " self.datacollector = mesa.DataCollector(\\n", " model\_reporters={\\"Gini\\": compute\_gini}, agent\_reporters={\\"Wealth\\": \\"wealth\\"}\\n", " )\\n", "\\n", " # Create agents\\n", " agents = MoneyAgent.create\_agents(\\n", " self,\\n", " self.num\_agents,\\n", " self.random.choices(self.grid.all\_cells.cells, k=self.num\_agents),\\n", " )\\n", "\\n", " def step(self):\\n", " # Collect data each step\\n", " self.datacollector.collect(self)\\n", " self.agents.shuffle\_do(\\"move\\")\\n", " self.agents.do(\\"give\_money\\")" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "At every step of the model, the datacollector will collect and store the model-level current Gini coefficient, as well as each agent's wealth, associating each with the current step.\\n", "\\n", "We run the model just as we did above. Now is when an interactive session, especially via a notebook, comes in handy: the DataCollector can export the data it has collected as a pandas\* DataFrame, for easy and interactive analysis. \\n", "\\n", "\*If you are new to Python, please be aware that pandas is already installed as a dependency of Mesa and that \[pandas\](https://pandas.pydata.org/docs/) is a \\"fast, powerful, flexible and easy to use open source data analysis and manipulation tool\\". Pandas is a great resource to help analyze the data collected in your models." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "model = MoneyModel(100, 10, 10)\\n", "for \_ in range(100):\\n", " model.step()" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Analyzing MoneyModel Data\\n", "\\n", "\*\*Code implementation:\*\*\\n", "\\n", "\\\\# Extract MoneyModel data in a Pandas dataframe\\n", "- \*Description:\* Call \`DataCollector.get\_model\_vars\_dataframe()\` method to get the model reporters (in this case gini coefficient) from the model object. We the use seaborn (sns) to do a line plot of the data of the model run. \\n", "- \*API:\* \[get\_model\_vars\_dataframe\](https://mesa.readthedocs.io/latest/apis/datacollection.html#datacollection.DataCollector.get\_model\_vars\_dataframe)" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "# Extract MoneyModel data in a Pandas dataframe\\n", "gini = model.datacollector.get\_model\_vars\_dataframe()\\n", "g = sns.lineplot(data=gini)\\n", "g.set(title=\\"Gini Coefficient over Time\\", ylabel=\\"Gini Coefficient\\");" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Exercises\\n", "- Display just the data to see the format\\n", "- Comment on the collect method on the step function and see the impact\\n", "- Increase agents and time to see how the plot changes" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Analyzing an MoneyAgent Data\\n", "\\n", "\*\*Code implementation:\*\*\\n", "\\n", "\\\\# Extract MoneyAgent data in a Pandas dataframe\\n", "- \*Description:\* Call \`DataCollector.get\_model\_agent\_dataframe()\` method to get the agent reporters (in this case agent wealth attribute) from the model object. \\n", "- \*API:\* \[get\_model\_agent\_dataframe\](https://mesa.readthedocs.io/latest/apis/datacollection.html#datacollection.DataCollector.get\_agent\_vars\_dataframe)" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "# Extract MoneyAgent data in a Pandas dataframe\\n", "agent\_wealth = model.datacollector.get\_agent\_vars\_dataframe()\\n", "agent\_wealth.head()" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "You'll see that the DataFrame's index is pairings of model step and agent ID. This is because the data collector stores the data in a dictionary, with the step number as the key, and a dictionary of agent ID and variable value pairs as the value. The data collector then converts this dictionary into a DataFrame, which is why the index is a pair of (model step, agent ID). You can analyze it the way you would any other DataFrame. For example, to get a histogram of agent wealth at the model's end.\\n", "\\n", "\*Note: As the following code is pandas and seaborn we do not provide explanatory text\*" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "last\_step = agent\_wealth.index.get\_level\_values(\\"Step\\").max() # Get the last step\\n", "end\_wealth = agent\_wealth.xs(last\_step, level=\\"Step\\")\[\\n", " \\"Wealth\\"\\n", "\] # Get the welath of each agentat the last step\\n", "# Create a histogram of wealth at the last step\\n", "g = sns.histplot(end\_wealth, discrete=True)\\n", "g.set(\\n", " title=\\"Distribution of wealth at the end of simulation\\",\\n", " xlabel=\\"Wealth\\",\\n", " ylabel=\\"number of agents\\",\\n", ");" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "Or to plot the wealth of a given agent (in this example, agent 7):" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "# Get the wealth of agent 7 over time\\n", "one\_agent\_wealth = agent\_wealth.xs(7, level=\\"AgentID\\")\\n", "\\n", "# Plot the wealth of agent 7 over time\\n", "g = sns.lineplot(data=one\_agent\_wealth, x=\\"Step\\", y=\\"Wealth\\")\\n", "g.set(title=\\"Wealth of agent 7 over time\\");" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "You can also plot a reporter of multiple agents over time." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "agent\_list = \[3, 14, 25\]\\n", "\\n", "# Get the wealth of multiple agents over time\\n", "multiple\_agents\_wealth = agent\_wealth\[\\n", " agent\_wealth.index.get\_level\_values(\\"AgentID\\").isin(agent\_list)\\n", "\]\\n", "# Plot the wealth of multiple agents over time\\n", "g = sns.lineplot(data=multiple\_agents\_wealth, x=\\"Step\\", y=\\"Wealth\\", hue=\\"AgentID\\")\\n", "g.set(title=\\"Wealth of agents 3, 14 and 25 over time\\");" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "We can also plot the average of all agents, with a 95% confidence interval for that average." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "# Transform the data to a long format\\n", "agent\_wealth\_long = agent\_wealth.T.unstack().reset\_index()\\n", "agent\_wealth\_long.columns = \[\\"Step\\", \\"AgentID\\", \\"Variable\\", \\"Value\\"\]\\n", "agent\_wealth\_long.head(3)\\n", "\\n", "# Plot the average wealth over time\\n", "g = sns.lineplot(data=agent\_wealth\_long, x=\\"Step\\", y=\\"Value\\", errorbar=(\\"ci\\", 95))\\n", "g.set(title=\\"Average wealth over time\\")" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "Which is exactly 1, as expected in this model, since each agent starts with one wealth unit, and each agent gives one wealth unit to another agent at each step." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "You can also use pandas to export the data to a CSV (comma separated value) file, which can be opened by any common spreadsheet application or opened by pandas.\\n", "\\n", "If you do not specify a file path, the file will be saved in the local directory. After you run the code below you will see two files appear (\*model\_data.csv\* and \*agent\_data.csv\*)" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "# save the model data (stored in the pandas gini object) to CSV\\n", "gini.to\_csv(\\"model\_data.csv\\")\\n", "\\n", "# save the agent data (stored in the pandas agent\_wealth object) to CSV\\n", "agent\_wealth.to\_csv(\\"agent\_data.csv\\")" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "# Challenge update the model, conduct a batch run with a parameter sweep,\\n", "# and visualize your results" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Next Steps\\n", "\\n", "Check out the \[Agent Management Through AgentSet tutorial\](https://mesa.readthedocs.io/latest/tutorials/3\_agentset.html) on effective ways to manage agents." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "\[Comer2014\] Comer, Kenneth W. “Who Goes First? An Examination of the Impact of Activation on Outcome Behavior in AgentBased Models.” George Mason University, 2014. http://mars.gmu.edu/bitstream/handle/1920/9070/Comer\_gmu\_0883E\_10539.pdf\\n", "\\n", "\[Dragulescu2002\] Drăgulescu, Adrian A., and Victor M. Yakovenko. “Statistical Mechanics of Money, Income, and Wealth: A Short Survey.” arXiv Preprint Cond-mat/0211175, 2002. http://arxiv.org/abs/cond-mat/0211175." \] } \], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display\_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language\_info": { "codemirror\_mode": { "name": "ipython", "version": 3 }, "file\_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert\_exporter": "python", "pygments\_lexer": "ipython3", "version": "3.12.5" }, "widgets": { "state": {}, "version": "1.1.2" } }, "nbformat": 4, "nbformat\_minor": 4 }
---
# Unknown
{ "cells": \[ { "cell\_type": "markdown", "metadata": {}, "source": \[ "# Visualization - Basic Dashboard\\n", "\\n", "### The Boltzmann Wealth Model " \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "If you want to get straight to the tutorial checkout these environment providers: \
\\n", "\[!\[Binder\](https://mybinder.org/badge\_logo.svg)\](https://mybinder.org/v2/gh/projectmesa/mesa/main?labpath=docs%2Ftutorials%2F4\_visualization\_basic.ipynb) (This can take 30 seconds to 5 minutes to load)\\n", "\\n", "Due to conflict with Colab and Solara there are no colab links for this tutorial\\n", "\\n", "\*If you are running locally, please ensure you have the latest Mesa version installed.\*\\n", "\\n", "## Tutorial Description\\n", "\\n", "This tutorial extends the Boltzmann wealth model from the \[AgentSet tutorial\](https://mesa.readthedocs.io/latest/tutorials/3\_agentset.html), by adding an interactive dashboard. \\n", "\\n", "In this portion, we will demonstrate how users can employ build a basic dashboard. This is part one of three part series on building interactive dashboards in Mesa. \\n", "\\n", "\*If you are starting here please see the \[Running Your First Model tutorial\](https://mesa.readthedocs.io/latest/tutorials/0\_first\_model.html) for dependency and start-up instructions\*" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Import Dependencies\\n", "This includes importing of dependencies needed for the tutorial." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "outputs": \[\], "source": \[ "# Has multi-dimensional arrays and matrices.\\n", "# Has a large collection of mathematical functions to operate on these arrays.\\n", "import numpy as np\\n", "\\n", "# Data manipulation and analysis.\\n", "import pandas as pd\\n", "\\n", "# Data visualization tools.\\n", "import seaborn as sns\\n", "\\n", "import mesa\\n", "from mesa.discrete\_space import CellAgent, OrthogonalMooreGrid\\n", "from mesa.visualization import SolaraViz, make\_plot\_component, make\_space\_component" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Basic Model\\n", "\\n", "The following is the basic model we will be using to build the dashboard. This is the same model seen in tutorials 0-3. " \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "def compute\_gini(model):\\n", " agent\_wealths = \[agent.wealth for agent in model.agents\]\\n", " x = sorted(agent\_wealths)\\n", " N = model.num\_agents\\n", " B = sum(xi \* (N - i) for i, xi in enumerate(x)) / (N \* sum(x))\\n", " return 1 + (1 / N) - 2 \* B\\n", "\\n", "\\n", "class MoneyAgent(CellAgent):\\n", " \\"\\"\\"An agent with fixed initial wealth.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, model, cell):\\n", " \\"\\"\\"initialize a MoneyAgent instance.\\n", "\\n", " Args:\\n", " model: A model instance\\n", " \\"\\"\\"\\n", " super().\_\_init\_\_(model)\\n", " self.cell = cell\\n", " self.wealth = 1\\n", "\\n", " def move(self):\\n", " \\"\\"\\"Move the agent to a random neighboring cell.\\"\\"\\"\\n", " self.cell = self.cell.neighborhood.select\_random\_cell()\\n", "\\n", " def give\_money(self):\\n", " \\"\\"\\"Give 1 unit of wealth to a random agent in the same cell.\\"\\"\\"\\n", " cellmates = \[a for a in self.cell.agents if a is not self\]\\n", "\\n", " if cellmates: # Only give money if there are other agents present\\n", " other = self.random.choice(cellmates)\\n", " other.wealth += 1\\n", " self.wealth -= 1\\n", "\\n", " def step(self):\\n", " \\"\\"\\"do one step of the agent.\\"\\"\\"\\n", " self.move()\\n", " if self.wealth > 0:\\n", " self.give\_money()\\n", "\\n", "\\n", "class MoneyModel(mesa.Model):\\n", " \\"\\"\\"A model with some number of agents.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, n=10, width=10, height=10, seed=None):\\n", " \\"\\"\\"Initialize a MoneyModel instance.\\n", "\\n", " Args:\\n", " N: The number of agents.\\n", " width: width of the grid.\\n", " height: Height of the grid.\\n", " \\"\\"\\"\\n", " super().\_\_init\_\_(seed=seed)\\n", " self.num\_agents = n\\n", " self.grid = OrthogonalMooreGrid((width, height), random=self.random)\\n", "\\n", " # Create agents\\n", " MoneyAgent.create\_agents(\\n", " self,\\n", " self.num\_agents,\\n", " self.random.choices(self.grid.all\_cells.cells, k=self.num\_agents),\\n", " )\\n", "\\n", " self.datacollector = mesa.DataCollector(\\n", " model\_reporters={\\"Gini\\": compute\_gini}, agent\_reporters={\\"Wealth\\": \\"wealth\\"}\\n", " )\\n", " self.datacollector.collect(self)\\n", "\\n", " def step(self):\\n", " \\"\\"\\"do one step of the model\\"\\"\\"\\n", " self.agents.shuffle\_do(\\"step\\")\\n", " self.datacollector.collect(self)" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "# Lets make sure the model works\\n", "model = MoneyModel(100, 10, 10)\\n", "for \_ in range(20):\\n", " model.step()\\n", "\\n", "\\n", "data = model.datacollector.get\_agent\_vars\_dataframe()\\n", "# Use seaborn\\n", "g = sns.histplot(data\[\\"Wealth\\"\], discrete=True)\\n", "g.set(title=\\"Wealth distribution\\", xlabel=\\"Wealth\\", ylabel=\\"number of agents\\");" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Adding visualization\\n", "\\n", "So far, we've built a model, run it, and analyzed some output afterwards. However, one of the advantages of agent-based models is that we can often watch them run step by step, potentially spotting unexpected patterns, behaviors or bugs, or developing new intuitions, hypotheses, or insights. Other times, watching a model run can explain it to an unfamiliar audience better than static explanations. Like many ABM frameworks, Mesa allows you to create an interactive visualization of the model. In this section we'll walk through creating a visualization using built-in components, and (for advanced users) how to create a new visualization element.\\n", "\\n", "First, a quick explanation of how Mesa's interactive visualization works. The visualization is done in a browser window or Jupyter instance, using the \[Solara\](https://solara.dev/) framework, a pure Python, React-style web framework. Running \`solara run app.py\` will launch a web server, which runs the model, and displays model detail at each step via a plotting library. Alternatively, you can execute everything inside a Jupyter instance and display it inline." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "#### Grid Visualization\\n", "\\n", "Mesa's grid visualizer works by looping over every cell in a grid, and generating a portrayal for every agent it finds. A portrayal is a dictionary (which can easily be turned into a JSON object) which tells Matplotlib the color and size of the scatterplot markers (each signifying an agent). The only thing we need to provide is a function which takes an agent, and returns a portrayal dictionary. Here's the simplest one: it'll draw each agent as a blue, filled circle, with a radius size of 50." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "def agent\_portrayal(agent):\\n", " return {\\n", " \\"color\\": \\"tab:blue\\",\\n", " \\"size\\": 50,\\n", " }" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "In addition to the portrayal method, we instantiate the model parameters, some of which are modifiable by user inputs. In this case, the number of agents, N, is specified as a slider of integers." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "model\_params = {\\n", " \\"n\\": {\\n", " \\"type\\": \\"SliderInt\\",\\n", " \\"value\\": 50,\\n", " \\"label\\": \\"Number of agents:\\",\\n", " \\"min\\": 10,\\n", " \\"max\\": 100,\\n", " \\"step\\": 1,\\n", " },\\n", " \\"width\\": 10,\\n", " \\"height\\": 10,\\n", "}" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "Next, we instantiate the visualization object which (by default) displays the grid containing the agents, and timeseries of values computed by the model's data collector. In this example, we specify the Gini coefficient.\\n", "\\n", "There are 3 buttons:\\n", "- the step button, which advances the model by 1 step\\n", "- the play button, which advances the model indefinitely until it is paused\\n", "- the pause button, which pauses the model\\n", "\\n", "To reset the model, the order of operations are important\\n", "1. Stop the model\\n", "2. Update the parameters (e.g. move the sliders)\\n", "3. Press reset " \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "# Create initial model instance\\n", "money\_model = MoneyModel(n=50, width=10, height=10) # keyword arguments\\n", "\\n", "SpaceGraph = make\_space\_component(agent\_portrayal)\\n", "GiniPlot = make\_plot\_component(\\"Gini\\")\\n", "\\n", "page = SolaraViz(\\n", " money\_model,\\n", " components=\[SpaceGraph, GiniPlot\],\\n", " model\_params=model\_params,\\n", " name=\\"Boltzmann Wealth Model\\",\\n", ")\\n", "# This is required to render the visualization in the Jupyter notebook\\n", "page" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Next Steps\\n", "\\n", "Check out the next \[visualization tutorial dynamic agents\](https://mesa.readthedocs.io/latest/tutorials/5\_visualization\_dynamic\_agents.html) on how to further enhance your interactive dashboard." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "\[Comer2014\] Comer, Kenneth W. “Who Goes First? An Examination of the Impact of Activation on Outcome Behavior in AgentBased Models.” George Mason University, 2014. http://mars.gmu.edu/bitstream/handle/1920/9070/Comer\_gmu\_0883E\_10539.pdf\\n", "\\n", "\[Dragulescu2002\] Drăgulescu, Adrian A., and Victor M. Yakovenko. “Statistical Mechanics of Money, Income, and Wealth: A Short Survey.” arXiv Preprint Cond-mat/0211175, 2002. http://arxiv.org/abs/cond-mat/0211175." \] } \], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display\_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language\_info": { "codemirror\_mode": { "name": "ipython", "version": 3 }, "file\_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert\_exporter": "python", "pygments\_lexer": "ipython3", "version": "3.12.5" }, "widgets": { "state": {}, "version": "1.1.2" } }, "nbformat": 4, "nbformat\_minor": 4 }
---
# Unknown
\# Mesa: Agent-based modeling in Python \`\`\`{image} https://joss.theoj.org/papers/10.21105/joss.07668/status.svg :target: https://doi.org/10.21105/joss.07668 \`\`\` \`\`\`{image} https://github.com/projectmesa/mesa/workflows/build/badge.svg :target: https://github.com/projectmesa/mesa/actions \`\`\` \`\`\`{image} https://codecov.io/gh/projectmesa/mesa/branch/main/graph/badge.svg :target: https://codecov.io/gh/projectmesa/mesa \`\`\` \`\`\`{image} https://img.shields.io/badge/code%20style-black-000000.svg :target: https://github.com/psf/black \`\`\` \`\`\`{image} https://img.shields.io/matrix/project-mesa:matrix.org?label=chat&logo=Matrix :target: https://matrix.to/#/#project-mesa:matrix.org \`\`\` \[Mesa\] is an Apache2 licensed agent-based modeling (or ABM) framework in Python. Mesa allows users to quickly create agent-based models using built-in core components (such as spatial grids and agent schedulers) or customized implementations; visualize them using a browser-based interface; and analyze their results using Python's data analysis tools. Mesa's goal is to make simulations accessible to everyone, so humanity can more effectively understand and solve complex problems. !\[A screenshot of the Wolf Sheep model in Mesa|100%\](images/wolf\_sheep.png) \*A visualisation of the Wolf Sheep model build with Mesa.\* ## Features - Built-in core modeling components - Flexible agent and model management through AgentSet - Browser-based Solara visualization - Built-in tools for data collection and analysis - Example model library ## Using Mesa ### Installation Options To install our latest stable release, run: \`\`\`bash pip install -U mesa \`\`\` To also install our recommended dependencies: \`\`\`bash pip install -U mesa\[rec\] \`\`\` The \`\[rec\]\` option installs additional recommended dependencies needed for visualization, plotting, and network modeling capabilities. On a Mac, this command might cause an error stating \`zsh: no matches found: mesa\[all\]\`. In that case, change the command to \`pip install -U "mesa\[rec\]"\`. ### Resources For help getting started with Mesa, check out these resources: - \[Getting started\] - Learn about Mesa's core concepts and components - \[Migration Guide\] - Upgrade to Mesa 3.0 - \[Mesa Examples\] - Browse user-contributed models and implementations - \[Mesa Extensions\] - Overview of mesa's Extensions - \[GitHub Discussions\] - Ask questions and discuss Mesa - \[Matrix Chat Room\] - Real-time chat with the Mesa community ### Development and Support Mesa is an open source project and welcomes contributions: - \[GitHub Repository\] - Access the source code - \[Issue Tracker\] - Report bugs or suggest features - \[Contributors Guide\] - Learn how to contribute ### Citing Mesa To cite Mesa in your publication, you can refer to our peer-reviewed article in the Journal of Open Source Software (JOSS): - ter Hoeven, E., Kwakkel, J., Hess, V., Pike, T., Wang, B., rht, & Kazil, J. (2025). Mesa 3: Agent-based modeling with Python in 2025. Journal of Open Source Software, 10(107), 7668. https://doi.org/10.21105/joss.07668 Our \[CITATION.cff\](https://github.com/projectmesa/mesa/blob/main/CITATION.cff) can be used to generate APA, BibTeX and other citation formats. The original Mesa conference paper from 2015 is \[available here\](http://conference.scipy.org.s3-website-us-east-1.amazonaws.com/proceedings/scipy2015/jacqueline\_kazil.html). \`\`\`{toctree} :hidden: true :maxdepth: 7 Getting started Overview Examples Migration guide API Documentation \`\`\` # Indices and tables - {ref}\`genindex\` - {ref}\`modindex\` - {ref}\`search\` \[contributors guide\]: https://github.com/projectmesa/mesa/blob/main/CONTRIBUTING.md \[github repository\]: https://github.com/projectmesa/mesa/ \[github discussions\]: https://github.com/projectmesa/mesa/discussions \[issue tracker\]: https://github.com/projectmesa/mesa/issues \[matrix chat room\]: https://matrix.to/#/#project-mesa:matrix.org \[mesa\]: https://github.com/projectmesa/mesa/ \[mesa overview\]: overview \[mesa examples\]: https://mesa.readthedocs.io/stable/examples.html \[mesa introductory tutorial\]: tutorials/intro\_tutorial \[mesa visualization tutorial\]: tutorials/visualization\_tutorial \[migration guide\]: migration\_guide \[Getting started\]: getting\_started \[Mesa Extensions\]: mesa\_extension.md
---
# Unknown
{ "cells": \[ { "cell\_type": "markdown", "metadata": {}, "source": \[ "# Agent Management Through AgentSet\\n", "\\n", "### The Boltzmann Wealth Model " \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "If you want to get straight to the tutorial checkout these environment providers: \
\\n", "(with Google Account) \[!\[Colab\](https://colab.research.google.com/assets/colab-badge.svg)\](https://colab.research.google.com/github/projectmesa/mesa/blob/main/docs/tutorials/2\_collecting\_data.ipynb) \
\\n", "(No Google Account) \[!\[Binder\](https://mybinder.org/badge\_logo.svg)\](https://mybinder.org/v2/gh/projectmesa/mesa/main?labpath=docs%2Ftutorials%2F2\_collecting\_data.ipynb) (This can take 30 seconds to 5 minutes to load)\\n", "\\n", "\*If you are running locally, please ensure you have the latest Mesa version installed.\*\\n", "\\n", "## Tutorial Description\\n", "\\n", "This tutorial extends the Boltzmann wealth model from the \[Collecting Data tutorial\](https://mesa.readthedocs.io/latest/tutorials/2\_collecting\_data.html), by demonstrating Mesa's AgentSet functionality. \\n", "\\n", "In this portion, we will demonstrate how users can employ AgentSet for different purposes. \\n", "\\n", "\*If you are starting here please see the \[Running Your First Model tutorial\](https://mesa.readthedocs.io/latest/tutorials/0\_first\_model.html) for dependency and start-up instructions\*" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### IN COLAB? - Run the next cell " \] }, { "cell\_type": "raw", "metadata": { "vscode": { "languageId": "raw" } }, "source": \[ "%pip install --quiet mesa\[rec\]" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Import Dependencies\\n", "This includes importing of dependencies needed for the tutorial." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "outputs": \[\], "source": \[ "# Has multi-dimensional arrays and matrices.\\n", "# Has a large collection of mathematical functions to operate on these arrays.\\n", "import numpy as np\\n", "\\n", "# Data manipulation and analysis.\\n", "import pandas as pd\\n", "\\n", "# Data visualization tools.\\n", "import seaborn as sns\\n", "\\n", "import mesa" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Agent Management Through AgentSet\\n", "\\n", "\*\*Background:\*\* Mesa uses a set based approach, \[AgentSet\](https://github.com/projectmesa/mesa/blob/f511a4bc57340cb2dd0ba4b0af76307b37aea0ca/mesa/agent.py#L147) to allow users efficiently and intuitively manage their agents. For the most part users will never explicitly call AgentSet and in fact, we have already used the AgentSet methods functionality when we used \`shuffle\_do(move)\` to reorder the agents and then \`do(exchange)\` to have the agents exchange money in sequence. Although you will likely never interact with AgentSent directly it is important to know the Mesa uses a set based approach for agent management. \\n", "\\n", "Beyond the method functionality there are additional ways AgentSet can help you manage your agents and we will look at two additional examples in this tutorial, but you can see more in the \[Getting Started Section of Mesa\](https://mesa.readthedocs.io/stable/getting\_started.html#agentset-functionality). \\n", "\\n", "\*\*Model-specific information:\*\* We will show two agent management techniques just to demonstrate the capability\\n", "1. \*\*Selecting\*\* We will institute a policy that has the rich agents give money to the poor agents\\n", "2. \*\*GroupBy\*\* We will group agents together based on wealth\\n", "\\n", "\*A big thanks to @Ewout for his exceptional work on developing and implementing AgentSet\*" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Selecting \\n", "\\n", "\*\*Model-specific Information:\*\* For this variation of the model we are going to institute a policy that only rich agents give money to poor agent\\n", "\\n", "\*\*Code Implementation:\*\* We will use \`agents.select\` to separate the agents into rich and poor agents. If there are rich agents then they are the only ones who give money. \\n", "\\n", "\\\\# Get lists of rich and poor agents\\n", "\\n", "- \*\*Description:\*\* Uses \`AgentSet.select\` with a function (in this case a lambda function) to select agents with greater than 3 units of wealth and less than three units of wealth. This will give us two lists of agents rich agent and poor agent which we can then use to execute the \`give\_money\` method. \\n", "- \*\*API:\*\* \[AgentSet.select\](https://mesa.readthedocs.io/latest/apis/agent.html#mesa.agent.AgentSet.select)" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "def compute\_gini(model):\\n", " agent\_wealths = \[agent.wealth for agent in model.agents\]\\n", " x = sorted(agent\_wealths)\\n", " n = model.num\_agents\\n", " B = sum(xi \* (n - i) for i, xi in enumerate(x)) / (n \* sum(x))\\n", " return 1 + (1 / n) - 2 \* B\\n", "\\n", "\\n", "class MoneyAgent(mesa.Agent):\\n", " \\"\\"\\"An agent with fixed initial wealth.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, model):\\n", " super().\_\_init\_\_(model)\\n", " self.wealth = 1\\n", "\\n", " def give\_money(self, poor\_agents):\\n", " if self.wealth > 0:\\n", " other\_agent = self.random.choice(poor\_agents)\\n", " other\_agent.wealth += 1\\n", " self.wealth -= 1\\n", "\\n", "\\n", "class MoneyModel(mesa.Model):\\n", " \\"\\"\\"A model with some number of agents.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, n):\\n", " super().\_\_init\_\_()\\n", " self.num\_agents = n\\n", "\\n", " # Create agents\\n", " MoneyAgent.create\_agents(model=self, n=n)\\n", "\\n", " self.datacollector = mesa.DataCollector(\\n", " model\_reporters={\\"Gini\\": compute\_gini}, agent\_reporters={\\"Wealth\\": \\"wealth\\"}\\n", " )\\n", "\\n", " def step(self):\\n", " self.datacollector.collect(self)\\n", " # Get lists of rich and poor agents\\n", " rich\_agents = model.agents.select(lambda a: a.wealth >= 3)\\n", " poor\_agents = model.agents.select(lambda a: a.wealth < 3)\\n", " # When there is rich agents only have them give money to poor agents\\n", " if len(rich\_agents) > 0:\\n", " rich\_agents.shuffle\_do(\\"give\_money\\", poor\_agents)\\n", " else:\\n", " poor\_agents.shuffle\_do(\\"give\_money\\", poor\_agents)" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "We now run the model, collect the data, and plot the results." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "model = MoneyModel(100)\\n", "for \_ in range(20):\\n", " model.step()\\n", "\\n", "\\n", "data = model.datacollector.get\_agent\_vars\_dataframe()\\n", "# Use seaborn\\n", "g = sns.histplot(data\[\\"Wealth\\"\], discrete=True)\\n", "g.set(title=\\"Wealth distribution\\", xlabel=\\"Wealth\\", ylabel=\\"number of agents\\");" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Group By \\n", "\\n", "\*\*Model-specific implementation:\*\* In this case we will give agents an attribute of ethnicity of Green, Blue or Mixed. Green and Blue agents only give money to their ethnicity while Mixed can give money to anyone.\\n", "\\n", "\*\*Code Implementation\*\*: Using \`groupby\` we will execute the above logic in our code by passing a list of grouped agents into our \`give\_money\` function. To ensure we can plot wealth by group we also need to add ethnicity to our datacollector. \\n", "\\n", "\\\\# Create dictionary of agents groupby\\n", "\\n", "\*\*Description:\*\* Uses \`AgentSet.groupby\` to group agents by their ethnicity attribute. This will give us a dictionary where the keys are the different ethnicities and the values are an \`AgentSet\`. In this case we will then use the \`AgentSet\` class and leverage its \`shuffle\_do\` capability to then give money to the target groups. \\n", "- \*\*API:\*\* \[AgentSet.select\](https://mesa.readthedocs.io/latest/apis/agent.html#mesa.agent.AgentSet.groupby)\\n", "- \*\*Note:\*\* \`AgentSet\` has a lot of functionality and similar to \`discrete\_space\` has the ability to add new features and make Mesa models more user-friendly. We strongly encourage you to check out the \[AgentSet API\](https://mesa.readthedocs.io/latest/apis/agent.html#mesa.agent.AgentSet) to see all the functionality and if you have an idea feel free to \[contribute\](https://github.com/projectmesa/mesa/blob/main/CONTRIBUTING.md) " \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "class MoneyAgent(mesa.Agent):\\n", " \\"\\"\\"An agent with fixed initial wealth.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, model, ethnicity):\\n", " super().\_\_init\_\_(model)\\n", " self.wealth = 1\\n", " self.ethnicity = ethnicity\\n", "\\n", " def give\_money(self, similars):\\n", " if self.wealth > 0:\\n", " other\_agent = self.random.choice(similars)\\n", " other\_agent.wealth += 1\\n", " self.wealth -= 1\\n", "\\n", "\\n", "class MoneyModel(mesa.Model):\\n", " \\"\\"\\"A model with some number of agents.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, n):\\n", " super().\_\_init\_\_()\\n", " self.num\_agents = n\\n", "\\n", " # Create a list of our different ethnicities\\n", " ethnicities = \[\\"Green\\", \\"Blue\\", \\"Mixed\\"\]\\n", "\\n", " # Create agents\\n", " MoneyAgent.create\_agents(\\n", " model=self,\\n", " n=self.num\_agents,\\n", " ethnicity=self.random.choices(ethnicities, k=self.num\_agents),\\n", " )\\n", "\\n", " self.datacollector = mesa.DataCollector(\\n", " model\_reporters={\\"Gini\\": compute\_gini},\\n", " agent\_reporters={\\"Wealth\\": \\"wealth\\", \\"Ethnicity\\": \\"ethnicity\\"},\\n", " )\\n", "\\n", " def step(self):\\n", " self.datacollector.collect(self)\\n", " # Create dictionary of agents groupby\\n", " grouped\_agents = model.agents.groupby(\\"ethnicity\\")\\n", " for ethnic, similars in grouped\_agents:\\n", " if ethnic != \\"Mixed\\":\\n", " similars.shuffle\_do(\\"give\_money\\", similars)\\n", " else:\\n", " similars.shuffle\_do(\\n", " \\"give\_money\\", self.agents\\n", " ) # This allows mixed to trade with anyone" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "# Run the model\\n", "model = MoneyModel(100)\\n", "for \_ in range(20):\\n", " model.step()\\n", "\\n", "# get the data\\n", "data = model.datacollector.get\_agent\_vars\_dataframe()\\n", "# assign histogram colors\\n", "palette = {\\"Green\\": \\"green\\", \\"Blue\\": \\"blue\\", \\"Mixed\\": \\"purple\\"}\\n", "sns.histplot(data=data, x=\\"Wealth\\", hue=\\"Ethnicity\\", discrete=True, palette=palette)\\n", "g.set(title=\\"Wealth distribution\\", xlabel=\\"Wealth\\", ylabel=\\"number of agents\\");" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Exercises \\n", "- Create a new policy or alter an existing policy in this model to see the impact\\n", "- Use a different feature in \`AgentSet\` and integrate into this model" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Next Steps\\n", "\\n", "Check out the \[basic visualization tutorial\](https://mesa.readthedocs.io/latest/tutorials/4\_visualization\_basic.html) on how to build interactive dashboards for your models." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "\[Comer2014\] Comer, Kenneth W. “Who Goes First? An Examination of the Impact of Activation on Outcome Behavior in AgentBased Models.” George Mason University, 2014. http://mars.gmu.edu/bitstream/handle/1920/9070/Comer\_gmu\_0883E\_10539.pdf\\n", "\\n", "\[Dragulescu2002\] Drăgulescu, Adrian A., and Victor M. Yakovenko. “Statistical Mechanics of Money, Income, and Wealth: A Short Survey.” arXiv Preprint Cond-mat/0211175, 2002. http://arxiv.org/abs/cond-mat/0211175." \] } \], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display\_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language\_info": { "codemirror\_mode": { "name": "ipython", "version": 3 }, "file\_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert\_exporter": "python", "pygments\_lexer": "ipython3", "version": "3.12.5" }, "widgets": { "state": {}, "version": "1.1.2" } }, "nbformat": 4, "nbformat\_minor": 4 }
---
# Unknown
\# Model \`\`\`{eval-rst} .. automodule:: mesa.model :members: :inherited-members: \`\`\`
---
# Unknown
\# Best Practices Here are some general principles that have proven helpful for developing models. ## Model Layout A model should be contained in a folder named with lower-case letters and underscores, such as \`wolf\_sheep\`. Within that directory: - \`Readme.md\` describes the model, how to use it, and any other details. - \`model.py\` should contain the model class. - \`agents.py\` should contain the agent class(es). - \`app.py\` should contain the Solara-based visualization code (optional). You can add more files as needed, for example: - \`run.py\` could contain the code to run the model. - \`batch\_run.py\` could contain the code to run the model multiple times. - \`analysis.py\` could contain any analysis code. Input data can be stored in a \`data\` directory, output data in an \`output\`, processed results in a \`results\` directory, images in an \`images\` directory, etc. All our \[examples\](examples) follow this layout. ## Randomization If your model involves some random choice, you can use the built-in \`random\` property that many Mesa objects have, including \`Model\`, \`Agent\`, and \`AgentSet\`. This works exactly like the built-in \`random\` library. \`\`\`python class AwesomeModel(Model): # ... def cool\_method(self): interesting\_number = self.random.random() print(interesting\_number) class AwesomeAgent(Agent): # ... def \_\_init\_\_(self, unique\_id, model, ...): super().\_\_init\_\_(unique\_id, model) # ... def my\_method(self): random\_number = self.random.randint(0, 100) \`\`\` \`Agent.random\` is just a convenient shorthand in the Agent class to \`self.model.random\`. If you create your own \`AgentSet\` instances, you have to pass \`random\` explicitly. Typically, you can simply do, in a Model instance, \`my\_agentset = AgentSet(\[\], random=self.random)\`. This ensures that \`my\_agentset\` uses the same random number generator as the rest of the model. When a model object is created, its random property is automatically seeded with the current time. The seed determines the sequence of random numbers; if you instantiate a model with the same seed, you will get the same results. To allow you to set the seed, make sure your model has a \`seed\` argument in its \`\_\_init\_\_\`. \`\`\`python class AwesomeModel(Model): def \_\_init\_\_(self, seed=None): super().\_\_init\_\_(seed=seed) ... def cool\_method(self): interesting\_number = self.random.random() print(interesting\_number) >>> model0 = AwesomeModel(seed=0) >>> model0.\_seed 0 >>> model0.cool\_method() 0.8444218515250481 >>> model1 = AwesomeModel(seed=0) >>> model1.cool\_method() 0.8444218515250481 \`\`\`
---
# Unknown
{ "cells": \[ { "cell\_type": "markdown", "metadata": {}, "source": \[ "# Creating Your First Model\\n", "\\n", "### The Boltzmann Wealth Model " \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "\*\*Important:\*\* \\n", "- If you are just exploring Mesa and want the fastest way to execute the code we recommend executing this tutorial online in a Colab notebook. \[!\[Colab\](https://colab.research.google.com/assets/colab-badge.svg)\](https://colab.research.google.com/github/projectmesa/mesa/blob/main/docs/tutorials/0\_first\_model.ipynb) or if you do not have a Google account you can use \[!\[Binder\](https://mybinder.org/badge\_logo.svg)\](https://mybinder.org/v2/gh/projectmesa/mesa/main?labpath=docs%2Ftutorials%2F)0\_first\_model.ipynb) (This can take 30 seconds to 5 minutes to load)\\n", "- If you are running locally, please ensure you have the latest Mesa version installed.\\n", "\\n", "## Tutorial Description\\n", "\\n", "\[Mesa\](https://github.com/projectmesa/mesa) is a Python framework for \[agent-based modeling\](https://en.wikipedia.org/wiki/Agent-based\_model). This tutorial is the first in a series of introductory tutorials that will assist you in getting started and discover some of the core features of Mesa. The tutorial starts with the key pieces of a model and then progressively adds functionality. \\n", "\\n", "Should anyone find any errors, bugs, have a suggestion, or just are looking for clarification, let us know in our \[chat\](https://matrix.to/#/#project-mesa:matrix.org)!\\n", "\\n", "The premise of this tutorial is to create a starter-level model representing agents exchanging money. " \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Model Description\\n", "\\n", "This is a simulated agent-based economy. In an agent-based economy, the behavior of an individual economic agent, such as a consumer or producer, is studied in a market environment.\\n", "This model is drawn from the field econophysics, specifically a paper prepared by Drăgulescu et al. for additional information on the modeling assumptions used in this model. \[Drăgulescu, 2002\].\\n", "\\n", "The assumption that govern this model are:\\n", "\\n", "1. There are some number of agents.\\n", "2. All agents begin with 1 unit of money.\\n", "3. At every step of the model, an agent gives 1 unit of money (if they\\n", " have it) to some other agent.\\n", "\\n", "Even as a starter-level model it yields results that are both interesting and unexpected. \\n", "\\n", "Due to its simplicity and intriguing results, we found it to be a good starter model. " \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Tutorial Setup\\n", "\\n", "Create and activate a \[virtual environment\](http://docs.python-guide.org/en/latest/dev/virtualenvs/). \*Python version 3.11 or higher is required\*.\\n", "\\n", "Install Mesa:\\n", "\\n", "\`\`\`bash\\n", "pip install mesa\[rec\] \\n", "\`\`\`\\n", "\\n", "Install Jupyter notebook (optional):\\n", "\\n", "\`\`\`bash\\n", "pip install jupyter\\n", "\`\`\`\\n", "\\n", "Install \[Seaborn\](https://seaborn.pydata.org/) (which is used for data visualization):\\n", "\\n", "\`\`\`bash\\n", "pip install seaborn\\n", "\`\`\`" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### IN COLAB? - Run the next cell " \] }, { "cell\_type": "raw", "metadata": { "vscode": { "languageId": "raw" } }, "source": \[ "%pip install --quiet mesa\[rec\]" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Building the Sample Model\\n", "\\n", "After Mesa is installed a model can be built.\\n", "\\n", " This tutorial is written in \[Jupyter\](http://jupyter.org) to facilitate the explanation portions. \\n", "\\n", "Start Jupyter form the command line:\\n", "\\n", "\`\`\`bash\\n", "jupyter lab\\n", "\`\`\`\\n", "\\n", "Create a new notebook named \`money\_model.ipynb\` (or whatever you want to call it)." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Import Dependencies\\n", "This includes importing of dependencies needed for the tutorial." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "outputs": \[\], "source": \[ "# Has multi-dimensional arrays and matrices.\\n", "# Has a large collection of mathematical functions to operate on these arrays.\\n", "import numpy as np\\n", "\\n", "# Data manipulation and analysis.\\n", "import pandas as pd\\n", "\\n", "# Data visualization tools.\\n", "import seaborn as sns\\n", "\\n", "import mesa" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Create Agent\\n", "\\n", "First create the agent. As the tutorial progresses, more functionality will be added to the agent.\\n", "\\n", "\*\*Background:\*\* Agents are the individual entities that act in the model. Mesa automatically assigns each agent that is created an integer as a \`unique\_id.\` \\n", "\\n", "\*\*Model-specific information:\*\* Agents are the individuals that exchange money, in this case the amount of money an individual agent has is represented as wealth. \\n", "\\n", "\*\*Code implementation:\*\* This is done by creating a new class (or object) that extends \`mesa.Agent\` creating a subclass of the \`Agent\` class from mesa. The new class is named \`MoneyAgent\`. The inherited code of the Mesa agent object can be found in the \[mesa repo\](https://github.com/projectmesa/mesa/blob/main/mesa/agent.py).\\n", "\\n", "The \`MoneyAgent\` class is created with the following code:" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "class MoneyAgent(mesa.Agent):\\n", " \\"\\"\\"An agent with fixed initial wealth.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, model):\\n", " # Pass the parameters to the parent class.\\n", " super().\_\_init\_\_(model)\\n", "\\n", " # Create the agent's variable and set the initial values.\\n", " self.wealth = 1" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Create Model\\n", "\\n", "Next, create the model. This gives us the two basic classes of any Mesa ABM - the agent class (population of agent objects that doing something) and the manager class (a model object that manages the creation, activation, datacollection etc of the agents)\\n", "\\n", "\*\*Background:\*\* The model can be visualized as a list containing all the agents. The model creates, holds and manages all the agent objects, specifically in a dictionary. The model activates agents in discrete time steps.\\n", "\\n", "\*\*Model-specific information:\*\* When a model is created the number of agents within the model is specified. The model then creates the agents and places them in a set of agents. \\n", "\\n", "\*\*Code implementation:\*\* This is done by creating a new class (or object) that extends \`mesa.Model\` and calls \`super().\_\_init\_\_()\`, creating a subclass of the \`Model\` class from mesa. The new class is named \`MoneyModel\`. The Mesa code you are using can be found in \[model module\](https://github.com/projectmesa/mesa/blob/main/mesa/model.py) and the AgentSet in the \[agent module\](https://github.com/projectmesa/mesa/blob/d7a3834c99a3be809abe2edc8b83610f3d4438ba/mesa/agent.py#L86). A critical point is that you can use the \`seed\` kwarg (keyword argument) to set a seed which controls the random number generator of the model class allowing for the reproducibility of results. \\n", "\\n", "The \`MoneyModel\` class is created with the following code:" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "class MoneyModel(mesa.Model):\\n", " \\"\\"\\"A model with some number of agents.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, n, seed=None):\\n", " super().\_\_init\_\_(seed=seed)\\n", " self.num\_agents = n\\n", " # Create agents\\n", " MoneyAgent.create\_agents(model=self, n=n)" \] }, { "attachments": {}, "cell\_type": "markdown", "metadata": {}, "source": \[ "### Making the Agents \`do\`\\n", "\\n", "With the basics of the Agent class and Model class created we can now activate the agents to \`do\` things\\n", "\\n", "\*\*Background:\*\* Mesa's \`do\` function calls agent functions to grow your ABM. A step is the smallest unit of time in the model, and is often referred to as a tick. The \`do\` function and Python functionality can be configured to activate agents in different orders. This can be important as the order in which agents are activated can impact the results of the model \[Comer2014\]. At each step of the model, one or more of the agents -- usually all of them -- are activated and take their own step, changing internally and/or interacting with one another or the environment.\\n", "\\n", "\*\*Model-specific information:\*\* For this section we will randomly reorder the Agent activation order using \`mesa.Agent.shuffle\_do\` and have the agents \`step\` function print the agent's unique id that they were assigned during the agent creation process. \\n", "\\n", "\*\*Code implementation:\*\* Using standard ABM convention we add a \`step\` function to the \`MoneyModel\` class which calls the \`mesa.Agent.shuffle\_do\` function. We then pass into \`shuffle\_do\` the parameter \\"step\\". This tells mesa to look for and execute the \`step\` function in our MoneyAgent class. " \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "class MoneyAgent(mesa.Agent):\\n", " \\"\\"\\"An agent with fixed initial wealth.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, model):\\n", " # Pass the parameters to the parent class.\\n", " super().\_\_init\_\_(model)\\n", "\\n", " # Create the agent's attribute and set the initial values.\\n", " self.wealth = 1\\n", "\\n", " def say\_hi(self):\\n", " # The agent's step will go here.\\n", " # For demonstration purposes we will print the agent's unique\_id\\n", " print(f\\"Hi, I am an agent, you can call me {self.unique\_id!s}.\\")\\n", "\\n", "\\n", "class MoneyModel(mesa.Model):\\n", " \\"\\"\\"A model with some number of agents.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, n, seed=None):\\n", " super().\_\_init\_\_(seed=seed)\\n", " self.num\_agents = n\\n", "\\n", " # Create n agents\\n", " MoneyAgent.create\_agents(model=self, n=n)\\n", "\\n", " def step(self):\\n", " \\"\\"\\"Advance the model by one step.\\"\\"\\"\\n", " # This function psuedo-randomly reorders the list of agent objects and\\n", " # then iterates through calling the function passed in as the parameter\\n", " self.agents.shuffle\_do(\\"say\_hi\\")" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Running the Model\\n", "We now have the pieces of a basic model. The model can be run by creating a model object and calling the step method. The model will run for one step and print the unique\_id of each agent. You may run the model for multiple steps by calling the step method multiple times.\\n", "\\n", "Create the model object, and run it for one step:" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "starter\_model = MoneyModel(10)\\n", "starter\_model.step()" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "outputs": \[\], "source": \[ "# Run this step a few times and see what happens!\\n", "starter\_model.step()\\n", "# Notice the order of the agents changes each time." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "# Challenge: Change the seed from None to a number like 42 and see the impact" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "# Challenge: Change \`shuffle\_do\` to just \`do\` and see the impact" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Exercise\\n", "Modifying the code below to have every agent print out its \`wealth\` when it is activated." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "outputs": \[\], "source": \[ "class MoneyAgent(mesa.Agent):\\n", " \\"\\"\\"An agent with fixed initial wealth.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, model):\\n", " # Pass the parameters to the parent class.\\n", " super().\_\_init\_\_(model)\\n", "\\n", " # Create the agent's variable and set the initial values.\\n", " self.wealth = 1\\n", "\\n", " def say\_wealth(self):\\n", " # The agent's step will go here.\\n", " # FIXME: need to print the agent's wealth\\n", " print(\\"Hi, I am an agent and I am broke!\\")" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "Create a model for 12 Agents, and run it for a few steps to see the output." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "outputs": \[\], "source": \[ "# Fixme: Create the model object, and run it" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Agents Exchange\\n", "\\n", "Returning back to the MoneyAgent the actual exchange process is now going to be created.\\n", "\\n", "\*\*Background:\*\* This is where the agent's behavior as it relates to each step or tick of the model is defined.\\n", "\\n", "\*\*Model-specific information:\*\* In this case, the agent will check its wealth, and if it has money, give one unit of it away to another random agent.\\n", "\\n", "\*\*Code implementation:\*\* The agent's step method is called by \`mesa.Agent.shuffle\_do(\\"exchange\\")\`during each step of the model. To allow the agent to choose another agent at random, we use the \`model.random\` random-number generator. This works just like Python's \`random\` module, but if a fixed seed is set when the model is instantiated (see earlier challenge), this allows users to replicate a specific model run later. Once we identify this other agent object we increase their wealth by 1 and decrease this agents wealth by one.\\n", "\\n", "This updates the step function as shown below:" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "class MoneyAgent(mesa.Agent):\\n", " \\"\\"\\"An agent with fixed initial wealth.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, model):\\n", " # Pass the parameters to the parent class.\\n", " super().\_\_init\_\_(model)\\n", "\\n", " # Create the agent's variable and set the initial values.\\n", " self.wealth = 1\\n", "\\n", " def exchange(self):\\n", " # Verify agent has some wealth\\n", " if self.wealth > 0:\\n", " other\_agent = self.random.choice(self.model.agents)\\n", " if other\_agent is not None:\\n", " other\_agent.wealth += 1\\n", " self.wealth -= 1\\n", "\\n", "\\n", "class MoneyModel(mesa.Model):\\n", " \\"\\"\\"A model with some number of agents.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, n):\\n", " super().\_\_init\_\_()\\n", " self.num\_agents = n\\n", "\\n", " # Create agents\\n", " MoneyAgent.create\_agents(model=self, n=n)\\n", "\\n", " def step(self):\\n", " \\"\\"\\"Advance the model by one step.\\"\\"\\"\\n", " # This function psuedo-randomly reorders the list of agent objects and\\n", " # then iterates through calling the function passed in as the parameter\\n", " self.agents.shuffle\_do(\\"exchange\\")" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Running your first model\\n", "\\n", "With exchange behavior added, it's time for the first rudimentary run of the model.\\n", "\\n", "Now let's create a model with 10 agents, and run it for 30 steps." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "model = MoneyModel(10) # Tells the model to create 10 agents\\n", "for \_ in range(30): # Runs the model for 30 steps;\\n", " model.step()\\n", "\\n", "# Note: An underscore is common convention for a variable that is not used." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "Next, we need to get some data out of the model. Specifically, we want to see the distribution of the agent's wealth.\\n", "\\n", " We can get the wealth values with list comprehension, and then use seaborn (or another graphics library) to visualize the data in a histogram." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "agent\_wealth = \[a.wealth for a in model.agents\]\\n", "# Create a histogram with seaborn\\n", "g = sns.histplot(agent\_wealth, discrete=True)\\n", "g.set(\\n", " title=\\"Wealth distribution\\", xlabel=\\"Wealth\\", ylabel=\\"number of agents\\"\\n", "); # The semicolon is just to avoid printing the object representation" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "To get a better idea of how a model behaves, we can create multiple model objects and see the distribution that emerges from all of them.\\n", "\\n", " We can do this with a nested for loop:" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "all\_wealth = \[\]\\n", "# This runs the model 100 times, each model executing 10 steps.\\n", "for \_ in range(100):\\n", " # Run the model\\n", " model = MoneyModel(10)\\n", " for \_ in range(30):\\n", " model.step()\\n", "\\n", " # Store the results\\n", " for agent in model.agents:\\n", " all\_wealth.append(agent.wealth)\\n", "\\n", "# Use seaborn\\n", "g = sns.histplot(all\_wealth, discrete=True)\\n", "g.set(title=\\"Wealth distribution\\", xlabel=\\"Wealth\\", ylabel=\\"number of agents\\");" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "This runs 100 instantiations of the model, and runs each for 30 steps. \\n", "\\n", "Notice that we set the histogram bins to be integers (\`discrete=True\`), since agents can only have whole numbers of wealth.\\n", "\\n", " This distribution looks a lot smoother. By running the model 100 times, we smooth out some of the 'noise' of randomness, and get to the model's overall expected behavior.\\n", "\\n", "This outcome might be surprising. Despite the fact that all agents, on average, give and receive one unit of money every step, the model converges to a state where most agents have a small amount of money and a small number have a lot of money." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Exercise\\n", "Change the above code to see the impact of different model runs, agent populations, and number of steps." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Next Steps\\n", "\\n", "Check out the \[adding space tutorial\](https://mesa.readthedocs.io/latest/tutorials/1\_adding\_space.html) on how to build interactive dashboards for your models." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### More Mesa\\n", "\\n", "If you are looking for other Mesa models or tools here are some additional resources. \\n", "\\n", "- Example ABMs: Find canonical examples and examples of ABMs demonstrating highlighted features in the \[Examples Tab\](https://mesa.readthedocs.io/stable/examples.html)\\n", "- Expanded Examples: Want to integrate Reinforcement Learning or work on the Traveling Salesman Problem? Checkout \[Mesa Examples\](https://github.com/projectmesa/mesa-examples/)\\n", "- Mesa-Geo: If you need an ABM with Geographic Information Systems (GIS) checkout \[Mesa-Geo\](https://mesa-geo.readthedocs.io/latest/)\\n", "- Mesa Frames: Have a large complex model that you need to speed up, check out \[Mesa Frames\](https://github.com/projectmesa/mesa-frames)" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Happy Modeling!\\n", "\\n", "This document is a work in progress. If you see any errors, exclusions or have any problems please contact \[us\](https://github.com/projectmesa/mesa/issues)." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "\[Comer2014\] Comer, Kenneth W. “Who Goes First? An Examination of the Impact of Activation on Outcome Behavior in AgentBased Models.” George Mason University, 2014. http://mars.gmu.edu/bitstream/handle/1920/9070/Comer\_gmu\_0883E\_10539.pdf\\n", "\\n", "\[Dragulescu2002\] Drăgulescu, Adrian A., and Victor M. Yakovenko. “Statistical Mechanics of Money, Income, and Wealth: A Short Survey.” arXiv Preprint Cond-mat/0211175, 2002. http://arxiv.org/abs/cond-mat/0211175." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[\] } \], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display\_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language\_info": { "codemirror\_mode": { "name": "ipython", "version": 3 }, "file\_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert\_exporter": "python", "pygments\_lexer": "ipython3", "version": "3.12.5" }, "widgets": { "state": {}, "version": "1.1.2" } }, "nbformat": 4, "nbformat\_minor": 4 }
---
# Search - Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Search
======
Ctrl+K
---
# Python Module Index — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Python Module Index
===================
[**b**](#cap-b)
| [**d**](#cap-d)
| [**e**](#cap-e)
| [**m**](#cap-m)
| | | |
| --- | --- | --- |
| | | |
| | **b** | |
| | [`batchrunner`](apis/batchrunner.html#module-batchrunner) | |
| | | |
| | **d** | |
| | [`datacollection`](apis/datacollection.html#module-datacollection) | |
| | | |
| | **e** | |
|  | `experimental` | |
| | [`experimental.continuous_space.continuous_space`](apis/experimental.html#module-experimental.continuous_space.continuous_space) | |
| | [`experimental.continuous_space.continuous_space_agents`](apis/experimental.html#module-experimental.continuous_space.continuous_space_agents) | |
| | [`experimental.devs.eventlist`](apis/experimental.html#module-experimental.devs.eventlist) | |
| | [`experimental.devs.simulator`](apis/experimental.html#module-experimental.devs.simulator) | |
| | | |
| | **m** | |
|  | [`mesa`](mesa.html#module-mesa) | |
| | [`mesa.agent`](mesa.html#module-mesa.agent) | |
| | [`mesa.batchrunner`](mesa.html#module-mesa.batchrunner) | |
| | [`mesa.datacollection`](mesa.html#module-mesa.datacollection) | |
| | [`mesa.discrete_space.__init__`](apis/discrete_space.html#module-mesa.discrete_space.__init__) | |
| | [`mesa.discrete_space.cell`](apis/discrete_space.html#module-mesa.discrete_space.cell) | |
| | [`mesa.discrete_space.cell_agent`](apis/discrete_space.html#module-mesa.discrete_space.cell_agent) | |
| | [`mesa.discrete_space.cell_collection`](apis/discrete_space.html#module-mesa.discrete_space.cell_collection) | |
| | [`mesa.discrete_space.discrete_space`](apis/discrete_space.html#module-mesa.discrete_space.discrete_space) | |
| | [`mesa.discrete_space.grid`](apis/discrete_space.html#module-mesa.discrete_space.grid) | |
| | [`mesa.discrete_space.network`](apis/discrete_space.html#module-mesa.discrete_space.network) | |
| | [`mesa.discrete_space.voronoi`](apis/discrete_space.html#module-mesa.discrete_space.voronoi) | |
| | [`mesa.mesa_logging`](apis/mesa_logging.html#module-mesa.mesa_logging) | |
| | [`mesa.model`](mesa.html#module-mesa.model) | |
| | [`mesa.space`](mesa.html#module-mesa.space) | |
| | [`mesa.visualization.command_console`](apis/visualization.html#module-mesa.visualization.command_console) | |
| | [`mesa.visualization.components.__init__`](apis/visualization.html#module-mesa.visualization.components.__init__) | |
| | [`mesa.visualization.components.altair_components`](apis/visualization.html#module-mesa.visualization.components.altair_components) | |
| | [`mesa.visualization.components.matplotlib_components`](apis/visualization.html#module-mesa.visualization.components.matplotlib_components) | |
| | [`mesa.visualization.mpl_space_drawing`](apis/visualization.html#module-mesa.visualization.mpl_space_drawing) | |
| | [`mesa.visualization.solara_viz`](apis/visualization.html#module-mesa.visualization.solara_viz) | |
| | [`mesa.visualization.user_param`](apis/visualization.html#module-mesa.visualization.user_param) | |
---
# Unknown
{ "cells": \[ { "cell\_type": "markdown", "metadata": {}, "source": \[ "# BatchRunner\\n", "\\n", "### The Boltzmann Wealth Model " \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "If you want to get straight to the tutorial checkout these environment providers: \
\\n", "(with Google Account) \[!\[Colab\](https://colab.research.google.com/assets/colab-badge.svg)\](https://colab.research.google.com/github/projectmesa/mesa/blob/main/docs/tutorials/7\_batch\_run.ipynb) \
\\n", "(No Google Account) \[!\[Binder\](https://mybinder.org/badge\_logo.svg)\](https://mybinder.org/v2/gh/projectmesa/mesa/main?labpath=docs%2Ftutorials%2F7\_batch\_run.ipynb) (This can take 30 seconds to 5 minutes to load)\\n", "\\n", "\*If you are running locally, please ensure you have the latest Mesa version installed.\*\\n", "\\n", "## Tutorial Description\\n", "\\n", "This tutorial extends the Boltzmann wealth model from the \[Collecting Data tutorial\](https://mesa.readthedocs.io/latest/tutorials/2\_collecting\_data.html), by showing how users can use \`batch\_run\` to conduct parameter sweeps of their models. \\n", "\\n", "\*If you are starting here please see the \[Running Your First Model tutorial\](https://mesa.readthedocs.io/latest/tutorials/0\_first\_model.html) for dependency and start-up instructions\*" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### IN COLAB? - Run the next cell " \] }, { "cell\_type": "raw", "metadata": { "vscode": { "languageId": "raw" } }, "source": \[ "%pip install --quiet mesa\[rec\]" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Import Dependencies\\n", "This includes importing of dependencies needed for the tutorial." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "outputs": \[\], "source": \[ "# Has multi-dimensional arrays and matrices.\\n", "# Has a large collection of mathematical functions to operate on these arrays.\\n", "import numpy as np\\n", "\\n", "# Data manipulation and analysis.\\n", "import pandas as pd\\n", "\\n", "# Data visualization tools.\\n", "import seaborn as sns\\n", "\\n", "import mesa\\n", "\\n", "# Import Cell Agent and OrthogonalMooreGrid\\n", "from mesa.discrete\_space import CellAgent, OrthogonalMooreGrid" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Base Model\\n", "\\n", "The below provides the base model from which we will add batch\_run functionality. Of note, this is the same as the \[collecting data tutorial\](https://mesa.readthedocs.io/latest/tutorials/2\_collecting\_data.html) but we add one agent reporter that counts if money is not given to that agent during a time step. \\n", "\\n", "We also added \`self.running=True\` in the \`MoneyModel\` class. This allows users to provide a conditional stop attribute (e.g. all sheep and wolves die) as opposed to a step count.)\\n", "\\n", "This is from the \[Running Your First Model tutorial\](https://mesa.readthedocs.io/latest/tutorials/0\_first\_model.html) tutorial. If you have any questions about it functionality please review that tutorial." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "def compute\_gini(model):\\n", " agent\_wealths = \[agent.wealth for agent in model.agents\]\\n", " x = sorted(agent\_wealths)\\n", " n = model.num\_agents\\n", " B = sum(xi \* (n - i) for i, xi in enumerate(x)) / (n \* sum(x))\\n", " return 1 + (1 / n) - 2 \* B\\n", "\\n", "\\n", "class MoneyAgent(CellAgent):\\n", " \\"\\"\\"An agent with fixed initial wealth.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, model, cell):\\n", " super().\_\_init\_\_(model)\\n", " self.cell = cell\\n", " self.wealth = 1\\n", " self.steps\_not\_given = 0\\n", "\\n", " def move(self):\\n", " self.cell = self.cell.neighborhood.select\_random\_cell()\\n", "\\n", " def give\_money(self):\\n", " cellmates = \[a for a in self.cell.agents if a is not self\]\\n", "\\n", " if len(cellmates) > 0 and self.wealth > 0:\\n", " other = self.random.choice(cellmates)\\n", " other.wealth += 1\\n", " self.wealth -= 1\\n", " self.steps\_not\_given = 0\\n", " else:\\n", " self.steps\_not\_given += 1\\n", "\\n", "\\n", "class MoneyModel(mesa.Model):\\n", " \\"\\"\\"A model with some number of agents.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, n, width, height, seed=None):\\n", " super().\_\_init\_\_(seed=seed)\\n", " self.num\_agents = n\\n", " self.grid = OrthogonalMooreGrid(\\n", " (width, height), torus=True, capacity=10, random=self.random\\n", " )\\n", " # Instantiate DataCollector\\n", " self.datacollector = mesa.DataCollector(\\n", " model\_reporters={\\"Gini\\": compute\_gini},\\n", " agent\_reporters={\\"Wealth\\": \\"wealth\\", \\"Steps\_not\_given\\": \\"steps\_not\_given\\"},\\n", " )\\n", " self.running = True\\n", "\\n", " # Create agents\\n", " agents = MoneyAgent.create\_agents(\\n", " self,\\n", " self.num\_agents,\\n", " self.random.choices(self.grid.all\_cells.cells, k=self.num\_agents),\\n", " )\\n", "\\n", " def step(self):\\n", " # Collect data each step\\n", " self.datacollector.collect(self)\\n", " self.agents.shuffle\_do(\\"move\\")\\n", " self.agents.do(\\"give\_money\\")" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "model = MoneyModel(100, 10, 10)\\n", "for \_ in range(100):\\n", " model.step()\\n", "\\n", "gini = model.datacollector.get\_model\_vars\_dataframe()\\n", "g = sns.lineplot(data=gini)\\n", "g.set(title=\\"Gini Coefficient over Time\\", ylabel=\\"Gini Coefficient\\");" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Batch Run\\n", "\\n", "Modelers typically won't run a model just once, but multiple times, with fixed parameters to find the overall distributions the model generates, and with varying parameters to analyze how these variables drive the model's outputs and behaviors. This is commonly referred to as parameter sweeps. Instead of needing to write nested for-loops for each model, Mesa provides a \[\`batch\_run\`\](https://mesa.readthedocs.io/latest/apis/batchrunner.html) function which automates parameter sweeps and allows the model variants to run on multiple processors." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Batch run parameters\\n", "\\n", "We call \`batch\_run\` with the following arguments:\\n", "\\n", "\* \`model\_cls\`\\n", " The model class that is used for the batch run.\\n", "\* \`parameters\`\\n", " A dictionary containing all the parameters of the model class and desired values to use for the batch run as key-value pairs. Each value can either be fixed ( e.g. \`{\\"height\\": 10, \\"width\\": 10}\`) or an iterable (e.g. \`{\\"n\\": range(10, 500, 10)}\`). \`batch\_run\` will then generate all possible parameter combinations based on this dictionary and run the model \`iterations\` times for each combination.\\n", "\* \`number\_processes\`\\n", " If not specified, defaults to 1. Set it to \`None\` to use all the available processors.\\n", " Note: Multiprocessing does make debugging challenging. If your parameter sweeps are resulting in unexpected errors set \`number\_processes=1\`.\\n", "\* \`iterations\`\\n", " The number of iterations to run each parameter combination for. Optional. If not specified, defaults to 1.\\n", "\* \`data\_collection\_period\`\\n", " The length of the period (number of steps) after which the model and agent reporters collect data. Optional. If not specified, defaults to -1, i.e. only at the end of each episode.\\n", "\* \`max\_steps\`\\n", " The maximum number of time steps after which the model halts. An episode does either end when \`self.running\` of the model class is set to \`False\` or when \`model.steps == max\_steps\` is reached. Optional. If not specified, defaults to 1000.\\n", "\* \`display\_progress\`\\n", " Display the batch run progress. Optional. If not specified, defaults to \`True\`." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "In the following example, we hold the height and width fixed, and vary the number of agents. We tell the batch runner to run 5 instantiations of the model with each number of agents, and to run each for 100 steps. \\n", "\\n", "We want to keep track of\\n", "\\n", "1. The Gini coefficient value at each time step\\n", "2. The individual agent's wealth development and steps without giving money.\\n", "\\n", "\*\*Important:\*\* Since for the latter, changes at each time step might be interesting, we set \`data\_collection\_period=1\`. By default, it only collects data at the end of each episode.\\n", "\\n", "Note: The total number of runs is 100 (20 different populations \* 5 iterations per population). " \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "params = {\\"width\\": 10, \\"height\\": 10, \\"n\\": range(5, 105, 5)}\\n", "\\n", "results = mesa.batch\_run(\\n", " MoneyModel,\\n", " parameters=params,\\n", " iterations=5,\\n", " max\_steps=100,\\n", " number\_processes=1,\\n", " data\_collection\_period=1,\\n", " display\_progress=True,\\n", ")" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "To further analyze the return of the \`batch\_run\` function, we convert the list of dictionaries to a Pandas DataFrame and print its keys." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Batch Run Analysis and Visualization" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "results\_df = pd.DataFrame(results)\\n", "print(f\\"The results have {len(results)} rows.\\")\\n", "print(f\\"The columns of the data frame are {list(results\_df.keys())}.\\")" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "First, we want to take a closer look at how the Gini coefficient at the end of each episode changes as we increase the size of the population. For this, we filter our results to only contain the data of one agent (the Gini coefficient will be the same for the entire population at any time) at the 100th step of each episode and then scatter-plot the values for the Gini coefficient over the the number of agents. Notice there are five values for each population size since we set \`iterations=5\` when calling the batch run." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "# Filter the results to only contain the data of one agent\\n", "# The Gini coefficient will be the same for the entire population at any time\\n", "results\_filtered = results\_df\[(results\_df.AgentID == 1) & (results\_df.Step == 100)\]\\n", "results\_filtered\[\[\\"iteration\\", \\"n\\", \\"Gini\\"\]\].reset\_index(\\n", " drop=True\\n", ").head() # Create a scatter plot\\n", "g = sns.scatterplot(data=results\_filtered, x=\\"n\\", y=\\"Gini\\")\\n", "g.set(\\n", " xlabel=\\"number of agents\\",\\n", " ylabel=\\"Gini coefficient\\",\\n", " title=\\"Gini coefficient vs. Number of Agents\\",\\n", ");" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "We can create different kinds of plot from this filtered DataFrame. For example, a point plot with error bars." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "outputs": \[\], "source": \[ "# Create a point plot with error bars\\n", "g = sns.pointplot(data=results\_filtered, x=\\"n\\", y=\\"Gini\\", linestyle=\\"None\\")\\n", "g.figure.set\_size\_inches(8, 4)\\n", "g.set(\\n", " xlabel=\\"number of agents\\",\\n", " ylabel=\\"Gini coefficient\\",\\n", " title=\\"Gini coefficient vs. number of agents\\",\\n", ");" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "Secondly, we want to display the agent's wealth at each time step of one specific episode. To do this, we again filter our large data frame, this time with a fixed number of agents and only for a specific iteration of that population.\\n", "To print the results, we convert the filtered data frame to a string specifying the desired columns to print. \\n", "\\n", "Pandas has built-in functions to convert to a lot of different data formats. For example, to display as a table in a Jupyter, we can use the \`to\_html()\` function which takes the same arguments as \`to\_string()\` (see commented lines)." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "# First, we filter the results\\n", "one\_episode\_wealth = results\_df\[(results\_df.n == 10) & (results\_df.iteration == 2)\]\\n", "# Then, print the columns of interest of the filtered data frame\\n", "print(\\n", " one\_episode\_wealth.to\_string(\\n", " index=False, columns=\[\\"Step\\", \\"AgentID\\", \\"Wealth\\"\], max\_rows=10\\n", " )\\n", ")\\n", "# For a prettier display we can also convert the data frame to html\\n", "# Uncomment the two lines below to test in Jupyter\\n", "# from IPython.display import display, HTML\\n", "# display(HTML(one\_episode\_wealth.to\_html(index=False, columns=\['Step',\\n", "# 'AgentID', 'Wealth'\], max\_rows=25)))" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "Lastly, we want to take a look at the development of the Gini coefficient over the course of one iteration. Filtering and printing looks almost the same as above, only this time we choose a different episode." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "results\_one\_episode = results\_df\[\\n", " (results\_df.n == 10) & (results\_df.iteration == 1) & (results\_df.AgentID == 1)\\n", "\]\\n", "print(results\_one\_episode.to\_string(index=False, columns=\[\\"Step\\", \\"Gini\\"\], max\_rows=10))" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Next Steps\\n", "\\n", "Check out the \[comparing 5 scenarios\](https://mesa.readthedocs.io/latest/tutorials/8\_comparing\_scenarios.html) on analyzing \`batch\_run\` results." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "\[Comer2014\] Comer, Kenneth W. “Who Goes First? An Examination of the Impact of Activation on Outcome Behavior in AgentBased Models.” George Mason University, 2014. http://mars.gmu.edu/bitstream/handle/1920/9070/Comer\_gmu\_0883E\_10539.pdf\\n", "\\n", "\[Dragulescu2002\] Drăgulescu, Adrian A., and Victor M. Yakovenko. “Statistical Mechanics of Money, Income, and Wealth: A Short Survey.” arXiv Preprint Cond-mat/0211175, 2002. http://arxiv.org/abs/cond-mat/0211175." \] } \], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display\_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language\_info": { "codemirror\_mode": { "name": "ipython", "version": 3 }, "file\_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert\_exporter": "python", "pygments\_lexer": "ipython3", "version": "3.12.5" }, "widgets": { "state": {}, "version": "1.1.2" } }, "nbformat": 4, "nbformat\_minor": 4 }
---
# Unknown
{ "cells": \[ { "cell\_type": "markdown", "metadata": {}, "source": \[ "# Comparing Scenarios\\n", "\\n", "### The Boltzmann Wealth Model " \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "If you want to get straight to the tutorial checkout these environment providers: \
\\n", "(with Google Account) \[!\[Colab\](https://colab.research.google.com/assets/colab-badge.svg)\](https://colab.research.google.com/github/projectmesa/mesa/blob/main/docs/tutorials/8\_comparing\_scenarios.ipynb) \
\\n", "(No Google Account) \[!\[Binder\](https://mybinder.org/badge\_logo.svg)\](https://mybinder.org/v2/gh/projectmesa/mesa/main?labpath=docs%2Ftutorials%2F8\_comparing\_scenarios.ipynb) (This can take 30 seconds to 5 minutes to load)\\n", "\\n", "\*If you are running locally, please ensure you have the latest Mesa version installed.\*\\n", "\\n", "## Tutorial Description\\n", "\\n", "This tutorial extends the Boltzmann wealth model from the \[Batch Run tutorial\](https://mesa.readthedocs.io/latest/tutorials/2\_batch\_run.html), by showing some ways in which users can analyze \`batch\_run\` results. \\n", "\\n", "\*If you are starting here please see the \[Running Your First Model tutorial\](https://mesa.readthedocs.io/latest/tutorials/0\_first\_model.html) for dependency and start-up instructions\*" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### IN COLAB? - Run the next cell " \] }, { "cell\_type": "raw", "metadata": { "vscode": { "languageId": "raw" } }, "source": \[ "%pip install --quiet mesa\[rec\]" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Import Dependencies\\n", "This includes importing of dependencies needed for the tutorial." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "outputs": \[\], "source": \[ "# Has multi-dimensional arrays and matrices.\\n", "# Has a large collection of mathematical functions to operate on these arrays.\\n", "import numpy as np\\n", "\\n", "# Data manipulation and analysis.\\n", "import pandas as pd\\n", "\\n", "# Data visualization tools.\\n", "import seaborn as sns\\n", "\\n", "import mesa\\n", "\\n", "# Import Cell Agent and OrthogonalMooreGrid\\n", "from mesa.discrete\_space import CellAgent, OrthogonalMooreGrid" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Base Model\\n", "\\n", "The below provides the base model from which we conduct a parameter sweep by altering the population parameter and running each variation for 5 scenarios. \\n", "\\n", "This is from the \[Batch Run tutorial\](https://mesa.readthedocs.io/latest/tutorials/7\_batch\_run.html) tutorial. If you have any questions about it functionality please review that tutorial." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "def compute\_gini(model):\\n", " agent\_wealths = \[agent.wealth for agent in model.agents\]\\n", " x = sorted(agent\_wealths)\\n", " n = model.num\_agents\\n", " B = sum(xi \* (n - i) for i, xi in enumerate(x)) / (n \* sum(x))\\n", " return 1 + (1 / n) - 2 \* B\\n", "\\n", "\\n", "class MoneyAgent(CellAgent):\\n", " \\"\\"\\"An agent with fixed initial wealth.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, model, cell):\\n", " super().\_\_init\_\_(model)\\n", " self.cell = cell\\n", " self.wealth = 1\\n", " self.steps\_not\_given = 0\\n", "\\n", " def move(self):\\n", " self.cell = self.cell.neighborhood.select\_random\_cell()\\n", "\\n", " def give\_money(self):\\n", " cellmates = \[a for a in self.cell.agents if a is not self\]\\n", "\\n", " if len(cellmates) > 0 and self.wealth > 0:\\n", " other = self.random.choice(cellmates)\\n", " other.wealth += 1\\n", " self.wealth -= 1\\n", " self.steps\_not\_given = 0\\n", " else:\\n", " self.steps\_not\_given += 1\\n", "\\n", "\\n", "class MoneyModel(mesa.Model):\\n", " \\"\\"\\"A model with some number of agents.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, n, width, height, seed=None):\\n", " super().\_\_init\_\_(seed=seed)\\n", " self.num\_agents = n\\n", " self.grid = OrthogonalMooreGrid(\\n", " (width, height), torus=True, capacity=10, random=self.random\\n", " )\\n", " # Instantiate DataCollector\\n", " self.datacollector = mesa.DataCollector(\\n", " model\_reporters={\\"Gini\\": compute\_gini},\\n", " agent\_reporters={\\"Wealth\\": \\"wealth\\", \\"Steps\_not\_given\\": \\"steps\_not\_given\\"},\\n", " )\\n", " self.running = True\\n", "\\n", " # Create agents\\n", " agents = MoneyAgent.create\_agents(\\n", " self,\\n", " self.num\_agents,\\n", " self.random.choices(self.grid.all\_cells.cells, k=self.num\_agents),\\n", " )\\n", "\\n", " def step(self):\\n", " # Collect data each step\\n", " self.datacollector.collect(self)\\n", " self.agents.shuffle\_do(\\"move\\")\\n", " self.agents.do(\\"give\_money\\")" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "params = {\\"width\\": 10, \\"height\\": 10, \\"n\\": range(5, 105, 5)}\\n", "\\n", "results = mesa.batch\_run(\\n", " MoneyModel,\\n", " parameters=params,\\n", " iterations=5,\\n", " max\_steps=100,\\n", " number\_processes=1,\\n", " data\_collection\_period=1,\\n", " display\_progress=True,\\n", ")" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "We will now extract the results into a pandas dataframe." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "results\_df = pd.DataFrame(results)\\n", "print(f\\"The results have {len(results)} rows.\\")\\n", "print(f\\"The columns of the data frame are {list(results\_df.keys())}.\\")" \] }, { "cell\_type": "markdown", "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "source": \[ "### Analyzing model reporters: Comparing 5 scenarios\\n", "Other insights might be gathered when we compare the Gini coefficient of different scenarios. For example, we can compare the Gini coefficient of a population with 25 agents to the Gini coefficient of a population with 400 agents. While doing this, we increase the number of iterations to 25 to get a better estimate of the Gini coefficient for each population size and get usable error estimations.\\n", "\\n", "As we look varying the parameters to see the impact on model outcomes, it is critical to again point out that users can set the random seed. Due to the often inherent randomness with ABMs the seed becomes crucial for: \\n", "- \*\*Reproducibility\*\* - Being able to replicate the ABM results\\n", "- \*\*Sensitivity Analysis\*\* - Identifying how sensitive/robust your model results are to random fluctuations\\n", "\\n", "Treating the seed as an additional parameter and running numerous scenarios allows us to see the impact of randomness on this model. " \] }, { "cell\_type": "code", "execution\_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "outputs": \[\], "source": \[ "params = {\\"seed\\": None, \\"width\\": 10, \\"height\\": 10, \\"n\\": \[5, 10, 20, 40, 80\]}\\n", "\\n", "results\_5s = mesa.batch\_run(\\n", " MoneyModel,\\n", " parameters=params,\\n", " iterations=25,\\n", " max\_steps=100,\\n", " number\_processes=1,\\n", " data\_collection\_period=1, # Need to collect every step\\n", " display\_progress=True,\\n", ")\\n", "\\n", "results\_5s\_df = pd.DataFrame(results\_5s)" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "We filter the results to only contain the data of one agent" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "outputs": \[\], "source": \[ "# The Gini coefficient will be the same for the entire population at any time.\\n", "results\_5s\_df\_filtered = results\_5s\_df\[(results\_5s\_df.AgentID == 1)\]\\n", "results\_5s\_df\_filtered.head(3)" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "outputs": \[\], "source": \[ "# Create a lineplot with error bars\\n", "g = sns.lineplot(\\n", " data=results\_5s\_df,\\n", " x=\\"Step\\",\\n", " y=\\"Gini\\",\\n", " hue=\\"n\\",\\n", " errorbar=(\\"ci\\", 95),\\n", " palette=\\"tab10\\",\\n", ")\\n", "g.figure.set\_size\_inches(8, 4)\\n", "plot\_title = (\\n", " \\"Gini coefficient for different population sizes\\\\n\\"\\n", " \\"(mean over 100 runs, with 95% confidence interval)\\"\\n", ")\\n", "g.set(title=plot\_title, ylabel=\\"Gini coefficient\\");" \] }, { "cell\_type": "markdown", "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "source": \[ "In this case it looks like the Gini coefficient increases slower for smaller populations. This can be because of different things, either because the Gini coefficient is a measure of inequality and the smaller the population, the more likely it is that the agents are all in the same wealth class, or because there are less interactions between agents in smaller populations, which means that the wealth of an agent is less likely to change." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Exercise:\\n", "Treat the seed as a parameter and see the impact on the Gini Coefficient\\n", "\\n", "You can also plot the seeds against the Gini Coefficient by changing the \\"hue\\" parameter in sns.lineplot function." \] }, { "cell\_type": "markdown", "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "source": \[ "### Analyzing agent reporters: Comparing 5 scenarios\\n", "From the agents we collected the wealth and the number of consecutive rounds without a transaction. We can compare the 5 different population sizes by plotting the average number of consecutive rounds without a transaction for each population size.\\n", "\\n", "Note that we're aggregating multiple times here: First we take the average of all agents for each single replication. Then we plot the averages for all replications, with the error band showing the 95% confidence interval of that first average (over all agents). So this error band is representing the uncertainty of the mean value of the number of consecutive rounds without a transaction for each population size." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "outputs": \[\], "source": \[ "# Calculate the mean of the wealth and the number of consecutive rounds\\n", "# for all agents in each episode.\\n", "agg\_results\_df = (\\n", " results\_5s\_df.groupby(\[\\"iteration\\", \\"n\\", \\"Step\\"\])\\n", " .agg({\\"Wealth\\": \\"mean\\", \\"Steps\_not\_given\\": \\"mean\\"})\\n", " .reset\_index()\\n", ")\\n", "agg\_results\_df.head(3)" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "outputs": \[\], "source": \[ "# Create a line plot with error bars\\n", "g = sns.lineplot(\\n", " data=agg\_results\_df, x=\\"Step\\", y=\\"Steps\_not\_given\\", hue=\\"n\\", palette=\\"tab10\\"\\n", ")\\n", "g.figure.set\_size\_inches(8, 4)\\n", "g.set(\\n", " title=\\"Average number of consecutive rounds without a transaction for \\"\\n", " \\"different population sizes\\\\n(mean with 95% confidence interval)\\",\\n", " ylabel=\\"Consecutive rounds without a transaction\\",\\n", ");" \] }, { "cell\_type": "markdown", "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "source": \[ "It can be clearly seen that the lower the number of agents, the higher the number of consecutive rounds without a transaction. This is because the agents have fewer interactions with each other and therefore the wealth of an agent is less likely to change." \] }, { "cell\_type": "markdown", "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "source": \[ "### General steps for analyzing results\\n", "\\n", "Many other analysis are possible based on the policies, scenarios and uncertainties that you might be interested in. In general, you can follow these steps to do your own analysis:\\n", "\\n", "1. Determine which metrics you want to analyse. Add these as model and agent reporters to the datacollector of your model.\\n", "2. Determine the input parameters you want to vary. Add these as parameters to the batch\_run function, using ranges or lists to test different values.\\n", "3. Determine the hyperparameters of the batch\_run function. Define the number of iterations, the number of processes, the number of steps, the data collection period, etc.\\n", "4. Run the batch\_run function and save the results.\\n", "5. Transform, filter and aggregate the results to get the data you want to analyze. Make sure it's in long format, so that each row represents a single value.\\n", "6. Choose a plot type, what to plot on the x and y axis, which columns to use for the hue. Seaborn also has an amazing \[Example Gallery\](https://seaborn.pydata.org/examples/index.html).\\n", "7. Plot the data and analyze the results." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Exercise: \\n", "Update the model in some new way (e.g. a new agent attribute, a new model reporter), conduct a batch run with a parameter sweep and visualize your results" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## That is it you have successfully completed Mesa's Introductory Tutorial!" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### More Mesa\\n", "\\n", "If you are looking for other Mesa models or tools here are some additional resources. \\n", "\\n", "- Interactive Dashboard: There is a separate \[visualization tutorial\](https://mesa.readthedocs.io/latest/tutorials/visualization\_tutorial.html) that will take users through building a dashboard for this model (aka Boltzmann Wealth Model).\\n", "- Example ABMs: Find canonical examples and examples of ABMs demonstrating highlighted features in the \[Examples Tab\](https://mesa.readthedocs.io/stable/examples.html)\\n", "- Expanded Examples: Want to integrate Reinforcement Learning or work on the Traveling Salesman Problem? Checkout \[Mesa Examples\](https://github.com/projectmesa/mesa-examples/)\\n", "- Mesa-Geo: If you need an ABM with Geographic Information Systems (GIS) checkout \[Mesa-Geo\](https://mesa-geo.readthedocs.io/latest/)\\n", "- Mesa Frames: Have a large complex model that you need to speed up, check out \[Mesa Frames\](https://github.com/projectmesa/mesa-frames)" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Happy Modeling!\\n", "\\n", "This document is a work in progress. If you see any errors, exclusions or have any problems please contact \[us\](https://github.com/projectmesa/mesa/issues)." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "\[Comer2014\] Comer, Kenneth W. “Who Goes First? An Examination of the Impact of Activation on Outcome Behavior in AgentBased Models.” George Mason University, 2014. http://mars.gmu.edu/bitstream/handle/1920/9070/Comer\_gmu\_0883E\_10539.pdf\\n", "\\n", "\[Dragulescu2002\] Drăgulescu, Adrian A., and Victor M. Yakovenko. “Statistical Mechanics of Money, Income, and Wealth: A Short Survey.” arXiv Preprint Cond-mat/0211175, 2002. http://arxiv.org/abs/cond-mat/0211175." \] } \], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display\_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language\_info": { "codemirror\_mode": { "name": "ipython", "version": 3 }, "file\_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert\_exporter": "python", "pygments\_lexer": "ipython3", "version": "3.12.5" }, "widgets": { "state": {}, "version": "1.1.2" } }, "nbformat": 4, "nbformat\_minor": 4 }
---
# Unknown
\# Schelling Segregation Model ## Summary The Schelling segregation model is a classic agent-based model, demonstrating how even a mild preference for similar neighbors can lead to a much higher degree of segregation than we would intuitively expect. The model consists of agents on a square grid, where each grid cell can contain at most one agent. Agents come in two colors: red and blue. They are happy if a certain number of their eight possible neighbors are of the same color, and unhappy otherwise. Unhappy agents will pick a random empty cell to move to each step, until they are happy. The model keeps running until there are no unhappy agents. By default, the number of similar neighbors the agents need to be happy is set to 3. That means the agents would be perfectly happy with a majority of their neighbors being of a different color (e.g. a Blue agent would be happy with five Red neighbors and three Blue ones). Despite this, the model consistently leads to a high degree of segregation, with most agents ending up with no neighbors of a different color. ## How to Run To run the model interactively, in this directory, run the following command \`\`\` $ solara run app.py \`\`\` Then open your browser to \[http://127.0.0.1:8765/\](http://127.0.0.1:8765/) and click the Play button. To view and run some example model analyses, launch the IPython Notebook and open \`\`analysis.ipynb\`\`. Visualizing the analysis also requires \[matplotlib\](http://matplotlib.org/). ## How to Run without the GUI To run the model with the grid displayed as an ASCII text, run \`python run\_ascii.py\` in this directory. ## Files \* \`\`model.py\`\`: Contains the Schelling model class \* \`\`agents.py\`\`: Contains the Schelling agent class \* \`\`app.py\`\`: Code for the interactive visualization. \* \`\`analysis.ipynb\`\`: Notebook demonstrating how to run experiments and parameter sweeps on the model. ## Further Reading Schelling's original paper describing the model: \[Schelling, Thomas C. Dynamic Models of Segregation. Journal of Mathematical Sociology. 1971, Vol. 1, pp 143-186.\](https://www.stat.berkeley.edu/~aldous/157/Papers/Schelling\_Seg\_Models.pdf) An interactive, browser-based explanation and implementation: \[Parable of the Polygons\](http://ncase.me/polygons/), by Vi Hart and Nicky Case. ## Agents \`\`\`python from mesa.discrete\_space import CellAgent class SchellingAgent(CellAgent): """Schelling segregation agent.""" def \_\_init\_\_( self, model, cell, agent\_type: int, homophily: float = 0.4, radius: int = 1 ) -> None: """Create a new Schelling agent. Args: model: The model instance the agent belongs to agent\_type: Indicator for the agent's type (minority=1, majority=0) homophily: Minimum number of similar neighbors needed for happiness radius: Search radius for checking neighbor similarity """ super().\_\_init\_\_(model) self.cell = cell self.type = agent\_type self.homophily = homophily self.radius = radius def step(self) -> None: """Determine if agent is happy and move if necessary.""" neighbors = list(self.cell.get\_neighborhood(radius=self.radius).agents) # Count similar neighbors similar\_neighbors = len(\[n for n in neighbors if n.type == self.type\]) # Calculate the fraction of similar neighbors if (valid\_neighbors := len(neighbors)) > 0: similarity\_fraction = similar\_neighbors / valid\_neighbors else: # If there are no neighbors, the similarity fraction is 0 similarity\_fraction = 0.0 # Move if unhappy if similarity\_fraction < self.homophily: self.cell = self.model.grid.select\_random\_empty\_cell() else: self.model.happy += 1 \`\`\` ## Model \`\`\`python from mesa import Model from mesa.datacollection import DataCollector from mesa.discrete\_space import OrthogonalMooreGrid from mesa.examples.basic.schelling.agents import SchellingAgent class Schelling(Model): """Model class for the Schelling segregation model.""" def \_\_init\_\_( self, height: int = 20, width: int = 20, density: float = 0.8, minority\_pc: float = 0.5, homophily: float = 0.4, radius: int = 1, seed=None, ): """Create a new Schelling model. Args: width: Width of the grid height: Height of the grid density: Initial chance for a cell to be populated (0-1) minority\_pc: Chance for an agent to be in minority class (0-1) homophily: Minimum number of similar neighbors needed for happiness radius: Search radius for checking neighbor similarity seed: Seed for reproducibility """ super().\_\_init\_\_(seed=seed) # Model parameters self.density = density self.minority\_pc = minority\_pc # Initialize grid self.grid = OrthogonalMooreGrid((width, height), random=self.random, capacity=1) # Track happiness self.happy = 0 # Set up data collection self.datacollector = DataCollector( model\_reporters={ "happy": "happy", "pct\_happy": lambda m: (m.happy / len(m.agents)) \* 100 if len(m.agents) > 0 else 0, "population": lambda m: len(m.agents), "minority\_pct": lambda m: ( sum(1 for agent in m.agents if agent.type == 1) / len(m.agents) \* 100 if len(m.agents) > 0 else 0 ), }, agent\_reporters={"agent\_type": "type"}, ) # Create agents and place them on the grid for cell in self.grid.all\_cells: if self.random.random() < self.density: agent\_type = 1 if self.random.random() < minority\_pc else 0 SchellingAgent( self, cell, agent\_type, homophily=homophily, radius=radius ) # Collect initial state self.datacollector.collect(self) def step(self): """Run one step of the model.""" self.happy = 0 # Reset counter of happy agents self.agents.shuffle\_do("step") # Activate all agents in random order self.datacollector.collect(self) # Collect data self.running = self.happy < len(self.agents) # Continue until everyone is happy \`\`\` ## App \`\`\`python import solara from mesa.examples.basic.schelling.model import Schelling from mesa.visualization import ( Slider, SolaraViz, make\_plot\_component, make\_space\_component, ) def get\_happy\_agents(model): """Display a text count of how many happy agents there are.""" return solara.Markdown(f"\*\*Happy agents: {model.happy}\*\*") def agent\_portrayal(agent): return {"color": "tab:orange" if agent.type == 0 else "tab:blue"} model\_params = { "seed": { "type": "InputText", "value": 42, "label": "Random Seed", }, "density": Slider("Agent density", 0.8, 0.1, 1.0, 0.1), "minority\_pc": Slider("Fraction minority", 0.2, 0.0, 1.0, 0.05), "homophily": Slider("Homophily", 0.4, 0.0, 1.0, 0.125), "width": 20, "height": 20, } model1 = Schelling() HappyPlot = make\_plot\_component({"happy": "tab:green"}) page = SolaraViz( model1, components=\[ make\_space\_component(agent\_portrayal), HappyPlot, get\_happy\_agents, \], model\_params=model\_params, ) page # noqa \`\`\`
---
# Unknown
\# Agent \`\`\`{eval-rst} .. automodule:: mesa.agent :members: :inherited-members: \`\`\`
---
# Mesa: Agent-based modeling in Python — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Mesa: Agent-based modeling in Python[#](#mesa-agent-based-modeling-in-python "Link to this heading")
=====================================================================================================
[](https://doi.org/10.21105/joss.07668)
[](https://github.com/projectmesa/mesa/actions)
[](https://codecov.io/gh/projectmesa/mesa)
[](https://github.com/psf/black)
[](https://matrix.to/#/#project-mesa:matrix.org)
[Mesa](https://github.com/projectmesa/mesa/)
is an Apache2 licensed agent-based modeling (or ABM) framework in Python.
Mesa allows users to quickly create agent-based models using built-in core components (such as spatial grids and agent schedulers) or customized implementations; visualize them using a browser-based interface; and analyze their results using Python’s data analysis tools. Mesa’s goal is to make simulations accessible to everyone, so humanity can more effectively understand and solve complex problems.
 _A visualisation of the Wolf Sheep model build with Mesa._
Features[#](#features "Link to this heading")
----------------------------------------------
* Built-in core modeling components
* Flexible agent and model management through AgentSet
* Browser-based Solara visualization
* Built-in tools for data collection and analysis
* Example model library
Using Mesa[#](#using-mesa "Link to this heading")
--------------------------------------------------
### Installation Options[#](#installation-options "Link to this heading")
To install our latest stable release, run:
pip install \-U mesa
To also install our recommended dependencies:
pip install \-U mesa\[rec\]
The `[rec]` option installs additional recommended dependencies needed for visualization, plotting, and network modeling capabilities.
On a Mac, this command might cause an error stating `zsh: no matches found: mesa[all]`. In that case, change the command to `pip install -U "mesa[rec]"`.
### Resources[#](#resources "Link to this heading")
For help getting started with Mesa, check out these resources:
* [Getting started](getting_started.html)
- Learn about Mesa’s core concepts and components
* [Migration Guide](migration_guide.html)
- Upgrade to Mesa 3.0
* [Mesa Examples](https://mesa.readthedocs.io/stable/examples.html)
- Browse user-contributed models and implementations
* [Mesa Extensions](mesa_extension.html)
- Overview of mesa’s Extensions
* [GitHub Discussions](https://github.com/projectmesa/mesa/discussions)
- Ask questions and discuss Mesa
* [Matrix Chat Room](https://matrix.to/#/#project-mesa:matrix.org)
- Real-time chat with the Mesa community
### Development and Support[#](#development-and-support "Link to this heading")
Mesa is an open source project and welcomes contributions:
* [GitHub Repository](https://github.com/projectmesa/mesa/)
- Access the source code
* [Issue Tracker](https://github.com/projectmesa/mesa/issues)
- Report bugs or suggest features
* [Contributors Guide](https://github.com/projectmesa/mesa/blob/main/CONTRIBUTING.md)
- Learn how to contribute
### Citing Mesa[#](#citing-mesa "Link to this heading")
To cite Mesa in your publication, you can refer to our peer-reviewed article in the Journal of Open Source Software (JOSS):
* ter Hoeven, E., Kwakkel, J., Hess, V., Pike, T., Wang, B., rht, & Kazil, J. (2025). Mesa 3: Agent-based modeling with Python in 2025. Journal of Open Source Software, 10(107), 7668. https://doi.org/10.21105/joss.07668
Our [CITATION.cff](https://github.com/projectmesa/mesa/blob/main/CITATION.cff)
can be used to generate APA, BibTeX and other citation formats.
The original Mesa conference paper from 2015 is [available here](http://conference.scipy.org.s3-website-us-east-1.amazonaws.com/proceedings/scipy2015/jacqueline_kazil.html)
.
Indices and tables[#](#indices-and-tables "Link to this heading")
==================================================================
* [Index](genindex.html)
* [Module Index](py-modindex.html)
* [Search Page](search.html)
On this page
### This Page
* [Show Source](_sources/index.md.txt)
---
# Unknown
\# Data collection \`\`\`{eval-rst} .. automodule:: datacollection :members: \`\`\`
---
# Unknown
\# Virus on a Network ## Summary This model is based on the NetLogo model "Virus on Network". It demonstrates the spread of a virus through a network and follows the SIR model, commonly seen in epidemiology. The SIR model is one of the simplest compartmental models, and many models are derivatives of this basic form. The model consists of three compartments: S: The number of susceptible individuals. When a susceptible and an infectious individual come into "infectious contact", the susceptible individual contracts the disease and transitions to the infectious compartment. I: The number of infectious individuals. These are individuals who have been infected and are capable of infecting susceptible individuals. R for the number of removed (and immune) or deceased individuals. These are individuals who have been infected and have either recovered from the disease and entered the removed compartment, or died. It is assumed that the number of deaths is negligible with respect to the total population. This compartment may also be called "recovered" or "resistant". For more information about this model, read the NetLogo's web page: http://ccl.northwestern.edu/netlogo/models/VirusonaNetwork. JavaScript library used in this example to render the network: \[d3.js\](https://d3js.org/). ## Installation To install the dependencies use pip and the requirements.txt in this directory. e.g. \`\`\` $ pip install -r requirements.txt \`\`\` ## How to Run To run the model interactively, in this directory, run the following command \`\`\` $ solara run app.py \`\`\` ## Files \* \`\`model.py\`\`: Contains the agent class, and the overall model class. \* \`\`agents.py\`\`: Contains the agent class. \* \`\`app.py\`\`: Contains the code for the interactive Solara visualization. ## Further Reading The full tutorial describing how the model is built can be found at: https://mesa.readthedocs.io/en/latest/tutorials/intro\_tutorial.html \[Stonedahl, F. and Wilensky, U. (2008). NetLogo Virus on a Network model\](http://ccl.northwestern.edu/netlogo/models/VirusonaNetwork). Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL. \[Wilensky, U. (1999). NetLogo\](http://ccl.northwestern.edu/netlogo/) Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL. ## Agents \`\`\`python from enum import Enum from mesa.discrete\_space import FixedAgent class State(Enum): SUSCEPTIBLE = 0 INFECTED = 1 RESISTANT = 2 class VirusAgent(FixedAgent): """Individual Agent definition and its properties/interaction methods.""" def \_\_init\_\_( self, model, initial\_state, virus\_spread\_chance, virus\_check\_frequency, recovery\_chance, gain\_resistance\_chance, cell, ): super().\_\_init\_\_(model) self.state = initial\_state self.virus\_spread\_chance = virus\_spread\_chance self.virus\_check\_frequency = virus\_check\_frequency self.recovery\_chance = recovery\_chance self.gain\_resistance\_chance = gain\_resistance\_chance self.cell = cell def try\_to\_infect\_neighbors(self): for agent in self.cell.neighborhood.agents: if (agent.state is State.SUSCEPTIBLE) and ( self.random.random() < self.virus\_spread\_chance ): agent.state = State.INFECTED def try\_gain\_resistance(self): if self.random.random() < self.gain\_resistance\_chance: self.state = State.RESISTANT def try\_remove\_infection(self): # Try to remove if self.random.random() < self.recovery\_chance: # Success self.state = State.SUSCEPTIBLE self.try\_gain\_resistance() else: # Failed self.state = State.INFECTED def check\_situation(self): if (self.state is State.INFECTED) and ( self.random.random() < self.virus\_check\_frequency ): self.try\_remove\_infection() def step(self): if self.state is State.INFECTED: self.try\_to\_infect\_neighbors() self.check\_situation() \`\`\` ## Model \`\`\`python import math import networkx as nx import mesa from mesa import Model from mesa.discrete\_space import CellCollection, Network from mesa.examples.basic.virus\_on\_network.agents import State, VirusAgent def number\_state(model, state): return sum(1 for a in model.grid.all\_cells.agents if a.state is state) def number\_infected(model): return number\_state(model, State.INFECTED) def number\_susceptible(model): return number\_state(model, State.SUSCEPTIBLE) def number\_resistant(model): return number\_state(model, State.RESISTANT) class VirusOnNetwork(Model): """A virus model with some number of agents.""" def \_\_init\_\_( self, num\_nodes=10, avg\_node\_degree=3, initial\_outbreak\_size=1, virus\_spread\_chance=0.4, virus\_check\_frequency=0.4, recovery\_chance=0.3, gain\_resistance\_chance=0.5, seed=None, ): super().\_\_init\_\_(seed=seed) prob = avg\_node\_degree / num\_nodes graph = nx.erdos\_renyi\_graph(n=num\_nodes, p=prob) self.grid = Network(graph, capacity=1, random=self.random) self.initial\_outbreak\_size = ( initial\_outbreak\_size if initial\_outbreak\_size <= num\_nodes else num\_nodes ) self.datacollector = mesa.DataCollector( { "Infected": number\_infected, "Susceptible": number\_susceptible, "Resistant": number\_resistant, "R over S": self.resistant\_susceptible\_ratio, } ) VirusAgent.create\_agents( self, num\_nodes, State.SUSCEPTIBLE, virus\_spread\_chance, virus\_check\_frequency, recovery\_chance, gain\_resistance\_chance, list(self.grid.all\_cells), ) # Infect some nodes infected\_nodes = CellCollection( self.random.sample(list(self.grid.all\_cells), self.initial\_outbreak\_size), random=self.random, ) for a in infected\_nodes.agents: a.state = State.INFECTED self.running = True self.datacollector.collect(self) def resistant\_susceptible\_ratio(self): try: return number\_state(self, State.RESISTANT) / number\_state( self, State.SUSCEPTIBLE ) except ZeroDivisionError: return math.inf def step(self): self.agents.shuffle\_do("step") # collect data self.datacollector.collect(self) \`\`\` ## App \`\`\`python import math import solara from mesa.examples.basic.virus\_on\_network.model import ( State, VirusOnNetwork, number\_infected, ) from mesa.visualization import ( Slider, SolaraViz, make\_plot\_component, make\_space\_component, ) def agent\_portrayal(agent): node\_color\_dict = { State.INFECTED: "tab:red", State.SUSCEPTIBLE: "tab:green", State.RESISTANT: "tab:gray", } return {"color": node\_color\_dict\[agent.state\], "size": 10} def get\_resistant\_susceptible\_ratio(model): ratio = model.resistant\_susceptible\_ratio() ratio\_text = r"$\\infty$" if ratio is math.inf else f"{ratio:.2f}" infected\_text = str(number\_infected(model)) return solara.Markdown( f"Resistant/Susceptible Ratio: {ratio\_text}
Infected Remaining: {infected\_text}" ) model\_params = { "seed": { "type": "InputText", "value": 42, "label": "Random Seed", }, "num\_nodes": Slider( label="Number of agents", value=10, min=10, max=100, step=1, ), "avg\_node\_degree": Slider( label="Avg Node Degree", value=3, min=3, max=8, step=1, ), "initial\_outbreak\_size": Slider( label="Initial Outbreak Size", value=1, min=1, max=10, step=1, ), "virus\_spread\_chance": Slider( label="Virus Spread Chance", value=0.4, min=0.0, max=1.0, step=0.1, ), "virus\_check\_frequency": Slider( label="Virus Check Frequency", value=0.4, min=0.0, max=1.0, step=0.1, ), "recovery\_chance": Slider( label="Recovery Chance", value=0.3, min=0.0, max=1.0, step=0.1, ), "gain\_resistance\_chance": Slider( label="Gain Resistance Chance", value=0.5, min=0.0, max=1.0, step=0.1, ), } def post\_process\_lineplot(ax): ax.set\_ylim(ymin=0) ax.set\_ylabel("# people") ax.legend(bbox\_to\_anchor=(1.05, 1.0), loc="upper left") SpacePlot = make\_space\_component(agent\_portrayal) StatePlot = make\_plot\_component( {"Infected": "tab:red", "Susceptible": "tab:green", "Resistant": "tab:gray"}, post\_process=post\_process\_lineplot, ) model1 = VirusOnNetwork() page = SolaraViz( model1, components=\[ SpacePlot, StatePlot, get\_resistant\_susceptible\_ratio, \], model\_params=model\_params, name="Virus Model", ) page # noqa \`\`\`
---
# Unknown
\# Wolf-Sheep Predation Model ## Summary A simple ecological model, consisting of three agent types: wolves, sheep, and grass. The wolves and the sheep wander around the grid at random. Wolves and sheep both expend energy moving around, and replenish it by eating. Sheep eat grass, and wolves eat sheep if they end up on the same grid cell. If wolves and sheep have enough energy, they reproduce, creating a new wolf or sheep (in this simplified model, only one parent is needed for reproduction). The grass on each cell regrows at a constant rate. If any wolves and sheep run out of energy, they die. The model is tests and demonstrates several Mesa concepts and features: - MultiGrid - Multiple agent types (wolves, sheep, grass) - Overlay arbitrary text (wolf's energy) on agent's shapes while drawing on CanvasGrid - Agents inheriting a behavior (random movement) from an abstract parent - Writing a model composed of multiple files. - Dynamically adding and removing agents from the schedule ## Installation To install the dependencies use pip and the requirements.txt in this directory. e.g. \`\`\` # First, we clone the Mesa repo $ git clone https://github.com/projectmesa/mesa.git $ cd mesa # Then we cd to the example directory $ cd examples/wolf\_sheep $ pip install -r requirements.txt \`\`\` ## How to Run To run the model interactively, run \`\`mesa runserver\`\` in this directory. e.g. \`\`\` $ mesa runserver \`\`\` Then open your browser to \[http://127.0.0.1:8521/\](http://127.0.0.1:8521/) and press Reset, then Run. ## Files \* \`\`wolf\_sheep/random\_walk.py\`\`: This defines the \`\`RandomWalker\`\` agent, which implements the behavior of moving randomly across a grid, one cell at a time. Both the Wolf and Sheep agents will inherit from it. \* \`\`wolf\_sheep/test\_random\_walk.py\`\`: Defines a simple model and a text-only visualization intended to make sure the RandomWalk class was working as expected. This doesn't actually model anything, but serves as an ad-hoc unit test. To run it, \`\`cd\`\` into the \`\`wolf\_sheep\`\` directory and run \`\`python test\_random\_walk.py\`\`. You'll see a series of ASCII grids, one per model step, with each cell showing a count of the number of agents in it. \* \`\`wolf\_sheep/agents.py\`\`: Defines the Wolf, Sheep, and GrassPatch agent classes. \* \`\`wolf\_sheep/scheduler.py\`\`: Defines a custom variant on the RandomActivationByType scheduler, where we can define filters for the \`get\_type\_count\` function. \* \`\`wolf\_sheep/model.py\`\`: Defines the Wolf-Sheep Predation model itself \* \`\`wolf\_sheep/server.py\`\`: Sets up the interactive visualization server \* \`\`run.py\`\`: Launches a model visualization server. ## Further Reading This model is closely based on the NetLogo Wolf-Sheep Predation Model: Wilensky, U. (1997). NetLogo Wolf Sheep Predation model. http://ccl.northwestern.edu/netlogo/models/WolfSheepPredation. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL. See also the \[Lotka–Volterra equations \](https://en.wikipedia.org/wiki/Lotka%E2%80%93Volterra\_equations) for an example of a classic differential-equation model with similar dynamics. ## Agents \`\`\`python from mesa.discrete\_space import CellAgent, FixedAgent class Animal(CellAgent): """The base animal class.""" def \_\_init\_\_( self, model, energy=8, p\_reproduce=0.04, energy\_from\_food=4, cell=None ): """Initialize an animal. Args: model: Model instance energy: Starting amount of energy p\_reproduce: Probability of reproduction (asexual) energy\_from\_food: Energy obtained from 1 unit of food cell: Cell in which the animal starts """ super().\_\_init\_\_(model) self.energy = energy self.p\_reproduce = p\_reproduce self.energy\_from\_food = energy\_from\_food self.cell = cell def spawn\_offspring(self): """Create offspring by splitting energy and creating new instance.""" self.energy /= 2 self.\_\_class\_\_( self.model, self.energy, self.p\_reproduce, self.energy\_from\_food, self.cell, ) def feed(self): """Abstract method to be implemented by subclasses.""" def step(self): """Execute one step of the animal's behavior.""" # Move to random neighboring cell self.move() self.energy -= 1 # Try to feed self.feed() # Handle death and reproduction if self.energy < 0: self.remove() elif self.random.random() < self.p\_reproduce: self.spawn\_offspring() class Sheep(Animal): """A sheep that walks around, reproduces (asexually) and gets eaten.""" def feed(self): """If possible, eat grass at current location.""" grass\_patch = next( obj for obj in self.cell.agents if isinstance(obj, GrassPatch) ) if grass\_patch.fully\_grown: self.energy += self.energy\_from\_food grass\_patch.fully\_grown = False def move(self): """Move towards a cell where there isn't a wolf, and preferably with grown grass.""" cells\_without\_wolves = self.cell.neighborhood.select( lambda cell: not any(isinstance(obj, Wolf) for obj in cell.agents) ) # If all surrounding cells have wolves, stay put if len(cells\_without\_wolves) == 0: return # Among safe cells, prefer those with grown grass cells\_with\_grass = cells\_without\_wolves.select( lambda cell: any( isinstance(obj, GrassPatch) and obj.fully\_grown for obj in cell.agents ) ) # Move to a cell with grass if available, otherwise move to any safe cell target\_cells = ( cells\_with\_grass if len(cells\_with\_grass) > 0 else cells\_without\_wolves ) self.cell = target\_cells.select\_random\_cell() class Wolf(Animal): """A wolf that walks around, reproduces (asexually) and eats sheep.""" def feed(self): """If possible, eat a sheep at current location.""" sheep = \[obj for obj in self.cell.agents if isinstance(obj, Sheep)\] if sheep: # If there are any sheep present sheep\_to\_eat = self.random.choice(sheep) self.energy += self.energy\_from\_food sheep\_to\_eat.remove() def move(self): """Move to a neighboring cell, preferably one with sheep.""" cells\_with\_sheep = self.cell.neighborhood.select( lambda cell: any(isinstance(obj, Sheep) for obj in cell.agents) ) target\_cells = ( cells\_with\_sheep if len(cells\_with\_sheep) > 0 else self.cell.neighborhood ) self.cell = target\_cells.select\_random\_cell() class GrassPatch(FixedAgent): """A patch of grass that grows at a fixed rate and can be eaten by sheep.""" @property def fully\_grown(self): """Whether the grass patch is fully grown.""" return self.\_fully\_grown @fully\_grown.setter def fully\_grown(self, value: bool) -> None: """Set grass growth state and schedule regrowth if eaten.""" self.\_fully\_grown = value if not value: # If grass was just eaten self.model.simulator.schedule\_event\_relative( setattr, self.grass\_regrowth\_time, function\_args=\[self, "fully\_grown", True\], ) def \_\_init\_\_(self, model, countdown, grass\_regrowth\_time, cell): """Create a new patch of grass. Args: model: Model instance countdown: Time until grass is fully grown again grass\_regrowth\_time: Time needed to regrow after being eaten cell: Cell to which this grass patch belongs """ super().\_\_init\_\_(model) self.\_fully\_grown = countdown == 0 self.grass\_regrowth\_time = grass\_regrowth\_time self.cell = cell # Schedule initial growth if not fully grown if not self.fully\_grown: self.model.simulator.schedule\_event\_relative( setattr, countdown, function\_args=\[self, "fully\_grown", True\] ) \`\`\` ## Model \`\`\`python """ Wolf-Sheep Predation Model ================================ Replication of the model found in NetLogo: Wilensky, U. (1997). NetLogo Wolf Sheep Predation model. http://ccl.northwestern.edu/netlogo/models/WolfSheepPredation. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL. """ import math from mesa import Model from mesa.datacollection import DataCollector from mesa.discrete\_space import OrthogonalVonNeumannGrid from mesa.examples.advanced.wolf\_sheep.agents import GrassPatch, Sheep, Wolf from mesa.experimental.devs import ABMSimulator class WolfSheep(Model): """Wolf-Sheep Predation Model. A model for simulating wolf and sheep (predator-prey) ecosystem modelling. """ description = ( "A model for simulating wolf and sheep (predator-prey) ecosystem modelling." ) def \_\_init\_\_( self, width=20, height=20, initial\_sheep=100, initial\_wolves=50, sheep\_reproduce=0.04, wolf\_reproduce=0.05, wolf\_gain\_from\_food=20, grass=True, grass\_regrowth\_time=30, sheep\_gain\_from\_food=4, seed=None, simulator: ABMSimulator = None, ): """Create a new Wolf-Sheep model with the given parameters. Args: height: Height of the grid width: Width of the grid initial\_sheep: Number of sheep to start with initial\_wolves: Number of wolves to start with sheep\_reproduce: Probability of each sheep reproducing each step wolf\_reproduce: Probability of each wolf reproducing each step wolf\_gain\_from\_food: Energy a wolf gains from eating a sheep grass: Whether to have the sheep eat grass for energy grass\_regrowth\_time: How long it takes for a grass patch to regrow once it is eaten sheep\_gain\_from\_food: Energy sheep gain from grass, if enabled seed: Random seed simulator: ABMSimulator instance for event scheduling """ super().\_\_init\_\_(seed=seed) self.simulator = simulator self.simulator.setup(self) # Initialize model parameters self.height = height self.width = width self.grass = grass # Create grid using experimental cell space self.grid = OrthogonalVonNeumannGrid( \[self.height, self.width\], torus=True, capacity=math.inf, random=self.random, ) # Set up data collection model\_reporters = { "Wolves": lambda m: len(m.agents\_by\_type\[Wolf\]), "Sheep": lambda m: len(m.agents\_by\_type\[Sheep\]), } if grass: model\_reporters\["Grass"\] = lambda m: len( m.agents\_by\_type\[GrassPatch\].select(lambda a: a.fully\_grown) ) self.datacollector = DataCollector(model\_reporters) # Create sheep: Sheep.create\_agents( self, initial\_sheep, energy=self.rng.random((initial\_sheep,)) \* 2 \* sheep\_gain\_from\_food, p\_reproduce=sheep\_reproduce, energy\_from\_food=sheep\_gain\_from\_food, cell=self.random.choices(self.grid.all\_cells.cells, k=initial\_sheep), ) # Create Wolves: Wolf.create\_agents( self, initial\_wolves, energy=self.rng.random((initial\_wolves,)) \* 2 \* wolf\_gain\_from\_food, p\_reproduce=wolf\_reproduce, energy\_from\_food=wolf\_gain\_from\_food, cell=self.random.choices(self.grid.all\_cells.cells, k=initial\_wolves), ) # Create grass patches if enabled if grass: possibly\_fully\_grown = \[True, False\] for cell in self.grid: fully\_grown = self.random.choice(possibly\_fully\_grown) countdown = ( 0 if fully\_grown else self.random.randrange(0, grass\_regrowth\_time) ) GrassPatch(self, countdown, grass\_regrowth\_time, cell) # Collect initial data self.running = True self.datacollector.collect(self) def step(self): """Execute one step of the model.""" # First activate all sheep, then all wolves, both in random order self.agents\_by\_type\[Sheep\].shuffle\_do("step") self.agents\_by\_type\[Wolf\].shuffle\_do("step") # Collect data self.datacollector.collect(self) \`\`\` ## App \`\`\`python from mesa.examples.advanced.wolf\_sheep.agents import GrassPatch, Sheep, Wolf from mesa.examples.advanced.wolf\_sheep.model import WolfSheep from mesa.experimental.devs import ABMSimulator from mesa.visualization import ( CommandConsole, Slider, SolaraViz, make\_plot\_component, make\_space\_component, ) def wolf\_sheep\_portrayal(agent): if agent is None: return portrayal = { "size": 25, } if isinstance(agent, Wolf): portrayal\["color"\] = "tab:red" portrayal\["marker"\] = "o" portrayal\["zorder"\] = 2 elif isinstance(agent, Sheep): portrayal\["color"\] = "tab:cyan" portrayal\["marker"\] = "o" portrayal\["zorder"\] = 2 elif isinstance(agent, GrassPatch): if agent.fully\_grown: portrayal\["color"\] = "tab:green" else: portrayal\["color"\] = "tab:brown" portrayal\["marker"\] = "s" portrayal\["size"\] = 75 return portrayal model\_params = { "seed": { "type": "InputText", "value": 42, "label": "Random Seed", }, "grass": { "type": "Select", "value": True, "values": \[True, False\], "label": "grass regrowth enabled?", }, "grass\_regrowth\_time": Slider("Grass Regrowth Time", 20, 1, 50), "initial\_sheep": Slider("Initial Sheep Population", 100, 10, 300), "sheep\_reproduce": Slider("Sheep Reproduction Rate", 0.04, 0.01, 1.0, 0.01), "initial\_wolves": Slider("Initial Wolf Population", 10, 5, 100), "wolf\_reproduce": Slider( "Wolf Reproduction Rate", 0.05, 0.01, 1.0, 0.01, ), "wolf\_gain\_from\_food": Slider("Wolf Gain From Food Rate", 20, 1, 50), "sheep\_gain\_from\_food": Slider("Sheep Gain From Food", 4, 1, 10), } def post\_process\_space(ax): ax.set\_aspect("equal") ax.set\_xticks(\[\]) ax.set\_yticks(\[\]) def post\_process\_lines(ax): ax.legend(loc="center left", bbox\_to\_anchor=(1, 0.9)) space\_component = make\_space\_component( wolf\_sheep\_portrayal, draw\_grid=False, post\_process=post\_process\_space ) lineplot\_component = make\_plot\_component( {"Wolves": "tab:orange", "Sheep": "tab:cyan", "Grass": "tab:green"}, post\_process=post\_process\_lines, ) simulator = ABMSimulator() model = WolfSheep(simulator=simulator, grass=True) page = SolaraViz( model, components=\[space\_component, lineplot\_component, CommandConsole\], model\_params=model\_params, name="Wolf Sheep", simulator=simulator, ) page # noqa \`\`\`
---
# Unknown
\# Boids Flockers ## Summary An implementation of Craig Reynolds's Boids flocker model. Agents (simulated birds) try to fly towards the average position of their neighbors and in the same direction as them, while maintaining a minimum distance. This produces flocking behavior. This model tests Mesa's continuous space feature, and uses numpy arrays to represent vectors. ## How to Run \* To launch the visualization interactively, run \`\`solara run app.py\`\` in this directory.It will automatically open a browser page. ## Files \* \[model.py\](model.py): Ccntains the Boid Model \* \[agents.py\](agents.py): Contains the Boid agent \* \[app.py\](app.py): Solara based Visualization code. ## Further Reading The following link can be visited for more information on the boid flockers model: https://cs.stanford.edu/people/eroberts/courses/soco/projects/2008-09/modeling-natural-systems/boids.html ## Agents \`\`\`python """A Boid (bird-oid) agent for implementing Craig Reynolds's Boids flocking model. This implementation uses numpy arrays to represent vectors for efficient computation of flocking behavior. """ import numpy as np from mesa.experimental.continuous\_space import ContinuousSpaceAgent class Boid(ContinuousSpaceAgent): """A Boid-style flocker agent. The agent follows three behaviors to flock: - Cohesion: steering towards neighboring agents - Separation: avoiding getting too close to any other agent - Alignment: trying to fly in the same direction as neighbors Boids have a vision that defines the radius in which they look for their neighbors to flock with. Their speed (a scalar) and direction (a vector) define their movement. Separation is their desired minimum distance from any other Boid. """ def \_\_init\_\_( self, model, space, position=(0, 0), speed=1, direction=(1, 1), vision=1, separation=1, cohere=0.03, separate=0.015, match=0.05, ): """Create a new Boid flocker agent. Args: model: Model instance the agent belongs to speed: Distance to move per step direction: numpy vector for the Boid's direction of movement vision: Radius to look around for nearby Boids separation: Minimum distance to maintain from other Boids cohere: Relative importance of matching neighbors' positions (default: 0.03) separate: Relative importance of avoiding close neighbors (default: 0.015) match: Relative importance of matching neighbors' directions (default: 0.05) """ super().\_\_init\_\_(space, model) self.position = position self.speed = speed self.direction = direction self.vision = vision self.separation = separation self.cohere\_factor = cohere self.separate\_factor = separate self.match\_factor = match self.neighbors = \[\] self.angle = 0.0 # represents the angle at which the boid is moving def step(self): """Get the Boid's neighbors, compute the new vector, and move accordingly.""" neighbors, distances = self.get\_neighbors\_in\_radius(radius=self.vision) self.neighbors = \[n for n in neighbors if n is not self\] # If no neighbors, maintain current direction if not neighbors: self.position += self.direction \* self.speed return delta = self.space.calculate\_difference\_vector(self.position, agents=neighbors) cohere\_vector = delta.sum(axis=0) \* self.cohere\_factor separation\_vector = ( -1 \* delta\[distances < self.separation\].sum(axis=0) \* self.separate\_factor ) match\_vector = ( np.asarray(\[n.direction for n in neighbors\]).sum(axis=0) \* self.match\_factor ) # Update direction based on the three behaviors self.direction += (cohere\_vector + separation\_vector + match\_vector) / len( neighbors ) # Normalize direction vector self.direction /= np.linalg.norm(self.direction) # Move boid self.position += self.direction \* self.speed \`\`\` ## Model \`\`\`python """ Boids Flocking Model =================== A Mesa implementation of Craig Reynolds's Boids flocker model. Uses numpy arrays to represent vectors. """ import os import sys sys.path.insert(0, os.path.abspath("../../../..")) import numpy as np from mesa import Model from mesa.examples.basic.boid\_flockers.agents import Boid from mesa.experimental.continuous\_space import ContinuousSpace class BoidFlockers(Model): """Flocker model class. Handles agent creation, placement and scheduling.""" def \_\_init\_\_( self, population\_size=100, width=100, height=100, speed=1, vision=10, separation=2, cohere=0.03, separate=0.015, match=0.05, seed=None, ): """Create a new Boids Flocking model. Args: population\_size: Number of Boids in the simulation (default: 100) width: Width of the space (default: 100) height: Height of the space (default: 100) speed: How fast the Boids move (default: 1) vision: How far each Boid can see (default: 10) separation: Minimum distance between Boids (default: 2) cohere: Weight of cohesion behavior (default: 0.03) separate: Weight of separation behavior (default: 0.015) match: Weight of alignment behavior (default: 0.05) seed: Random seed for reproducibility (default: None) """ super().\_\_init\_\_(seed=seed) self.agent\_angles = np.zeros( population\_size ) # holds the angle representing the direction of all agents at a given step # Set up the space self.space = ContinuousSpace( \[\[0, width\], \[0, height\]\], torus=True, random=self.random, n\_agents=population\_size, ) # Create and place the Boid agents positions = self.rng.random(size=(population\_size, 2)) \* self.space.size directions = self.rng.uniform(-1, 1, size=(population\_size, 2)) Boid.create\_agents( self, population\_size, self.space, position=positions, direction=directions, cohere=cohere, separate=separate, match=match, speed=speed, vision=vision, separation=separation, ) # For tracking statistics self.average\_heading = None self.update\_average\_heading() # vectorizing the calculation of angles for all agents def calculate\_angles(self): d1 = np.array(\[agent.direction\[0\] for agent in self.agents\]) d2 = np.array(\[agent.direction\[1\] for agent in self.agents\]) self.agent\_angles = np.degrees(np.arctan2(d1, d2)) for agent, angle in zip(self.agents, self.agent\_angles): agent.angle = angle def update\_average\_heading(self): """Calculate the average heading (direction) of all Boids.""" if not self.agents: self.average\_heading = 0 return headings = np.array(\[agent.direction for agent in self.agents\]) mean\_heading = np.mean(headings, axis=0) self.average\_heading = np.arctan2(mean\_heading\[1\], mean\_heading\[0\]) def step(self): """Run one step of the model. All agents are activated in random order using the AgentSet shuffle\_do method. """ self.agents.shuffle\_do("step") self.update\_average\_heading() self.calculate\_angles() \`\`\` ## App \`\`\`python import os import sys from matplotlib.markers import MarkerStyle sys.path.insert(0, os.path.abspath("../../../..")) from mesa.examples.basic.boid\_flockers.model import BoidFlockers from mesa.visualization import Slider, SolaraViz, make\_space\_component # Pre-compute markers for different angles (e.g., every 10 degrees) MARKER\_CACHE = {} for angle in range(0, 360, 10): marker = MarkerStyle(10) marker.\_transform = marker.get\_transform().rotate\_deg(angle) MARKER\_CACHE\[angle\] = marker def boid\_draw(agent): neighbors = len(agent.neighbors) # Calculate the angle deg = agent.angle # Round to nearest 10 degrees rounded\_deg = round(deg / 10) \* 10 % 360 # using cached markers to speed things up if neighbors <= 1: return {"color": "red", "size": 20, "marker": MARKER\_CACHE\[rounded\_deg\]} elif neighbors >= 2: return {"color": "green", "size": 20, "marker": MARKER\_CACHE\[rounded\_deg\]} model\_params = { "seed": { "type": "InputText", "value": 42, "label": "Random Seed", }, "population\_size": Slider( label="Number of boids", value=100, min=10, max=200, step=10, ), "width": 100, "height": 100, "speed": Slider( label="Speed of Boids", value=5, min=1, max=20, step=1, ), "vision": Slider( label="Vision of Bird (radius)", value=10, min=1, max=50, step=1, ), "separation": Slider( label="Minimum Separation", value=2, min=1, max=20, step=1, ), } model = BoidFlockers() page = SolaraViz( model, components=\[make\_space\_component(agent\_portrayal=boid\_draw, backend="matplotlib")\], model\_params=model\_params, name="Boid Flocking Model", ) page # noqa \`\`\`
---
# Unknown
\## Discrete Space \`\`\`{eval-rst} .. automodule:: mesa.discrete\_space.\_\_init\_\_ :members: \`\`\` \`\`\`{eval-rst} .. automodule:: mesa.discrete\_space.cell :members: \`\`\` \`\`\`{eval-rst} .. automodule:: mesa.discrete\_space.cell\_agent :members: \`\`\` \`\`\`{eval-rst} .. automodule:: mesa.discrete\_space.cell\_collection :members: \`\`\` \`\`\`{eval-rst} .. automodule:: mesa.discrete\_space.discrete\_space :members: \`\`\` \`\`\`{eval-rst} .. automodule:: mesa.discrete\_space.grid :members: \`\`\` \`\`\`{eval-rst} .. automodule:: mesa.discrete\_space.network :members: \`\`\` \`\`\`{eval-rst} .. automodule:: mesa.discrete\_space.voronoi :members: \`\`\`
---
# Unknown
{ "cells": \[ { "cell\_type": "markdown", "metadata": {}, "source": \[ "# Visualization - Custom Components\\n", "\\n", "### The Boltzmann Wealth Model " \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "If you want to get straight to the tutorial checkout these environment providers: \
\\n", "\[!\[Binder\](https://mybinder.org/badge\_logo.svg)\](https://mybinder.org/v2/gh/projectmesa/mesa/main?labpath=docs%2Ftutorials%2F4\_visualization\_basic.ipynb) (This can take 30 seconds to 5 minutes to load)\\n", "\\n", "Due to conflict with Colab and Solara there are no colab links for this tutorial\\n", "\\n", "\*If you are running locally, please ensure you have the latest Mesa version installed.\*\\n", "\\n", "## Tutorial Description\\n", "\\n", "This tutorial extends the Boltzmann wealth model from the \[Visualization Basic Dashboard tutorial\](https://mesa.readthedocs.io/latest/tutorials/4\_visualization\_basic.html), by adding an interactive dashboard. \\n", "\\n", "In this portion, we will demonstrate how users can employ create dynamic agent representation with their Mesa dashboards. This is part two of three visualization tutorials. \\n", "\\n", "\*If you are starting here please see the \[Running Your First Model tutorial\](https://mesa.readthedocs.io/latest/tutorials/0\_first\_model.html) for dependency and start-up instructions\*" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Import Dependencies\\n", "This includes importing of dependencies needed for the tutorial." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": { "collapsed": false, "jupyter": { "outputs\_hidden": false } }, "outputs": \[\], "source": \[ "# Has multi-dimensional arrays and matrices.\\n", "# Has a large collection of mathematical functions to operate on these arrays.\\n", "import numpy as np\\n", "\\n", "# Data manipulation and analysis.\\n", "import pandas as pd\\n", "\\n", "# Data visualization tools.\\n", "import seaborn as sns\\n", "\\n", "import mesa\\n", "from mesa.discrete\_space import CellAgent, OrthogonalMooreGrid\\n", "from mesa.visualization import SolaraViz, make\_plot\_component, make\_space\_component" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Basic Model\\n", "\\n", "The following is the basic model we will be using to build the dashboard. This is the same model seen in tutorials 0-3. " \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "def compute\_gini(model):\\n", " agent\_wealths = \[agent.wealth for agent in model.agents\]\\n", " x = sorted(agent\_wealths)\\n", " N = model.num\_agents\\n", " B = sum(xi \* (N - i) for i, xi in enumerate(x)) / (N \* sum(x))\\n", " return 1 + (1 / N) - 2 \* B\\n", "\\n", "\\n", "class MoneyAgent(CellAgent):\\n", " \\"\\"\\"An agent with fixed initial wealth.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, model, cell):\\n", " \\"\\"\\"initialize a MoneyAgent instance.\\n", "\\n", " Args:\\n", " model: A model instance\\n", " \\"\\"\\"\\n", " super().\_\_init\_\_(model)\\n", " self.cell = cell\\n", " self.wealth = 1\\n", "\\n", " def move(self):\\n", " \\"\\"\\"Move the agent to a random neighboring cell.\\"\\"\\"\\n", " self.cell = self.cell.neighborhood.select\_random\_cell()\\n", "\\n", " def give\_money(self):\\n", " \\"\\"\\"Give 1 unit of wealth to a random agent in the same cell.\\"\\"\\"\\n", " cellmates = \[a for a in self.cell.agents if a is not self\]\\n", "\\n", " if cellmates: # Only give money if there are other agents present\\n", " other = self.random.choice(cellmates)\\n", " other.wealth += 1\\n", " self.wealth -= 1\\n", "\\n", " def step(self):\\n", " \\"\\"\\"do one step of the agent.\\"\\"\\"\\n", " self.move()\\n", " if self.wealth > 0:\\n", " self.give\_money()\\n", "\\n", "\\n", "class MoneyModel(mesa.Model):\\n", " \\"\\"\\"A model with some number of agents.\\"\\"\\"\\n", "\\n", " def \_\_init\_\_(self, n=10, width=10, height=10, seed=None):\\n", " \\"\\"\\"Initialize a MoneyModel instance.\\n", "\\n", " Args:\\n", " N: The number of agents.\\n", " width: width of the grid.\\n", " height: Height of the grid.\\n", " \\"\\"\\"\\n", " super().\_\_init\_\_(seed=seed)\\n", " self.num\_agents = n\\n", " self.grid = OrthogonalMooreGrid((width, height), random=self.random)\\n", "\\n", " # Create agents\\n", " MoneyAgent.create\_agents(\\n", " self,\\n", " self.num\_agents,\\n", " self.random.choices(self.grid.all\_cells.cells, k=self.num\_agents),\\n", " )\\n", "\\n", " self.datacollector = mesa.DataCollector(\\n", " model\_reporters={\\"Gini\\": compute\_gini}, agent\_reporters={\\"Wealth\\": \\"wealth\\"}\\n", " )\\n", " self.datacollector.collect(self)\\n", "\\n", " def step(self):\\n", " \\"\\"\\"do one step of the model\\"\\"\\"\\n", " self.agents.shuffle\_do(\\"step\\")\\n", " self.datacollector.collect(self)" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "# Lets make sure the model works\\n", "model = MoneyModel(100, 10, 10)\\n", "for \_ in range(20):\\n", " model.step()\\n", "\\n", "\\n", "data = model.datacollector.get\_agent\_vars\_dataframe()\\n", "# Use seaborn\\n", "g = sns.histplot(data\[\\"Wealth\\"\], discrete=True)\\n", "g.set(title=\\"Wealth distribution\\", xlabel=\\"Wealth\\", ylabel=\\"Number of Agents\\");" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "### Adding visualization\\n", "\\n", "So far, we've built a model, run it, and analyzed some output afterwards. However, one of the advantages of agent-based models is that we can often watch them run step by step, potentially spotting unexpected patterns, behaviors or bugs, or developing new intuitions, hypotheses, or insights. Other times, watching a model run can explain it to an unfamiliar audience better than static explanations. Like many ABM frameworks, Mesa allows you to create an interactive visualization of the model. In this section we'll walk through creating a visualization using built-in components, and (for advanced users) how to create a new visualization element.\\n", "\\n", "First, a quick explanation of how Mesa's interactive visualization works. The visualization is done in a browser window or Jupyter instance, using the \[Solara\](https://solara.dev/) framework, a pure Python, React-style web framework. Running \`solara run app.py\` will launch a web server, which runs the model, and displays model detail at each step via a plotting library. Alternatively, you can execute everything inside a Jupyter instance and display it inline.\\n", "\\n", "\*Thanks to @Corvince for all his work creating Mesa's visualization capability\*" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Building Custom Components\\n", "\\n", "This section is for users who have a basic familiarity with Python's Matplotlib plotting library.\\n", "\\n", "If the visualization elements provided by Mesa aren't enough for you, you can build your own and plug them into the model server.\\n", "\\n", "For this example, let's build a simple histogram visualization, which can count the number of agents with each value of wealth." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "First we need to update our imports\\n", "\\n", "We use Matplotlib in this tutorial, but Mesa also has Altair. If you would like other visualization support like Plotly or Bokeh, please feel free to \[contribute\](https://github.com/projectmesa/mesa/blob/main/CONTRIBUTING.md)\\n", "\\n", "In addition, due to the way Solara works we need to trigger an update whenever the underlying model changes. For this you need to register an update counter with every component." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "import solara\\n", "from matplotlib.figure import Figure\\n", "\\n", "from mesa.visualization.utils import update\_counter" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "Next we provide a function for our agent portrayal and our model parameters. " \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "def agent\_portrayal(agent):\\n", " size = 10\\n", " color = \\"tab:red\\"\\n", " if agent.wealth > 0:\\n", " size = 50\\n", " color = \\"tab:blue\\"\\n", " return {\\"size\\": size, \\"color\\": color}\\n", "\\n", "\\n", "model\_params = {\\n", " \\"n\\": {\\n", " \\"type\\": \\"SliderInt\\",\\n", " \\"value\\": 50,\\n", " \\"label\\": \\"Number of agents:\\",\\n", " \\"min\\": 10,\\n", " \\"max\\": 100,\\n", " \\"step\\": 1,\\n", " },\\n", " \\"width\\": 10,\\n", " \\"height\\": 10,\\n", "}" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "Now we add our custom component. In this case we will build a histogram of agent wealth. \\n", "\\n", "Besides the standard matplotlib code to build a histogram, please notice 3 key features. \\n", "\\n", "1. \`@solara.component\` this is needed for any compoenent you add\\n", "2. \`update\_counter.get()\` this is needed so solara updates the dashboard with your agent based model \\n", "3. you must initialize a \`figure\` using this method instead of \`plt.figure()\`, for thread safety purpose\\n" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "@solara.component\\n", "def Histogram(model):\\n", " update\_counter.get() # This is required to update the counter\\n", " # Note: you must initialize a figure using this method instead of\\n", " # plt.figure(), for thread safety purpose\\n", " fig = Figure()\\n", " ax = fig.subplots()\\n", " wealth\_vals = \[agent.wealth for agent in model.agents\]\\n", " # Note: you have to use Matplotlib's OOP API instead of plt.hist\\n", " # because plt.hist is not thread-safe.\\n", " ax.hist(wealth\_vals, bins=10)\\n", " solara.FigureMatplotlib(fig)" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "Now we create the model an initialize the visualization" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "# Create initial model instance\\n", "money\_model = MoneyModel(n=50, width=10, height=10)\\n", "\\n", "SpaceGraph = make\_space\_component(agent\_portrayal)\\n", "GiniPlot = make\_plot\_component(\\"Gini\\")\\n", "\\n", "page = SolaraViz(\\n", " money\_model,\\n", " components=\[SpaceGraph, GiniPlot, Histogram\],\\n", " model\_params=model\_params,\\n", " name=\\"Boltzmann Wealth Model\\",\\n", ")\\n", "# This is required to render the visualization in the Jupyter notebook\\n", "page" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "You can even run the visuals independently by calling it with the model instance" \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[ "Histogram(money\_model)" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Exercise\\n", " - Build you own custom component" \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "## Next Steps\\n", "\\n", "Check out the next \[batch run tutorial\](https://mesa.readthedocs.io/latest/tutorials/7\_batch\_run.html) on how to conduct parameter sweeps and run numerous iterations of your model." \] }, { "cell\_type": "markdown", "metadata": {}, "source": \[ "\[Comer2014\] Comer, Kenneth W. “Who Goes First? An Examination of the Impact of Activation on Outcome Behavior in AgentBased Models.” George Mason University, 2014. http://mars.gmu.edu/bitstream/handle/1920/9070/Comer\_gmu\_0883E\_10539.pdf\\n", "\\n", "\[Dragulescu2002\] Drăgulescu, Adrian A., and Victor M. Yakovenko. “Statistical Mechanics of Money, Income, and Wealth: A Short Survey.” arXiv Preprint Cond-mat/0211175, 2002. http://arxiv.org/abs/cond-mat/0211175." \] }, { "cell\_type": "code", "execution\_count": null, "metadata": {}, "outputs": \[\], "source": \[\] } \], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display\_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language\_info": { "codemirror\_mode": { "name": "ipython", "version": 3 }, "file\_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert\_exporter": "python", "pygments\_lexer": "ipython3", "version": "3.12.5" }, "widgets": { "state": {}, "version": "1.1.2" } }, "nbformat": 4, "nbformat\_minor": 4 }
---
# Unknown
\# Spaces \`\`\`{eval-rst} .. automodule:: mesa.space :members: :inherited-members: \`\`\`
---
# Unknown
\# Boltzmann Wealth Model (Tutorial) ## Summary A simple model of agents exchanging wealth. All agents start with the same amount of money. Every step, each agent with one unit of money or more gives one unit of wealth to another random agent. This is the model described in the \[Intro Tutorial\](https://mesa.readthedocs.io/en/latest/tutorials/intro\_tutorial.html), with the completed code. If you want to go over the step-by-step tutorial, please go and run the \[Jupyter Notebook\](https://github.com/projectmesa/mesa/blob/main/docs/tutorials/intro\_tutorial.ipynb). The code here runs the finalized code in the last cells directly. As the model runs, the distribution of wealth among agents goes from being perfectly uniform (all agents have the same starting wealth), to highly skewed -- a small number have high wealth, more have none at all. ## How to Run To follow the tutorial example, launch the Jupyter Notebook and run the code in \`\`Introduction to Mesa Tutorial Code.ipynb\`\` which you can find in the main mesa repo \[here\](https://github.com/projectmesa/mesa/blob/main/docs/tutorials/intro\_tutorial.ipynb) To launch the interactive server, as described in the \[last section of the tutorial\](https://mesa.readthedocs.io/en/latest/tutorials/intro\_tutorial.html#adding-visualization), run: \`\`\` $ solara run app.py \`\`\` If your browser doesn't open automatically, point it to \[http://127.0.0.1:8765/\](http://127.0.0.1:8765/). When the visualization loads, click on the Play button. ## Files \* \`\`model.py\`\`: Final version of the model. \* \`\`agents.py\`\`: Final version of the agent. \* \`\`app.py\`\`: Code for the interactive visualization. ## Optional An optional visualization is also provided using Streamlit, which is another popular Python library for creating interactive web applications. To run the Streamlit app, you will need to install the \`streamlit\` and \`altair\` libraries: \`\`\` $ pip install streamlit altair \`\`\` Then, you can run the Streamlit app using the following command: \`\`\` $ streamlit run st\_app.py \`\`\` ## Further Reading The full tutorial describing how the model is built can be found at: https://mesa.readthedocs.io/en/latest/tutorials/intro\_tutorial.html This model is drawn from econophysics and presents a statistical mechanics approach to wealth distribution. Some examples of further reading on the topic can be found at: \[Milakovic, M. A Statistical Equilibrium Model of Wealth Distribution. February, 2001.\](https://editorialexpress.com/cgi-bin/conference/download.cgi?db\_name=SCE2001&paper\_id=214) \[Dragulescu, A and Yakovenko, V. Statistical Mechanics of Money, Income, and Wealth: A Short Survey. November, 2002\](http://arxiv.org/pdf/cond-mat/0211175v1.pdf) ## Agents \`\`\`python from mesa.discrete\_space import CellAgent class MoneyAgent(CellAgent): """An agent with fixed initial wealth. Each agent starts with 1 unit of wealth and can give 1 unit to other agents if they occupy the same cell. Attributes: wealth (int): The agent's current wealth (starts at 1) """ def \_\_init\_\_(self, model, cell): """Create a new agent. Args: model (Model): The model instance that contains the agent """ super().\_\_init\_\_(model) self.cell = cell self.wealth = 1 def move(self): """Move the agent to a random neighboring cell.""" self.cell = self.cell.neighborhood.select\_random\_cell() def give\_money(self): """Give 1 unit of wealth to a random agent in the same cell.""" cellmates = \[a for a in self.cell.agents if a is not self\] if cellmates: # Only give money if there are other agents present other = self.random.choice(cellmates) other.wealth += 1 self.wealth -= 1 def step(self): """Execute one step for the agent: 1. Move to a neighboring cell 2. If wealth > 0, maybe give money to another agent in the same cell """ self.move() if self.wealth > 0: self.give\_money() \`\`\` ## Model \`\`\`python """ Boltzmann Wealth Model ===================== A simple model of wealth distribution based on the Boltzmann-Gibbs distribution. Agents move randomly on a grid, giving one unit of wealth to a random neighbor when they occupy the same cell. """ from mesa import Model from mesa.datacollection import DataCollector from mesa.discrete\_space import OrthogonalMooreGrid from mesa.examples.basic.boltzmann\_wealth\_model.agents import MoneyAgent class BoltzmannWealth(Model): """A simple model of an economy where agents exchange currency at random. All agents begin with one unit of currency, and each time step agents can give a unit of currency to another agent in the same cell. Over time, this produces a highly skewed distribution of wealth. Attributes: num\_agents (int): Number of agents in the model grid (MultiGrid): The space in which agents move running (bool): Whether the model should continue running datacollector (DataCollector): Collects and stores model data """ def \_\_init\_\_(self, n=100, width=10, height=10, seed=None): """Initialize the model. Args: n (int, optional): Number of agents. Defaults to 100. width (int, optional): Grid width. Defaults to 10. height (int, optional): Grid height. Defaults to 10. seed (int, optional): Random seed. Defaults to None. """ super().\_\_init\_\_(seed=seed) self.num\_agents = n self.grid = OrthogonalMooreGrid((width, height), random=self.random) # Set up data collection self.datacollector = DataCollector( model\_reporters={"Gini": self.compute\_gini}, agent\_reporters={"Wealth": "wealth"}, ) MoneyAgent.create\_agents( self, self.num\_agents, self.random.choices(self.grid.all\_cells.cells, k=self.num\_agents), ) self.running = True self.datacollector.collect(self) def step(self): self.agents.shuffle\_do("step") # Activate all agents in random order self.datacollector.collect(self) # Collect data def compute\_gini(self): """Calculate the Gini coefficient for the model's current wealth distribution. The Gini coefficient is a measure of inequality in distributions. - A Gini of 0 represents complete equality, where all agents have equal wealth. - A Gini of 1 represents maximal inequality, where one agent has all wealth. """ agent\_wealths = \[agent.wealth for agent in self.agents\] x = sorted(agent\_wealths) n = self.num\_agents # Calculate using the standard formula for Gini coefficient b = sum(xi \* (n - i) for i, xi in enumerate(x)) / (n \* sum(x)) return 1 + (1 / n) - 2 \* b \`\`\` ## App \`\`\`python from mesa.examples.basic.boltzmann\_wealth\_model.model import BoltzmannWealth from mesa.mesa\_logging import INFO, log\_to\_stderr from mesa.visualization import ( SolaraViz, make\_plot\_component, make\_space\_component, ) log\_to\_stderr(INFO) def agent\_portrayal(agent): color = agent.wealth # we are using a colormap to translate wealth to color return {"color": color} model\_params = { "seed": { "type": "InputText", "value": 42, "label": "Random Seed", }, "n": { "type": "SliderInt", "value": 50, "label": "Number of agents:", "min": 10, "max": 100, "step": 1, }, "width": 10, "height": 10, } def post\_process(ax): ax.get\_figure().colorbar(ax.collections\[0\], label="wealth", ax=ax) # Create initial model instance model = BoltzmannWealth(50, 10, 10) # Create visualization elements. The visualization elements are solara components # that receive the model instance as a "prop" and display it in a certain way. # Under the hood these are just classes that receive the model instance. # You can also author your own visualization elements, which can also be functions # that receive the model instance and return a valid solara component. SpaceGraph = make\_space\_component( agent\_portrayal, cmap="viridis", vmin=0, vmax=10, post\_process=post\_process ) GiniPlot = make\_plot\_component("Gini") # Create the SolaraViz page. This will automatically create a server and display the # visualization elements in a web browser. # Display it using the following command in the example directory: # solara run app.py # It will automatically update and display any changes made to this file page = SolaraViz( model, components=\[SpaceGraph, GiniPlot\], model\_params=model\_params, name="Boltzmann Wealth Model", ) page # noqa # In a notebook environment, we can also display the visualization elements directly # SpaceGraph(model1) # GiniPlot(model1) # The plots will be static. If you want to pick up model steps, # you have to make the model reactive first # reactive\_model = solara.reactive(model1) # SpaceGraph(reactive\_model) # In a different notebook block: # reactive\_model.value.step() \`\`\`
---
# Documentation page not found
- Read the Docs
[mesa.readthedocs.io](/)
The documentation page you requested does not exist or may have been removed.
Hosted by [](//readthedocs.org/)
---
# Getting started — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Getting started[#](#getting-started "Link to this heading")
============================================================
Mesa is a modular framework for building, analyzing and visualizing agent-based models.
**Agent-based models** are computer simulations involving multiple entities (the agents) acting and interacting with one another based on their programmed behavior. Agents can be used to represent living cells, animals, individual humans, even entire organizations or abstract entities. Sometimes, we may have an understanding of how the individual components of a system behave, and want to see what system-level behaviors and effects emerge from their interaction. Other times, we may have a good idea of how the system overall behaves, and want to figure out what individual behaviors explain it. Or we may want to see how to get agents to cooperate or compete most effectively. Or we may just want to build a cool toy with colorful little dots moving around.
Tutorials[#](#tutorials "Link to this heading")
------------------------------------------------
If you want to get a quick start on how to build agent based models with MESA, check the overview and tutorials:
* [Overview of the MESA library](overview.html)
: Learn about the core concepts and components of Mesa.
* [Introductory Tutorial](tutorials/intro_tutorial.html)
: Learn how to create your first Mesa model.
* [Visualization Tutorial](tutorials/visualization_tutorial.html)
: Learn how to create interactive visualizations for your models.
Examples[#](#examples "Link to this heading")
----------------------------------------------
Mesa ships with a collection of example models. These are classic ABMs, so if you are familiar with ABMs and want to get a quick sense of how MESA works, these examples are great place to start. You can find them [here](examples.html)
.
Further resources[#](#further-resources "Link to this heading")
----------------------------------------------------------------
To further explore Mesa and its features, we have the following resources available:
### Best practices[#](#best-practices "Link to this heading")
* [Mesa best practices](best-practices.html)
: an overview of tips and guidelines for using MESA.
### API documentation[#](#api-documentation "Link to this heading")
* [Mesa API reference](#apis)
: Detailed documentation of Mesa’s classes and functions.
### Repository of models built using MESA[#](#repository-of-models-built-using-mesa "Link to this heading")
* [Mesa Examples repository](https://github.com/projectmesa/mesa-examples)
: A collection of example models demonstrating various Mesa features and modeling techniques.
### Migration guide[#](#migration-guide "Link to this heading")
* [Mesa 3.0 Migration guide](migration_guide.html)
: If you’re upgrading from an earlier version of Mesa, this guide will help you navigate the changes in Mesa 3.0.
### Source Ccode and development[#](#source-ccode-and-development "Link to this heading")
* [Mesa GitHub repository](https://github.com/projectmesa/mesa)
: Access the full source code of Mesa, contribute to its development, or report issues.
* [Mesa release notes](https://github.com/projectmesa/mesa/releases)
: View the detailed changelog of Mesa, including all past releases and their features.
### Community and support[#](#community-and-support "Link to this heading")
* [Mesa GitHub Discussions](https://github.com/projectmesa/mesa/discussions)
: Join discussions, ask questions, and connect with other Mesa users.
* [Matrix Chat](https://matrix.to/#/#project-mesa:matrix.org)
: Real-time chat for quick questions and community interaction.
Enjoy modelling with Mesa, and feel free to reach out!
On this page
### This Page
* [Show Source](_sources/getting_started.md.txt)
---
# Unknown
\# Conway's Game Of "Life" ## Summary \[The Game of Life\](https://en.wikipedia.org/wiki/Conway%27s\_Game\_of\_Life), also known simply as "Life", is a cellular automaton devised by the British mathematician John Horton Conway in 1970. The "game" is a zero-player game, meaning that its evolution is determined by its initial state, requiring no further input by a human. One interacts with the Game of "Life" by creating an initial configuration and observing how it evolves, or, for advanced "players", by creating patterns with particular properties. ## How to Run To run the model interactively you can use either the streamlit or solara version. For solara, you use \`\`\` $ solara run app.py \`\`\` For streamlit, you need \`\`\` $ streamlit run st\_app.py \`\`\` This will open your browser and show you the controls. You can start the model by hitting the run button. ## Files \* \`\`agents.py\`\`: Defines the behavior of an individual cell, which can be in two states: DEAD or ALIVE. \* \`\`model.py\`\`: Defines the model itself, initialized with a random configuration of alive and dead cells. \* \`\`app.py\`\`: Defines an interactive visualization using solara. \* \`\`st\_app.py\`\`: Defines an interactive visualization using Streamlit. ## Optional \* For the streamlit version, you need to have streamlit installed (can be done via pip install streamlit) ## Further Reading \[Conway's Game of Life\](https://en.wikipedia.org/wiki/Conway%27s\_Game\_of\_Life) ## Agents \`\`\`python from mesa.discrete\_space import FixedAgent class Cell(FixedAgent): """Represents a single ALIVE or DEAD cell in the simulation.""" DEAD = 0 ALIVE = 1 @property def x(self): return self.cell.coordinate\[0\] @property def y(self): return self.cell.coordinate\[1\] def \_\_init\_\_(self, model, cell, init\_state=DEAD): """Create a cell, in the given state, at the given x, y position.""" super().\_\_init\_\_(model) self.cell = cell self.state = init\_state self.\_next\_state = None @property def is\_alive(self): return self.state == self.ALIVE @property def neighbors(self): return self.cell.neighborhood.agents def determine\_state(self): """Compute if the cell will be dead or alive at the next tick. This is based on the number of alive or dead neighbors. The state is not changed here, but is just computed and stored in self.\_nextState, because our current state may still be necessary for our neighbors to calculate their next state. """ # Get the neighbors and apply the rules on whether to be alive or dead # at the next tick. live\_neighbors = sum(neighbor.is\_alive for neighbor in self.neighbors) # Assume nextState is unchanged, unless changed below. self.\_next\_state = self.state if self.is\_alive: if live\_neighbors < 2 or live\_neighbors > 3: self.\_next\_state = self.DEAD else: if live\_neighbors == 3: self.\_next\_state = self.ALIVE def assume\_state(self): """Set the state to the new computed state -- computed in step().""" self.state = self.\_next\_state \`\`\` ## Model \`\`\`python from mesa import Model from mesa.discrete\_space import OrthogonalMooreGrid from mesa.examples.basic.conways\_game\_of\_life.agents import Cell class ConwaysGameOfLife(Model): """Represents the 2-dimensional array of cells in Conway's Game of Life.""" def \_\_init\_\_(self, width=50, height=50, initial\_fraction\_alive=0.2, seed=None): """Create a new playing area of (width, height) cells.""" super().\_\_init\_\_(seed=seed) # Use a simple grid, where edges wrap around. self.grid = OrthogonalMooreGrid((width, height), capacity=1, torus=True) # Place a cell at each location, with some initialized to # ALIVE and some to DEAD. for cell in self.grid.all\_cells: Cell( self, cell, init\_state=Cell.ALIVE if self.random.random() < initial\_fraction\_alive else Cell.DEAD, ) self.running = True def step(self): """Perform the model step in two stages: - First, all cells assume their next state (whether they will be dead or alive) - Then, all cells change state to their next state. """ self.agents.do("determine\_state") self.agents.do("assume\_state") \`\`\` ## App \`\`\`python from mesa.examples.basic.conways\_game\_of\_life.model import ConwaysGameOfLife from mesa.visualization import ( SolaraViz, make\_space\_component, ) def agent\_portrayal(agent): return { "color": "white" if agent.state == 0 else "black", "marker": "s", "size": 25, } def post\_process(ax): ax.set\_aspect("equal") ax.set\_xticks(\[\]) ax.set\_yticks(\[\]) model\_params = { "seed": { "type": "InputText", "value": 42, "label": "Random Seed", }, "width": { "type": "SliderInt", "value": 50, "label": "Width", "min": 5, "max": 60, "step": 1, }, "height": { "type": "SliderInt", "value": 50, "label": "Height", "min": 5, "max": 60, "step": 1, }, "initial\_fraction\_alive": { "type": "SliderFloat", "value": 0.2, "label": "Cells initially alive", "min": 0, "max": 1, "step": 0.01, }, } # Create initial model instance model1 = ConwaysGameOfLife() # Create visualization elements. The visualization elements are solara components # that receive the model instance as a "prop" and display it in a certain way. # Under the hood these are just classes that receive the model instance. # You can also author your own visualization elements, which can also be functions # that receive the model instance and return a valid solara component. SpaceGraph = make\_space\_component( agent\_portrayal, post\_process=post\_process, draw\_grid=False ) # Create the SolaraViz page. This will automatically create a server and display the # visualization elements in a web browser. # Display it using the following command in the example directory: # solara run app.py # It will automatically update and display any changes made to this file page = SolaraViz( model1, components=\[SpaceGraph\], model\_params=model\_params, name="Game of Life", ) page # noqa \`\`\`
---
# Unknown
\# Batchrunner \`\`\`{eval-rst} .. automodule:: batchrunner :members: \`\`\`
---
# Unknown
\# Visualization For a detailed tutorial, please refer to our \[Visualization Tutorial\](../tutorials/visualization\_tutorial.ipynb). ## Jupyter Visualization \`\`\`{eval-rst} .. automodule:: mesa.visualization.solara\_viz :members: :undoc-members: :show-inheritance: \`\`\` \`\`\`{eval-rst} .. automodule:: mesa.visualization.components.\_\_init\_\_ :members: :undoc-members: :show-inheritance: \`\`\` ## User Parameters \`\`\`{eval-rst} .. automodule:: mesa.visualization.user\_param :members: :undoc-members: :show-inheritance: \`\`\` ## Matplotlib-based visualizations \`\`\`{eval-rst} .. automodule:: mesa.visualization.components.matplotlib\_components :members: :undoc-members: :show-inheritance: \`\`\` \`\`\`{eval-rst} .. automodule:: mesa.visualization.mpl\_space\_drawing :members: :undoc-members: :show-inheritance: \`\`\` ## Altair-based visualizations \`\`\`{eval-rst} .. automodule:: mesa.visualization.components.altair\_components :members: :undoc-members: :show-inheritance: \`\`\` ## Command Console \`\`\`{eval-rst} .. automodule:: mesa.visualization.command\_console :members: :undoc-members: :show-inheritance: \`\`\`
---
# Documentation page not found
- Read the Docs
[mesa.readthedocs.io](/)
The documentation page you requested does not exist or may have been removed.
Hosted by [](//readthedocs.org/)
---
# Mesa: Agent-based modeling in Python — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Mesa: Agent-based modeling in Python[#](#mesa-agent-based-modeling-in-python "Link to this heading")
=====================================================================================================
[](https://github.com/projectmesa/mesa/actions)
[](https://codecov.io/gh/projectmesa/mesa)
[](https://github.com/psf/black)
[](https://matrix.to/#/#project-mesa:matrix.org)
[Mesa](https://github.com/projectmesa/mesa/)
is an Apache2 licensed agent-based modeling (or ABM) framework in Python.
Mesa allows users to quickly create agent-based models using built-in core components (such as spatial grids and agent schedulers) or customized implementations; visualize them using a browser-based interface; and analyze their results using Python’s data analysis tools. Its goal is to be the Python-based counterpart to NetLogo, Repast, or MASON.
 _A visualisation of the Wolf Sheep model build with Mesa._
Features[#](#features "Link to this heading")
----------------------------------------------
* Built-in core modeling components
* Flexible agent and model management through AgentSet
* Browser-based Solara visualization
* Built-in tools for data collection and analysis
* Example model library
Using Mesa[#](#using-mesa "Link to this heading")
--------------------------------------------------
### Installation Options[#](#installation-options "Link to this heading")
To install our latest stable release, run:
pip install \-U mesa
To also install our recommended dependencies:
pip install \-U mesa\[rec\]
The `[rec]` option installs additional recommended dependencies needed for visualization, plotting, and network modeling capabilities.
On a Mac, this command might cause an error stating `zsh: no matches found: mesa[all]`. In that case, change the command to `pip install -U "mesa[rec]"`.
### Resources[#](#resources "Link to this heading")
For help getting started with Mesa, check out these resources:
* [Getting started](getting_started.html)
- Learn about Mesa’s core concepts and components
* [Migration Guide](migration_guide.html)
- Upgrade to Mesa 3.0
* [Mesa Examples](https://mesa.readthedocs.io/stable/examples.html)
- Browse user-contributed models and implementations
* [Mesa Extensions](mesa_extension.html)
- Overview of mesa’s Extensions
* [GitHub Discussions](https://github.com/projectmesa/mesa/discussions)
- Ask questions and discuss Mesa
* [Matrix Chat Room](https://matrix.to/#/#project-mesa:matrix.org)
- Real-time chat with the Mesa community
### Development and Support[#](#development-and-support "Link to this heading")
Mesa is an open source project and welcomes contributions:
* [GitHub Repository](https://github.com/projectmesa/mesa/)
- Access the source code
* [Issue Tracker](https://github.com/projectmesa/mesa/issues)
- Report bugs or suggest features
* [Contributors Guide](https://github.com/projectmesa/mesa/blob/main/CONTRIBUTING.md)
- Learn how to contribute
The original Mesa conference paper is [available here](http://conference.scipy.org.s3-website-us-east-1.amazonaws.com/proceedings/scipy2015/jacqueline_kazil.html)
.
Indices and tables[#](#indices-and-tables "Link to this heading")
==================================================================
* [Index](genindex.html)
* [Module Index](py-modindex.html)
* [Search Page](search.html)
On this page
### This Page
* [Show Source](_sources/index.md.txt)
---
# Unknown
\# Demographic Prisoner's Dilemma on a Grid ## Summary The Demographic Prisoner's Dilemma is a family of variants on the classic two-player \[Prisoner's Dilemma\]. The model consists of agents, each with a strategy of either Cooperate or Defect. Each agent's payoff is based on its strategy and the strategies of its spatial neighbors. After each step of the model, the agents adopt the strategy of their neighbor with the highest total score. The model payoff table is: | | Cooperate | Defect| |:-------------:|:---------:|:-----:| | \*\*Cooperate\*\* | 1, 1 | 0, D | | \*\*Defect\*\* | D, 0 | 0, 0 | Where \*D\* is the defection bonus, generally set higher than 1. In these runs, the defection bonus is set to $D=1.6$. The Demographic Prisoner's Dilemma demonstrates how simple rules can lead to the emergence of widespread cooperation, despite the Defection strategy dominating each individual interaction game. However, it is also interesting for another reason: it is known to be sensitive to the activation regime employed in it. ## How to Run ##### Web based model simulation To run the model interactively, run \`\`solara run app.py\`\` in this directory. ##### Jupyter Notebook Launch the \`\`Demographic Prisoner's Dilemma Activation Schedule.ipynb\`\` notebook and run the code. ## Files \* \`\`agents.py\`\`: contains the agent class. \* \`\`model.py\`\`: contains the model class; the model takes a \`\`activation\_order\`\` string as an argument, which determines in which order agents are activated: Sequential, Random or Simultaneous. \* \`\`app.py\`\`: contains the interactive visualization server. \* \`\`Demographic Prisoner's Dilemma Activation Schedule.ipynb\`\`: Jupyter Notebook for running the scheduling experiment. This runs the model three times, one for each activation type, and demonstrates how the activation regime drives the model to different outcomes. ## Further Reading This model is adapted from: Wilensky, U. (2002). NetLogo PD Basic Evolutionary model. http://ccl.northwestern.edu/netlogo/models/PDBasicEvolutionary. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL. The Demographic Prisoner's Dilemma originates from: \[Epstein, J. Zones of Cooperation in Demographic Prisoner's Dilemma. 1998.\](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.8.8629&rep=rep1&type=pdf) ## Agents \`\`\`python from mesa.discrete\_space import CellAgent class PDAgent(CellAgent): """Agent member of the iterated, spatial prisoner's dilemma model.""" def \_\_init\_\_(self, model, starting\_move=None, cell=None): """ Create a new Prisoner's Dilemma agent. Args: model: model instance starting\_move: If provided, determines the agent's initial state: C(ooperating) or D(efecting). Otherwise, random. """ super().\_\_init\_\_(model) self.score = 0 self.cell = cell if starting\_move: self.move = starting\_move else: self.move = self.random.choice(\["C", "D"\]) self.next\_move = None @property def is\_cooroperating(self): return self.move == "C" def step(self): """Get the best neighbor's move, and change own move accordingly if better than own score.""" # neighbors = self.model.grid.get\_neighbors(self.pos, True, include\_center=True) neighbors = \[\*list(self.cell.neighborhood.agents), self\] best\_neighbor = max(neighbors, key=lambda a: a.score) self.next\_move = best\_neighbor.move if self.model.activation\_order != "Simultaneous": self.advance() def advance(self): self.move = self.next\_move self.score += self.increment\_score() def increment\_score(self): neighbors = self.cell.neighborhood.agents if self.model.activation\_order == "Simultaneous": moves = \[neighbor.next\_move for neighbor in neighbors\] else: moves = \[neighbor.move for neighbor in neighbors\] return sum(self.model.payoff\[(self.move, move)\] for move in moves) \`\`\` ## Model \`\`\`python import mesa from mesa.discrete\_space import OrthogonalMooreGrid from mesa.examples.advanced.pd\_grid.agents import PDAgent class PdGrid(mesa.Model): """Model class for iterated, spatial prisoner's dilemma model.""" activation\_regimes = \["Sequential", "Random", "Simultaneous"\] # This dictionary holds the payoff for this agent, # keyed on: (my\_move, other\_move) payoff = {("C", "C"): 1, ("C", "D"): 0, ("D", "C"): 1.6, ("D", "D"): 0} def \_\_init\_\_( self, width=50, height=50, activation\_order="Random", payoffs=None, seed=None ): """ Create a new Spatial Prisoners' Dilemma Model. Args: width, height: Grid size. There will be one agent per grid cell. activation\_order: Can be "Sequential", "Random", or "Simultaneous". Determines the agent activation regime. payoffs: (optional) Dictionary of (move, neighbor\_move) payoffs. """ super().\_\_init\_\_(seed=seed) self.activation\_order = activation\_order self.grid = OrthogonalMooreGrid((width, height), torus=True, random=self.random) if payoffs is not None: self.payoff = payoffs PDAgent.create\_agents( self, len(self.grid.all\_cells.cells), cell=self.grid.all\_cells.cells ) self.datacollector = mesa.DataCollector( { "Cooperating\_Agents": lambda m: len( \[a for a in m.agents if a.move == "C"\] ) } ) self.running = True self.datacollector.collect(self) def step(self): # Activate all agents, based on the activation regime match self.activation\_order: case "Sequential": self.agents.do("step") case "Random": self.agents.shuffle\_do("step") case "Simultaneous": self.agents.do("step") self.agents.do("advance") case \_: raise ValueError(f"Unknown activation order: {self.activation\_order}") # Collect data self.datacollector.collect(self) def run(self, n): """Run the model for n steps.""" for \_ in range(n): self.step() \`\`\` ## App \`\`\`python """ Solara-based visualization for the Spatial Prisoner's Dilemma Model. """ from mesa.examples.advanced.pd\_grid.model import PdGrid from mesa.visualization import ( Slider, SolaraViz, make\_plot\_component, make\_space\_component, ) def pd\_agent\_portrayal(agent): """ Portrayal function for rendering PD agents in the visualization. """ return { "color": "blue" if agent.move == "C" else "red", "marker": "s", # square marker "size": 25, } # Model parameters model\_params = { "seed": { "type": "InputText", "value": 42, "label": "Random Seed", }, "width": Slider("Grid Width", value=50, min=10, max=100, step=1), "height": Slider("Grid Height", value=50, min=10, max=100, step=1), "activation\_order": { "type": "Select", "value": "Random", "values": PdGrid.activation\_regimes, "label": "Activation Regime", }, } # Create grid visualization component using Altair grid\_viz = make\_space\_component(agent\_portrayal=pd\_agent\_portrayal) # Create plot for tracking cooperating agents over time plot\_component = make\_plot\_component("Cooperating\_Agents") # Initialize model initial\_model = PdGrid() # Create visualization with all components page = SolaraViz( model=initial\_model, components=\[grid\_viz, plot\_component\], model\_params=model\_params, name="Spatial Prisoner's Dilemma", ) page # noqa B018 \`\`\`
---
# Mesa Migration guide — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Mesa Migration guide[#](#mesa-migration-guide "Link to this heading")
======================================================================
This guide contains breaking changes between major Mesa versions and how to resolve them.
Non-breaking changes aren’t included, for those see our [Release history](https://github.com/projectmesa/mesa/releases)
.
Mesa 3.0[#](#mesa-3-0 "Link to this heading")
----------------------------------------------
Mesa 3.0 introduces significant changes to core functionalities, including agent and model initialization, scheduling, and visualization. The guide below outlines these changes and provides instructions for migrating your existing Mesa projects to version 3.0.
_This guide is a work in progress. The development of it is tracked in [Issue #2233](https://github.com/projectmesa/mesa/issues/2233)
._
### Upgrade strategy[#](#upgrade-strategy "Link to this heading")
We recommend the following upgrade strategy:
* Update to the latest Mesa 2.x release (`mesa<3`).
* Update to the latest Mesa 3.0.x release (`mesa<3.1`).
* Update to the latest Mesa 3.x release (`mesa<4`).
With each update, resolve all errors and warnings, before updating to the next one.
### Reserved and private variables[#](#reserved-and-private-variables "Link to this heading")
#### Reserved variables[#](#reserved-variables "Link to this heading")
Currently, we have reserved the following variables:
* Model: `agents`, `current_id`, `random`, `running`, `steps`, `time`.
* Agent: `unique_id`, `model`.
You can use (read) any reserved variable, but Mesa may update them automatically and rely on them, so modify/update at your own risk.
#### Private variables[#](#private-variables "Link to this heading")
Any variables starting with an underscore (`_`) are considered private and for Mesa’s internal use. We might use any of those. Modifying or overwriting any private variable is at your own risk.
* Ref: [Discussion #2230](https://github.com/projectmesa/mesa/discussions/2230)
, [PR #2225](https://github.com/projectmesa/mesa/pull/2225)
### Removal of `mesa.flat` namespace[#](#removal-of-mesa-flat-namespace "Link to this heading")
The `mesa.flat` namespace is removed. Use the full namespace for your imports.
* Ref: [PR #2091](https://github.com/projectmesa/mesa/pull/2091)
### Mandatory Model initialization with `super().__init__()`[#](#mandatory-model-initialization-with-super-init "Link to this heading")
In Mesa 3.0, it is now mandatory to call `super().__init__()` when initializing your model class. This ensures that all necessary Mesa model variables are correctly set up and agents are properly added to the model. If you want to control the seed of the random number generator, you have to pass this as a keyword argument to super as shown below.
Make sure all your model classes explicitly call `super().__init__()` in their `__init__` method:
class MyModel(mesa.Model):
def \_\_init\_\_(self, some\_arg\_I\_need, seed\=None, some\_kwarg\_I\_need\=True):
super().\_\_init\_\_(seed\=seed) \# Calling super is now required, passing seed is highly recommended
\# Your model initialization code here
\# this code uses some\_arg\_I\_need and my\_init\_kwarg
This change ensures that all Mesa models are properly initialized, which is crucial for:
* Correctly adding agents to the model
* Setting up other essential Mesa model variables
* Maintaining consistency across all models
If you forget to call `super().__init__()`, you’ll now see this error:
RuntimeError: The Mesa Model class was not initialized. You must explicitly initialize the Model by calling super().\_\_init\_\_() on initialization.
* Ref: [PR #2218](https://github.com/projectmesa/mesa/pull/2218)
, [PR #1928](https://github.com/projectmesa/mesa/pull/1928)
, Mesa-examples [PR #83](https://github.com/projectmesa/mesa-examples/pull/83)
### Automatic assignment of `unique_id` to Agents[#](#automatic-assignment-of-unique-id-to-agents "Link to this heading")
In Mesa 3.0, `unique_id` for agents is now automatically assigned, simplifying agent creation and ensuring unique IDs across all agents in a model.
1. Remove `unique_id` from agent initialization:
\# Old
agent \= MyAgent(unique\_id\=unique\_id, model\=self, ...)
agent \= MyAgent(unique\_id, self, ...)
agent \= MyAgent(self.next\_id(), self, ...)
\# New
agent \= MyAgent(model\=self, ...)
agent \= MyAgent(self, ...)
2. Remove `unique_id` from Agent super() call:
\# Old
class MyAgent(Agent):
def \_\_init\_\_(self, unique\_id, model, ...):
super().\_\_init\_\_(unique\_id, model)
\# New
class MyAgent(Agent):
def \_\_init\_\_(self, model, ...):
super().\_\_init\_\_(model)
3. Important notes:
* `unique_id` is now automatically assigned relative to a Model instance and starts from 1
* `Model.next_id()` is removed
* If you previously used custom `unique_id` values, store that information in a separate attribute
* Ref: [PR #2226](https://github.com/projectmesa/mesa/pull/2226)
, [PR #2260](https://github.com/projectmesa/mesa/pull/2260)
, Mesa-examples [PR #194](https://github.com/projectmesa/mesa-examples/pull/194)
, [Issue #2213](https://github.com/projectmesa/mesa/issues/2213)
### AgentSet and `Model.agents`[#](#agentset-and-model-agents "Link to this heading")
In Mesa 3.0, the Model class internally manages agents using several data structures:
* `self._agents`: A dictionary containing hard references to all agents, indexed by their `unique_id`.
* `self._agents_by_type`: A dictionary of AgentSets, organizing agents by their type.
* `self._all_agents`: An AgentSet containing all agents in the model.
These internal structures are used to efficiently manage and access agents. Users should interact with agents through the public `model.agents` property, which returns the `self._all_agents` AgentSet.
#### `Model.agents`[#](#model-agents "Link to this heading")
* Attempting to set `model.agents` now raises an `AttributeError` instead of a warning. This attribute is reserved for internal use by Mesa.
* If you were previously setting `model.agents` in your code, you must update it to use a different attribute name for custom agent storage.
For example, replace:
model.agents \= my\_custom\_agents
With:
model.custom\_agents \= my\_custom\_agents
### Time and schedulers[#](#time-and-schedulers "Link to this heading")
#### Automatic increase of the `steps` counter[#](#automatic-increase-of-the-steps-counter "Link to this heading")
The `steps` counter is now automatically increased. With each call to `Model.steps()` it’s increased by 1, at the beginning of the step.
You can access it by `Model.steps`, and it’s internally in the datacollector, batchrunner and the visualisation.
* Ref: [PR #2223](https://github.com/projectmesa/mesa/pull/2223)
, Mesa-examples [PR #161](https://github.com/projectmesa/mesa-examples/pull/161)
#### Removal of `Model._time` and rename `._steps`[#](#removal-of-model-time-and-rename-steps "Link to this heading")
* `Model._time` is removed. You can define your own time variable if needed.
* `Model._steps` steps is renamed to `Model.steps`.
#### Removal of `Model._advance_time()`[#](#removal-of-model-advance-time "Link to this heading")
* The `Model._advance_time()` method is removed. This now happens automatically.
#### Replacing Schedulers with AgentSet functionality[#](#replacing-schedulers-with-agentset-functionality "Link to this heading")
The whole Time module in Mesa is deprecated and will be removed in Mesa 3.1. All schedulers should be replaced with AgentSet functionality and the internal `Model.steps` counter. This allows much more flexibility in how to activate Agents and makes it explicit what’s done exactly.
Here’s how to replace each scheduler:
##### BaseScheduler[#](#basescheduler "Link to this heading")
Replace:
self.schedule \= BaseScheduler(self)
self.schedule.step()
With:
self.agents.do("step")
##### RandomActivation[#](#randomactivation "Link to this heading")
Replace:
self.schedule \= RandomActivation(self)
self.schedule.step()
With:
self.agents.shuffle\_do("step")
##### SimultaneousActivation[#](#simultaneousactivation "Link to this heading")
Replace:
self.schedule \= SimultaneousActivation(self)
self.schedule.step()
With:
self.agents.do("step")
self.agents.do("advance")
##### StagedActivation[#](#stagedactivation "Link to this heading")
Replace:
self.schedule \= StagedActivation(self, \["stage1", "stage2", "stage3"\])
self.schedule.step()
With:
for stage in \["stage1", "stage2", "stage3"\]:
self.agents.do(stage)
If you were using the `shuffle` and/or `shuffle_between_stages` options:
stages \= \["stage1", "stage2", "stage3"\]
if shuffle:
self.random.shuffle(stages)
for stage in stages:
if shuffle\_between\_stages:
self.agents.shuffle\_do(stage)
else:
self.agents.do(stage)
##### RandomActivationByType[#](#randomactivationbytype "Link to this heading")
Replace:
self.schedule \= RandomActivationByType(self)
self.schedule.step()
With:
for agent\_class in self.agent\_types:
self.agents\_by\_type\[agent\_class\].shuffle\_do("step")
###### Replacing `step_type`[#](#replacing-step-type "Link to this heading")
The `RandomActivationByType` scheduler had a `step_type` method that allowed stepping only agents of a specific type. To replicate this functionality using AgentSet:
Replace:
self.schedule.step\_type(AgentType)
With:
self.agents\_by\_type\[AgentType\].shuffle\_do("step")
##### General Notes[#](#general-notes "Link to this heading")
1. The `Model.steps` counter is now automatically incremented. You don’t need to manage it manually.
2. If you were using `self.schedule.agents`, replace it with `self.agents`.
3. If you were using `self.schedule.get_agent_count()`, replace it with `len(self.agents)`.
4. If you were using `self.schedule.agents_by_type`, replace it with `self.agents_by_type`.
5. Agents are now automatically added to or removed from the model’s `AgentSet` (`model.agents`) when they are created or deleted, eliminating the need to manually call `self.schedule.add()` or `self.schedule.remove()`.
* However, you still need to explicitly remove the Agent itself by using `Agent.remove()`. Typically, this means:
* Replace `self.schedule.remove(agent)` with `agent.remove()` in the Model.
* Replace `self.model.schedule.remove(self)` with `self.remove()` within the Agent.
From now on you’re now not bound by 5 distinct schedulers, but can mix and match any combination of AgentSet methods (`do`, `shuffle`, `select`, etc.) to get the desired Agent activation.
Ref: Original discussion [#1912](https://github.com/projectmesa/mesa/discussions/1912)
, decision discussion [#2231](https://github.com/projectmesa/mesa/discussions/2231)
, example updates [#183](https://github.com/projectmesa/mesa-examples/pull/183)
and [#201](https://github.com/projectmesa/mesa-examples/pull/201)
, PR [#2306](https://github.com/projectmesa/mesa/pull/2306)
### Visualisation[#](#visualisation "Link to this heading")
Mesa has adopted a new API for our frontend. If you already migrated to the experimental new SolaraViz you can still use the import from mesa.experimental. Otherwise here is a list of things you need to change.
> **Note:** SolaraViz is experimental and still in active development for Mesa 3.0. While we attempt to minimize them, there might be API breaking changes between Mesa 3.0 and 3.1. There won’t be breaking changes between Mesa 3.0.x patch releases.
#### Model Initialization[#](#model-initialization "Link to this heading")
Previously SolaraViz was initialized by providing a `model_cls` and a `model_params`. This has changed to expect a model instance `model`. You can still provide (user-settable) `model_params`, but only if users should be able to change them. It is now also possible to pass in a “reactive model” by first calling `model = solara.reactive(model)`. This is useful for notebook environments. It allows you to pass the model to the SolaraViz Module, but continue to use the model. For example calling `model.value.step()` (notice the extra .value) will automatically update the plots. This currently only automatically works for the step method, you can force visualization updates by calling `model.value.force_update()`.
### Model Initialization with Keyword Arguments[#](#model-initialization-with-keyword-arguments "Link to this heading")
With the introduction of SolaraViz in Mesa 3.0, models are now instantiated using `**model_parameters.value`. This means all inputs for initializing a new model must be keyword arguments. Ensure your model’s `__init__` method accepts keyword arguments matching the keys in `model_params`.
class MyModel(mesa.Model):
def \_\_init\_\_(self, n\_agents\=10, seed\=None):
super().\_\_init\_\_(seed\=seed)
\# Initialize the model with N agents
#### Default space visualization[#](#default-space-visualization "Link to this heading")
Previously we included a default space drawer that you could configure with an `agent_portrayal` function. You now have to explicitly create a space drawer with the `agent_portrayal` function
\# old
from mesa.experimental import SolaraViz
SolaraViz(model\_cls, model\_params, agent\_portrayal\=agent\_portrayal)
\# new
from mesa.visualization import SolaraViz, make\_space\_component
SolaraViz(model, components\=\[make\_space\_component(agent\_portrayal)\])
#### Plotting “measures”[#](#plotting-measures "Link to this heading")
“Measure” plots also need to be made explicit here. Previously, measure could either be 1) A function that receives a model and returns a solara component or 2) A string or list of string of variables that are collected by the datacollector and are to be plotted as a line plot. 1) still works, but you can pass that function to “components” directly. 2) needs to explicitly call the `make_plot_measure()`function.
\# old
from mesa.experimental import SolaraViz
def make\_plot(model):
...
SolaraViz(model\_cls, model\_params, measures\=\[make\_plot, "foo", \["bar", "baz"\]\])
\# new
from mesa.visualization import SolaraViz, make\_plot\_component
SolaraViz(model, components\=\[make\_plot, make\_plot\_component("foo"), make\_plot\_component("bar", "baz")\])
#### Plotting text[#](#plotting-text "Link to this heading")
To plot model-dependent text the experimental SolaraViz provided a `make_text` function that wraps another functions that receives the model and turns its string return value into a solara text component. Again, this other function can now be passed directly to the new SolaraViz components array. It is okay if your function just returns a string.
\# old
from mesa.experimental import SolaraViz, make\_text
def show\_steps(model):
return f"Steps: {model.steps}"
SolaraViz(model\_cls, model\_params, measures\=make\_text(show\_steps))
\# new
from mesa.visualisation import SolaraViz
def show\_steps(model):
return f"Steps: {model.steps}"
SolaraViz(model, components\=\[show\_steps\])
### Other changes[#](#other-changes "Link to this heading")
#### Removal of Model.initialize\_data\_collector[#](#removal-of-model-initialize-data-collector "Link to this heading")
The `initialize_data_collector` in the Model class is removed. In the Model class, replace:
Replace:
self.initialize\_data\_collector(...)
With:
self.datacollector \= DataCollector(...)
* Ref: [PR #2327](https://github.com/projectmesa/mesa/pull/2327)
, Mesa-examples [PR #208](https://github.com/projectmesa/mesa-examples/pull/208)
)
On this page
### This Page
* [Show Source](_sources/migration_guide.md.txt)
---
# APIs — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
APIs[#](#apis "Link to this heading")
======================================
* [Model](model.html)
* [`Model`](model.html#mesa.model.Model)
* [`Model.running`](model.html#mesa.model.Model.running)
* [`Model.steps`](model.html#mesa.model.Model.steps)
* [`Model.random`](model.html#mesa.model.Model.random)
* [`Model.rng`](model.html#mesa.model.Model.rng)
* [`Model.agents`](model.html#mesa.model.Model.agents)
* [`Model.agent_types`](model.html#mesa.model.Model.agent_types)
* [`Model.agents_by_type`](model.html#mesa.model.Model.agents_by_type)
* [`Model.register_agent()`](model.html#mesa.model.Model.register_agent)
* [`Model.deregister_agent()`](model.html#mesa.model.Model.deregister_agent)
* [`Model.run_model()`](model.html#mesa.model.Model.run_model)
* [`Model.step()`](model.html#mesa.model.Model.step)
* [`Model.reset_randomizer()`](model.html#mesa.model.Model.reset_randomizer)
* [`Model.reset_rng()`](model.html#mesa.model.Model.reset_rng)
* [`Model.remove_all_agents()`](model.html#mesa.model.Model.remove_all_agents)
* [Agent](agent.html)
* [`Agent`](agent.html#mesa.agent.Agent)
* [`Agent.model`](agent.html#mesa.agent.Agent.model)
* [`Agent.unique_id`](agent.html#mesa.agent.Agent.unique_id)
* [`Agent.pos`](agent.html#mesa.agent.Agent.pos)
* [`Agent.remove()`](agent.html#mesa.agent.Agent.remove)
* [`Agent.step()`](agent.html#mesa.agent.Agent.step)
* [`Agent.create_agents()`](agent.html#mesa.agent.Agent.create_agents)
* [`Agent.random`](agent.html#mesa.agent.Agent.random)
* [`Agent.rng`](agent.html#mesa.agent.Agent.rng)
* [`AgentSet`](agent.html#mesa.agent.AgentSet)
* [`AgentSet.model`](agent.html#mesa.agent.AgentSet.model)
* [`AgentSet.select()`](agent.html#mesa.agent.AgentSet.select)
* [`AgentSet.shuffle()`](agent.html#mesa.agent.AgentSet.shuffle)
* [`AgentSet.sort()`](agent.html#mesa.agent.AgentSet.sort)
* [`AgentSet.do()`](agent.html#mesa.agent.AgentSet.do)
* [`AgentSet.shuffle_do()`](agent.html#mesa.agent.AgentSet.shuffle_do)
* [`AgentSet.map()`](agent.html#mesa.agent.AgentSet.map)
* [`AgentSet.agg()`](agent.html#mesa.agent.AgentSet.agg)
* [`AgentSet.get()`](agent.html#mesa.agent.AgentSet.get)
* [`AgentSet.set()`](agent.html#mesa.agent.AgentSet.set)
* [`AgentSet.add()`](agent.html#mesa.agent.AgentSet.add)
* [`AgentSet.discard()`](agent.html#mesa.agent.AgentSet.discard)
* [`AgentSet.remove()`](agent.html#mesa.agent.AgentSet.remove)
* [`AgentSet.groupby()`](agent.html#mesa.agent.AgentSet.groupby)
* [`AgentSet.clear()`](agent.html#mesa.agent.AgentSet.clear)
* [`AgentSet.count()`](agent.html#mesa.agent.AgentSet.count)
* [`AgentSet.index()`](agent.html#mesa.agent.AgentSet.index)
* [`AgentSet.isdisjoint()`](agent.html#mesa.agent.AgentSet.isdisjoint)
* [`AgentSet.pop()`](agent.html#mesa.agent.AgentSet.pop)
* [`GroupBy`](agent.html#mesa.agent.GroupBy)
* [`GroupBy.groups`](agent.html#mesa.agent.GroupBy.groups)
* [`GroupBy.map()`](agent.html#mesa.agent.GroupBy.map)
* [`GroupBy.do()`](agent.html#mesa.agent.GroupBy.do)
* [`GroupBy.count()`](agent.html#mesa.agent.GroupBy.count)
* [`GroupBy.agg()`](agent.html#mesa.agent.GroupBy.agg)
* [Spaces](space.html)
* [Classes](space.html#classes)
* [`accept_tuple_argument()`](space.html#mesa.space.accept_tuple_argument)
* [`is_integer()`](space.html#mesa.space.is_integer)
* [`warn_if_agent_has_position_already()`](space.html#mesa.space.warn_if_agent_has_position_already)
* [`is_single_argument_function()`](space.html#mesa.space.is_single_argument_function)
* [`PropertyLayer`](space.html#mesa.space.PropertyLayer)
* [`PropertyLayer.name`](space.html#mesa.space.PropertyLayer.name)
* [`PropertyLayer.width`](space.html#mesa.space.PropertyLayer.width)
* [`PropertyLayer.height`](space.html#mesa.space.PropertyLayer.height)
* [`PropertyLayer.data`](space.html#mesa.space.PropertyLayer.data)
* [`PropertyLayer.set_cell()`](space.html#mesa.space.PropertyLayer.set_cell)
* [`PropertyLayer.set_cells()`](space.html#mesa.space.PropertyLayer.set_cells)
* [`PropertyLayer.modify_cell()`](space.html#mesa.space.PropertyLayer.modify_cell)
* [`PropertyLayer.modify_cells()`](space.html#mesa.space.PropertyLayer.modify_cells)
* [`PropertyLayer.select_cells()`](space.html#mesa.space.PropertyLayer.select_cells)
* [`PropertyLayer.aggregate_property()`](space.html#mesa.space.PropertyLayer.aggregate_property)
* [`SingleGrid`](space.html#mesa.space.SingleGrid)
* [`SingleGrid.remove_agent()`](space.html#mesa.space.SingleGrid.remove_agent)
* [`SingleGrid.add_property_layer()`](space.html#mesa.space.SingleGrid.add_property_layer)
* [`SingleGrid.agents`](space.html#mesa.space.SingleGrid.agents)
* [`SingleGrid.coord_iter()`](space.html#mesa.space.SingleGrid.coord_iter)
* [`SingleGrid.default_val()`](space.html#mesa.space.SingleGrid.default_val)
* [`SingleGrid.empty_mask`](space.html#mesa.space.SingleGrid.empty_mask)
* [`SingleGrid.exists_empty_cells()`](space.html#mesa.space.SingleGrid.exists_empty_cells)
* [`SingleGrid.get_neighborhood()`](space.html#mesa.space.SingleGrid.get_neighborhood)
* [`SingleGrid.get_neighborhood_mask()`](space.html#mesa.space.SingleGrid.get_neighborhood_mask)
* [`SingleGrid.get_neighbors()`](space.html#mesa.space.SingleGrid.get_neighbors)
* [`SingleGrid.is_cell_empty()`](space.html#mesa.space.SingleGrid.is_cell_empty)
* [`SingleGrid.iter_neighborhood()`](space.html#mesa.space.SingleGrid.iter_neighborhood)
* [`SingleGrid.iter_neighbors()`](space.html#mesa.space.SingleGrid.iter_neighbors)
* [`SingleGrid.move_agent()`](space.html#mesa.space.SingleGrid.move_agent)
* [`SingleGrid.move_agent_to_one_of()`](space.html#mesa.space.SingleGrid.move_agent_to_one_of)
* [`SingleGrid.move_to_empty()`](space.html#mesa.space.SingleGrid.move_to_empty)
* [`SingleGrid.out_of_bounds()`](space.html#mesa.space.SingleGrid.out_of_bounds)
* [`SingleGrid.remove_property_layer()`](space.html#mesa.space.SingleGrid.remove_property_layer)
* [`SingleGrid.select_cells()`](space.html#mesa.space.SingleGrid.select_cells)
* [`SingleGrid.swap_pos()`](space.html#mesa.space.SingleGrid.swap_pos)
* [`SingleGrid.torus_adj()`](space.html#mesa.space.SingleGrid.torus_adj)
* [`MultiGrid`](space.html#mesa.space.MultiGrid)
* [`MultiGrid.default_val()`](space.html#mesa.space.MultiGrid.default_val)
* [`MultiGrid.remove_agent()`](space.html#mesa.space.MultiGrid.remove_agent)
* [`MultiGrid.iter_neighbors()`](space.html#mesa.space.MultiGrid.iter_neighbors)
* [`MultiGrid.add_property_layer()`](space.html#mesa.space.MultiGrid.add_property_layer)
* [`MultiGrid.agents`](space.html#mesa.space.MultiGrid.agents)
* [`MultiGrid.coord_iter()`](space.html#mesa.space.MultiGrid.coord_iter)
* [`MultiGrid.empty_mask`](space.html#mesa.space.MultiGrid.empty_mask)
* [`MultiGrid.exists_empty_cells()`](space.html#mesa.space.MultiGrid.exists_empty_cells)
* [`MultiGrid.get_neighborhood()`](space.html#mesa.space.MultiGrid.get_neighborhood)
* [`MultiGrid.get_neighborhood_mask()`](space.html#mesa.space.MultiGrid.get_neighborhood_mask)
* [`MultiGrid.get_neighbors()`](space.html#mesa.space.MultiGrid.get_neighbors)
* [`MultiGrid.is_cell_empty()`](space.html#mesa.space.MultiGrid.is_cell_empty)
* [`MultiGrid.iter_neighborhood()`](space.html#mesa.space.MultiGrid.iter_neighborhood)
* [`MultiGrid.move_agent()`](space.html#mesa.space.MultiGrid.move_agent)
* [`MultiGrid.move_agent_to_one_of()`](space.html#mesa.space.MultiGrid.move_agent_to_one_of)
* [`MultiGrid.move_to_empty()`](space.html#mesa.space.MultiGrid.move_to_empty)
* [`MultiGrid.out_of_bounds()`](space.html#mesa.space.MultiGrid.out_of_bounds)
* [`MultiGrid.remove_property_layer()`](space.html#mesa.space.MultiGrid.remove_property_layer)
* [`MultiGrid.select_cells()`](space.html#mesa.space.MultiGrid.select_cells)
* [`MultiGrid.swap_pos()`](space.html#mesa.space.MultiGrid.swap_pos)
* [`MultiGrid.torus_adj()`](space.html#mesa.space.MultiGrid.torus_adj)
* [`HexSingleGrid`](space.html#mesa.space.HexSingleGrid)
* [`HexSingleGrid.add_property_layer()`](space.html#mesa.space.HexSingleGrid.add_property_layer)
* [`HexSingleGrid.agents`](space.html#mesa.space.HexSingleGrid.agents)
* [`HexSingleGrid.coord_iter()`](space.html#mesa.space.HexSingleGrid.coord_iter)
* [`HexSingleGrid.default_val()`](space.html#mesa.space.HexSingleGrid.default_val)
* [`HexSingleGrid.empty_mask`](space.html#mesa.space.HexSingleGrid.empty_mask)
* [`HexSingleGrid.exists_empty_cells()`](space.html#mesa.space.HexSingleGrid.exists_empty_cells)
* [`HexSingleGrid.get_neighborhood()`](space.html#mesa.space.HexSingleGrid.get_neighborhood)
* [`HexSingleGrid.get_neighborhood_mask()`](space.html#mesa.space.HexSingleGrid.get_neighborhood_mask)
* [`HexSingleGrid.get_neighbors()`](space.html#mesa.space.HexSingleGrid.get_neighbors)
* [`HexSingleGrid.is_cell_empty()`](space.html#mesa.space.HexSingleGrid.is_cell_empty)
* [`HexSingleGrid.iter_neighborhood()`](space.html#mesa.space.HexSingleGrid.iter_neighborhood)
* [`HexSingleGrid.iter_neighbors()`](space.html#mesa.space.HexSingleGrid.iter_neighbors)
* [`HexSingleGrid.move_agent()`](space.html#mesa.space.HexSingleGrid.move_agent)
* [`HexSingleGrid.move_agent_to_one_of()`](space.html#mesa.space.HexSingleGrid.move_agent_to_one_of)
* [`HexSingleGrid.move_to_empty()`](space.html#mesa.space.HexSingleGrid.move_to_empty)
* [`HexSingleGrid.out_of_bounds()`](space.html#mesa.space.HexSingleGrid.out_of_bounds)
* [`HexSingleGrid.remove_agent()`](space.html#mesa.space.HexSingleGrid.remove_agent)
* [`HexSingleGrid.remove_property_layer()`](space.html#mesa.space.HexSingleGrid.remove_property_layer)
* [`HexSingleGrid.select_cells()`](space.html#mesa.space.HexSingleGrid.select_cells)
* [`HexSingleGrid.swap_pos()`](space.html#mesa.space.HexSingleGrid.swap_pos)
* [`HexSingleGrid.torus_adj()`](space.html#mesa.space.HexSingleGrid.torus_adj)
* [`HexMultiGrid`](space.html#mesa.space.HexMultiGrid)
* [`HexMultiGrid.add_property_layer()`](space.html#mesa.space.HexMultiGrid.add_property_layer)
* [`HexMultiGrid.agents`](space.html#mesa.space.HexMultiGrid.agents)
* [`HexMultiGrid.coord_iter()`](space.html#mesa.space.HexMultiGrid.coord_iter)
* [`HexMultiGrid.default_val()`](space.html#mesa.space.HexMultiGrid.default_val)
* [`HexMultiGrid.empty_mask`](space.html#mesa.space.HexMultiGrid.empty_mask)
* [`HexMultiGrid.exists_empty_cells()`](space.html#mesa.space.HexMultiGrid.exists_empty_cells)
* [`HexMultiGrid.get_neighborhood()`](space.html#mesa.space.HexMultiGrid.get_neighborhood)
* [`HexMultiGrid.get_neighborhood_mask()`](space.html#mesa.space.HexMultiGrid.get_neighborhood_mask)
* [`HexMultiGrid.get_neighbors()`](space.html#mesa.space.HexMultiGrid.get_neighbors)
* [`HexMultiGrid.is_cell_empty()`](space.html#mesa.space.HexMultiGrid.is_cell_empty)
* [`HexMultiGrid.iter_neighborhood()`](space.html#mesa.space.HexMultiGrid.iter_neighborhood)
* [`HexMultiGrid.iter_neighbors()`](space.html#mesa.space.HexMultiGrid.iter_neighbors)
* [`HexMultiGrid.move_agent()`](space.html#mesa.space.HexMultiGrid.move_agent)
* [`HexMultiGrid.move_agent_to_one_of()`](space.html#mesa.space.HexMultiGrid.move_agent_to_one_of)
* [`HexMultiGrid.move_to_empty()`](space.html#mesa.space.HexMultiGrid.move_to_empty)
* [`HexMultiGrid.out_of_bounds()`](space.html#mesa.space.HexMultiGrid.out_of_bounds)
* [`HexMultiGrid.remove_agent()`](space.html#mesa.space.HexMultiGrid.remove_agent)
* [`HexMultiGrid.remove_property_layer()`](space.html#mesa.space.HexMultiGrid.remove_property_layer)
* [`HexMultiGrid.select_cells()`](space.html#mesa.space.HexMultiGrid.select_cells)
* [`HexMultiGrid.swap_pos()`](space.html#mesa.space.HexMultiGrid.swap_pos)
* [`HexMultiGrid.torus_adj()`](space.html#mesa.space.HexMultiGrid.torus_adj)
* [`ContinuousSpace`](space.html#mesa.space.ContinuousSpace)
* [`ContinuousSpace.agents`](space.html#mesa.space.ContinuousSpace.agents)
* [`ContinuousSpace.move_agent()`](space.html#mesa.space.ContinuousSpace.move_agent)
* [`ContinuousSpace.remove_agent()`](space.html#mesa.space.ContinuousSpace.remove_agent)
* [`ContinuousSpace.get_neighbors()`](space.html#mesa.space.ContinuousSpace.get_neighbors)
* [`ContinuousSpace.get_heading()`](space.html#mesa.space.ContinuousSpace.get_heading)
* [`ContinuousSpace.get_distance()`](space.html#mesa.space.ContinuousSpace.get_distance)
* [`ContinuousSpace.torus_adj()`](space.html#mesa.space.ContinuousSpace.torus_adj)
* [`ContinuousSpace.out_of_bounds()`](space.html#mesa.space.ContinuousSpace.out_of_bounds)
* [`NetworkGrid`](space.html#mesa.space.NetworkGrid)
* [`NetworkGrid.agents`](space.html#mesa.space.NetworkGrid.agents)
* [`NetworkGrid.default_val()`](space.html#mesa.space.NetworkGrid.default_val)
* [`NetworkGrid.get_neighborhood()`](space.html#mesa.space.NetworkGrid.get_neighborhood)
* [`NetworkGrid.get_neighbors()`](space.html#mesa.space.NetworkGrid.get_neighbors)
* [`NetworkGrid.move_agent()`](space.html#mesa.space.NetworkGrid.move_agent)
* [`NetworkGrid.remove_agent()`](space.html#mesa.space.NetworkGrid.remove_agent)
* [`NetworkGrid.is_cell_empty()`](space.html#mesa.space.NetworkGrid.is_cell_empty)
* [`NetworkGrid.get_cell_list_contents()`](space.html#mesa.space.NetworkGrid.get_cell_list_contents)
* [`NetworkGrid.get_all_cell_contents()`](space.html#mesa.space.NetworkGrid.get_all_cell_contents)
* [`NetworkGrid.iter_cell_list_contents()`](space.html#mesa.space.NetworkGrid.iter_cell_list_contents)
* [Data collection](datacollection.html)
* [`DataCollector`](datacollection.html#datacollection.DataCollector)
* [`DataCollector.collect()`](datacollection.html#datacollection.DataCollector.collect)
* [`DataCollector.add_table_row()`](datacollection.html#datacollection.DataCollector.add_table_row)
* [`DataCollector.get_model_vars_dataframe()`](datacollection.html#datacollection.DataCollector.get_model_vars_dataframe)
* [`DataCollector.get_agent_vars_dataframe()`](datacollection.html#datacollection.DataCollector.get_agent_vars_dataframe)
* [`DataCollector.get_agenttype_vars_dataframe()`](datacollection.html#datacollection.DataCollector.get_agenttype_vars_dataframe)
* [`DataCollector.get_table_dataframe()`](datacollection.html#datacollection.DataCollector.get_table_dataframe)
* [Batchrunner](batchrunner.html)
* [`batch_run()`](batchrunner.html#batchrunner.batch_run)
* [Visualization](visualization.html)
* [Jupyter Visualization](visualization.html#module-mesa.visualization.solara_viz)
* [`split_model_params()`](visualization.html#mesa.visualization.solara_viz.split_model_params)
* [`check_param_is_fixed()`](visualization.html#mesa.visualization.solara_viz.check_param_is_fixed)
* [`make_initial_grid_layout()`](visualization.html#mesa.visualization.solara_viz.make_initial_grid_layout)
* [`make_space_component()`](visualization.html#mesa.visualization.components.__init__.make_space_component)
* [`make_plot_component()`](visualization.html#mesa.visualization.components.__init__.make_plot_component)
* [User Parameters](visualization.html#module-mesa.visualization.user_param)
* [`UserParam`](visualization.html#mesa.visualization.user_param.UserParam)
* [`Slider`](visualization.html#mesa.visualization.user_param.Slider)
* [Matplotlib-based visualizations](visualization.html#module-mesa.visualization.components.matplotlib_components)
* [`make_space_matplotlib()`](visualization.html#mesa.visualization.components.matplotlib_components.make_space_matplotlib)
* [`make_mpl_space_component()`](visualization.html#mesa.visualization.components.matplotlib_components.make_mpl_space_component)
* [`make_plot_measure()`](visualization.html#mesa.visualization.components.matplotlib_components.make_plot_measure)
* [`make_mpl_plot_component()`](visualization.html#mesa.visualization.components.matplotlib_components.make_mpl_plot_component)
* [`collect_agent_data()`](visualization.html#mesa.visualization.mpl_space_drawing.collect_agent_data)
* [`draw_space()`](visualization.html#mesa.visualization.mpl_space_drawing.draw_space)
* [`draw_property_layers()`](visualization.html#mesa.visualization.mpl_space_drawing.draw_property_layers)
* [`draw_orthogonal_grid()`](visualization.html#mesa.visualization.mpl_space_drawing.draw_orthogonal_grid)
* [`draw_hex_grid()`](visualization.html#mesa.visualization.mpl_space_drawing.draw_hex_grid)
* [`draw_network()`](visualization.html#mesa.visualization.mpl_space_drawing.draw_network)
* [`draw_continuous_space()`](visualization.html#mesa.visualization.mpl_space_drawing.draw_continuous_space)
* [`draw_voronoi_grid()`](visualization.html#mesa.visualization.mpl_space_drawing.draw_voronoi_grid)
* [Altair-based visualizations](visualization.html#module-mesa.visualization.components.altair_components)
* [`make_space_altair()`](visualization.html#mesa.visualization.components.altair_components.make_space_altair)
* [`make_altair_space()`](visualization.html#mesa.visualization.components.altair_components.make_altair_space)
* [Experimental](experimental.html)
* [Cell Space](experimental.html#module-experimental.cell_space.__init__)
* [`Cell`](experimental.html#experimental.cell_space.__init__.Cell)
* [`CellAgent`](experimental.html#experimental.cell_space.__init__.CellAgent)
* [`CellCollection`](experimental.html#experimental.cell_space.__init__.CellCollection)
* [`DiscreteSpace`](experimental.html#experimental.cell_space.__init__.DiscreteSpace)
* [`FixedAgent`](experimental.html#experimental.cell_space.__init__.FixedAgent)
* [`Grid`](experimental.html#experimental.cell_space.__init__.Grid)
* [`Grid2DMovingAgent`](experimental.html#experimental.cell_space.__init__.Grid2DMovingAgent)
* [`HexGrid`](experimental.html#experimental.cell_space.__init__.HexGrid)
* [`Network`](experimental.html#experimental.cell_space.__init__.Network)
* [`OrthogonalMooreGrid`](experimental.html#experimental.cell_space.__init__.OrthogonalMooreGrid)
* [`OrthogonalVonNeumannGrid`](experimental.html#experimental.cell_space.__init__.OrthogonalVonNeumannGrid)
* [`PropertyLayer`](experimental.html#experimental.cell_space.__init__.PropertyLayer)
* [`VoronoiGrid`](experimental.html#experimental.cell_space.__init__.VoronoiGrid)
* [`Cell`](experimental.html#experimental.cell_space.cell.Cell)
* [`HasCellProtocol`](experimental.html#experimental.cell_space.cell_agent.HasCellProtocol)
* [`HasCell`](experimental.html#experimental.cell_space.cell_agent.HasCell)
* [`BasicMovement`](experimental.html#experimental.cell_space.cell_agent.BasicMovement)
* [`FixedCell`](experimental.html#experimental.cell_space.cell_agent.FixedCell)
* [`CellAgent`](experimental.html#experimental.cell_space.cell_agent.CellAgent)
* [`FixedAgent`](experimental.html#experimental.cell_space.cell_agent.FixedAgent)
* [`Grid2DMovingAgent`](experimental.html#experimental.cell_space.cell_agent.Grid2DMovingAgent)
* [`CellCollection`](experimental.html#experimental.cell_space.cell_collection.CellCollection)
* [`DiscreteSpace`](experimental.html#experimental.cell_space.discrete_space.DiscreteSpace)
* [`pickle_gridcell()`](experimental.html#experimental.cell_space.grid.pickle_gridcell)
* [`unpickle_gridcell()`](experimental.html#experimental.cell_space.grid.unpickle_gridcell)
* [`Grid`](experimental.html#experimental.cell_space.grid.Grid)
* [`OrthogonalMooreGrid`](experimental.html#experimental.cell_space.grid.OrthogonalMooreGrid)
* [`OrthogonalVonNeumannGrid`](experimental.html#experimental.cell_space.grid.OrthogonalVonNeumannGrid)
* [`HexGrid`](experimental.html#experimental.cell_space.grid.HexGrid)
* [`Network`](experimental.html#experimental.cell_space.network.Network)
* [`Delaunay`](experimental.html#experimental.cell_space.voronoi.Delaunay)
* [`VoronoiGrid`](experimental.html#experimental.cell_space.voronoi.VoronoiGrid)
* [Devs](experimental.html#module-experimental.devs.eventlist)
* [`Priority`](experimental.html#experimental.devs.eventlist.Priority)
* [`SimulationEvent`](experimental.html#experimental.devs.eventlist.SimulationEvent)
* [`EventList`](experimental.html#experimental.devs.eventlist.EventList)
* [`Simulator`](experimental.html#experimental.devs.simulator.Simulator)
* [`ABMSimulator`](experimental.html#experimental.devs.simulator.ABMSimulator)
* [`DEVSimulator`](experimental.html#experimental.devs.simulator.DEVSimulator)
* [Continuous Space](experimental.html#module-experimental.continuous_space.continuous_space)
* [`ContinuousSpace`](experimental.html#experimental.continuous_space.continuous_space.ContinuousSpace)
* [`HasPositionProtocol`](experimental.html#experimental.continuous_space.continuous_space_agents.HasPositionProtocol)
* [`ContinuousSpaceAgent`](experimental.html#experimental.continuous_space.continuous_space_agents.ContinuousSpaceAgent)
### This Page
* [Show Source](../_sources/apis/api_main.md.txt)
---
# Unknown
\# Epstein Civil Violence Model ## Summary This model is based on Joshua Epstein's simulation of how civil unrest grows and is suppressed. Citizen agents wander the grid randomly, and are endowed with individual risk aversion and hardship levels; there is also a universal regime legitimacy value. There are also Cop agents, who work on behalf of the regime. Cops arrest Citizens who are actively rebelling; Citizens decide whether to rebel based on their hardship and the regime legitimacy, and their perceived probability of arrest. The model generates mass uprising as self-reinforcing processes: if enough agents are rebelling, the probability of any individual agent being arrested is reduced, making more agents more likely to join the uprising. However, the more rebelling Citizens the Cops arrest, the less likely additional agents become to join. ## How to Run To run the model interactively, in this directory, run the following command \`\`\` $ solara run app.py \`\`\` ## Files \* \`\`model.py\`\`: Core model code. \* \`\`agent.py\`\`: Agent classes. \* \`\`app.py\`\`: Sets up the interactive visualization. \* \`\`Epstein Civil Violence.ipynb\`\`: Jupyter notebook conducting some preliminary analysis of the model. ## Further Reading This model is based adapted from: \[Epstein, J. “Modeling civil violence: An agent-based computational approach”, Proceedings of the National Academy of Sciences, Vol. 99, Suppl. 3, May 14, 2002\](http://www.pnas.org/content/99/suppl.3/7243.short) A similar model is also included with NetLogo: Wilensky, U. (2004). NetLogo Rebellion model. http://ccl.northwestern.edu/netlogo/models/Rebellion. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL. ## Agents \`\`\`python import math from enum import Enum import mesa class CitizenState(Enum): ACTIVE = 1 QUIET = 2 ARRESTED = 3 class EpsteinAgent(mesa.discrete\_space.CellAgent): def update\_neighbors(self): """ Look around and see who my neighbors are """ self.neighborhood = self.cell.get\_neighborhood(radius=self.vision) self.neighbors = self.neighborhood.agents self.empty\_neighbors = \[c for c in self.neighborhood if c.is\_empty\] def move(self): if self.model.movement and self.empty\_neighbors: new\_pos = self.random.choice(self.empty\_neighbors) self.move\_to(new\_pos) class Citizen(EpsteinAgent): """ A member of the general population, may or may not be in active rebellion. Summary of rule: If grievance - risk > threshold, rebel. Attributes: hardship: Agent's 'perceived hardship (i.e., physical or economic privation).' Exogenous, drawn from U(0,1). regime\_legitimacy: Agent's perception of regime legitimacy, equal across agents. Exogenous. risk\_aversion: Exogenous, drawn from U(0,1). threshold: if (grievance - (risk\_aversion \* arrest\_probability)) > threshold, go/remain Active vision: number of cells in each direction (N, S, E and W) that agent can inspect condition: Can be "Quiescent" or "Active;" deterministic function of greivance, perceived risk, and grievance: deterministic function of hardship and regime\_legitimacy; how aggrieved is agent at the regime? arrest\_probability: agent's assessment of arrest probability, given rebellion """ def \_\_init\_\_( self, model, regime\_legitimacy, threshold, vision, arrest\_prob\_constant ): """ Create a new Citizen. Args: model: the model to which the agent belongs hardship: Agent's 'perceived hardship (i.e., physical or economic privation).' Exogenous, drawn from U(0,1). regime\_legitimacy: Agent's perception of regime legitimacy, equal across agents. Exogenous. risk\_aversion: Exogenous, drawn from U(0,1). threshold: if (grievance - (risk\_aversion \* arrest\_probability)) > threshold, go/remain Active vision: number of cells in each direction (N, S, E and W) that agent can inspect. Exogenous. model: model instance """ super().\_\_init\_\_(model) self.hardship = self.random.random() self.risk\_aversion = self.random.random() self.regime\_legitimacy = regime\_legitimacy self.threshold = threshold self.state = CitizenState.QUIET self.vision = vision self.jail\_sentence = 0 self.grievance = self.hardship \* (1 - self.regime\_legitimacy) self.arrest\_prob\_constant = arrest\_prob\_constant self.arrest\_probability = None self.neighborhood = \[\] self.neighbors = \[\] self.empty\_neighbors = \[\] def step(self): """ Decide whether to activate, then move if applicable. """ if self.jail\_sentence: self.jail\_sentence -= 1 return # no other changes or movements if agent is in jail. self.update\_neighbors() self.update\_estimated\_arrest\_probability() net\_risk = self.risk\_aversion \* self.arrest\_probability if (self.grievance - net\_risk) > self.threshold: self.state = CitizenState.ACTIVE else: self.state = CitizenState.QUIET self.move() def update\_estimated\_arrest\_probability(self): """ Based on the ratio of cops to actives in my neighborhood, estimate the p(Arrest | I go active). """ cops\_in\_vision = 0 actives\_in\_vision = 1 # citizen counts herself for neighbor in self.neighbors: if isinstance(neighbor, Cop): cops\_in\_vision += 1 elif neighbor.state == CitizenState.ACTIVE: actives\_in\_vision += 1 # there is a body of literature on this equation # the round is not in the pnas paper but without it, its impossible to replicate # the dynamics shown there. self.arrest\_probability = 1 - math.exp( -1 \* self.arrest\_prob\_constant \* round(cops\_in\_vision / actives\_in\_vision) ) class Cop(EpsteinAgent): """ A cop for life. No defection. Summary of rule: Inspect local vision and arrest a random active agent. Attributes: unique\_id: unique int x, y: Grid coordinates vision: number of cells in each direction (N, S, E and W) that cop is able to inspect """ def \_\_init\_\_(self, model, vision, max\_jail\_term): """ Create a new Cop. Args: x, y: Grid coordinates vision: number of cells in each direction (N, S, E and W) that agent can inspect. Exogenous. model: model instance """ super().\_\_init\_\_(model) self.vision = vision self.max\_jail\_term = max\_jail\_term def step(self): """ Inspect local vision and arrest a random active agent. Move if applicable. """ self.update\_neighbors() active\_neighbors = \[\] for agent in self.neighbors: if isinstance(agent, Citizen) and agent.state == CitizenState.ACTIVE: active\_neighbors.append(agent) if active\_neighbors: arrestee = self.random.choice(active\_neighbors) arrestee.jail\_sentence = self.random.randint(0, self.max\_jail\_term) arrestee.state = CitizenState.ARRESTED self.move() \`\`\` ## Model \`\`\`python import mesa from mesa.examples.advanced.epstein\_civil\_violence.agents import ( Citizen, CitizenState, Cop, ) class EpsteinCivilViolence(mesa.Model): """ Model 1 from "Modeling civil violence: An agent-based computational approach," by Joshua Epstein. http://www.pnas.org/content/99/suppl\_3/7243.full Args: height: grid height width: grid width citizen\_density: approximate % of cells occupied by citizens. cop\_density: approximate % of cells occupied by cops. citizen\_vision: number of cells in each direction (N, S, E and W) that citizen can inspect cop\_vision: number of cells in each direction (N, S, E and W) that cop can inspect legitimacy: (L) citizens' perception of regime legitimacy, equal across all citizens max\_jail\_term: (J\_max) active\_threshold: if (grievance - (risk\_aversion \* arrest\_probability)) > threshold, citizen rebels arrest\_prob\_constant: set to ensure agents make plausible arrest probability estimates movement: binary, whether agents try to move at step end max\_iters: model may not have a natural stopping point, so we set a max. """ def \_\_init\_\_( self, width=40, height=40, citizen\_density=0.7, cop\_density=0.074, citizen\_vision=7, cop\_vision=7, legitimacy=0.8, max\_jail\_term=1000, active\_threshold=0.1, arrest\_prob\_constant=2.3, movement=True, max\_iters=1000, seed=None, ): super().\_\_init\_\_(seed=seed) self.movement = movement self.max\_iters = max\_iters self.grid = mesa.discrete\_space.OrthogonalVonNeumannGrid( (width, height), capacity=1, torus=True, random=self.random ) model\_reporters = { "active": CitizenState.ACTIVE.name, "quiet": CitizenState.QUIET.name, "arrested": CitizenState.ARRESTED.name, } agent\_reporters = { "jail\_sentence": lambda a: getattr(a, "jail\_sentence", None), "arrest\_probability": lambda a: getattr(a, "arrest\_probability", None), } self.datacollector = mesa.DataCollector( model\_reporters=model\_reporters, agent\_reporters=agent\_reporters ) if cop\_density + citizen\_density > 1: raise ValueError("Cop density + citizen density must be less than 1") for cell in self.grid.all\_cells: klass = self.random.choices( \[Citizen, Cop, None\], cum\_weights=\[citizen\_density, citizen\_density + cop\_density, 1\], )\[0\] if klass == Cop: cop = Cop(self, vision=cop\_vision, max\_jail\_term=max\_jail\_term) cop.move\_to(cell) elif klass == Citizen: citizen = Citizen( self, regime\_legitimacy=legitimacy, threshold=active\_threshold, vision=citizen\_vision, arrest\_prob\_constant=arrest\_prob\_constant, ) citizen.move\_to(cell) self.running = True self.\_update\_counts() self.datacollector.collect(self) def step(self): """ Advance the model by one step and collect data. """ self.agents.shuffle\_do("step") self.\_update\_counts() self.datacollector.collect(self) if self.steps > self.max\_iters: self.running = False def \_update\_counts(self): """Helper function for counting nr. of citizens in given state.""" counts = self.agents\_by\_type\[Citizen\].groupby("state").count() for state in CitizenState: setattr(self, state.name, counts.get(state, 0)) \`\`\` ## App \`\`\`python from mesa.examples.advanced.epstein\_civil\_violence.agents import ( Citizen, CitizenState, Cop, ) from mesa.examples.advanced.epstein\_civil\_violence.model import EpsteinCivilViolence from mesa.visualization import ( Slider, SolaraViz, make\_plot\_component, make\_space\_component, ) COP\_COLOR = "#000000" agent\_colors = { CitizenState.ACTIVE: "#FE6100", CitizenState.QUIET: "#648FFF", CitizenState.ARRESTED: "#808080", } def citizen\_cop\_portrayal(agent): if agent is None: return portrayal = { "size": 50, } if isinstance(agent, Citizen): portrayal\["color"\] = agent\_colors\[agent.state\] elif isinstance(agent, Cop): portrayal\["color"\] = COP\_COLOR return portrayal def post\_process(ax): ax.set\_aspect("equal") ax.set\_xticks(\[\]) ax.set\_yticks(\[\]) ax.get\_figure().set\_size\_inches(10, 10) model\_params = { "seed": { "type": "InputText", "value": 42, "label": "Random Seed", }, "height": 40, "width": 40, "citizen\_density": Slider("Initial Agent Density", 0.7, 0.0, 0.9, 0.1), "cop\_density": Slider("Initial Cop Density", 0.04, 0.0, 0.1, 0.01), "citizen\_vision": Slider("Citizen Vision", 7, 1, 10, 1), "cop\_vision": Slider("Cop Vision", 7, 1, 10, 1), "legitimacy": Slider("Government Legitimacy", 0.82, 0.0, 1, 0.01), "max\_jail\_term": Slider("Max Jail Term", 30, 0, 50, 1), } space\_component = make\_space\_component( citizen\_cop\_portrayal, post\_process=post\_process, draw\_grid=False ) chart\_component = make\_plot\_component( {state.name.lower(): agent\_colors\[state\] for state in CitizenState} ) epstein\_model = EpsteinCivilViolence() page = SolaraViz( epstein\_model, components=\[space\_component, chart\_component\], model\_params=model\_params, name="Epstein Civil Violence", ) page # noqa \`\`\`
---
# Unknown
\# Sugarscape Constant Growback Model with Traders ## Summary This is Epstein & Axtell's Sugarscape model with Traders, a detailed description is in Chapter four of \*Growing Artificial Societies: Social Science from the Bottom Up (1996)\*. The model shows an emergent price equilibrium can happen via a decentralized dynamics. This code generally matches the code in the Complexity Explorer Tutorial, but in \`.py\` instead of \`.ipynb\` format. ### Agents: - \*\*Resource\*\*: Resource agents grow back at one unit of sugar and spice per time step up to a specified max amount and can be harvested and traded by the trader agents. (if you do the interactive run, the color will be green if the resource agent has a bigger amount of sugar, or yellow if it has a bigger amount of spice) - \*\*Traders\*\*: Trader agents have the following attributes: (1) metabolism for sugar, (2) metabolism for spice, (3) vision, (4) initial sugar endowment and (5) initial spice endowment. The traverse the landscape harvesting sugar and spice and trading with other agents. If they run out of sugar or spice then they are removed from the model. (red circle if you do the interactive run) The trader agents traverse the landscape according to rule \*\*M\*\*: - Look out as far as vision permits in the four principal lattice directions and identify the unoccupied site(s). - Considering only unoccupied sites find the nearest position that produces the most welfare using the Cobb-Douglas function. - Move to the new position - Collect all the resources (sugar and spice) at that location (Epstein and Axtell, 1996, p. 99) The traders trade according to rule \*\*T\*\*: - Agents and potential trade partner compute their marginal rates of substitution (MRS), if they are equal \*end\*. - Exchange resources, with spice flowing from the agent with the higher MRS to the agent with the lower MRS and sugar flowing the opposite direction. - The price (p) is calculated by taking the geometric mean of the agents' MRS. - If p > 1 then p units of spice are traded for 1 unit of sugar; if p < 1 then 1/p units of sugar for 1 unit of spice - The trade occurs if it will (a) make both agent better off (increases MRS) and (b) does not cause the agents' MRS to cross over one another otherwise \*end\*. - This process then repeats until an \*end\* condition is met. (Epstein and Axtell, 1996, p. 105) The model demonstrates several Mesa concepts and features: - OrthogonalMooreGrid - Multiple agent types (traders, sugar, spice) - Dynamically removing agents from the grid and schedule when they die - Data Collection at the model and agent level - custom solara matplotlib space visualization ## How to Run To run the model interactively: \`\`\` $ solara run app.py \`\`\` Then open your browser to \[http://127.0.0.1:8521/\](http://127.0.0.1:8521/) and press Reset, then Run. ## Files \* \`model.py\`: The Sugarscape Constant Growback with Traders model. \* \`agents.py\`: Defines the Trader agent class and the Resource agent class which contains an amount of sugar and spice. \* \`app.py\`: Runs a visualization server via Solara (\`solara run app.py\`). \* \`sugar\_map.txt\`: Provides sugar and spice landscape in raster type format. \* \`tests.py\`: Has tests to ensure that the model reproduces the results in shown in Growing Artificial Societies. ## Additional Resources - \[Growing Artificial Societies\](https://mitpress.mit.edu/9780262550253/growing-artificial-societies/) - \[Complexity Explorer Sugarscape with Traders Tutorial\](https://www.complexityexplorer.org/courses/172-agent-based-models-with-python-an-introduction-to-mesa) ## Agents \`\`\`python import math from mesa.discrete\_space import CellAgent # Helper function def get\_distance(cell\_1, cell\_2): """ Calculate the Euclidean distance between two positions used in trade.move() """ x1, y1 = cell\_1.coordinate x2, y2 = cell\_2.coordinate dx = x1 - x2 dy = y1 - y2 return math.sqrt(dx\*\*2 + dy\*\*2) class Trader(CellAgent): """ Trader: - has a metabolism of sugar and spice - harvest and trade sugar and spice to survive """ def \_\_init\_\_( self, model, cell, sugar=0, spice=0, metabolism\_sugar=0, metabolism\_spice=0, vision=0, ): super().\_\_init\_\_(model) self.cell = cell self.sugar = sugar self.spice = spice self.metabolism\_sugar = metabolism\_sugar self.metabolism\_spice = metabolism\_spice self.vision = vision self.prices = \[\] self.trade\_partners = \[\] def get\_trader(self, cell): """ helper function used in self.trade\_with\_neighbors() """ for agent in cell.agents: if isinstance(agent, Trader): return agent def calculate\_welfare(self, sugar, spice): """ helper function part 2 self.move() self.trade() """ # calculate total resources m\_total = self.metabolism\_sugar + self.metabolism\_spice # Cobb-Douglas functional form; starting on p. 97 # on Growing Artificial Societies return sugar \*\* (self.metabolism\_sugar / m\_total) \* spice \*\* ( self.metabolism\_spice / m\_total ) def is\_starved(self): """ Helper function for self.maybe\_die() """ return (self.sugar <= 0) or (self.spice <= 0) def calculate\_MRS(self, sugar, spice): """ Helper function for - self.trade() - self.maybe\_self\_spice() Determines what trader agent needs and can give up """ return (spice / self.metabolism\_spice) / (sugar / self.metabolism\_sugar) def calculate\_sell\_spice\_amount(self, price): """ helper function for self.maybe\_sell\_spice() which is called from self.trade() """ if price >= 1: sugar = 1 spice = int(price) else: sugar = int(1 / price) spice = 1 return sugar, spice def sell\_spice(self, other, sugar, spice): """ used in self.maybe\_sell\_spice() exchanges sugar and spice between traders """ self.sugar += sugar other.sugar -= sugar self.spice -= spice other.spice += spice def maybe\_sell\_spice(self, other, price, welfare\_self, welfare\_other): """ helper function for self.trade() """ sugar\_exchanged, spice\_exchanged = self.calculate\_sell\_spice\_amount(price) # Assess new sugar and spice amount - what if change did occur self\_sugar = self.sugar + sugar\_exchanged other\_sugar = other.sugar - sugar\_exchanged self\_spice = self.spice - spice\_exchanged other\_spice = other.spice + spice\_exchanged # double check to ensure agents have resources if ( (self\_sugar <= 0) or (other\_sugar <= 0) or (self\_spice <= 0) or (other\_spice <= 0) ): return False # trade criteria #1 - are both agents better off? both\_agents\_better\_off = ( welfare\_self < self.calculate\_welfare(self\_sugar, self\_spice) ) and (welfare\_other < other.calculate\_welfare(other\_sugar, other\_spice)) # trade criteria #2 is their mrs crossing with potential trade mrs\_not\_crossing = self.calculate\_MRS( self\_sugar, self\_spice ) > other.calculate\_MRS(other\_sugar, other\_spice) if not (both\_agents\_better\_off and mrs\_not\_crossing): return False # criteria met, execute trade self.sell\_spice(other, sugar\_exchanged, spice\_exchanged) return True def trade(self, other): """ helper function used in trade\_with\_neighbors() other is a trader agent object """ # sanity check to verify code is working as expected assert self.sugar > 0 assert self.spice > 0 assert other.sugar > 0 assert other.spice > 0 # calculate marginal rate of substitution in Growing Artificial Societies p. 101 mrs\_self = self.calculate\_MRS(self.sugar, self.spice) mrs\_other = other.calculate\_MRS(other.sugar, other.spice) # calculate each agents welfare welfare\_self = self.calculate\_welfare(self.sugar, self.spice) welfare\_other = other.calculate\_welfare(other.sugar, other.spice) if math.isclose(mrs\_self, mrs\_other): return # calculate price price = math.sqrt(mrs\_self \* mrs\_other) if mrs\_self > mrs\_other: # self is a sugar buyer, spice seller sold = self.maybe\_sell\_spice(other, price, welfare\_self, welfare\_other) # no trade - criteria not met if not sold: return else: # self is a spice buyer, sugar seller sold = other.maybe\_sell\_spice(self, price, welfare\_other, welfare\_self) # no trade - criteria not met if not sold: return # Capture data self.prices.append(price) self.trade\_partners.append(other.unique\_id) # continue trading self.trade(other) ###################################################################### # # # MAIN TRADE FUNCTIONS # # # ###################################################################### def move(self): """ Function for trader agent to identify optimal move for each step in 4 parts 1 - identify all possible moves 2 - determine which move maximizes welfare 3 - find closest best option 4 - move """ # 1. identify all possible moves neighboring\_cells = \[ cell for cell in self.cell.get\_neighborhood(self.vision, include\_center=True) if cell.is\_empty \] # 2. determine which move maximizes welfare welfares = \[ self.calculate\_welfare( self.sugar + cell.sugar, self.spice + cell.spice, ) for cell in neighboring\_cells \] # 3. Find closest best option # find the highest welfare in welfares max\_welfare = max(welfares) # get the index of max welfare cells # fixme: rewrite using enumerate and single loop candidate\_indices = \[ i for i in range(len(welfares)) if math.isclose(welfares\[i\], max\_welfare) \] # convert index to positions of those cells candidates = \[neighboring\_cells\[i\] for i in candidate\_indices\] min\_dist = min(get\_distance(self.cell, cell) for cell in candidates) final\_candidates = \[ cell for cell in candidates if math.isclose(get\_distance(self.cell, cell), min\_dist, rel\_tol=1e-02) \] # 4. Move Agent self.cell = self.random.choice(final\_candidates) def eat(self): self.sugar += self.cell.sugar self.cell.sugar = 0 self.sugar -= self.metabolism\_sugar self.spice += self.cell.spice self.cell.spice = 0 self.spice -= self.metabolism\_spice def maybe\_die(self): """ Function to remove Traders who have consumed all their sugar or spice """ if self.is\_starved(): self.remove() def trade\_with\_neighbors(self): """ Function for trader agents to decide who to trade with in three parts 1- identify neighbors who can trade 2- trade (2 sessions) 3- collect data """ # iterate through traders in neighboring cells and trade for a in self.cell.get\_neighborhood(radius=self.vision).agents: self.trade(a) return \`\`\` ## Model \`\`\`python from pathlib import Path import numpy as np import mesa from mesa.discrete\_space import OrthogonalVonNeumannGrid from mesa.discrete\_space.property\_layer import PropertyLayer from mesa.examples.advanced.sugarscape\_g1mt.agents import Trader # Helper Functions def flatten(list\_of\_lists): """ helper function for model datacollector for trade price collapses agent price list into one list """ return \[item for sublist in list\_of\_lists for item in sublist\] def geometric\_mean(list\_of\_prices): """ find the geometric mean of a list of prices """ return np.exp(np.log(list\_of\_prices).mean()) def get\_trade(agent): """ For agent reporters in data collector return list of trade partners and None for other agents """ if isinstance(agent, Trader): return agent.trade\_partners else: return None class SugarscapeG1mt(mesa.Model): """ Manager class to run Sugarscape with Traders """ def \_\_init\_\_( self, width=50, height=50, initial\_population=200, endowment\_min=25, endowment\_max=50, metabolism\_min=1, metabolism\_max=5, vision\_min=1, vision\_max=5, enable\_trade=True, seed=None, ): super().\_\_init\_\_(seed=seed) # Initiate width and height of sugarscape self.width = width self.height = height # Initiate population attributes self.enable\_trade = enable\_trade self.running = True # initiate mesa grid class self.grid = OrthogonalVonNeumannGrid( (self.width, self.height), torus=False, random=self.random ) # initiate datacollector self.datacollector = mesa.DataCollector( model\_reporters={ "#Traders": lambda m: len(m.agents), "Trade Volume": lambda m: sum(len(a.trade\_partners) for a in m.agents), "Price": lambda m: geometric\_mean( flatten(\[a.prices for a in m.agents\]) ), }, agent\_reporters={"Trade Network": lambda a: get\_trade(a)}, ) # read in landscape file from supplementary material self.sugar\_distribution = np.genfromtxt(Path(\_\_file\_\_).parent / "sugar-map.txt") self.spice\_distribution = np.flip(self.sugar\_distribution, 1) self.grid.add\_property\_layer( PropertyLayer.from\_data("sugar", self.sugar\_distribution) ) self.grid.add\_property\_layer( PropertyLayer.from\_data("spice", self.spice\_distribution) ) Trader.create\_agents( self, initial\_population, self.random.choices(self.grid.all\_cells.cells, k=initial\_population), sugar=self.rng.integers( endowment\_min, endowment\_max, (initial\_population,), endpoint=True ), spice=self.rng.integers( endowment\_min, endowment\_max, (initial\_population,), endpoint=True ), metabolism\_sugar=self.rng.integers( metabolism\_min, metabolism\_max, (initial\_population,), endpoint=True ), metabolism\_spice=self.rng.integers( metabolism\_min, metabolism\_max, (initial\_population,), endpoint=True ), vision=self.rng.integers( vision\_min, vision\_max, (initial\_population,), endpoint=True ), ) def step(self): """ Unique step function that does staged activation of sugar and spice and then randomly activates traders """ # step Resource agents self.grid.sugar.data = np.minimum( self.grid.sugar.data + 1, self.sugar\_distribution ) self.grid.spice.data = np.minimum( self.grid.spice.data + 1, self.spice\_distribution ) # step trader agents # to account for agent death and removal we need a separate data structure to # iterate trader\_shuffle = self.agents\_by\_type\[Trader\].shuffle() for agent in trader\_shuffle: agent.prices = \[\] agent.trade\_partners = \[\] agent.move() agent.eat() agent.maybe\_die() if not self.enable\_trade: # If trade is not enabled, return early self.datacollector.collect(self) return trader\_shuffle = self.agents\_by\_type\[Trader\].shuffle() for agent in trader\_shuffle: agent.trade\_with\_neighbors() # collect model level data # fixme we can already collect agent class data # fixme, we don't have resource agents anymore so this can be done simpler self.datacollector.collect(self) """ Mesa is working on updating datacollector agent reporter so it can collect information on specific agents from mesa.time.RandomActivationByType. Please see issue #1419 at https://github.com/projectmesa/mesa/issues/1419 (contributions welcome) Below is one way to update agent\_records to get specific Trader agent data """ # Need to remove excess data # Create local variable to store trade data agent\_trades = self.datacollector.\_agent\_records\[self.steps\] # Get rid of all None to reduce data storage needs agent\_trades = \[agent for agent in agent\_trades if agent\[2\] is not None\] # Reassign the dictionary value with lean trade data self.datacollector.\_agent\_records\[self.steps\] = agent\_trades def run\_model(self, step\_count=1000): for \_ in range(step\_count): self.step() \`\`\` ## App \`\`\`python from mesa.examples.advanced.sugarscape\_g1mt.model import SugarscapeG1mt from mesa.visualization import Slider, SolaraViz, make\_plot\_component from mesa.visualization.components.matplotlib\_components import make\_mpl\_space\_component def agent\_portrayal(agent): return {"marker": "o", "color": "red", "size": 10} propertylayer\_portrayal = { "sugar": {"color": "blue", "alpha": 0.8, "colorbar": True, "vmin": 0, "vmax": 10}, "spice": {"color": "red", "alpha": 0.8, "colorbar": True, "vmin": 0, "vmax": 10}, } sugarscape\_space = make\_mpl\_space\_component( agent\_portrayal=agent\_portrayal, propertylayer\_portrayal=propertylayer\_portrayal, post\_process=None, draw\_grid=False, ) model\_params = { "seed": { "type": "InputText", "value": 42, "label": "Random Seed", }, "width": 50, "height": 50, # Population parameters "initial\_population": Slider( "Initial Population", value=200, min=50, max=500, step=10 ), # Agent endowment parameters "endowment\_min": Slider("Min Initial Endowment", value=25, min=5, max=30, step=1), "endowment\_max": Slider("Max Initial Endowment", value=50, min=30, max=100, step=1), # Metabolism parameters "metabolism\_min": Slider("Min Metabolism", value=1, min=1, max=3, step=1), "metabolism\_max": Slider("Max Metabolism", value=5, min=3, max=8, step=1), # Vision parameters "vision\_min": Slider("Min Vision", value=1, min=1, max=3, step=1), "vision\_max": Slider("Max Vision", value=5, min=3, max=8, step=1), # Trade parameter "enable\_trade": {"type": "Checkbox", "value": True, "label": "Enable Trading"}, } model = SugarscapeG1mt() page = SolaraViz( model, components=\[ sugarscape\_space, make\_plot\_component("#Traders"), make\_plot\_component("Price"), \], model\_params=model\_params, name="Sugarscape {G1, M, T}", play\_interval=150, ) page # noqa \`\`\`
---
# Unknown
\# Mesa Core Examples This repository contains a curated set of classic agent-based models implemented using Mesa. These core examples are maintained by the Mesa development team and serve as both demonstrations of Mesa's capabilities and starting points for your own models. ## Overview The examples are categorized into two groups: 1. \*\*Basic Examples\*\* - Simpler models that use only stable Mesa features; ideal for beginners 2. \*\*Advanced Examples\*\* - More complex models that demonstrate additional concepts and may use some experimental features > \*\*Note:\*\* Looking for more examples? Visit the \[mesa-examples\](https://github.com/projectmesa/mesa-examples) repository for user-contributed models and showcases. ## Basic Examples The basic examples are relatively simple and only use stable Mesa features. They are good starting points for learning how to use Mesa. ### \[Boltzmann Wealth Model\](examples/basic/boltzmann\_wealth\_model) Completed code to go along with the \[tutorial\](https://mesa.readthedocs.io/latest/tutorials/intro\_tutorial.html) on making a simple model of how a highly-skewed wealth distribution can emerge from simple rules. ### \[Boids Flockers Model\](examples/basic/boid\_flockers) \[Boids\](https://en.wikipedia.org/wiki/Boids)-style flocking model, demonstrating the use of agents moving through a continuous space following direction vectors. ### \[Conway's Game of Life\](examples/basic/conways\_game\_of\_life) Implementation of \[Conway's Game of Life\](https://en.wikipedia.org/wiki/Conway%27s\_Game\_of\_Life), a cellular automata where simple rules can give rise to complex patterns. ### \[Schelling Segregation Model\](examples/basic/schelling) Mesa implementation of the classic \[Schelling segregation\](http://nifty.stanford.edu/2014/mccown-schelling-model-segregation/) model. ### \[Virus on a Network Model\](examples/basic/virus\_on\_network) This model is based on the NetLogo \[Virus on a Network\](https://ccl.northwestern.edu/netlogo/models/VirusonaNetwork) model. ## Advanced Examples The advanced examples are more complex and may use experimental Mesa features. They are good starting points for learning how to build more complex models. ### \[Epstein Civil Violence Model\](examples/advanced/epstein\_civil\_violence) Joshua Epstein's \[model\](https://www.pnas.org/doi/10.1073/pnas.092080199) of how a decentralized uprising can be suppressed or reach a critical mass of support. ### \[Demographic Prisoner's Dilemma on a Grid\](examples/advanced/pd\_grid) Grid-based demographic prisoner's dilemma model, demonstrating how simple rules can lead to the emergence of widespread cooperation -- and how a model activation regime can change its outcome. ### \[Sugarscape Model with Traders\](examples/advanced/sugarscape\_g1mt) This is Epstein & Axtell's Sugarscape model with Traders, a detailed description is in Chapter four of \*Growing Artificial Societies: Social Science from the Bottom Up (1996)\*. The model shows how emergent price equilibrium can happen via decentralized dynamics. ### \[Wolf-Sheep Predation Model\](examples/advanced/wolf\_sheep) Implementation of an ecological model of predation and reproduction, based on the NetLogo \[Wolf Sheep Predation\](http://ccl.northwestern.edu/netlogo/models/WolfSheepPredation) model. \`\`\`{toctree} :hidden: true :maxdepth: 2 schelling boid flockers virus on network boltzmann wealth model conways game of life epstein civil violence pd grid wolf sheep sugarscape g1mt \`\`\`
---
# Conway’s Game Of “Life” — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Conway’s Game Of “Life”[#](#conway-s-game-of-life "Link to this heading")
==========================================================================
Summary[#](#summary "Link to this heading")
--------------------------------------------
[The Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life)
, also known simply as “Life”, is a cellular automaton devised by the British mathematician John Horton Conway in 1970.
The “game” is a zero-player game, meaning that its evolution is determined by its initial state, requiring no further input by a human. One interacts with the Game of “Life” by creating an initial configuration and observing how it evolves, or, for advanced “players”, by creating patterns with particular properties.
How to Run[#](#how-to-run "Link to this heading")
--------------------------------------------------
To run the model interactively you can use either the streamlit or solara version. For solara, you use
$ solara run app.py
For streamlit, you need
$ streamlit run st\_app.py
This will open your browser and show you the controls. You can start the model by hitting the run button.
Files[#](#files "Link to this heading")
----------------------------------------
* `agents.py`: Defines the behavior of an individual cell, which can be in two states: DEAD or ALIVE.
* `model.py`: Defines the model itself, initialized with a random configuration of alive and dead cells.
* `app.py`: Defines an interactive visualization using solara.
* `st_app.py`: Defines an interactive visualization using Streamlit.
Optional[#](#optional "Link to this heading")
----------------------------------------------
* For the streamlit version, you need to have streamlit installed (can be done via pip install streamlit)
Further Reading[#](#further-reading "Link to this heading")
------------------------------------------------------------
[Conway’s Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life)
Agents[#](#agents "Link to this heading")
------------------------------------------
from mesa import Agent
class Cell(Agent):
"""Represents a single ALIVE or DEAD cell in the simulation."""
DEAD \= 0
ALIVE \= 1
def \_\_init\_\_(self, pos, model, init\_state\=DEAD):
"""Create a cell, in the given state, at the given x, y position."""
super().\_\_init\_\_(model)
self.x, self.y \= pos
self.state \= init\_state
self.\_next\_state \= None
@property
def is\_alive(self):
return self.state \== self.ALIVE
@property
def neighbors(self):
return self.model.grid.iter\_neighbors((self.x, self.y), True)
def determine\_state(self):
"""Compute if the cell will be dead or alive at the next tick. This is
based on the number of alive or dead neighbors. The state is not
changed here, but is just computed and stored in self.\_nextState,
because our current state may still be necessary for our neighbors
to calculate their next state.
"""
\# Get the neighbors and apply the rules on whether to be alive or dead
\# at the next tick.
live\_neighbors \= sum(neighbor.is\_alive for neighbor in self.neighbors)
\# Assume nextState is unchanged, unless changed below.
self.\_next\_state \= self.state
if self.is\_alive:
if live\_neighbors < 2 or live\_neighbors \> 3:
self.\_next\_state \= self.DEAD
else:
if live\_neighbors \== 3:
self.\_next\_state \= self.ALIVE
def assume\_state(self):
"""Set the state to the new computed state -- computed in step()."""
self.state \= self.\_next\_state
Model[#](#model "Link to this heading")
----------------------------------------
from mesa import Model
from mesa.examples.basic.conways\_game\_of\_life.agents import Cell
from mesa.space import SingleGrid
class ConwaysGameOfLife(Model):
"""Represents the 2-dimensional array of cells in Conway's Game of Life."""
def \_\_init\_\_(self, width\=50, height\=50, initial\_fraction\_alive\=0.2, seed\=None):
"""Create a new playing area of (width, height) cells."""
super().\_\_init\_\_(seed\=seed)
\# Use a simple grid, where edges wrap around.
self.grid \= SingleGrid(width, height, torus\=True)
\# Place a cell at each location, with some initialized to
\# ALIVE and some to DEAD.
for \_contents, (x, y) in self.grid.coord\_iter():
cell \= Cell((x, y), self)
if self.random.random() < initial\_fraction\_alive:
cell.state \= cell.ALIVE
self.grid.place\_agent(cell, (x, y))
self.running \= True
def step(self):
"""Perform the model step in two stages:
- First, all cells assume their next state (whether they will be dead or alive)
- Then, all cells change state to their next state.
"""
self.agents.do("determine\_state")
self.agents.do("assume\_state")
App[#](#app "Link to this heading")
------------------------------------
from mesa.examples.basic.conways\_game\_of\_life.model import ConwaysGameOfLife
from mesa.visualization import (
SolaraViz,
make\_space\_component,
)
def agent\_portrayal(agent):
return {
"color": "white" if agent.state \== 0 else "black",
"marker": "s",
"size": 25,
}
def post\_process(ax):
ax.set\_aspect("equal")
ax.set\_xticks(\[\])
ax.set\_yticks(\[\])
model\_params \= {
"seed": {
"type": "InputText",
"value": 42,
"label": "Random Seed",
},
"width": {
"type": "SliderInt",
"value": 50,
"label": "Width",
"min": 5,
"max": 60,
"step": 1,
},
"height": {
"type": "SliderInt",
"value": 50,
"label": "Height",
"min": 5,
"max": 60,
"step": 1,
},
"initial\_fraction\_alive": {
"type": "SliderFloat",
"value": 0.2,
"label": "Cells initially alive",
"min": 0,
"max": 1,
"step": 0.01,
},
}
\# Create initial model instance
model1 \= ConwaysGameOfLife()
\# Create visualization elements. The visualization elements are solara components
\# that receive the model instance as a "prop" and display it in a certain way.
\# Under the hood these are just classes that receive the model instance.
\# You can also author your own visualization elements, which can also be functions
\# that receive the model instance and return a valid solara component.
SpaceGraph \= make\_space\_component(
agent\_portrayal, post\_process\=post\_process, draw\_grid\=False
)
\# Create the SolaraViz page. This will automatically create a server and display the
\# visualization elements in a web browser.
\# Display it using the following command in the example directory:
\# solara run app.py
\# It will automatically update and display any changes made to this file
page \= SolaraViz(
model1,
components\=\[SpaceGraph\],
model\_params\=model\_params,
name\="Game of Life",
)
page \# noqa
On this page
### This Page
* [Show Source](../../_sources/examples/basic/conways_game_of_life.md.txt)
---
# Overview of the MESA library — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Overview of the MESA library[#](#overview-of-the-mesa-library "Link to this heading")
======================================================================================
Mesa is modular, meaning that its modeling, analysis and visualization components are kept separate but intended to work together. The modules are grouped into three categories:
1. **Modeling:** Classes used to build the models themselves: a model and agent classes, space for them to move around in, and built-in functionality for managing agents.
2. **Analysis:** Tools to collect data generated from your model, or to run it multiple times with different parameter values.
3. **Visualization:** Classes to create and launch an interactive model visualization, using a browser-based interface.
Modeling modules[#](#modeling-modules "Link to this heading")
--------------------------------------------------------------
Most models consist of one class to represent the model itself and one or more classes for agents. Mesa provides built-in functionality for managing agents and their interactions. These are implemented in Mesa’s modeling modules:
* [mesa.model](apis/model.html)
* [mesa.agent](apis/agent.html)
* [mesa.space](apis/space.html)
The skeleton of a model might look like this:
import mesa
class MyAgent(mesa.Agent):
def \_\_init\_\_(self, model, age):
super().\_\_init\_\_(model)
self.age \= age
def step(self):
self.age += 1
print(f"Agent {self.unique\_id} now is {self.age} years old")
\# Whatever else the agent does when activated
class MyModel(mesa.Model):
def \_\_init\_\_(self, n\_agents):
super().\_\_init\_\_()
self.grid \= mesa.space.MultiGrid(10, 10, torus\=True)
for \_ in range(n\_agents):
initial\_age \= self.random.randint(0, 80)
a \= MyAgent(self, initial\_age)
coords \= (self.random.randrange(0, 10), self.random.randrange(0, 10))
self.grid.place\_agent(a, coords)
def step(self):
self.agents.shuffle\_do("step")
Spaces in Mesa[#](#spaces-in-mesa "Link to this heading")
----------------------------------------------------------
Mesa provides several types of spaces where agents can exist and interact:
### Discrete Spaces[#](#discrete-spaces "Link to this heading")
Mesa implements discrete spaces using a doubly-linked structure where each cell maintains connections to its neighbors. Available variants include:
1. **Grid-based Spaces:**
\# Create a Von Neumann grid (4 neighbors per cell)
grid \= mesa.space.OrthogonalVonNeumannGrid((width, height), torus\=False)
\# Create a Moore grid (8 neighbors per cell)
grid \= mesa.space.OrthogonalMooreGrid((width, height), torus\=True)
\# Create a hexagonal grid
grid \= mesa.space.HexGrid((width, height), torus\=False)
2. **Network Space:**
\# Create a network-based space
network \= mesa.space.NetworkGrid(network)
3. **Voronoi Space:**
\# Create an irregular tessellation
mesh \= mesa.space.VoronoiMesh(points)
### Property Layers[#](#property-layers "Link to this heading")
Discrete spaces support PropertyLayers - efficient numpy-based arrays for storing cell-level properties:
\# Create and use a property layer
grid.create\_property\_layer("elevation", default\_value\=10)
high\_ground \= grid.elevation.select\_cells(lambda x: x \> 50)
### Continuous Space[#](#continuous-space "Link to this heading")
For models requiring continuous movement:
\# Create a continuous space
space \= mesa.space.ContinuousSpace(x\_max, y\_max, torus\=True)
\# Move an agent to specific coordinates
space.move\_agent(agent, (new\_x, new\_y))
Time Advancement and Agent Activation[#](#time-advancement-and-agent-activation "Link to this heading")
--------------------------------------------------------------------------------------------------------
Mesa supports multiple approaches to advancing time and activating agents:
### Basic Time Steps[#](#basic-time-steps "Link to this heading")
The simplest approach runs the model for a specified number of steps:
model \= MyModel(seed\=42)
for \_ in range(100):
model.step()
### Agent Activation Patterns[#](#agent-activation-patterns "Link to this heading")
Mesa 3.0 provides flexible agent activation through the AgentSet API:
\# Sequential activation
model.agents.do("step")
\# Random activation
model.agents.shuffle\_do("step")
\# Multi-stage activation
for stage in \["move", "eat", "reproduce"\]:
model.agents.do(stage)
\# Activation by agent type
for klass in model.agent\_types:
model.agents\_by\_type\[klass\].do("step")
### Event-Based Scheduling[#](#event-based-scheduling "Link to this heading")
Mesa also supports event-based time progression (experimental):
\# Pure event-based
simulator \= mesa.experimental.DiscreteEventSimulator()
model \= MyModel(seed\=42, simulator\=simulator)
simulator.schedule\_event\_relative(some\_function, 3.1415)
\# Hybrid time-step and event scheduling
model \= MyModel(seed\=42, simulator\=mesa.experimental.ABMSimulator())
model.simulator.schedule\_event\_next\_tick(some\_function)
AgentSet and model.agents[#](#agentset-and-model-agents "Link to this heading")
--------------------------------------------------------------------------------
Mesa 3.0 makes `model.agents` and the AgentSet class central in managing and activating agents.
### model.agents[#](#model-agents "Link to this heading")
`model.agents` is an AgentSet containing all agents in the model. It’s automatically updated when agents are added or removed:
\# Get total number of agents
num\_agents \= len(model.agents)
\# Iterate over all agents
for agent in model.agents:
print(agent.unique\_id)
### AgentSet Functionality[#](#agentset-functionality "Link to this heading")
AgentSet offers several methods for efficient agent management:
1. **Selecting**: Filter agents based on criteria.
high\_energy\_agents \= model.agents.select(lambda a: a.energy \> 50)
2. **Shuffling and Sorting**: Randomize or order agents.
shuffled\_agents \= model.agents.shuffle()
sorted\_agents \= model.agents.sort(key\="energy", ascending\=False)
3. **Applying methods**: Execute methods on all agents.
model.agents.do("step")
model.agents.shuffle\_do("move") \# Shuffle then apply method
4. **Aggregating**: Compute aggregate values across agents.
avg\_energy \= model.agents.agg("energy", func\=np.mean)
5. **Grouping**: Group agents by attributes.
grouped\_agents \= model.agents.groupby("species")
for \_, agent\_group in grouped\_agents:
agent\_group.shuffle\_do()
species\_counts \= grouped\_agents.count()
mean\_age\_by\_group \= grouped\_agents.agg("age", np.mean)
`model.agents` can also be accessed within a model instance using `self.agents`.
These are just some examples of using the AgentSet, there are many more possibilities, see the [AgentSet API docs](apis/agent.html)
.
Analysis modules[#](#analysis-modules "Link to this heading")
--------------------------------------------------------------
If you’re using modeling for research, you’ll want a way to collect the data each model run generates. You’ll probably also want to run the model multiple times, to see how some output changes with different parameters. Data collection and batch running are implemented in the appropriately-named analysis modules:
* [mesa.datacollection](apis/datacollection.html)
* [mesa.batchrunner](apis/batchrunner.html)
You’d add a data collector to the model like this:
import mesa
import numpy as np
\# ...
class MyModel(mesa.Model):
def \_\_init\_\_(self, n\_agents):
super().\_\_init\_\_()
\# ... (model initialization code)
self.datacollector \= mesa.DataCollector(
model\_reporters\={"mean\_age": lambda m: m.agents.agg("age", np.mean)},
agent\_reporters\={"age": "age"}
)
def step(self):
self.agents.shuffle\_do("step")
self.datacollector.collect(self)
The data collector will collect the specified model- and agent-level data at each step of the model. After you’re done running it, you can extract the data as a [pandas](http://pandas.pydata.org/)
DataFrame:
model \= MyModel(5)
for t in range(10):
model.step()
model\_df \= model.datacollector.get\_model\_vars\_dataframe()
agent\_df \= model.datacollector.get\_agent\_vars\_dataframe()
To batch-run the model while varying, for example, the n\_agents parameter, you’d use the [`batch_run`](apis/batchrunner.html)
function:
import mesa
parameters \= {"n\_agents": range(1, 6)}
results \= mesa.batch\_run(
MyModel,
parameters,
iterations\=5,
max\_steps\=100,
data\_collection\_period\=1,
number\_processes\=1 \# Change to use multiple CPU cores for parallel execution
)
The results are returned as a list of dictionaries, which can be easily converted to a pandas DataFrame for further analysis.
Visualization[#](#visualization "Link to this heading")
--------------------------------------------------------
Mesa now uses a new browser-based visualization system called SolaraViz. This allows for interactive, customizable visualizations of your models.
Note: SolaraViz is experimental and still in active development in Mesa 3.x. While we attempt to minimize them, there might be API breaking changes in minor releases.
> **Note:** SolaraViz instantiates new models using `**model_parameters.value`, so all model inputs must be keyword arguments.
Ensure your model’s `__init__` method accepts keyword arguments matching the `model_params` keys.
class MyModel(Model):
def \_\_init\_\_(self, n\_agents\=10, seed\=None):
super().\_\_init\_\_(seed\=seed)
\# Initialize the model with N agents
The core functionality for building your own visualizations resides in the [`mesa.visualization`](apis/visualization.html)
namespace.
Here’s a basic example of how to set up a visualization:
from mesa.visualization import SolaraViz, make\_space\_component, make\_plot\_component
def agent\_portrayal(agent):
return {"color": "blue", "size": 50}
model\_params \= {
"N": {
"type": "SliderInt",
"value": 50,
"label": "Number of agents:",
"min": 10,
"max": 100,
"step": 1,
}
}
page \= SolaraViz(
MyModel,
\[\
make\_space\_component(agent\_portrayal),\
make\_plot\_component("mean\_age")\
\],
model\_params\=model\_params
)
page
This will create an interactive visualization of your model, including:
* A grid visualization of agents
* A plot of a model metric over time
* A slider to adjust the number of agents
You can also create custom visualization components using Matplotlib. For more advanced usage and customization options, please refer to the [visualization tutorial](tutorials/visualization_tutorial.html)
.
On this page
### This Page
* [Show Source](_sources/overview.md.txt)
---
# Schelling Segregation Model — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Schelling Segregation Model[#](#schelling-segregation-model "Link to this heading")
====================================================================================
Summary[#](#summary "Link to this heading")
--------------------------------------------
The Schelling segregation model is a classic agent-based model, demonstrating how even a mild preference for similar neighbors can lead to a much higher degree of segregation than we would intuitively expect. The model consists of agents on a square grid, where each grid cell can contain at most one agent. Agents come in two colors: red and blue. They are happy if a certain number of their eight possible neighbors are of the same color, and unhappy otherwise. Unhappy agents will pick a random empty cell to move to each step, until they are happy. The model keeps running until there are no unhappy agents.
By default, the number of similar neighbors the agents need to be happy is set to 3. That means the agents would be perfectly happy with a majority of their neighbors being of a different color (e.g. a Blue agent would be happy with five Red neighbors and three Blue ones). Despite this, the model consistently leads to a high degree of segregation, with most agents ending up with no neighbors of a different color.
How to Run[#](#how-to-run "Link to this heading")
--------------------------------------------------
To run the model interactively, in this directory, run the following command
$ solara run app.py
Then open your browser to [http://127.0.0.1:8765/](http://127.0.0.1:8765/)
and click the Play button.
To view and run some example model analyses, launch the IPython Notebook and open `analysis.ipynb`. Visualizing the analysis also requires [matplotlib](http://matplotlib.org/)
.
How to Run without the GUI[#](#how-to-run-without-the-gui "Link to this heading")
----------------------------------------------------------------------------------
To run the model with the grid displayed as an ASCII text, run `python run_ascii.py` in this directory.
Files[#](#files "Link to this heading")
----------------------------------------
* `model.py`: Contains the Schelling model class
* `agents.py`: Contains the Schelling agent class
* `app.py`: Code for the interactive visualization.
* `analysis.ipynb`: Notebook demonstrating how to run experiments and parameter sweeps on the model.
Further Reading[#](#further-reading "Link to this heading")
------------------------------------------------------------
Schelling’s original paper describing the model:
[Schelling, Thomas C. Dynamic Models of Segregation. Journal of Mathematical Sociology. 1971, Vol. 1, pp 143-186.](https://www.stat.berkeley.edu/~aldous/157/Papers/Schelling_Seg_Models.pdf)
An interactive, browser-based explanation and implementation:
[Parable of the Polygons](http://ncase.me/polygons/)
, by Vi Hart and Nicky Case.
Agents[#](#agents "Link to this heading")
------------------------------------------
from mesa import Agent
class SchellingAgent(Agent):
"""Schelling segregation agent."""
def \_\_init\_\_(self, model, agent\_type: int) \-> None:
"""Create a new Schelling agent.
Args:
model: The model instance the agent belongs to
agent\_type: Indicator for the agent's type (minority=1, majority=0)
"""
super().\_\_init\_\_(model)
self.type \= agent\_type
def step(self) \-> None:
"""Determine if agent is happy and move if necessary."""
neighbors \= self.model.grid.get\_neighbors(
self.pos, moore\=True, radius\=self.model.radius
)
\# Count similar neighbors
similar\_neighbors \= len(\[n for n in neighbors if n.type \== self.type\])
\# Calculate the fraction of similar neighbors
if (valid\_neighbors := len(neighbors)) \> 0:
similarity\_fraction \= similar\_neighbors / valid\_neighbors
else:
\# If there are no neighbors, the similarity fraction is 0
similarity\_fraction \= 0.0
\# Move if unhappy
if similarity\_fraction < self.model.homophily:
self.model.grid.move\_to\_empty(self)
else:
self.model.happy += 1
Model[#](#model "Link to this heading")
----------------------------------------
from mesa import Model
from mesa.datacollection import DataCollector
from mesa.examples.basic.schelling.agents import SchellingAgent
from mesa.space import SingleGrid
class Schelling(Model):
"""Model class for the Schelling segregation model."""
def \_\_init\_\_(
self,
height: int \= 20,
width: int \= 20,
density: float \= 0.8,
minority\_pc: float \= 0.5,
homophily: float \= 0.4,
radius: int \= 1,
seed\=None,
):
"""Create a new Schelling model.
Args:
width: Width of the grid
height: Height of the grid
density: Initial chance for a cell to be populated (0-1)
minority\_pc: Chance for an agent to be in minority class (0-1)
homophily: Minimum number of similar neighbors needed for happiness
radius: Search radius for checking neighbor similarity
seed: Seed for reproducibility
"""
super().\_\_init\_\_(seed\=seed)
\# Model parameters
self.height \= height
self.width \= width
self.density \= density
self.minority\_pc \= minority\_pc
self.homophily \= homophily
self.radius \= radius
\# Initialize grid
self.grid \= SingleGrid(width, height, torus\=True)
\# Track happiness
self.happy \= 0
\# Set up data collection
self.datacollector \= DataCollector(
model\_reporters\={
"happy": "happy",
"pct\_happy": lambda m: (m.happy / len(m.agents)) \* 100
if len(m.agents) \> 0
else 0,
"population": lambda m: len(m.agents),
"minority\_pct": lambda m: (
sum(1 for agent in m.agents if agent.type \== 1)
/ len(m.agents)
\* 100
if len(m.agents) \> 0
else 0
),
},
agent\_reporters\={"agent\_type": "type"},
)
\# Create agents and place them on the grid
for \_, pos in self.grid.coord\_iter():
if self.random.random() < self.density:
agent\_type \= 1 if self.random.random() < minority\_pc else 0
agent \= SchellingAgent(self, agent\_type)
self.grid.place\_agent(agent, pos)
\# Collect initial state
self.datacollector.collect(self)
def step(self):
"""Run one step of the model."""
self.happy \= 0 \# Reset counter of happy agents
self.agents.shuffle\_do("step") \# Activate all agents in random order
self.datacollector.collect(self) \# Collect data
self.running \= self.happy < len(self.agents) \# Continue until everyone is happy
App[#](#app "Link to this heading")
------------------------------------
import solara
from mesa.examples.basic.schelling.model import Schelling
from mesa.visualization import (
Slider,
SolaraViz,
make\_plot\_component,
make\_space\_component,
)
def get\_happy\_agents(model):
"""Display a text count of how many happy agents there are."""
return solara.Markdown(f"\*\*Happy agents: {model.happy}\*\*")
def agent\_portrayal(agent):
return {"color": "tab:orange" if agent.type \== 0 else "tab:blue"}
model\_params \= {
"seed": {
"type": "InputText",
"value": 42,
"label": "Random Seed",
},
"density": Slider("Agent density", 0.8, 0.1, 1.0, 0.1),
"minority\_pc": Slider("Fraction minority", 0.2, 0.0, 1.0, 0.05),
"homophily": Slider("Homophily", 0.4, 0.0, 1.0, 0.125),
"width": 20,
"height": 20,
}
model1 \= Schelling()
HappyPlot \= make\_plot\_component({"happy": "tab:green"})
page \= SolaraViz(
model1,
components\=\[\
make\_space\_component(agent\_portrayal),\
HappyPlot,\
get\_happy\_agents,\
\],
model\_params\=model\_params,
)
page \# noqa
On this page
### This Page
* [Show Source](../../_sources/examples/basic/schelling.md.txt)
---
# Wolf-Sheep Predation Model — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Wolf-Sheep Predation Model[#](#wolf-sheep-predation-model "Link to this heading")
==================================================================================
Summary[#](#summary "Link to this heading")
--------------------------------------------
A simple ecological model, consisting of three agent types: wolves, sheep, and grass. The wolves and the sheep wander around the grid at random. Wolves and sheep both expend energy moving around, and replenish it by eating. Sheep eat grass, and wolves eat sheep if they end up on the same grid cell.
If wolves and sheep have enough energy, they reproduce, creating a new wolf or sheep (in this simplified model, only one parent is needed for reproduction). The grass on each cell regrows at a constant rate. If any wolves and sheep run out of energy, they die.
The model is tests and demonstrates several Mesa concepts and features:
* MultiGrid
* Multiple agent types (wolves, sheep, grass)
* Overlay arbitrary text (wolf’s energy) on agent’s shapes while drawing on CanvasGrid
* Agents inheriting a behavior (random movement) from an abstract parent
* Writing a model composed of multiple files.
* Dynamically adding and removing agents from the schedule
Installation[#](#installation "Link to this heading")
------------------------------------------------------
To install the dependencies use pip and the requirements.txt in this directory. e.g.
# First, we clone the Mesa repo
$ git clone https://github.com/projectmesa/mesa.git
$ cd mesa
# Then we cd to the example directory
$ cd examples/wolf\_sheep
$ pip install -r requirements.txt
How to Run[#](#how-to-run "Link to this heading")
--------------------------------------------------
To run the model interactively, run `mesa runserver` in this directory. e.g.
$ mesa runserver
Then open your browser to [http://127.0.0.1:8521/](http://127.0.0.1:8521/)
and press Reset, then Run.
Files[#](#files "Link to this heading")
----------------------------------------
* `wolf_sheep/random_walk.py`: This defines the `RandomWalker` agent, which implements the behavior of moving randomly across a grid, one cell at a time. Both the Wolf and Sheep agents will inherit from it.
* `wolf_sheep/test_random_walk.py`: Defines a simple model and a text-only visualization intended to make sure the RandomWalk class was working as expected. This doesn’t actually model anything, but serves as an ad-hoc unit test. To run it, `cd` into the `wolf_sheep` directory and run `python test_random_walk.py`. You’ll see a series of ASCII grids, one per model step, with each cell showing a count of the number of agents in it.
* `wolf_sheep/agents.py`: Defines the Wolf, Sheep, and GrassPatch agent classes.
* `wolf_sheep/scheduler.py`: Defines a custom variant on the RandomActivationByType scheduler, where we can define filters for the `get_type_count` function.
* `wolf_sheep/model.py`: Defines the Wolf-Sheep Predation model itself
* `wolf_sheep/server.py`: Sets up the interactive visualization server
* `run.py`: Launches a model visualization server.
Further Reading[#](#further-reading "Link to this heading")
------------------------------------------------------------
This model is closely based on the NetLogo Wolf-Sheep Predation Model:
Wilensky, U. (1997). NetLogo Wolf Sheep Predation model. http://ccl.northwestern.edu/netlogo/models/WolfSheepPredation. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
See also the [Lotka–Volterra equations](https://en.wikipedia.org/wiki/Lotka%E2%80%93Volterra_equations)
for an example of a classic differential-equation model with similar dynamics.
Agents[#](#agents "Link to this heading")
------------------------------------------
from mesa.experimental.cell\_space import CellAgent, FixedAgent
class Animal(CellAgent):
"""The base animal class."""
def \_\_init\_\_(
self, model, energy\=8, p\_reproduce\=0.04, energy\_from\_food\=4, cell\=None
):
"""Initialize an animal.
Args:
model: Model instance
energy: Starting amount of energy
p\_reproduce: Probability of reproduction (asexual)
energy\_from\_food: Energy obtained from 1 unit of food
cell: Cell in which the animal starts
"""
super().\_\_init\_\_(model)
self.energy \= energy
self.p\_reproduce \= p\_reproduce
self.energy\_from\_food \= energy\_from\_food
self.cell \= cell
def spawn\_offspring(self):
"""Create offspring by splitting energy and creating new instance."""
self.energy /= 2
self.\_\_class\_\_(
self.model,
self.energy,
self.p\_reproduce,
self.energy\_from\_food,
self.cell,
)
def feed(self):
"""Abstract method to be implemented by subclasses."""
def step(self):
"""Execute one step of the animal's behavior."""
\# Move to random neighboring cell
self.move()
self.energy \-= 1
\# Try to feed
self.feed()
\# Handle death and reproduction
if self.energy < 0:
self.remove()
elif self.random.random() < self.p\_reproduce:
self.spawn\_offspring()
class Sheep(Animal):
"""A sheep that walks around, reproduces (asexually) and gets eaten."""
def feed(self):
"""If possible, eat grass at current location."""
grass\_patch \= next(
obj for obj in self.cell.agents if isinstance(obj, GrassPatch)
)
if grass\_patch.fully\_grown:
self.energy += self.energy\_from\_food
grass\_patch.fully\_grown \= False
def move(self):
"""Move towards a cell where there isn't a wolf, and preferably with grown grass."""
cells\_without\_wolves \= self.cell.neighborhood.select(
lambda cell: not any(isinstance(obj, Wolf) for obj in cell.agents)
)
\# If all surrounding cells have wolves, stay put
if len(cells\_without\_wolves) \== 0:
return
\# Among safe cells, prefer those with grown grass
cells\_with\_grass \= cells\_without\_wolves.select(
lambda cell: any(
isinstance(obj, GrassPatch) and obj.fully\_grown for obj in cell.agents
)
)
\# Move to a cell with grass if available, otherwise move to any safe cell
target\_cells \= (
cells\_with\_grass if len(cells\_with\_grass) \> 0 else cells\_without\_wolves
)
self.cell \= target\_cells.select\_random\_cell()
class Wolf(Animal):
"""A wolf that walks around, reproduces (asexually) and eats sheep."""
def feed(self):
"""If possible, eat a sheep at current location."""
sheep \= \[obj for obj in self.cell.agents if isinstance(obj, Sheep)\]
if sheep: \# If there are any sheep present
sheep\_to\_eat \= self.random.choice(sheep)
self.energy += self.energy\_from\_food
sheep\_to\_eat.remove()
def move(self):
"""Move to a neighboring cell, preferably one with sheep."""
cells\_with\_sheep \= self.cell.neighborhood.select(
lambda cell: any(isinstance(obj, Sheep) for obj in cell.agents)
)
target\_cells \= (
cells\_with\_sheep if len(cells\_with\_sheep) \> 0 else self.cell.neighborhood
)
self.cell \= target\_cells.select\_random\_cell()
class GrassPatch(FixedAgent):
"""A patch of grass that grows at a fixed rate and can be eaten by sheep."""
@property
def fully\_grown(self):
"""Whether the grass patch is fully grown."""
return self.\_fully\_grown
@fully\_grown.setter
def fully\_grown(self, value: bool) \-> None:
"""Set grass growth state and schedule regrowth if eaten."""
self.\_fully\_grown \= value
if not value: \# If grass was just eaten
self.model.simulator.schedule\_event\_relative(
setattr,
self.grass\_regrowth\_time,
function\_args\=\[self, "fully\_grown", True\],
)
def \_\_init\_\_(self, model, countdown, grass\_regrowth\_time, cell):
"""Create a new patch of grass.
Args:
model: Model instance
countdown: Time until grass is fully grown again
grass\_regrowth\_time: Time needed to regrow after being eaten
cell: Cell to which this grass patch belongs
"""
super().\_\_init\_\_(model)
self.\_fully\_grown \= countdown \== 0
self.grass\_regrowth\_time \= grass\_regrowth\_time
self.cell \= cell
\# Schedule initial growth if not fully grown
if not self.fully\_grown:
self.model.simulator.schedule\_event\_relative(
setattr, countdown, function\_args\=\[self, "fully\_grown", True\]
)
Model[#](#model "Link to this heading")
----------------------------------------
"""
Wolf-Sheep Predation Model
\================================
Replication of the model found in NetLogo:
Wilensky, U. (1997). NetLogo Wolf Sheep Predation model.
http://ccl.northwestern.edu/netlogo/models/WolfSheepPredation.
Center for Connected Learning and Computer-Based Modeling,
Northwestern University, Evanston, IL.
"""
import math
from mesa import Model
from mesa.datacollection import DataCollector
from mesa.examples.advanced.wolf\_sheep.agents import GrassPatch, Sheep, Wolf
from mesa.experimental.cell\_space import OrthogonalVonNeumannGrid
from mesa.experimental.devs import ABMSimulator
class WolfSheep(Model):
"""Wolf-Sheep Predation Model.
A model for simulating wolf and sheep (predator-prey) ecosystem modelling.
"""
description \= (
"A model for simulating wolf and sheep (predator-prey) ecosystem modelling."
)
def \_\_init\_\_(
self,
width\=20,
height\=20,
initial\_sheep\=100,
initial\_wolves\=50,
sheep\_reproduce\=0.04,
wolf\_reproduce\=0.05,
wolf\_gain\_from\_food\=20,
grass\=True,
grass\_regrowth\_time\=30,
sheep\_gain\_from\_food\=4,
seed\=None,
simulator: ABMSimulator \= None,
):
"""Create a new Wolf-Sheep model with the given parameters.
Args:
height: Height of the grid
width: Width of the grid
initial\_sheep: Number of sheep to start with
initial\_wolves: Number of wolves to start with
sheep\_reproduce: Probability of each sheep reproducing each step
wolf\_reproduce: Probability of each wolf reproducing each step
wolf\_gain\_from\_food: Energy a wolf gains from eating a sheep
grass: Whether to have the sheep eat grass for energy
grass\_regrowth\_time: How long it takes for a grass patch to regrow
once it is eaten
sheep\_gain\_from\_food: Energy sheep gain from grass, if enabled
seed: Random seed
simulator: ABMSimulator instance for event scheduling
"""
super().\_\_init\_\_(seed\=seed)
self.simulator \= simulator
self.simulator.setup(self)
\# Initialize model parameters
self.height \= height
self.width \= width
self.grass \= grass
\# Create grid using experimental cell space
self.grid \= OrthogonalVonNeumannGrid(
\[self.height, self.width\],
torus\=True,
capacity\=math.inf,
random\=self.random,
)
\# Set up data collection
model\_reporters \= {
"Wolves": lambda m: len(m.agents\_by\_type\[Wolf\]),
"Sheep": lambda m: len(m.agents\_by\_type\[Sheep\]),
}
if grass:
model\_reporters\["Grass"\] \= lambda m: len(
m.agents\_by\_type\[GrassPatch\].select(lambda a: a.fully\_grown)
)
self.datacollector \= DataCollector(model\_reporters)
\# Create sheep:
Sheep.create\_agents(
self,
initial\_sheep,
energy\=self.rng.random((initial\_sheep,)) \* 2 \* sheep\_gain\_from\_food,
p\_reproduce\=sheep\_reproduce,
energy\_from\_food\=sheep\_gain\_from\_food,
cell\=self.random.choices(self.grid.all\_cells.cells, k\=initial\_sheep),
)
\# Create Wolves:
Wolf.create\_agents(
self,
initial\_wolves,
energy\=self.rng.random((initial\_wolves,)) \* 2 \* wolf\_gain\_from\_food,
p\_reproduce\=wolf\_reproduce,
energy\_from\_food\=wolf\_gain\_from\_food,
cell\=self.random.choices(self.grid.all\_cells.cells, k\=initial\_wolves),
)
\# Create grass patches if enabled
if grass:
possibly\_fully\_grown \= \[True, False\]
for cell in self.grid:
fully\_grown \= self.random.choice(possibly\_fully\_grown)
countdown \= (
0 if fully\_grown else self.random.randrange(0, grass\_regrowth\_time)
)
GrassPatch(self, countdown, grass\_regrowth\_time, cell)
\# Collect initial data
self.running \= True
self.datacollector.collect(self)
def step(self):
"""Execute one step of the model."""
\# First activate all sheep, then all wolves, both in random order
self.agents\_by\_type\[Sheep\].shuffle\_do("step")
self.agents\_by\_type\[Wolf\].shuffle\_do("step")
\# Collect data
self.datacollector.collect(self)
App[#](#app "Link to this heading")
------------------------------------
from mesa.examples.advanced.wolf\_sheep.agents import GrassPatch, Sheep, Wolf
from mesa.examples.advanced.wolf\_sheep.model import WolfSheep
from mesa.experimental.devs import ABMSimulator
from mesa.visualization import (
Slider,
SolaraViz,
make\_plot\_component,
make\_space\_component,
)
def wolf\_sheep\_portrayal(agent):
if agent is None:
return
portrayal \= {
"size": 25,
}
if isinstance(agent, Wolf):
portrayal\["color"\] \= "tab:red"
portrayal\["marker"\] \= "o"
portrayal\["zorder"\] \= 2
elif isinstance(agent, Sheep):
portrayal\["color"\] \= "tab:cyan"
portrayal\["marker"\] \= "o"
portrayal\["zorder"\] \= 2
elif isinstance(agent, GrassPatch):
if agent.fully\_grown:
portrayal\["color"\] \= "tab:green"
else:
portrayal\["color"\] \= "tab:brown"
portrayal\["marker"\] \= "s"
portrayal\["size"\] \= 75
return portrayal
model\_params \= {
"seed": {
"type": "InputText",
"value": 42,
"label": "Random Seed",
},
"grass": {
"type": "Select",
"value": True,
"values": \[True, False\],
"label": "grass regrowth enabled?",
},
"grass\_regrowth\_time": Slider("Grass Regrowth Time", 20, 1, 50),
"initial\_sheep": Slider("Initial Sheep Population", 100, 10, 300),
"sheep\_reproduce": Slider("Sheep Reproduction Rate", 0.04, 0.01, 1.0, 0.01),
"initial\_wolves": Slider("Initial Wolf Population", 10, 5, 100),
"wolf\_reproduce": Slider(
"Wolf Reproduction Rate",
0.05,
0.01,
1.0,
0.01,
),
"wolf\_gain\_from\_food": Slider("Wolf Gain From Food Rate", 20, 1, 50),
"sheep\_gain\_from\_food": Slider("Sheep Gain From Food", 4, 1, 10),
}
def post\_process\_space(ax):
ax.set\_aspect("equal")
ax.set\_xticks(\[\])
ax.set\_yticks(\[\])
def post\_process\_lines(ax):
ax.legend(loc\="center left", bbox\_to\_anchor\=(1, 0.9))
space\_component \= make\_space\_component(
wolf\_sheep\_portrayal, draw\_grid\=False, post\_process\=post\_process\_space
)
lineplot\_component \= make\_plot\_component(
{"Wolves": "tab:orange", "Sheep": "tab:cyan", "Grass": "tab:green"},
post\_process\=post\_process\_lines,
)
simulator \= ABMSimulator()
model \= WolfSheep(simulator\=simulator, grass\=True)
page \= SolaraViz(
model,
components\=\[space\_component, lineplot\_component\],
model\_params\=model\_params,
name\="Wolf Sheep",
simulator\=simulator,
)
page \# noqa
On this page
### This Page
* [Show Source](../../_sources/examples/advanced/wolf_sheep.md.txt)
---
# Boltzmann Wealth Model (Tutorial) — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Boltzmann Wealth Model (Tutorial)[#](#boltzmann-wealth-model-tutorial "Link to this heading")
==============================================================================================
Summary[#](#summary "Link to this heading")
--------------------------------------------
A simple model of agents exchanging wealth. All agents start with the same amount of money. Every step, each agent with one unit of money or more gives one unit of wealth to another random agent. This is the model described in the [Intro Tutorial](https://mesa.readthedocs.io/en/latest/tutorials/intro_tutorial.html)
, with the completed code.
If you want to go over the step-by-step tutorial, please go and run the [Jupyter Notebook](https://github.com/projectmesa/mesa/blob/main/docs/tutorials/intro_tutorial.ipynb)
. The code here runs the finalized code in the last cells directly.
As the model runs, the distribution of wealth among agents goes from being perfectly uniform (all agents have the same starting wealth), to highly skewed – a small number have high wealth, more have none at all.
How to Run[#](#how-to-run "Link to this heading")
--------------------------------------------------
To follow the tutorial example, launch the Jupyter Notebook and run the code in `Introduction to Mesa Tutorial Code.ipynb` which you can find in the main mesa repo [here](https://github.com/projectmesa/mesa/blob/main/docs/tutorials/intro_tutorial.ipynb)
To launch the interactive server, as described in the [last section of the tutorial](https://mesa.readthedocs.io/en/latest/tutorials/intro_tutorial.html#adding-visualization)
, run:
$ solara run app.py
If your browser doesn’t open automatically, point it to [http://127.0.0.1:8765/](http://127.0.0.1:8765/)
. When the visualization loads, click on the Play button.
Files[#](#files "Link to this heading")
----------------------------------------
* `model.py`: Final version of the model.
* `agents.py`: Final version of the agent.
* `app.py`: Code for the interactive visualization.
Optional[#](#optional "Link to this heading")
----------------------------------------------
An optional visualization is also provided using Streamlit, which is another popular Python library for creating interactive web applications.
To run the Streamlit app, you will need to install the `streamlit` and `altair` libraries:
$ pip install streamlit altair
Then, you can run the Streamlit app using the following command:
$ streamlit run st\_app.py
Further Reading[#](#further-reading "Link to this heading")
------------------------------------------------------------
The full tutorial describing how the model is built can be found at: https://mesa.readthedocs.io/en/latest/tutorials/intro\_tutorial.html
This model is drawn from econophysics and presents a statistical mechanics approach to wealth distribution. Some examples of further reading on the topic can be found at:
[Milakovic, M. A Statistical Equilibrium Model of Wealth Distribution. February, 2001.](https://editorialexpress.com/cgi-bin/conference/download.cgi?db_name=SCE2001&paper_id=214)
[Dragulescu, A and Yakovenko, V. Statistical Mechanics of Money, Income, and Wealth: A Short Survey. November, 2002](http://arxiv.org/pdf/cond-mat/0211175v1.pdf)
Agents[#](#agents "Link to this heading")
------------------------------------------
from mesa import Agent
class MoneyAgent(Agent):
"""An agent with fixed initial wealth.
Each agent starts with 1 unit of wealth and can give 1 unit to other agents
if they occupy the same cell.
Attributes:
wealth (int): The agent's current wealth (starts at 1)
"""
def \_\_init\_\_(self, model):
"""Create a new agent.
Args:
model (Model): The model instance that contains the agent
"""
super().\_\_init\_\_(model)
self.wealth \= 1
def move(self):
"""Move the agent to a random neighboring cell."""
possible\_steps \= self.model.grid.get\_neighborhood(
self.pos, moore\=True, include\_center\=False
)
new\_position \= self.random.choice(possible\_steps)
self.model.grid.move\_agent(self, new\_position)
def give\_money(self):
"""Give 1 unit of wealth to a random agent in the same cell."""
cellmates \= self.model.grid.get\_cell\_list\_contents(\[self.pos\])
\# Remove self from potential recipients
cellmates.pop(cellmates.index(self))
if cellmates: \# Only give money if there are other agents present
other \= self.random.choice(cellmates)
other.wealth += 1
self.wealth \-= 1
def step(self):
"""Execute one step for the agent:
1. Move to a neighboring cell
2. If wealth > 0, maybe give money to another agent in the same cell
"""
self.move()
if self.wealth \> 0:
self.give\_money()
Model[#](#model "Link to this heading")
----------------------------------------
"""
Boltzmann Wealth Model
\=====================
A simple model of wealth distribution based on the Boltzmann-Gibbs distribution.
Agents move randomly on a grid, giving one unit of wealth to a random neighbor
when they occupy the same cell.
"""
from mesa import Model
from mesa.datacollection import DataCollector
from mesa.examples.basic.boltzmann\_wealth\_model.agents import MoneyAgent
from mesa.space import MultiGrid
class BoltzmannWealth(Model):
"""A simple model of an economy where agents exchange currency at random.
All agents begin with one unit of currency, and each time step agents can give
a unit of currency to another agent in the same cell. Over time, this produces
a highly skewed distribution of wealth.
Attributes:
num\_agents (int): Number of agents in the model
grid (MultiGrid): The space in which agents move
running (bool): Whether the model should continue running
datacollector (DataCollector): Collects and stores model data
"""
def \_\_init\_\_(self, n\=100, width\=10, height\=10, seed\=None):
"""Initialize the model.
Args:
n (int, optional): Number of agents. Defaults to 100.
width (int, optional): Grid width. Defaults to 10.
height (int, optional): Grid height. Defaults to 10.
seed (int, optional): Random seed. Defaults to None.
"""
super().\_\_init\_\_(seed\=seed)
self.num\_agents \= n
self.grid \= MultiGrid(width, height, torus\=True)
\# Set up data collection
self.datacollector \= DataCollector(
model\_reporters\={"Gini": self.compute\_gini},
agent\_reporters\={"Wealth": "wealth"},
)
\# Create and place the agents
for \_ in range(self.num\_agents):
agent \= MoneyAgent(self)
\# Add agent to random grid cell
x \= self.random.randrange(self.grid.width)
y \= self.random.randrange(self.grid.height)
self.grid.place\_agent(agent, (x, y))
self.running \= True
self.datacollector.collect(self)
def step(self):
self.agents.shuffle\_do("step") \# Activate all agents in random order
self.datacollector.collect(self) \# Collect data
def compute\_gini(self):
"""Calculate the Gini coefficient for the model's current wealth distribution.
The Gini coefficient is a measure of inequality in distributions.
- A Gini of 0 represents complete equality, where all agents have equal wealth.
- A Gini of 1 represents maximal inequality, where one agent has all wealth.
"""
agent\_wealths \= \[agent.wealth for agent in self.agents\]
x \= sorted(agent\_wealths)
n \= self.num\_agents
\# Calculate using the standard formula for Gini coefficient
b \= sum(xi \* (n \- i) for i, xi in enumerate(x)) / (n \* sum(x))
return 1 + (1 / n) \- 2 \* b
App[#](#app "Link to this heading")
------------------------------------
from mesa.examples.basic.boltzmann\_wealth\_model.model import BoltzmannWealth
from mesa.mesa\_logging import DEBUG, log\_to\_stderr
from mesa.visualization import (
SolaraViz,
make\_plot\_component,
make\_space\_component,
)
log\_to\_stderr(DEBUG)
def agent\_portrayal(agent):
color \= agent.wealth \# we are using a colormap to translate wealth to color
return {"color": color}
model\_params \= {
"seed": {
"type": "InputText",
"value": 42,
"label": "Random Seed",
},
"n": {
"type": "SliderInt",
"value": 50,
"label": "Number of agents:",
"min": 10,
"max": 100,
"step": 1,
},
"width": 10,
"height": 10,
}
def post\_process(ax):
ax.get\_figure().colorbar(ax.collections\[0\], label\="wealth", ax\=ax)
\# Create initial model instance
model \= BoltzmannWealth(50, 10, 10)
\# Create visualization elements. The visualization elements are solara components
\# that receive the model instance as a "prop" and display it in a certain way.
\# Under the hood these are just classes that receive the model instance.
\# You can also author your own visualization elements, which can also be functions
\# that receive the model instance and return a valid solara component.
SpaceGraph \= make\_space\_component(
agent\_portrayal, cmap\="viridis", vmin\=0, vmax\=10, post\_process\=post\_process
)
GiniPlot \= make\_plot\_component("Gini")
\# Create the SolaraViz page. This will automatically create a server and display the
\# visualization elements in a web browser.
\# Display it using the following command in the example directory:
\# solara run app.py
\# It will automatically update and display any changes made to this file
page \= SolaraViz(
model,
components\=\[SpaceGraph, GiniPlot\],
model\_params\=model\_params,
name\="Boltzmann Wealth Model",
)
page \# noqa
\# In a notebook environment, we can also display the visualization elements directly
\# SpaceGraph(model1)
\# GiniPlot(model1)
\# The plots will be static. If you want to pick up model steps,
\# you have to make the model reactive first
\# reactive\_model = solara.reactive(model1)
\# SpaceGraph(reactive\_model)
\# In a different notebook block:
\# reactive\_model.value.step()
On this page
### This Page
* [Show Source](../../_sources/examples/basic/boltzmann_wealth_model.md.txt)
---
# Unknown
\# Experimental This namespace contains experimental features. These are under development, and their API is not necessarily stable. ## Devs \`\`\`{eval-rst} .. automodule:: experimental.devs.eventlist :members: \`\`\` \`\`\`{eval-rst} .. automodule:: experimental.devs.simulator :members: \`\`\` ## Continuous Space \`\`\`{eval-rst} .. automodule:: experimental.continuous\_space.continuous\_space :members: \`\`\` \`\`\`{eval-rst} .. automodule:: experimental.continuous\_space.continuous\_space\_agents :members: \`\`\`
---
# Unknown
\# Mesa Extensions Overview This contains an overview of Mesa Extensions. Mesa's extensibility is a key feature that allows users to enhance functionality, improve scalability, and foster innovation in agent-based modeling. ## Mesa-Geo 🌍 \*\*Field:\*\* Geographic Information Systems (GIS) --- \*\*Description:\*\* Mesa-Geo is an extension of the Mesa framework designed to facilitate working with geographic data in agent-based modeling. It introduces a \*\*GeoSpace\*\* to host \*\*GeoAgents\*\*, which are enhanced agents that include a \`geometry\` attribute (\[a Shapely object\](https://shapely.readthedocs.io/en/latest/manual.html)) and a \`crs\` attribute (Coordinate Reference System). These attributes enable the integration of geographic and spatial data into simulations. Geometries can be defined manually using Shapely or imported from various sources, such as vector data files (e.g., shapefiles), GeoJSON objects, or GeoPandas GeoDataFrames. --- \*\*Key Features:\*\* - \*\*Spatial Reference Systems Support:\*\* Mesa-Geo handles coordinate reference systems (CRS), which is essential for working with geographic data in various projections. - \*\*Geometric Operations Support:\*\* Mesa-Geo utilizes Shapely, which provides robust tools for creating and manipulating geometric shapes like points, polygons, and lines. - \*\*Topological Operations Support:\*\* Functions for analyzing spatial relationships between geometries. --- \*\*Author(s):\*\* Wang Boyu --- \*\*Additional Resources:\*\* For more information, visit the official \[Mesa-Geo repository\](https://github.com/projectmesa/mesa-geo?tab=readme-ov-file). --- ## Mesa Examples 📊 \*\*Description:\*\* Mesa Examples provide a collection of models and use cases demonstrating the features and capabilities of the Mesa framework for agent-based modeling. These examples include core and user-submitted models covering a variety of domains like grid spaces, networks, visualization, and GIS. --- \*\*Key Features:\*\* - \*\*Core Examples:\*\* Fully tested and updated models included directly with the Mesa framework. - \*\*User Examples:\*\* Community-contributed models showcasing advanced and diverse use cases. - \*\*Extensive Coverage:\*\* Examples for grid spaces, GIS integration, networks, visualization, and more. - \*\*Easy Access:\*\* Available directly from the Mesa package or via installation from the repository. --- \*\*Author(s):\*\* Contributions from the Mesa developer community. --- \*\*Examples Include:\*\* - \*\*Grid Space:\*\* Models like Bank Reserves, Conway’s Game of Life, and Forest Fire. - \*\*GIS:\*\* GeoSchelling Models, Urban Growth, and Population Models. - \*\*Network:\*\* Boltzmann Wealth Model and Ant System for the Traveling Salesman Problem. - \*\*Visualization:\*\* Charting tools and grid displays. --- \*\*For More Information:\*\* For more Detail, Visit the \[Mesa Examples Repository\](https://github.com/projectmesa/mesa/tree/main/mesa/examples). --- ## \*\*Mesa-Frames\*\* 🚀 \*\*Description:\*\* Mesa-Frames is an extension of the Mesa framework designed to handle complex simulations with thousands of agents. By utilizing DataFrames (pandas or Polars), it enhances scalability and performance while maintaining a syntax similar to Mesa. --- \*\*Key Features:\*\* - \*\*Enhanced Performance:\*\* Uses DataFrames for SIMD processing and vectorized functions to speed up simulations. - \*\*Backend Support:\*\* Supports \`pandas\` (ease of use) and \`Polars\` (performance innovations with Rust-based backend). - \*\*Seamless Integration:\*\* Maintains a similar API and functionality as the base Mesa framework for easier adoption. - \*\*In-Place Operations:\*\* Functional programming and fast memory-efficient copy methods. - \*\*Future Plans:\*\* GPU functionality, automatic model vectorization, and backend-independent AgentSet class. --- \*\*Usage:\*\* - Define agents using \`AgentSetPandas\` or \`AgentSetPolars\`. - Implement models by subclassing \`ModelDF\`. - Perform vectorized operations to enhance simulation performance. --- \*\*Author(s):\*\* Developed and maintained by the Mesa development community. --- \*\*License:\*\* Distributed under the MIT License. --- \*\*More Information:\*\* Visit the \[GitHub Repository\](https://github.com/projectmesa/mesa-frames). ---
---
# Virus on a Network — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Virus on a Network[#](#virus-on-a-network "Link to this heading")
==================================================================
Summary[#](#summary "Link to this heading")
--------------------------------------------
This model is based on the NetLogo model “Virus on Network”. It demonstrates the spread of a virus through a network and follows the SIR model, commonly seen in epidemiology.
The SIR model is one of the simplest compartmental models, and many models are derivatives of this basic form. The model consists of three compartments:
S: The number of susceptible individuals. When a susceptible and an infectious individual come into “infectious contact”, the susceptible individual contracts the disease and transitions to the infectious compartment. I: The number of infectious individuals. These are individuals who have been infected and are capable of infecting susceptible individuals. R for the number of removed (and immune) or deceased individuals. These are individuals who have been infected and have either recovered from the disease and entered the removed compartment, or died. It is assumed that the number of deaths is negligible with respect to the total population. This compartment may also be called “recovered” or “resistant”.
For more information about this model, read the NetLogo’s web page: http://ccl.northwestern.edu/netlogo/models/VirusonaNetwork.
JavaScript library used in this example to render the network: [d3.js](https://d3js.org/)
.
Installation[#](#installation "Link to this heading")
------------------------------------------------------
To install the dependencies use pip and the requirements.txt in this directory. e.g.
$ pip install -r requirements.txt
How to Run[#](#how-to-run "Link to this heading")
--------------------------------------------------
To run the model interactively, in this directory, run the following command
$ solara run app.py
Files[#](#files "Link to this heading")
----------------------------------------
* `model.py`: Contains the agent class, and the overall model class.
* `agents.py`: Contains the agent class.
* `app.py`: Contains the code for the interactive Solara visualization.
Further Reading[#](#further-reading "Link to this heading")
------------------------------------------------------------
The full tutorial describing how the model is built can be found at: https://mesa.readthedocs.io/en/latest/tutorials/intro\_tutorial.html
[Stonedahl, F. and Wilensky, U. (2008). NetLogo Virus on a Network model](http://ccl.northwestern.edu/netlogo/models/VirusonaNetwork)
. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
[Wilensky, U. (1999). NetLogo](http://ccl.northwestern.edu/netlogo/)
Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
Agents[#](#agents "Link to this heading")
------------------------------------------
from enum import Enum
from mesa import Agent
class State(Enum):
SUSCEPTIBLE \= 0
INFECTED \= 1
RESISTANT \= 2
class VirusAgent(Agent):
"""Individual Agent definition and its properties/interaction methods."""
def \_\_init\_\_(
self,
model,
initial\_state,
virus\_spread\_chance,
virus\_check\_frequency,
recovery\_chance,
gain\_resistance\_chance,
):
super().\_\_init\_\_(model)
self.state \= initial\_state
self.virus\_spread\_chance \= virus\_spread\_chance
self.virus\_check\_frequency \= virus\_check\_frequency
self.recovery\_chance \= recovery\_chance
self.gain\_resistance\_chance \= gain\_resistance\_chance
def try\_to\_infect\_neighbors(self):
neighbors\_nodes \= self.model.grid.get\_neighborhood(
self.pos, include\_center\=False
)
susceptible\_neighbors \= \[\
agent\
for agent in self.model.grid.get\_cell\_list\_contents(neighbors\_nodes)\
if agent.state is State.SUSCEPTIBLE\
\]
for a in susceptible\_neighbors:
if self.random.random() < self.virus\_spread\_chance:
a.state \= State.INFECTED
def try\_gain\_resistance(self):
if self.random.random() < self.gain\_resistance\_chance:
self.state \= State.RESISTANT
def try\_remove\_infection(self):
\# Try to remove
if self.random.random() < self.recovery\_chance:
\# Success
self.state \= State.SUSCEPTIBLE
self.try\_gain\_resistance()
else:
\# Failed
self.state \= State.INFECTED
def try\_check\_situation(self):
if (self.random.random() < self.virus\_check\_frequency) and (
self.state is State.INFECTED
):
self.try\_remove\_infection()
def step(self):
if self.state is State.INFECTED:
self.try\_to\_infect\_neighbors()
self.try\_check\_situation()
Model[#](#model "Link to this heading")
----------------------------------------
import math
import networkx as nx
import mesa
from mesa import Model
from mesa.examples.basic.virus\_on\_network.agents import State, VirusAgent
def number\_state(model, state):
return sum(1 for a in model.grid.get\_all\_cell\_contents() if a.state is state)
def number\_infected(model):
return number\_state(model, State.INFECTED)
def number\_susceptible(model):
return number\_state(model, State.SUSCEPTIBLE)
def number\_resistant(model):
return number\_state(model, State.RESISTANT)
class VirusOnNetwork(Model):
"""A virus model with some number of agents."""
def \_\_init\_\_(
self,
num\_nodes\=10,
avg\_node\_degree\=3,
initial\_outbreak\_size\=1,
virus\_spread\_chance\=0.4,
virus\_check\_frequency\=0.4,
recovery\_chance\=0.3,
gain\_resistance\_chance\=0.5,
seed\=None,
):
super().\_\_init\_\_(seed\=seed)
self.num\_nodes \= num\_nodes
prob \= avg\_node\_degree / self.num\_nodes
self.G \= nx.erdos\_renyi\_graph(n\=self.num\_nodes, p\=prob)
self.grid \= mesa.space.NetworkGrid(self.G)
self.initial\_outbreak\_size \= (
initial\_outbreak\_size if initial\_outbreak\_size <= num\_nodes else num\_nodes
)
self.virus\_spread\_chance \= virus\_spread\_chance
self.virus\_check\_frequency \= virus\_check\_frequency
self.recovery\_chance \= recovery\_chance
self.gain\_resistance\_chance \= gain\_resistance\_chance
self.datacollector \= mesa.DataCollector(
{
"Infected": number\_infected,
"Susceptible": number\_susceptible,
"Resistant": number\_resistant,
"R over S": self.resistant\_susceptible\_ratio,
}
)
\# Create agents
for node in self.G.nodes():
a \= VirusAgent(
self,
State.SUSCEPTIBLE,
self.virus\_spread\_chance,
self.virus\_check\_frequency,
self.recovery\_chance,
self.gain\_resistance\_chance,
)
\# Add the agent to the node
self.grid.place\_agent(a, node)
\# Infect some nodes
infected\_nodes \= self.random.sample(list(self.G), self.initial\_outbreak\_size)
for a in self.grid.get\_cell\_list\_contents(infected\_nodes):
a.state \= State.INFECTED
self.running \= True
self.datacollector.collect(self)
def resistant\_susceptible\_ratio(self):
try:
return number\_state(self, State.RESISTANT) / number\_state(
self, State.SUSCEPTIBLE
)
except ZeroDivisionError:
return math.inf
def step(self):
self.agents.shuffle\_do("step")
\# collect data
self.datacollector.collect(self)
App[#](#app "Link to this heading")
------------------------------------
import math
import solara
from mesa.examples.basic.virus\_on\_network.model import (
State,
VirusOnNetwork,
number\_infected,
)
from mesa.visualization import (
Slider,
SolaraViz,
make\_plot\_component,
make\_space\_component,
)
def agent\_portrayal(agent):
node\_color\_dict \= {
State.INFECTED: "tab:red",
State.SUSCEPTIBLE: "tab:green",
State.RESISTANT: "tab:gray",
}
return {"color": node\_color\_dict\[agent.state\], "size": 10}
def get\_resistant\_susceptible\_ratio(model):
ratio \= model.resistant\_susceptible\_ratio()
ratio\_text \= r"$\\infty$" if ratio is math.inf else f"{ratio:.2f}"
infected\_text \= str(number\_infected(model))
return solara.Markdown(
f"Resistant/Susceptible Ratio: {ratio\_text}
Infected Remaining: {infected\_text}"
)
model\_params \= {
"seed": {
"type": "InputText",
"value": 42,
"label": "Random Seed",
},
"num\_nodes": Slider(
label\="Number of agents",
value\=10,
min\=10,
max\=100,
step\=1,
),
"avg\_node\_degree": Slider(
label\="Avg Node Degree",
value\=3,
min\=3,
max\=8,
step\=1,
),
"initial\_outbreak\_size": Slider(
label\="Initial Outbreak Size",
value\=1,
min\=1,
max\=10,
step\=1,
),
"virus\_spread\_chance": Slider(
label\="Virus Spread Chance",
value\=0.4,
min\=0.0,
max\=1.0,
step\=0.1,
),
"virus\_check\_frequency": Slider(
label\="Virus Check Frequency",
value\=0.4,
min\=0.0,
max\=1.0,
step\=0.1,
),
"recovery\_chance": Slider(
label\="Recovery Chance",
value\=0.3,
min\=0.0,
max\=1.0,
step\=0.1,
),
"gain\_resistance\_chance": Slider(
label\="Gain Resistance Chance",
value\=0.5,
min\=0.0,
max\=1.0,
step\=0.1,
),
}
def post\_process\_lineplot(ax):
ax.set\_ylim(ymin\=0)
ax.set\_ylabel("# people")
ax.legend(bbox\_to\_anchor\=(1.05, 1.0), loc\="upper left")
SpacePlot \= make\_space\_component(agent\_portrayal)
StatePlot \= make\_plot\_component(
{"Infected": "tab:red", "Susceptible": "tab:green", "Resistant": "tab:gray"},
post\_process\=post\_process\_lineplot,
)
model1 \= VirusOnNetwork()
page \= SolaraViz(
model1,
components\=\[\
SpacePlot,\
StatePlot,\
get\_resistant\_susceptible\_ratio,\
\],
model\_params\=model\_params,
name\="Virus Model",
)
page \# noqa
On this page
### This Page
* [Show Source](../../_sources/examples/basic/virus_on_network.md.txt)
---
# Demographic Prisoner’s Dilemma on a Grid — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Demographic Prisoner’s Dilemma on a Grid[#](#demographic-prisoner-s-dilemma-on-a-grid "Link to this heading")
==============================================================================================================
Summary[#](#summary "Link to this heading")
--------------------------------------------
The Demographic Prisoner’s Dilemma is a family of variants on the classic two-player \[Prisoner’s Dilemma\]. The model consists of agents, each with a strategy of either Cooperate or Defect. Each agent’s payoff is based on its strategy and the strategies of its spatial neighbors. After each step of the model, the agents adopt the strategy of their neighbor with the highest total score.
The model payoff table is:
| | Cooperate | Defect |
| --- | --- | --- |
| **Cooperate** | 1, 1 | 0, D |
| **Defect** | D, 0 | 0, 0 |
Where _D_ is the defection bonus, generally set higher than 1. In these runs, the defection bonus is set to $D=1.6$.
The Demographic Prisoner’s Dilemma demonstrates how simple rules can lead to the emergence of widespread cooperation, despite the Defection strategy dominating each individual interaction game. However, it is also interesting for another reason: it is known to be sensitive to the activation regime employed in it.
How to Run[#](#how-to-run "Link to this heading")
--------------------------------------------------
### Web based model simulation[#](#web-based-model-simulation "Link to this heading")
To run the model interactively, run `solara run app.py` in this directory.
### Jupyter Notebook[#](#jupyter-notebook "Link to this heading")
Launch the `Demographic Prisoner's Dilemma Activation Schedule.ipynb` notebook and run the code.
Files[#](#files "Link to this heading")
----------------------------------------
* `agents.py`: contains the agent class.
* `model.py`: contains the model class; the model takes a `activation_order` string as an argument, which determines in which order agents are activated: Sequential, Random or Simultaneous.
* `app.py`: contains the interactive visualization server.
* `Demographic Prisoner's Dilemma Activation Schedule.ipynb`: Jupyter Notebook for running the scheduling experiment. This runs the model three times, one for each activation type, and demonstrates how the activation regime drives the model to different outcomes.
Further Reading[#](#further-reading "Link to this heading")
------------------------------------------------------------
This model is adapted from:
Wilensky, U. (2002). NetLogo PD Basic Evolutionary model. http://ccl.northwestern.edu/netlogo/models/PDBasicEvolutionary. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
The Demographic Prisoner’s Dilemma originates from:
[Epstein, J. Zones of Cooperation in Demographic Prisoner’s Dilemma. 1998.](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.8.8629&rep=rep1&type=pdf)
Agents[#](#agents "Link to this heading")
------------------------------------------
from mesa.experimental.cell\_space import CellAgent
class PDAgent(CellAgent):
"""Agent member of the iterated, spatial prisoner's dilemma model."""
def \_\_init\_\_(self, model, starting\_move\=None, cell\=None):
"""
Create a new Prisoner's Dilemma agent.
Args:
model: model instance
starting\_move: If provided, determines the agent's initial state:
C(ooperating) or D(efecting). Otherwise, random.
"""
super().\_\_init\_\_(model)
self.score \= 0
self.cell \= cell
if starting\_move:
self.move \= starting\_move
else:
self.move \= self.random.choice(\["C", "D"\])
self.next\_move \= None
@property
def is\_cooroperating(self):
return self.move \== "C"
def step(self):
"""Get the best neighbor's move, and change own move accordingly
if better than own score."""
\# neighbors = self.model.grid.get\_neighbors(self.pos, True, include\_center=True)
neighbors \= \[\*list(self.cell.neighborhood.agents), self\]
best\_neighbor \= max(neighbors, key\=lambda a: a.score)
self.next\_move \= best\_neighbor.move
if self.model.activation\_order != "Simultaneous":
self.advance()
def advance(self):
self.move \= self.next\_move
self.score += self.increment\_score()
def increment\_score(self):
neighbors \= self.cell.neighborhood.agents
if self.model.activation\_order \== "Simultaneous":
moves \= \[neighbor.next\_move for neighbor in neighbors\]
else:
moves \= \[neighbor.move for neighbor in neighbors\]
return sum(self.model.payoff\[(self.move, move)\] for move in moves)
Model[#](#model "Link to this heading")
----------------------------------------
import mesa
from mesa.examples.advanced.pd\_grid.agents import PDAgent
from mesa.experimental.cell\_space import OrthogonalMooreGrid
class PdGrid(mesa.Model):
"""Model class for iterated, spatial prisoner's dilemma model."""
activation\_regimes \= \["Sequential", "Random", "Simultaneous"\]
\# This dictionary holds the payoff for this agent,
\# keyed on: (my\_move, other\_move)
payoff \= {("C", "C"): 1, ("C", "D"): 0, ("D", "C"): 1.6, ("D", "D"): 0}
def \_\_init\_\_(
self, width\=50, height\=50, activation\_order\="Random", payoffs\=None, seed\=None
):
"""
Create a new Spatial Prisoners' Dilemma Model.
Args:
width, height: Grid size. There will be one agent per grid cell.
activation\_order: Can be "Sequential", "Random", or "Simultaneous".
Determines the agent activation regime.
payoffs: (optional) Dictionary of (move, neighbor\_move) payoffs.
"""
super().\_\_init\_\_(seed\=seed)
self.activation\_order \= activation\_order
self.grid \= OrthogonalMooreGrid((width, height), torus\=True, random\=self.random)
if payoffs is not None:
self.payoff \= payoffs
PDAgent.create\_agents(
self, len(self.grid.all\_cells.cells), cell\=self.grid.all\_cells.cells
)
self.datacollector \= mesa.DataCollector(
{
"Cooperating\_Agents": lambda m: len(
\[a for a in m.agents if a.move \== "C"\]
)
}
)
self.running \= True
self.datacollector.collect(self)
def step(self):
\# Activate all agents, based on the activation regime
match self.activation\_order:
case "Sequential":
self.agents.do("step")
case "Random":
self.agents.shuffle\_do("step")
case "Simultaneous":
self.agents.do("step")
self.agents.do("advance")
case \_:
raise ValueError(f"Unknown activation order: {self.activation\_order}")
\# Collect data
self.datacollector.collect(self)
def run(self, n):
"""Run the model for n steps."""
for \_ in range(n):
self.step()
App[#](#app "Link to this heading")
------------------------------------
"""
Solara-based visualization for the Spatial Prisoner's Dilemma Model.
"""
from mesa.examples.advanced.pd\_grid.model import PdGrid
from mesa.visualization import (
Slider,
SolaraViz,
make\_plot\_component,
make\_space\_component,
)
def pd\_agent\_portrayal(agent):
"""
Portrayal function for rendering PD agents in the visualization.
"""
return {
"color": "blue" if agent.move \== "C" else "red",
"marker": "s", \# square marker
"size": 25,
}
\# Model parameters
model\_params \= {
"seed": {
"type": "InputText",
"value": 42,
"label": "Random Seed",
},
"width": Slider("Grid Width", value\=50, min\=10, max\=100, step\=1),
"height": Slider("Grid Height", value\=50, min\=10, max\=100, step\=1),
"activation\_order": {
"type": "Select",
"value": "Random",
"values": PdGrid.activation\_regimes,
"label": "Activation Regime",
},
}
\# Create grid visualization component using Altair
grid\_viz \= make\_space\_component(agent\_portrayal\=pd\_agent\_portrayal)
\# Create plot for tracking cooperating agents over time
plot\_component \= make\_plot\_component("Cooperating\_Agents")
\# Initialize model
initial\_model \= PdGrid()
\# Create visualization with all components
page \= SolaraViz(
model\=initial\_model,
components\=\[grid\_viz, plot\_component\],
model\_params\=model\_params,
name\="Spatial Prisoner's Dilemma",
)
page \# noqa B018
On this page
### This Page
* [Show Source](../../_sources/examples/advanced/pd_grid.md.txt)
---
# Epstein Civil Violence Model — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Epstein Civil Violence Model[#](#epstein-civil-violence-model "Link to this heading")
======================================================================================
Summary[#](#summary "Link to this heading")
--------------------------------------------
This model is based on Joshua Epstein’s simulation of how civil unrest grows and is suppressed. Citizen agents wander the grid randomly, and are endowed with individual risk aversion and hardship levels; there is also a universal regime legitimacy value. There are also Cop agents, who work on behalf of the regime. Cops arrest Citizens who are actively rebelling; Citizens decide whether to rebel based on their hardship and the regime legitimacy, and their perceived probability of arrest.
The model generates mass uprising as self-reinforcing processes: if enough agents are rebelling, the probability of any individual agent being arrested is reduced, making more agents more likely to join the uprising. However, the more rebelling Citizens the Cops arrest, the less likely additional agents become to join.
How to Run[#](#how-to-run "Link to this heading")
--------------------------------------------------
To run the model interactively, in this directory, run the following command
$ solara run app.py
Files[#](#files "Link to this heading")
----------------------------------------
* `model.py`: Core model code.
* `agent.py`: Agent classes.
* `app.py`: Sets up the interactive visualization.
* `Epstein Civil Violence.ipynb`: Jupyter notebook conducting some preliminary analysis of the model.
Further Reading[#](#further-reading "Link to this heading")
------------------------------------------------------------
This model is based adapted from:
[Epstein, J. “Modeling civil violence: An agent-based computational approach”, Proceedings of the National Academy of Sciences, Vol. 99, Suppl. 3, May 14, 2002](http://www.pnas.org/content/99/suppl.3/7243.short)
A similar model is also included with NetLogo:
Wilensky, U. (2004). NetLogo Rebellion model. http://ccl.northwestern.edu/netlogo/models/Rebellion. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
Agents[#](#agents "Link to this heading")
------------------------------------------
import math
from enum import Enum
import mesa
class CitizenState(Enum):
ACTIVE \= 1
QUIET \= 2
ARRESTED \= 3
class EpsteinAgent(mesa.experimental.cell\_space.CellAgent):
def update\_neighbors(self):
"""
Look around and see who my neighbors are
"""
self.neighborhood \= self.cell.get\_neighborhood(radius\=self.vision)
self.neighbors \= self.neighborhood.agents
self.empty\_neighbors \= \[c for c in self.neighborhood if c.is\_empty\]
def move(self):
if self.model.movement and self.empty\_neighbors:
new\_pos \= self.random.choice(self.empty\_neighbors)
self.move\_to(new\_pos)
class Citizen(EpsteinAgent):
"""
A member of the general population, may or may not be in active rebellion.
Summary of rule: If grievance - risk > threshold, rebel.
Attributes:
hardship: Agent's 'perceived hardship (i.e., physical or economic
privation).' Exogenous, drawn from U(0,1).
regime\_legitimacy: Agent's perception of regime legitimacy, equal
across agents. Exogenous.
risk\_aversion: Exogenous, drawn from U(0,1).
threshold: if (grievance - (risk\_aversion \* arrest\_probability)) >
threshold, go/remain Active
vision: number of cells in each direction (N, S, E and W) that agent
can inspect
condition: Can be "Quiescent" or "Active;" deterministic function of
greivance, perceived risk, and
grievance: deterministic function of hardship and regime\_legitimacy;
how aggrieved is agent at the regime?
arrest\_probability: agent's assessment of arrest probability, given
rebellion
"""
def \_\_init\_\_(
self, model, regime\_legitimacy, threshold, vision, arrest\_prob\_constant
):
"""
Create a new Citizen.
Args:
model: the model to which the agent belongs
hardship: Agent's 'perceived hardship (i.e., physical or economic
privation).' Exogenous, drawn from U(0,1).
regime\_legitimacy: Agent's perception of regime legitimacy, equal
across agents. Exogenous.
risk\_aversion: Exogenous, drawn from U(0,1).
threshold: if (grievance - (risk\_aversion \* arrest\_probability)) >
threshold, go/remain Active
vision: number of cells in each direction (N, S, E and W) that
agent can inspect. Exogenous.
model: model instance
"""
super().\_\_init\_\_(model)
self.hardship \= self.random.random()
self.risk\_aversion \= self.random.random()
self.regime\_legitimacy \= regime\_legitimacy
self.threshold \= threshold
self.state \= CitizenState.QUIET
self.vision \= vision
self.jail\_sentence \= 0
self.grievance \= self.hardship \* (1 \- self.regime\_legitimacy)
self.arrest\_prob\_constant \= arrest\_prob\_constant
self.arrest\_probability \= None
self.neighborhood \= \[\]
self.neighbors \= \[\]
self.empty\_neighbors \= \[\]
def step(self):
"""
Decide whether to activate, then move if applicable.
"""
if self.jail\_sentence:
self.jail\_sentence \-= 1
return \# no other changes or movements if agent is in jail.
self.update\_neighbors()
self.update\_estimated\_arrest\_probability()
net\_risk \= self.risk\_aversion \* self.arrest\_probability
if (self.grievance \- net\_risk) \> self.threshold:
self.state \= CitizenState.ACTIVE
else:
self.state \= CitizenState.QUIET
self.move()
def update\_estimated\_arrest\_probability(self):
"""
Based on the ratio of cops to actives in my neighborhood, estimate the
p(Arrest | I go active).
"""
cops\_in\_vision \= 0
actives\_in\_vision \= 1 \# citizen counts herself
for neighbor in self.neighbors:
if isinstance(neighbor, Cop):
cops\_in\_vision += 1
elif neighbor.state \== CitizenState.ACTIVE:
actives\_in\_vision += 1
\# there is a body of literature on this equation
\# the round is not in the pnas paper but without it, its impossible to replicate
\# the dynamics shown there.
self.arrest\_probability \= 1 \- math.exp(
\-1 \* self.arrest\_prob\_constant \* round(cops\_in\_vision / actives\_in\_vision)
)
class Cop(EpsteinAgent):
"""
A cop for life. No defection.
Summary of rule: Inspect local vision and arrest a random active agent.
Attributes:
unique\_id: unique int
x, y: Grid coordinates
vision: number of cells in each direction (N, S, E and W) that cop is
able to inspect
"""
def \_\_init\_\_(self, model, vision, max\_jail\_term):
"""
Create a new Cop.
Args:
x, y: Grid coordinates
vision: number of cells in each direction (N, S, E and W) that
agent can inspect. Exogenous.
model: model instance
"""
super().\_\_init\_\_(model)
self.vision \= vision
self.max\_jail\_term \= max\_jail\_term
def step(self):
"""
Inspect local vision and arrest a random active agent. Move if
applicable.
"""
self.update\_neighbors()
active\_neighbors \= \[\]
for agent in self.neighbors:
if isinstance(agent, Citizen) and agent.state \== CitizenState.ACTIVE:
active\_neighbors.append(agent)
if active\_neighbors:
arrestee \= self.random.choice(active\_neighbors)
arrestee.jail\_sentence \= self.random.randint(0, self.max\_jail\_term)
arrestee.state \= CitizenState.ARRESTED
self.move()
Model[#](#model "Link to this heading")
----------------------------------------
import mesa
from mesa.examples.advanced.epstein\_civil\_violence.agents import (
Citizen,
CitizenState,
Cop,
)
class EpsteinCivilViolence(mesa.Model):
"""
Model 1 from "Modeling civil violence: An agent-based computational
approach," by Joshua Epstein.
http://www.pnas.org/content/99/suppl\_3/7243.full
Args:
height: grid height
width: grid width
citizen\_density: approximate % of cells occupied by citizens.
cop\_density: approximate % of cells occupied by cops.
citizen\_vision: number of cells in each direction (N, S, E and W) that
citizen can inspect
cop\_vision: number of cells in each direction (N, S, E and W) that cop
can inspect
legitimacy: (L) citizens' perception of regime legitimacy, equal
across all citizens
max\_jail\_term: (J\_max)
active\_threshold: if (grievance - (risk\_aversion \* arrest\_probability))
> threshold, citizen rebels
arrest\_prob\_constant: set to ensure agents make plausible arrest
probability estimates
movement: binary, whether agents try to move at step end
max\_iters: model may not have a natural stopping point, so we set a
max.
"""
def \_\_init\_\_(
self,
width\=40,
height\=40,
citizen\_density\=0.7,
cop\_density\=0.074,
citizen\_vision\=7,
cop\_vision\=7,
legitimacy\=0.8,
max\_jail\_term\=1000,
active\_threshold\=0.1,
arrest\_prob\_constant\=2.3,
movement\=True,
max\_iters\=1000,
seed\=None,
):
super().\_\_init\_\_(seed\=seed)
self.movement \= movement
self.max\_iters \= max\_iters
self.grid \= mesa.experimental.cell\_space.OrthogonalVonNeumannGrid(
(width, height), capacity\=1, torus\=True, random\=self.random
)
model\_reporters \= {
"active": CitizenState.ACTIVE.name,
"quiet": CitizenState.QUIET.name,
"arrested": CitizenState.ARRESTED.name,
}
agent\_reporters \= {
"jail\_sentence": lambda a: getattr(a, "jail\_sentence", None),
"arrest\_probability": lambda a: getattr(a, "arrest\_probability", None),
}
self.datacollector \= mesa.DataCollector(
model\_reporters\=model\_reporters, agent\_reporters\=agent\_reporters
)
if cop\_density + citizen\_density \> 1:
raise ValueError("Cop density + citizen density must be less than 1")
for cell in self.grid.all\_cells:
klass \= self.random.choices(
\[Citizen, Cop, None\],
cum\_weights\=\[citizen\_density, citizen\_density + cop\_density, 1\],
)\[0\]
if klass \== Cop:
cop \= Cop(self, vision\=cop\_vision, max\_jail\_term\=max\_jail\_term)
cop.move\_to(cell)
elif klass \== Citizen:
citizen \= Citizen(
self,
regime\_legitimacy\=legitimacy,
threshold\=active\_threshold,
vision\=citizen\_vision,
arrest\_prob\_constant\=arrest\_prob\_constant,
)
citizen.move\_to(cell)
self.running \= True
self.\_update\_counts()
self.datacollector.collect(self)
def step(self):
"""
Advance the model by one step and collect data.
"""
self.agents.shuffle\_do("step")
self.\_update\_counts()
self.datacollector.collect(self)
if self.steps \> self.max\_iters:
self.running \= False
def \_update\_counts(self):
"""Helper function for counting nr. of citizens in given state."""
counts \= self.agents\_by\_type\[Citizen\].groupby("state").count()
for state in CitizenState:
setattr(self, state.name, counts.get(state, 0))
App[#](#app "Link to this heading")
------------------------------------
from mesa.examples.advanced.epstein\_civil\_violence.agents import (
Citizen,
CitizenState,
Cop,
)
from mesa.examples.advanced.epstein\_civil\_violence.model import EpsteinCivilViolence
from mesa.visualization import (
Slider,
SolaraViz,
make\_plot\_component,
make\_space\_component,
)
COP\_COLOR \= "#000000"
agent\_colors \= {
CitizenState.ACTIVE: "#FE6100",
CitizenState.QUIET: "#648FFF",
CitizenState.ARRESTED: "#808080",
}
def citizen\_cop\_portrayal(agent):
if agent is None:
return
portrayal \= {
"size": 50,
}
if isinstance(agent, Citizen):
portrayal\["color"\] \= agent\_colors\[agent.state\]
elif isinstance(agent, Cop):
portrayal\["color"\] \= COP\_COLOR
return portrayal
def post\_process(ax):
ax.set\_aspect("equal")
ax.set\_xticks(\[\])
ax.set\_yticks(\[\])
ax.get\_figure().set\_size\_inches(10, 10)
model\_params \= {
"seed": {
"type": "InputText",
"value": 42,
"label": "Random Seed",
},
"height": 40,
"width": 40,
"citizen\_density": Slider("Initial Agent Density", 0.7, 0.0, 0.9, 0.1),
"cop\_density": Slider("Initial Cop Density", 0.04, 0.0, 0.1, 0.01),
"citizen\_vision": Slider("Citizen Vision", 7, 1, 10, 1),
"cop\_vision": Slider("Cop Vision", 7, 1, 10, 1),
"legitimacy": Slider("Government Legitimacy", 0.82, 0.0, 1, 0.01),
"max\_jail\_term": Slider("Max Jail Term", 30, 0, 50, 1),
}
space\_component \= make\_space\_component(
citizen\_cop\_portrayal, post\_process\=post\_process, draw\_grid\=False
)
chart\_component \= make\_plot\_component(
{state.name.lower(): agent\_colors\[state\] for state in CitizenState}
)
epstein\_model \= EpsteinCivilViolence()
page \= SolaraViz(
epstein\_model,
components\=\[space\_component, chart\_component\],
model\_params\=model\_params,
name\="Epstein Civil Violence",
)
page \# noqa
On this page
### This Page
* [Show Source](../../_sources/examples/advanced/epstein_civil_violence.md.txt)
---
# Boids Flockers — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Boids Flockers[#](#boids-flockers "Link to this heading")
==========================================================
Summary[#](#summary "Link to this heading")
--------------------------------------------
An implementation of Craig Reynolds’s Boids flocker model. Agents (simulated birds) try to fly towards the average position of their neighbors and in the same direction as them, while maintaining a minimum distance. This produces flocking behavior.
This model tests Mesa’s continuous space feature, and uses numpy arrays to represent vectors.
How to Run[#](#how-to-run "Link to this heading")
--------------------------------------------------
* To launch the visualization interactively, run `solara run app.py` in this directory.It will automatically open a browser page.
Files[#](#files "Link to this heading")
----------------------------------------
* [model.py](#model.py)
: Ccntains the Boid Model
* [agents.py](#agents.py)
: Contains the Boid agent
* [app.py](#app.py)
: Solara based Visualization code.
Further Reading[#](#further-reading "Link to this heading")
------------------------------------------------------------
The following link can be visited for more information on the boid flockers model: https://cs.stanford.edu/people/eroberts/courses/soco/projects/2008-09/modeling-natural-systems/boids.html
Agents[#](#agents "Link to this heading")
------------------------------------------
"""A Boid (bird-oid) agent for implementing Craig Reynolds's Boids flocking model.
This implementation uses numpy arrays to represent vectors for efficient computation
of flocking behavior.
"""
import numpy as np
from mesa.experimental.continuous\_space import ContinuousSpaceAgent
class Boid(ContinuousSpaceAgent):
"""A Boid-style flocker agent.
The agent follows three behaviors to flock:
- Cohesion: steering towards neighboring agents
- Separation: avoiding getting too close to any other agent
- Alignment: trying to fly in the same direction as neighbors
Boids have a vision that defines the radius in which they look for their
neighbors to flock with. Their speed (a scalar) and direction (a vector)
define their movement. Separation is their desired minimum distance from
any other Boid.
"""
def \_\_init\_\_(
self,
model,
space,
position\=(0, 0),
speed\=1,
direction\=(1, 1),
vision\=1,
separation\=1,
cohere\=0.03,
separate\=0.015,
match\=0.05,
):
"""Create a new Boid flocker agent.
Args:
model: Model instance the agent belongs to
speed: Distance to move per step
direction: numpy vector for the Boid's direction of movement
vision: Radius to look around for nearby Boids
separation: Minimum distance to maintain from other Boids
cohere: Relative importance of matching neighbors' positions (default: 0.03)
separate: Relative importance of avoiding close neighbors (default: 0.015)
match: Relative importance of matching neighbors' directions (default: 0.05)
"""
super().\_\_init\_\_(space, model)
self.position \= position
self.speed \= speed
self.direction \= direction
self.vision \= vision
self.separation \= separation
self.cohere\_factor \= cohere
self.separate\_factor \= separate
self.match\_factor \= match
self.neighbors \= \[\]
def step(self):
"""Get the Boid's neighbors, compute the new vector, and move accordingly."""
neighbors, distances \= self.get\_neighbors\_in\_radius(radius\=self.vision)
self.neighbors \= \[n for n in neighbors if n is not self\]
\# If no neighbors, maintain current direction
if not neighbors:
self.position += self.direction \* self.speed
return
delta \= self.space.calculate\_difference\_vector(self.position, agents\=neighbors)
cohere\_vector \= delta.sum(axis\=0) \* self.cohere\_factor
separation\_vector \= (
\-1 \* delta\[distances < self.separation\].sum(axis\=0) \* self.separate\_factor
)
match\_vector \= (
np.asarray(\[n.direction for n in neighbors\]).sum(axis\=0) \* self.match\_factor
)
\# Update direction based on the three behaviors
self.direction += (cohere\_vector + separation\_vector + match\_vector) / len(
neighbors
)
\# Normalize direction vector
self.direction /= np.linalg.norm(self.direction)
\# Move boid
self.position += self.direction \* self.speed
Model[#](#model "Link to this heading")
----------------------------------------
"""
Boids Flocking Model
\===================
A Mesa implementation of Craig Reynolds's Boids flocker model.
Uses numpy arrays to represent vectors.
"""
import os
import sys
sys.path.insert(0, os.path.abspath("../../../.."))
import numpy as np
from mesa import Model
from mesa.examples.basic.boid\_flockers.agents import Boid
from mesa.experimental.continuous\_space import ContinuousSpace
class BoidFlockers(Model):
"""Flocker model class. Handles agent creation, placement and scheduling."""
def \_\_init\_\_(
self,
population\_size\=100,
width\=100,
height\=100,
speed\=1,
vision\=10,
separation\=2,
cohere\=0.03,
separate\=0.015,
match\=0.05,
seed\=None,
):
"""Create a new Boids Flocking model.
Args:
population\_size: Number of Boids in the simulation (default: 100)
width: Width of the space (default: 100)
height: Height of the space (default: 100)
speed: How fast the Boids move (default: 1)
vision: How far each Boid can see (default: 10)
separation: Minimum distance between Boids (default: 2)
cohere: Weight of cohesion behavior (default: 0.03)
separate: Weight of separation behavior (default: 0.015)
match: Weight of alignment behavior (default: 0.05)
seed: Random seed for reproducibility (default: None)
"""
super().\_\_init\_\_(seed\=seed)
\# Set up the space
self.space \= ContinuousSpace(
\[\[0, width\], \[0, height\]\],
torus\=True,
random\=self.random,
n\_agents\=population\_size,
)
\# Create and place the Boid agents
positions \= self.rng.random(size\=(population\_size, 2)) \* self.space.size
directions \= self.rng.uniform(\-1, 1, size\=(population\_size, 2))
Boid.create\_agents(
self,
population\_size,
self.space,
position\=positions,
direction\=directions,
cohere\=cohere,
separate\=separate,
match\=match,
speed\=speed,
vision\=vision,
separation\=separation,
)
\# For tracking statistics
self.average\_heading \= None
self.update\_average\_heading()
def update\_average\_heading(self):
"""Calculate the average heading (direction) of all Boids."""
if not self.agents:
self.average\_heading \= 0
return
headings \= np.array(\[agent.direction for agent in self.agents\])
mean\_heading \= np.mean(headings, axis\=0)
self.average\_heading \= np.arctan2(mean\_heading\[1\], mean\_heading\[0\])
def step(self):
"""Run one step of the model.
All agents are activated in random order using the AgentSet shuffle\_do method.
"""
self.agents.shuffle\_do("step")
self.update\_average\_heading()
App[#](#app "Link to this heading")
------------------------------------
import os
import sys
sys.path.insert(0, os.path.abspath("../../../.."))
from mesa.examples.basic.boid\_flockers.model import BoidFlockers
from mesa.visualization import Slider, SolaraViz, make\_space\_component
def boid\_draw(agent):
neighbors \= len(agent.neighbors)
if neighbors <= 1:
return {"color": "red", "size": 20}
elif neighbors \>= 2:
return {"color": "green", "size": 20}
model\_params \= {
"seed": {
"type": "InputText",
"value": 42,
"label": "Random Seed",
},
"population\_size": Slider(
label\="Number of boids",
value\=100,
min\=10,
max\=200,
step\=10,
),
"width": 100,
"height": 100,
"speed": Slider(
label\="Speed of Boids",
value\=5,
min\=1,
max\=20,
step\=1,
),
"vision": Slider(
label\="Vision of Bird (radius)",
value\=10,
min\=1,
max\=50,
step\=1,
),
"separation": Slider(
label\="Minimum Separation",
value\=2,
min\=1,
max\=20,
step\=1,
),
}
model \= BoidFlockers()
page \= SolaraViz(
model,
components\=\[make\_space\_component(agent\_portrayal\=boid\_draw, backend\="matplotlib")\],
model\_params\=model\_params,
name\="Boid Flocking Model",
)
page \# noqa
On this page
### This Page
* [Show Source](../../_sources/examples/basic/boid_flockers.md.txt)
---
# Introductory Tutorial — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Introductory Tutorial[#](#introductory-tutorial "Link to this heading")
========================================================================
The Boltzmann Wealth Model[#](#the-boltzmann-wealth-model "Link to this heading")
----------------------------------------------------------------------------------
**Important:**
* If you are just exploring Mesa and want the fastest way to execute the code we recommend executing this tutorial online in a Colab notebook. [](https://colab.research.google.com/github/projectmesa/mesa/blob/main/docs/tutorials/intro_tutorial.ipynb)
or if you do not have a Google account you can use [](https://mybinder.org/v2/gh/projectmesa/mesa/main?labpath=docs%2Ftutorials%2Fintro_tutorial.ipynb)
(This can take 30 seconds to 5 minutes to load)
* If you are running locally, please ensure you have the latest Mesa version installed.
Tutorial Description[#](#tutorial-description "Link to this heading")
----------------------------------------------------------------------
[Mesa](https://github.com/projectmesa/mesa)
is a Python framework for [agent-based modeling](https://en.wikipedia.org/wiki/Agent-based_model)
. This tutorial will assist you in getting started and discover some of the core features of Mesa. The tutorial starts with the key pieces of a model and then progressively adds functionality.
Should anyone find any errors, bugs, have a suggestion, or just are looking for clarification, let us know in our [chat](https://matrix.to/#/#project-mesa:matrix.org)
!
The premise of this tutorial is to create a starter-level model representing agents exchanging money.
The table of contents (icon on the left) shows each of the items this tutorial covers with the major sections being:
* Model Description and Set Up
* Building the Basic Model
* Adding Space
* Collecting Data
* AgentSet Functionality
* Batch Run
### More Mesa[#](#more-mesa "Link to this heading")
If you are looking for other Mesa models or tools here are some additional resources.
* Interactive Dashboard: There is a separate [visualization tutorial](https://mesa.readthedocs.io/latest/tutorials/visualization_tutorial.html)
that will take users through building a dashboard for this model (aka Boltzmann Wealth Model).
* Classic ABMs: You can also find canonical examples of ABMs written in Mesa in the [Examples Tab](https://mesa.readthedocs.io/stable/examples.html)
* More Examples: Want to integrate Reinforcement Learning or work on the Traveling Salesman Problem checkout [Mesa Examples](https://github.com/projectmesa/mesa-examples/)
* Mesa-Geo: If you need an ABM with Geographic Information Systems (GIS) checkout [Mesa-Geo](https://mesa-geo.readthedocs.io/latest/)
* Mesa Frames: Have a large complex model that you need to speed up, check out [Mesa Frames](https://github.com/projectmesa/mesa-frames)
Model Description[#](#model-description "Link to this heading")
----------------------------------------------------------------
This is a simulated agent-based economy. In an agent-based economy, the behavior of an individual economic agent, such as a consumer or producer, is studied in a market environment. This model is drawn from the field econophysics, specifically a paper prepared by Drăgulescu et al. for additional information on the modeling assumptions used in this model. \[Drăgulescu, 2002\].
The assumption that govern this model are:
1. There are some number of agents.
2. All agents begin with 1 unit of money.
3. At every step of the model, an agent gives 1 unit of money (if they have it) to some other agent.
Even as a starter-level model it yields results that are both interesting and unexpected.
Due to its simplicity and intriguing results, we found it to be the best starter model.
### Tutorial Setup[#](#tutorial-setup "Link to this heading")
Create and activate a [virtual environment](http://docs.python-guide.org/en/latest/dev/virtualenvs/)
. _Python version 3.11 or higher is required_.
Install Mesa:
pip install \--upgrade mesa\[rec\]
Install Jupyter notebook (optional):
pip install jupyter
Install [Seaborn](https://seaborn.pydata.org/)
(which is used for data visualization):
pip install seaborn
**If running in Google Colab run the below cell to install Mesa.** (This will also work in a locally installed version of Jupyter).
### CHANGE THE NEXT CELL to code if you are in Google COLAB[#](#change-the-next-cell-to-code-if-you-are-in-google-colab "Link to this heading")
Building the Sample Model[#](#building-the-sample-model "Link to this heading")
--------------------------------------------------------------------------------
After Mesa is installed a model can be built. A jupyter notebook is recommended for this tutorial, this allows for small segments of codes to be examined one at a time.
### Creating Model With Jupyter notebook[#](#creating-model-with-jupyter-notebook "Link to this heading")
Write the model interactively in [Jupyter](http://jupyter.org/)
cells.
Start Jupyter:
jupyter lab
Create a new notebook named `money_model.ipynb` (or whatever you want to call it).
### Creating Model With Script File (IDE, Text Editor, Colab, etc.)[#](#creating-model-with-script-file-ide-text-editor-colab-etc "Link to this heading")
Create a new file called `money_model.py` (or whatever you want to call it)
_Code will be added as the tutorial progresses._
**Good Practice:** Place a model in its own folder/directory. This is not specifically required for the starter\_model, but as other models become more complicated and expand multiple python scripts, documentation, discussions and notebooks may be added.
### Import Dependencies[#](#import-dependencies "Link to this heading")
This includes importing of dependencies needed for the tutorial.
import mesa
\# Data visualization tools.
import seaborn as sns
\# Has multi-dimensional arrays and matrices. Has a large collection of
\# mathematical functions to operate on these arrays.
import numpy as np
\# Data manipulation and analysis.
import pandas as pd
### Create Agent[#](#create-agent "Link to this heading")
First create the agent. As the tutorial progresses, more functionality will be added to the agent.
**Background:** Agents are the individual entities that act in the model. Mesa automatically assigns each agent that is created an integer as a `unique_id.`
**Model-specific information:** Agents are the individuals that exchange money, in this case the amount of money an individual agent has is represented as wealth.
**Code implementation:** This is done by creating a new class (or object) that extends `mesa.Agent` creating a subclass of the `Agent` class from mesa. The new class is named `MoneyAgent`. The inherited code of the Mesa agent object can be found in the [mesa repo](https://github.com/projectmesa/mesa/blob/main/mesa/agent.py)
.
The `MoneyAgent` class is created with the following code:
class MoneyAgent(mesa.Agent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model):
\# Pass the parameters to the parent class.
super().\_\_init\_\_(model)
\# Create the agent's variable and set the initial values.
self.wealth \= 1
### Create Model[#](#create-model "Link to this heading")
Next, create the model. This gives us the two basic classes of any Mesa ABM - the agent class (population of agent objects that doing something) and the manager class (a model object that manages the creation, activation, datacollection etc of the agents)
**Background:** The model can be visualized as a list containing all the agents. The model creates, holds and manages all the agent objects, specifically in a dictionary. The model activates agents in discrete time steps.
**Model-specific information:** When a model is created the number of agents within the model is specified. The model then creates the agents and places them in a set of agents.
**Code implementation:** This is done by creating a new class (or object) that extends `mesa.Model` and calls `super().__init__()`, creating a subclass of the `Model` class from mesa. The new class is named `MoneyModel`. The technical details about the model object can be found in [model module](https://github.com/projectmesa/mesa/blob/main/mesa/model.py)
and the AgentSet in the [agent module](https://github.com/projectmesa/mesa/blob/d7a3834c99a3be809abe2edc8b83610f3d4438ba/mesa/agent.py#L86)
. A critical point is that you can use the `seed` kwarg (keyword argument) to set a seed which controls the random number generator of the model class allowing for the reproducibility of results.
The `MoneyModel` class is created with the following code:
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n, seed\=None):
super().\_\_init\_\_(seed\=seed)
self.num\_agents \= n
\# Create agents
MoneyAgent.create\_agents(model\=self, n\=n)
### Making the Agents `do`[#](#making-the-agents-do "Link to this heading")
With the basics of the Agent class and Model class created we can now activate the agents to `do` things
**Background:** Mesa’s `do` function calls agent functions to grow your ABM. A step is the smallest unit of time in the model, and is often referred to as a tick. The `do` function and Python functionality can be configured to activate agents in different orders. This can be important as the order in which agents are activated can impact the results of the model \[Comer2014\]. At each step of the model, one or more of the agents – usually all of them – are activated and take their own step, changing internally and/or interacting with one another or the environment.
**Model-specific information:** For this section we will randomly reorder the Agent activation order using `mesa.Agent.shuffle_do` and have the agents `step` function print the agent’s unique id that they were assigned during the agent creation process.
**Code implementation:** Using standard ABM convention we add a `step` function to the `MoneyModel` class which calls the `mesa.Agent.shuffle_do` function. We then pass into `shuffle_do` the parameter “step”. This tells mesa to look for and execute the `step` function in our MoneyAgent class.
class MoneyAgent(mesa.Agent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model):
\# Pass the parameters to the parent class.
super().\_\_init\_\_(model)
\# Create the agent's attribute and set the initial values.
self.wealth \= 1
def say\_hi(self):
\# The agent's step will go here.
\# For demonstration purposes we will print the agent's unique\_id
print(f"Hi, I am an agent, you can call me {str(self.unique\_id)}.")
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n, seed\=None):
super().\_\_init\_\_(seed\=seed)
self.num\_agents \= n
\# Create n agents
MoneyAgent.create\_agents(model\=self, n\=n)
def step(self):
"""Advance the model by one step."""
\# This function psuedo-randomly reorders the list of agent objects and
\# then iterates through calling the function passed in as the parameter
self.agents.shuffle\_do("say\_hi")
### Running the Model[#](#running-the-model "Link to this heading")
A basic model has now been created. The model can be run by creating a model object and calling the step method. The model will run for one step and print the unique\_id of each agent. You may run the model for multiple steps by calling the step method multiple times.
note: If you are using `.py` (script) files instead of `.ipynb` (Jupyter), the common convention is to have a `run.py` in the same directory as your model code. You then (1) import the `MoneyModel` class, (2) create a model object and (3) run it for a few steps. As shown below:
from money\_model import MoneyModel
starter\_model \= MoneyModel(10)
starter\_model.step()
Create the model object, and run it for one step:
starter\_model \= MoneyModel(10)
starter\_model.step()
Hi, I am an agent, you can call me 10.
Hi, I am an agent, you can call me 9.
Hi, I am an agent, you can call me 7.
Hi, I am an agent, you can call me 1.
Hi, I am an agent, you can call me 3.
Hi, I am an agent, you can call me 4.
Hi, I am an agent, you can call me 2.
Hi, I am an agent, you can call me 6.
Hi, I am an agent, you can call me 8.
Hi, I am an agent, you can call me 5.
\# Run this step a few times and see what happens! notice the order of the agents changes each time.
starter\_model.step()
Hi, I am an agent, you can call me 6.
Hi, I am an agent, you can call me 1.
Hi, I am an agent, you can call me 8.
Hi, I am an agent, you can call me 7.
Hi, I am an agent, you can call me 3.
Hi, I am an agent, you can call me 5.
Hi, I am an agent, you can call me 10.
Hi, I am an agent, you can call me 2.
Hi, I am an agent, you can call me 4.
Hi, I am an agent, you can call me 9.
\# Challenge: Change the seed from None to a number like 42 and see the impact
\# Challenge: Change \`shuffle\_do\` to just \`do\` and see the impact
### Exercise[#](#exercise "Link to this heading")
Modifying the code below to have every agent print out its `wealth` when it is activated.
class MoneyAgent(mesa.Agent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model):
\# Pass the parameters to the parent class.
super().\_\_init\_\_(model)
\# Create the agent's variable and set the initial values.
self.wealth \= 1
def say\_wealth(self):
\# The agent's step will go here.
\# FIXME: need to print the agent's wealth
print(f"Hi, I am an agent and I am broke!")
Create a model for 12 Agents, and run it for a few steps to see the output.
\# Fixme: Create the model object, and run it
### Agents Exchange[#](#agents-exchange "Link to this heading")
Returning back to the MoneyAgent the actual exchange process is now going to be created.
**Background:** This is where the agent’s behavior as it relates to each step or tick of the model is defined.
**Model-specific information:** In this case, the agent will check its wealth, and if it has money, give one unit of it away to another random agent.
**Code implementation:** The agent’s step method is called by `mesa.Agent.shuffle_do("exchange")`during each step of the model. To allow the agent to choose another agent at random, we use the `model.random` random-number generator. This works just like Python’s `random` module, but if a fixed seed set is set when the model is instantiated (see earlier challenge), this allows users to replicate a specific model run later. Once we identify this other agent object we increase their wealth by 1 and decrease this agents wealth by one.
This updates the step function as shown below
class MoneyAgent(mesa.Agent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model):
\# Pass the parameters to the parent class.
super().\_\_init\_\_(model)
\# Create the agent's variable and set the initial values.
self.wealth \= 1
def exchange(self):
\# Verify agent has some wealth
if self.wealth \> 0:
other\_agent \= self.random.choice(self.model.agents)
if other\_agent is not None:
other\_agent.wealth += 1
self.wealth \-= 1
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n):
super().\_\_init\_\_()
self.num\_agents \= n
\# Create agents
MoneyAgent.create\_agents(model\=self, n\=n)
def step(self):
"""Advance the model by one step."""
\# This function psuedo-randomly reorders the list of agent objects and
\# then iterates through calling the function passed in as the parameter
self.agents.shuffle\_do("exchange")
### Running your first model[#](#running-your-first-model "Link to this heading")
With that last piece in hand, it’s time for the first rudimentary run of the model.
If you’ve written the code in its own script file (`money_model.py` or a different name) you can now modify your `run.py` or even launch a Jupyter notebook. You then just follow the same three steps of (1) import your model class `MoneyModel`, (2) create the model object and (3) run it for a few steps. If you wrote the code in one notebook then step 1, importing, is not necessary.
from money\_model import MoneyModel
now let’s create a model with 10 agents, and run it for 30 steps.
model \= MoneyModel(10) \# Tells the model to create 10 agents
for \_ in range(
30
): \# Runs the model for 10 steps; an underscore is common convention for a variable that is not used
model.step()
next, we need to get some data out of the model. Specifically, we want to see the distribution of the agent’s wealth. We can get the wealth values with list comprehension, and then use seaborn (or another graphics library) to visualize the data in a histogram.
agent\_wealth \= \[a.wealth for a in model.agents\]
\# Create a histogram with seaborn
g \= sns.histplot(agent\_wealth, discrete\=True)
g.set(
title\="Wealth distribution", xlabel\="Wealth", ylabel\="number of agents"
); \# The semicolon is just to avoid printing the object representation

To get a better idea of how a model behaves, we can create multiple model runs and see the distribution that emerges from all of them. We can do this with a nested for loop:
all\_wealth \= \[\]
\# This runs the model 100 times, each model executing 10 steps.
for \_ in range(100):
\# Run the model
model \= MoneyModel(10)
for \_ in range(30):
model.step()
\# Store the results
for agent in model.agents:
all\_wealth.append(agent.wealth)
\# Use seaborn
g \= sns.histplot(all\_wealth, discrete\=True)
g.set(title\="Wealth distribution", xlabel\="Wealth", ylabel\="number of agents");

This runs 100 instantiations of the model, and runs each for 30 steps. (notice that we set the histogram bins to be integers, since agents can only have whole numbers of wealth). This distribution looks a lot smoother. By running the model 100 times, we smooth out some of the ‘noise’ of randomness, and get to the model’s overall expected behavior.
This outcome might be surprising. Despite the fact that all agents, on average, give and receive one unit of money every step, the model converges to a state where most agents have a small amount of money and a small number have a lot of money.
Adding space[#](#adding-space "Link to this heading")
------------------------------------------------------
**Background:** Many ABMs have a spatial element, with agents moving around and interacting with nearby neighbors. Mesa has several types of [spaces](https://mesa.readthedocs.io/latest/apis/space.html)
from different types of grids to networks to an in development [cell\_space](https://mesa.readthedocs.io/latest/apis/experimental.html#module-experimental.cell_space.__init__)
. Mesa grids are divided into cells, and agents can only be on a particular cell, like pieces on a chess board. Continuous space, in contrast, allows agents to have any arbitrary position. (Think of grids vs continuous space like the difference between integers and decimals).
Both grids and continuous spaces are frequently [toroidal](https://en.wikipedia.org/wiki/Toroidal_graph)
, meaning that the edges wrap around, with cells on the right edge connected to those on the left edge, and the top to the bottom. This prevents some cells having fewer neighbors than others, or agents being able to go off the edge of the environment. You can envision a torous by thinking of donut.
Mesa has two main types of grids: `SingleGrid` and `MultiGrid`. `SingleGrid` enforces at most one agent per cell; `MultiGrid` allows multiple agents to be in the same cell. We are going to use `MultiGrid` and then only exchange money with agents in the same cell.
**Model-specific information:** Let’s add a simple spatial element to our model by putting our agents on a grid and make them walk around at random. Instead of giving their unit of money to any random agent, they’ll give it to an agent on the same cell. For the Money model multiple agents can be in the same spaces and since they are on a torus the agents on the left side can exchange money with agent on the right. Agents on the top can exchange with agents on the bottom.
**Code Implementation:** We get a random integer within the width and height of the grid space and the use Mesa’s multigrid `place_agent` function to place the agent in the specified grid location.
We instantiate a grid with width and height parameters, and a boolean as to whether the grid is toroidal. Let’s make width and height model parameters, in addition to the number of agents, and have the grid always be toroidal. We can place agents on a grid with the grid’s `place_agent` method, which takes an agent and an (x, y) tuple of the coordinates to place the agent.
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n, width, height, seed\=None):
super().\_\_init\_\_(seed\=seed)
self.num\_agents \= n
self.grid \= mesa.space.MultiGrid(width, height, True)
\# Create agents
agents \= MoneyAgent.create\_agents(model\=self, n\=n)
\# Create x and y positions for agents
x \= self.rng.integers(0, self.grid.width, size\=(n,))
y \= self.rng.integers(0, self.grid.height, size\=(n,))
for a, i, j in zip(agents, x, y):
\# Add the agent to a random grid cell
self.grid.place\_agent(a, (i, j))
### Moving in Mesa[#](#moving-in-mesa "Link to this heading")
Under the hood, each agent’s position is stored in two ways: the agent is contained in the grid in the cell it is currently in, and the agent has a `pos` variable with an (x, y) coordinate tuple. The `place_agent` method adds the coordinate to the agent automatically.
Now we need to add to the agents’ behaviors, letting them move around and only give money to other agents in the same cell.
First let’s handle movement, and have the agents move to a neighboring cell. The grid object provides a `move_agent` method, which like you’d imagine, moves an agent to a given cell. That still leaves us to get the possible neighboring cells to move to. There are a couple ways to do this. One is to use the current coordinates, and loop over all coordinates +/- 1 away from it. For example:
neighbors \= \[\]
x, y \= self.pos
for dx in \[\-1, 0, 1\]:
for dy in \[\-1, 0, 1\]:
neighbors.append((x+dx, y+dy))
But there’s an even simpler way, using the grid’s built-in `get_neighborhood` method, which returns all the neighbors of a given cell. This method can get two types of cell neighborhoods: [Moore](https://en.wikipedia.org/wiki/Moore_neighborhood)
(includes all 8 surrounding squares), and [Von neumann](https://en.wikipedia.org/wiki/Von_neumann_neighborhood)
(only up/down/left/right). It also needs an argument as to whether to include the center cell itself as one of the neighbors.
With that in mind, the agent’s `move` method looks like this:
class MoneyAgent(mesa.Agent):
#...
def move(self):
possible\_steps \= self.model.grid.get\_neighborhood(
self.pos,
moore\=True,
include\_center\=False)
new\_position \= self.random.choice(possible\_steps)
self.model.grid.move\_agent(self, new\_position)
Next, we need to get all the other agents present in a cell, and give one of them some money. We can get the contents of one or more cells using the grid’s `get_cell_list_contents` method, or by accessing a cell directly. The method accepts a list of cell coordinate tuples, or a single tuple if we only care about one cell.
class MoneyAgent(mesa.Agent):
#...
def give\_money(self):
cellmates \= self.model.grid.get\_cell\_list\_contents(\[self.pos\])
\# Ensure agent is not giving money to itself
cellmates.pop(
cellmates.index(self)
)
if len(cellmates) \> 0:
other \= self.random.choice(cellmates)
other.wealth += 1
self.wealth \-= 1
Now, putting that all together should look like this:
class MoneyAgent(mesa.Agent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model):
super().\_\_init\_\_(model)
self.wealth \= 1
def move(self):
possible\_steps \= self.model.grid.get\_neighborhood(
self.pos, moore\=True, include\_center\=False
)
new\_position \= self.random.choice(possible\_steps)
self.model.grid.move\_agent(self, new\_position)
def give\_money(self):
cellmates \= self.model.grid.get\_cell\_list\_contents(\[self.pos\])
\# Ensure agent is not giving money to itself
cellmates.pop(cellmates.index(self))
if len(cellmates) \> 0:
other\_agent \= self.random.choice(cellmates)
other\_agent.wealth += 1
self.wealth \-= 1
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n, width, height, seed\=None):
super().\_\_init\_\_(seed\=seed)
self.num\_agents \= n
self.grid \= mesa.space.MultiGrid(width, height, True)
\# Create agents
agents \= MoneyAgent.create\_agents(model\=self, n\=n)
\# Create x and y coordinates for agents
x \= self.rng.integers(0, self.grid.width, size\=(n,))
y \= self.rng.integers(0, self.grid.height, size\=(n,))
for a, i, j in zip(agents, x, y):
\# Add the agent to a random grid cell
self.grid.place\_agent(a, (i, j))
def step(self):
self.agents.shuffle\_do("move")
self.agents.do("give\_money")
Let’s create a model with 100 agents on a 10x10 grid, and run it for 20 steps.
model \= MoneyModel(100, 10, 10)
for \_ in range(20):
model.step()
now let’s use seaborn and numpy to visualize the number of agents residing in each cell. To do that, we create a numpy array of the same size as the grid, filled with zeros. Then we use the grid object’s `coord_iter()` feature, which lets us loop over every cell in the grid, giving us each cell’s positions and contents in turn.
agent\_counts \= np.zeros((model.grid.width, model.grid.height))
for cell\_content, (x, y) in model.grid.coord\_iter():
agent\_count \= len(cell\_content)
agent\_counts\[x\]\[y\] \= agent\_count
\# Plot using seaborn, with a visual size of 5x5
g \= sns.heatmap(agent\_counts, cmap\="viridis", annot\=True, cbar\=False, square\=True)
g.figure.set\_size\_inches(5, 5)
g.set(title\="number of agents on each cell of the grid");

\# Challenge: Change the size of the grid
\# Challenge: Change from multigrid to grid (only one agent per cell)
Collecting Data[#](#collecting-data "Link to this heading")
------------------------------------------------------------
**Background:** So far, at the end of every model run, we’ve had to go and write our own code to get the data out of the model. This has two problems: it isn’t very efficient, and it only gives us end results. If we wanted to know the wealth of each agent at each step, we’d have to add that to the loop of executing steps, and figure out some way to store the data.
Since one of the main goals of agent-based modeling is generating data for analysis, Mesa provides a class which can handle data collection and storage for us and make it easier to analyze.
The data collector stores three categories of data:
* Model-level variables : Model-level collection functions take a model object as an input. Such as a function that computes a dynamic of the whole model (in this case we will compute a measure of wealth inequality based on all agent’s wealth)
* Agent-level variables: Agent-level collection functions take an agent object as an input and is typically the state of an agent attributes, in this case wealth.
* Tables (which are a catch-all for everything else).
**Model-specific information:** We will collect two variables to show Mesa capabilities. At the model level, let’s measure the model’s [Gini Coefficient](https://en.wikipedia.org/wiki/Gini_coefficient)
, a measure of wealth inequality. At the agent level, we want to collect every agent’s wealth at every step.
**Code implementation:** Let’s add a DataCollector to the model with [`mesa.DataCollector`](https://github.com/projectmesa/mesa/blob/main/mesa/datacollection.py)
, and collect the agent’s wealth and the gini coefficient at each time step.
def compute\_gini(model):
agent\_wealths \= \[agent.wealth for agent in model.agents\]
x \= sorted(agent\_wealths)
n \= model.num\_agents
B \= sum(xi \* (n \- i) for i, xi in enumerate(x)) / (n \* sum(x))
return 1 + (1 / n) \- 2 \* B
class MoneyAgent(mesa.Agent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model):
super().\_\_init\_\_(model)
self.wealth \= 1
def move(self):
possible\_steps \= self.model.grid.get\_neighborhood(
self.pos, moore\=True, include\_center\=False
)
new\_position \= self.random.choice(possible\_steps)
self.model.grid.move\_agent(self, new\_position)
def give\_money(self):
cellmates \= self.model.grid.get\_cell\_list\_contents(\[self.pos\])
\# Ensure agent is not giving money to itself
cellmates.pop(cellmates.index(self))
if len(cellmates) \> 0:
other \= self.random.choice(cellmates)
other.wealth += 1
self.wealth \-= 1
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n, width, height):
super().\_\_init\_\_()
self.num\_agents \= n
\# create the space
self.grid \= mesa.space.MultiGrid(width, height, True)
\# collect the output
self.datacollector \= mesa.DataCollector(
model\_reporters\={"Gini": compute\_gini}, agent\_reporters\={"Wealth": "wealth"}
)
\# Create agents
agents \= MoneyAgent.create\_agents(model\=self, n\=n)
\# Create x and y positions for agents
x \= self.rng.integers(0, self.grid.width, size\=(n,))
y \= self.rng.integers(0, self.grid.height, size\=(n,))
for a, i, j in zip(agents, x, y):
\# Add the agent to a random grid cell
self.grid.place\_agent(a, (i, j))
def step(self):
self.datacollector.collect(self)
self.agents.shuffle\_do("move")
self.agents.do("give\_money")
At every step of the model, the datacollector will collect and store the model-level current Gini coefficient, as well as each agent’s wealth, associating each with the current step.
We run the model just as we did above. Now is when an interactive session, especially via a notebook, comes in handy: the DataCollector can export the data it has collected as a pandas\* DataFrame, for easy and interactive analysis.
\*If you are new to Python, please be aware that pandas is already installed as a dependency of Mesa and that [pandas](https://pandas.pydata.org/docs/)
is a “fast, powerful, flexible and easy to use open source data analysis and manipulation tool”. Pandas is a great resource to help analyze the data collected in your models.
model \= MoneyModel(100, 10, 10)
for \_ in range(100):
model.step()
To get the series of Gini coefficients as a pandas DataFrame:
### Visualizing a Model Data[#](#visualizing-a-model-data "Link to this heading")
gini \= model.datacollector.get\_model\_vars\_dataframe()
\# Plot the Gini coefficient over time
g \= sns.lineplot(data\=gini)
g.set(title\="Gini Coefficient over Time", ylabel\="Gini Coefficient");

### Visualizing an Agent Data[#](#visualizing-an-agent-data "Link to this heading")
Similarly, we can get the agent-wealth data:
agent\_wealth \= model.datacollector.get\_agent\_vars\_dataframe()
agent\_wealth.head()
| | | Wealth |
| --- | --- | --- |
| Step | AgentID | |
| --- | --- | --- |
| 1 | 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
| 5 | 1 |
You’ll see that the DataFrame’s index is pairings of model step and agent ID. This is because the data collector stores the data in a dictionary, with the step number as the key, and a dictionary of agent ID and variable value pairs as the value. The data collector then converts this dictionary into a DataFrame, which is why the index is a pair of (model step, agent ID). You can analyze it the way you would any other DataFrame. For example, to get a histogram of agent wealth at the model’s end:
last\_step \= agent\_wealth.index.get\_level\_values("Step").max()
end\_wealth \= agent\_wealth.xs(last\_step, level\="Step")\["Wealth"\]
\# Create a histogram of wealth at the last step
g \= sns.histplot(end\_wealth, discrete\=True)
g.set(
title\="Distribution of wealth at the end of simulation",
xlabel\="Wealth",
ylabel\="number of agents",
);

Or to plot the wealth of a given agent (in this example, agent 7):
\# Get the wealth of agent 7 over time
one\_agent\_wealth \= agent\_wealth.xs(7, level\="AgentID")
\# Plot the wealth of agent 7 over time
g \= sns.lineplot(data\=one\_agent\_wealth, x\="Step", y\="Wealth")
g.set(title\="Wealth of agent 7 over time");

You can also plot a reporter of multiple agents over time.
agent\_list \= \[3, 14, 25\]
\# Get the wealth of multiple agents over time
multiple\_agents\_wealth \= agent\_wealth\[\
agent\_wealth.index.get\_level\_values("AgentID").isin(agent\_list)\
\]
\# Plot the wealth of multiple agents over time
g \= sns.lineplot(data\=multiple\_agents\_wealth, x\="Step", y\="Wealth", hue\="AgentID")
g.set(title\="Wealth of agents 3, 14 and 25 over time");

We can also plot the average of all agents, with a 95% confidence interval for that average.
\# Transform the data to a long format
agent\_wealth\_long \= agent\_wealth.T.unstack().reset\_index()
agent\_wealth\_long.columns \= \["Step", "AgentID", "Variable", "Value"\]
agent\_wealth\_long.head(3)
\# Plot the average wealth over time
g \= sns.lineplot(data\=agent\_wealth\_long, x\="Step", y\="Value", errorbar\=("ci", 95))
g.set(title\="Average wealth over time")
\[Text(0.5, 1.0, 'Average wealth over time')\]

Which is exactly 1, as expected in this model, since each agent starts with one wealth unit, and each agent gives one wealth unit to another agent at each step.
You can also use pandas to export the data to a CSV (comma separated value) file, which can be opened by any common spreadsheet application or opened by pandas.
If you do not specify a file path, the file will be saved in the local directory. After you run the code below you will see two files appear (_model\_data.csv_ and _agent\_data.csv_)
\# save the model data (stored in the pandas gini object) to CSV
gini.to\_csv("model\_data.csv")
\# save the agent data (stored in the pandas agent\_wealth object) to CSV
agent\_wealth.to\_csv("agent\_data.csv")
AgentSet Functionality[#](#agentset-functionality "Link to this heading")
--------------------------------------------------------------------------
**Background:** With Mesa’s AgentSet approach users can also [manage agents](https://mesa.readthedocs.io/latest/overview.html#agentset-and-model-agents)
in several ways.
**Model-specific information:** We will show three agent management techniques just to demonstrate the capability
1. **Applying Methods** We will shuffle the agents and move them and then have them exchange money without reordering them
2. **Selecting** We will institute a policy that has the rich agents give money to the poor agents
3. **GroupBy** We will group agents together based on wealth
### Applying Methods[#](#applying-methods "Link to this heading")
**Code Implementation** In this variation we accomplish the same process using the AgentSet features. We remove the step function entirely, shuffle the agent order have them execute the `move` function. Then we have them execute the `give_money` function to get a similar result as we saw in the Adding Space Section.
class MoneyAgent(mesa.Agent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model):
super().\_\_init\_\_(model)
self.wealth \= 1
def move(self):
possible\_steps \= self.model.grid.get\_neighborhood(
self.pos, moore\=True, include\_center\=False
)
new\_position \= self.random.choice(possible\_steps)
self.model.grid.move\_agent(self, new\_position)
def give\_money(self):
if self.wealth \> 0:
cellmates \= self.model.grid.get\_cell\_list\_contents(\[self.pos\])
\# Ensure agent is not giving money to itself
cellmates.pop(cellmates.index(self))
if len(cellmates) \> 0:
other\_agent \= self.random.choice(cellmates)
other\_agent.wealth += 1
self.wealth \-= 1
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n, width, height, seed\=None):
super().\_\_init\_\_(seed\=seed)
self.num\_agents \= n
self.grid \= mesa.space.MultiGrid(width, height, True)
\# Create agents
agents \= MoneyAgent.create\_agents(model\=self, n\=n)
\# Create x and y positions for agents
x \= self.rng.integers(0, self.grid.width, size\=(n,))
y \= self.rng.integers(0, self.grid.height, size\=(n,))
for a, i, j in zip(agents, x, y):
\# Add the agent to a random grid cell
self.grid.place\_agent(a, (i, j))
self.datacollector \= mesa.DataCollector(
model\_reporters\={"Gini": compute\_gini}, agent\_reporters\={"Wealth": "wealth"}
)
def step(self):
self.datacollector.collect(self)
self.agents.shuffle\_do("move")
self.agents.do("give\_money")
Then we set up our model object and run it for 20 steps
model \= MoneyModel(100, 10, 10)
for \_ in range(20):
model.step()
Then we plot our model result on the grid
agent\_counts \= np.zeros((model.grid.width, model.grid.height))
for cell\_content, (x, y) in model.grid.coord\_iter():
agent\_count \= len(cell\_content)
agent\_counts\[x\]\[y\] \= agent\_count
\# Plot using seaborn, with a visual size of 5x5
g \= sns.heatmap(agent\_counts, cmap\="viridis", annot\=True, cbar\=False, square\=True)
g.figure.set\_size\_inches(5, 5)
g.set(title\="Number of agents on each cell of the grid");

### Selecting[#](#selecting "Link to this heading")
**Model-specific Information:** For this variation of the model we are going to institute a policy that rich agents give money to poor agent
**Code Implementation:** We will use `agents.select` to separate the agents into rich and poor agents. If there are rich agents then they are the only ones who give money.
class MoneyAgent(mesa.Agent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model):
super().\_\_init\_\_(model)
self.wealth \= 1
def give\_money(self, poor\_agents):
if self.wealth \> 0:
other\_agent \= self.random.choice(poor\_agents)
other\_agent.wealth += 1
self.wealth \-= 1
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n):
super().\_\_init\_\_()
self.num\_agents \= n
\# Create agents
MoneyAgent.create\_agents(model\=self, n\=n)
self.datacollector \= mesa.DataCollector(
model\_reporters\={"Gini": compute\_gini}, agent\_reporters\={"Wealth": "wealth"}
)
def step(self):
self.datacollector.collect(self)
\# Get lists of rich and poor agents
rich\_agents \= model.agents.select(lambda a: a.wealth \>= 3)
poor\_agents \= model.agents.select(lambda a: a.wealth < 3)
\# When there is rich agents only have them give money to the poor agents
if len(rich\_agents) \> 0:
rich\_agents.shuffle\_do("give\_money", poor\_agents)
else:
poor\_agents.shuffle\_do("give\_money", poor\_agents)
We now run the model, collect the data, and plot the results.
model \= MoneyModel(100)
for \_ in range(20):
model.step()
data \= model.datacollector.get\_agent\_vars\_dataframe()
\# Use seaborn
g \= sns.histplot(data\["Wealth"\], discrete\=True)
g.set(title\="Wealth distribution", xlabel\="Wealth", ylabel\="number of agents");

### Group By[#](#group-by "Link to this heading")
**Model-specific implementation:** In this case we will give agents an attribute of enthnicity of Green, Blue or Mixed. Green and Blue agents only give money to their ethnicity while Mixed can give money to anyone.
**Code Implementation**: Using `groupby` we will execute the above logic in our code by passing a list of grouped agents into our `give_money` function. To ensure we can plot wealth by group we also need to add ethnicity to our datacollector.
class MoneyAgent(mesa.Agent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model, ethnicity):
super().\_\_init\_\_(model)
self.wealth \= 1
self.ethnicity \= ethnicity
def give\_money(self, similars):
if self.wealth \> 0:
other\_agent \= self.random.choice(similars)
other\_agent.wealth += 1
self.wealth \-= 1
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n):
super().\_\_init\_\_()
self.num\_agents \= n
\# Create a list of our different ethnicities
ethnicities \= \["Green", "Blue", "Mixed"\]
\# Create agents
MoneyAgent.create\_agents(model\=self, n\=n, ethnicity\=self.random.choice(ethnicities))
self.datacollector \= mesa.DataCollector(
model\_reporters\={"Gini": compute\_gini},
agent\_reporters\={"Wealth": "wealth", "Ethnicity": "ethnicity"},
)
def step(self):
self.datacollector.collect(self)
\# groupby returns a dictionary of the different ethnicities with a list of agents
grouped\_agents \= model.agents.groupby("ethnicity")
for ethnic, similars in grouped\_agents:
if ethnic != "Mixed":
similars.shuffle\_do("give\_money", similars)
else:
similars.shuffle\_do(
"give\_money", self.agents
) \# This allows mixed to trade with anyone
\# Run the model
model \= MoneyModel(100)
for \_ in range(20):
model.step()
\# get the data
data \= model.datacollector.get\_agent\_vars\_dataframe()
\# assign histogram colors
palette \= {"Green": "green", "Blue": "blue", "Mixed": "purple"}
sns.histplot(data\=data, x\="Wealth", hue\="Ethnicity", discrete\=True, palette\=palette)
g.set(title\="Wealth distribution", xlabel\="Wealth", ylabel\="number of agents");

Batch Run[#](#batch-run "Link to this heading")
------------------------------------------------
Like we mentioned above, you usually won’t run a model only once, but multiple times, with fixed parameters to find the overall distributions the model generates, and with varying parameters to analyze how they drive the model’s outputs and behaviors. This is commonly referred to as parameter sweeps. Instead of needing to write nested for-loops for each model, Mesa provides a [`batch_run`](https://github.com/projectmesa/mesa/blob/main/mesa/batchrunner.py)
function which automates it for you.
The batch runner also requires an additional variable `self.running` for the MoneyModel class. This variable enables conditional shut off of the model once a condition is met. In this example it will be set as True indefinitely.
### Additional agent reporter[#](#additional-agent-reporter "Link to this heading")
To make the results a little bit more interesting, we will also calculate the number of consecutive time steps an agent hasn’t given any wealth as an agent reporter.
This way we can see how data is handled when multiple reporters are used.
def compute\_gini(model):
agent\_wealths \= \[agent.wealth for agent in model.agents\]
x \= sorted(agent\_wealths)
n \= model.num\_agents
B \= sum(xi \* (n \- i) for i, xi in enumerate(x)) / (n \* sum(x))
return 1 + (1 / n) \- 2 \* B
class MoneyModel(mesa.Model):
"""A model with some number of agents."""
def \_\_init\_\_(self, n, width, height, seed\=None):
super().\_\_init\_\_(seed\=seed)
self.num\_agents \= n
self.grid \= mesa.space.MultiGrid(width, height, True)
self.running \= True
\# Create agents
agents \= MoneyAgent.create\_agents(model\=self, n\=n)
\# Create x and y positions for agents
x \= self.rng.integers(0, self.grid.width, size\=(n,))
y \= self.rng.integers(0, self.grid.height, size\=(n,))
for a, i, j in zip(agents, x, y):
\# Add the agent to a random grid cell
self.grid.place\_agent(a, (i, j))
self.datacollector \= mesa.DataCollector(
model\_reporters\={"Gini": compute\_gini},
agent\_reporters\={"Wealth": "wealth", "Steps\_not\_given": "steps\_not\_given"},
)
def step(self):
self.datacollector.collect(self)
self.agents.shuffle\_do("move")
self.agents.shuffle\_do("give\_money")
class MoneyAgent(mesa.Agent):
"""An agent with fixed initial wealth."""
def \_\_init\_\_(self, model):
super().\_\_init\_\_(model)
self.wealth \= 1
self.steps\_not\_given \= 0
def move(self):
possible\_steps \= self.model.grid.get\_neighborhood(
self.pos, moore\=True, include\_center\=False
)
new\_position \= self.random.choice(possible\_steps)
self.model.grid.move\_agent(self, new\_position)
def give\_money(self):
cellmates \= self.model.grid.get\_cell\_list\_contents(\[self.pos\])
cellmates.pop(cellmates.index(self))
if len(cellmates) \> 0 and self.wealth \> 0:
other \= self.random.choice(cellmates)
other.wealth += 1
self.wealth \-= 1
self.steps\_not\_given \= 0
else:
self.steps\_not\_given += 1
### Batch run parameters[#](#batch-run-parameters "Link to this heading")
We call `batch_run` with the following arguments:
* `model_cls` The model class that is used for the batch run.
* `parameters` A dictionary containing all the parameters of the model class and desired values to use for the batch run as key-value pairs. Each value can either be fixed ( e.g. `{"height": 10, "width": 10}`) or an iterable (e.g. `{"n": range(10, 500, 10)}`). `batch_run` will then generate all possible parameter combinations based on this dictionary and run the model `iterations` times for each combination.
* `number_processes` If not specified, defaults to 1. Set it to `None` to use all the available processors. Note: Multiprocessing does make debugging challenging. If your parameter sweeps are resulting in unexpected errors set `number_processes=1`.
* `iterations` The number of iterations to run each parameter combination for. Optional. If not specified, defaults to 1.
* `data_collection_period` The length of the period (number of steps) after which the model and agent reporters collect data. Optional. If not specified, defaults to -1, i.e. only at the end of each episode.
* `max_steps` The maximum number of time steps after which the model halts. An episode does either end when `self.running` of the model class is set to `False` or when `model.steps == max_steps` is reached. Optional. If not specified, defaults to 1000.
* `display_progress` Display the batch run progress. Optional. If not specified, defaults to `True`.
In the following example, we hold the height and width fixed, and vary the number of agents. We tell the batch runner to run 5 instantiations of the model with each number of agents, and to run each for 100 steps.
We want to keep track of
1. the Gini coefficient value at each time step, and
2. the individual agent’s wealth development and steps without giving money.
**Important:** Since for the latter, changes at each time step might be interesting, we set `data_collection_period=1`. By default, it only collects data at the end of each episode.
Note: The total number of runs is 245 (= 49 different populations \* 5 iterations per population). However, the resulting list of dictionaries will be of length 6186250 (= 250 average agents per population \* 49 different populations \* 5 iterations per population \* 101 steps per iteration).
**Note for Windows OS users:** If you are running this tutorial in Jupyter, make sure that you set `number_processes = 1` (single process). If `number_processes` is greater than 1, it is less straightforward to set up. For details on how to use multiprocessing on windows, see [multiprocessing’s programming guidelines](https://docs.python.org/3/library/multiprocessing.html#multiprocessing-programming)
.
params \= {"width": 10, "height": 10, "n": range(5, 100, 5)}
results \= mesa.batch\_run(
MoneyModel,
parameters\=params,
iterations\=5,
max\_steps\=100,
number\_processes\=1,
data\_collection\_period\=1,
display\_progress\=True,
)
To further analyze the return of the `batch_run` function, we convert the list of dictionaries to a Pandas DataFrame and print its keys.
### Batch Run Analysis and Visualization[#](#batch-run-analysis-and-visualization "Link to this heading")
results\_df \= pd.DataFrame(results)
print(results\_df.keys())
Index(\['RunId', 'iteration', 'Step', 'width', 'height', 'n', 'Gini', 'AgentID',\
'Wealth', 'Steps\_not\_given'\],
dtype='object')
First, we want to take a closer look at how the Gini coefficient at the end of each episode changes as we increase the size of the population. For this, we filter our results to only contain the data of one agent (the Gini coefficient will be the same for the entire population at any time) at the 100th step of each episode and then scatter-plot the values for the Gini coefficient over the the number of agents. Notice there are five values for each population size since we set `iterations=5` when calling the batch run.
\# Filter the results to only contain the data of one agent (the Gini coefficient will be the same for the entire population at any time) at the 100th step of each episode
results\_filtered \= results\_df\[(results\_df.AgentID \== 1) & (results\_df.Step \== 100)\]
results\_filtered\[\["iteration", "n", "Gini"\]\].reset\_index(
drop\=True
).head() \# Create a scatter plot
g \= sns.scatterplot(data\=results\_filtered, x\="n", y\="Gini")
g.set(
xlabel\="number of agents",
ylabel\="Gini coefficient",
title\="Gini coefficient vs. number of agents",
);

We can create different kinds of plot from this filtered DataFrame. For example, a point plot with error bars.
\# Create a point plot with error bars
g \= sns.pointplot(data\=results\_filtered, x\="n", y\="Gini", linestyle\="None")
g.figure.set\_size\_inches(8, 4)
g.set(
xlabel\="number of agents",
ylabel\="Gini coefficient",
title\="Gini coefficient vs. number of agents",
);

Secondly, we want to display the agent’s wealth at each time step of one specific episode. To do this, we again filter our large data frame, this time with a fixed number of agents and only for a specific iteration of that population. To print the results, we convert the filtered data frame to a string specifying the desired columns to print.
Pandas has built-in functions to convert to a lot of different data formats. For example, to display as a table in a Jupyter notebook, we can use the `to_html()` function which takes the same arguments as `to_string()` (see commented lines).
\# First, we filter the results
one\_episode\_wealth \= results\_df\[(results\_df.n \== 10) & (results\_df.iteration \== 2)\]
\# Then, print the columns of interest of the filtered data frame
print(
one\_episode\_wealth.to\_string(
index\=False, columns\=\["Step", "AgentID", "Wealth"\], max\_rows\=10
)
)
\# For a prettier display we can also convert the data frame to html, uncomment to test in a Jupyter notebook
\# from IPython.display import display, HTML
\# display(HTML(one\_episode\_wealth.to\_html(index=False, columns=\['Step', 'AgentID', 'Wealth'\], max\_rows=25)))
Step AgentID Wealth
0 NaN NaN
1 1.0 1.0
1 2.0 1.0
1 3.0 1.0
1 4.0 1.0
... ... ...
100 6.0 0.0
100 7.0 1.0
100 8.0 1.0
100 9.0 1.0
100 10.0 2.0
Lastly, we want to take a look at the development of the Gini coefficient over the course of one iteration. Filtering and printing looks almost the same as above, only this time we choose a different episode.
results\_one\_episode \= results\_df\[\
(results\_df.n \== 10) & (results\_df.iteration \== 1) & (results\_df.AgentID \== 1)\
\]
print(results\_one\_episode.to\_string(index\=False, columns\=\["Step", "Gini"\], max\_rows\=10))
Step Gini
1 0.0
2 0.0
3 0.0
4 0.0
5 0.0
... ...
96 0.0
97 0.0
98 0.0
99 0.0
100 0.0
### Analyzing model reporters: Comparing 5 scenarios[#](#analyzing-model-reporters-comparing-5-scenarios "Link to this heading")
Other insights might be gathered when we compare the Gini coefficient of different scenarios. For example, we can compare the Gini coefficient of a population with 25 agents to the Gini coefficient of a population with 400 agents. While doing this, we increase the number of iterations to 25 to get a better estimate of the Gini coefficient for each population size and get usable error estimations.
As we look varying the parameters to see the impact on model outcomes, it is critical to again point out that users can set the random seed. Due to the often inherent randomness with ABMs the seed becomes crucial for:
* **Reproducibility** - Being able to replicate the ABM results
* **Sensitivity Analysis** - Identifying how sensitive/robust your model results are to random fluctuations
Treating the seed as an additional parameter and running numerous scenarios allows us to see the impact of randomness on this model.
params \= {"seed": None, "width": 10, "height": 10, "n": \[5, 10, 20, 40, 80\]}
results\_5s \= mesa.batch\_run(
MoneyModel,
parameters\=params,
iterations\=25,
max\_steps\=100,
number\_processes\=1,
data\_collection\_period\=1, \# Important, otherwise the datacollector will only collect data of the last time step
display\_progress\=True,
)
results\_5s\_df \= pd.DataFrame(results\_5s)
\# Again filter the results to only contain the data of one agent (the Gini coefficient will be the same for the entire population at any time)
results\_5s\_df\_filtered \= results\_5s\_df\[(results\_5s\_df.AgentID \== 1)\]
results\_5s\_df\_filtered.head(3)
| | RunId | iteration | Step | seed | width | height | n | Gini | AgentID | Wealth | Steps\_not\_given |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 1 | 0 | 0 | 1 | None | 10 | 10 | 5 | 0.0 | 1.0 | 1.0 | 0.0 |
| 6 | 0 | 0 | 2 | None | 10 | 10 | 5 | 0.0 | 1.0 | 1.0 | 1.0 |
| 11 | 0 | 0 | 3 | None | 10 | 10 | 5 | 0.0 | 1.0 | 1.0 | 2.0 |
\# Create a lineplot with error bars
g \= sns.lineplot(
data\=results\_5s\_df,
x\="Step",
y\="Gini",
hue\="n",
errorbar\=("ci", 95),
palette\="tab10",
)
g.figure.set\_size\_inches(8, 4)
plot\_title \= "Gini coefficient for different population sizes\\n(mean over 100 runs, with 95% confidence interval)"
g.set(title\=plot\_title, ylabel\="Gini coefficient");

In this case it looks like the Gini coefficient increases slower for smaller populations. This can be because of different things, either because the Gini coefficient is a measure of inequality and the smaller the population, the more likely it is that the agents are all in the same wealth class, or because there are less interactions between agents in smaller populations, which means that the wealth of an agent is less likely to change.
\# Challenge: Treat the seed as a parameter and see the impact on the Gini Coefficient.
\# You can also plot the seeds against the Gini Coefficient by changing the "hue" parameter in sns.lineplot function.
### Analyzing agent reporters: Comparing 5 scenarios[#](#analyzing-agent-reporters-comparing-5-scenarios "Link to this heading")
From the agents we collected the wealth and the number of consecutive rounds without a transaction. We can compare the 5 different population sizes by plotting the average number of consecutive rounds without a transaction for each population size.
Note that we’re aggregating multiple times here: First we take the average of all agents for each single replication. Then we plot the averages for all replications, with the error band showing the 95% confidence interval of that first average (over all agents). So this error band is representing the uncertainty of the mean value of the number of consecutive rounds without a transaction for each population size.
\# Calculate the mean of the wealth and the number of consecutive rounds for all agents in each episode
agg\_results\_df \= (
results\_5s\_df.groupby(\["iteration", "n", "Step"\])
.agg({"Wealth": "mean", "Steps\_not\_given": "mean"})
.reset\_index()
)
agg\_results\_df.head(3)
| | iteration | n | Step | Wealth | Steps\_not\_given |
| --- | --- | --- | --- | --- | --- |
| 0 | 0 | 5 | 0 | NaN | NaN |
| 1 | 0 | 5 | 1 | 1.0 | 0.0 |
| 2 | 0 | 5 | 2 | 1.0 | 1.0 |
\# Create a line plot with error bars
g \= sns.lineplot(
data\=agg\_results\_df, x\="Step", y\="Steps\_not\_given", hue\="n", palette\="tab10"
)
g.figure.set\_size\_inches(8, 4)
g.set(
title\="Average number of consecutive rounds without a transaction for different population sizes\\n(mean with 95% confidence interval)",
ylabel\="Consecutive rounds without a transaction",
);

It can be clearly seen that the lower the number of agents, the higher the number of consecutive rounds without a transaction. This is because the agents have fewer interactions with each other and therefore the wealth of an agent is less likely to change.
### General steps for analyzing results[#](#general-steps-for-analyzing-results "Link to this heading")
Many other analysis are possible based on the policies, scenarios and uncertainties that you might be interested in. In general, you can follow these steps to do your own analysis:
1. Determine which metrics you want to analyse. Add these as model and agent reporters to the datacollector of your model.
2. Determine the input parameters you want to vary. Add these as parameters to the batch\_run function, using ranges or lists to test different values.
3. Determine the hyperparameters of the batch\_run function. Define the number of iterations, the number of processes, the number of steps, the data collection period, etc.
4. Run the batch\_run function and save the results.
5. Transform, filter and aggregate the results to get the data you want to analyze. Make sure it’s in long format, so that each row represents a single value.
6. Choose a plot type, what to plot on the x and y axis, which columns to use for the hue. Seaborn also has an amazing [Example Gallery](https://seaborn.pydata.org/examples/index.html)
.
7. Plot the data and analyze the results.
\# Challenge update the model, conduct a batch run with a parameter sweep, and visualize your results
Next Steps[#](#next-steps "Link to this heading")
--------------------------------------------------
Check out the [visualization tutorial](https://mesa.readthedocs.io/latest/tutorials/visualization_tutorial.html)
on how to build interactive dashboards for your models.
Happy Modeling
-----------------------------------------------------------
This document is a work in progress. If you see any errors, exclusions or have any problems please contact [us](https://github.com/projectmesa/mesa/issues)
.
\[Comer2014\] Comer, Kenneth W. “Who Goes First? An Examination of the Impact of Activation on Outcome Behavior in AgentBased Models.” George Mason University, 2014. http://mars.gmu.edu/bitstream/handle/1920/9070/Comer\_gmu\_0883E\_10539.pdf
\[Dragulescu2002\] Drăgulescu, Adrian A., and Victor M. Yakovenko. “Statistical Mechanics of Money, Income, and Wealth: A Short Survey.” arXiv Preprint Cond-mat/0211175, 2002. http://arxiv.org/abs/cond-mat/0211175.
On this page
### This Page
* [Show Source](../_sources/tutorials/intro_tutorial.ipynb.txt)
---
# Visualization Tutorial — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Visualization Tutorial[#](#visualization-tutorial "Link to this heading")
==========================================================================
_This version of the visualisation tutorial is updated for Mesa 3.1, and works with Mesa `3.1.0` and above._
**Important:**
* If you are just exploring Mesa and want the fastest way to the the dashboard and code checkout [](https://py.cafe/app/tpike3/boltzmann-wealth-model)
(click “Editor” to see the code)
* If you want to see the dashboard in an interactive notebook try [](https://mybinder.org/v2/gh/projectmesa/mesa/main?labpath=docs%2Ftutorials%2Fvisualization_tutorial.ipynb)
* If you have installed mesa and are running locally, please ensure that your [Mesa version](https://pypi.org/project/Mesa/)
is up-to-date in order to run this tutorial.
Adding visualization[#](#adding-visualization "Link to this heading")
----------------------------------------------------------------------
So far, we’ve built a model, run it, and analyzed some output afterwards. However, one of the advantages of agent-based models is that we can often watch them run step by step, potentially spotting unexpected patterns, behaviors or bugs, or developing new intuitions, hypotheses, or insights. Other times, watching a model run can explain it to an unfamiliar audience better than static explanations. Like many ABM frameworks, Mesa allows you to create an interactive visualization of the model. In this section we’ll walk through creating a visualization using built-in components, and (for advanced users) how to create a new visualization element.
First, a quick explanation of how Mesa’s interactive visualization works. The visualization is done in a browser window, using the [Solara](https://solara.dev/)
framework, a pure Python, React-style web framework. Running `solara run app.py` will launch a web server, which runs the model, and displays model detail at each step via the Matplotlib plotting library. Alternatively, you can execute everything inside a notebook environment and display it inline.
### Grid Visualization[#](#grid-visualization "Link to this heading")
To start with, let’s have a visualization where we can watch the agents moving around the grid. Let us use the same `MoneyModel` created in the [Introductory Tutorial](https://mesa.readthedocs.io/stable/tutorials/intro_tutorial.html)
.
Mesa’s grid visualizer works by looping over every cell in a grid, and generating a portrayal for every agent it finds. A portrayal is a dictionary (which can easily be turned into a JSON object) which tells Matplotlib the color and size of the scatterplot markers (each signifying an agent). The only thing we need to provide is a function which takes an agent, and returns a portrayal dictionary. Here’s the simplest one: it’ll draw each agent as a blue, filled circle, with a radius size of 50.
Part 1 - Basic Dashboard[#](#part-1-basic-dashboard "Link to this heading")
----------------------------------------------------------------------------
**Note:** Due to the computational cost of running multiple dashboards it is recommended that at the end of each part you restart your kernel and then only run the the cells in that portion of the tutorial (e.g. Part 1). Each portion is entirely self contained.
import mesa
print(f"Mesa version: {mesa.\_\_version\_\_}")
from mesa.visualization import SolaraViz, make\_plot\_component, make\_space\_component
\# Import the local MoneyModel.py
from MoneyModel import MoneyModel
Mesa version: 3.1.5
def agent\_portrayal(agent):
return {
"color": "tab:blue",
"size": 50,
}
In addition to the portrayal method, we instantiate the model parameters, some of which are modifiable by user inputs. In this case, the number of agents, N, is specified as a slider of integers.
model\_params \= {
"n": {
"type": "SliderInt",
"value": 50,
"label": "Number of agents:",
"min": 10,
"max": 100,
"step": 1,
},
"width": 10,
"height": 10,
}
Next, we instantiate the visualization object which (by default) displays the grid containing the agents, and timeseries of values computed by the model’s data collector. In this example, we specify the Gini coefficient.
There are 3 buttons:
* the step button, which advances the model by 1 step
* the play button, which advances the model indefinitely until it is paused, or until `model.running` is False (you may specify the stopping condition)
* the pause button, which pauses the model
To reset the model, simply change the model parameter from the user input (e.g. the “Number of agents” slider).
\# Create initial model instance
money\_model \= MoneyModel(n\=50, width\=10, height\=10) #keyword arguments
SpaceGraph \= make\_space\_component(agent\_portrayal)
GiniPlot \= make\_plot\_component("Gini")
page \= SolaraViz(
money\_model,
components\=\[SpaceGraph, GiniPlot\],
model\_params\=model\_params,
name\="Boltzmann Wealth Model",
)
\# This is required to render the visualization in the Jupyter notebook
page
Part 2 - Dynamic Agent Representation[#](#part-2-dynamic-agent-representation "Link to this heading")
------------------------------------------------------------------------------------------------------
Due to the computational cost of running multiple dashboards it is recommended that at the end of each part you restart your kernel and then only run the import cell and the cells in that portion of the part of the tutorial (e.g. Part 2)
In the visualization above, all we could see is the agents moving around – but not how much money they had, or anything else of interest. Let’s change it so that agents who are broke (wealth 0) are drawn in red, smaller. (TODO: Currently, we can’t predict the drawing order of the circles, so a broke agent may be overshadowed by a wealthy agent. We should fix this by doing a hollow circle instead) In addition to size and color, an agent’s shape can also be customized when using the default drawer. The allowed values for shapes can be found [here](https://matplotlib.org/stable/api/markers_api.html)
.
To do this, we go back to our `agent_portrayal` code and add some code to change the portrayal based on the agent properties and launch the server again.
import mesa
print(f"Mesa version: {mesa.\_\_version\_\_}")
from mesa.visualization import SolaraViz, make\_plot\_component, make\_space\_component
\# Import the local MoneyModel.py
from MoneyModel import MoneyModel
Mesa version: 3.1.5
def agent\_portrayal(agent):
size \= 10
color \= "tab:red"
if agent.wealth \> 0:
size \= 50
color \= "tab:blue"
return {"size": size, "color": color}
model\_params \= {
"n": {
"type": "SliderInt",
"value": 50,
"label": "Number of agents:",
"min": 10,
"max": 100,
"step": 1,
},
"width": 10,
"height": 10,
}
\# Create initial model instance
money\_model \= MoneyModel(n\=50, width\=10, height\=10)
SpaceGraph \= make\_space\_component(agent\_portrayal)
GiniPlot \= make\_plot\_component("Gini")
page \= SolaraViz(
money\_model,
components\=\[SpaceGraph, GiniPlot\],
model\_params\=model\_params,
name\="Boltzmann Wealth Model",
)
\# This is required to render the visualization in the Jupyter notebook
page
Part 3 - Custom Components[#](#part-3-custom-components "Link to this heading")
--------------------------------------------------------------------------------
Due to the computational cost of running multiple dashboards it is recommended that at the end of each part you restart your kernel and then only run the import cell and the cells in that portion of the part of the tutorial (e.g. Part 3)
**Note:** This section is for users who have a basic familiarity with Python’s Matplotlib plotting library.
If the visualization elements provided by Mesa aren’t enough for you, you can build your own and plug them into the model server.
For this example, let’s build a simple histogram visualization, which can count the number of agents with each value of wealth.
**Note:** Due to the way solara works we need to trigger an update whenever the underlying model changes. For this you need to register an update counter with every component.
import mesa
print(f"Mesa version: {mesa.\_\_version\_\_}")
import solara
from matplotlib.figure import Figure
from mesa.visualization.utils import update\_counter
from mesa.visualization import SolaraViz, make\_plot\_component, make\_space\_component
\# Import the local MoneyModel.py
from MoneyModel import MoneyModel
Mesa version: 3.1.5
def agent\_portrayal(agent):
size \= 10
color \= "tab:red"
if agent.wealth \> 0:
size \= 50
color \= "tab:blue"
return {"size": size, "color": color}
model\_params \= {
"n": {
"type": "SliderInt",
"value": 50,
"label": "Number of agents:",
"min": 10,
"max": 100,
"step": 1,
},
"width": 10,
"height": 10,
}
Next, we update our solara frontend to use this new component
@solara.component
def Histogram(model):
update\_counter.get() \# This is required to update the counter
\# Note: you must initialize a figure using this method instead of
\# plt.figure(), for thread safety purpose
fig \= Figure()
ax \= fig.subplots()
wealth\_vals \= \[agent.wealth for agent in model.agents\]
\# Note: you have to use Matplotlib's OOP API instead of plt.hist
\# because plt.hist is not thread-safe.
ax.hist(wealth\_vals, bins\=10)
solara.FigureMatplotlib(fig)
\# Create initial model instance
money\_model \= MoneyModel(n\=50, width\=10, height\=10)
SpaceGraph \= make\_space\_component(agent\_portrayal)
GiniPlot \= make\_plot\_component("Gini")
page \= SolaraViz(
money\_model,
components\=\[SpaceGraph, GiniPlot, Histogram\],
model\_params\=model\_params,
name\="Boltzmann Wealth Model",
)
\# This is required to render the visualization in the Jupyter notebook
page
You can even run the visuals independently by calling it with the model instance
Histogram(money\_model)
### Happy Modeling
This document is a work in progress. If you see any errors, exclusions or have any problems please contact [us](https://github.com/projectmesa/mesa/issues)
.
On this page
### This Page
* [Show Source](../_sources/tutorials/visualization_tutorial.ipynb.txt)
---
# Sugarscape Constant Growback Model with Traders — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Sugarscape Constant Growback Model with Traders[#](#sugarscape-constant-growback-model-with-traders "Link to this heading")
============================================================================================================================
Summary[#](#summary "Link to this heading")
--------------------------------------------
This is Epstein & Axtell’s Sugarscape model with Traders, a detailed description is in Chapter four of _Growing Artificial Societies: Social Science from the Bottom Up (1996)_. The model shows an emergent price equilibrium can happen via a decentralized dynamics.
This code generally matches the code in the Complexity Explorer Tutorial, but in `.py` instead of `.ipynb` format.
### Agents:[#](#agents "Link to this heading")
* **Resource**: Resource agents grow back at one unit of sugar and spice per time step up to a specified max amount and can be harvested and traded by the trader agents. (if you do the interactive run, the color will be green if the resource agent has a bigger amount of sugar, or yellow if it has a bigger amount of spice)
* **Traders**: Trader agents have the following attributes: (1) metabolism for sugar, (2) metabolism for spice, (3) vision, (4) initial sugar endowment and (5) initial spice endowment. The traverse the landscape harvesting sugar and spice and trading with other agents. If they run out of sugar or spice then they are removed from the model. (red circle if you do the interactive run)
The trader agents traverse the landscape according to rule **M**:
* Look out as far as vision permits in the four principal lattice directions and identify the unoccupied site(s).
* Considering only unoccupied sites find the nearest position that produces the most welfare using the Cobb-Douglas function.
* Move to the new position
* Collect all the resources (sugar and spice) at that location (Epstein and Axtell, 1996, p. 99)
The traders trade according to rule **T**:
* Agents and potential trade partner compute their marginal rates of substitution (MRS), if they are equal _end_.
* Exchange resources, with spice flowing from the agent with the higher MRS to the agent with the lower MRS and sugar flowing the opposite direction.
* The price (p) is calculated by taking the geometric mean of the agents’ MRS.
* If p > 1 then p units of spice are traded for 1 unit of sugar; if p < 1 then 1/p units of sugar for 1 unit of spice
* The trade occurs if it will (a) make both agent better off (increases MRS) and (b) does not cause the agents’ MRS to cross over one another otherwise _end_.
* This process then repeats until an _end_ condition is met. (Epstein and Axtell, 1996, p. 105)
The model demonstrates several Mesa concepts and features:
* OrthogonalMooreGrid
* Multiple agent types (traders, sugar, spice)
* Dynamically removing agents from the grid and schedule when they die
* Data Collection at the model and agent level
* custom solara matplotlib space visualization
How to Run[#](#how-to-run "Link to this heading")
--------------------------------------------------
To run the model interactively:
$ solara run app.py
Then open your browser to [http://127.0.0.1:8521/](http://127.0.0.1:8521/)
and press Reset, then Run.
Files[#](#files "Link to this heading")
----------------------------------------
* `model.py`: The Sugarscape Constant Growback with Traders model.
* `agents.py`: Defines the Trader agent class and the Resource agent class which contains an amount of sugar and spice.
* `app.py`: Runs a visualization server via Solara (`solara run app.py`).
* `sugar_map.txt`: Provides sugar and spice landscape in raster type format.
* `tests.py`: Has tests to ensure that the model reproduces the results in shown in Growing Artificial Societies.
Additional Resources[#](#additional-resources "Link to this heading")
----------------------------------------------------------------------
* [Growing Artificial Societies](https://mitpress.mit.edu/9780262550253/growing-artificial-societies/)
* [Complexity Explorer Sugarscape with Traders Tutorial](https://www.complexityexplorer.org/courses/172-agent-based-models-with-python-an-introduction-to-mesa)
Agents[#](#id1 "Link to this heading")
---------------------------------------
import math
from mesa.experimental.cell\_space import CellAgent
\# Helper function
def get\_distance(cell\_1, cell\_2):
"""
Calculate the Euclidean distance between two positions
used in trade.move()
"""
x1, y1 \= cell\_1.coordinate
x2, y2 \= cell\_2.coordinate
dx \= x1 \- x2
dy \= y1 \- y2
return math.sqrt(dx\*\*2 + dy\*\*2)
class Trader(CellAgent):
"""
Trader:
- has a metabolism of sugar and spice
- harvest and trade sugar and spice to survive
"""
def \_\_init\_\_(
self,
model,
cell,
sugar\=0,
spice\=0,
metabolism\_sugar\=0,
metabolism\_spice\=0,
vision\=0,
):
super().\_\_init\_\_(model)
self.cell \= cell
self.sugar \= sugar
self.spice \= spice
self.metabolism\_sugar \= metabolism\_sugar
self.metabolism\_spice \= metabolism\_spice
self.vision \= vision
self.prices \= \[\]
self.trade\_partners \= \[\]
def get\_trader(self, cell):
"""
helper function used in self.trade\_with\_neighbors()
"""
for agent in cell.agents:
if isinstance(agent, Trader):
return agent
def calculate\_welfare(self, sugar, spice):
"""
helper function
part 2 self.move()
self.trade()
"""
\# calculate total resources
m\_total \= self.metabolism\_sugar + self.metabolism\_spice
\# Cobb-Douglas functional form; starting on p. 97
\# on Growing Artificial Societies
return sugar \*\* (self.metabolism\_sugar / m\_total) \* spice \*\* (
self.metabolism\_spice / m\_total
)
def is\_starved(self):
"""
Helper function for self.maybe\_die()
"""
return (self.sugar <= 0) or (self.spice <= 0)
def calculate\_MRS(self, sugar, spice):
"""
Helper function for
- self.trade()
- self.maybe\_self\_spice()
Determines what trader agent needs and can give up
"""
return (spice / self.metabolism\_spice) / (sugar / self.metabolism\_sugar)
def calculate\_sell\_spice\_amount(self, price):
"""
helper function for self.maybe\_sell\_spice() which is called from
self.trade()
"""
if price \>= 1:
sugar \= 1
spice \= int(price)
else:
sugar \= int(1 / price)
spice \= 1
return sugar, spice
def sell\_spice(self, other, sugar, spice):
"""
used in self.maybe\_sell\_spice()
exchanges sugar and spice between traders
"""
self.sugar += sugar
other.sugar \-= sugar
self.spice \-= spice
other.spice += spice
def maybe\_sell\_spice(self, other, price, welfare\_self, welfare\_other):
"""
helper function for self.trade()
"""
sugar\_exchanged, spice\_exchanged \= self.calculate\_sell\_spice\_amount(price)
\# Assess new sugar and spice amount - what if change did occur
self\_sugar \= self.sugar + sugar\_exchanged
other\_sugar \= other.sugar \- sugar\_exchanged
self\_spice \= self.spice \- spice\_exchanged
other\_spice \= other.spice + spice\_exchanged
\# double check to ensure agents have resources
if (
(self\_sugar <= 0)
or (other\_sugar <= 0)
or (self\_spice <= 0)
or (other\_spice <= 0)
):
return False
\# trade criteria #1 - are both agents better off?
both\_agents\_better\_off \= (
welfare\_self < self.calculate\_welfare(self\_sugar, self\_spice)
) and (welfare\_other < other.calculate\_welfare(other\_sugar, other\_spice))
\# trade criteria #2 is their mrs crossing with potential trade
mrs\_not\_crossing \= self.calculate\_MRS(
self\_sugar, self\_spice
) \> other.calculate\_MRS(other\_sugar, other\_spice)
if not (both\_agents\_better\_off and mrs\_not\_crossing):
return False
\# criteria met, execute trade
self.sell\_spice(other, sugar\_exchanged, spice\_exchanged)
return True
def trade(self, other):
"""
helper function used in trade\_with\_neighbors()
other is a trader agent object
"""
\# sanity check to verify code is working as expected
assert self.sugar \> 0
assert self.spice \> 0
assert other.sugar \> 0
assert other.spice \> 0
\# calculate marginal rate of substitution in Growing Artificial Societies p. 101
mrs\_self \= self.calculate\_MRS(self.sugar, self.spice)
mrs\_other \= other.calculate\_MRS(other.sugar, other.spice)
\# calculate each agents welfare
welfare\_self \= self.calculate\_welfare(self.sugar, self.spice)
welfare\_other \= other.calculate\_welfare(other.sugar, other.spice)
if math.isclose(mrs\_self, mrs\_other):
return
\# calculate price
price \= math.sqrt(mrs\_self \* mrs\_other)
if mrs\_self \> mrs\_other:
\# self is a sugar buyer, spice seller
sold \= self.maybe\_sell\_spice(other, price, welfare\_self, welfare\_other)
\# no trade - criteria not met
if not sold:
return
else:
\# self is a spice buyer, sugar seller
sold \= other.maybe\_sell\_spice(self, price, welfare\_other, welfare\_self)
\# no trade - criteria not met
if not sold:
return
\# Capture data
self.prices.append(price)
self.trade\_partners.append(other.unique\_id)
\# continue trading
self.trade(other)
######################################################################
\# #
\# MAIN TRADE FUNCTIONS #
\# #
######################################################################
def move(self):
"""
Function for trader agent to identify optimal move for each step in 4 parts
1 - identify all possible moves
2 - determine which move maximizes welfare
3 - find closest best option
4 - move
"""
\# 1. identify all possible moves
neighboring\_cells \= \[\
cell\
for cell in self.cell.get\_neighborhood(self.vision, include\_center\=True)\
if cell.is\_empty\
\]
\# 2. determine which move maximizes welfare
welfares \= \[\
self.calculate\_welfare(\
self.sugar + cell.sugar,\
self.spice + cell.spice,\
)\
for cell in neighboring\_cells\
\]
\# 3. Find closest best option
\# find the highest welfare in welfares
max\_welfare \= max(welfares)
\# get the index of max welfare cells
\# fixme: rewrite using enumerate and single loop
candidate\_indices \= \[\
i for i in range(len(welfares)) if math.isclose(welfares\[i\], max\_welfare)\
\]
\# convert index to positions of those cells
candidates \= \[neighboring\_cells\[i\] for i in candidate\_indices\]
min\_dist \= min(get\_distance(self.cell, cell) for cell in candidates)
final\_candidates \= \[\
cell\
for cell in candidates\
if math.isclose(get\_distance(self.cell, cell), min\_dist, rel\_tol\=1e-02)\
\]
\# 4. Move Agent
self.cell \= self.random.choice(final\_candidates)
def eat(self):
self.sugar += self.cell.sugar
self.cell.sugar \= 0
self.sugar \-= self.metabolism\_sugar
self.spice += self.cell.spice
self.cell.spice \= 0
self.spice \-= self.metabolism\_spice
def maybe\_die(self):
"""
Function to remove Traders who have consumed all their sugar or spice
"""
if self.is\_starved():
self.remove()
def trade\_with\_neighbors(self):
"""
Function for trader agents to decide who to trade with in three parts
1- identify neighbors who can trade
2- trade (2 sessions)
3- collect data
"""
\# iterate through traders in neighboring cells and trade
for a in self.cell.get\_neighborhood(radius\=self.vision).agents:
self.trade(a)
return
Model[#](#model "Link to this heading")
----------------------------------------
from pathlib import Path
import numpy as np
import mesa
from mesa.examples.advanced.sugarscape\_g1mt.agents import Trader
from mesa.experimental.cell\_space import OrthogonalVonNeumannGrid
from mesa.experimental.cell\_space.property\_layer import PropertyLayer
\# Helper Functions
def flatten(list\_of\_lists):
"""
helper function for model datacollector for trade price
collapses agent price list into one list
"""
return \[item for sublist in list\_of\_lists for item in sublist\]
def geometric\_mean(list\_of\_prices):
"""
find the geometric mean of a list of prices
"""
return np.exp(np.log(list\_of\_prices).mean())
def get\_trade(agent):
"""
For agent reporters in data collector
return list of trade partners and None for other agents
"""
if isinstance(agent, Trader):
return agent.trade\_partners
else:
return None
class SugarscapeG1mt(mesa.Model):
"""
Manager class to run Sugarscape with Traders
"""
def \_\_init\_\_(
self,
width\=50,
height\=50,
initial\_population\=200,
endowment\_min\=25,
endowment\_max\=50,
metabolism\_min\=1,
metabolism\_max\=5,
vision\_min\=1,
vision\_max\=5,
enable\_trade\=True,
seed\=None,
):
super().\_\_init\_\_(seed\=seed)
\# Initiate width and height of sugarscape
self.width \= width
self.height \= height
\# Initiate population attributes
self.enable\_trade \= enable\_trade
self.running \= True
\# initiate mesa grid class
self.grid \= OrthogonalVonNeumannGrid(
(self.width, self.height), torus\=False, random\=self.random
)
\# initiate datacollector
self.datacollector \= mesa.DataCollector(
model\_reporters\={
"#Traders": lambda m: len(m.agents),
"Trade Volume": lambda m: sum(len(a.trade\_partners) for a in m.agents),
"Price": lambda m: geometric\_mean(
flatten(\[a.prices for a in m.agents\])
),
},
agent\_reporters\={"Trade Network": lambda a: get\_trade(a)},
)
\# read in landscape file from supplementary material
self.sugar\_distribution \= np.genfromtxt(Path(\_\_file\_\_).parent / "sugar-map.txt")
self.spice\_distribution \= np.flip(self.sugar\_distribution, 1)
self.grid.add\_property\_layer(
PropertyLayer.from\_data("sugar", self.sugar\_distribution)
)
self.grid.add\_property\_layer(
PropertyLayer.from\_data("spice", self.spice\_distribution)
)
Trader.create\_agents(
self,
initial\_population,
self.random.choices(self.grid.all\_cells.cells, k\=initial\_population),
sugar\=self.rng.integers(
endowment\_min, endowment\_max, (initial\_population,), endpoint\=True
),
spice\=self.rng.integers(
endowment\_min, endowment\_max, (initial\_population,), endpoint\=True
),
metabolism\_sugar\=self.rng.integers(
metabolism\_min, metabolism\_max, (initial\_population,), endpoint\=True
),
metabolism\_spice\=self.rng.integers(
metabolism\_min, metabolism\_max, (initial\_population,), endpoint\=True
),
vision\=self.rng.integers(
vision\_min, vision\_max, (initial\_population,), endpoint\=True
),
)
def step(self):
"""
Unique step function that does staged activation of sugar and spice
and then randomly activates traders
"""
\# step Resource agents
self.grid.sugar.data \= np.minimum(
self.grid.sugar.data + 1, self.sugar\_distribution
)
self.grid.spice.data \= np.minimum(
self.grid.spice.data + 1, self.spice\_distribution
)
\# step trader agents
\# to account for agent death and removal we need a separate data structure to
\# iterate
trader\_shuffle \= self.agents\_by\_type\[Trader\].shuffle()
for agent in trader\_shuffle:
agent.prices \= \[\]
agent.trade\_partners \= \[\]
agent.move()
agent.eat()
agent.maybe\_die()
if not self.enable\_trade:
\# If trade is not enabled, return early
self.datacollector.collect(self)
return
trader\_shuffle \= self.agents\_by\_type\[Trader\].shuffle()
for agent in trader\_shuffle:
agent.trade\_with\_neighbors()
\# collect model level data
\# fixme we can already collect agent class data
\# fixme, we don't have resource agents anymore so this can be done simpler
self.datacollector.collect(self)
"""
Mesa is working on updating datacollector agent reporter
so it can collect information on specific agents from
mesa.time.RandomActivationByType.
Please see issue #1419 at
https://github.com/projectmesa/mesa/issues/1419
(contributions welcome)
Below is one way to update agent\_records to get specific Trader agent data
"""
\# Need to remove excess data
\# Create local variable to store trade data
agent\_trades \= self.datacollector.\_agent\_records\[self.steps\]
\# Get rid of all None to reduce data storage needs
agent\_trades \= \[agent for agent in agent\_trades if agent\[2\] is not None\]
\# Reassign the dictionary value with lean trade data
self.datacollector.\_agent\_records\[self.steps\] \= agent\_trades
def run\_model(self, step\_count\=1000):
for \_ in range(step\_count):
self.step()
App[#](#app "Link to this heading")
------------------------------------
from mesa.examples.advanced.sugarscape\_g1mt.model import SugarscapeG1mt
from mesa.visualization import Slider, SolaraViz, make\_plot\_component
from mesa.visualization.components.matplotlib\_components import make\_mpl\_space\_component
def agent\_portrayal(agent):
return {"marker": "o", "color": "red", "size": 10}
propertylayer\_portrayal \= {
"sugar": {"color": "blue", "alpha": 0.8, "colorbar": True, "vmin": 0, "vmax": 10},
"spice": {"color": "red", "alpha": 0.8, "colorbar": True, "vmin": 0, "vmax": 10},
}
sugarscape\_space \= make\_mpl\_space\_component(
agent\_portrayal\=agent\_portrayal,
propertylayer\_portrayal\=propertylayer\_portrayal,
post\_process\=None,
draw\_grid\=False,
)
model\_params \= {
"seed": {
"type": "InputText",
"value": 42,
"label": "Random Seed",
},
"width": 50,
"height": 50,
\# Population parameters
"initial\_population": Slider(
"Initial Population", value\=200, min\=50, max\=500, step\=10
),
\# Agent endowment parameters
"endowment\_min": Slider("Min Initial Endowment", value\=25, min\=5, max\=30, step\=1),
"endowment\_max": Slider("Max Initial Endowment", value\=50, min\=30, max\=100, step\=1),
\# Metabolism parameters
"metabolism\_min": Slider("Min Metabolism", value\=1, min\=1, max\=3, step\=1),
"metabolism\_max": Slider("Max Metabolism", value\=5, min\=3, max\=8, step\=1),
\# Vision parameters
"vision\_min": Slider("Min Vision", value\=1, min\=1, max\=3, step\=1),
"vision\_max": Slider("Max Vision", value\=5, min\=3, max\=8, step\=1),
\# Trade parameter
"enable\_trade": {"type": "Checkbox", "value": True, "label": "Enable Trading"},
}
model \= SugarscapeG1mt()
page \= SolaraViz(
model,
components\=\[\
sugarscape\_space,\
make\_plot\_component("#Traders"),\
make\_plot\_component("Price"),\
\],
model\_params\=model\_params,
name\="Sugarscape {G1, M, T}",
play\_interval\=150,
)
page \# noqa
On this page
### This Page
* [Show Source](../../_sources/examples/advanced/sugarscape_g1mt.md.txt)
---
# Best Practices — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Best Practices[#](#best-practices "Link to this heading")
==========================================================
Here are some general principles that have proven helpful for developing models.
Model Layout[#](#model-layout "Link to this heading")
------------------------------------------------------
A model should be contained in a folder named with lower-case letters and underscores, such as `wolf_sheep`. Within that directory:
* `Readme.md` describes the model, how to use it, and any other details.
* `model.py` should contain the model class.
* `agents.py` should contain the agent class(es).
* `app.py` should contain the Solara-based visualization code (optional).
You can add more files as needed, for example:
* `run.py` could contain the code to run the model.
* `batch_run.py` could contain the code to run the model multiple times.
* `analysis.py` could contain any analysis code.
Input data can be stored in a `data` directory, output data in an `output`, processed results in a `results` directory, images in an `images` directory, etc.
All our [examples](examples.html)
follow this layout.
Randomization[#](#randomization "Link to this heading")
--------------------------------------------------------
If your model involves some random choice, you can use the built-in `random` property that many Mesa objects have, including `Model`, `Agent`, and `AgentSet`. This works exactly like the built-in `random` library.
class AwesomeModel(Model):
\# ...
def cool\_method(self):
interesting\_number \= self.random.random()
print(interesting\_number)
class AwesomeAgent(Agent):
\# ...
def \_\_init\_\_(self, unique\_id, model, ...):
super().\_\_init\_\_(unique\_id, model)
\# ...
def my\_method(self):
random\_number \= self.random.randint(0, 100)
`Agent.random` is just a convenient shorthand in the Agent class to `self.model.random`. If you create your own `AgentSet` instances, you have to pass `random` explicitly. Typically, you can simply do, in a Model instance, `my_agentset = AgentSet([], random=self.random)`. This ensures that `my_agentset` uses the same random number generator as the rest of the model.
When a model object is created, its random property is automatically seeded with the current time. The seed determines the sequence of random numbers; if you instantiate a model with the same seed, you will get the same results. To allow you to set the seed, make sure your model has a `seed` argument in its `__init__`.
class AwesomeModel(Model):
def \_\_init\_\_(self, seed\=None):
super().\_\_init\_\_(seed\=seed)
...
def cool\_method(self):
interesting\_number \= self.random.random()
print(interesting\_number)
\>>> model0 \= AwesomeModel(seed\=0)
\>>> model0.\_seed
0
\>>> model0.cool\_method()
0.8444218515250481
\>>> model1 \= AwesomeModel(seed\=0)
\>>> model1.cool\_method()
0.8444218515250481
On this page
### This Page
* [Show Source](_sources/best-practices.md.txt)
---
# Unknown
\# Getting started Mesa is a modular framework for building, analyzing and visualizing agent-based models. \*\*Agent-based models\*\* are computer simulations involving multiple entities (the agents) acting and interacting with one another based on their programmed behavior. Agents can be used to represent living cells, animals, individual humans, even entire organizations or abstract entities. Sometimes, we may have an understanding of how the individual components of a system behave, and want to see what system-level behaviors and effects emerge from their interaction. Other times, we may have a good idea of how the system overall behaves, and want to figure out what individual behaviors explain it. Or we may want to see how to get agents to cooperate or compete most effectively. Or we may just want to build a cool toy with colorful little dots moving around. ## Tutorials If you want to get a quick start on how to build agent based models with MESA, check the overview and tutorials: - \[Overview of the MESA library\](overview): Learn about the core concepts and components of Mesa. - \[Introductory Tutorial\](tutorials/intro\_tutorial): Learn how to create your first Mesa model. - \[Visualization Tutorial\](tutorials/visualization\_tutorial): Learn how to create interactive visualizations for your models. ## Examples Mesa ships with a collection of example models. These are classic ABMs, so if you are familiar with ABMs and want to get a quick sense of how MESA works, these examples are great place to start. You can find them \[here\](examples). ## Further resources To further explore Mesa and its features, we have the following resources available: ### Best practices - \[Mesa best practices\](best-practices): an overview of tips and guidelines for using MESA. ### API documentation - \[Mesa API reference\](apis): Detailed documentation of Mesa's classes and functions. ### Repository of models built using MESA - \[Mesa Examples repository\](https://github.com/projectmesa/mesa-examples): A collection of example models demonstrating various Mesa features and modeling techniques. ### Migration guide - \[Mesa 3.0 Migration guide\](migration\_guide): If you're upgrading from an earlier version of Mesa, this guide will help you navigate the changes in Mesa 3.0. ### Source Ccode and development - \[Mesa GitHub repository\](https://github.com/projectmesa/mesa): Access the full source code of Mesa, contribute to its development, or report issues. - \[Mesa release notes\](https://github.com/projectmesa/mesa/releases): View the detailed changelog of Mesa, including all past releases and their features. ### Community and support - \[Mesa GitHub Discussions\](https://github.com/projectmesa/mesa/discussions): Join discussions, ask questions, and connect with other Mesa users. - \[Matrix Chat\](https://matrix.to/#/#project-mesa:matrix.org): Real-time chat for quick questions and community interaction. Enjoy modelling with Mesa, and feel free to reach out! \`\`\`{toctree} :hidden: true :maxdepth: 7 tutorials/intro\_tutorial tutorials/visualization\_tutorial Best Practices \`\`\`
---
# Model — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Model[#](#module-mesa.model "Link to this heading")
====================================================
The model class for Mesa framework.
Core Objects: Model
_class_ Model(_\*args: [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")
_, _seed: [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _rng: Generator | BitGenerator | [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| integer | [Sequence](https://docs.python.org/3/library/collections.abc.html#collections.abc.Sequence "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\] | SeedSequence | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _\*\*kwargs: [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")
_)[\[source\]](../_modules/mesa/model.html#Model)
[#](#mesa.model.Model "Link to this definition")
Base class for models in the Mesa ABM library.
This class serves as a foundational structure for creating agent-based models. It includes the basic attributes and methods necessary for initializing and running a simulation model.
running[#](#mesa.model.Model.running "Link to this definition")
A boolean indicating if the model should continue running.
steps[#](#mesa.model.Model.steps "Link to this definition")
the number of times model.step() has been called.
random[#](#mesa.model.Model.random "Link to this definition")
a seeded python.random number generator.
rng[#](#mesa.model.Model.rng "Link to this definition")
a seeded numpy.random.Generator
Notes
Model.agents returns the AgentSet containing all agents registered with the model. Changing the content of the AgentSet directly can result in strange behavior. If you want change the composition of this AgentSet, ensure you operate on a copy.
Create a new model.
Overload this method with the actual code to initialize the model. Always start with super().\_\_init\_\_() to initialize the model object properly.
Parameters:
* **args** – arguments to pass onto super
* **seed** – the seed for the random number generator
* **rng** – Pseudorandom number generator state. When rng is None, a new numpy.random.Generator is created using entropy from the operating system. Types other than numpy.random.Generator are passed to numpy.random.default\_rng to instantiate a Generator.
* **kwargs** – keyword arguments to pass onto super
Notes
you have to pass either seed or rng, but not both.
_property_ agents_: [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
_[#](#mesa.model.Model.agents "Link to this definition")
Provides an AgentSet of all agents in the model, combining agents from all types.
_property_ agent\_types_: [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[type](https://docs.python.org/3/library/functions.html#type "(in Python v3.13)")\
\]_[#](#mesa.model.Model.agent_types "Link to this definition")
Return a list of all unique agent types registered with the model.
_property_ agents\_by\_type_: [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[[type](https://docs.python.org/3/library/functions.html#type "(in Python v3.13)")\
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\], [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")\
\]_[#](#mesa.model.Model.agents_by_type "Link to this definition")
A dictionary where the keys are agent types and the values are the corresponding AgentSets.
register\_agent(_agent_)[\[source\]](../_modules/mesa/model.html#Model.register_agent)
[#](#mesa.model.Model.register_agent "Link to this definition")
Register the agent with the model.
Parameters:
**agent** – The agent to register.
Notes
This method is called automatically by `Agent.__init__`, so there is no need to use this if you are subclassing Agent and calling its super in the `__init__` method.
deregister\_agent(_agent_)[\[source\]](../_modules/mesa/model.html#Model.deregister_agent)
[#](#mesa.model.Model.deregister_agent "Link to this definition")
Deregister the agent with the model.
Parameters:
**agent** – The agent to deregister.
Notes
This method is called automatically by `Agent.remove`
run\_model() → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/model.html#Model.run_model)
[#](#mesa.model.Model.run_model "Link to this definition")
Run the model until the end condition is reached.
Overload as needed.
step() → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/model.html#Model.step)
[#](#mesa.model.Model.step "Link to this definition")
A single step. Fill in here.
reset\_randomizer(_seed: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/model.html#Model.reset_randomizer)
[#](#mesa.model.Model.reset_randomizer "Link to this definition")
Reset the model random number generator.
Parameters:
**seed** – A new seed for the RNG; if None, reset using the current seed
reset\_rng(_rng: Generator | BitGenerator | [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| integer | [Sequence](https://docs.python.org/3/library/collections.abc.html#collections.abc.Sequence "(in Python v3.13)")
\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\] | SeedSequence | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_) → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/model.html#Model.reset_rng)
[#](#mesa.model.Model.reset_rng "Link to this definition")
Reset the model random number generator.
Parameters:
**rng** – A new seed for the RNG; if None, reset using the current seed
remove\_all\_agents()[\[source\]](../_modules/mesa/model.html#Model.remove_all_agents)
[#](#mesa.model.Model.remove_all_agents "Link to this definition")
Remove all agents from the model.
Notes
This method calls agent.remove for all agents in the model. If you need to remove agents from e.g., a SingleGrid, you can either explicitly implement your own agent.remove method or clean this up near where you are calling this method.
On this page
### This Page
* [Show Source](../_sources/apis/model.md.txt)
---
# Mesa Extensions Overview — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Mesa Extensions Overview[#](#mesa-extensions-overview "Link to this heading")
==============================================================================
This contains an overview of Mesa Extensions. Mesa’s extensibility is a key feature that allows users to enhance functionality, improve scalability, and foster innovation in agent-based modeling.
Mesa-Geo 🌍[#](#mesa-geo "Link to this heading")
-------------------------------------------------
**Field:** Geographic Information Systems (GIS)
* * *
**Description:** Mesa-Geo is an extension of the Mesa framework designed to facilitate working with geographic data in agent-based modeling. It introduces a **GeoSpace** to host **GeoAgents**, which are enhanced agents that include a `geometry` attribute ([a Shapely object](https://shapely.readthedocs.io/en/latest/manual.html)
) and a `crs` attribute (Coordinate Reference System). These attributes enable the integration of geographic and spatial data into simulations. Geometries can be defined manually using Shapely or imported from various sources, such as vector data files (e.g., shapefiles), GeoJSON objects, or GeoPandas GeoDataFrames.
* * *
**Key Features:**
* **Spatial Reference Systems Support:** Mesa-Geo handles coordinate reference systems (CRS), which is essential for working with geographic data in various projections.
* **Geometric Operations Support:** Mesa-Geo utilizes Shapely, which provides robust tools for creating and manipulating geometric shapes like points, polygons, and lines.
* **Topological Operations Support:** Functions for analyzing spatial relationships between geometries.
* * *
**Author(s):** Wang Boyu
* * *
**Additional Resources:** For more information, visit the official [Mesa-Geo repository](https://github.com/projectmesa/mesa-geo?tab=readme-ov-file)
.
* * *
Mesa Examples 📊[#](#mesa-examples "Link to this heading")
-----------------------------------------------------------
**Description:** Mesa Examples provide a collection of models and use cases demonstrating the features and capabilities of the Mesa framework for agent-based modeling. These examples include core and user-submitted models covering a variety of domains like grid spaces, networks, visualization, and GIS.
* * *
**Key Features:**
* **Core Examples:** Fully tested and updated models included directly with the Mesa framework.
* **User Examples:** Community-contributed models showcasing advanced and diverse use cases.
* **Extensive Coverage:** Examples for grid spaces, GIS integration, networks, visualization, and more.
* **Easy Access:** Available directly from the Mesa package or via installation from the repository.
* * *
**Author(s):** Contributions from the Mesa developer community.
* * *
**Examples Include:**
* **Grid Space:** Models like Bank Reserves, Conway’s Game of Life, and Forest Fire.
* **GIS:** GeoSchelling Models, Urban Growth, and Population Models.
* **Network:** Boltzmann Wealth Model and Ant System for the Traveling Salesman Problem.
* **Visualization:** Charting tools and grid displays.
* * *
**For More Information:** For more Detail, Visit the [Mesa Examples Repository](https://github.com/projectmesa/mesa/tree/main/mesa/examples)
.
* * *
**Mesa-Frames** 🚀[#](#mesa-frames "Link to this heading")
-----------------------------------------------------------
**Description:** Mesa-Frames is an extension of the Mesa framework designed to handle complex simulations with thousands of agents. By utilizing DataFrames (pandas or Polars), it enhances scalability and performance while maintaining a syntax similar to Mesa.
* * *
**Key Features:**
* **Enhanced Performance:** Uses DataFrames for SIMD processing and vectorized functions to speed up simulations.
* **Backend Support:** Supports `pandas` (ease of use) and `Polars` (performance innovations with Rust-based backend).
* **Seamless Integration:** Maintains a similar API and functionality as the base Mesa framework for easier adoption.
* **In-Place Operations:** Functional programming and fast memory-efficient copy methods.
* **Future Plans:** GPU functionality, automatic model vectorization, and backend-independent AgentSet class.
* * *
**Usage:**
* Define agents using `AgentSetPandas` or `AgentSetPolars`.
* Implement models by subclassing `ModelDF`.
* Perform vectorized operations to enhance simulation performance.
* * *
**Author(s):** Developed and maintained by the Mesa development community.
* * *
**License:** Distributed under the MIT License.
* * *
**More Information:** Visit the [GitHub Repository](https://github.com/projectmesa/mesa-frames)
.
* * *
On this page
### This Page
* [Show Source](_sources/mesa_extension.md.txt)
---
# Agent — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Agent[#](#module-mesa.agent "Link to this heading")
====================================================
Agent related classes.
Core Objects: Agent and AgentSet.
_class_ Agent(_model: [Model](../mesa.html#mesa.model.Model "mesa.model.Model")
_, _\*args_, _\*\*kwargs_)[\[source\]](../_modules/mesa/agent.html#Agent)
[#](#mesa.agent.Agent "Link to this definition")
Base class for a model agent in Mesa.
model[#](#mesa.agent.Agent.model "Link to this definition")
A reference to the model instance.
Type:
[Model](../mesa.html#mesa.model.Model "mesa.model.Model")
unique\_id[#](#mesa.agent.Agent.unique_id "Link to this definition")
A unique identifier for this agent.
Type:
[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
pos[#](#mesa.agent.Agent.pos "Link to this definition")
A reference to the position where this agent is located.
Type:
Position
Notes
unique\_id is unique relative to a model instance and starts from 1
Create a new agent.
Parameters:
* **model** ([_Model_](../mesa.html#mesa.model.Model "mesa.model.Model")
) – The model instance in which the agent exists.
* **args** – passed on to super
* **kwargs** – passed on to super
Notes
to make proper use of python’s super, in each class remove the arguments and keyword arguments you need and pass on the rest to super
remove() → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/agent.html#Agent.remove)
[#](#mesa.agent.Agent.remove "Link to this definition")
Remove and delete the agent from the model.
Notes
If you need to do additional cleanup when removing an agent by for example removing it from a space, consider extending this method in your own agent class.
step() → [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
[\[source\]](../_modules/mesa/agent.html#Agent.step)
[#](#mesa.agent.Agent.step "Link to this definition")
A single step of the agent.
_classmethod_ create\_agents(_model: [Model](../mesa.html#mesa.model.Model "mesa.model.Model")
_, _n: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_, _\*args_, _\*\*kwargs_) → [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\][\[source\]](../_modules/mesa/agent.html#Agent.create_agents)
[#](#mesa.agent.Agent.create_agents "Link to this definition")
Create N agents.
Parameters:
* **model** – the model to which the agents belong
* **args** – arguments to pass onto agent instances each arg is either a single object or a sequence of length n
* **n** – the number of agents to create
* **kwargs** – keyword arguments to pass onto agent instances each keyword arg is either a single object or a sequence of length n
Returns:
AgentSet containing the agents created.
_property_ random_: [Random](https://docs.python.org/3/library/random.html#random.Random "(in Python v3.13)")
_[#](#mesa.agent.Agent.random "Link to this definition")
Return a seeded stdlib rng.
_property_ rng_: Generator_[#](#mesa.agent.Agent.rng "Link to this definition")
Return a seeded np.random rng.
_class_ AgentSet(_agents: [Iterable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable "(in Python v3.13)")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\]_, _random: [Random](https://docs.python.org/3/library/random.html#random.Random "(in Python v3.13)")
| [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_)[\[source\]](../_modules/mesa/agent.html#AgentSet)
[#](#mesa.agent.AgentSet "Link to this definition")
A collection class that represents an ordered set of agents within an agent-based model (ABM).
This class extends both MutableSet and Sequence, providing set-like functionality with order preservation and sequence operations.
model[#](#mesa.agent.AgentSet.model "Link to this definition")
The ABM model instance to which this AgentSet belongs.
Type:
[Model](../mesa.html#mesa.model.Model "mesa.model.Model")
Notes
The AgentSet maintains weak references to agents, allowing for efficient management of agent lifecycles without preventing garbage collection. It is associated with a specific model instance, enabling interactions with the model’s environment and other agents.The implementation uses a WeakKeyDictionary to store agents, which means that agents not referenced elsewhere in the program may be automatically removed from the AgentSet.
Notes
A UserWarning is issued if random=None. You can resolve this warning by explicitly passing a random number generator. In most cases, this will be the seeded random number generator in the model. So, you would do random=self.random in a Model or Agent instance.
Initializes the AgentSet with a collection of agents and a reference to the model.
Parameters:
* **agents** (_Iterable__\[_[_Agent_](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
_\]_) – An iterable of Agent objects to be included in the set.
* **random** (_Random_) – the random number generator
select(_filter\_func: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
\[\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\], [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")\
\] | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_, _at\_most: [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
| [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
\= inf_, _inplace: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _agent\_type: [type](https://docs.python.org/3/library/functions.html#type "(in Python v3.13)")
\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\] | [None](https://docs.python.org/3/library/constants.html#None "(in Python v3.13)")
\= None_) → [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
[\[source\]](../_modules/mesa/agent.html#AgentSet.select)
[#](#mesa.agent.AgentSet.select "Link to this definition")
Select a subset of agents from the AgentSet based on a filter function and/or quantity limit.
Parameters:
* **filter\_func** (_Callable__\[__\[_[_Agent_](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
_\]__,_ [_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")\
_\]__,_ _optional_) – A function that takes an Agent and returns True if the agent should be included in the result. Defaults to None, meaning no filtering is applied.
* **at\_most** ([_int_](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")
_|_ [_float_](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")
_,_ _optional_) – The maximum amount of agents to select. Defaults to infinity. - If an integer, at most the first number of matching agents are selected. - If a float between 0 and 1, at most that fraction of original the agents are selected.
* **inplace** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_,_ _optional_) – If True, modifies the current AgentSet; otherwise, returns a new AgentSet. Defaults to False.
* **agent\_type** ([_type_](https://docs.python.org/3/library/functions.html#type "(in Python v3.13)")
_\[_[_Agent_](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
_\]__,_ _optional_) – The class type of the agents to select. Defaults to None, meaning no type filtering is applied.
Returns:
A new AgentSet containing the selected agents, unless inplace is True, in which case the current AgentSet is updated.
Return type:
[AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
Notes
* at\_most just return the first n or fraction of agents. To take a random sample, shuffle() beforehand.
* at\_most is an upper limit. When specifying other criteria, the number of agents returned can be smaller.
shuffle(_inplace: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_) → [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
[\[source\]](../_modules/mesa/agent.html#AgentSet.shuffle)
[#](#mesa.agent.AgentSet.shuffle "Link to this definition")
Randomly shuffle the order of agents in the AgentSet.
Parameters:
**inplace** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_,_ _optional_) – If True, shuffles the agents in the current AgentSet; otherwise, returns a new shuffled AgentSet. Defaults to False.
Returns:
A shuffled AgentSet. Returns the current AgentSet if inplace is True.
Return type:
[AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
Note
Using inplace = True is more performant
sort(_key: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
\[\[[Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
\], [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\] | [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _ascending: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_, _inplace: [bool](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
\= False_) → [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
[\[source\]](../_modules/mesa/agent.html#AgentSet.sort)
[#](#mesa.agent.AgentSet.sort "Link to this definition")
Sort the agents in the AgentSet based on a specified attribute or custom function.
Parameters:
* **key** (_Callable__\[__\[_[_Agent_](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")\
_\]__,_ _Any__\]_ _|_ [_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
) – A function or attribute name based on which the agents are sorted.
* **ascending** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_,_ _optional_) – If True, the agents are sorted in ascending order. Defaults to False.
* **inplace** ([_bool_](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")
_,_ _optional_) – If True, sorts the agents in the current AgentSet; otherwise, returns a new sorted AgentSet. Defaults to False.
Returns:
A sorted AgentSet. Returns the current AgentSet if inplace is True.
Return type:
[AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
do(_method: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
| [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_, _\*args_, _\*\*kwargs_) → [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
[\[source\]](../_modules/mesa/agent.html#AgentSet.do)
[#](#mesa.agent.AgentSet.do "Link to this definition")
Invoke a method or function on each agent in the AgentSet.
Parameters:
* **method** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_,_ _callable_) –
the callable to do on each agent
* in case of str, the name of the method to call on each agent.
* in case of callable, the function to be called with each agent as first argument
* **\*args** – Variable length argument list passed to the callable being called.
* **\*\*kwargs** – Arbitrary keyword arguments passed to the callable being called.
Returns:
The results of the callable calls if return\_results is True, otherwise the AgentSet itself.
Return type:
[AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
| [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[Any\]
shuffle\_do(_method: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
| [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_, _\*args_, _\*\*kwargs_) → [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
[\[source\]](../_modules/mesa/agent.html#AgentSet.shuffle_do)
[#](#mesa.agent.AgentSet.shuffle_do "Link to this definition")
Shuffle the agents in the AgentSet and then invoke a method or function on each agent.
It’s a fast, optimized version of calling shuffle() followed by do().
map(_method: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
| [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_, _\*args_, _\*\*kwargs_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\][\[source\]](../_modules/mesa/agent.html#AgentSet.map)
[#](#mesa.agent.AgentSet.map "Link to this definition")
Invoke a method or function on each agent in the AgentSet and return the results.
Parameters:
* **method** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_,_ _callable_) –
the callable to apply on each agent
* in case of str, the name of the method to call on each agent.
* in case of callable, the function to be called with each agent as first argument
* **\*args** – Variable length argument list passed to the callable being called.
* **\*\*kwargs** – Arbitrary keyword arguments passed to the callable being called.
Returns:
The results of the callable calls
Return type:
[list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[Any\]
agg(_attribute: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _func: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_) → [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")
[\[source\]](../_modules/mesa/agent.html#AgentSet.agg)
[#](#mesa.agent.AgentSet.agg "Link to this definition")
Aggregate an attribute of all agents in the AgentSet using a specified function.
Parameters:
* **attribute** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
) – The name of the attribute to aggregate.
* **func** (_Callable_) – The function to apply to the attribute values (e.g., min, max, sum, np.mean).
Returns:
The result of applying the function to the attribute values. Often a single value.
Return type:
Any
get(_attr\_names: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _handle\_missing: [Literal](https://docs.python.org/3/library/typing.html#typing.Literal "(in Python v3.13)")
\['error', 'default'\] \= 'error'_, _default\_value: [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")
\= None_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\][\[source\]](../_modules/mesa/agent.html#AgentSet.get)
[#](#mesa.agent.AgentSet.get "Link to this definition")
get(_attr\_names: [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
\]_, _handle\_missing: [Literal](https://docs.python.org/3/library/typing.html#typing.Literal "(in Python v3.13)")
\['error', 'default'\] \= 'error'_, _default\_value: [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")
\= None_) → [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[[list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")\
\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\]\]
Retrieve the specified attribute(s) from each agent in the AgentSet.
Parameters:
* **attr\_names** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_|_ [_list_](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
_\[_[_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")\
_\]_) – The name(s) of the attribute(s) to retrieve from each agent.
* **handle\_missing** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_,_ _optional_) – How to handle missing attributes. Can be: - ‘error’ (default): raises an AttributeError if attribute is missing. - ‘default’: returns the specified default\_value.
* **default\_value** (_Any__,_ _optional_) – The default value to return if ‘handle\_missing’ is set to ‘default’ and the agent does not have the attribute.
Returns:
A list with the attribute value for each agent if attr\_names is a str. list\[list\[Any\]\]: A list with a lists of attribute values for each agent if attr\_names is a list of str.
Return type:
[list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")
\[Any\]
Raises:
* [**AttributeError**](https://docs.python.org/3/library/exceptions.html#AttributeError "(in Python v3.13)")
– If ‘handle\_missing’ is ‘error’ and the agent does not have the specified attribute(s).
* [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)")
– If an unknown ‘handle\_missing’ option is provided.
set(_attr\_name: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _value: [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")
_) → [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
[\[source\]](../_modules/mesa/agent.html#AgentSet.set)
[#](#mesa.agent.AgentSet.set "Link to this definition")
Set a specified attribute to a given value for all agents in the AgentSet.
Parameters:
* **attr\_name** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
) – The name of the attribute to set.
* **value** (_Any_) – The value to set the attribute to.
Returns:
The AgentSet instance itself, after setting the attribute.
Return type:
[AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")
add(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_)[\[source\]](../_modules/mesa/agent.html#AgentSet.add)
[#](#mesa.agent.AgentSet.add "Link to this definition")
Add an agent to the AgentSet.
Parameters:
**agent** ([_Agent_](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
) – The agent to add to the set.
Note
This method is an implementation of the abstract method from MutableSet.
discard(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_)[\[source\]](../_modules/mesa/agent.html#AgentSet.discard)
[#](#mesa.agent.AgentSet.discard "Link to this definition")
Remove an agent from the AgentSet if it exists.
This method does not raise an error if the agent is not present.
Parameters:
**agent** ([_Agent_](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
) – The agent to remove from the set.
Note
This method is an implementation of the abstract method from MutableSet.
remove(_agent: [Agent](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
_)[\[source\]](../_modules/mesa/agent.html#AgentSet.remove)
[#](#mesa.agent.AgentSet.remove "Link to this definition")
Remove an agent from the AgentSet.
This method raises an error if the agent is not present.
Parameters:
**agent** ([_Agent_](../mesa.html#mesa.agent.Agent "mesa.agent.Agent")
) – The agent to remove from the set.
Note
This method is an implementation of the abstract method from MutableSet.
groupby(_by: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
| [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _result\_type: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
\= 'agentset'_) → [GroupBy](../mesa.html#mesa.agent.GroupBy "mesa.agent.GroupBy")
[\[source\]](../_modules/mesa/agent.html#AgentSet.groupby)
[#](#mesa.agent.AgentSet.groupby "Link to this definition")
Group agents by the specified attribute or return from the callable.
Parameters:
* **by** (_Callable__,_ [_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
) –
used to determine what to group agents by
* if `by` is a callable, it will be called for each agent and the return is used for grouping
* if `by` is a str, it should refer to an attribute on the agent and the value of this attribute will be used for grouping
* **result\_type** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_,_ _optional_) – The datatype for the resulting groups {“agentset”, “list”}
Returns:
GroupBy
Notes: There might be performance benefits to using result\_type=’list’ if you don’t need the advanced functionality of an AgentSet.
clear()[#](#mesa.agent.AgentSet.clear "Link to this definition")
This is slow (creates N new iterators!) but effective.
count(_value_) → integer \-- return number of occurrences of value[#](#mesa.agent.AgentSet.count "Link to this definition")
index(_value_\[, _start_\[, _stop_\]\]) → integer \-- return first index of value.[#](#mesa.agent.AgentSet.index "Link to this definition")
Raises ValueError if the value is not present.
Supporting start and stop arguments is optional, but recommended.
isdisjoint(_other_)[#](#mesa.agent.AgentSet.isdisjoint "Link to this definition")
Return True if two sets have a null intersection.
pop()[#](#mesa.agent.AgentSet.pop "Link to this definition")
Return the popped value. Raise KeyError if empty.
_class_ GroupBy(_groups: [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
, [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")\
| [AgentSet](../mesa.html#mesa.agent.AgentSet "mesa.agent.AgentSet")\
\]_)[\[source\]](../_modules/mesa/agent.html#GroupBy)
[#](#mesa.agent.GroupBy "Link to this definition")
Helper class for AgentSet.groupby.
groups[#](#mesa.agent.GroupBy.groups "Link to this definition")
A dictionary with the group\_name as key and group as values
Type:
[dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
Initialize a GroupBy instance.
Parameters:
**groups** ([_dict_](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
) – A dictionary with the group\_name as key and group as values
map(_method: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
| [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _\*args_, _\*\*kwargs_) → [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
, [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\][\[source\]](../_modules/mesa/agent.html#GroupBy.map)
[#](#mesa.agent.GroupBy.map "Link to this definition")
Apply the specified callable to each group and return the results.
Parameters:
* **method** (_Callable__,_ [_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
) –
The callable to apply to each group,
* if `method` is a callable, it will be called it will be called with the group as first argument
* if `method` is a str, it should refer to a method on the group
Additional arguments and keyword arguments will be passed on to the callable.
* **args** – arguments to pass to the callable
* **kwargs** – keyword arguments to pass to the callable
Returns:
dict with group\_name as key and the return of the method as value
Notes
this method is useful for methods or functions that do return something. It will break method chaining. For that, use `do` instead.
do(_method: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
| [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _\*args_, _\*\*kwargs_) → [GroupBy](../mesa.html#mesa.agent.GroupBy "mesa.agent.GroupBy")
[\[source\]](../_modules/mesa/agent.html#GroupBy.do)
[#](#mesa.agent.GroupBy.do "Link to this definition")
Apply the specified callable to each group.
Parameters:
* **method** (_Callable__,_ [_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
) –
The callable to apply to each group,
* if `method` is a callable, it will be called it will be called with the group as first argument
* if `method` is a str, it should refer to a method on the group
Additional arguments and keyword arguments will be passed on to the callable.
* **args** – arguments to pass to the callable
* **kwargs** – keyword arguments to pass to the callable
Returns:
the original GroupBy instance
Notes
this method is useful for methods or functions that don’t return anything and/or if you want to chain multiple do calls
count() → [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[[Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
, [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")\
\][\[source\]](../_modules/mesa/agent.html#GroupBy.count)
[#](#mesa.agent.GroupBy.count "Link to this definition")
Return the count of agents in each group.
Returns:
A dictionary mapping group names to the number of agents in each group.
Return type:
[dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
agg(_attr\_name: [str](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
_, _func: [Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable "(in Python v3.13)")
_) → [dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[[Hashable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Hashable "(in Python v3.13)")\
, [Any](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")\
\][\[source\]](../_modules/mesa/agent.html#GroupBy.agg)
[#](#mesa.agent.GroupBy.agg "Link to this definition")
Aggregate the values of a specific attribute across each group using the provided function.
Parameters:
* **attr\_name** ([_str_](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")
) – The name of the attribute to aggregate.
* **func** (_Callable_) – The function to apply (e.g., sum, min, max, mean).
Returns:
A dictionary mapping group names to the result of applying the aggregation function.
Return type:
[dict](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.13)")
\[Hashable, Any\]
On this page
### This Page
* [Show Source](../_sources/apis/agent.md.txt)
---
# Data collection — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Data collection[#](#module-datacollection "Link to this heading")
==================================================================
Mesa Data Collection Module.
DataCollector is meant to provide a simple, standard way to collect data generated by a Mesa model. It collects four types of data: model-level data, agent-level data, agent-type-level data, and tables.
A DataCollector is instantiated with three dictionaries of reporter names and associated variable names or functions for each, one for model-level data, one for agent-level data, and one for agent-type-level data; a fourth dictionary provides table names and columns. Variable names are converted into functions which retrieve attributes of that name.
When the collect() method is called, each model-level function is called, with the model as the argument, and the results associated with the relevant variable. Then the agent-level functions are called on each agent, and the agent-type-level functions are called on each agent of the specified type.
Additionally, other objects can write directly to tables by passing in an appropriate dictionary object for a table row.
The DataCollector then stores the data it collects in dictionaries:
* model\_vars maps each reporter to a list of its values
* tables maps each table to a dictionary, with each column as a key with a list as its value.
* \_agent\_records maps each model step to a list of each agent’s id and its values.
* \_agenttype\_records maps each model step to a dictionary of agent types, each containing a list of each agent’s id and its values.
Finally, DataCollector can create a pandas DataFrame from each collection.
_class_ DataCollector(_model\_reporters\=None_, _agent\_reporters\=None_, _agenttype\_reporters\=None_, _tables\=None_)[\[source\]](../_modules/datacollection.html#DataCollector)
[#](#datacollection.DataCollector "Link to this definition")
Class for collecting data generated by a Mesa model.
A DataCollector is instantiated with dictionaries of names of model-, agent-, and agent-type-level variables to collect, associated with attribute names or functions which actually collect them. When the collect(…) method is called, it collects these attributes and executes these functions one by one and stores the results.
Instantiate a DataCollector with lists of model, agent, and agent-type reporters.
Both model\_reporters, agent\_reporters, and agenttype\_reporters accept a dictionary mapping a variable name to either an attribute name, a function, a method of a class/instance, or a function with parameters placed in a list.
Model reporters can take four types of arguments: 1. Lambda function:
> {“agent\_count”: lambda m: len(m.agents)}
2. Method of a class/instance: {“agent\_count”: self.get\_agent\_count} # self here is a class instance {“agent\_count”: Model.get\_agent\_count} # Model here is a class
3. Class attributes of a model: {“model\_attribute”: “model\_attribute”}
4. Functions with parameters that have been placed in a list: {“Model\_Function”: \[function, \[param\_1, param\_2\]\]}
Agent reporters can similarly take: 1. Attribute name (string) referring to agent’s attribute:
> {“energy”: “energy”}
2. Lambda function: {“energy”: lambda a: a.energy}
3. Method of an agent class/instance: {“agent\_action”: self.do\_action} # self here is an agent class instance {“agent\_action”: Agent.do\_action} # Agent here is a class
4. Functions with parameters placed in a list: {“Agent\_Function”: \[function, \[param\_1, param\_2\]\]}
Agenttype reporters take a dictionary mapping agent types to dictionaries of reporter names and attributes/funcs/methods, similar to agent\_reporters:
> {Wolf: {“energy”: lambda a: a.energy}}
The tables arg accepts a dictionary mapping names of tables to lists of columns. For example, if we want to allow agents to write their age when they are destroyed (to keep track of lifespans), it might look like:
> {“Lifespan”: \[“unique\_id”, “age”\]}
Parameters:
* **model\_reporters** – Dictionary of reporter names and attributes/funcs/methods.
* **agent\_reporters** – Dictionary of reporter names and attributes/funcs/methods.
* **agenttype\_reporters** – Dictionary of agent types to dictionaries of reporter names and attributes/funcs/methods.
* **tables** – Dictionary of table names to lists of column names.
Notes
* If you want to pickle your model you must not use lambda functions.
* If your model includes a large number of agents, it is recommended to use attribute names for the agent reporter, as it will be faster.
collect(_model_)[\[source\]](../_modules/datacollection.html#DataCollector.collect)
[#](#datacollection.DataCollector.collect "Link to this definition")
Collect all the data for the given model object.
add\_table\_row(_table\_name_, _row_, _ignore\_missing\=False_)[\[source\]](../_modules/datacollection.html#DataCollector.add_table_row)
[#](#datacollection.DataCollector.add_table_row "Link to this definition")
Add a row dictionary to a specific table.
Parameters:
* **table\_name** – Name of the table to append a row to.
* **row** – A dictionary of the form {column\_name: value…}
* **ignore\_missing** – If True, fill any missing columns with Nones; if False, throw an error if any columns are missing
get\_model\_vars\_dataframe()[\[source\]](../_modules/datacollection.html#DataCollector.get_model_vars_dataframe)
[#](#datacollection.DataCollector.get_model_vars_dataframe "Link to this definition")
Create a pandas DataFrame from the model variables.
The DataFrame has one column for each model variable, and the index is (implicitly) the model tick.
get\_agent\_vars\_dataframe()[\[source\]](../_modules/datacollection.html#DataCollector.get_agent_vars_dataframe)
[#](#datacollection.DataCollector.get_agent_vars_dataframe "Link to this definition")
Create a pandas DataFrame from the agent variables.
The DataFrame has one column for each variable, with two additional columns for tick and agent\_id.
get\_agenttype\_vars\_dataframe(_agent\_type_)[\[source\]](../_modules/datacollection.html#DataCollector.get_agenttype_vars_dataframe)
[#](#datacollection.DataCollector.get_agenttype_vars_dataframe "Link to this definition")
Create a pandas DataFrame from the agent-type variables for a specific agent type.
The DataFrame has one column for each variable, with two additional columns for tick and agent\_id.
Parameters:
**agent\_type** – The type of agent to get the data for.
get\_table\_dataframe(_table\_name_)[\[source\]](../_modules/datacollection.html#DataCollector.get_table_dataframe)
[#](#datacollection.DataCollector.get_table_dataframe "Link to this definition")
Create a pandas DataFrame from a particular table.
Parameters:
**table\_name** – The name of the table to convert.
On this page
### This Page
* [Show Source](../_sources/apis/datacollection.md.txt)
---
# Python Module Index — Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Python Module Index
===================
[**b**](#cap-b)
| [**d**](#cap-d)
| [**e**](#cap-e)
| [**m**](#cap-m)
| | | |
| --- | --- | --- |
| | | |
| | **b** | |
| | [`batchrunner`](apis/batchrunner.html#module-batchrunner) | |
| | | |
| | **d** | |
| | [`datacollection`](apis/datacollection.html#module-datacollection) | |
| | | |
| | **e** | |
|  | `experimental` | |
| | [`experimental.cell_space.__init__`](apis/experimental.html#module-experimental.cell_space.__init__) | |
| | [`experimental.cell_space.cell`](apis/experimental.html#module-experimental.cell_space.cell) | |
| | [`experimental.cell_space.cell_agent`](apis/experimental.html#module-experimental.cell_space.cell_agent) | |
| | [`experimental.cell_space.cell_collection`](apis/experimental.html#module-experimental.cell_space.cell_collection) | |
| | [`experimental.cell_space.discrete_space`](apis/experimental.html#module-experimental.cell_space.discrete_space) | |
| | [`experimental.cell_space.grid`](apis/experimental.html#module-experimental.cell_space.grid) | |
| | [`experimental.cell_space.network`](apis/experimental.html#module-experimental.cell_space.network) | |
| | [`experimental.cell_space.voronoi`](apis/experimental.html#module-experimental.cell_space.voronoi) | |
| | [`experimental.continuous_space.continuous_space`](apis/experimental.html#module-experimental.continuous_space.continuous_space) | |
| | [`experimental.continuous_space.continuous_space_agents`](apis/experimental.html#module-experimental.continuous_space.continuous_space_agents) | |
| | [`experimental.devs.eventlist`](apis/experimental.html#module-experimental.devs.eventlist) | |
| | [`experimental.devs.simulator`](apis/experimental.html#module-experimental.devs.simulator) | |
| | | |
| | **m** | |
|  | [`mesa`](mesa.html#module-mesa) | |
| | [`mesa.agent`](mesa.html#module-mesa.agent) | |
| | [`mesa.batchrunner`](mesa.html#module-mesa.batchrunner) | |
| | [`mesa.datacollection`](mesa.html#module-mesa.datacollection) | |
| | [`mesa.mesa_logging`](apis/mesa_logging.html#module-mesa.mesa_logging) | |
| | [`mesa.model`](mesa.html#module-mesa.model) | |
| | [`mesa.space`](mesa.html#module-mesa.space) | |
| | [`mesa.visualization.components.__init__`](apis/visualization.html#module-mesa.visualization.components.__init__) | |
| | [`mesa.visualization.components.altair_components`](apis/visualization.html#module-mesa.visualization.components.altair_components) | |
| | [`mesa.visualization.components.matplotlib_components`](apis/visualization.html#module-mesa.visualization.components.matplotlib_components) | |
| | [`mesa.visualization.mpl_space_drawing`](apis/visualization.html#module-mesa.visualization.mpl_space_drawing) | |
| | [`mesa.visualization.solara_viz`](apis/visualization.html#module-mesa.visualization.solara_viz) | |
| | [`mesa.visualization.user_param`](apis/visualization.html#module-mesa.visualization.user_param) | |
---
# Search - Mesa .1 documentation
[Skip to main content](#main-content)
Back to top Ctrl+K
Search
======
Ctrl+K
---
# Unknown
\# Mesa: Agent-based modeling in Python \`\`\`{image} https://github.com/projectmesa/mesa/workflows/build/badge.svg :target: https://github.com/projectmesa/mesa/actions \`\`\` \`\`\`{image} https://codecov.io/gh/projectmesa/mesa/branch/main/graph/badge.svg :target: https://codecov.io/gh/projectmesa/mesa \`\`\` \`\`\`{image} https://img.shields.io/badge/code%20style-black-000000.svg :target: https://github.com/psf/black \`\`\` \`\`\`{image} https://img.shields.io/matrix/project-mesa:matrix.org?label=chat&logo=Matrix :target: https://matrix.to/#/#project-mesa:matrix.org \`\`\` \[Mesa\] is an Apache2 licensed agent-based modeling (or ABM) framework in Python. Mesa allows users to quickly create agent-based models using built-in core components (such as spatial grids and agent schedulers) or customized implementations; visualize them using a browser-based interface; and analyze their results using Python's data analysis tools. Its goal is to be the Python-based counterpart to NetLogo, Repast, or MASON. !\[A screenshot of the Wolf Sheep model in Mesa|100%\](images/wolf\_sheep.png) \*A visualisation of the Wolf Sheep model build with Mesa.\* ## Features - Built-in core modeling components - Flexible agent and model management through AgentSet - Browser-based Solara visualization - Built-in tools for data collection and analysis - Example model library ## Using Mesa ### Installation Options To install our latest stable release, run: \`\`\`bash pip install -U mesa \`\`\` To also install our recommended dependencies: \`\`\`bash pip install -U mesa\[rec\] \`\`\` The \`\[rec\]\` option installs additional recommended dependencies needed for visualization, plotting, and network modeling capabilities. On a Mac, this command might cause an error stating \`zsh: no matches found: mesa\[all\]\`. In that case, change the command to \`pip install -U "mesa\[rec\]"\`. ### Resources For help getting started with Mesa, check out these resources: - \[Getting started\] - Learn about Mesa's core concepts and components - \[Migration Guide\] - Upgrade to Mesa 3.0 - \[Mesa Examples\] - Browse user-contributed models and implementations - \[Mesa Extensions\] - Overview of mesa's Extensions - \[GitHub Discussions\] - Ask questions and discuss Mesa - \[Matrix Chat Room\] - Real-time chat with the Mesa community ### Development and Support Mesa is an open source project and welcomes contributions: - \[GitHub Repository\] - Access the source code - \[Issue Tracker\] - Report bugs or suggest features - \[Contributors Guide\] - Learn how to contribute The original Mesa conference paper is \[available here\](http://conference.scipy.org.s3-website-us-east-1.amazonaws.com/proceedings/scipy2015/jacqueline\_kazil.html). \`\`\`{toctree} :hidden: true :maxdepth: 7 Getting started Overview Examples Migration guide API Documentation \`\`\` # Indices and tables - {ref}\`genindex\` - {ref}\`modindex\` - {ref}\`search\` \[contributors guide\]: https://github.com/projectmesa/mesa/blob/main/CONTRIBUTING.md \[github repository\]: https://github.com/projectmesa/mesa/ \[github discussions\]: https://github.com/projectmesa/mesa/discussions \[issue tracker\]: https://github.com/projectmesa/mesa/issues \[matrix chat room\]: https://matrix.to/#/#project-mesa:matrix.org \[mesa\]: https://github.com/projectmesa/mesa/ \[mesa overview\]: overview \[mesa examples\]: https://mesa.readthedocs.io/stable/examples.html \[mesa introductory tutorial\]: tutorials/intro\_tutorial \[mesa visualization tutorial\]: tutorials/visualization\_tutorial \[migration guide\]: migration\_guide \[Getting started\]: getting\_started \[Mesa Extensions\]: mesa\_extension.md
---
# Unknown
\# Conway's Game Of "Life" ## Summary \[The Game of Life\](https://en.wikipedia.org/wiki/Conway%27s\_Game\_of\_Life), also known simply as "Life", is a cellular automaton devised by the British mathematician John Horton Conway in 1970. The "game" is a zero-player game, meaning that its evolution is determined by its initial state, requiring no further input by a human. One interacts with the Game of "Life" by creating an initial configuration and observing how it evolves, or, for advanced "players", by creating patterns with particular properties. ## How to Run To run the model interactively you can use either the streamlit or solara version. For solara, you use \`\`\` $ solara run app.py \`\`\` For streamlit, you need \`\`\` $ streamlit run st\_app.py \`\`\` This will open your browser and show you the controls. You can start the model by hitting the run button. ## Files \* \`\`agents.py\`\`: Defines the behavior of an individual cell, which can be in two states: DEAD or ALIVE. \* \`\`model.py\`\`: Defines the model itself, initialized with a random configuration of alive and dead cells. \* \`\`app.py\`\`: Defines an interactive visualization using solara. \* \`\`st\_app.py\`\`: Defines an interactive visualization using Streamlit. ## Optional \* For the streamlit version, you need to have streamlit installed (can be done via pip install streamlit) ## Further Reading \[Conway's Game of Life\](https://en.wikipedia.org/wiki/Conway%27s\_Game\_of\_Life) ## Agents \`\`\`python from mesa import Agent class Cell(Agent): """Represents a single ALIVE or DEAD cell in the simulation.""" DEAD = 0 ALIVE = 1 def \_\_init\_\_(self, pos, model, init\_state=DEAD): """Create a cell, in the given state, at the given x, y position.""" super().\_\_init\_\_(model) self.x, self.y = pos self.state = init\_state self.\_next\_state = None @property def is\_alive(self): return self.state == self.ALIVE @property def neighbors(self): return self.model.grid.iter\_neighbors((self.x, self.y), True) def determine\_state(self): """Compute if the cell will be dead or alive at the next tick. This is based on the number of alive or dead neighbors. The state is not changed here, but is just computed and stored in self.\_nextState, because our current state may still be necessary for our neighbors to calculate their next state. """ # Get the neighbors and apply the rules on whether to be alive or dead # at the next tick. live\_neighbors = sum(neighbor.is\_alive for neighbor in self.neighbors) # Assume nextState is unchanged, unless changed below. self.\_next\_state = self.state if self.is\_alive: if live\_neighbors < 2 or live\_neighbors > 3: self.\_next\_state = self.DEAD else: if live\_neighbors == 3: self.\_next\_state = self.ALIVE def assume\_state(self): """Set the state to the new computed state -- computed in step().""" self.state = self.\_next\_state \`\`\` ## Model \`\`\`python from mesa import Model from mesa.examples.basic.conways\_game\_of\_life.agents import Cell from mesa.space import SingleGrid class ConwaysGameOfLife(Model): """Represents the 2-dimensional array of cells in Conway's Game of Life.""" def \_\_init\_\_(self, width=50, height=50, initial\_fraction\_alive=0.2, seed=None): """Create a new playing area of (width, height) cells.""" super().\_\_init\_\_(seed=seed) # Use a simple grid, where edges wrap around. self.grid = SingleGrid(width, height, torus=True) # Place a cell at each location, with some initialized to # ALIVE and some to DEAD. for \_contents, (x, y) in self.grid.coord\_iter(): cell = Cell((x, y), self) if self.random.random() < initial\_fraction\_alive: cell.state = cell.ALIVE self.grid.place\_agent(cell, (x, y)) self.running = True def step(self): """Perform the model step in two stages: - First, all cells assume their next state (whether they will be dead or alive) - Then, all cells change state to their next state. """ self.agents.do("determine\_state") self.agents.do("assume\_state") \`\`\` ## App \`\`\`python from mesa.examples.basic.conways\_game\_of\_life.model import ConwaysGameOfLife from mesa.visualization import ( SolaraViz, make\_space\_component, ) def agent\_portrayal(agent): return { "color": "white" if agent.state == 0 else "black", "marker": "s", "size": 25, } def post\_process(ax): ax.set\_aspect("equal") ax.set\_xticks(\[\]) ax.set\_yticks(\[\]) model\_params = { "seed": { "type": "InputText", "value": 42, "label": "Random Seed", }, "width": { "type": "SliderInt", "value": 50, "label": "Width", "min": 5, "max": 60, "step": 1, }, "height": { "type": "SliderInt", "value": 50, "label": "Height", "min": 5, "max": 60, "step": 1, }, "initial\_fraction\_alive": { "type": "SliderFloat", "value": 0.2, "label": "Cells initially alive", "min": 0, "max": 1, "step": 0.01, }, } # Create initial model instance model1 = ConwaysGameOfLife() # Create visualization elements. The visualization elements are solara components # that receive the model instance as a "prop" and display it in a certain way. # Under the hood these are just classes that receive the model instance. # You can also author your own visualization elements, which can also be functions # that receive the model instance and return a valid solara component. SpaceGraph = make\_space\_component( agent\_portrayal, post\_process=post\_process, draw\_grid=False ) # Create the SolaraViz page. This will automatically create a server and display the # visualization elements in a web browser. # Display it using the following command in the example directory: # solara run app.py # It will automatically update and display any changes made to this file page = SolaraViz( model1, components=\[SpaceGraph\], model\_params=model\_params, name="Game of Life", ) page # noqa \`\`\`
---