Mesa 3.0.0__py3-none-any.whl → 3.0.0a0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of Mesa might be problematic. Click here for more details.

Files changed (104) hide show
  1. mesa/__init__.py +3 -3
  2. mesa/agent.py +114 -406
  3. mesa/batchrunner.py +27 -54
  4. mesa/cookiecutter-mesa/cookiecutter.json +8 -0
  5. mesa/cookiecutter-mesa/hooks/post_gen_project.py +11 -0
  6. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/README.md +4 -0
  7. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/app.pytemplate +27 -0
  8. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/setup.pytemplate +11 -0
  9. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}}/model.pytemplate +60 -0
  10. mesa/datacollection.py +29 -140
  11. mesa/experimental/__init__.py +1 -11
  12. mesa/experimental/cell_space/__init__.py +1 -16
  13. mesa/experimental/cell_space/cell.py +23 -93
  14. mesa/experimental/cell_space/cell_agent.py +21 -117
  15. mesa/experimental/cell_space/cell_collection.py +17 -54
  16. mesa/experimental/cell_space/discrete_space.py +8 -92
  17. mesa/experimental/cell_space/grid.py +8 -32
  18. mesa/experimental/cell_space/network.py +7 -12
  19. mesa/experimental/devs/__init__.py +0 -2
  20. mesa/experimental/devs/eventlist.py +14 -52
  21. mesa/experimental/devs/examples/epstein_civil_violence.py +39 -71
  22. mesa/experimental/devs/examples/wolf_sheep.py +45 -45
  23. mesa/experimental/devs/simulator.py +15 -55
  24. mesa/main.py +63 -0
  25. mesa/model.py +83 -211
  26. mesa/space.py +149 -215
  27. mesa/time.py +77 -62
  28. mesa/{experimental → visualization}/UserParam.py +6 -17
  29. mesa/visualization/__init__.py +2 -25
  30. mesa/{experimental → visualization}/components/altair.py +0 -10
  31. mesa/visualization/components/matplotlib.py +134 -0
  32. mesa/{experimental/solara_viz.py → visualization/jupyter_viz.py} +110 -65
  33. {mesa-3.0.0.dist-info → mesa-3.0.0a0.dist-info}/METADATA +13 -65
  34. mesa-3.0.0a0.dist-info/RECORD +38 -0
  35. mesa-3.0.0.dist-info/licenses/NOTICE → mesa-3.0.0a0.dist-info/licenses/LICENSE +2 -2
  36. mesa/examples/README.md +0 -37
  37. mesa/examples/__init__.py +0 -21
  38. mesa/examples/advanced/epstein_civil_violence/Epstein Civil Violence.ipynb +0 -116
  39. mesa/examples/advanced/epstein_civil_violence/Readme.md +0 -34
  40. mesa/examples/advanced/epstein_civil_violence/__init__.py +0 -0
  41. mesa/examples/advanced/epstein_civil_violence/agents.py +0 -164
  42. mesa/examples/advanced/epstein_civil_violence/app.py +0 -73
  43. mesa/examples/advanced/epstein_civil_violence/model.py +0 -114
  44. mesa/examples/advanced/pd_grid/Readme.md +0 -43
  45. mesa/examples/advanced/pd_grid/__init__.py +0 -0
  46. mesa/examples/advanced/pd_grid/agents.py +0 -50
  47. mesa/examples/advanced/pd_grid/analysis.ipynb +0 -228
  48. mesa/examples/advanced/pd_grid/app.py +0 -54
  49. mesa/examples/advanced/pd_grid/model.py +0 -71
  50. mesa/examples/advanced/sugarscape_g1mt/Readme.md +0 -64
  51. mesa/examples/advanced/sugarscape_g1mt/__init__.py +0 -0
  52. mesa/examples/advanced/sugarscape_g1mt/agents.py +0 -344
  53. mesa/examples/advanced/sugarscape_g1mt/app.py +0 -62
  54. mesa/examples/advanced/sugarscape_g1mt/model.py +0 -180
  55. mesa/examples/advanced/sugarscape_g1mt/sugar-map.txt +0 -50
  56. mesa/examples/advanced/sugarscape_g1mt/tests.py +0 -69
  57. mesa/examples/advanced/wolf_sheep/Readme.md +0 -57
  58. mesa/examples/advanced/wolf_sheep/__init__.py +0 -0
  59. mesa/examples/advanced/wolf_sheep/agents.py +0 -102
  60. mesa/examples/advanced/wolf_sheep/app.py +0 -84
  61. mesa/examples/advanced/wolf_sheep/model.py +0 -137
  62. mesa/examples/basic/__init__.py +0 -0
  63. mesa/examples/basic/boid_flockers/Readme.md +0 -22
  64. mesa/examples/basic/boid_flockers/__init__.py +0 -0
  65. mesa/examples/basic/boid_flockers/agents.py +0 -71
  66. mesa/examples/basic/boid_flockers/app.py +0 -58
  67. mesa/examples/basic/boid_flockers/model.py +0 -69
  68. mesa/examples/basic/boltzmann_wealth_model/Readme.md +0 -56
  69. mesa/examples/basic/boltzmann_wealth_model/__init__.py +0 -0
  70. mesa/examples/basic/boltzmann_wealth_model/agents.py +0 -31
  71. mesa/examples/basic/boltzmann_wealth_model/app.py +0 -74
  72. mesa/examples/basic/boltzmann_wealth_model/model.py +0 -43
  73. mesa/examples/basic/boltzmann_wealth_model/st_app.py +0 -115
  74. mesa/examples/basic/conways_game_of_life/Readme.md +0 -39
  75. mesa/examples/basic/conways_game_of_life/__init__.py +0 -0
  76. mesa/examples/basic/conways_game_of_life/agents.py +0 -47
  77. mesa/examples/basic/conways_game_of_life/app.py +0 -51
  78. mesa/examples/basic/conways_game_of_life/model.py +0 -31
  79. mesa/examples/basic/conways_game_of_life/st_app.py +0 -72
  80. mesa/examples/basic/schelling/Readme.md +0 -40
  81. mesa/examples/basic/schelling/__init__.py +0 -0
  82. mesa/examples/basic/schelling/agents.py +0 -26
  83. mesa/examples/basic/schelling/analysis.ipynb +0 -205
  84. mesa/examples/basic/schelling/app.py +0 -42
  85. mesa/examples/basic/schelling/model.py +0 -59
  86. mesa/examples/basic/virus_on_network/Readme.md +0 -61
  87. mesa/examples/basic/virus_on_network/__init__.py +0 -0
  88. mesa/examples/basic/virus_on_network/agents.py +0 -69
  89. mesa/examples/basic/virus_on_network/app.py +0 -114
  90. mesa/examples/basic/virus_on_network/model.py +0 -96
  91. mesa/experimental/cell_space/voronoi.py +0 -257
  92. mesa/experimental/components/matplotlib.py +0 -242
  93. mesa/visualization/components/__init__.py +0 -83
  94. mesa/visualization/components/altair_components.py +0 -188
  95. mesa/visualization/components/matplotlib_components.py +0 -175
  96. mesa/visualization/mpl_space_drawing.py +0 -593
  97. mesa/visualization/solara_viz.py +0 -458
  98. mesa/visualization/user_param.py +0 -69
  99. mesa/visualization/utils.py +0 -9
  100. mesa-3.0.0.dist-info/RECORD +0 -95
  101. mesa-3.0.0.dist-info/licenses/LICENSE +0 -202
  102. /mesa/{examples/advanced → cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}}}/__init__.py +0 -0
  103. {mesa-3.0.0.dist-info → mesa-3.0.0a0.dist-info}/WHEEL +0 -0
  104. {mesa-3.0.0.dist-info → mesa-3.0.0a0.dist-info}/entry_points.txt +0 -0
