Mesa 3.0.0b1__py3-none-any.whl → 3.0.0rc0__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 (111) hide show
  1. mesa/__init__.py +1 -3
  2. mesa/agent.py +23 -8
  3. mesa/batchrunner.py +26 -1
  4. {examples → mesa/examples}/README.md +11 -11
  5. mesa/examples/__init__.py +21 -0
  6. {examples → mesa/examples}/advanced/epstein_civil_violence/Readme.md +3 -2
  7. examples/advanced/epstein_civil_violence/epstein_civil_violence/agent.py → mesa/examples/advanced/epstein_civil_violence/agents.py +44 -38
  8. mesa/examples/advanced/epstein_civil_violence/app.py +73 -0
  9. mesa/examples/advanced/epstein_civil_violence/model.py +114 -0
  10. examples/advanced/pd_grid/readme.md → mesa/examples/advanced/pd_grid/Readme.md +4 -3
  11. mesa/examples/advanced/pd_grid/app.py +54 -0
  12. {examples/advanced/pd_grid → mesa/examples/advanced}/pd_grid/model.py +1 -2
  13. {examples → mesa/examples}/advanced/sugarscape_g1mt/Readme.md +6 -29
  14. examples/advanced/sugarscape_g1mt/sugarscape_g1mt/trader_agents.py → mesa/examples/advanced/sugarscape_g1mt/agents.py +26 -3
  15. {examples → mesa/examples}/advanced/sugarscape_g1mt/app.py +19 -18
  16. {examples/advanced/sugarscape_g1mt → mesa/examples/advanced}/sugarscape_g1mt/model.py +6 -6
  17. {examples → mesa/examples}/advanced/sugarscape_g1mt/tests.py +3 -6
  18. mesa/examples/advanced/wolf_sheep/app.py +84 -0
  19. {examples/advanced/wolf_sheep → mesa/examples/advanced}/wolf_sheep/model.py +9 -8
  20. mesa/examples/basic/boid_flockers/Readme.md +22 -0
  21. {examples → mesa/examples}/basic/boid_flockers/app.py +3 -4
  22. {examples → mesa/examples}/basic/boid_flockers/model.py +1 -2
  23. {examples → mesa/examples}/basic/boltzmann_wealth_model/Readme.md +1 -5
  24. mesa/examples/basic/boltzmann_wealth_model/__init__.py +0 -0
  25. {examples → mesa/examples}/basic/boltzmann_wealth_model/app.py +15 -12
  26. {examples → mesa/examples}/basic/boltzmann_wealth_model/model.py +3 -4
  27. {examples → mesa/examples}/basic/conways_game_of_life/Readme.md +11 -7
  28. mesa/examples/basic/conways_game_of_life/__init__.py +0 -0
  29. {examples → mesa/examples}/basic/conways_game_of_life/agents.py +8 -8
  30. mesa/examples/basic/conways_game_of_life/app.py +51 -0
  31. {examples → mesa/examples}/basic/conways_game_of_life/model.py +3 -4
  32. {examples → mesa/examples}/basic/conways_game_of_life/st_app.py +2 -1
  33. examples/basic/schelling/README.md → mesa/examples/basic/schelling/Readme.md +2 -9
  34. mesa/examples/basic/schelling/__init__.py +0 -0
  35. {examples → mesa/examples}/basic/schelling/app.py +6 -7
  36. {examples → mesa/examples}/basic/schelling/model.py +1 -2
  37. mesa/examples/basic/virus_on_network/__init__.py +0 -0
  38. mesa/examples/basic/virus_on_network/app.py +114 -0
  39. {examples → mesa/examples}/basic/virus_on_network/model.py +4 -7
  40. mesa/experimental/cell_space/discrete_space.py +6 -0
  41. mesa/experimental/devs/eventlist.py +6 -0
  42. mesa/model.py +13 -0
  43. mesa/space.py +70 -35
  44. mesa/visualization/__init__.py +16 -5
  45. mesa/visualization/components/__init__.py +83 -0
  46. mesa/visualization/components/altair_components.py +188 -0
  47. mesa/visualization/components/matplotlib_components.py +176 -0
  48. mesa/visualization/mpl_space_drawing.py +558 -0
  49. mesa/visualization/solara_viz.py +30 -20
  50. {mesa-3.0.0b1.dist-info → mesa-3.0.0rc0.dist-info}/METADATA +1 -3
  51. mesa-3.0.0rc0.dist-info/RECORD +95 -0
  52. examples/advanced/epstein_civil_violence/epstein_civil_violence/model.py +0 -146
  53. examples/advanced/epstein_civil_violence/epstein_civil_violence/portrayal.py +0 -33
  54. examples/advanced/epstein_civil_violence/epstein_civil_violence/server.py +0 -81
  55. examples/advanced/epstein_civil_violence/requirements.txt +0 -3
  56. examples/advanced/epstein_civil_violence/run.py +0 -3
  57. examples/advanced/pd_grid/pd_grid/portrayal.py +0 -19
  58. examples/advanced/pd_grid/pd_grid/server.py +0 -21
  59. examples/advanced/pd_grid/requirements.txt +0 -3
  60. examples/advanced/pd_grid/run.py +0 -3
  61. examples/advanced/sugarscape_g1mt/requirements.txt +0 -6
  62. examples/advanced/sugarscape_g1mt/run.py +0 -105
  63. examples/advanced/sugarscape_g1mt/sugarscape_g1mt/resource_agents.py +0 -26
  64. examples/advanced/sugarscape_g1mt/sugarscape_g1mt/server.py +0 -61
  65. examples/advanced/wolf_sheep/requirements.txt +0 -1
  66. examples/advanced/wolf_sheep/run.py +0 -3
  67. examples/advanced/wolf_sheep/wolf_sheep/resources/sheep.png +0 -0
  68. examples/advanced/wolf_sheep/wolf_sheep/resources/wolf.png +0 -0
  69. examples/advanced/wolf_sheep/wolf_sheep/server.py +0 -78
  70. examples/basic/__init__.py +0 -13
  71. examples/basic/boid_flockers/Readme.md +0 -43
  72. examples/basic/conways_game_of_life/portrayal.py +0 -18
  73. examples/basic/conways_game_of_life/requirements.txt +0 -1
  74. examples/basic/conways_game_of_life/server.py +0 -11
  75. examples/basic/virus_on_network/app.py +0 -133
  76. mesa/cookiecutter-mesa/cookiecutter.json +0 -8
  77. mesa/cookiecutter-mesa/hooks/post_gen_project.py +0 -13
  78. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/README.md +0 -4
  79. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/app.pytemplate +0 -27
  80. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/setup.pytemplate +0 -11
  81. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}}/__init__.py +0 -1
  82. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}}/model.pytemplate +0 -60
  83. mesa/examples.py +0 -3
  84. mesa/main.py +0 -65
  85. mesa/visualization/components/altair.py +0 -88
  86. mesa/visualization/components/matplotlib.py +0 -342
  87. mesa-3.0.0b1.dist-info/RECORD +0 -114
  88. {examples → mesa/examples/advanced}/__init__.py +0 -0
  89. {examples → mesa/examples}/advanced/epstein_civil_violence/Epstein Civil Violence.ipynb +0 -0
  90. {examples/advanced → mesa/examples/advanced/epstein_civil_violence}/__init__.py +0 -0
  91. {examples/advanced/epstein_civil_violence/epstein_civil_violence → mesa/examples/advanced/pd_grid}/__init__.py +0 -0
  92. /examples/advanced/pd_grid/pd_grid/agent.py → /mesa/examples/advanced/pd_grid/agents.py +0 -0
  93. {examples → mesa/examples}/advanced/pd_grid/analysis.ipynb +0 -0
  94. {examples/advanced/pd_grid/pd_grid → mesa/examples/advanced/sugarscape_g1mt}/__init__.py +0 -0
  95. {examples/advanced/sugarscape_g1mt → mesa/examples/advanced}/sugarscape_g1mt/sugar-map.txt +0 -0
  96. {examples → mesa/examples}/advanced/wolf_sheep/Readme.md +0 -0
  97. {examples/advanced/sugarscape_g1mt/sugarscape_g1mt → mesa/examples/advanced/wolf_sheep}/__init__.py +0 -0
  98. {examples/advanced/wolf_sheep → mesa/examples/advanced}/wolf_sheep/agents.py +0 -0
  99. {examples/advanced/wolf_sheep → mesa/examples/basic}/__init__.py +0 -0
  100. {examples/advanced/wolf_sheep/wolf_sheep → mesa/examples/basic/boid_flockers}/__init__.py +0 -0
  101. {examples → mesa/examples}/basic/boid_flockers/agents.py +0 -0
  102. {examples → mesa/examples}/basic/boltzmann_wealth_model/agents.py +0 -0
  103. {examples → mesa/examples}/basic/boltzmann_wealth_model/st_app.py +0 -0
  104. {examples → mesa/examples}/basic/schelling/agents.py +0 -0
  105. {examples → mesa/examples}/basic/schelling/analysis.ipynb +0 -0
  106. /examples/basic/virus_on_network/README.md → /mesa/examples/basic/virus_on_network/Readme.md +0 -0
  107. {examples → mesa/examples}/basic/virus_on_network/agents.py +0 -0
  108. {mesa-3.0.0b1.dist-info → mesa-3.0.0rc0.dist-info}/WHEEL +0 -0
  109. {mesa-3.0.0b1.dist-info → mesa-3.0.0rc0.dist-info}/entry_points.txt +0 -0
  110. {mesa-3.0.0b1.dist-info → mesa-3.0.0rc0.dist-info}/licenses/LICENSE +0 -0
  111. {mesa-3.0.0b1.dist-info → mesa-3.0.0rc0.dist-info}/licenses/NOTICE +0 -0
