Skip to content

Commit 421b575

Browse files
authored
Docs: Update outdated examples: auto-generated agent IDs, updated initialization, and minor fixes (#170)
* Update dependencies: add 'mesa>=3.2.0' and retain existing versions for 'boto3' in pyproject.toml * update uv.lock * Refactor MoneyAgent initialization and agent addition in MoneyModel for improved clarity and efficiency * Update introductory tutorial notebook: fix installation command, adjust execution counts, and improve wealth distribution output * Refactor MoneyModel initialization loop to use underscore for unused variable * Remove unused 'unique_id' field from DataFrame initialization in agent class * Remove 'unique_id' field from MoneyAgentPolars DataFrame initialization * Remove 'unique_id' field from MoneyAgentPolars DataFrame initialization * Update AgentSetDF documentation to clarify 'unique_id' column requirement and remove it from MoneyAgent initialization * Refactor SugarscapeMesa to use set for agents instead of list for mesa3.0 * Remove 'unique_id' parameter from AntMesa and Sugar class initializers * Refactor SugarscapeMesa to remove agent_id and simplify Sugar initialization * Remove 'unique_id' from AntPolarsBase initialization and update null handling in AntPolarsLoop * Update display name in introductory tutorial to 'mesa-frames' * Refactor AntPolarsLoop to improve readability by consolidating method chaining in get_best_moves * Remove agent_id from AntMesa initialization in SugarscapeMesa
1 parent 959cdee commit 421b575

File tree

11 files changed

+1515
-1617
lines changed

11 files changed

+1515
-1617
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ class MoneyAgentPolars(AgentSetPolars):
9898
super().__init__(model)
9999
# Adding the agents to the agent set
100100
self += pl.DataFrame(
101-
{"unique_id": pl.arange(n, eager=True), "wealth": pl.ones(n, eager=True)}
101+
{"wealth": pl.ones(n, eager=True)}
102102
)
103103

104104
def step(self) -> None:

docs/general/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class MoneyAgentPolars(AgentSetPolars):
4848
def __init__(self, n: int, model: ModelDF):
4949
super().__init__(model)
5050
self += pl.DataFrame(
51-
{"unique_id": pl.arange(n, eager=True), "wealth": pl.ones(n, eager=True)}
51+
{"wealth": pl.ones(n, eager=True)}
5252
)
5353

5454
def step(self) -> None:

docs/general/user-guide/0_getting-started.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ If you're familiar with mesa, this guide will help you understand the key differ
8888
def __init__(self, n, model):
8989
super().__init__(model)
9090
self += pl.DataFrame({
91-
"unique_id": pl.arange(n),
9291
"wealth": pl.ones(n)
9392
})
9493
def step(self):

docs/general/user-guide/1_classes.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
To create your own AgentSetDF class, you need to subclass the AgentSetPolars class and make sure to call `super().__init__(model)`.
66

7-
Typically, the next step would be to populate the class with your agents. To do that, you need to add a DataFrame to the AgentSetDF. You can do `self += agents` or `self.add(agents)`, where `agents` is a DataFrame or something that could be passed to a DataFrame constructor, like a dictionary or lists of lists. You need to make sure your DataFrame has a 'unique_id' column and that the ids are unique across the model, otherwise you will get an error raised. In the DataFrame, you should also put any attribute of the agent you are using.
7+
Typically, the next step would be to populate the class with your agents. To do that, you need to add a DataFrame to the AgentSetDF. You can do `self += agents` or `self.add(agents)`, where `agents` is a DataFrame or something that could be passed to a DataFrame constructor, like a dictionary or lists of lists. You need to make sure your DataFrame doesn't have a 'unique_id' column because IDs are generated automatically, otherwise you will get an error raised. In the DataFrame, you should also put any attribute of the agent you are using.
88

99
How can you choose which agents should be in the same AgentSet? The idea is that you should minimize the missing values in the DataFrame (so they should have similar/same attributes) and mostly everybody should do the same actions.
1010

@@ -16,7 +16,6 @@ class MoneyAgent(AgentSetPolars):
1616
super().__init__(model)
1717
self.initial_wealth = pl.ones(n)
1818
self += pl.DataFrame({
19-
"unique_id": pl.arange(n),
2019
"wealth": self.initial_wealth
2120
})
2221

docs/general/user-guide/2_introductory-tutorial.ipynb

Lines changed: 53 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@
2020
},
2121
{
2222
"cell_type": "code",
23-
"execution_count": null,
23+
"execution_count": 18,
2424
"id": "df4d8623",
2525
"metadata": {},
2626
"outputs": [],
2727
"source": [
28-
"# !pip install mesa-frames mesa"
28+
"# !pip install git+https://github.com/projectmesa/mesa-frames mesa"
2929
]
3030
},
3131
{
@@ -44,7 +44,7 @@
4444
},
4545
{
4646
"cell_type": "code",
47-
"execution_count": 1,
47+
"execution_count": 19,
4848
"id": "fc0ee981",
4949
"metadata": {},
5050
"outputs": [],
@@ -79,7 +79,7 @@
7979
},
8080
{
8181
"cell_type": "code",
82-
"execution_count": null,
82+
"execution_count": 20,
8383
"id": "2bac0126",
8484
"metadata": {},
8585
"outputs": [],
@@ -90,9 +90,7 @@
9090
"class MoneyAgentPolars(AgentSetPolars):\n",
9191
" def __init__(self, n: int, model: ModelDF):\n",
9292
" super().__init__(model)\n",
93-
" self += pl.DataFrame(\n",
94-
" {\"unique_id\": pl.arange(n, eager=True), \"wealth\": pl.ones(n, eager=True)}\n",
95-
" )\n",
93+
" self += pl.DataFrame({\"wealth\": pl.ones(n, eager=True)})\n",
9694
"\n",
9795
" def step(self) -> None:\n",
9896
" self.do(\"give_money\")\n",
@@ -118,10 +116,33 @@
118116
},
119117
{
120118
"cell_type": "code",
121-
"execution_count": null,
119+
"execution_count": 21,
122120
"id": "65da4e6f",
123121
"metadata": {},
124-
"outputs": [],
122+
"outputs": [
123+
{
124+
"name": "stdout",
125+
"output_type": "stream",
126+
"text": [
127+
"shape: (9, 2)\n",
128+
"┌────────────┬──────────┐\n",
129+
"│ statistic ┆ wealth │\n",
130+
"│ --- ┆ --- │\n",
131+
"│ str ┆ f64 │\n",
132+
"╞════════════╪══════════╡\n",
133+
"│ count ┆ 1000.0 │\n",
134+
"│ null_count ┆ 0.0 │\n",
135+
"│ mean ┆ 1.0 │\n",
136+
"│ std ┆ 1.134587 │\n",
137+
"│ min ┆ 0.0 │\n",
138+
"│ 25% ┆ 0.0 │\n",
139+
"│ 50% ┆ 1.0 │\n",
140+
"│ 75% ┆ 2.0 │\n",
141+
"│ max ┆ 8.0 │\n",
142+
"└────────────┴──────────┘\n"
143+
]
144+
}
145+
],
125146
"source": [
126147
"# Choose either MoneyAgentPandas or MoneyAgentPolars\n",
127148
"agent_class = MoneyAgentPolars\n",
@@ -131,6 +152,7 @@
131152
"model.run_model(100)\n",
132153
"\n",
133154
"wealth_dist = list(model.agents.df.values())[0]\n",
155+
"\n",
134156
"# Print the final wealth distribution\n",
135157
"print(wealth_dist.select(pl.col(\"wealth\")).describe())"
136158
]
@@ -150,7 +172,7 @@
150172
},
151173
{
152174
"cell_type": "code",
153-
"execution_count": null,
175+
"execution_count": 22,
154176
"id": "fbdb540810924de8",
155177
"metadata": {},
156178
"outputs": [],
@@ -161,21 +183,18 @@
161183
" ## Adding the agents to the agent set\n",
162184
" # 1. Changing the df attribute directly (not recommended, if other agents were added before, they will be lost)\n",
163185
" \"\"\"self.df = pl.DataFrame(\n",
164-
" {\"unique_id\": pl.arange(n, eager=True), \"wealth\": pl.ones(n, eager=True)}\n",
186+
" {\"wealth\": pl.ones(n, eager=True)}\n",
165187
" )\"\"\"\n",
166188
" # 2. Adding the dataframe with add\n",
167189
" \"\"\"self.add(\n",
168190
" pl.DataFrame(\n",
169191
" {\n",
170-
" \"unique_id\": pl.arange(n, eager=True),\n",
171192
" \"wealth\": pl.ones(n, eager=True),\n",
172193
" }\n",
173194
" )\n",
174195
" )\"\"\"\n",
175196
" # 3. Adding the dataframe with __iadd__\n",
176-
" self += pl.DataFrame(\n",
177-
" {\"unique_id\": pl.arange(n, eager=True), \"wealth\": pl.ones(n, eager=True)}\n",
178-
" )\n",
197+
" self += pl.DataFrame({\"wealth\": pl.ones(n, eager=True)})\n",
179198
"\n",
180199
" def step(self) -> None:\n",
181200
" # The give_money method is called\n",
@@ -216,9 +235,7 @@
216235
"class MoneyAgentPolarsNative(AgentSetPolars):\n",
217236
" def __init__(self, n: int, model: ModelDF):\n",
218237
" super().__init__(model)\n",
219-
" self += pl.DataFrame(\n",
220-
" {\"unique_id\": pl.arange(n, eager=True), \"wealth\": pl.ones(n, eager=True)}\n",
221-
" )\n",
238+
" self += pl.DataFrame({\"wealth\": pl.ones(n, eager=True)})\n",
222239
"\n",
223240
" def step(self) -> None:\n",
224241
" self.do(\"give_money\")\n",
@@ -231,7 +248,9 @@
231248
"\n",
232249
" # Wealth of wealthy is decreased by 1\n",
233250
" self.df = self.df.with_columns(\n",
234-
" wealth=pl.when(pl.col(\"unique_id\").is_in(self.active_agents[\"unique_id\"]))\n",
251+
" wealth=pl.when(\n",
252+
" pl.col(\"unique_id\").is_in(self.active_agents[\"unique_id\"].implode())\n",
253+
" )\n",
235254
" .then(pl.col(\"wealth\") - 1)\n",
236255
" .otherwise(pl.col(\"wealth\"))\n",
237256
" )\n",
@@ -257,14 +276,12 @@
257276
},
258277
{
259278
"cell_type": "code",
260-
"execution_count": 12,
279+
"execution_count": 23,
261280
"id": "9dbe761af964af5b",
262281
"metadata": {},
263282
"outputs": [],
264283
"source": [
265284
"import mesa\n",
266-
"import importlib.metadata\n",
267-
"from packaging import version\n",
268285
"\n",
269286
"\n",
270287
"class MoneyAgent(mesa.Agent):\n",
@@ -292,7 +309,7 @@
292309
" def __init__(self, N: int):\n",
293310
" super().__init__()\n",
294311
" self.num_agents = N\n",
295-
" for i in range(N):\n",
312+
" for _ in range(N):\n",
296313
" self.agents.add(MoneyAgent(self))\n",
297314
"\n",
298315
" def step(self):\n",
@@ -306,7 +323,7 @@
306323
},
307324
{
308325
"cell_type": "code",
309-
"execution_count": 13,
326+
"execution_count": 24,
310327
"id": "2d864cd3",
311328
"metadata": {},
312329
"outputs": [
@@ -317,21 +334,21 @@
317334
"Execution times:\n",
318335
"---------------\n",
319336
"mesa:\n",
320-
" Number of agents: 100, Time: 0.06 seconds\n",
321-
" Number of agents: 1001, Time: 3.56 seconds\n",
322-
" Number of agents: 2000, Time: 12.81 seconds\n",
337+
" Number of agents: 100, Time: 0.03 seconds\n",
338+
" Number of agents: 1001, Time: 1.45 seconds\n",
339+
" Number of agents: 2000, Time: 5.40 seconds\n",
323340
"---------------\n",
324341
"---------------\n",
325342
"mesa-frames (pl concise):\n",
326-
" Number of agents: 100, Time: 0.20 seconds\n",
327-
" Number of agents: 1001, Time: 0.21 seconds\n",
328-
" Number of agents: 2000, Time: 0.23 seconds\n",
343+
" Number of agents: 100, Time: 1.60 seconds\n",
344+
" Number of agents: 1001, Time: 2.68 seconds\n",
345+
" Number of agents: 2000, Time: 3.04 seconds\n",
329346
"---------------\n",
330347
"---------------\n",
331348
"mesa-frames (pl native):\n",
332-
" Number of agents: 100, Time: 0.11 seconds\n",
333-
" Number of agents: 1001, Time: 0.12 seconds\n",
334-
" Number of agents: 2000, Time: 0.13 seconds\n",
349+
" Number of agents: 100, Time: 0.62 seconds\n",
350+
" Number of agents: 1001, Time: 0.80 seconds\n",
351+
" Number of agents: 2000, Time: 1.10 seconds\n",
335352
"---------------\n"
336353
]
337354
}
@@ -390,7 +407,7 @@
390407
],
391408
"metadata": {
392409
"kernelspec": {
393-
"display_name": "Python 3",
410+
"display_name": "mesa-frames",
394411
"language": "python",
395412
"name": "python3"
396413
},
@@ -404,9 +421,9 @@
404421
"name": "python",
405422
"nbconvert_exporter": "python",
406423
"pygments_lexer": "ipython3",
407-
"version": "3.12.1"
424+
"version": "3.12.3"
408425
}
409426
},
410427
"nbformat": 4,
411428
"nbformat_minor": 5
412-
}
429+
}

