Mesa 3.0.0b2__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 (28) hide show
  1. mesa/__init__.py +1 -1
  2. mesa/batchrunner.py +26 -1
  3. mesa/examples/README.md +11 -11
  4. mesa/examples/advanced/epstein_civil_violence/agents.py +44 -38
  5. mesa/examples/advanced/epstein_civil_violence/app.py +29 -28
  6. mesa/examples/advanced/epstein_civil_violence/model.py +33 -65
  7. mesa/examples/advanced/pd_grid/app.py +8 -4
  8. mesa/examples/advanced/sugarscape_g1mt/app.py +5 -13
  9. mesa/examples/advanced/wolf_sheep/app.py +25 -18
  10. mesa/examples/basic/boid_flockers/app.py +2 -2
  11. mesa/examples/basic/boltzmann_wealth_model/app.py +14 -10
  12. mesa/examples/basic/conways_game_of_life/app.py +15 -3
  13. mesa/examples/basic/schelling/app.py +5 -5
  14. mesa/examples/basic/virus_on_network/app.py +25 -47
  15. mesa/space.py +0 -30
  16. mesa/visualization/__init__.py +16 -5
  17. mesa/visualization/components/__init__.py +83 -0
  18. mesa/visualization/components/{altair.py → altair_components.py} +34 -2
  19. mesa/visualization/components/matplotlib_components.py +176 -0
  20. mesa/visualization/mpl_space_drawing.py +558 -0
  21. mesa/visualization/solara_viz.py +30 -20
  22. {mesa-3.0.0b2.dist-info → mesa-3.0.0rc0.dist-info}/METADATA +1 -1
  23. {mesa-3.0.0b2.dist-info → mesa-3.0.0rc0.dist-info}/RECORD +27 -25
  24. mesa/visualization/components/matplotlib.py +0 -386
  25. {mesa-3.0.0b2.dist-info → mesa-3.0.0rc0.dist-info}/WHEEL +0 -0
  26. {mesa-3.0.0b2.dist-info → mesa-3.0.0rc0.dist-info}/entry_points.txt +0 -0
  27. {mesa-3.0.0b2.dist-info → mesa-3.0.0rc0.dist-info}/licenses/LICENSE +0 -0
  28. {mesa-3.0.0b2.dist-info → mesa-3.0.0rc0.dist-info}/licenses/NOTICE +0 -0
@@ -1,65 +1,65 @@
1
- mesa/__init__.py,sha256=Bld7cqsOkGY-bJUf3fuXBts9eH5TRlebkX8pZNI7l9M,659
1
+ mesa/__init__.py,sha256=JtANO2arGfbYdpYBvtWWDotVxxQInnzNtfru-pNt8Zo,660
2
2
  mesa/agent.py,sha256=Ein1Ei7n1wZNKcv4L1NlP3iPu9q1pm-QGIL64dLC5Fw,24636
3
- mesa/batchrunner.py,sha256=0AqTcvjWNPp1aqn7zuUKSovx6Rnkk4M-KouCZ4Guqy0,6419
3
+ mesa/batchrunner.py,sha256=sMFLTxj5avP_-HGO0leLVuxXK2dH0xdPopvhAmawwRQ,7213
4
4
  mesa/datacollection.py,sha256=xyb07aBpd-HSDh5bk-XcVqGiDu5bfaLlxj5eDlGIwqY,16138
5
5
  mesa/model.py,sha256=fojtI87UxDLnRB71CGUKbZWh0BrstBHoCU9xWcw-MsA,10406
6
- mesa/space.py,sha256=f9TaLgb2nFPNiZn-Mgr5votcn80BBU_LnOm8fbLkEWw,65052
6
+ mesa/space.py,sha256=cfzlRfy9chegp8d89k2aqI29jo9cb18USlz2G2iOZU4,64082
7
7
  mesa/time.py,sha256=5yWubqst13MfjXpsYjY-MNdIQH3KWi373KRmRZT5BBo,15044
8
- mesa/examples/README.md,sha256=-H6ECbl2bqkAK3PKz6ixlm9pN13f-CyKfNssm2Kbyw0,2810
8
+ mesa/examples/README.md,sha256=dNn8kv0BNQem3NNhO5mbOANQoK8UUYOo7rnkCFV9tnE,2882
9
9
  mesa/examples/__init__.py,sha256=iJpTRiCJUwLVA253t5BIxoX3bFnPJ2_XPzET3ev5mxg,835