mesa/batchrunner.py CHANGED
@@ -1,32 +1,4 @@
1
- """batchrunner for running a factorial experiment design over a model.
2
-
3
- To take advantage of parallel execution of experiments, `batch_run` uses
4
- multiprocessing if ``number_processes`` is larger than 1. It is strongly advised
5
- to only run in parallel using a normal python file (so don't try to do it in a
6
- jupyter notebook). Moreover, best practice when using multiprocessing is to
7
- put the code inside an ``if __name__ == '__main__':`` code black as shown below::
8
-
9
- from mesa.batchrunner import batch_run
10
-
11
- params = {"width": 10, "height": 10, "N": range(10, 500, 10)}
12
-
13
- if __name__ == '__main__':
14
- results = batch_run(
15
- MoneyModel,
16
- parameters=params,
17
- iterations=5,
18
- max_steps=100,
19
- number_processes=None,
20
- data_collection_period=1,
21
- display_progress=True,
22
- )
23
-
24
-
25
-
26
- """
27
-
28
1
  import itertools
29
- import multiprocessing
30
2
  from collections.abc import Iterable, Mapping
31
3
  from functools import partial
32
4
  from multiprocessing import Pool
@@ -36,8 +8,6 @@ from tqdm.auto import tqdm
36
8
 