examples/boltzmann_wealth/performance_plot.py

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1+
import importlib.metadata
2+
13
import matplotlib.pyplot as plt
24
import mesa
35
import numpy as np
4-
56
import perfplot
67
import polars as pl
78
import seaborn as sns
8-
import importlib.metadata
99
from packaging import version
1010

1111
from mesa_frames import AgentSetPolars, ModelDF
@@ -20,9 +20,9 @@ def mesa_implementation(n_agents: int) -> None:
2020
class MoneyAgent(mesa.Agent):
2121
"""An agent with fixed initial wealth."""
2222

23-
def __init__(self, unique_id, model):
23+
def __init__(self, model):
2424
# Pass the parameters to the parent class.
25-
super().__init__(unique_id, model)
25+
super().__init__(model)
2626

2727
# Create the agent's variable and set the initial values.
2828
self.wealth = 1
@@ -42,13 +42,12 @@ class MoneyModel(mesa.Model):
4242
def __init__(self, N):
4343
super().__init__()
4444
self.num_agents = N
45-
self.agents = [MoneyAgent(i, self) for i in range(self.num_agents)]
45+
for _ in range(self.num_agents):
46+
self.agents.add(MoneyAgent(self))
4647

4748
def step(self):
4849
"""Advance the model by one step."""
49-
self.random.shuffle(self.agents)
50-
for agent in self.agents:
51-
agent.step()
50+
self.agents.shuffle_do("step")
5251

