Mesa 3.1.0.dev0__py3-none-any.whl → 3.1.2__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 (60) hide show
  1. mesa/__init__.py +3 -3
  2. mesa/agent.py +48 -0
  3. mesa/batchrunner.py +14 -1
  4. mesa/datacollection.py +1 -6
  5. mesa/examples/__init__.py +2 -2
  6. mesa/examples/advanced/epstein_civil_violence/app.py +5 -0
  7. mesa/examples/advanced/pd_grid/agents.py +2 -1
  8. mesa/examples/advanced/pd_grid/analysis.ipynb +44 -89
  9. mesa/examples/advanced/pd_grid/app.py +5 -0
  10. mesa/examples/advanced/pd_grid/model.py +3 -5
  11. mesa/examples/advanced/sugarscape_g1mt/agents.py +12 -65
  12. mesa/examples/advanced/sugarscape_g1mt/app.py +24 -19
  13. mesa/examples/advanced/sugarscape_g1mt/model.py +45 -52
  14. mesa/examples/advanced/wolf_sheep/agents.py +36 -2
  15. mesa/examples/advanced/wolf_sheep/model.py +17 -16
  16. mesa/examples/basic/boid_flockers/app.py +5 -0
  17. mesa/examples/basic/boltzmann_wealth_model/app.py +8 -5
  18. mesa/examples/basic/boltzmann_wealth_model/st_app.py +1 -1
  19. mesa/examples/basic/conways_game_of_life/app.py +5 -0
  20. mesa/examples/basic/conways_game_of_life/st_app.py +2 -2
  21. mesa/examples/basic/schelling/agents.py +11 -5
  22. mesa/examples/basic/schelling/analysis.ipynb +42 -36
  23. mesa/examples/basic/schelling/app.py +6 -1
  24. mesa/examples/basic/schelling/model.py +3 -3
  25. mesa/examples/basic/virus_on_network/app.py +5 -0
  26. mesa/experimental/__init__.py +17 -10
  27. mesa/experimental/cell_space/__init__.py +19 -7
  28. mesa/experimental/cell_space/cell.py +22 -37
  29. mesa/experimental/cell_space/cell_agent.py +12 -1
  30. mesa/experimental/cell_space/cell_collection.py +18 -3
  31. mesa/experimental/cell_space/discrete_space.py +15 -64
  32. mesa/experimental/cell_space/grid.py +74 -4
  33. mesa/experimental/cell_space/network.py +13 -1
  34. mesa/experimental/cell_space/property_layer.py +444 -0
  35. mesa/experimental/cell_space/voronoi.py +13 -1
  36. mesa/experimental/devs/__init__.py +20 -2
  37. mesa/experimental/devs/eventlist.py +19 -1
  38. mesa/experimental/devs/simulator.py +24 -8
  39. mesa/experimental/mesa_signals/__init__.py +23 -0
  40. mesa/experimental/mesa_signals/mesa_signal.py +485 -0
  41. mesa/experimental/mesa_signals/observable_collections.py +133 -0
  42. mesa/experimental/mesa_signals/signals_util.py +52 -0
  43. mesa/mesa_logging.py +190 -0
  44. mesa/model.py +17 -23
  45. mesa/visualization/__init__.py +2 -2
  46. mesa/visualization/mpl_space_drawing.py +8 -6
  47. mesa/visualization/solara_viz.py +49 -11
  48. {mesa-3.1.0.dev0.dist-info → mesa-3.1.2.dist-info}/METADATA +4 -2
  49. mesa-3.1.2.dist-info/RECORD +94 -0
  50. {mesa-3.1.0.dev0.dist-info → mesa-3.1.2.dist-info}/WHEEL +1 -1
  51. mesa/experimental/UserParam.py +0 -67
  52. mesa/experimental/components/altair.py +0 -81
  53. mesa/experimental/components/matplotlib.py +0 -242
  54. mesa/experimental/devs/examples/epstein_civil_violence.py +0 -305
  55. mesa/experimental/devs/examples/wolf_sheep.py +0 -250
  56. mesa/experimental/solara_viz.py +0 -453
  57. mesa-3.1.0.dev0.dist-info/RECORD +0 -94
  58. {mesa-3.1.0.dev0.dist-info → mesa-3.1.2.dist-info}/entry_points.txt +0 -0
  59. {mesa-3.1.0.dev0.dist-info → mesa-3.1.2.dist-info}/licenses/LICENSE +0 -0
  60. {mesa-3.1.0.dev0.dist-info → mesa-3.1.2.dist-info}/licenses/NOTICE +0 -0
