Mesa 3.2.0.dev0__py3-none-any.whl → 3.3.0__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 (58) hide show
  1. mesa/__init__.py +1 -1
  2. mesa/agent.py +9 -7
  3. mesa/datacollection.py +1 -1
  4. mesa/examples/README.md +1 -1
  5. mesa/examples/__init__.py +2 -0
  6. mesa/examples/advanced/alliance_formation/Readme.md +50 -0
  7. mesa/examples/advanced/alliance_formation/__init__ .py +0 -0
  8. mesa/examples/advanced/alliance_formation/agents.py +20 -0
  9. mesa/examples/advanced/alliance_formation/app.py +71 -0
  10. mesa/examples/advanced/alliance_formation/model.py +184 -0
  11. mesa/examples/advanced/epstein_civil_violence/app.py +11 -11
  12. mesa/examples/advanced/pd_grid/Readme.md +4 -6
  13. mesa/examples/advanced/pd_grid/app.py +10 -11
  14. mesa/examples/advanced/sugarscape_g1mt/Readme.md +4 -5
  15. mesa/examples/advanced/sugarscape_g1mt/app.py +34 -16
  16. mesa/examples/advanced/wolf_sheep/Readme.md +2 -17
  17. mesa/examples/advanced/wolf_sheep/app.py +21 -18
  18. mesa/examples/basic/boid_flockers/Readme.md +6 -1
  19. mesa/examples/basic/boid_flockers/app.py +15 -11
  20. mesa/examples/basic/boltzmann_wealth_model/Readme.md +2 -12
  21. mesa/examples/basic/boltzmann_wealth_model/app.py +39 -32
  22. mesa/examples/basic/conways_game_of_life/Readme.md +1 -9
  23. mesa/examples/basic/conways_game_of_life/app.py +13 -16
  24. mesa/examples/basic/schelling/Readme.md +2 -10
  25. mesa/examples/basic/schelling/agents.py +9 -3
  26. mesa/examples/basic/schelling/app.py +50 -3
  27. mesa/examples/basic/schelling/model.py +2 -0
  28. mesa/examples/basic/schelling/resources/blue_happy.png +0 -0
  29. mesa/examples/basic/schelling/resources/blue_unhappy.png +0 -0
  30. mesa/examples/basic/schelling/resources/orange_happy.png +0 -0
  31. mesa/examples/basic/schelling/resources/orange_unhappy.png +0 -0
  32. mesa/examples/basic/virus_on_network/Readme.md +0 -4
  33. mesa/examples/basic/virus_on_network/app.py +31 -14
  34. mesa/experimental/__init__.py +2 -2
  35. mesa/experimental/continuous_space/continuous_space.py +1 -1
  36. mesa/experimental/meta_agents/__init__.py +25 -0
  37. mesa/experimental/meta_agents/meta_agent.py +387 -0
  38. mesa/model.py +3 -3
  39. mesa/space.py +4 -1
  40. mesa/visualization/__init__.py +2 -0
  41. mesa/visualization/backends/__init__.py +23 -0
  42. mesa/visualization/backends/abstract_renderer.py +97 -0
  43. mesa/visualization/backends/altair_backend.py +440 -0
  44. mesa/visualization/backends/matplotlib_backend.py +419 -0
  45. mesa/visualization/components/__init__.py +28 -8
  46. mesa/visualization/components/altair_components.py +86 -0
  47. mesa/visualization/components/matplotlib_components.py +4 -2
  48. mesa/visualization/components/portrayal_components.py +120 -0
  49. mesa/visualization/mpl_space_drawing.py +292 -129
  50. mesa/visualization/solara_viz.py +274 -32
  51. mesa/visualization/space_drawers.py +797 -0
  52. mesa/visualization/space_renderer.py +399 -0
  53. {mesa-3.2.0.dev0.dist-info → mesa-3.3.0.dist-info}/METADATA +13 -4
  54. {mesa-3.2.0.dev0.dist-info → mesa-3.3.0.dist-info}/RECORD +57 -40
  55. mesa/examples/advanced/sugarscape_g1mt/tests.py +0 -69
  56. {mesa-3.2.0.dev0.dist-info → mesa-3.3.0.dist-info}/WHEEL +0 -0
  57. {mesa-3.2.0.dev0.dist-info → mesa-3.3.0.dist-info}/licenses/LICENSE +0 -0
  58. {mesa-3.2.0.dev0.dist-info → mesa-3.3.0.dist-info}/licenses/NOTICE +0 -0