5352
def run_model(self, n_steps) -> None:
5453
for _ in range(n_steps):
@@ -72,21 +71,18 @@ def __init__(self, n: int, model: ModelDF):
7271
## Adding the agents to the agent set
7372
# 1. Changing the agents attribute directly (not recommended, if other agents were added before, they will be lost)
7473
"""self.agents = pl.DataFrame(
75-
{"unique_id": pl.arange(n, eager=True), "wealth": pl.ones(n, eager=True)}
74+
"wealth": pl.ones(n, eager=True)}
7675
)"""
7776
# 2. Adding the dataframe with add
7877
"""self.add(
7978
pl.DataFrame(
8079
{
81-
"unique_id": pl.arange(n, eager=True),
8280
"wealth": pl.ones(n, eager=True),
8381
}
8482
)
8583
)"""
8684
# 3. Adding the dataframe with __iadd__
87-
self += pl.DataFrame(
88-
{"unique_id": pl.arange(n, eager=True), "wealth": pl.ones(n, eager=True)}
89-
)
85+
self += pl.DataFrame({"wealth": pl.ones(n, eager=True)})
9086

9187
def step(self) -> None:
9288
# The give_money method is called
@@ -127,9 +123,7 @@ def give_money(self):
127123
class MoneyAgentPolarsNative(AgentSetPolars):
128124
def __init__(self, n: int, model: ModelDF):
129125
super().__init__(model)
130-
self += pl.DataFrame(
131-
{"unique_id": pl.arange(n, eager=True), "wealth": pl.ones(n, eager=True)}
132-
)
126+
self += pl.DataFrame({"wealth": pl.ones(n, eager=True)})
133127