10
10
  mesa/examples/advanced/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  mesa/examples/advanced/epstein_civil_violence/Epstein Civil Violence.ipynb,sha256=yh50ZAK2BVJyJIKsQTTxywnasqWn1IiQUVrwmZKue4w,29032
12
12
  mesa/examples/advanced/epstein_civil_violence/Readme.md,sha256=IEU5IZTe5EbvAA2vkYxiIw8vK3O0MZcjbxzn8I2cQic,1874
13
13
  mesa/examples/advanced/epstein_civil_violence/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- mesa/examples/advanced/epstein_civil_violence/agents.py,sha256=R1Nu-_c_qBPCvr1vl6GgamOP4AUV9GJdcF3V7frAgdY,5676
15
- mesa/examples/advanced/epstein_civil_violence/app.py,sha256=GpfqVX6iu3EydsikrPT_JZKkXpb-WHHuwBYP_NZqivY,2062
16
- mesa/examples/advanced/epstein_civil_violence/model.py,sha256=HFA6hsxHVXwjqSlTA7EB9-kctiuzIWWod0zdbEv7y84,5193
14
+ mesa/examples/advanced/epstein_civil_violence/agents.py,sha256=0X4JLj2K2cl1bACkFLI6-K6tKbr2SLZlAy_kjgUDjzA,5863
15
+ mesa/examples/advanced/epstein_civil_violence/app.py,sha256=puJmjkEevHyilfDpnkE65Y2ax6JEyOALg-IEtK8jBKk,1787
16
+ mesa/examples/advanced/epstein_civil_violence/model.py,sha256=fcTkjCRhEhDerDC1W_lrezdoWD1y5xIublkGIhCak8w,3918
17
17
  mesa/examples/advanced/pd_grid/Readme.md,sha256=UVUQxZRFdfymCKDdQEn3ZEwgSqgp9cKJPsU8oZpLFnY,2367
18
18
  mesa/examples/advanced/pd_grid/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
19
  mesa/examples/advanced/pd_grid/agents.py,sha256=DzGj4LZUjV0xMQAwkRsv2Aoap1cUvLscJswfA1PdVDs,1716
20
20
  mesa/examples/advanced/pd_grid/analysis.ipynb,sha256=ReYtRe2JVyCCXoMBONvynXDQ_eGtQSWhNcuJY3CYTTI,82323
21
- mesa/examples/advanced/pd_grid/app.py,sha256=y-W_cWeaXDtsK02ptM1tR8VbHUGO5DMua1Rf9qB7Cgo,1370
21
+ mesa/examples/advanced/pd_grid/app.py,sha256=G4hKCQH4CXG_6OhoUyQeG4HFyx2I5gZuGkPkK1uh2lQ,1390
22
22
  mesa/examples/advanced/pd_grid/model.py,sha256=iKy1Oa5lG_hlxwlw67NfFLP9dKk5uDreaaT0xO9-55A,2325
23
23
  mesa/examples/advanced/sugarscape_g1mt/Readme.md,sha256=x3kKw1Rre2FPkNhGDLtdzeThmH089mxsGYUPZUeu26k,3595
24
24
  mesa/examples/advanced/sugarscape_g1mt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
25
  mesa/examples/advanced/sugarscape_g1mt/agents.py,sha256=zE7zbO2_OaQiFDq_-t-0hv4ButBWv26dnS1zaPc3_ZE,10183
26
- mesa/examples/advanced/sugarscape_g1mt/app.py,sha256=qyVXRABxwvl3bAC6kC_t69JdunBe-RE-jCUyXASN5lo,2032
26
+ mesa/examples/advanced/sugarscape_g1mt/app.py,sha256=PYuHoAH4AfU8fbrkBpY-ZW8evwz5izLEP8srN1CHp_Y,1946
27
27
  mesa/examples/advanced/sugarscape_g1mt/model.py,sha256=VVoUni3N2yk7vLEcWC1hiQemaa1vmzJU3gKxVRXxnqM,6069
28
28
  mesa/examples/advanced/sugarscape_g1mt/sugar-map.txt,sha256=zZtGYciBPT4miZVnbVuoQ5TugTmGrbDWV9yb5KH6tnU,5000
