Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions examples/color_patches/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ An agent's state represents its "opinion" and is shown by the color of the cell

## How to Run

To run the model interactively, run ``mesa runserver` in this directory. e.g.
To run the model interactively, run ``solara run`` in this directory. e.g.

```
$ mesa runserver
```bash
$ 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.
Then open your browser to [http://localhost:8765/](http://localhost:8765/) and press Reset, then Run.

## Files

Expand Down
86 changes: 86 additions & 0 deletions examples/traffic_flow/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Traffic Flow (Mesa ABM)

A minimal traffic flow agent-based model built with the Mesa framework (tested with Mesa `3.3.1`).

The model uses Mesa 3.x's modern `OrthogonalMooreGrid` for discrete space representation, providing the latest Mesa API features.

The model uses a discrete grid world with cars that move only from left to right. When a car reaches the right edge, it wraps back to the left using a torus grid.

## What this model does

- The world is a `width x height` `OrthogonalMooreGrid`.
- Cars are placed randomly at initialization (one car per cell).
- Each simulation step (a “tick”), every car attempts to move one cell to the right:
- If the cell is empty, it moves.
- If the cell is occupied, it waits.

## Core rules / logic

- **Movement check**: a car checks the cell at `(x+1, y)`.
- **Wrap-around**: since the grid is a torus, moving past the right edge returns to the left edge.
- **No overtaking**: cars do not change lanes or move diagonally (future feature).

## Project structure

- `traffic_flow/agent.py`
- `CarAgent`: defines movement behavior (`move`) and agent step (`step`).
- `traffic_flow/model.py`
- `TraficFlow`: creates the grid, places cars, and advances the model.
- `run.py`
- CLI runner that prints the grid as ASCII each tick.
- `app.py`
- Solara UI entrypoint using `mesa.visualization.SolaraViz`.

## Requirements

- Python 3.8+
- Mesa 3.x (this was built with Mesa `3.3.1`)
- Solara (only required for UI)

Install (example):

```bash
pip install "mesa[rec]" solara
```

## How to run (CLI)

From the `examples/traffic_flow` directory:

```bash
python run.py
```

### Output format

- `C` = a car occupies the cell
- `.` = empty cell

Each printed block corresponds to one simulation step (a “tick”).

## How to run (Solara UI)

From the `examples/traffic_flow` directory:

```bash
solara run app.py
```

Open the URL shown in your terminal.

### Using the sliders

The parameter widgets typically apply to the next model instance. After changing sliders, use the UI control to reset/restart the model so it rebuilds with the new parameters.

## Model parameters

- `width` (int): grid width
- `height` (int): grid height
- `n_cars` (int): number of cars placed initially
- `seed` (int/str): random seed passed to the Mesa model

### Practical limits

- `n_cars` should be less than or equal to `width * height`.
- If `n_cars` is close to `width * height`, initialization can slow down because the model searches repeatedly for empty cells.

59 changes: 59 additions & 0 deletions examples/traffic_flow/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from mesa.visualization import SolaraViz, make_space_component
from traffic_flow.model import TraficFlow


def car_portrayal(agent):
if agent is None or agent.pos is None:
return
return {
"color": "#1f77b4",
"size": 50,
}


space_component = make_space_component(
car_portrayal,
draw_grid=True,
)

model_params = {
"width": {
"type": "SliderInt",
"value": 20,
"label": "Width",
"min": 5,
"max": 60,
"step": 1,
},
"height": {
"type": "SliderInt",
"value": 5,
"label": "Height",
"min": 2,
"max": 20,
"step": 1,
},
"n_cars": {
"type": "SliderInt",
"value": 20,
"label": "Number of cars",
"min": 1,
"max": 200,
"step": 1,
},
"seed": {
"type": "InputText",
"value": 1,
"label": "Seed",
},
}

model = TraficFlow(width=20, height=5, n_cars=20, seed=1)

page = SolaraViz(
model,
components=[space_component],
model_params=model_params,
name="Traffic Flow",
)
page # noqa
22 changes: 22 additions & 0 deletions examples/traffic_flow/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from traffic_flow.model import TraficFlow


def render_grid(model):
lines = []
for y in reversed(range(model.grid.height)):
row = []
for x in range(model.grid.width):
cell_agents = model.grid.get_cell_list_contents((x, y))
row.append("C" if cell_agents else ".")
lines.append("".join(row))
return "\n".join(lines)


if __name__ == "__main__":
model = TraficFlow(width=20, height=5, n_cars=20, seed=1)

for t in range(10):
print(f"tick {t}")
print(render_grid(model))
print()
model.step()
20 changes: 20 additions & 0 deletions examples/traffic_flow/traffic_flow/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from mesa import Agent


class CarAgent(Agent):
def __init__(self, model):
super().__init__(model)

def move(self):
x, y = self.pos
new_pos = ((x + 1) % self.model.grid.dimensions[0], y)
if len(self.model.grid._cells[new_pos].agents) == 0:
# Remove from current cell
self.model.grid._cells[self.pos].remove_agent(self)
# Add to new cell
self.model.grid._cells[new_pos].add_agent(self)
# Update agent position
self.pos = new_pos

def step(self):
self.move()
25 changes: 25 additions & 0 deletions examples/traffic_flow/traffic_flow/model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from mesa import Model
from mesa.discrete_space import OrthogonalMooreGrid

from .agent import CarAgent


class TraficFlow(Model):
def __init__(self, width=20, height=5, n_cars=10, seed=None):
super().__init__(seed=seed)

self.grid = OrthogonalMooreGrid([width, height], torus=True, random=self.random)

for _ in range(n_cars):
car = CarAgent(self)

x = self.random.randrange(self.grid.dimensions[0])
y = self.random.randrange(self.grid.dimensions[1])
while len(self.grid._cells[(x, y)].agents) > 0:
x = self.random.randrange(self.grid.dimensions[0])
y = self.random.randrange(self.grid.dimensions[1])
self.grid._cells[(x, y)].add_agent(car)
car.pos = (x, y)

def step(self):
self.agents.shuffle_do("step")