134128
def step(self) -> None:
135129
self.do("give_money")
@@ -142,7 +136,9 @@ def give_money(self):
142136

143137
# Wealth of wealthy is decreased by 1
144138
self.df = self.df.with_columns(
145-
wealth=pl.when(pl.col("unique_id").is_in(self.active_agents["unique_id"]))
139+
wealth=pl.when(
140+
pl.col("unique_id").is_in(self.active_agents["unique_id"].implode())
141+
)
146142
.then(pl.col("wealth") - 1)
147143
.otherwise(pl.col("wealth"))
148144
)

examples/sugarscape_ig/ss_mesa/agents.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ def get_distance(pos_1, pos_2):
1717

1818

1919
class AntMesa(mesa.Agent):
20-
def __init__(self, unique_id, model, moore=False, sugar=0, metabolism=0, vision=0):
21-
super().__init__(unique_id, model)
20+
def __init__(self, model, moore=False, sugar=0, metabolism=0, vision=0):
21+
super().__init__(model)
2222
self.moore = moore
2323
self.sugar = sugar
2424
self.metabolism = metabolism
@@ -71,8 +71,8 @@ def step(self):
7171

7272

7373
class Sugar(mesa.Agent):
74-
def __init__(self, unique_id, model, max_sugar):
75-
super().__init__(unique_id, model)
74+
def __init__(self, model, max_sugar):
75+
super().__init__(model)
7676
self.amount = max_sugar
7777
self.max_sugar = max_sugar
7878

0 commit comments

Comments
 (0)