29
29
  mesa/examples/advanced/sugarscape_g1mt/tests.py,sha256=UNahmZTgLquSqmoi_9GcE3JP0qBHjkrHFZ15NMm0ce8,2517
30
30
  mesa/examples/advanced/wolf_sheep/Readme.md,sha256=6zrtCg4Fb-hgQxqdLMpTkIYMwD6owCv8BMz_qn0N98Q,3165
31
31
  mesa/examples/advanced/wolf_sheep/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
32
  mesa/examples/advanced/wolf_sheep/agents.py,sha256=UocDCsKmXkWxt0-ToVIOhBjX-amYwMtZbHN8U2AolFI,3068
33
- mesa/examples/advanced/wolf_sheep/app.py,sha256=oqb8ZsEj7aP-Rhh5RiuQ9c8Za1wrbmtrehq8lUDlGgA,2066
33
+ mesa/examples/advanced/wolf_sheep/app.py,sha256=n-WIPMHPYRvqrnsEF7y7mTLN5XKxKB3rJhQZzXZHwo8,2210
34
34
  mesa/examples/advanced/wolf_sheep/model.py,sha256=qtCTA2fBP9lA7jJ8UUJ5SIy8gXW7K73YoY8F3YDKp6k,4522
35
35
  mesa/examples/basic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
36
  mesa/examples/basic/boid_flockers/Readme.md,sha256=4KJinsLPtUciQSMzvaX3tU5r1HTUg3AFOFDKy73W5RE,894
37
37
  mesa/examples/basic/boid_flockers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
38
  mesa/examples/basic/boid_flockers/agents.py,sha256=QXT1zxOq_kdk_w60H2zPV3KpivzCHQ-ApyFIIDvxvok,2693
39
- mesa/examples/basic/boid_flockers/app.py,sha256=QutSC7do1EgYATzJ-uSJTyoAtvM3HoVv9E3JRSviFP4,1269
39
+ mesa/examples/basic/boid_flockers/app.py,sha256=5wKzyctjTq3iX1MJc69l3753a_iyYhFq3kv54h7dGSE,1289
40
40
  mesa/examples/basic/boid_flockers/model.py,sha256=o335lgyGQ1E5TkAj4B-INhUL65mO0dEV3tf3gG40FvU,2201
41
41
  mesa/examples/basic/boltzmann_wealth_model/Readme.md,sha256=wl1ylO9KWoTiuIJKOnk2FGdcmyVUqJ5wiSbVUa3WWAc,2725
42
42
  mesa/examples/basic/boltzmann_wealth_model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
43
  mesa/examples/basic/boltzmann_wealth_model/agents.py,sha256=uVUo9jWQnv5I3uCaYE_N7X-cOdHhdy6RtLUL_znELgI,892
44
- mesa/examples/basic/boltzmann_wealth_model/app.py,sha256=MmTWGFT-BiWobXeTIAcfehVxjC0tQdsM9ILTGoPHXCw,1943
44
+ mesa/examples/basic/boltzmann_wealth_model/app.py,sha256=ltSC6BD5rEIecY0JIXK92BfWcZJpNaioRzfnxzzMsEk,2069
45
45
  mesa/examples/basic/boltzmann_wealth_model/model.py,sha256=BYcfR5Nw0zXkKP72CoVnLkIvV-IVnNKKNQ7KsbJ07pc,1508
46
46
  mesa/examples/basic/boltzmann_wealth_model/st_app.py,sha256=v3Je2hSe8nXPgfmZhX8lHM-7xs8dk2g1Zz0X81AqX3k,3466
47
47
  mesa/examples/basic/conways_game_of_life/Readme.md,sha256=VRgN6roF6leQ_IMYwxFypSfFjZo9jnCd-rkPTjpp7II,1453
48
48
  mesa/examples/basic/conways_game_of_life/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
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=2r3j5aFuNAMrlRd8nAAexRNViOfj86pLuZTd8FWKv0E,1232
50
+ mesa/examples/basic/conways_game_of_life/app.py,sha256=DrA1CwiT43rDMZGSDO62B77_QymySkq486IeV9K8nJY,1433
51
51
  mesa/examples/basic/conways_game_of_life/model.py,sha256=c7lwSelxTplbQlbfGjBSevS2TEg5DFJA8bvhbYbyD_s,1174
52
52
  mesa/examples/basic/conways_game_of_life/st_app.py,sha256=_poqU2VR4rfiiq4WFXTbOUSW7liuM86iq913mW6LS50,2400