@@ -0,0 +1,94 @@
1
+ mesa/__init__.py,sha256=ZzoDPNujAbk6_r2EXHXdaqxwv8kfwY92pdL7jALFKOY,611
2
+ mesa/agent.py,sha256=4CXMOFA9KhvTypaV_OHZGqxOR4GVwyX4x8DOtQENUQA,26130
3
+ mesa/batchrunner.py,sha256=w8StV82F_7DAAVQc5V7_Ggp0EL1NYn__UcBE-Nwrgv4,7771
4
+ mesa/datacollection.py,sha256=8loT4pQsXcHArxHSsbRc7HTc2GP5gsEIeKFKr3xya4I,15991
5
+ mesa/mesa_logging.py,sha256=PEDqUaQ2Y4bkYBkrHVkGT0sF86gUdbSH1T3vCg3qQeE,4949
6
+ mesa/model.py,sha256=oVcV-_OZ3GVv1sb3KqyGA9TAWCDQu9qEDWwRi_AXR40,8353
7
+ mesa/space.py,sha256=cfzlRfy9chegp8d89k2aqI29jo9cb18USlz2G2iOZU4,64082
8
+ mesa/examples/README.md,sha256=dNn8kv0BNQem3NNhO5mbOANQoK8UUYOo7rnkCFV9tnE,2882
9
+ mesa/examples/__init__.py,sha256=pyPWFRUxyYtQilJECbH7LY1eYBk8VB0Yg-_SbFEEvFA,825
10
+ mesa/examples/advanced/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ mesa/examples/advanced/epstein_civil_violence/Epstein Civil Violence.ipynb,sha256=yh50ZAK2BVJyJIKsQTTxywnasqWn1IiQUVrwmZKue4w,29032
12
+ mesa/examples/advanced/epstein_civil_violence/Readme.md,sha256=RXuGIZAibz3KVkP51PGjwzcRx2R9Ettmh3qbDTPqDcg,1735
13
+ mesa/examples/advanced/epstein_civil_violence/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ mesa/examples/advanced/epstein_civil_violence/agents.py,sha256=0X4JLj2K2cl1bACkFLI6-K6tKbr2SLZlAy_kjgUDjzA,5863
15
+ mesa/examples/advanced/epstein_civil_violence/app.py,sha256=fFlPijAUDLs_WfROGIlUXRakkkfbWnytcXFTAzdRplU,1890
16
+ mesa/examples/advanced/epstein_civil_violence/model.py,sha256=fcTkjCRhEhDerDC1W_lrezdoWD1y5xIublkGIhCak8w,3918
17
+ mesa/examples/advanced/pd_grid/Readme.md,sha256=UVUQxZRFdfymCKDdQEn3ZEwgSqgp9cKJPsU8oZpLFnY,2367
18
+ mesa/examples/advanced/pd_grid/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ mesa/examples/advanced/pd_grid/agents.py,sha256=8JnezmnwxjcqAUAgXa1iWls0Nz4yBS-TJi1TSVcHbqM,1752
20
+ mesa/examples/advanced/pd_grid/analysis.ipynb,sha256=TTSY7mZlIYPjPjpW7cxr7Gzpo-NKKEBpXX4_f0V6NfI,5432
21
+ mesa/examples/advanced/pd_grid/app.py,sha256=-_fTP7f_oITKHt7dDVJou7Oa7u7v_C4Ml5yw7D1sbx8,1457
22
+ mesa/examples/advanced/pd_grid/model.py,sha256=-ytTSW0a_TQGTQW02k7XKAMiMak_b2XkJUw5kkGNHMQ,2291
23
+ mesa/examples/advanced/sugarscape_g1mt/Readme.md,sha256=x3kKw1Rre2FPkNhGDLtdzeThmH089mxsGYUPZUeu26k,3595
24
+ mesa/examples/advanced/sugarscape_g1mt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
+ mesa/examples/advanced/sugarscape_g1mt/agents.py,sha256=ugTNvWjQNm_jMInv9d0sOIFaChIDs-TWazN78YrDP9g,8466
26
+ mesa/examples/advanced/sugarscape_g1mt/app.py,sha256=7BnjOEkzltfUSx_Hz8h7QXqWARrnAIULodReXd4joRo,2479
27
+ mesa/examples/advanced/sugarscape_g1mt/model.py,sha256=s4n9SRaaMNY9CXFtry83BELZU69UJOCa4DMrw_eehr4,5763
28
+ mesa/examples/advanced/sugarscape_g1mt/sugar-map.txt,sha256=zZtGYciBPT4miZVnbVuoQ5TugTmGrbDWV9yb5KH6tnU,5000
29
+ mesa/examples/advanced/sugarscape_g1mt/tests.py,sha256=UNahmZTgLquSqmoi_9GcE3JP0qBHjkrHFZ15NMm0ce8,2517
30
+ mesa/examples/advanced/wolf_sheep/Readme.md,sha256=6zrtCg4Fb-hgQxqdLMpTkIYMwD6owCv8BMz_qn0N98Q,3165
31
+ mesa/examples/advanced/wolf_sheep/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
+ mesa/examples/advanced/wolf_sheep/agents.py,sha256=lxk9nxDaIGxB7zJ0pIOF2PfOAee8lX-vG447Cklt7UQ,5090
33
+ mesa/examples/advanced/wolf_sheep/app.py,sha256=IIl-gDh1O3oYIvrXXGmKHbW5Iw3ZpCn691dGwKgyI3E,2508
34
+ mesa/examples/advanced/wolf_sheep/model.py,sha256=IUN1STm6jCGuzXo2sCF86r1U-dI63yhLhnI14tu9BSw,4567
35
+ mesa/examples/basic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
+ mesa/examples/basic/boid_flockers/Readme.md,sha256=4KJinsLPtUciQSMzvaX3tU5r1HTUg3AFOFDKy73W5RE,894
37
+ mesa/examples/basic/boid_flockers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
+ mesa/examples/basic/boid_flockers/agents.py,sha256=72oL4jWEiJfSgshSEcL44irptIY6WAQDRAQ0cO2MxS8,3827
39
+ mesa/examples/basic/boid_flockers/app.py,sha256=oJbv_CbeiXu97q1W_2xlsXIVAqqLvfxshn2Y70_7PyA,1244
40
+ mesa/examples/basic/boid_flockers/model.py,sha256=scy0OaYzQVY5vVarsI7dUydynwoH3-uYoYcsBTtwtyA,3399
41
+ mesa/examples/basic/boltzmann_wealth_model/Readme.md,sha256=wl1ylO9KWoTiuIJKOnk2FGdcmyVUqJ5wiSbVUa3WWAc,2725
42
+ mesa/examples/basic/boltzmann_wealth_model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
+ mesa/examples/basic/boltzmann_wealth_model/agents.py,sha256=Jol2aspw--UtQn0EiReXVmlWtzpdC2o_YUTAyu1sDk4,1546
44
+ mesa/examples/basic/boltzmann_wealth_model/app.py,sha256=wTQBu9A3uscTZSPqZ5jYssykGPiseye2YBjMngYI48A,2233
45
+ mesa/examples/basic/boltzmann_wealth_model/model.py,sha256=ED4EFHJlrrcF12WYOEpXpPt5asK2T6uzpq_S97EtfHo,2941
46
+ mesa/examples/basic/boltzmann_wealth_model/st_app.py,sha256=PQ65LkYPXn-lx4lCfXuFJmzcmAfVB3oEEdIyuq9a7iU,3454
47
+ mesa/examples/basic/conways_game_of_life/Readme.md,sha256=VRgN6roF6leQ_IMYwxFypSfFjZo9jnCd-rkPTjpp7II,1453
48
+ mesa/examples/basic/conways_game_of_life/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
+ mesa/examples/basic/conways_game_of_life/agents.py,sha256=ETn87GV8it9p0nlSn6f1qu5CDEmqokkr6Rq7KWaT-5U,1627
50
+ mesa/examples/basic/conways_game_of_life/app.py,sha256=HPzss2X3ntTOgdmg0C0EWw3lmAF7WiN9MZEgGdLW-xU,1997
51
+ mesa/examples/basic/conways_game_of_life/model.py,sha256=8L88m8F_YauwWeDef6UA2myQoAwC0B5sH5jsfyLn-u8,1221
52
+ mesa/examples/basic/conways_game_of_life/st_app.py,sha256=9qz3o0pOuvLZR-_aPPVHN-RIwFSNzvwWWfxCaD2K5cs,2402
53
+ mesa/examples/basic/schelling/Readme.md,sha256=CRKBfYtnLJLlTKLsTRQ-7gsQRxVxDooOBN5uP8PEtaU,2296
54
+ mesa/examples/basic/schelling/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
+ mesa/examples/basic/schelling/agents.py,sha256=WdDM-BYeOUuIL_2U5rlZz4Rs_5orstHY2Z6G6zvQEyg,1224
56
+ mesa/examples/basic/schelling/analysis.ipynb,sha256=UMDoumvBFhZilwJhxl5Mou2bmDDqxguK5RdnoY2gkNc,5910
57
+ mesa/examples/basic/schelling/app.py,sha256=eqgqCu6_6jk1RrmT82e_AoEDMvy8eZ0OJnnlITpiBXQ,1067
58
+ mesa/examples/basic/schelling/model.py,sha256=ZNTK42pJnIJfsnqaI0ZXFxw9xtWPXkUMIemMr4uXmW8,2766
59
+ mesa/examples/basic/virus_on_network/Readme.md,sha256=qmXGx4Fo0tRBvJiiJ684bkWJPn2gcFaiikLwgc5APWI,2336
60
+ mesa/examples/basic/virus_on_network/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
+ mesa/examples/basic/virus_on_network/agents.py,sha256=a_WhqYblJlW6od67eXfU-nb7IMRyYpgxtf0le--VYoA,1975
62
+ mesa/examples/basic/virus_on_network/app.py,sha256=8I8VWQ7pBcOaNGyLDEO4IbNSTRy161-eWg-iEUVQ3-I,2553
63
+ mesa/examples/basic/virus_on_network/model.py,sha256=jQoCmvygwCvhUrlL0l7V8GcDLv94CgwtuK7DDGU8q8g,2813
64
+ mesa/experimental/__init__.py,sha256=32D_blj5droexwyh83MjPska0_xYzL1ncJFgyuyBaWs,905
65
+ mesa/experimental/cell_space/__init__.py,sha256=0A3YTen0Lk-e3Q73VEXK7N2UEHb9f50gW11H_jx7DXc,1744
66
+ mesa/experimental/cell_space/cell.py,sha256=Dl0ek7W_vgAZOp6zXBvkwYTG7E36OQ-4zZ5bW43mKtw,6600
67
+ mesa/experimental/cell_space/cell_agent.py,sha256=LOTLKR2To9hU-igKsauA5sikS7k8wgwlt-Pi0C7lGU0,4262
68
+ mesa/experimental/cell_space/cell_collection.py,sha256=VnD3I4bqnwgFxKSzTElYYJIBFJGdaEaNTggrbFKgPrc,4715
69
+ mesa/experimental/cell_space/discrete_space.py,sha256=qNGez9SV4E83Outs_12suuS0ZtTHcwyv6ZB1xzTXUWk,3846
70
+ mesa/experimental/cell_space/grid.py,sha256=d-1S2iXijGkoJ9yc271pB8iXlzsX13usJjcjevCs_rU,10432
71
+ mesa/experimental/cell_space/network.py,sha256=ujN2dV1i9hcXh6H0s7gwTuPT6gh7BCaziOUYPCybQKk,1862
72
+ mesa/experimental/cell_space/property_layer.py,sha256=HFpBWOjI7PFU_K8VDb_pl9h62MftCBWL7PUKQNT3Ke8,17379
73
+ mesa/experimental/cell_space/voronoi.py,sha256=5D9j45FW2IVPcZrp-hskw_z84QwHIdduwXLdTKeqWMQ,10472
74
+ mesa/experimental/devs/__init__.py,sha256=wkDrpqQ3qHGqrsOSTD-UOj-qOw0oFgnCw_ZXr9xFs90,1200
75
+ mesa/experimental/devs/eventlist.py,sha256=6igPkHJt-syLcdpFV14_n6HGej2F1cM9giDQo85fHPw,7217
76
+ mesa/experimental/devs/simulator.py,sha256=UiVRIlNodSIveD2mS_8-vj0T_FulU8vhXxSxCfsK1Vc,12991
77
+ mesa/experimental/mesa_signals/__init__.py,sha256=QjG4FSKQl5ZSzV9ctiaB7UqYDR3FARAyUc7HbGtQjX4,840
78
+ mesa/experimental/mesa_signals/mesa_signal.py,sha256=Vxo4gIV6a959MANL3RMANsGh0R9lkZTNO19XIYzvKSM,16860
79
+ mesa/experimental/mesa_signals/observable_collections.py,sha256=rHEj6BYxLHFFGzSdoDKAdtzJ6y-IHHfcP3qEDJJsY6Y,3917
80
+ mesa/experimental/mesa_signals/signals_util.py,sha256=fmq_FsIxsIvGjtmc4A9TGdBUtdliMHhEOpjRXivRDjA,1618
81
+ mesa/visualization/__init__.py,sha256=YW-oHEOTjbtDKD_TylAMtVnt8mrsz1Fw7ifdc4WeHxA,743
82
+ mesa/visualization/mpl_space_drawing.py,sha256=GVpNwdAN1Q_VzkSsQBC2_OBrGo1hwRXSi4n-lgGZlT8,20077
83
+ mesa/visualization/solara_viz.py,sha256=BjhmH2FLlVc8rxfAze9Ex1wj_0jkVOH-_bXz2MYzd2A,19325
84
+ mesa/visualization/user_param.py,sha256=Dl2WOwLYLf0pfLpabCZtIdFRyKZrK6Qtc3utZx5GPYg,2139
85
+ mesa/visualization/utils.py,sha256=lJHgRKF5BHLf72Tw3YpwyiWuRoIimaTKQ7xBCw_Rx3A,146
86
+ mesa/visualization/components/__init__.py,sha256=Bq3nrPikcaIo9BSs0O3zptWVLlUmAkLo3s0mEmpH1RE,3022
87
+ mesa/visualization/components/altair_components.py,sha256=wotpFFQgMY-ZR3lNVm_fRos-iDg0Wjnj6Tk67_7f1SQ,5847
88
+ mesa/visualization/components/matplotlib_components.py,sha256=xQETaFyHIfmL_9JwrLIgubuIQ7-pp7TMoXT1WMmozus,5441
89
+ mesa-3.1.2.dist-info/METADATA,sha256=GCOm4kE42KgetomHYGWGoHjI_jWBELOtU-ejvyC_SMs,9949
90
+ mesa-3.1.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
91
+ mesa-3.1.2.dist-info/entry_points.txt,sha256=IOcQtetGF8l4wHpOs_hGb19Rz-FS__BMXOJR10IBPsA,39
92
+ mesa-3.1.2.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
93
+ mesa-3.1.2.dist-info/licenses/NOTICE,sha256=GbsWoK0QWv1JyZ_xer2s-jNilv0RtWl-0UrtlJANHPg,578
94
+ mesa-3.1.2.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.26.1
2
+ Generator: hatchling 1.27.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,67 +0,0 @@
1
- """helper classes."""
2
-
3
-
4
- class UserParam: # noqa: D101
5
- _ERROR_MESSAGE = "Missing or malformed inputs for '{}' Option '{}'"
6
-
7
- def maybe_raise_error(self, param_type, valid): # noqa: D102
8
- if valid:
9
- return
10
- msg = self._ERROR_MESSAGE.format(param_type, self.label)
11
- raise ValueError(msg)
12
-
13
-
14
- class Slider(UserParam):
15
- """A number-based slider input with settable increment.
16
-
17
- Example:
18
- slider_option = Slider("My Slider", value=123, min=10, max=200, step=0.1)
19
-
20
- Args:
21
- label: The displayed label in the UI
22
- value: The initial value of the slider
23
- min: The minimum possible value of the slider
24
- max: The maximum possible value of the slider
25
- step: The step between min and max for a range of possible values
26
- dtype: either int or float
27
- """
28
-
29
- def __init__(
30
- self,
31
- label="",
32
- value=None,
33
- min=None,
34
- max=None,
35
- step=1,
36
- dtype=None,
37
- ):
38
- """Slider class.
39
-
40
- Args:
41
- label: The displayed label in the UI
42
- value: The initial value of the slider
43
- min: The minimum possible value of the slider
44
- max: The maximum possible value of the slider
45
- step: The step between min and max for a range of possible values
46
- dtype: either int or float
47
- """
48
- self.label = label
49
- self.value = value
50
- self.min = min
51
- self.max = max
52
- self.step = step
53
-
54
- # Validate option type to make sure values are supplied properly
55
- valid = not (self.value is None or self.min is None or self.max is None)
56
- self.maybe_raise_error("slider", valid)
57
-
58
- if dtype is None:
59
- self.is_float_slider = self._check_values_are_float(value, min, max, step)
60
- else:
61
- self.is_float_slider = dtype is float
62
-
63
- def _check_values_are_float(self, value, min, max, step):
64
- return any(isinstance(n, float) for n in (value, min, max, step))
65
-
66
- def get(self, attr): # noqa: D102
67
- return getattr(self, attr)
@@ -1,81 +0,0 @@
1
- """Altair components."""
2
-
3
- import contextlib
4
-
5
- import solara
6
-
7
- with contextlib.suppress(ImportError):
8
- import altair as alt
9
-
10
-
11
- @solara.component
12
- def SpaceAltair(model, agent_portrayal, dependencies: list[any] | None = None):
13
- """A component that renders a Space using Altair.
14
-
15
- Args:
16
- model: a model instance
17
- agent_portrayal: agent portray specification
18
- dependencies: optional list of dependencies (currently not used)
19
-
20
- """
21
- space = getattr(model, "grid", None)
22
- if space is None:
23
- # Sometimes the space is defined as model.space instead of model.grid
24
- space = model.space
25
- chart = _draw_grid(space, agent_portrayal)
26
- solara.FigureAltair(chart)
27
-
28
-
29
- def _draw_grid(space, agent_portrayal):
30
- def portray(g):
31
- all_agent_data = []
32
- for content, (x, y) in g.coord_iter():
33
- if not content:
34
- continue
35
- if not hasattr(content, "__iter__"):
36
- # Is a single grid
37
- content = [content] # noqa: PLW2901
38
- for agent in content:
39
- # use all data from agent portrayal, and add x,y coordinates
40
- agent_data = agent_portrayal(agent)
41
- agent_data["x"] = x
42
- agent_data["y"] = y
43
- all_agent_data.append(agent_data)
44
- return all_agent_data
45
-
46
- all_agent_data = portray(space)
47
- invalid_tooltips = ["color", "size", "x", "y"]
48
-
49
- encoding_dict = {
50
- # no x-axis label
51
- "x": alt.X("x", axis=None, type="ordinal"),
52
- # no y-axis label
53
- "y": alt.Y("y", axis=None, type="ordinal"),
54
- "tooltip": [
55
- alt.Tooltip(key, type=alt.utils.infer_vegalite_type([value]))
56
- for key, value in all_agent_data[0].items()
57
- if key not in invalid_tooltips
58
- ],
59
- }
60
- has_color = "color" in all_agent_data[0]
61
- if has_color:
62
- encoding_dict["color"] = alt.Color("color", type="nominal")
63
- has_size = "size" in all_agent_data[0]
64
- if has_size:
65
- encoding_dict["size"] = alt.Size("size", type="quantitative")
66
-
67
- chart = (
68
- alt.Chart(
69
- alt.Data(values=all_agent_data), encoding=alt.Encoding(**encoding_dict)
70
- )
71
- .mark_point(filled=True)
72
- .properties(width=280, height=280)
73
- # .configure_view(strokeOpacity=0) # hide grid/chart lines
74
- )
75
- # This is the default value for the marker size, which auto-scales
76
- # according to the grid area.
77
- if not has_size:
78
- length = min(space.width, space.height)
79
- chart = chart.mark_point(size=30000 / length**2, filled=True)
80
-
81
- return chart
@@ -1,242 +0,0 @@
1
- """Support for using matplotlib to draw spaces."""
2
-
3
- from collections import defaultdict
4
-
5
- import networkx as nx
6
- import solara
7
- from matplotlib.figure import Figure
8
- from matplotlib.ticker import MaxNLocator
9
-
10
- import mesa
11
- from mesa.experimental.cell_space import VoronoiGrid
12
-
13
-
14
- @solara.component
15
- def SpaceMatplotlib(model, agent_portrayal, dependencies: list[any] | None = None):
16
- """A component for rendering a space using Matplotlib.
17
-
18
- Args:
19
- model: a model instance
20
- agent_portrayal: a specification of how to portray an agent.
21
- dependencies: list of dependencies.
22
-
23
- """
24
- space_fig = Figure()
25
- space_ax = space_fig.subplots()
26
- space = getattr(model, "grid", None)
27
- if space is None:
28
- # Sometimes the space is defined as model.space instead of model.grid
29
- space = model.space
30
- if isinstance(space, mesa.space.NetworkGrid):
31
- _draw_network_grid(space, space_ax, agent_portrayal)
32
- elif isinstance(space, mesa.space.ContinuousSpace):
33
- _draw_continuous_space(space, space_ax, agent_portrayal)
34
- elif isinstance(space, VoronoiGrid):
35
- _draw_voronoi(space, space_ax, agent_portrayal)
36
- else:
37
- _draw_grid(space, space_ax, agent_portrayal)
38
- solara.FigureMatplotlib(space_fig, format="png", dependencies=dependencies)
39
-
40
-
41
- # matplotlib scatter does not allow for multiple shapes in one call
42
- def _split_and_scatter(portray_data, space_ax):
43
- grouped_data = defaultdict(lambda: {"x": [], "y": [], "s": [], "c": []})
44
-
45
- # Extract data from the dictionary
46
- x = portray_data["x"]
47
- y = portray_data["y"]
48
- s = portray_data["s"]
49
- c = portray_data["c"]
50
- m = portray_data["m"]
51
-
52
- if not (len(x) == len(y) == len(s) == len(c) == len(m)):
53
- raise ValueError(
54
- "Length mismatch in portrayal data lists: "
55
- f"x: {len(x)}, y: {len(y)}, size: {len(s)}, "
56
- f"color: {len(c)}, marker: {len(m)}"
57
- )
58
-
59
- # Group the data by marker
60
- for i in range(len(x)):
61
- marker = m[i]
62
- grouped_data[marker]["x"].append(x[i])
63
- grouped_data[marker]["y"].append(y[i])
64
- grouped_data[marker]["s"].append(s[i])
65
- grouped_data[marker]["c"].append(c[i])
66
-
67
- # Plot each group with the same marker
68
- for marker, data in grouped_data.items():
69
- space_ax.scatter(data["x"], data["y"], s=data["s"], c=data["c"], marker=marker)
70
-
71
-
72
- def _draw_grid(space, space_ax, agent_portrayal):
73
- def portray(g):
74
- x = []
75
- y = []
76
- s = [] # size
77
- c = [] # color
78
- m = [] # shape
79
- for i in range(g.width):
80
- for j in range(g.height):
81
- content = g._grid[i][j]
82
- if not content:
83
- continue
84
- if not hasattr(content, "__iter__"):
85
- # Is a single grid
86
- content = [content]
87
- for agent in content:
88
- data = agent_portrayal(agent)
89
- x.append(i)
90
- y.append(j)
91
-
92
- # This is the default value for the marker size, which auto-scales
93
- # according to the grid area.
94
- default_size = (180 / max(g.width, g.height)) ** 2
95
- # establishing a default prevents misalignment if some agents are not given size, color, etc.
96
- size = data.get("size", default_size)
97
- s.append(size)
98
- color = data.get("color", "tab:blue")
99
- c.append(color)
100
- mark = data.get("shape", "o")
101
- m.append(mark)
102
- out = {"x": x, "y": y, "s": s, "c": c, "m": m}
103
- return out
104
-
105
- space_ax.set_xlim(-1, space.width)
106
- space_ax.set_ylim(-1, space.height)
107
- _split_and_scatter(portray(space), space_ax)
108
-
109
-
110
- def _draw_network_grid(space, space_ax, agent_portrayal):
111
- graph = space.G
112
- pos = nx.spring_layout(graph, seed=0)
113
- nx.draw(
114
- graph,
115
- ax=space_ax,
116
- pos=pos,
117
- **agent_portrayal(graph),
118
- )
119
-
120
-
121
- def _draw_continuous_space(space, space_ax, agent_portrayal):
122
- def portray(space):
123
- x = []
124
- y = []
125
- s = [] # size
126
- c = [] # color
127
- m = [] # shape
128
- for agent in space._agent_to_index:
129
- data = agent_portrayal(agent)
130
- _x, _y = agent.pos
131
- x.append(_x)
132
- y.append(_y)
133
-
134
- # This is matplotlib's default marker size
135
- default_size = 20
136
- # establishing a default prevents misalignment if some agents are not given size, color, etc.
137
- size = data.get("size", default_size)
138
- s.append(size)
139
- color = data.get("color", "tab:blue")
140
- c.append(color)
141
- mark = data.get("shape", "o")
142
- m.append(mark)
143
- out = {"x": x, "y": y, "s": s, "c": c, "m": m}
144
- return out
145
-
146
- # Determine border style based on space.torus
147
- border_style = "solid" if not space.torus else (0, (5, 10))
148
-
149
- # Set the border of the plot
150
- for spine in space_ax.spines.values():
151
- spine.set_linewidth(1.5)
152
- spine.set_color("black")
153
- spine.set_linestyle(border_style)
154
-
155
- width = space.x_max - space.x_min
156
- x_padding = width / 20
157
- height = space.y_max - space.y_min
158
- y_padding = height / 20
159
- space_ax.set_xlim(space.x_min - x_padding, space.x_max + x_padding)
160
- space_ax.set_ylim(space.y_min - y_padding, space.y_max + y_padding)
161
-
162
- # Portray and scatter the agents in the space
163
- _split_and_scatter(portray(space), space_ax)
164
-
165
-
166
- def _draw_voronoi(space, space_ax, agent_portrayal):
167
- def portray(g):
168
- x = []
169
- y = []
170
- s = [] # size
171
- c = [] # color
172
-
173
- for cell in g.all_cells:
174
- for agent in cell.agents:
175
- data = agent_portrayal(agent)
176
- x.append(cell.coordinate[0])
177
- y.append(cell.coordinate[1])
178
- if "size" in data:
179
- s.append(data["size"])
180
- if "color" in data:
181
- c.append(data["color"])
182
- out = {"x": x, "y": y}
183
- # This is the default value for the marker size, which auto-scales
184
- # according to the grid area.
185
- out["s"] = s
186
- if len(c) > 0:
187
- out["c"] = c
188
-
189
- return out
190
-
191
- x_list = [i[0] for i in space.centroids_coordinates]
192
- y_list = [i[1] for i in space.centroids_coordinates]
193
- x_max = max(x_list)
194
- x_min = min(x_list)
195
- y_max = max(y_list)
196
- y_min = min(y_list)
197
-
198
- width = x_max - x_min
199
- x_padding = width / 20
200
- height = y_max - y_min
201
- y_padding = height / 20
202
- space_ax.set_xlim(x_min - x_padding, x_max + x_padding)
203
- space_ax.set_ylim(y_min - y_padding, y_max + y_padding)
204
- space_ax.scatter(**portray(space))
205
-
206
- for cell in space.all_cells:
207
- polygon = cell.properties["polygon"]
208
- space_ax.fill(
209
- *zip(*polygon),
210
- alpha=min(1, cell.properties[space.cell_coloring_property]),
211
- c="red",
212
- ) # Plot filled polygon
213
- space_ax.plot(*zip(*polygon), color="black") # Plot polygon edges in red
214
-
215
-
216
- @solara.component
217
- def PlotMatplotlib(model, measure, dependencies: list[any] | None = None):
218
- """A solara component for creating a matplotlib figure.
219
-
220
- Args:
221
- model: Model instance
222
- measure: measure to plot
223
- dependencies: list of additional dependencies
224
-
225
- """
226
- fig = Figure()
227
- ax = fig.subplots()
228
- df = model.datacollector.get_model_vars_dataframe()
229
- if isinstance(measure, str):
230
- ax.plot(df.loc[:, measure])
231
- ax.set_ylabel(measure)
232
- elif isinstance(measure, dict):
233
- for m, color in measure.items():
234
- ax.plot(df.loc[:, m], label=m, color=color)
235
- fig.legend()
236
- elif isinstance(measure, list | tuple):
237
- for m in measure:
238
- ax.plot(df.loc[:, m], label=m)
239
- fig.legend()
240
- # Set integer x axis
241
- ax.xaxis.set_major_locator(MaxNLocator(integer=True))
242
- solara.FigureMatplotlib(fig, dependencies=dependencies)