37
9
  from mesa.model import Model
38
10
 
39
- multiprocessing.set_start_method("spawn", force=True)
40
-
41
11
 
42
12
  def batch_run(
43
13
  model_cls: type[Model],
@@ -51,22 +21,29 @@ def batch_run(
51
21
  ) -> list[dict[str, Any]]:
52
22
  """Batch run a mesa model with a set of parameter values.
53
23
 
54
- Args:
55
- model_cls (Type[Model]): The model class to batch-run
56
- parameters (Mapping[str, Union[Any, Iterable[Any]]]): Dictionary with model parameters over which to run the model. You can either pass single values or iterables.
57
- number_processes (int, optional): Number of processes used, by default 1. Set this to None if you want to use all CPUs.
58
- iterations (int, optional): Number of iterations for each parameter combination, by default 1
59
- data_collection_period (int, optional): Number of steps after which data gets collected, by default -1 (end of episode)
60
- max_steps (int, optional): Maximum number of model steps after which the model halts, by default 1000
61
- display_progress (bool, optional): Display batch run process, by default True
62
-
63
- Returns:
64
- List[Dict[str, Any]]
65
-
66
- Notes:
67
- batch_run assumes the model has a `datacollector` attribute that has a DataCollector object initialized.
24
+ Parameters
25
+ ----------
26
+ model_cls : Type[Model]
27
+ The model class to batch-run
28
+ parameters : Mapping[str, Union[Any, Iterable[Any]]],
29
+ Dictionary with model parameters over which to run the model. You can either pass single values or iterables.
30
+ number_processes : int, optional
31
+ Number of processes used, by default 1. Set this to None if you want to use all CPUs.
32
+ iterations : int, optional
33
+ Number of iterations for each parameter combination, by default 1
34
+ data_collection_period : int, optional
35
+ Number of steps after which data gets collected, by default -1 (end of episode)
36
+ max_steps : int, optional
37
+ Maximum number of model steps after which the model halts, by default 1000
38
+ display_progress : bool, optional
39
+ Display batch run process, by default True
68
40
 
41
+ Returns
42
+ -------
43
+ List[Dict[str, Any]]
44
+ [description]
69
45
  """
46
+
70
47
  runs_list = []
71
48
  run_id = 0
72
49
  for iteration in range(iterations):
@@ -108,7 +85,7 @@ def _make_model_kwargs(
108
85
  parameters : Mapping[str, Union[Any, Iterable[Any]]]
109
86
  Single or multiple values for each model parameter name
110
87
 
111
- Returns:
88
+ Returns
112
89
  -------
113
90
  List[Dict[str, Any]]
114
91
  A list of all kwargs combinations.
@@ -148,21 +125,21 @@ def _model_run_func(
148
125
  data_collection_period : int
149
126
  Number of steps after which data gets collected
150
127
 
151
- Returns:
128
+ Returns
152
129
  -------
153
130
  List[Dict[str, Any]]
154
131
  Return model_data, agent_data from the reporters
155
132
  """
156
133
  run_id, iteration, kwargs = run
157
134
  model = model_cls(**kwargs)
158
- while model.running and model.steps <= max_steps:
135
+ while model.running and model.schedule.steps <= max_steps:
159
136
  model.step()
160
137
 
161
138
  data = []
162
139
 
163
- steps = list(range(0, model.steps, data_collection_period))
164
- if not steps or steps[-1] != model.steps - 1:
165
- steps.append(model.steps - 1)
140
+ steps = list(range(0, model.schedule.steps, data_collection_period))
141
+ if not steps or steps[-1] != model.schedule.steps - 1:
142
+ steps.append(model.schedule.steps - 1)
166
143
 
167
144
  for step in steps:
168
145
  model_data, all_agents_data = _collect_data(model, step)
@@ -201,10 +178,6 @@ def _collect_data(
201
178
  step: int,
202
179
  ) -> tuple[dict[str, Any], list[dict[str, Any]]]:
203
180
  """Collect model and agent data from a model using mesas datacollector."""
204
- if not hasattr(model, "datacollector"):
205
- raise AttributeError(
206
- "The model does not have a datacollector attribute. Please add a DataCollector to your model."
207
- )
208
181
  dc = model.datacollector
209
182
 
210
183
  model_data = {param: values[step] for param, values in dc.model_vars.items()}
@@ -0,0 +1,8 @@
1
+ {
2
+ "project": "Example Project",
3
+ "snake": "{{ cookiecutter.project.lower().replace(' ', '_') }}",
4
+ "camel": "{{ cookiecutter.project.title().replace(' ', '') }}",
5
+ "agent": "{{ cookiecutter.camel + 'Agent'}}",
6
+ "model": "{{ cookiecutter.camel + 'Model'}}",
7
+ "description": "Example short description of the project"
8
+ }
@@ -0,0 +1,11 @@
1
+ import glob
2
+ import os
3
+
4
+ file_list = glob.glob("**/*.pytemplate", recursive=True)
5
+
6
+ for file_path in file_list:
7
+ # Check if the file is a regular file
8
+ if not os.path.isfile(file_path):
9
+ continue
10
+ # Rename the file
11
+ os.rename(file_path, file_path.replace(".pytemplate", ".py"))
@@ -0,0 +1,4 @@
1
+ {{cookiecutter.project}}
2
+ ========================
3
+
4
+ {{cookiecutter.description}}
@@ -0,0 +1,27 @@
1
+ """
2
+ Configure visualization elements and instantiate a server
3
+ """
4
+ from mesa.visualization import JupyterViz
5
+
6
+ from {{ cookiecutter.snake }}.model import {{ cookiecutter.model }}, {{ cookiecutter.agent }} # noqa
7
+
8
+ import mesa
9
+
10
+
11
+ def circle_portrayal_example(agent):
12
+ return {
13
+ "size": 40,
14
+ # This is Matplotlib's color
15
+ "color": "tab:pink",
16
+ }
17
+
18
+
19
+ model_params = {"num_agents": 10, "width": 10, "height": 10}
20
+
21
+ page = JupyterViz(
22
+ {{cookiecutter.model}},
23
+ model_params,
24
+ measures=["num_agents"],
25
+ agent_portrayal=circle_portrayal_example
26
+ )
27
+ page # noqa
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env python
2
+ from setuptools import find_packages, setup
3
+
4
+ requires = ["mesa"]
5
+
6
+ setup(
7
+ name="{{cookiecutter.snake}}",
8
+ version="0.0.1",
9
+ packages=find_packages(),
10
+ install_requires=requires,
11
+ )
@@ -0,0 +1,60 @@
1
+ import mesa
2
+
3
+
4
+ class {{cookiecutter.agent}}(mesa.Agent): # noqa
5
+ """
6
+ An agent
7
+ """
8
+
9
+ def __init__(self, unique_id, model):
10
+ """
11
+ Customize the agent
12
+ """
13
+ self.unique_id = unique_id
14
+ super().__init__(unique_id, model)
15
+
16
+ def step(self):
17
+ """
18
+ Modify this method to change what an individual agent will do during each step.
19
+ Can include logic based on neighbors states.
20
+ """
21
+ pass
22
+
23
+
24
+ class {{cookiecutter.model}}(mesa.Model):
25
+ """
26
+ The model class holds the model-level attributes, manages the agents, and generally handles
27
+ the global level of our model.
28
+
29
+ There is only one model-level parameter: how many agents the model contains. When a new model
30
+ is started, we want it to populate itself with the given number of agents.
31
+
32
+ The scheduler is a special model component which controls the order in which agents are activated.
33
+ """
34
+
35
+ def __init__(self, num_agents, width, height):
36
+ super().__init__()
37
+ self.num_agents = num_agents
38
+ self.schedule = mesa.time.RandomActivation(self)
39
+ self.grid = mesa.space.MultiGrid(width=width, height=height, torus=True)
40
+
41
+ for i in range(self.num_agents):
42
+ agent = {{cookiecutter.agent}}(i, self)
43
+ self.schedule.add(agent)
44
+
45
+ x = self.random.randrange(self.grid.width)
46
+ y = self.random.randrange(self.grid.height)
47
+ self.grid.place_agent(agent, (x, y))
48
+
49
+ # example data collector
50
+ self.datacollector = mesa.datacollection.DataCollector({"num_agents": "num_agents"})
51
+
52
+ self.running = True
53
+ self.datacollector.collect(self)
54
+
55
+ def step(self):
56
+ """
57
+ A model step. Used for collecting data and advancing the schedule
58
+ """
59
+ self.datacollector.collect(self)
60
+ self.schedule.step()
mesa/datacollection.py CHANGED
@@ -1,19 +1,20 @@
1
- """Mesa Data Collection Module.
1
+ """
2
+ Mesa Data Collection Module
3
+ ===========================
2
4
 
3
5
  DataCollector is meant to provide a simple, standard way to collect data
4
- generated by a Mesa model. It collects four types of data: model-level data,
5
- agent-level data, agent-type-level data, and tables.
6
+ generated by a Mesa model. It collects three types of data: model-level data,
7
+ agent-level data, and tables.
6
8
 
7
- A DataCollector is instantiated with three dictionaries of reporter names and
8
- associated variable names or functions for each, one for model-level data,
9
- one for agent-level data, and one for agent-type-level data; a fourth dictionary
10
- provides table names and columns. Variable names are converted into functions
11
- which retrieve attributes of that name.
9
+ A DataCollector is instantiated with two dictionaries of reporter names and
10
+ associated variable names or functions for each, one for model-level data and
11
+ one for agent-level data; a third dictionary provides table names and columns.
12
+ Variable names are converted into functions which retrieve attributes of that
13
+ name.
12
14
 
13
15
  When the collect() method is called, each model-level function is called, with
14
16
  the model as the argument, and the results associated with the relevant
15
- variable. Then the agent-level functions are called on each agent, and the
16
- agent-type-level functions are called on each agent of the specified type.
17
+ variable. Then the agent-level functions are called on each agent.
17
18
 
18
19
  Additionally, other objects can write directly to tables by passing in an
19
20
  appropriate dictionary object for a table row.
@@ -22,18 +23,19 @@ The DataCollector then stores the data it collects in dictionaries:
22
23
  * model_vars maps each reporter to a list of its values
23
24
  * tables maps each table to a dictionary, with each column as a key with a
24
25
  list as its value.
25
- * _agent_records maps each model step to a list of each agent's id
26
+ * _agent_records maps each model step to a list of each agents id
26
27
  and its values.
27
- * _agenttype_records maps each model step to a dictionary of agent types,
28
- each containing a list of each agent's id and its values.
29
28
 
30
29
  Finally, DataCollector can create a pandas DataFrame from each collection.
30
+
31
+ The default DataCollector here makes several assumptions:
32
+ * The model has an agent list called agents
33
+ * For collecting agent-level variables, agents must have a unique_id
31
34
  """
32
35
 
33
36
  import contextlib
34
37
  import itertools
35
38
  import types
36
- import warnings
37
39
  from copy import deepcopy
38
40
  from functools import partial
39
41
 
@@ -44,25 +46,24 @@ with contextlib.suppress(ImportError):
44
46
  class DataCollector:
45
47
  """Class for collecting data generated by a Mesa model.
46
48
 
47
- A DataCollector is instantiated with dictionaries of names of model-,
48
- agent-, and agent-type-level variables to collect, associated with
49
- attribute names or functions which actually collect them. When the
50
- collect(...) method is called, it collects these attributes and executes
51
- these functions one by one and stores the results.
49
+ A DataCollector is instantiated with dictionaries of names of model- and
50
+ agent-level variables to collect, associated with attribute names or
51
+ functions which actually collect them. When the collect(...) method is
52
+ called, it collects these attributes and executes these functions one by
53
+ one and stores the results.
52
54
  """
53
55
 
54
56
  def __init__(
55
57
  self,
56
58
  model_reporters=None,
57
59
  agent_reporters=None,
58
- agenttype_reporters=None,
59
60
  tables=None,
60
61
  ):
61
- """Instantiate a DataCollector with lists of model, agent, and agent-type reporters.
62
-
63
- Both model_reporters, agent_reporters, and agenttype_reporters accept a
64
- dictionary mapping a variable name to either an attribute name, a function,
65
- a method of a class/instance, or a function with parameters placed in a list.
62
+ """
63
+ Instantiate a DataCollector with lists of model and agent reporters.
64
+ Both model_reporters and agent_reporters accept a dictionary mapping a
65
+ variable name to either an attribute name, a function, a method of a class/instance,
66
+ or a function with parameters placed in a list.
66
67
 
67
68
  Model reporters can take four types of arguments:
68
69
  1. Lambda function:
@@ -86,10 +87,6 @@ class DataCollector:
86
87
  4. Functions with parameters placed in a list:
87
88
  {"Agent_Function": [function, [param_1, param_2]]}
88
89
 
89
- Agenttype reporters take a dictionary mapping agent types to dictionaries
90
- of reporter names and attributes/funcs/methods, similar to agent_reporters:
91
- {Wolf: {"energy": lambda a: a.energy}}
92
-
93
90
  The tables arg accepts a dictionary mapping names of tables to lists of
94
91
  columns. For example, if we want to allow agents to write their age
95
92
  when they are destroyed (to keep track of lifespans), it might look
@@ -99,8 +96,6 @@ class DataCollector:
99
96
  Args:
100
97
  model_reporters: Dictionary of reporter names and attributes/funcs/methods.
101
98
  agent_reporters: Dictionary of reporter names and attributes/funcs/methods.
102
- agenttype_reporters: Dictionary of agent types to dictionaries of
103
- reporter names and attributes/funcs/methods.
104
99
  tables: Dictionary of table names to lists of column names.
105
100
 
106
101
  Notes:
@@ -110,11 +105,9 @@ class DataCollector:
110
105
  """
111
106
  self.model_reporters = {}
112
107
  self.agent_reporters = {}
113
- self.agenttype_reporters = {}
114
108
 
115
109
  self.model_vars = {}
116
110
  self._agent_records = {}
117
- self._agenttype_records = {}
118
111
  self.tables = {}
119
112
 
120
113
  if model_reporters is not None:
@@ -125,11 +118,6 @@ class DataCollector:
125
118
  for name, reporter in agent_reporters.items():
126
119
  self._new_agent_reporter(name, reporter)
127
120
 
128
- if agenttype_reporters is not None:
129
- for agent_type, reporters in agenttype_reporters.items():
130
- for name, reporter in reporters.items():
131
- self._new_agenttype_reporter(agent_type, name, reporter)
132
-
133
121
  if tables is not None:
134
122
  for name, columns in tables.items():
135
123
  self._new_table(name, columns)
@@ -177,38 +165,6 @@ class DataCollector:
177
165
 
178
166
  self.agent_reporters[name] = reporter
179
167
 
180
- def _new_agenttype_reporter(self, agent_type, name, reporter):
181
- """Add a new agent-type-level reporter to collect.
182
-
183
- Args:
184
- agent_type: The type of agent to collect data for.
185
- name: Name of the agent-type-level variable to collect.
186
- reporter: Attribute string, function object, method of a class/instance, or
187
- function with parameters placed in a list that returns the
188
- variable when given an agent instance.
189
- """
190
- if agent_type not in self.agenttype_reporters:
191
- self.agenttype_reporters[agent_type] = {}
192
-
193
- # Use the same logic as _new_agent_reporter
194
- if isinstance(reporter, str):
195
- attribute_name = reporter
196
-
197
- def attr_reporter(agent):
198
- return getattr(agent, attribute_name, None)
199
-
200
- reporter = attr_reporter
201
-
202
- elif isinstance(reporter, list):
203
- func, params = reporter[0], reporter[1]
204
-
205
- def func_with_params(agent):
206
- return func(agent, *params)
207
-
208
- reporter = func_with_params
209
-
210
- self.agenttype_reporters[agent_type][name] = reporter
211
-
212
168
  def _new_table(self, table_name, table_columns):
213
169
  """Add a new table that objects can write to.
214
170
 
@@ -224,7 +180,7 @@ class DataCollector:
224
180
  rep_funcs = self.agent_reporters.values()
225
181
 
226
182
  def get_reports(agent):
227
- _prefix = (agent.model.steps, agent.unique_id)
183
+ _prefix = (agent.model._steps, agent.unique_id)
228
184
  reports = tuple(rep(agent) for rep in rep_funcs)
229
185
  return _prefix + reports
230
186
 
@@ -236,34 +192,6 @@ class DataCollector:
236
192
  )
237
193
  return agent_records
238
194
 
239
- def _record_agenttype(self, model, agent_type):
240
- """Record agent-type data in a mapping of functions and agents."""
241
- rep_funcs = self.agenttype_reporters[agent_type].values()
242
-
243
- def get_reports(agent):
244
- _prefix = (agent.model.steps, agent.unique_id)
245
- reports = tuple(rep(agent) for rep in rep_funcs)
246
- return _prefix + reports
247
-
248
- agent_types = model.agent_types
249
- if agent_type in agent_types:
250
- agents = model.agents_by_type[agent_type]
251
- else:
252
- from mesa import Agent
253
-
254
- if issubclass(agent_type, Agent):
255
- agents = [
256
- agent for agent in model.agents if isinstance(agent, agent_type)
257
- ]
258
- else:
259
- # Raise error if agent_type is not in model.agent_types
260
- raise ValueError(
261
- f"Agent type {agent_type} is not recognized as an Agent type in the model or Agent subclass. Use an Agent (sub)class, like {agent_types}."
262
- )
263
-
264
- agenttype_records = map(get_reports, agents)
265
- return agenttype_records
266
-
267
195
  def collect(self, model):
268
196
  """Collect all the data for the given model object."""
269
197
  if self.model_reporters:
@@ -282,20 +210,13 @@ class DataCollector:
282
210
  elif isinstance(reporter, list):
283
211
  self.model_vars[var].append(deepcopy(reporter[0](*reporter[1])))
284
212
  # Assume it's a callable otherwise (e.g., method)
213
+ # TODO: Check if method of a class explicitly
285
214
  else:
286
215
  self.model_vars[var].append(deepcopy(reporter()))
287
216
 
288
217
  if self.agent_reporters:
289
218
  agent_records = self._record_agents(model)
290
- self._agent_records[model.steps] = list(agent_records)
291
-
292
- if self.agenttype_reporters:
293
- self._agenttype_records[model.steps] = {}
294
- for agent_type in self.agenttype_reporters:
295
- agenttype_records = self._record_agenttype(model, agent_type)
296
- self._agenttype_records[model.steps][agent_type] = list(
297
- agenttype_records
298
- )
219
+ self._agent_records[model._steps] = list(agent_records)
299
220
 
300
221
  def add_table_row(self, table_name, row, ignore_missing=False):
301
222
  """Add a row dictionary to a specific table.
@@ -353,38 +274,6 @@ class DataCollector:
353
274
  )
354
275
  return df
355
276
 
356
- def get_agenttype_vars_dataframe(self, agent_type):
357
- """Create a pandas DataFrame from the agent-type variables for a specific agent type.
358
-
359
- The DataFrame has one column for each variable, with two additional
360
- columns for tick and agent_id.
361
-
362
- Args:
363
- agent_type: The type of agent to get the data for.
364
- """
365
- # Check if self.agenttype_reporters dictionary is empty for this agent type, if so return empty DataFrame
366
- if agent_type not in self.agenttype_reporters:
367
- warnings.warn(
368
- f"No agent-type reporters have been defined for {agent_type} in the DataCollector, returning empty DataFrame.",
369
- UserWarning,
370
- stacklevel=2,
371
- )
372
- return pd.DataFrame()
373
-
374
- all_records = itertools.chain.from_iterable(
375
- records[agent_type]
376
- for records in self._agenttype_records.values()
377
- if agent_type in records
378
- )
379
- rep_names = list(self.agenttype_reporters[agent_type])
380
-
381
- df = pd.DataFrame.from_records(
382
- data=all_records,
383
- columns=["Step", "AgentID", *rep_names],
384
- index=["Step", "AgentID"],
385
- )
386
- return df
387
-
388
277
  def get_table_dataframe(self, table_name):
389
278
  """Create a pandas DataFrame from a particular table.
390
279
 
@@ -1,13 +1,3 @@
1
- """Experimental init."""
2
-
3
1
  from mesa.experimental import cell_space
4
2
 
5
- try:
6
- from .solara_viz import JupyterViz, Slider, SolaraViz, make_text
7
-
8
- __all__ = ["cell_space", "JupyterViz", "Slider", "SolaraViz", "make_text"]
9
- except ImportError:
10
- print(
11
- "Could not import SolaraViz. If you need it, install with 'pip install --pre mesa[viz]'"
12
- )
13
- __all__ = ["cell_space"]
3
+ __all__ = ["cell_space"]
@@ -1,16 +1,5 @@
1
- """Cell spaces.
2
-
3
- Cell spaces offer an alternative API for discrete spaces. It is experimental and under development. The API is more
4
- expressive that the default grids available in `mesa.space`.
5
-
6
- """
7
-
8
1
  from mesa.experimental.cell_space.cell import Cell
9
- from mesa.experimental.cell_space.cell_agent import (
10
- CellAgent,
11
- FixedAgent,
12
- Grid2DMovingAgent,
13
- )
2
+ from mesa.experimental.cell_space.cell_agent import CellAgent
14
3
  from mesa.experimental.cell_space.cell_collection import CellCollection
15
4
  from mesa.experimental.cell_space.discrete_space import DiscreteSpace
16
5
  from mesa.experimental.cell_space.grid import (
@@ -20,19 +9,15 @@ from mesa.experimental.cell_space.grid import (
20
9
  OrthogonalVonNeumannGrid,
21
10
  )
22
11
  from mesa.experimental.cell_space.network import Network
23
- from mesa.experimental.cell_space.voronoi import VoronoiGrid
24
12
 
25
13
  __all__ = [
26
14
  "CellCollection",
27
15
  "Cell",
28
16
  "CellAgent",
29
- "Grid2DMovingAgent",
30
- "FixedAgent",
31
17
  "DiscreteSpace",
32
18
  "Grid",
33
19
  "HexGrid",
34
20
  "OrthogonalMooreGrid",
35
21
  "OrthogonalVonNeumannGrid",
36
22
  "Network",
37
- "VoronoiGrid",
38
23
  ]