53
53
  mesa/examples/basic/schelling/Readme.md,sha256=CRKBfYtnLJLlTKLsTRQ-7gsQRxVxDooOBN5uP8PEtaU,2296
54
54
  mesa/examples/basic/schelling/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
55
  mesa/examples/basic/schelling/agents.py,sha256=dvznzN2As979x-4EH8Y-i7HhlCuv1OdtWYebOdxTdhk,773
56
56
  mesa/examples/basic/schelling/analysis.ipynb,sha256=JDJy6-U6eO-LrHWxZr1c3lkvtoY0DNHa-kJ4J-Z-wwo,5804
57
- mesa/examples/basic/schelling/app.py,sha256=-SXLVg7KPzquh7LausjqTzJh_EA3fFn4xXmY3H4Ba38,973
57
+ mesa/examples/basic/schelling/app.py,sha256=DlePd3iTkBSzurRy1vbZXlAugpxcEMFFR5Iy6b9RWp8,973
58
58
  mesa/examples/basic/schelling/model.py,sha256=szYiw76JD-OMlZ2Op80Y9L2PZ3VMVfyuUNl1J_jC8BE,1856
59
59
  mesa/examples/basic/virus_on_network/Readme.md,sha256=UnCkKiJK7wVw40a-oDR6qdf3QpCsBhgNOVZg-2UXPlc,2528
60
60
  mesa/examples/basic/virus_on_network/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
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=EQfXYV94GdnC71hVIl9Zpy4JqKNRFINCJxHFdOKbNTU,3340
62
+ mesa/examples/basic/virus_on_network/app.py,sha256=Bxjm2FHxnbjQd3V1absTM4GDOrWOlOYZtYMn3Yy0Ol8,2439
63
63
  mesa/examples/basic/virus_on_network/model.py,sha256=jQoCmvygwCvhUrlL0l7V8GcDLv94CgwtuK7DDGU8q8g,2813
64
64
  mesa/experimental/UserParam.py,sha256=f32nmFjroe76HpxU75ZCEOqFW2nAsDfmqIf8kQ1zt-E,2086
65
65
  mesa/experimental/__init__.py,sha256=faBYyHSp-sFQPaBx8-WsLToVKCndpSzpt18HmNZtasM,385
@@ -80,14 +80,16 @@ mesa/experimental/devs/simulator.py,sha256=wvqkLIDgbJNaem9nwMacyEYRp0W3ai5Oxptw3
80
80
  mesa/experimental/devs/examples/epstein_civil_violence.py,sha256=E8YSV3O5ihKsntGtnltHM-4IyS8eg2DSRUqmIiw_1iU,10916
81
81
  mesa/experimental/devs/examples/wolf_sheep.py,sha256=1eb1CfYNQoprqSJat-LPYPvwWH1ENQdj39viEqwSk0s,8103
82
82
  mesa/visualization/UserParam.py,sha256=Dl2WOwLYLf0pfLpabCZtIdFRyKZrK6Qtc3utZx5GPYg,2139
83
- mesa/visualization/__init__.py,sha256=sa8lqeLcDtte19SMzFiKP6K4CrVLxAPwrhDu_AsDWTs,395
84
- mesa/visualization/solara_viz.py,sha256=SHlQ8Y4k6EU7LxlJjjvvjDJWGWryahjQXCwMiVgoF0E,14944
83
+ mesa/visualization/__init__.py,sha256=RSv-SKZgeadKq_QawaR7oTqi9JBQu99yqe717-0aUnA,742
84
+ mesa/visualization/mpl_space_drawing.py,sha256=E8IpP6Us8JLBBMDOKdWpfH7NuLQaZbuzFqviJbXuPWk,18862
85
+ mesa/visualization/solara_viz.py,sha256=2YDoj3HAFKG7LrdbOaLOBUYKnTnvWGnEGwqPqhXGPY0,15409
85
86
  mesa/visualization/utils.py,sha256=lJHgRKF5BHLf72Tw3YpwyiWuRoIimaTKQ7xBCw_Rx3A,146