@@ -14,29 +14,14 @@ The model is tests and demonstrates several Mesa concepts and features:
14
14
  - Writing a model composed of multiple files.
15
15
  - Dynamically adding and removing agents from the schedule
16
16
 
17
- ## Installation
18
-
19
- To install the dependencies use pip and the requirements.txt in this directory. e.g.
20
-
21
- ```
22
- # First, we clone the Mesa repo
23
- $ git clone https://github.com/projectmesa/mesa.git
24
- $ cd mesa
25
- # Then we cd to the example directory
26
- $ cd examples/wolf_sheep
27
- $ pip install -r requirements.txt
28
- ```
29
-
30
17
  ## How to Run
31
18
 
32
- To run the model interactively, run ``mesa runserver`` in this directory. e.g.
19
+ To run the model interactively, in this directory, run the following command
33
20
 
34
21
  ```
35
- $ mesa runserver
22
+ $ solara run app.py
36
23
  ```
37
24
 
38
- Then open your browser to [http://127.0.0.1:8521/](http://127.0.0.1:8521/) and press Reset, then Run.
39
-
40
25
  ## Files
41
26
 
42
27
  * ``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.
@@ -5,34 +5,32 @@ from mesa.visualization import (
5
5
  CommandConsole,
6
6
  Slider,
7
7
  SolaraViz,
8
+ SpaceRenderer,
8
9
  make_plot_component,
9
- make_space_component,
10
10
  )
11
+ from mesa.visualization.components import AgentPortrayalStyle
11
12
 
12
13
 
13
14
  def wolf_sheep_portrayal(agent):
14
15
  if agent is None:
15
16
  return
16
17
 
17
- portrayal = {
18
- "size": 25,
19
- }
18
+ portrayal = AgentPortrayalStyle(
19
+ size=50,
20
+ marker="o",
21
+ zorder=2,
22
+ )
20
23
 
21
24
  if isinstance(agent, Wolf):
22
- portrayal["color"] = "tab:red"
23
- portrayal["marker"] = "o"
24
- portrayal["zorder"] = 2
25
+ portrayal.update(("color", "red"))
25
26
  elif isinstance(agent, Sheep):
26
- portrayal["color"] = "tab:cyan"
27
- portrayal["marker"] = "o"
28
- portrayal["zorder"] = 2
27
+ portrayal.update(("color", "cyan"))
29
28
  elif isinstance(agent, GrassPatch):
30
29
  if agent.fully_grown:
31
- portrayal["color"] = "tab:green"
30
+ portrayal.update(("color", "tab:green"))
32
31
  else:
33
- portrayal["color"] = "tab:brown"
34
- portrayal["marker"] = "s"
35
- portrayal["size"] = 75
32
+ portrayal.update(("color", "tab:brown"))
33
+ portrayal.update(("marker", "s"), ("size", 125), ("zorder", 1))
36
34
 
37
35
  return portrayal
38
36
 
@@ -75,9 +73,6 @@ def post_process_lines(ax):
75
73
  ax.legend(loc="center left", bbox_to_anchor=(1, 0.9))
76
74
 
77
75
 
78
- space_component = make_space_component(
79
- wolf_sheep_portrayal, draw_grid=False, post_process=post_process_space
80
- )
81
76
  lineplot_component = make_plot_component(
82
77
  {"Wolves": "tab:orange", "Sheep": "tab:cyan", "Grass": "tab:green"},
83
78
  post_process=post_process_lines,
@@ -86,9 +81,17 @@ lineplot_component = make_plot_component(
86
81
  simulator = ABMSimulator()
87
82
  model = WolfSheep(simulator=simulator, grass=True)
88
83
 
84
+ renderer = SpaceRenderer(
85
+ model,
86
+ backend="matplotlib",
87
+ )
88
+ renderer.draw_agents(wolf_sheep_portrayal)
89
+ renderer.post_process = post_process_space
90
+
89
91
  page = SolaraViz(
90
92
  model,
91
- components=[space_component, lineplot_component, CommandConsole],
93
+ renderer,
94
+ components=[lineplot_component, CommandConsole],
92
95
  model_params=model_params,
93
96
  name="Wolf Sheep",
94
97
  simulator=simulator,
@@ -8,7 +8,12 @@ This model tests Mesa's continuous space feature, and uses numpy arrays to repre
8
8
 
9
9
  ## How to Run
10
10
 
11
- * To launch the visualization interactively, run ``solara run app.py`` in this directory.It will automatically open a browser page.
11
+ To run the model interactively, in this directory, run the following command
12
+
13
+ ```
14
+ $ solara run app.py
15
+ ```
16
+
12
17
 
13
18
  ## Files
14
19
 
@@ -1,12 +1,8 @@
1
- import os
2
- import sys
3
-
4
1
  from matplotlib.markers import MarkerStyle
5
2
 
6
- sys.path.insert(0, os.path.abspath("../../../.."))
7
-
8
3
  from mesa.examples.basic.boid_flockers.model import BoidFlockers
9
- from mesa.visualization import Slider, SolaraViz, make_space_component
4
+ from mesa.visualization import Slider, SolaraViz, SpaceRenderer
5
+ from mesa.visualization.components import AgentPortrayalStyle
10
6
 
11
7
  # Pre-compute markers for different angles (e.g., every 10 degrees)
12
8
  MARKER_CACHE = {}
@@ -25,10 +21,12 @@ def boid_draw(agent):
25
21
  rounded_deg = round(deg / 10) * 10 % 360
26
22
 
27
23
  # using cached markers to speed things up
28
- if neighbors <= 1:
29
- return {"color": "red", "size": 20, "marker": MARKER_CACHE[rounded_deg]}
30
- elif neighbors >= 2:
31
- return {"color": "green", "size": 20, "marker": MARKER_CACHE[rounded_deg]}
24
+ boid_style = AgentPortrayalStyle(
25
+ color="red", size=20, marker=MARKER_CACHE[rounded_deg]
26
+ )
27
+ if neighbors >= 2:
28
+ boid_style.update(("color", "green"), ("marker", MARKER_CACHE[rounded_deg]))
29
+ return boid_style
32
30
 
33
31
 
34
32
  model_params = {
@@ -71,9 +69,15 @@ model_params = {
71
69
 
72
70
  model = BoidFlockers()
73
71
 
72
+ # Quickest way to visualize grid along with agents or property layers.
73
+ renderer = SpaceRenderer(
74
+ model,
75
+ backend="matplotlib",
76
+ ).render(agent_portrayal=boid_draw)
77
+
74
78
  page = SolaraViz(
75
79
  model,
76
- components=[make_space_component(agent_portrayal=boid_draw, backend="matplotlib")],
80
+ renderer,
77
81
  model_params=model_params,
78
82
  name="Boid Flocking Model",
79
83
  )
@@ -2,25 +2,18 @@
2
2
 
3
3
  ## Summary
4
4
 
5
- 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.
6
-
7
- 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.
5
+ 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. Mesa's [Getting Started](https://mesa.readthedocs.io/latest/getting_started.html) section walks through the Boltzmann Wealth Model in a series of short introductory tutorials, starting with[Creating your First Model](https://mesa.readthedocs.io/latest/tutorials/0_first_model.html).
8
6
 
9
7
  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.
10
8
 
11
9
  ## How to Run
12
10
 
13
- 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)
14
-
15
-
16
- 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:
11
+ To run the model interactively, in this directory, run the following command
17
12
 
18
13
  ```
19
14
  $ solara run app.py
20
15
  ```
21
16
 
22
- 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.
23
-
24
17
 
25
18
  ## Files
26
19
 
@@ -46,9 +39,6 @@ Then, you can run the Streamlit app using the following command:
46
39
 
47
40
  ## Further Reading
48
41
 
49
- The full tutorial describing how the model is built can be found at:
50
- https://mesa.readthedocs.io/en/latest/tutorials/intro_tutorial.html
51
-
52
42
  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:
53
43
 
54
44
  [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)
@@ -1,17 +1,21 @@
1
+ import altair as alt
2
+
1
3
  from mesa.examples.basic.boltzmann_wealth_model.model import BoltzmannWealth
2
4
  from mesa.mesa_logging import INFO, log_to_stderr
3
5
  from mesa.visualization import (
4
6
  SolaraViz,
7
+ SpaceRenderer,
5
8
  make_plot_component,
6
- make_space_component,
7
9
  )
10
+ from mesa.visualization.components import AgentPortrayalStyle
8
11
 
9
12
  log_to_stderr(INFO)
10
13
 
11
14
 
12
15
  def agent_portrayal(agent):
13
- color = agent.wealth # we are using a colormap to translate wealth to color
14
- return {"color": color}
16
+ return AgentPortrayalStyle(
17
+ color=agent.wealth
18
+ ) # we are using a colormap to translate wealth to color
15
19
 
16
20
 
17
21
  model_params = {
@@ -33,45 +37,48 @@ model_params = {
33
37
  }
34
38
 
35
39
 
36
- def post_process(ax):
37
- ax.get_figure().colorbar(ax.collections[0], label="wealth", ax=ax)
40
+ def post_process(chart):
41
+ """Post-process the Altair chart to add a colorbar legend."""
42
+ chart = chart.encode(
43
+ color=alt.Color(
44
+ "color:N",
45
+ scale=alt.Scale(scheme="viridis", domain=[0, 10]),
46
+ legend=alt.Legend(
47
+ title="Wealth",
48
+ orient="right",
49
+ type="gradient",
50
+ gradientLength=200,
51
+ ),
52
+ ),
53
+ )
54
+ return chart
38
55
 
39
56
 
40
- # Create initial model instance
41
57
  model = BoltzmannWealth(50, 10, 10)
42
58
 
43
- # Create visualization elements. The visualization elements are solara components
44
- # that receive the model instance as a "prop" and display it in a certain way.
45
- # Under the hood these are just classes that receive the model instance.
46
- # You can also author your own visualization elements, which can also be functions
47
- # that receive the model instance and return a valid solara component.
59
+ # The SpaceRenderer is responsible for drawing the model's space and agents.
60
+ # It builds the visualization in layers, first drawing the grid structure,
61
+ # and then drawing the agents on top. It uses a specified backend
62
+ # (like "altair" or "matplotlib") for creating the plots.
63
+ renderer = SpaceRenderer(model, backend="altair")
64
+ # Can customize the grid appearance.
65
+ renderer.draw_structure(grid_color="black", grid_dash=[6, 2], grid_opacity=0.3)
66
+ renderer.draw_agents(agent_portrayal=agent_portrayal, cmap="viridis", vmin=0, vmax=10)
48
67
 
49
- SpaceGraph = make_space_component(
50
- agent_portrayal, cmap="viridis", vmin=0, vmax=10, post_process=post_process
51
- )
68
+ # The post_process function is used to modify the Altair chart after it has been created.
69
+ # It can be used to add legends, colorbars, or other visual elements.
70
+ renderer.post_process = post_process
71
+
72
+ # Creates a line plot component from the model's "Gini" datacollector.
52
73
  GiniPlot = make_plot_component("Gini")
53
74
 
54
- # Create the SolaraViz page. This will automatically create a server and display the
55
- # visualization elements in a web browser.
56
- # Display it using the following command in the example directory:
57
- # solara run app.py
58
- # It will automatically update and display any changes made to this file
75
+ # The SolaraViz page combines the model, renderer, and components into a web interface.
76
+ # To run the visualization, save this code as app.py and run `solara run app.py`
59
77
  page = SolaraViz(
60
78
  model,
61
- components=[SpaceGraph, GiniPlot],
79
+ renderer,
80
+ components=[GiniPlot],
62
81
  model_params=model_params,
63
82
  name="Boltzmann Wealth Model",
64
83
  )
65
84
  page # noqa
66
-
67
-
68
- # In a notebook environment, we can also display the visualization elements directly
69
- # SpaceGraph(model1)
70
- # GiniPlot(model1)
71
-
72
- # The plots will be static. If you want to pick up model steps,
73
- # you have to make the model reactive first
74
- # reactive_model = solara.reactive(model1)
75
- # SpaceGraph(reactive_model)
76
- # In a different notebook block:
77
- # reactive_model.value.step()
@@ -9,20 +9,12 @@ The "game" is a zero-player game, meaning that its evolution is determined by it
9
9
 
10
10
  ## How to Run
11
11
 
12
- To run the model interactively you can use either the streamlit or solara version. For solara, you use
12
+ To run the model interactively, in this directory, run the following command
13
13
 
14
14
  ```
15
15
  $ solara run app.py
16
16
  ```
17
17
 
18
- For streamlit, you need
19
-
20
- ```
21
- $ streamlit run st_app.py
22
- ```
23
-
24
- This will open your browser and show you the controls. You can start the model by hitting the run button.
25
-
26
18
  ## Files
27
19
 
28
20
  * ``agents.py``: Defines the behavior of an individual cell, which can be in two states: DEAD or ALIVE.
@@ -1,16 +1,17 @@
1
1
  from mesa.examples.basic.conways_game_of_life.model import ConwaysGameOfLife
2
2
  from mesa.visualization import (
3
3
  SolaraViz,
4
- make_space_component,
4
+ SpaceRenderer,
5
5
  )
6
+ from mesa.visualization.components import AgentPortrayalStyle
6
7
 
7
8
 
8
9
  def agent_portrayal(agent):
9
- return {
10
- "color": "white" if agent.state == 0 else "black",
11
- "marker": "s",
12
- "size": 25,
13
- }
10
+ return AgentPortrayalStyle(
11
+ color="white" if agent.state == 0 else "black",
12
+ marker="s",
13
+ size=30,
14
+ )
14
15
 
15
16
 
16
17
  def post_process(ax):
@@ -54,15 +55,11 @@ model_params = {
54
55
  # Create initial model instance
55
56
  model1 = ConwaysGameOfLife()
56
57
 
57
- # Create visualization elements. The visualization elements are solara components
58
- # that receive the model instance as a "prop" and display it in a certain way.
59
- # Under the hood these are just classes that receive the model instance.
60
- # You can also author your own visualization elements, which can also be functions
61
- # that receive the model instance and return a valid solara component.
62
- SpaceGraph = make_space_component(
63
- agent_portrayal, post_process=post_process, draw_grid=False
64
- )
65
-
58
+ renderer = SpaceRenderer(model1, backend="matplotlib")
59
+ # In this case the renderer only draws the agents because we just want to observe
60
+ # the state of the agents, not the structure of the grid.
61
+ renderer.draw_agents(agent_portrayal=agent_portrayal)
62
+ renderer.post_process = post_process
66
63
 
67
64
  # Create the SolaraViz page. This will automatically create a server and display the
68
65
  # visualization elements in a web browser.
@@ -71,7 +68,7 @@ SpaceGraph = make_space_component(
71
68
  # It will automatically update and display any changes made to this file
72
69
  page = SolaraViz(
73
70
  model1,
74
- components=[SpaceGraph],
71
+ renderer,
75
72
  model_params=model_params,
76
73
  name="Game of Life",
77
74
  )
@@ -2,9 +2,9 @@
2
2
 
3
3
  ## Summary
4
4
 
5
- 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.
5
+ 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: orange 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.
6
6
 
7
- 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.
7
+ 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 Orange 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.
8
8
 
9
9
  ## How to Run
10
10
 
@@ -14,14 +14,6 @@ To run the model interactively, in this directory, run the following command
14
14
  $ solara run app.py
15
15
  ```
16
16
 
17
- Then open your browser to [http://127.0.0.1:8765/](http://127.0.0.1:8765/) and click the Play button.
18
-
19
- 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/).
20
-
21
- ## How to Run without the GUI
22
-
23
- To run the model with the grid displayed as an ASCII text, run `python run_ascii.py` in this directory.
24
-
25
17
  ## Files
26
18
 
27
19
  * ``model.py``: Contains the Schelling model class
@@ -19,8 +19,9 @@ class SchellingAgent(CellAgent):
19
19
  self.type = agent_type
20
20
  self.homophily = homophily
21
21
  self.radius = radius
22
+ self.happy = False
22
23
 
23
- def step(self) -> None:
24
+ def assign_state(self) -> None:
24
25
  """Determine if agent is happy and move if necessary."""
25
26
  neighbors = list(self.cell.get_neighborhood(radius=self.radius).agents)
26
27
 
@@ -34,8 +35,13 @@ class SchellingAgent(CellAgent):
34
35
  # If there are no neighbors, the similarity fraction is 0
35
36
  similarity_fraction = 0.0
36
37
 
37
- # Move if unhappy
38
38
  if similarity_fraction < self.homophily:
39
- self.cell = self.model.grid.select_random_empty_cell()
39
+ self.happy = False
40
40
  else:
41
+ self.happy = True
41
42
  self.model.happy += 1
43
+
44
+ def step(self) -> None:
45
+ # Move if unhappy
46
+ if not self.happy:
47
+ self.cell = self.model.grid.select_random_empty_cell()
@@ -1,12 +1,15 @@
1
+ import os
2
+
1
3
  import solara
2
4
 
3
5
  from mesa.examples.basic.schelling.model import Schelling
4
6
  from mesa.visualization import (
5
7
  Slider,
6
8
  SolaraViz,
9
+ SpaceRenderer,
7
10
  make_plot_component,
8
- make_space_component,
9
11
  )
12
+ from mesa.visualization.components import AgentPortrayalStyle
10
13
 
11
14
 
12
15
  def get_happy_agents(model):
@@ -14,8 +17,45 @@ def get_happy_agents(model):
14
17
  return solara.Markdown(f"**Happy agents: {model.happy}**")
15
18
 
16
19
 
20
+ path = os.path.dirname(os.path.abspath(__file__))
21
+
22
+
17
23
  def agent_portrayal(agent):
18
- return {"color": "tab:orange" if agent.type == 0 else "tab:blue"}
24
+ style = AgentPortrayalStyle(
25
+ x=agent.cell.coordinate[0],
26
+ y=agent.cell.coordinate[1],
27
+ marker=os.path.join(path, "resources", "orange_happy.png"),
28
+ size=75,
29
+ )
30
+ if agent.type == 0:
31
+ if agent.happy:
32
+ style.update(
33
+ (
34
+ "marker",
35
+ os.path.join(path, "resources", "blue_happy.png"),
36
+ ),
37
+ )
38
+ else:
39
+ style.update(
40
+ (
41
+ "marker",
42
+ os.path.join(path, "resources", "blue_unhappy.png"),
43
+ ),
44
+ ("size", 50),
45
+ ("zorder", 2),
46
+ )
47
+ else:
48
+ if not agent.happy:
49
+ style.update(
50
+ (
51
+ "marker",
52
+ os.path.join(path, "resources", "orange_unhappy.png"),
53
+ ),
54
+ ("size", 50),
55
+ ("zorder", 2),
56
+ )
57
+
58
+ return style
19
59
 
20
60
 
21
61
  model_params = {
@@ -31,14 +71,21 @@ model_params = {
31
71
  "height": 20,
32
72
  }
33
73
 
74
+ # Note: Models with images as markers are very performance intensive.
34
75
  model1 = Schelling()
76
+ renderer = SpaceRenderer(model1, backend="matplotlib")
77
+ # Here we use renderer.render() to render the agents and grid in one go.
78
+ # This function always renders the grid and then renders the agents or
79
+ # property layers on top of it if specified. It also supports passing the
80
+ # post_process function to fine-tune the plot after rendering in itself.
81
+ renderer.render(agent_portrayal=agent_portrayal)
35
82
 
36
83
  HappyPlot = make_plot_component({"happy": "tab:green"})
37
84
 
38
85
  page = SolaraViz(
39
86
  model1,
87
+ renderer,
40
88
  components=[
41
- make_space_component(agent_portrayal),
42
89
  HappyPlot,
43
90
  get_happy_agents,
44
91
  ],
@@ -68,11 +68,13 @@ class Schelling(Model):
68
68
  )
69
69
 
70
70
  # Collect initial state
71
+ self.agents.do("assign_state")
71
72
  self.datacollector.collect(self)
72
73
 
73
74
  def step(self):
74
75
  """Run one step of the model."""
75
76
  self.happy = 0 # Reset counter of happy agents
76
77
  self.agents.shuffle_do("step") # Activate all agents in random order
78
+ self.agents.do("assign_state")
77
79
  self.datacollector.collect(self) # Collect data
78
80
  self.running = self.happy < len(self.agents) # Continue until everyone is happy
@@ -38,10 +38,6 @@ To run the model interactively, in this directory, run the following command
38
38
 
39
39
  ## Further Reading
40
40
 
41
- The full tutorial describing how the model is built can be found at:
42
- https://mesa.readthedocs.io/en/latest/tutorials/intro_tutorial.html
43
-
44
-
45
41
  [Stonedahl, F. and Wilensky, U. (2008). NetLogo Virus on a Network model](http://ccl.northwestern.edu/netlogo/models/VirusonaNetwork).
46
42
  Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
47
43
 
@@ -10,18 +10,19 @@ from mesa.examples.basic.virus_on_network.model import (
10
10
  from mesa.visualization import (
11
11
  Slider,
12
12
  SolaraViz,
13
+ SpaceRenderer,
13
14
  make_plot_component,
14
- make_space_component,
15
15
  )
16
+ from mesa.visualization.components import AgentPortrayalStyle
16
17
 
17
18
 
18
19
  def agent_portrayal(agent):
19
20
  node_color_dict = {
20
- State.INFECTED: "tab:red",
21
- State.SUSCEPTIBLE: "tab:green",
22
- State.RESISTANT: "tab:gray",
21
+ State.INFECTED: "red",
22
+ State.SUSCEPTIBLE: "green",
23
+ State.RESISTANT: "gray",
23
24
  }
24
- return {"color": node_color_dict[agent.state], "size": 10}
25
+ return AgentPortrayalStyle(color=node_color_dict[agent.state], size=20)
25
26
 
26
27
 
27
28
  def get_resistant_susceptible_ratio(model):
@@ -92,24 +93,40 @@ model_params = {
92
93
  }
93
94
 
94
95
 
95
- def post_process_lineplot(ax):
96
- ax.set_ylim(ymin=0)
97
- ax.set_ylabel("# people")
98
- ax.legend(bbox_to_anchor=(1.05, 1.0), loc="upper left")
96
+ def post_process_lineplot(chart):
97
+ chart = chart.properties(
98
+ width=400,
99
+ height=400,
100
+ ).configure_legend(
101
+ strokeColor="black",
102
+ fillColor="#ECE9E9",
103
+ orient="right",
104
+ cornerRadius=5,
105
+ padding=10,
106
+ strokeWidth=1,
107
+ )
108
+ return chart
109
+
99
110
 
111
+ model1 = VirusOnNetwork()
112
+ renderer = SpaceRenderer(model1, backend="altair")
113
+ renderer.draw_structure(
114
+ node_kwargs={"color": "black", "filled": False, "strokeWidth": 5},
115
+ edge_kwargs={"strokeDash": [6, 1]},
116
+ ) # Do this to draw the underlying network and customize it
117
+ renderer.draw_agents(agent_portrayal)
100
118
 
101
- SpacePlot = make_space_component(agent_portrayal)
119
+ # Plot components can also be in altair and support post_process
102
120
  StatePlot = make_plot_component(
103
- {"Infected": "tab:red", "Susceptible": "tab:green", "Resistant": "tab:gray"},
121
+ {"Infected": "red", "Susceptible": "green", "Resistant": "gray"},
122
+ backend="altair",
104
123
  post_process=post_process_lineplot,
105
124
  )
106
125
 
107
- model1 = VirusOnNetwork()
108
-
109
126
  page = SolaraViz(
110
127
  model1,
128
+ renderer,
111
129
  components=[
112
- SpacePlot,
113
130
  StatePlot,
114
131
  get_resistant_susceptible_ratio,
115
132
  ],
@@ -15,6 +15,6 @@ Notes:
15
15
  - Features graduate from experimental status once their APIs are stabilized
16
16
  """
17
17
 
18
- from mesa.experimental import continuous_space, devs, mesa_signals
18
+ from mesa.experimental import continuous_space, devs, mesa_signals, meta_agents
19
19
 
20
- __all__ = ["continuous_space", "devs", "mesa_signals"]
20
+ __all__ = ["continuous_space", "devs", "mesa_signals", "meta_agents"]