@@ -0,0 +1,188 @@
1
+ """Altair based solara components for visualization mesa spaces."""
2
+
3
+ import contextlib
4
+ import warnings
5
+
6
+ import solara
7
+
8
+ with contextlib.suppress(ImportError):
9
+ import altair as alt
10
+
11
+ from mesa.experimental.cell_space import DiscreteSpace, Grid
12
+ from mesa.space import ContinuousSpace, _Grid
13
+ from mesa.visualization.utils import update_counter
14
+
15
+
16
+ def make_space_altair(*args, **kwargs): # noqa: D103
17
+ warnings.warn(
18
+ "make_space_altair has been renamed to make_altair_space",
19
+ DeprecationWarning,
20
+ stacklevel=2,
21
+ )
22
+ return make_altair_space(*args, **kwargs)
23
+
24
+
25
+ def make_altair_space(
26
+ agent_portrayal, propertylayer_portrayal, post_process, **space_drawing_kwargs
27
+ ):
28
+ """Create an Altair-based space visualization component.
29
+
30
+ Args:
31
+ agent_portrayal: Function to portray agents.
32
+ propertylayer_portrayal: not yet implemented
33
+ post_process :not yet implemented
34
+ space_drawing_kwargs : not yet implemented
35
+
36
+ ``agent_portrayal`` is called with an agent and should return a dict. Valid fields in this dict are "color",
37
+ "size", "marker", and "zorder". Other field are ignored and will result in a user warning.
38
+
39
+
40
+ Returns:
41
+ function: A function that creates a SpaceMatplotlib component
42
+ """
43
+ if agent_portrayal is None:
44
+
45
+ def agent_portrayal(a):
46
+ return {"id": a.unique_id}
47
+
48
+ def MakeSpaceAltair(model):
49
+ return SpaceAltair(model, agent_portrayal)
50
+
51
+ return MakeSpaceAltair
52
+
53
+
54
+ @solara.component
55
+ def SpaceAltair(model, agent_portrayal, dependencies: list[any] | None = None):
56
+ """Create an Altair-based space visualization component.
57
+
58
+ Returns:
59
+ a solara FigureAltair instance
60
+ """
61
+ update_counter.get()
62
+ space = getattr(model, "grid", None)
63
+ if space is None:
64
+ # Sometimes the space is defined as model.space instead of model.grid
65
+ space = model.space
66
+
67
+ chart = _draw_grid(space, agent_portrayal)
68
+ solara.FigureAltair(chart)
69
+
70
+
71
+ def _get_agent_data_old__discrete_space(space, agent_portrayal):
72
+ """Format agent portrayal data for old-style discrete spaces.
73
+
74
+ Args:
75
+ space: the mesa.space._Grid instance
76
+ agent_portrayal: the agent portrayal callable
77
+
78
+ Returns:
79
+ list of dicts
80
+
81
+ """
82
+ all_agent_data = []
83
+ for content, (x, y) in space.coord_iter():
84
+ if not content:
85
+ continue
86
+ if not hasattr(content, "__iter__"):
87
+ # Is a single grid
88
+ content = [content] # noqa: PLW2901
89
+ for agent in content:
90
+ # use all data from agent portrayal, and add x,y coordinates
91
+ agent_data = agent_portrayal(agent)
92
+ agent_data["x"] = x
93
+ agent_data["y"] = y
94
+ all_agent_data.append(agent_data)
95
+ return all_agent_data
96
+
97
+
98
+ def _get_agent_data_new_discrete_space(space: DiscreteSpace, agent_portrayal):
99
+ """Format agent portrayal data for new-style discrete spaces.
100
+
101
+ Args:
102
+ space: the mesa.experiment.cell_space.Grid instance
103
+ agent_portrayal: the agent portrayal callable
104
+
105
+ Returns:
106
+ list of dicts
107
+
108
+ """
109
+ all_agent_data = []
110
+
111
+ for cell in space.all_cells:
112
+ for agent in cell.agents:
113
+ agent_data = agent_portrayal(agent)
114
+ agent_data["x"] = cell.coordinate[0]
115
+ agent_data["y"] = cell.coordinate[1]
116
+ all_agent_data.append(agent_data)
117
+ return all_agent_data
118
+
119
+
120
+ def _get_agent_data_continuous_space(space: ContinuousSpace, agent_portrayal):
121
+ """Format agent portrayal data for continuous space.
122
+
123
+ Args:
124
+ space: the ContinuousSpace instance
125
+ agent_portrayal: the agent portrayal callable
126
+
127
+ Returns:
128
+ list of dicts
129
+ """
130
+ all_agent_data = []
131
+ for agent in space._agent_to_index:
132
+ agent_data = agent_portrayal(agent)
133
+ agent_data["x"] = agent.pos[0]
134
+ agent_data["y"] = agent.pos[1]
135
+ all_agent_data.append(agent_data)
136
+ return all_agent_data
137
+
138
+
139
+ def _draw_grid(space, agent_portrayal):
140
+ match space:
141
+ case Grid():
142
+ all_agent_data = _get_agent_data_new_discrete_space(space, agent_portrayal)
143
+ case _Grid():
144
+ all_agent_data = _get_agent_data_old__discrete_space(space, agent_portrayal)
145
+ case ContinuousSpace():
146
+ all_agent_data = _get_agent_data_continuous_space(space, agent_portrayal)
147
+ case _:
148
+ raise NotImplementedError(
149
+ f"visualizing {type(space)} is currently not supported through altair"
150
+ )
151
+
152
+ invalid_tooltips = ["color", "size", "x", "y"]
153
+
154
+ x_y_type = "ordinal" if not isinstance(space, ContinuousSpace) else "nominal"
155
+
156
+ encoding_dict = {
157
+ # no x-axis label
158
+ "x": alt.X("x", axis=None, type=x_y_type),
159
+ # no y-axis label
160
+ "y": alt.Y("y", axis=None, type=x_y_type),
161
+ "tooltip": [
162
+ alt.Tooltip(key, type=alt.utils.infer_vegalite_type([value]))
163
+ for key, value in all_agent_data[0].items()
164
+ if key not in invalid_tooltips
165
+ ],
166
+ }
167
+ has_color = "color" in all_agent_data[0]
168
+ if has_color:
169
+ encoding_dict["color"] = alt.Color("color", type="nominal")
170
+ has_size = "size" in all_agent_data[0]
171
+ if has_size:
172
+ encoding_dict["size"] = alt.Size("size", type="quantitative")
173
+
174
+ chart = (
175
+ alt.Chart(
176
+ alt.Data(values=all_agent_data), encoding=alt.Encoding(**encoding_dict)
177
+ )
178
+ .mark_point(filled=True)
179
+ .properties(width=280, height=280)
180
+ # .configure_view(strokeOpacity=0) # hide grid/chart lines
181
+ )
182
+ # This is the default value for the marker size, which auto-scales
183
+ # according to the grid area.
184
+ if not has_size:
185
+ length = min(space.width, space.height)
186
+ chart = chart.mark_point(size=30000 / length**2, filled=True)
187
+
188
+ return chart
@@ -0,0 +1,176 @@
1
+ """Matplotlib based solara components for visualization MESA spaces and plots."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import warnings
6
+ from collections.abc import Callable
7
+
8
+ import matplotlib.pyplot as plt
9
+ import solara
10
+ from matplotlib.figure import Figure
11
+
12
+ from mesa.visualization.mpl_space_drawing import draw_space
13
+ from mesa.visualization.utils import update_counter
14
+
15
+
16
+ def make_space_matplotlib(*args, **kwargs): # noqa: D103
17
+ warnings.warn(
18
+ "make_space_matplotlib has been renamed to make_mpl_space_component",
19
+ DeprecationWarning,
20
+ stacklevel=2,
21
+ )
22
+ return make_mpl_space_component(*args, **kwargs)
23
+
24
+
25
+ def make_mpl_space_component(
26
+ agent_portrayal: Callable | None = None,
27
+ propertylayer_portrayal: dict | None = None,
28
+ post_process: Callable | None = None,
29
+ **space_drawing_kwargs,
30
+ ) -> SpaceMatplotlib:
31
+ """Create a Matplotlib-based space visualization component.
32
+
33
+ Args:
34
+ agent_portrayal: Function to portray agents.
35
+ propertylayer_portrayal: Dictionary of PropertyLayer portrayal specifications
36
+ post_process : a callable that will be called with the Axes instance. Allows for fine tuning plots (e.g., control ticks)
37
+ space_drawing_kwargs : additional keyword arguments to be passed on to the underlying space drawer function. See
38
+ the functions for drawing the various spaces for further details.
39
+
40
+ ``agent_portrayal`` is called with an agent and should return a dict. Valid fields in this dict are "color",
41
+ "size", "marker", and "zorder". Other field are ignored and will result in a user warning.
42
+
43
+
44
+ Returns:
45
+ function: A function that creates a SpaceMatplotlib component
46
+ """
47
+ if agent_portrayal is None:
48
+
49
+ def agent_portrayal(a):
50
+ return {}
51
+
52
+ def MakeSpaceMatplotlib(model):
53
+ return SpaceMatplotlib(
54
+ model,
55
+ agent_portrayal,
56
+ propertylayer_portrayal,
57
+ post_process=post_process,
58
+ **space_drawing_kwargs,
59
+ )
60
+
61
+ return MakeSpaceMatplotlib
62
+
63
+
64
+ @solara.component
65
+ def SpaceMatplotlib(
66
+ model,
67
+ agent_portrayal,
68
+ propertylayer_portrayal,
69
+ dependencies: list[any] | None = None,
70
+ post_process: Callable | None = None,
71
+ **space_drawing_kwargs,
72
+ ):
73
+ """Create a Matplotlib-based space visualization component."""
74
+ update_counter.get()
75
+
76
+ space = getattr(model, "grid", None)
77
+ if space is None:
78
+ space = getattr(model, "space", None)
79
+
80
+ fig = Figure()
81
+ ax = fig.add_subplot()
82
+
83
+ draw_space(
84
+ space,
85
+ agent_portrayal,
86
+ propertylayer_portrayal=propertylayer_portrayal,
87
+ ax=ax,
88
+ **space_drawing_kwargs,
89
+ )
90
+
91
+ if post_process is not None:
92
+ post_process(ax)
93
+
94
+ solara.FigureMatplotlib(
95
+ fig, format="png", bbox_inches="tight", dependencies=dependencies
96
+ )
97
+
98
+
99
+ def make_plot_measure(*args, **kwargs): # noqa: D103
100
+ warnings.warn(
101
+ "make_plot_measure has been renamed to make_plot_component",
102
+ DeprecationWarning,
103
+ stacklevel=2,
104
+ )
105
+ return make_mpl_plot_component(*args, **kwargs)
106
+
107
+
108
+ def make_mpl_plot_component(
109
+ measure: str | dict[str, str] | list[str] | tuple[str],
110
+ post_process: Callable | None = None,
111
+ save_format="png",
112
+ ):
113
+ """Create a plotting function for a specified measure.
114
+
115
+ Args:
116
+ measure (str | dict[str, str] | list[str] | tuple[str]): Measure(s) to plot.
117
+ post_process: a user-specified callable to do post-processing called with the Axes instance.
118
+ save_format: save format of figure in solara backend
119
+
120
+ Returns:
121
+ function: A function that creates a PlotMatplotlib component.
122
+ """
123
+
124
+ def MakePlotMatplotlib(model):
125
+ return PlotMatplotlib(
126
+ model, measure, post_process=post_process, save_format=save_format
127
+ )
128
+
129
+ return MakePlotMatplotlib
130
+
131
+
132
+ @solara.component
133
+ def PlotMatplotlib(
134
+ model,
135
+ measure,
136
+ dependencies: list[any] | None = None,
137
+ post_process: Callable | None = None,
138
+ save_format="png",
139
+ ):
140
+ """Create a Matplotlib-based plot for a measure or measures.
141
+
142
+ Args:
143
+ model (mesa.Model): The model instance.
144
+ measure (str | dict[str, str] | list[str] | tuple[str]): Measure(s) to plot.
145
+ dependencies (list[any] | None): Optional dependencies for the plot.
146
+ post_process: a user-specified callable to do post-processing called with the Axes instance.
147
+ save_format: format used for saving the figure.
148
+
149
+ Returns:
150
+ solara.FigureMatplotlib: A component for rendering the plot.
151
+ """
152
+ update_counter.get()
153
+ fig = Figure()
154
+ ax = fig.subplots()
155
+ df = model.datacollector.get_model_vars_dataframe()
156
+ if isinstance(measure, str):
157
+ ax.plot(df.loc[:, measure])
158
+ ax.set_ylabel(measure)
159
+ elif isinstance(measure, dict):
160
+ for m, color in measure.items():
161
+ ax.plot(df.loc[:, m], label=m, color=color)
162
+ ax.legend(loc="best")
163
+ elif isinstance(measure, list | tuple):
164
+ for m in measure:
165
+ ax.plot(df.loc[:, m], label=m)
166
+ ax.legend(loc="best")
167
+
168
+ if post_process is not None:
169
+ post_process(ax)
170
+
171
+ ax.set_xlabel("Step")
172
+ # Set integer x axis
173
+ ax.xaxis.set_major_locator(plt.MaxNLocator(integer=True))
174
+ solara.FigureMatplotlib(
175
+ fig, format=save_format, bbox_inches="tight", dependencies=dependencies
176
+ )