86
- mesa/visualization/components/altair.py,sha256=e_J3ZPv4ldtJje5pUm1UgNqcMh7Nc4fyIgvbbcCWESg,4856
87
- mesa/visualization/components/matplotlib.py,sha256=EBK1zRCl71LkOgeOV7eQE1Ig22n1ZFGtNBhweozPFYk,13241
88
- mesa-3.0.0b2.dist-info/METADATA,sha256=8FG5-NHehf7et0SOy8FKHCFH-9nvMwOhKpXNi6vfl10,9849
89
- mesa-3.0.0b2.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
90
- mesa-3.0.0b2.dist-info/entry_points.txt,sha256=IOcQtetGF8l4wHpOs_hGb19Rz-FS__BMXOJR10IBPsA,39
91
- mesa-3.0.0b2.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
92
- mesa-3.0.0b2.dist-info/licenses/NOTICE,sha256=GbsWoK0QWv1JyZ_xer2s-jNilv0RtWl-0UrtlJANHPg,578
93
- mesa-3.0.0b2.dist-info/RECORD,,
87
+ mesa/visualization/components/__init__.py,sha256=Bq3nrPikcaIo9BSs0O3zptWVLlUmAkLo3s0mEmpH1RE,3022
88
+ mesa/visualization/components/altair_components.py,sha256=wotpFFQgMY-ZR3lNVm_fRos-iDg0Wjnj6Tk67_7f1SQ,5847
89
+ mesa/visualization/components/matplotlib_components.py,sha256=eYd94MKufaWErYvpiYwq73Yx16Qfj_TdLIC77g5gF-Q,5411
90
+ mesa-3.0.0rc0.dist-info/METADATA,sha256=XJEJSgjqWZ14isamAG2WeKZoVMTQY83D6Z0dM80R2qg,9850
91
+ mesa-3.0.0rc0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
92
+ mesa-3.0.0rc0.dist-info/entry_points.txt,sha256=IOcQtetGF8l4wHpOs_hGb19Rz-FS__BMXOJR10IBPsA,39
93
+ mesa-3.0.0rc0.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
94
+ mesa-3.0.0rc0.dist-info/licenses/NOTICE,sha256=GbsWoK0QWv1JyZ_xer2s-jNilv0RtWl-0UrtlJANHPg,578
95
+ mesa-3.0.0rc0.dist-info/RECORD,,
@@ -1,386 +0,0 @@
1
- """Matplotlib based solara components for visualization MESA spaces and plots."""
2
-
3
- import warnings
4
-
5
- import matplotlib.pyplot as plt
6
- import networkx as nx
7
- import numpy as np
8
- import solara
9
- from matplotlib.cm import ScalarMappable
10
- from matplotlib.colors import LinearSegmentedColormap, Normalize, to_rgba
11
- from matplotlib.figure import Figure
12
-
13
- import mesa
14
- from mesa.experimental.cell_space import Grid, VoronoiGrid
15
- from mesa.space import PropertyLayer
16
- from mesa.visualization.utils import update_counter
17
-
18
-
19
- def make_space_matplotlib(agent_portrayal=None, propertylayer_portrayal=None):
20
- """Create a Matplotlib-based space visualization component.
21
-
22
- Args:
23
- agent_portrayal (function): Function to portray agents
24
- propertylayer_portrayal (dict): Dictionary of PropertyLayer portrayal specifications
25
-
26
- Returns:
27
- function: A function that creates a SpaceMatplotlib component
28
- """
29
- if agent_portrayal is None:
30
-
31
- def agent_portrayal(a):
32
- return {"id": a.unique_id}
33
-
34
- def MakeSpaceMatplotlib(model):
35
- return SpaceMatplotlib(model, agent_portrayal, propertylayer_portrayal)
36
-
37
- return MakeSpaceMatplotlib
38
-
39
-
40
- @solara.component
41
- def SpaceMatplotlib(
42
- model,
43
- agent_portrayal,
44
- propertylayer_portrayal,
45
- dependencies: list[any] | None = None,
46
- ):
47
- """Create a Matplotlib-based space visualization component."""
48
- update_counter.get()
49
- space_fig = Figure()
50
- space_ax = space_fig.subplots()
51
- space = getattr(model, "grid", None)
52
- if space is None:
53
- space = getattr(model, "space", None)
54
-
55
- # https://stackoverflow.com/questions/67524641/convert-multiple-isinstance-checks-to-structural-pattern-matching
56
- match space:
57
- case mesa.space._Grid():
58
- _draw_grid(space, space_ax, agent_portrayal, propertylayer_portrayal, model)
59
- case mesa.space.ContinuousSpace():
60
- _draw_continuous_space(space, space_ax, agent_portrayal, model)
61
- case mesa.space.NetworkGrid():
62
- _draw_network_grid(space, space_ax, agent_portrayal)
63
- case VoronoiGrid():
64
- _draw_voronoi(space, space_ax, agent_portrayal)
65
- case Grid(): # matches OrthogonalMooreGrid, OrthogonalVonNeumannGrid, and Hexgrid
66
- # fixme add a separate draw method for hexgrids in the future
67
- _draw_discrete_space_grid(space, space_ax, agent_portrayal)
68
- case None:
69
- if propertylayer_portrayal:
70
- draw_property_layers(space_ax, space, propertylayer_portrayal, model)
71
-
72
- solara.FigureMatplotlib(
73
- space_fig, format="png", bbox_inches="tight", dependencies=dependencies
74
- )
75
-
76
-
77
- def draw_property_layers(ax, space, propertylayer_portrayal, model):
78
- """Draw PropertyLayers on the given axes.
79
-
80
- Args:
81
- ax (matplotlib.axes.Axes): The axes to draw on.
82
- space (mesa.space._Grid): The space containing the PropertyLayers.
83
- propertylayer_portrayal (dict): Dictionary of PropertyLayer portrayal specifications.
84
- model (mesa.Model): The model instance.
85
- """
86
- for layer_name, portrayal in propertylayer_portrayal.items():
87
- layer = getattr(model, layer_name, None)
88
- if not isinstance(layer, PropertyLayer):
89
- continue
90
-
91
- data = layer.data.astype(float) if layer.data.dtype == bool else layer.data
92
- width, height = data.shape if space is None else (space.width, space.height)
93
-
94
- if space and data.shape != (width, height):
95
- warnings.warn(
96
- f"Layer {layer_name} dimensions ({data.shape}) do not match space dimensions ({width}, {height}).",
97
- UserWarning,
98
- stacklevel=2,
99
- )
100
-
101
- # Get portrayal properties, or use defaults
102
- alpha = portrayal.get("alpha", 1)
103
- vmin = portrayal.get("vmin", np.min(data))
104
- vmax = portrayal.get("vmax", np.max(data))
105
- colorbar = portrayal.get("colorbar", True)
106
-
107
- # Draw the layer
108
- if "color" in portrayal:
109
- rgba_color = to_rgba(portrayal["color"])
110
- normalized_data = (data - vmin) / (vmax - vmin)
111
- rgba_data = np.full((*data.shape, 4), rgba_color)
112
- rgba_data[..., 3] *= normalized_data * alpha
113
- rgba_data = np.clip(rgba_data, 0, 1)
114
- cmap = LinearSegmentedColormap.from_list(
115
- layer_name, [(0, 0, 0, 0), (*rgba_color[:3], alpha)]
116
- )
117
- im = ax.imshow(
118
- rgba_data.transpose(1, 0, 2),
119
- extent=(0, width, 0, height),
120
- origin="lower",
121
- )
122
- if colorbar:
123
- norm = Normalize(vmin=vmin, vmax=vmax)
124
- sm = ScalarMappable(norm=norm, cmap=cmap)
125
- sm.set_array([])
126
- ax.figure.colorbar(sm, ax=ax, orientation="vertical")
127
-
128
- elif "colormap" in portrayal:
129
- cmap = portrayal.get("colormap", "viridis")
130
- if isinstance(cmap, list):
131
- cmap = LinearSegmentedColormap.from_list(layer_name, cmap)
132
- im = ax.imshow(
133
- data.T,
134
- cmap=cmap,
135
- alpha=alpha,
136
- vmin=vmin,
137
- vmax=vmax,
138
- extent=(0, width, 0, height),
139
- origin="lower",
140
- )
141
- if colorbar:
142
- plt.colorbar(im, ax=ax, label=layer_name)
143
- else:
144
- raise ValueError(
145
- f"PropertyLayer {layer_name} portrayal must include 'color' or 'colormap'."
146
- )
147
-
148
-
149
- def _draw_grid(space, space_ax, agent_portrayal, propertylayer_portrayal, model):
150
- if propertylayer_portrayal:
151
- draw_property_layers(space_ax, space, propertylayer_portrayal, model)
152
-
153
- agent_data = _get_agent_data(space, agent_portrayal)
154
-
155
- space_ax.set_xlim(0, space.width)
156
- space_ax.set_ylim(0, space.height)
157
- _split_and_scatter(agent_data, space_ax)
158
-
159
- # Draw grid lines
160
- for x in range(space.width + 1):
161
- space_ax.axvline(x, color="gray", linestyle=":")
162
- for y in range(space.height + 1):
163
- space_ax.axhline(y, color="gray", linestyle=":")
164
-
165
-
166
- def _get_agent_data(space, agent_portrayal):
167
- """Helper function to get agent data for visualization."""
168
- x, y, s, c, m = [], [], [], [], []
169
- for agents, pos in space.coord_iter():
170
- if not agents:
171
- continue
172
- if not isinstance(agents, list):
173
- agents = [agents] # noqa PLW2901
174
- for agent in agents:
175
- data = agent_portrayal(agent)
176
- x.append(pos[0] + 0.5) # Center the agent in the cell
177
- y.append(pos[1] + 0.5) # Center the agent in the cell
178
- default_size = (180 / max(space.width, space.height)) ** 2
179
- s.append(data.get("size", default_size))
180
- c.append(data.get("color", "tab:blue"))
181
- m.append(data.get("shape", "o"))
182
- return {"x": x, "y": y, "s": s, "c": c, "m": m}
183
-
184
-
185
- def _split_and_scatter(portray_data, space_ax):
186
- """Helper function to split and scatter agent data."""
187
- for marker in set(portray_data["m"]):
188
- mask = [m == marker for m in portray_data["m"]]
189
- space_ax.scatter(
190
- [x for x, show in zip(portray_data["x"], mask) if show],
191
- [y for y, show in zip(portray_data["y"], mask) if show],
192
- s=[s for s, show in zip(portray_data["s"], mask) if show],
193
- c=[c for c, show in zip(portray_data["c"], mask) if show],
194
- marker=marker,
195
- )
196
-
197
-
198
- def _draw_network_grid(space, space_ax, agent_portrayal):
199
- graph = space.G
200
- pos = nx.spring_layout(graph, seed=0)
201
- nx.draw(
202
- graph,
203
- ax=space_ax,
204
- pos=pos,
205
- **agent_portrayal(graph),
206
- )
207
-
208
-
209
- def _draw_continuous_space(space, space_ax, agent_portrayal, model):
210
- def portray(space):
211
- x = []
212
- y = []
213
- s = [] # size
214
- c = [] # color
215
- m = [] # shape
216
- for agent in space._agent_to_index:
217
- data = agent_portrayal(agent)
218
- _x, _y = agent.pos
219
- x.append(_x)
220
- y.append(_y)
221
-
222
- # This is matplotlib's default marker size
223
- default_size = 20
224
- size = data.get("size", default_size)
225
- s.append(size)
226
- color = data.get("color", "tab:blue")
227
- c.append(color)
228
- mark = data.get("shape", "o")
229
- m.append(mark)
230
- return {"x": x, "y": y, "s": s, "c": c, "m": m}
231
-
232
- # Determine border style based on space.torus
233
- border_style = "solid" if not space.torus else (0, (5, 10))
234
-
235
- # Set the border of the plot
236
- for spine in space_ax.spines.values():
237
- spine.set_linewidth(1.5)
238
- spine.set_color("black")
239
- spine.set_linestyle(border_style)
240
-
241
- width = space.x_max - space.x_min
242
- x_padding = width / 20
243
- height = space.y_max - space.y_min
244
- y_padding = height / 20
245
- space_ax.set_xlim(space.x_min - x_padding, space.x_max + x_padding)
246
- space_ax.set_ylim(space.y_min - y_padding, space.y_max + y_padding)
247
-
248
- # Portray and scatter the agents in the space
249
- _split_and_scatter(portray(space), space_ax)
250
-
251
-
252
- def _draw_voronoi(space, space_ax, agent_portrayal):
253
- def portray(g):
254
- x = []
255
- y = []
256
- s = [] # size
257
- c = [] # color
258
-
259
- for cell in g.all_cells:
260
- for agent in cell.agents:
261
- data = agent_portrayal(agent)
262
- x.append(cell.coordinate[0])
263
- y.append(cell.coordinate[1])
264
- if "size" in data:
265
- s.append(data["size"])
266
- if "color" in data:
267
- c.append(data["color"])
268
- out = {"x": x, "y": y}
269
- out["s"] = s
270
- if len(c) > 0:
271
- out["c"] = c
272
-
273
- return out
274
-
275
- x_list = [i[0] for i in space.centroids_coordinates]
276
- y_list = [i[1] for i in space.centroids_coordinates]
277
- x_max = max(x_list)
278
- x_min = min(x_list)
279
- y_max = max(y_list)
280
- y_min = min(y_list)
281
-
282
- width = x_max - x_min
283
- x_padding = width / 20
284
- height = y_max - y_min
285
- y_padding = height / 20
286
- space_ax.set_xlim(x_min - x_padding, x_max + x_padding)
287
- space_ax.set_ylim(y_min - y_padding, y_max + y_padding)
288
- space_ax.scatter(**portray(space))
289
-
290
- for cell in space.all_cells:
291
- polygon = cell.properties["polygon"]
292
- space_ax.fill(
293
- *zip(*polygon),
294
- alpha=min(1, cell.properties[space.cell_coloring_property]),
295
- c="red",
296
- ) # Plot filled polygon
297
- space_ax.plot(*zip(*polygon), color="black") # Plot polygon edges in black
298
-
299
-
300
- def _draw_discrete_space_grid(space: Grid, space_ax, agent_portrayal):
301
- if space._ndims != 2:
302
- raise ValueError("Space must be 2D")
303
-
304
- def portray(g):
305
- x = []
306
- y = []
307
- s = [] # size
308
- c = [] # color
309
-
310
- for cell in g.all_cells:
311
- for agent in cell.agents:
312
- data = agent_portrayal(agent)
313
- x.append(cell.coordinate[0])
314
- y.append(cell.coordinate[1])
315
- if "size" in data:
316
- s.append(data["size"])
317
- if "color" in data:
318
- c.append(data["color"])
319
- out = {"x": x, "y": y}
320
- out["s"] = s
321
- if len(c) > 0:
322
- out["c"] = c
323
-
324
- return out
325
-
326
- space_ax.set_xlim(0, space.width)
327
- space_ax.set_ylim(0, space.height)
328
-
329
- # Draw grid lines
330
- for x in range(space.width + 1):
331
- space_ax.axvline(x, color="gray", linestyle=":")
332
- for y in range(space.height + 1):
333
- space_ax.axhline(y, color="gray", linestyle=":")
334
-
335
- space_ax.scatter(**portray(space))
336
-
337
-
338
- def make_plot_measure(measure: str | dict[str, str] | list[str] | tuple[str]):
339
- """Create a plotting function for a specified measure.
340
-
341
- Args:
342
- measure (str | dict[str, str] | list[str] | tuple[str]): Measure(s) to plot.
343
-
344
- Returns:
345
- function: A function that creates a PlotMatplotlib component.
346
- """
347
-
348
- def MakePlotMeasure(model):
349
- return PlotMatplotlib(model, measure)
350
-
351
- return MakePlotMeasure
352
-
353
-
354
- @solara.component
355
- def PlotMatplotlib(model, measure, dependencies: list[any] | None = None):
356
- """Create a Matplotlib-based plot for a measure or measures.
357
-
358
- Args:
359
- model (mesa.Model): The model instance.
360
- measure (str | dict[str, str] | list[str] | tuple[str]): Measure(s) to plot.
361
- dependencies (list[any] | None): Optional dependencies for the plot.
362
-
363
- Returns:
364
- solara.FigureMatplotlib: A component for rendering the plot.
365
- """
366
- update_counter.get()
367
- fig = Figure()
368
- ax = fig.subplots()
369
- df = model.datacollector.get_model_vars_dataframe()
370
- if isinstance(measure, str):
371
- ax.plot(df.loc[:, measure])
372
- ax.set_ylabel(measure)
373
- elif isinstance(measure, dict):
374
- for m, color in measure.items():
375
- ax.plot(df.loc[:, m], label=m, color=color)
376
- ax.legend(loc="best")
377
- elif isinstance(measure, list | tuple):
378
- for m in measure:
379
- ax.plot(df.loc[:, m], label=m)
380
- ax.legend(loc="best")
381
- ax.set_xlabel("Step")
382
- # Set integer x axis
383
- ax.xaxis.set_major_locator(plt.MaxNLocator(integer=True))
384
- solara.FigureMatplotlib(
385
- fig, format="png", bbox_inches="tight", dependencies=dependencies
386
- )