From 0c3595612083305fd51c1bb66cb0a09af699c2d6 Mon Sep 17 00:00:00 2001 From: rht Date: Fri, 16 Feb 2024 07:57:23 -0500 Subject: [PATCH 01/25] ci: Move codespell to pre-commit (#2040) * ci: Move codespell to pre-commit * Intentionally introduce typos * Fix intentionally introduced typos --- .github/workflows/codespell.yml | 18 ------------------ .pre-commit-config.yaml | 8 ++++++++ 2 files changed, 8 insertions(+), 18 deletions(-) delete mode 100644 .github/workflows/codespell.yml diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml deleted file mode 100644 index 119fe8904e6..00000000000 --- a/.github/workflows/codespell.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: build - -on: - push: - branches: - - main - - release** - pull_request: - -jobs: - codespell: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: codespell-project/actions-codespell@master - with: - ignore_words_file: .codespellignore - skip: .*bootstrap.*,*.js,.*bootstrap-theme.css.map diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2cf01563948..32f2f7d53a9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,3 +24,11 @@ repos: - id: trailing-whitespace - id: check-toml - id: check-yaml +- repo: https://github.com/codespell-project/codespell + rev: v2.2.6 + hooks: + - id: codespell + args: [ + "--ignore-words", + ".codespellignore", + ] From ac9fdd10d2dfe100cd585a336266a382f220c702 Mon Sep 17 00:00:00 2001 From: rht Date: Fri, 16 Feb 2024 07:58:38 -0500 Subject: [PATCH 02/25] tests: Speed up test_batch_run (#2039) * tests: Speed up test_batch_run * ci: Print 10 slowest unit tests --- .github/workflows/build_lint.yml | 2 +- tests/test_batch_run.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_lint.yml b/.github/workflows/build_lint.yml index 39ee106c6db..c1dcedb83d5 100644 --- a/.github/workflows/build_lint.yml +++ b/.github/workflows/build_lint.yml @@ -73,7 +73,7 @@ jobs: - name: Install Mesa run: pip install --no-deps . - name: Test with pytest - run: pytest --cov=mesa tests/ --cov-report=xml + run: pytest --durations=10 --cov=mesa tests/ --cov-report=xml - if: matrix.os == 'ubuntu' name: Codecov uses: codecov/codecov-action@v4 diff --git a/tests/test_batch_run.py b/tests/test_batch_run.py index 1557666f34f..f5ddb0ae9f3 100644 --- a/tests/test_batch_run.py +++ b/tests/test_batch_run.py @@ -124,8 +124,8 @@ def test_batch_run_with_params(): mesa.batch_run( MockModel, { - "variable_model_params": range(5), - "variable_agent_params": ["H", "E", "L", "L", "O"], + "variable_model_params": range(3), + "variable_agent_params": ["H", "E", "Y"], }, number_processes=2, ) @@ -148,7 +148,7 @@ def test_batch_run_no_agent_reporters(): def test_batch_run_single_core(): - mesa.batch_run(MockModel, {}, number_processes=1, iterations=10) + mesa.batch_run(MockModel, {}, number_processes=1, iterations=6) def test_batch_run_unhashable_param(): From 8418b5756d488c95aa054dd135388a6c09bb60a3 Mon Sep 17 00:00:00 2001 From: Corvince Date: Mon, 19 Feb 2024 22:33:43 +0100 Subject: [PATCH 03/25] Update benchmarks.yml (#2043) --- .github/workflows/benchmarks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index 8428aba7235..d59663f6b53 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -29,7 +29,7 @@ jobs: - name: Add project directory to PYTHONPATH run: echo "PYTHONPATH=$PYTHONPATH:$(pwd)" >> $GITHUB_ENV - name: Install dependencies - run: pip install numpy pandas tqdm tabulate + run: pip install numpy pandas tqdm tabulate matplotlib solara networkx # Benchmarks on the projectmesa main branch - name: Checkout main branch uses: actions/checkout@v4 From 2b379567460b35226ca8f788012e6dd0bc0ef293 Mon Sep 17 00:00:00 2001 From: rht Date: Thu, 15 Feb 2024 18:38:45 -0500 Subject: [PATCH 04/25] docs: Convert howto.rst -> howto.md via rst2myst --- docs/howto.md | 65 ++++++++++++++++++++++++++++++++++++++++++++++ docs/howto.rst | 70 -------------------------------------------------- 2 files changed, 65 insertions(+), 70 deletions(-) create mode 100644 docs/howto.md delete mode 100644 docs/howto.rst diff --git a/docs/howto.md b/docs/howto.md new file mode 100644 index 00000000000..adb565eb55d --- /dev/null +++ b/docs/howto.md @@ -0,0 +1,65 @@ +# How-to Guide + +Here you can find code that allows you to get to get started on common tasks in Mesa. + +## Models with Discrete Time + +If you have `Multiple` type agents and one of them has time attribute you can still build a model that is run by discrete time. In this example, each step of the model, and the agents have a time attribute that is equal to the discrete time to run its own step. + +```python +if self.model.schedule.time in self.discrete_time: + self.model.space.move_agent(self, new_pos) +``` + +## Implementing Model Level Functions in Staged Activation + +In staged activation, if you may want a function to be implemented only on the model level and not at the level of agents. +For such functions, include the prefix "model." before the model function name, when defining the function list. +For example, consider a central employment exchange which adjust the wage rate common to all laborers +in the direction of excess demand. + +```python stage_list=[Send_Labour_Supply, Send_Labour_Demand, model.Adjust_Wage_Rate] self.schedule = StagedActivation(self,stage_list,shuffle=True) + +``` + +## Using `` `numpy.random` `` + +Sometimes you need to use `numpy`'s `random` library, for example to get a Poisson distribution. + +```python +class MyModel(Model): + def __init__(self, ...): + super().__init__() + self.random = np.random.default_rng(seed) +``` + +And just use `numpy`'s random as usual, e.g. `self.random.poisson()`. + +## Using multi-process `` `batch_run` `` on Windows + +You will have an issue with `batch_run` and `number_processes = None`. Your cell will +show no progress, and in your terminal you will receive *AttributeError: Can't get attribute 'MoneyModel' on +\*. One way to overcome this is to take your code outside of Jupyter and adjust the above +code as follows. + +```python +from multiprocessing import freeze_support + +params = {"width": 10, "height": 10, "N": range(10, 500, 10)} + +if __name__ == '__main__': + freeze_support() + results = batch_run( + MoneyModel, + parameters=params, + iterations=5, + max_steps=100, + number_processes=None, + data_collection_period=1, + display_progress=True, + ) +``` + +If you would still like to run your code in Jupyter you will need to adjust the cell as noted above. Then you can +you can add the [nbmultitask library](<(https://nbviewer.org/github/micahscopes/nbmultitask/blob/39b6f31b047e8a51a0fcb5c93ae4572684f877ce/examples.ipynb)>) +or look at this [stackoverflow](https://stackoverflow.com/questions/50937362/multiprocessing-on-python-3-jupyter). diff --git a/docs/howto.rst b/docs/howto.rst deleted file mode 100644 index 09792af5bbd..00000000000 --- a/docs/howto.rst +++ /dev/null @@ -1,70 +0,0 @@ -How-to Guide -============ - -Here you can find code that allows you to get to get started on common tasks in Mesa. - -Models with Discrete Time -------------------------- -If you have `Multiple` type agents and one of them has time attribute you can still build a model that is run by discrete time. In this example, each step of the model, and the agents have a time attribute that is equal to the discrete time to run its own step. - -.. code:: python - - if self.model.schedule.time in self.discrete_time: - self.model.space.move_agent(self, new_pos) - -Implementing Model Level Functions in Staged Activation -------------------------------------------------------- -In staged activation, if you may want a function to be implemented only on the model level and not at the level of agents. -For such functions, include the prefix "model." before the model function name, when defining the function list. -For example, consider a central employment exchange which adjust the wage rate common to all laborers -in the direction of excess demand. - -.. code:: python - stage_list=[Send_Labour_Supply, Send_Labour_Demand, model.Adjust_Wage_Rate] - self.schedule = StagedActivation(self,stage_list,shuffle=True) - -Using ```numpy.random``` -------------- - -Sometimes you need to use ``numpy``'s ``random`` library, for example to get a Poisson distribution. - -.. code:: python - - class MyModel(Model): - def __init__(self, ...): - super().__init__() - self.random = np.random.default_rng(seed) - -And just use `numpy`'s random as usual, e.g. ``self.random.poisson()``. - -Using multi-process ```batch_run``` on Windows -------------- - -You will have an issue with `batch_run` and `number_processes = None`. Your cell will -show no progress, and in your terminal you will receive *AttributeError: Can't get attribute 'MoneyModel' on -*. One way to overcome this is to take your code outside of Jupyter and adjust the above -code as follows. - - -.. code:: python - - from multiprocessing import freeze_support - - params = {"width": 10, "height": 10, "N": range(10, 500, 10)} - - if __name__ == '__main__': - freeze_support() - results = batch_run( - MoneyModel, - parameters=params, - iterations=5, - max_steps=100, - number_processes=None, - data_collection_period=1, - display_progress=True, - ) - - -If you would still like to run your code in Jupyter you will need to adjust the cell as noted above. Then you can -you can add the `nbmultitask library <(https://nbviewer.org/github/micahscopes/nbmultitask/blob/39b6f31b047e8a51a0fcb5c93ae4572684f877ce/examples.ipynb)>`__ -or look at this `stackoverflow `__. From 59528b49aeca355e3843e08318a9706b8c0a65e3 Mon Sep 17 00:00:00 2001 From: rht Date: Thu, 15 Feb 2024 18:43:48 -0500 Subject: [PATCH 05/25] docs: Apply manual fixes to howto.md --- docs/howto.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/howto.md b/docs/howto.md index adb565eb55d..ae47e7f7225 100644 --- a/docs/howto.md +++ b/docs/howto.md @@ -18,11 +18,11 @@ For such functions, include the prefix "model." before the model function name, For example, consider a central employment exchange which adjust the wage rate common to all laborers in the direction of excess demand. -```python stage_list=[Send_Labour_Supply, Send_Labour_Demand, model.Adjust_Wage_Rate] self.schedule = StagedActivation(self,stage_list,shuffle=True) - +```python +stage_list=[Send_Labour_Supply, Send_Labour_Demand, model.Adjust_Wage_Rate] self.schedule = StagedActivation(self,stage_list,shuffle=True) ``` -## Using `` `numpy.random` `` +## Using `numpy.random` Sometimes you need to use `numpy`'s `random` library, for example to get a Poisson distribution. @@ -35,7 +35,7 @@ class MyModel(Model): And just use `numpy`'s random as usual, e.g. `self.random.poisson()`. -## Using multi-process `` `batch_run` `` on Windows +## Using multi-process `batch_run` on Windows You will have an issue with `batch_run` and `number_processes = None`. Your cell will show no progress, and in your terminal you will receive *AttributeError: Can't get attribute 'MoneyModel' on @@ -61,5 +61,5 @@ if __name__ == '__main__': ``` If you would still like to run your code in Jupyter you will need to adjust the cell as noted above. Then you can -you can add the [nbmultitask library](<(https://nbviewer.org/github/micahscopes/nbmultitask/blob/39b6f31b047e8a51a0fcb5c93ae4572684f877ce/examples.ipynb)>) +you can add the [nbmultitask library](https://nbviewer.org/github/micahscopes/nbmultitask/blob/39b6f31b047e8a51a0fcb5c93ae4572684f877ce/examples.ipynb) or look at this [stackoverflow](https://stackoverflow.com/questions/50937362/multiprocessing-on-python-3-jupyter). From 1e443b948803c9217e5b28ad8cff834a66d8feff Mon Sep 17 00:00:00 2001 From: rht Date: Thu, 15 Feb 2024 18:54:05 -0500 Subject: [PATCH 06/25] docs: Convert best-practices.rst -> best-practices.md via rst2myst --- docs/best-practices.md | 80 +++++++++++++++++++++++++++++++++++++ docs/best-practices.rst | 87 ----------------------------------------- 2 files changed, 80 insertions(+), 87 deletions(-) create mode 100644 docs/best-practices.md delete mode 100644 docs/best-practices.rst diff --git a/docs/best-practices.md b/docs/best-practices.md new file mode 100644 index 00000000000..e7f695ac876 --- /dev/null +++ b/docs/best-practices.md @@ -0,0 +1,80 @@ +# Best Practices + +Here are some general principles that have proven helpful for developing models. + +## Model Layout + +A model should be contained in a folder named with lower-case letters and +underscores, such as `thunder_cats`. Within that directory: + +- `README.md` describes the model, how to use it, and any other details. + Github will automatically show this file to anyone visiting the directory. +- `model.py` should contain the model class. If the file gets large, it may + make sense to move the complex bits into other files, but this is the first + place readers will look to figure out how the model works. +- `server.py` should contain the visualization support, including the server + class. +- `run.py` is a Python script that will run the model when invoked via + `mesa runserver`. + +After the number of files grows beyond a half-dozen, try to use sub-folders to +organize them. For example, if the visualization uses image files, put those in +an `images` directory. + +The [Schelling](https://github.com/projectmesa/mesa-examples/tree/main/examples/schelling) model is +a good example of a small well-packaged model. + +It's easy to create a cookiecutter mesa model by running `mesa startproject` + +## Randomization + +If your model involves some random choice, you can use the built-in `random` +property that Mesa `Model` and `Agent` objects have. This works exactly +like the built-in `random` library. + +```python +class AwesomeModel(Model): + # ... + + def cool_method(self): + interesting_number = self.random.random() + print(interesting_number) + +class AwesomeAgent(Agent): + # ... + def __init__(self, unique_id, model, ...): + super().__init__(unique_id, model) + # ... + + def my_method(self): + random_number = self.random.randint(0, 100) +``` + +(The agent's random property is just a reference to its parent model's +`random` property). + +When a model object is created, its random property is automatically seeded +with the current time. The seed determines the sequence of random numbers; if +you instantiate a model with the same seed, you will get the same results. +To allow you to set the seed, make sure your model has a `seed` argument in its +constructor. + +```python +class AwesomeModel(Model): + + def __init__(self, seed=None): + pass + + def cool_method(self): + interesting_number = self.random.random() + print(interesting_number) + +>>> model0 = AwesomeModel(seed=0) +>>> model0._seed +0 +>>> model0.cool_method() +0.8444218515250481 +>>> model1 = AwesomeModel(seed=0) +>>> model1.cool_method() +0.8444218515250481 +``` diff --git a/docs/best-practices.rst b/docs/best-practices.rst deleted file mode 100644 index a73c125f899..00000000000 --- a/docs/best-practices.rst +++ /dev/null @@ -1,87 +0,0 @@ -Best Practices -============== - -Here are some general principles that have proven helpful for developing models. - -Model Layout ------------- - -A model should be contained in a folder named with lower-case letters and -underscores, such as ``thunder_cats``. Within that directory: - -* ``README.md`` describes the model, how to use it, and any other details. - Github will automatically show this file to anyone visiting the directory. - -* ``model.py`` should contain the model class. If the file gets large, it may - make sense to move the complex bits into other files, but this is the first - place readers will look to figure out how the model works. - -* ``server.py`` should contain the visualization support, including the server - class. - -* ``run.py`` is a Python script that will run the model when invoked via - ``mesa runserver``. - -After the number of files grows beyond a half-dozen, try to use sub-folders to -organize them. For example, if the visualization uses image files, put those in -an ``images`` directory. - -The `Schelling -`_ model is -a good example of a small well-packaged model. - -It's easy to create a cookiecutter mesa model by running ``mesa startproject`` - -Randomization -------------- - -If your model involves some random choice, you can use the built-in ``random`` -property that Mesa ``Model`` and ``Agent`` objects have. This works exactly -like the built-in ``random`` library. - -.. code:: python - - class AwesomeModel(Model): - # ... - - def cool_method(self): - interesting_number = self.random.random() - print(interesting_number) - - class AwesomeAgent(Agent): - # ... - def __init__(self, unique_id, model, ...): - super().__init__(unique_id, model) - # ... - - def my_method(self): - random_number = self.random.randint(0, 100) - -(The agent's random property is just a reference to its parent model's -``random`` property). - -When a model object is created, its random property is automatically seeded -with the current time. The seed determines the sequence of random numbers; if -you instantiate a model with the same seed, you will get the same results. -To allow you to set the seed, make sure your model has a ``seed`` argument in its -constructor. - -.. code:: python - - class AwesomeModel(Model): - - def __init__(self, seed=None): - pass - - def cool_method(self): - interesting_number = self.random.random() - print(interesting_number) - - >>> model0 = AwesomeModel(seed=0) - >>> model0._seed - 0 - >>> model0.cool_method() - 0.8444218515250481 - >>> model1 = AwesomeModel(seed=0) - >>> model1.cool_method() - 0.8444218515250481 From 0d2d6e2c58b92795163ef7033344c02e03ec5f10 Mon Sep 17 00:00:00 2001 From: rht Date: Thu, 15 Feb 2024 18:54:56 -0500 Subject: [PATCH 07/25] docs: Convert overview.rst -> overview.md via rst2myst --- docs/{overview.rst => overview.md} | 200 ++++++++++++++--------------- 1 file changed, 95 insertions(+), 105 deletions(-) rename docs/{overview.rst => overview.md} (50%) diff --git a/docs/overview.rst b/docs/overview.md similarity index 50% rename from docs/overview.rst rename to docs/overview.md index b2b9ddfc6e6..a384b02e11e 100644 --- a/docs/overview.rst +++ b/docs/overview.md @@ -1,13 +1,10 @@ -Mesa Overview -============= +# Mesa Overview Mesa is a modular framework for building, analyzing and visualizing agent-based models. **Agent-based models** are computer simulations involving multiple entities (the agents) acting and interacting with one another based on their programmed behavior. Agents can be used to represent living cells, animals, individual humans, even entire organizations or abstract entities. Sometimes, we may have an understanding of how the individual components of a system behave, and want to see what system-level behaviors and effects emerge from their interaction. Other times, we may have a good idea of how the system overall behaves, and want to figure out what individual behaviors explain it. Or we may want to see how to get agents to cooperate or compete most effectively. Or we may just want to build a cool toy with colorful little dots moving around. - -Mesa Modules ------------- +## Mesa Modules Mesa is modular, meaning that its modeling, analysis and visualization components are kept separate but intended to work together. The modules are grouped into three categories: @@ -15,142 +12,135 @@ Mesa is modular, meaning that its modeling, analysis and visualization component 2. **Analysis:** Tools to collect data generated from your model, or to run it multiple times with different parameter values. 3. **Visualization:** Classes to create and launch an interactive model visualization, using a server with a JavaScript interface. - -Modeling modules -~~~~~~~~~~~~~~~~ +### Modeling modules Most models consist of one class to represent the model itself; one class (or more) for agents; a scheduler to handle time (what order the agents act in), and possibly a space for the agents to inhabit and move through. These are implemented in Mesa's modeling modules: -* ``mesa.Model``, ``mesa.Agent`` -* `mesa.time `_ -* `mesa.space `_ +- `mesa.Model`, `mesa.Agent` +- [mesa.time](apis/time.html) +- [mesa.space](apis/space.html) The skeleton of a model might look like this: -.. code:: python - - import mesa - - class MyAgent(mesa.Agent): - def __init__(self, name, model): - super().__init__(name, model) - self.name = name - - def step(self): - print("{} activated".format(self.name)) - # Whatever else the agent does when activated - - class MyModel(mesa.Model): - def __init__(self, n_agents): - super().__init__() - self.schedule = mesa.time.RandomActivation(self) - self.grid = mesa.space.MultiGrid(10, 10, torus=True) - for i in range(n_agents): - a = MyAgent(i, self) - self.schedule.add(a) - coords = (self.random.randrange(0, 10), self.random.randrange(0, 10)) - self.grid.place_agent(a, coords) - - def step(self): - self.schedule.step() +```python +import mesa + +class MyAgent(mesa.Agent): + def __init__(self, name, model): + super().__init__(name, model) + self.name = name + + def step(self): + print("{} activated".format(self.name)) + # Whatever else the agent does when activated + +class MyModel(mesa.Model): + def __init__(self, n_agents): + super().__init__() + self.schedule = mesa.time.RandomActivation(self) + self.grid = mesa.space.MultiGrid(10, 10, torus=True) + for i in range(n_agents): + a = MyAgent(i, self) + self.schedule.add(a) + coords = (self.random.randrange(0, 10), self.random.randrange(0, 10)) + self.grid.place_agent(a, coords) + + def step(self): + self.schedule.step() +``` If you instantiate a model and run it for one step, like so: -.. code:: python +```python +model = MyModel(5) +model.step() +``` - model = MyModel(5) - model.step() +You should see agents 0-4, activated in random order. See the [tutorial](tutorials/intro_tutorial.html) or API documentation for more detail on how to add model functionality. -You should see agents 0-4, activated in random order. See the `tutorial `_ or API documentation for more detail on how to add model functionality. +To bootstrap a new model install mesa and run `mesa startproject` -To bootstrap a new model install mesa and run ``mesa startproject`` - -Analysis modules -~~~~~~~~~~~~~~~~ +### Analysis modules If you're using modeling for research, you'll want a way to collect the data each model run generates. You'll probably also want to run the model multiple times, to see how some output changes with different parameters. Data collection and batch running are implemented in the appropriately-named analysis modules: -* `mesa.datacollection `_ -* `mesa.batchrunner `_ +- [mesa.datacollection](apis/datacollection.html) +- [mesa.batchrunner](apis/batchrunner.html) You'd add a data collector to the model like this: -.. code:: python - - import mesa +```python +import mesa - # ... +# ... - class MyModel(mesa.Model): - def __init__(self, n_agents): - # ... - self.dc = mesa.DataCollector(model_reporters={"agent_count": - lambda m: m.schedule.get_agent_count()}, - agent_reporters={"name": lambda a: a.name}) +class MyModel(mesa.Model): + def __init__(self, n_agents): + # ... + self.dc = mesa.DataCollector(model_reporters={"agent_count": + lambda m: m.schedule.get_agent_count()}, + agent_reporters={"name": lambda a: a.name}) - def step(self): - self.schedule.step() - self.dc.collect(self) + def step(self): + self.schedule.step() + self.dc.collect(self) +``` -The data collector will collect the specified model- and agent-level data at each step of the model. After you're done running it, you can extract the data as a `pandas `_ DataFrame: - -.. code:: python - - model = MyModel(5) - for t in range(10): - model.step() - model_df = model.dc.get_model_vars_dataframe() - agent_df = model.dc.get_agent_vars_dataframe() +The data collector will collect the specified model- and agent-level data at each step of the model. After you're done running it, you can extract the data as a [pandas](http://pandas.pydata.org/) DataFrame: +```python +model = MyModel(5) +for t in range(10): + model.step() +model_df = model.dc.get_model_vars_dataframe() +agent_df = model.dc.get_agent_vars_dataframe() +``` To batch-run the model while varying, for example, the n_agents parameter, you'd use the `batch_run` function: -.. code:: python - - import mesa - - parameters = {"n_agents": range(1, 20)} - mesa.batch_run( - MyModel, - parameters, - max_steps=10, - ) +```python +import mesa +parameters = {"n_agents": range(1, 20)} +mesa.batch_run( + MyModel, + parameters, + max_steps=10, +) +``` As with the data collector, once the runs are all over, you can extract the data as a data frame. -.. code:: python +```python +batch_df = batch_run.get_model_vars_dataframe() +``` - batch_df = batch_run.get_model_vars_dataframe() - - -Visualization modules -~~~~~~~~~~~~~~~~~~~~~ +### Visualization modules Finally, you may want to directly observe your model as it runs. Mesa's main visualization tool uses a small local web server to render the model in a browser, using JavaScript. There are different components for drawing different types of data: for example, grids for drawing agents moving around on a grid, or charts for showing how some data changes as the model runs. A few core modules are: -* mesa.visualization.ModularVisualization -* mesa.visualization.modules +- mesa.visualization.ModularVisualization +- mesa.visualization.modules To quickly spin up a model visualization, you might do something like: -.. code:: python - - import mesa - - def agent_portrayal(agent): - portrayal = {"Shape": "circle", - "Filled": "true", - "Layer": 0, - "Color": "red", - "r": 0.5} - return portrayal - - grid = mesa.visualization.CanvasGrid(agent_portrayal, 10, 10, 500, 500) - server = mesa.visualization.ModularServer(MyModel, - [grid], - "My Model", - {'n_agents': 10}) - server.launch() +```python +import mesa + +def agent_portrayal(agent): + portrayal = {"Shape": "circle", + "Filled": "true", + "Layer": 0, + "Color": "red", + "r": 0.5} + return portrayal + +grid = mesa.visualization.CanvasGrid(agent_portrayal, 10, 10, 500, 500) +server = mesa.visualization.ModularServer(MyModel, + [grid], + "My Model", + {'n_agents': 10}) +server.launch() +``` This will launch the browser-based visualization, on the default port 8521. From beb89f998a0c659f5e842c1dca3d129af4763a08 Mon Sep 17 00:00:00 2001 From: rht Date: Thu, 15 Feb 2024 18:56:22 -0500 Subject: [PATCH 08/25] docs: Convert packages.rst -> packages.md via rst2myst --- docs/{packages.rst => packages.md} | 96 +++++++++++++----------------- 1 file changed, 40 insertions(+), 56 deletions(-) rename docs/{packages.rst => packages.md} (55%) diff --git a/docs/packages.rst b/docs/packages.md similarity index 55% rename from docs/packages.rst rename to docs/packages.md index 4cfb4ea90c6..e15c6baac4f 100644 --- a/docs/packages.rst +++ b/docs/packages.md @@ -1,27 +1,24 @@ -"How To" Mesa Packages -====================== +# "How To" Mesa Packages The Mesa core functionality is just a subset of what we believe researchers creating Agent Based Models (ABMs) will use. We designed Mesa to be extensible, so that individuals from various domains can build, maintain, and share their own packages that work with Mesa in pursuit of "unifying algorithmic theories of the relation between adaptive behavior and system complexity (Volker Grimm et al 2005)." **DRY Principle** -This decoupling of code to create building blocks is a best practice in software engineering. Specifically, it exercises the `DRY principle (or don't repeat yourself) `_ (Hunt and Thomas 2010). The creators of Mesa designed Mesa in order for this principle to be exercised in the development of agent-based models (ABMs). For example, a group of health experts may create a library of human interactions on top of core Mesa. That library then is used by other health experts. So, those health experts don't have to rewrite the same basic behaviors. +This decoupling of code to create building blocks is a best practice in software engineering. Specifically, it exercises the [DRY principle (or don't repeat yourself)](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) (Hunt and Thomas 2010). The creators of Mesa designed Mesa in order for this principle to be exercised in the development of agent-based models (ABMs). For example, a group of health experts may create a library of human interactions on top of core Mesa. That library then is used by other health experts. So, those health experts don't have to rewrite the same basic behaviors. **Benefits to Scientists** Besides a best practice of the software engineering community, there are other benefits for the scientific community. 1. **Reproducibility and Replicability.** Decoupled shared packages also allows for reproducibility and replicability. Having a package that is shared allows others to reproduce the model results. It also allows others to apply the model to similar phenomenon and replicate the results over a diversity of data. Both are essential part of the scientific method (Leek and Peng 2015). - 2. **Accepted truths.** Once results are reproduced and replicated, a library could be considered an accepted truth, meaning that the community agrees the library does what the library intends to do and the library can be trusted to do this. Part of the idea behind 'accepted truths' is that subject matter experts are the ones that write and maintain the library. - 3. **Building blocks.** Think of libraries like Legos. The researcher can borrow a piece from here or there to pull together the base of their model, so they can focus on the value add that they bring. For example, someone might pull from a human interactions library and a decision-making library and combine the two to look at how human cognitive function effects the physical spread of disease. **Mesa and Mesa Packages** Because of the possibilities of nuanced libraries, few things will actually make it into core Mesa. Mesa is intended to only include core functionality that everyone uses. However, it is not impossible that something written on the outside is brought into core at a later date if the value to everyone is proven through adoption. -An example that is analogous to Mesa and Mesa packages is `Django `_ and `Django Packages `_. Django is a web framework that allows you to build a website in Python, but there are lots of things besides a basic website that you might want. For example, you might want authentication functionality. It would be inefficient for everyone to write their own authentication functionality, so one person writes it (or a group of people). They share it with the world and then many people can use it. +An example that is analogous to Mesa and Mesa packages is [Django](https://www.djangoproject.com/) and [Django Packages](https://djangopackages.org/). Django is a web framework that allows you to build a website in Python, but there are lots of things besides a basic website that you might want. For example, you might want authentication functionality. It would be inefficient for everyone to write their own authentication functionality, so one person writes it (or a group of people). They share it with the world and then many people can use it. This process isn't perfect. Just because you write something doesn't mean people are going to use it. Sometimes two different packages will be created that do similar things, but one of them does it better or is easier to use. That is the one that will get more adoption. In the world of academia, often researchers hold on to their content until they are ready to publish it. In the world of open source software, this can backfire. The sooner you open source something the more likely it will be a success, because you will build consensus and engagement. Another thing that can happen is that while you are working on perfecting it, someone else is building in the open and establishes the audience you were looking for. So, don't be afraid to start working directly out in the open and then release it to the world. @@ -29,98 +26,85 @@ This process isn't perfect. Just because you write something doesn't mean people There are two sections in this documentation. The first is the User Guide, which is aimed at users of packages. The section is a package development guide, which is aimed at those who want to develop packages. Without further ado, let's get started! +## User Guide -User Guide --------------------------------------------------- - -* Note: MESA does not endorse or verify any of the code shared through MESA packages. This is left to the domain experts of the community that created the code.* +- Note: MESA does not endorse or verify any of the code shared through MESA packages. This is left to the domain experts of the community that created the code.\* **Step 1: Select a package** -Currently, a central list of compatible packages is located on the `Mesa Wiki Packages Page `_. +Currently, a central list of compatible packages is located on the [Mesa Wiki Packages Page](https://github.com/projectmesa/mesa/wiki/Mesa-Packages). **Step 2: Establish an environment** Create a virtual environment for the ABM you are building. The purpose of a virtual environment is to isolate the packages for your project from other projects. This is helpful when you need to use two different versions of a package or if you are running one version in production but want to test out another version. You can do with either virtualenv or Anaconda. - - `Why a virtual environment `_ - - `Virtualenv and Virtualenv Wrapper `_ - - `Creating a virtual environment with Anaconda `_ +> - [Why a virtual environment](https://realpython.com/blog/python/python-virtual-environments-a-primer/#why-the-need-for-virtual-environments) +> - [Virtualenv and Virtualenv Wrapper](http://docs.python-guide.org/en/latest/#python-development-environments) +> - [Creating a virtual environment with Anaconda](https://conda.io/docs/user-guide/tasks/manage-environments.html) **Step 3: Install the packages** Install the package(s) into your environment via pip/conda or GitHub. If the package is a mature package that is hosted in the Python package repository, then you can install it just like you did Mesa: - .. code:: bash - - pip install package_name +> ```bash +> pip install package_name +> ``` However, sometimes it takes a little bit for projects to reach that level of maturity. In that case to use the library, you would install from GitHub (or other code repository) with something like the following: - - .. code:: bash - - pip install https://github.com/ +> ```bash +> pip install https://github.com/ +> ``` The commands above should also work with Anaconda, just replace the `pip` with `conda`. - -Package Development: A "How-to Guide" --------------------------------------------------- +## Package Development: A "How-to Guide" The purpose of this section is help you understand, setup, and distribute your Mesa package as quickly as possible. A Mesa package is just a Python package or repo. We just call it a Mesa package, because we are talking about a Python package in the context of Mesa. These instructions assume that you are a little familiar with development, but that you have little knowledge of the packaging process. There are two ways to share a package: - 1. Via GitHub or other service (e.g. GitLab, Bitbucket, etc.) - 2. Via PyPI, the Python package manager +> 1. Via GitHub or other service (e.g. GitLab, Bitbucket, etc.) +> 2. Via PyPI, the Python package manager Sharing a package via PyPI make it easier to install for users but is more overhead for whomever is maintaining it. However, if you are truly intending for a wider/longer-term adoption, then PyPI should be your goal. Most likely you created an ABM that has the code that you want to share in it, which is what the steps below describe. - **Sharing your package** - - 1. Layout a new file structure to move the code into and then make sure it is callable from Mesa, in a simple, easy to understand way. For example, ``from example_package import foo``. See `Creating the Scaffolding `_. - - 2. `Pick a name `_. - - 3. `Create a repo on GitHub `_. - - * Enter the name of the repo. - * Select a license (not sure-- click the blue 'i' next to the i for a great run down of licenses). We recommend something permissive Apache 2.0, BSD, or MIT so that others can freely adopt it. The more permissive the more likely it will gain followers and adoption. If you do not include a license, it is our belief that you will retain all rights, which means that people can't use your project, but it should be noted that we are also not lawyers. - * Create a readme.md file (this contains a description of the package) see an example: `Bilateral Shapley `_ - - 4. `Clone the repo to your computer `_. - - 5. Copy your code directory into the repo that you cloned one your computer. - - 6. Add a requirements.txt file, which lets people know which external Python packages are needed to run the code in your repo. To create a file, run: ``pip freeze > requirements.txt``. Note, if you are running Anaconda, you will need to install pip first: ``conda install pip``. - - 7. ``git add`` all the files to the repo, which means the repo starts to track the files. Then ``git commit`` the files with a meaningful message. To learn more about this see: `Saving changes `_. Finally, you will want to ``git push`` all your changes to GitHub, see: `Git Push `_. - - 8. Let people know about your package on the `MESA Wiki Page `_ and share it on the `email list `_. In the future, we will create more of a directory, but at this point we are not there yet. +> 1. Layout a new file structure to move the code into and then make sure it is callable from Mesa, in a simple, easy to understand way. For example, `from example_package import foo`. See [Creating the Scaffolding](https://python-packaging.readthedocs.io/en/latest/minimal.html#creating-the-scaffolding). +> +> 2. [Pick a name](https://python-packaging.readthedocs.io/en/latest/minimal.html#picking-a-name). +> +> 3. [Create a repo on GitHub](https://help.github.com/articles/create-a-repo/). +> +> - Enter the name of the repo. +> - Select a license (not sure-- click the blue 'i' next to the i for a great run down of licenses). We recommend something permissive Apache 2.0, BSD, or MIT so that others can freely adopt it. The more permissive the more likely it will gain followers and adoption. If you do not include a license, it is our belief that you will retain all rights, which means that people can't use your project, but it should be noted that we are also not lawyers. +> - Create a readme.md file (this contains a description of the package) see an example: [Bilateral Shapley](https://github.com/tpike3/bilateralshapley/blob/master/README.md) +> +> 4. [Clone the repo to your computer](https://help.github.com/articles/cloning-a-repository/#platform-linux). +> +> 5. Copy your code directory into the repo that you cloned one your computer. +> +> 6. Add a requirements.txt file, which lets people know which external Python packages are needed to run the code in your repo. To create a file, run: `pip freeze > requirements.txt`. Note, if you are running Anaconda, you will need to install pip first: `conda install pip`. +> +> 7. `git add` all the files to the repo, which means the repo starts to track the files. Then `git commit` the files with a meaningful message. To learn more about this see: [Saving changes](https://www.atlassian.com/git/tutorials/saving-changes). Finally, you will want to `git push` all your changes to GitHub, see: [Git Push](https://help.github.com/articles/pushing-to-a-remote/). +> +> 8. Let people know about your package on the [MESA Wiki Page](https://github.com/projectmesa/mesa/wiki) and share it on the [email list](https://groups.google.com/forum/#!forum/projectmesa). In the future, we will create more of a directory, but at this point we are not there yet. From this point, someone can clone your repo and then add your repo to their Python path and use it in their project. However, if you want to take your package to the next level, you will want to add more structure to your package and share it on PyPI. - **Next Level: PyPI** +You want to do even more. The authoritative guide for python package development is through the [Python Packaging User Guide](https://packaging.python.org/). This will take you through the entire process necessary for getting your package on the Python Package Index. -You want to do even more. The authoritative guide for python package development is through the `Python Packaging User Guide `_. This will take you through the entire process necessary for getting your package on the Python Package Index. - -The `Python Package Index `_ is the main repository of software for Python Packages and following this guide will ensure your code and documentation meets the standards for distribution across the Python community. - +The [Python Package Index](https://pypi.org) is the main repository of software for Python Packages and following this guide will ensure your code and documentation meets the standards for distribution across the Python community. - -References -=========== +# References Grimm, Volker, Eloy Revilla, Uta Berger, Florian Jeltsch, Wolf M. Mooij, Steven F. Railsback, Hans-Hermann Thulke, Jacob Weiner, Thorsten Wiegand, and Donald L. DeAngelis. 2005. “Pattern-Oriented Modeling of Agent Based Complex Systems: Lessons from Ecology.” American Association for the Advancement of Science 310 (5750): 987–91. doi:10.1126/science.1116681. Hunt, Andrew, and David Thomas. 2010. The Pragmatic Programmer: From Journeyman to Master. Reading, Massachusetts: Addison-Wesley. Leek, Jeffrey T., and Roger D. Peng. 2015. “Reproducible Research Can Still Be Wrong: Adopting a Prevention Approach.” Proceedings of the National Academy of Sciences 112 (6): 1645–46. doi:10.1073/pnas.1421412111. - From 647dd0e5a15259db25a24bbed3a51cee418abb71 Mon Sep 17 00:00:00 2001 From: rht Date: Thu, 15 Feb 2024 19:07:33 -0500 Subject: [PATCH 09/25] docs: Convert mesa.rst -> mesa.md via rst2myst --- docs/{mesa.rst => mesa.md} | 55 +++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 25 deletions(-) rename docs/{mesa.rst => mesa.md} (62%) diff --git a/docs/mesa.rst b/docs/mesa.md similarity index 62% rename from docs/mesa.rst rename to docs/mesa.md index 524a79af088..08a7148cbce 100644 --- a/docs/mesa.rst +++ b/docs/mesa.md @@ -1,77 +1,82 @@ -mesa package -============ +# mesa package -Subpackages ------------ +## Subpackages -.. toctree:: +```{toctree} +mesa.visualization +``` - mesa.visualization +## Submodules -Submodules ----------- - -mesa.agent module ------------------ +## mesa.agent module +```{eval-rst} .. automodule:: mesa.agent :members: :undoc-members: :show-inheritance: +``` -mesa.batchrunner module ------------------------ +## mesa.batchrunner module +```{eval-rst} .. automodule:: mesa.batchrunner :members: :undoc-members: :show-inheritance: +``` -mesa.datacollection module --------------------------- +## mesa.datacollection module +```{eval-rst} .. automodule:: mesa.datacollection :members: :undoc-members: :show-inheritance: +``` -mesa.main module ----------------- +## mesa.main module +```{eval-rst} .. automodule:: mesa.main :members: :undoc-members: :show-inheritance: +``` -mesa.model module ------------------ +## mesa.model module +```{eval-rst} .. automodule:: mesa.model :members: :undoc-members: :show-inheritance: +``` -mesa.space module ------------------ +## mesa.space module +```{eval-rst} .. automodule:: mesa.space :members: :undoc-members: :show-inheritance: +``` -mesa.time module ----------------- +## mesa.time module +```{eval-rst} .. automodule:: mesa.time :members: :undoc-members: :show-inheritance: +``` -Module contents ---------------- +## Module contents +```{eval-rst} .. automodule:: mesa :members: :undoc-members: :show-inheritance: +``` From 2f7a39bcd55448c8a9d2460f0c4319fd66e2aee5 Mon Sep 17 00:00:00 2001 From: rht Date: Thu, 15 Feb 2024 19:08:46 -0500 Subject: [PATCH 10/25] docs: Convert index.rst -> index.md via rst2myst --- docs/index.md | 105 ++++++++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 111 ------------------------------------------------- 2 files changed, 105 insertions(+), 111 deletions(-) create mode 100644 docs/index.md delete mode 100644 docs/index.rst diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000000..22812595c8e --- /dev/null +++ b/docs/index.md @@ -0,0 +1,105 @@ +# Mesa: Agent-based modeling in Python + +```{image} https://github.com/projectmesa/mesa/workflows/build/badge.svg +:target: https://github.com/projectmesa/mesa/actions +``` + +```{image} https://codecov.io/gh/projectmesa/mesa/branch/main/graph/badge.svg +:target: https://codecov.io/gh/projectmesa/mesa +``` + +```{image} https://img.shields.io/badge/code%20style-black-000000.svg +:target: https://github.com/psf/black +``` + +```{image} https://img.shields.io/matrix/project-mesa:matrix.org?label=chat&logo=Matrix +:target: https://matrix.to/#/#project-mesa:matrix.orgs +``` + +[Mesa] is an Apache2 licensed agent-based modeling (or ABM) framework in Python. + +Mesa allows users to quickly create agent-based models using built-in core components (such as spatial grids and agent schedulers) or customized implementations; visualize them using a browser-based interface; and analyze their results using Python's data analysis tools. Its goal is to be the Python-based counterpart to NetLogo, Repast, or MASON. + +```{image} https://raw.githubusercontent.com/projectmesa/mesa/main/docs/images/Mesa_Screenshot.png +:alt: A screenshot of the Schelling Model in Mesa +:scale: 100% +:width: 100% +``` + +*Above: A Mesa implementation of the Schelling segregation model, +being visualized in a browser window and analyzed in a Jupyter +notebook.* + +## Features + +- Modular components +- Browser-based visualization +- Built-in tools for analysis + +## Using Mesa + +Getting started quickly: + +```bash +pip install mesa +``` + +To launch an example model, clone the [repository](https://github.com/projectmesa/mesa) folder and invoke `mesa runserver` for one of the `examples/` subdirectories: + +```bash +mesa runserver examples/wolf_sheep +``` + +For more help on using Mesa, check out the following resources: + +- [Mesa Introductory Tutorial] +- [Mesa Visualization Tutorial] +- [GitHub Issue Tracker] +- [Email list] +- [PyPI] + +## Contributing back to Mesa + +If you run into an issue, please file a [ticket] for us to discuss. If possible, follow up with a pull request. + +If you would like to add a feature, please reach out via [ticket] or the [email list] for discussion. A feature is most likely to be added if you build it! + +- [Contributors guide] +- [Github] + +## Mesa Packages + +ABM features users have shared that you may want to use in your model + +- [See the Packages](https://github.com/projectmesa/mesa/wiki) +- {ref}`Mesa-Packages ` + +```{toctree} +:hidden: true +:maxdepth: 7 + +Mesa Overview +tutorials/intro_tutorial +tutorials/visualization_tutorial +Best Practices +How-to Guide +API Documentation +Mesa Packages +tutorials/adv_tutorial_legacy.ipynb +``` + +# Indices and tables + +- {ref}`genindex` +- {ref}`modindex` +- {ref}`search` + +[contributors guide]: https://github.com/projectmesa/mesa/blob/main/CONTRIBUTING.rst +[email list]: https://groups.google.com/d/forum/projectmesa +[github]: https://github.com/projectmesa/mesa/ +[github issue tracker]: https://github.com/projectmesa/mesa/issues +[mesa]: https://github.com/projectmesa/mesa/ +[mesa introductory tutorial]: tutorials/intro_tutorial.html +[mesa visualization tutorial]: tutorials/visualization_tutorial.html +[pypi]: https://pypi.python.org/pypi/Mesa/ +[ticket]: https://github.com/projectmesa/mesa/issues diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index 17404bc153b..00000000000 --- a/docs/index.rst +++ /dev/null @@ -1,111 +0,0 @@ -Mesa: Agent-based modeling in Python -==================================== - -.. image:: https://github.com/projectmesa/mesa/workflows/build/badge.svg - :target: https://github.com/projectmesa/mesa/actions - -.. image:: https://codecov.io/gh/projectmesa/mesa/branch/main/graph/badge.svg - :target: https://codecov.io/gh/projectmesa/mesa - -.. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/psf/black - -.. image:: https://img.shields.io/matrix/project-mesa:matrix.org?label=chat&logo=Matrix - :target: https://matrix.to/#/#project-mesa:matrix.orgs - -`Mesa`_ is an Apache2 licensed agent-based modeling (or ABM) framework in Python. - -Mesa allows users to quickly create agent-based models using built-in core components (such as spatial grids and agent schedulers) or customized implementations; visualize them using a browser-based interface; and analyze their results using Python's data analysis tools. Its goal is to be the Python-based counterpart to NetLogo, Repast, or MASON. - - -.. image:: https://raw.githubusercontent.com/projectmesa/mesa/main/docs/images/Mesa_Screenshot.png - :width: 100% - :scale: 100% - :alt: A screenshot of the Schelling Model in Mesa - -*Above: A Mesa implementation of the Schelling segregation model, -being visualized in a browser window and analyzed in a Jupyter -notebook.* - -.. _`Mesa` : https://github.com/projectmesa/mesa/ - - -Features --------- - -* Modular components -* Browser-based visualization -* Built-in tools for analysis - -Using Mesa ----------- - -Getting started quickly: - -.. code-block:: bash - - pip install mesa - -To launch an example model, clone the `repository `_ folder and invoke ``mesa runserver`` for one of the ``examples/`` subdirectories: - -.. code-block:: bash - - mesa runserver examples/wolf_sheep - -For more help on using Mesa, check out the following resources: - -* `Mesa Introductory Tutorial`_ -* `Mesa Visualization Tutorial`_ -* `GitHub Issue Tracker`_ -* `Email list`_ -* `PyPI`_ - -.. _`Mesa Introductory Tutorial` : tutorials/intro_tutorial.html -.. _`Mesa Visualization Tutorial` : tutorials/visualization_tutorial.html -.. _`GitHub Issue Tracker` : https://github.com/projectmesa/mesa/issues -.. _`Email list` : https://groups.google.com/d/forum/projectmesa -.. _`PyPI` : https://pypi.python.org/pypi/Mesa/ - -Contributing back to Mesa -------------------------- - -If you run into an issue, please file a `ticket`_ for us to discuss. If possible, follow up with a pull request. - -If you would like to add a feature, please reach out via `ticket`_ or the `email list`_ for discussion. A feature is most likely to be added if you build it! - -* `Contributors guide`_ -* `Github`_ - -.. _`ticket` : https://github.com/projectmesa/mesa/issues -.. _`Contributors guide` : https://github.com/projectmesa/mesa/blob/main/CONTRIBUTING.rst -.. _`Github` : https://github.com/projectmesa/mesa/ - - -Mesa Packages --------------------------------------- - -ABM features users have shared that you may want to use in your model - -* `See the Packages `_ -* :ref:`Mesa-Packages ` - - -.. toctree:: - :hidden: - :maxdepth: 7 - - Mesa Overview - tutorials/intro_tutorial - tutorials/visualization_tutorial - Best Practices - How-to Guide - API Documentation - Mesa Packages - tutorials/adv_tutorial_legacy.ipynb - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` From a83b8d3e1436e4b27eb74328f2e213fccc0992d8 Mon Sep 17 00:00:00 2001 From: rht Date: Tue, 20 Feb 2024 20:56:31 -0500 Subject: [PATCH 11/25] docs: Convert api/*.rst -> api/*.md via rst2myst (#2035) --- docs/apis/api_main.md | 12 +++++++++++ docs/apis/api_main.rst | 12 ----------- docs/apis/{batchrunner.rst => batchrunner.md} | 2 ++ .../{datacollection.rst => datacollection.md} | 2 ++ docs/apis/{init.rst => init.md} | 9 ++++++--- docs/apis/space.md | 5 +++++ docs/apis/space.rst | 3 --- docs/apis/{time.rst => time.md} | 2 ++ .../{visualization.rst => visualization.md} | 20 +++++++++++++++---- 9 files changed, 45 insertions(+), 22 deletions(-) create mode 100644 docs/apis/api_main.md delete mode 100644 docs/apis/api_main.rst rename docs/apis/{batchrunner.rst => batchrunner.md} (69%) rename docs/apis/{datacollection.rst => datacollection.md} (70%) rename docs/apis/{init.rst => init.md} (51%) create mode 100644 docs/apis/space.md delete mode 100644 docs/apis/space.rst rename docs/apis/{time.rst => time.md} (77%) rename docs/apis/{visualization.rst => visualization.md} (75%) diff --git a/docs/apis/api_main.md b/docs/apis/api_main.md new file mode 100644 index 00000000000..ae77d47a466 --- /dev/null +++ b/docs/apis/api_main.md @@ -0,0 +1,12 @@ +# APIs + +```{toctree} +:maxdepth: 3 + +Base Classes +time +space +datacollection +batchrunner +visualization +``` diff --git a/docs/apis/api_main.rst b/docs/apis/api_main.rst deleted file mode 100644 index bb3b4b14629..00000000000 --- a/docs/apis/api_main.rst +++ /dev/null @@ -1,12 +0,0 @@ -APIs ----- - -.. toctree:: - :maxdepth: 3 - - Base Classes - time - space - datacollection - batchrunner - visualization diff --git a/docs/apis/batchrunner.rst b/docs/apis/batchrunner.md similarity index 69% rename from docs/apis/batchrunner.rst rename to docs/apis/batchrunner.md index 2d41aefe943..29074843a72 100644 --- a/docs/apis/batchrunner.rst +++ b/docs/apis/batchrunner.md @@ -1,2 +1,4 @@ +```{eval-rst} .. automodule:: batchrunner :members: +``` diff --git a/docs/apis/datacollection.rst b/docs/apis/datacollection.md similarity index 70% rename from docs/apis/datacollection.rst rename to docs/apis/datacollection.md index dc03b2c8767..2455aac7223 100644 --- a/docs/apis/datacollection.rst +++ b/docs/apis/datacollection.md @@ -1,2 +1,4 @@ +```{eval-rst} .. automodule:: datacollection :members: +``` diff --git a/docs/apis/init.rst b/docs/apis/init.md similarity index 51% rename from docs/apis/init.rst rename to docs/apis/init.md index 48922db88a2..caa4544956f 100644 --- a/docs/apis/init.rst +++ b/docs/apis/init.md @@ -1,8 +1,11 @@ -Base Classes ----- +# Base Classes +```{eval-rst} .. autoclass:: mesa.Agent :members: +``` +```{eval-rst} .. autoclass:: mesa.Model - :members: \ No newline at end of file + :members: +``` diff --git a/docs/apis/space.md b/docs/apis/space.md new file mode 100644 index 00000000000..86ad12f7b71 --- /dev/null +++ b/docs/apis/space.md @@ -0,0 +1,5 @@ +```{eval-rst} +.. automodule:: mesa.space + :members: + :inherited-members: +``` diff --git a/docs/apis/space.rst b/docs/apis/space.rst deleted file mode 100644 index 715d3645b00..00000000000 --- a/docs/apis/space.rst +++ /dev/null @@ -1,3 +0,0 @@ -.. automodule:: mesa.space - :members: - :inherited-members: \ No newline at end of file diff --git a/docs/apis/time.rst b/docs/apis/time.md similarity index 77% rename from docs/apis/time.rst rename to docs/apis/time.md index 53c5d027c5c..df69d86c358 100644 --- a/docs/apis/time.rst +++ b/docs/apis/time.md @@ -1,3 +1,5 @@ +```{eval-rst} .. automodule:: mesa.time :members: :inherited-members: +``` diff --git a/docs/apis/visualization.rst b/docs/apis/visualization.md similarity index 75% rename from docs/apis/visualization.rst rename to docs/apis/visualization.md index 466936d2c47..fde799e0f54 100644 --- a/docs/apis/visualization.rst +++ b/docs/apis/visualization.md @@ -1,26 +1,38 @@ -Visualization -------------- +# Visualization +```{eval-rst} .. automodule:: visualization.__init__ :members: +``` +```{eval-rst} .. automodule:: visualization.ModularVisualization :members: +``` +```{eval-rst} .. automodule:: visualization.TextVisualization :members: +``` -Modules -~~~~~~~ +## Modules +```{eval-rst} .. automodule:: visualization.modules.__init__ :members: +``` +```{eval-rst} .. automodule:: visualization.modules.CanvasGridVisualization :members: +``` +```{eval-rst} .. automodule:: visualization.modules.ChartVisualization :members: +``` +```{eval-rst} .. automodule:: visualization.modules.TextVisualization :members: +``` From d65f41c2b940d78158027aab464cef2762837dfe Mon Sep 17 00:00:00 2001 From: rht Date: Tue, 20 Feb 2024 20:56:59 -0500 Subject: [PATCH 12/25] docs: Convert visualization .rst -> .md via rst2myst (#2036) --- docs/mesa.visualization.md | 46 ++++ ...ules.rst => mesa.visualization.modules.md} | 46 ++-- docs/mesa.visualization.rst | 45 ---- ...alization.rst => modular-visualization.md} | 203 +++++++++--------- 4 files changed, 171 insertions(+), 169 deletions(-) create mode 100644 docs/mesa.visualization.md rename docs/{mesa.visualization.modules.rst => mesa.visualization.modules.md} (51%) delete mode 100644 docs/mesa.visualization.rst rename docs/{modular-visualization.rst => modular-visualization.md} (58%) diff --git a/docs/mesa.visualization.md b/docs/mesa.visualization.md new file mode 100644 index 00000000000..5efa966222e --- /dev/null +++ b/docs/mesa.visualization.md @@ -0,0 +1,46 @@ +# mesa.visualization package + +## Subpackages + +```{toctree} +mesa.visualization.modules +``` + +## Submodules + +## mesa.visualization.ModularVisualization module + +```{eval-rst} +.. automodule:: mesa.visualization.ModularVisualization + :members: + :undoc-members: + :show-inheritance: +``` + +## mesa.visualization.TextVisualization module + +```{eval-rst} +.. automodule:: mesa.visualization.TextVisualization + :members: + :undoc-members: + :show-inheritance: +``` + +## mesa.visualization.UserParam module + +```{eval-rst} +.. automodule:: mesa.visualization.UserParam + :members: + :undoc-members: + :show-inheritance: + +``` + +## Module contents + +```{eval-rst} +.. automodule:: mesa.visualization + :members: + :undoc-members: + :show-inheritance: +``` diff --git a/docs/mesa.visualization.modules.rst b/docs/mesa.visualization.modules.md similarity index 51% rename from docs/mesa.visualization.modules.rst rename to docs/mesa.visualization.modules.md index b96466dadde..6380f982c47 100644 --- a/docs/mesa.visualization.modules.rst +++ b/docs/mesa.visualization.modules.md @@ -1,70 +1,76 @@ -mesa.visualization.modules package -================================== +# mesa.visualization.modules package -Submodules ----------- +## Submodules -mesa.visualization.modules.BarChartVisualization module -------------------------------------------------------- +## mesa.visualization.modules.BarChartVisualization module +```{eval-rst} .. automodule:: mesa.visualization.modules.BarChartVisualization :members: :undoc-members: :show-inheritance: +``` -mesa.visualization.modules.CanvasGridVisualization module ---------------------------------------------------------- +## mesa.visualization.modules.CanvasGridVisualization module +```{eval-rst} .. automodule:: mesa.visualization.modules.CanvasGridVisualization :members: :undoc-members: :show-inheritance: +``` -mesa.visualization.modules.ChartVisualization module ----------------------------------------------------- +## mesa.visualization.modules.ChartVisualization module +```{eval-rst} .. automodule:: mesa.visualization.modules.ChartVisualization :members: :undoc-members: :show-inheritance: +``` -mesa.visualization.modules.HexGridVisualization module ------------------------------------------------------- +## mesa.visualization.modules.HexGridVisualization module +```{eval-rst} .. automodule:: mesa.visualization.modules.HexGridVisualization :members: :undoc-members: :show-inheritance: +``` -mesa.visualization.modules.NetworkVisualization module ------------------------------------------------------- +## mesa.visualization.modules.NetworkVisualization module +```{eval-rst} .. automodule:: mesa.visualization.modules.NetworkVisualization :members: :undoc-members: :show-inheritance: +``` -mesa.visualization.modules.PieChartVisualization module -------------------------------------------------------- +## mesa.visualization.modules.PieChartVisualization module +```{eval-rst} .. automodule:: mesa.visualization.modules.PieChartVisualization :members: :undoc-members: :show-inheritance: +``` -mesa.visualization.modules.TextVisualization module ---------------------------------------------------- +## mesa.visualization.modules.TextVisualization module +```{eval-rst} .. automodule:: mesa.visualization.modules.TextVisualization :members: :undoc-members: :show-inheritance: +``` -Module contents ---------------- +## Module contents +```{eval-rst} .. automodule:: mesa.visualization.modules :members: :undoc-members: :show-inheritance: +``` diff --git a/docs/mesa.visualization.rst b/docs/mesa.visualization.rst deleted file mode 100644 index 2e8ae7ac24d..00000000000 --- a/docs/mesa.visualization.rst +++ /dev/null @@ -1,45 +0,0 @@ -mesa.visualization package -========================== - -Subpackages ------------ - -.. toctree:: - - mesa.visualization.modules - -Submodules ----------- - -mesa.visualization.ModularVisualization module ----------------------------------------------- - -.. automodule:: mesa.visualization.ModularVisualization - :members: - :undoc-members: - :show-inheritance: - -mesa.visualization.TextVisualization module -------------------------------------------- - -.. automodule:: mesa.visualization.TextVisualization - :members: - :undoc-members: - :show-inheritance: - -mesa.visualization.UserParam module ------------------------------------ - -.. automodule:: mesa.visualization.UserParam - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: mesa.visualization - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/modular-visualization.rst b/docs/modular-visualization.md similarity index 58% rename from docs/modular-visualization.rst rename to docs/modular-visualization.md index 247303c8dcc..93fb4673a08 100644 --- a/docs/modular-visualization.rst +++ b/docs/modular-visualization.md @@ -1,5 +1,4 @@ -Modular Visualization - An In-Depth Look -======================================== +# Modular Visualization - An In-Depth Look Modular visualization is one of Mesa's core features. Mesa is designed to provide predefined visualization modules, which can be easily @@ -7,8 +6,7 @@ subclassed for your needs, and mixed-and-matched to visualize your particular model. (Some day, Mesa hopes to host a wide variety.) This document describes how to use and create new visualization modules. -Overview --------- +## Overview An interactive modular visualization is a set of **Elements**, each of which is an instance of a visualization **Module**. To visualize a @@ -16,22 +14,22 @@ model, create a new ModularServer with a list of the elements you want to visualize, in the order you want them to appear on the visualization web page. -For example, if you have a model ``MyModel``, and two elements, -*canvas\_vis* and *graph\_vis*, you would create a visualization with +For example, if you have a model `MyModel`, and two elements, +*canvas_vis* and *graph_vis*, you would create a visualization with them via: -.. code:: python - - server = ModularServer(MyModel, [canvas_vis, graph_vis]) - server.launch() +```python +server = ModularServer(MyModel, [canvas_vis, graph_vis]) +server.launch() +``` Then you will be able to view the elements in your browser at -http://127.0.0.1:8521/. If you prefer a different port, for example +. If you prefer a different port, for example 8887, you can pass it to the server as an argument. -.. code:: python - - server.launch(8887) +```python +server.launch(8887) +``` Under the hood, each visualization module consists of two parts: @@ -41,8 +39,7 @@ Under the hood, each visualization module consists of two parts: from the Python render (via the ModularServer) and actually draws it in the browser. -Using Pre-Built Modules ------------------------ +## Using Pre-Built Modules Mesa already comes with some pre-built modules. Using the built-ins allow you to build a visualization without worrying about the HTML and @@ -55,43 +52,43 @@ agent-based models, particularly the simpler ones. CanvasGrid iterates over every object in every cell of your model's grid (it assumes that your model has a grid named **grid**) and converts it into a dictionary which defines how it will be drawn. It does this via a -**portrayal\_method**: a function which the user defines, which takes an +**portrayal_method**: a function which the user defines, which takes an object as an input and outputs a dictionary with the following keys: -:: - - "Shape": Can be "circle", "rect" or "arrowHead" - For Circles: - "r": The radius, defined as a fraction of cell size. r=1 will fill the entire cell. - For rectangles: - "w", "h": The width and height of the rectangle, which are in fractions of cell width and height. - For arrowHead: - "scale": Proportion scaling as a fraction of cell size. - "heading_x": represents x direction unit vector. - "heading_y": represents y direction unit vector. - "Color": The color to draw the shape in; needs to be a valid HTML color, e.g."Red" or "#AA08F8" - "Filled": either "true" or "false", and determines whether the shape is filled or not. - "Layer": Layer number of 0 or above; higher-numbered layers are drawn above lower-numbered layers. - "text": Text to overlay on top of the shape. Normally, agent's unique_id is used . - "text_color": Color of the text overlay. - (Shapes also have "x" and "y" coordinates, for the x and y of the grid cell in which it is, but CanvasGrid adds those automatically). +``` +"Shape": Can be "circle", "rect" or "arrowHead" + For Circles: + "r": The radius, defined as a fraction of cell size. r=1 will fill the entire cell. + For rectangles: + "w", "h": The width and height of the rectangle, which are in fractions of cell width and height. + For arrowHead: + "scale": Proportion scaling as a fraction of cell size. + "heading_x": represents x direction unit vector. + "heading_y": represents y direction unit vector. +"Color": The color to draw the shape in; needs to be a valid HTML color, e.g."Red" or "#AA08F8" +"Filled": either "true" or "false", and determines whether the shape is filled or not. +"Layer": Layer number of 0 or above; higher-numbered layers are drawn above lower-numbered layers. +"text": Text to overlay on top of the shape. Normally, agent's unique_id is used . +"text_color": Color of the text overlay. +(Shapes also have "x" and "y" coordinates, for the x and y of the grid cell in which it is, but CanvasGrid adds those automatically). +``` For example, suppose for a Schelling model, we want to draw all agents as circles; red ones for the majority (agent type=0), and blue ones for the minority (agent type=1). The function to do this might look like this: -.. code:: python - - def schelling_draw(agent): - if agent is None: - return - portrayal = {"Shape": "circle", "r": 0.5, "Filled": "true", "Layer": 0} - if agent.type == 0: - portrayal["Color"] = "Red" - else: - portrayal["Color"] = "Blue" - return portrayal +```python +def schelling_draw(agent): + if agent is None: + return + portrayal = {"Shape": "circle", "r": 0.5, "Filled": "true", "Layer": 0} + if agent.type == 0: + portrayal["Color"] = "Red" + else: + portrayal["Color"] = "Blue" + return portrayal +``` In addition, a CanvasGrid needs to know the width and height of the grid (in number of cells), and the width and height in pixels of the grid to @@ -102,20 +99,19 @@ with a grid of 10x10, which we want to draw at 500px X 500px. using the portrayal function we wrote above, we would instantiate our visualization element as follows: -.. code:: python - - canvas_element = CanvasGrid(schelling_draw, 10, 10, 500, 500) +```python +canvas_element = CanvasGrid(schelling_draw, 10, 10, 500, 500) +``` Then, to launch a server with this grid as the only visualization element: -.. code:: python - - server = ModularServer(SchellingModel, [canvas_element], "Schelling") - server.launch() +```python +server = ModularServer(SchellingModel, [canvas_element], "Schelling") +server.launch() +``` -Sub-Classing Modules --------------------- +## Sub-Classing Modules In some cases, you may want to customize the internals of an existing visualization module. The best way to do this is to create a subclass of @@ -130,42 +126,41 @@ model object. Suppose we want a module which can get an arbitrary variable out of a model, and display its name and value. Let's create a new subclass: -.. code:: python +```python +from mesa.visualization.ModularTextVisualization import TextElement - from mesa.visualization.ModularTextVisualization import TextElement +class AttributeElement(TextElement): + def __init__(self, attr_name): + ''' + Create a new text attribute element. - class AttributeElement(TextElement): - def __init__(self, attr_name): - ''' - Create a new text attribute element. + Args: + attr_name: The name of the attribute to extract from the model. - Args: - attr_name: The name of the attribute to extract from the model. + Example return: "happy: 10" + ''' + self.attr_name = attr_name - Example return: "happy: 10" - ''' - self.attr_name = attr_name - - def render(self, model): - val = getattr(model, self.attr_name) - return attr_name + ": " + str(val) + def render(self, model): + val = getattr(model, self.attr_name) + return attr_name + ": " + str(val) +``` Now, if we wanted to use our new AttributeElement to add the number of happy agents to our Schelling visualization, it might look something like this: -.. code:: python - - happy_element = AttributeElement("happy") - server = ModularServer(SchellingModel, [canvas_element, happy_element], "Schelling") - server.launch() +```python +happy_element = AttributeElement("happy") +server = ModularServer(SchellingModel, [canvas_element, happy_element], "Schelling") +server.launch() +``` Note that, in this case, we only wanted to change the Python-side render method. We're still using the parent module's HTML and JavaScript template. -Creating a new browser display ------------------------------- +## Creating a new browser display But what if we want more than just a different Python renderer; we want to substantially change how a module displays in the browser, or create @@ -175,23 +170,23 @@ as well: Let's take a look at the internals of **TextModule.js**, the JavaScript for the TextVisualization. Here it is, in all its glory: -.. code:: javascript - - const TextModule = function () { - const text = document.createElement("p"); - text.className = "lead"; +```javascript +const TextModule = function () { + const text = document.createElement("p"); + text.className = "lead"; - // Append text tag to #elements: - document.getElementById("elements").appendChild(text); + // Append text tag to #elements: + document.getElementById("elements").appendChild(text); - this.render = function (data) { - text.innerHTML = data; - }; + this.render = function (data) { + text.innerHTML = data; + }; - this.reset = function () { - text.innerHTML = ""; - }; - }; + this.reset = function () { + text.innerHTML = ""; + }; +}; +``` This code is the JavaScript equivalent of defining a class. When instantiated, a TextModule object will create a new paragraph tag and @@ -209,20 +204,20 @@ Now let's take a look at the TextModule's Python counterpart, **TextElement** (which resides in **TextVisualization.py**). Again, here's the whole thing: -.. code:: python +```python +from mesa.visualization.ModularVisualization import VisualizationElement - from mesa.visualization.ModularVisualization import VisualizationElement - - class TextElement(VisualizationElement): - js_includes = ["TextModule.js"] - js_code = "elements.push(new TextModule());" +class TextElement(VisualizationElement): + js_includes = ["TextModule.js"] + js_code = "elements.push(new TextModule());" +``` That's it! Notice that it is lacking a *render()* method, like the one -we defined above. Look at what is there: *js\_includes* is a list of +we defined above. Look at what is there: *js_includes* is a list of JavaScript files to import into the page when this element is present. In this case, it just imports **TextModule.js**. -Next, *js\_code* is some JavaScript code, in Python string form, to run +Next, *js_code* is some JavaScript code, in Python string form, to run when the visualization page loads. In this case, *new TextModule()* creates a new TextModule object as defined above (which, remember, also appends a new paragraph to the page body) which is then appended to the @@ -233,12 +228,12 @@ To help understand why it looks like this, here's a snippet of JavaScript from the overall visualization template itself, on how to handle incoming data: -.. code:: javascript - - data = msg["data"] - for (var i in elements) { - elements[i].render(data[i]); - } +```javascript +data = msg["data"] +for (var i in elements) { + elements[i].render(data[i]); +} +``` Data to visualize arrive over the websocket as a list. For each index of the list, the code passes that element of the data to the *render* From 7f101672db1561950f5694ac0edf51327ff76f64 Mon Sep 17 00:00:00 2001 From: rht Date: Tue, 20 Feb 2024 20:57:48 -0500 Subject: [PATCH 13/25] docs: Convert CONTRIBUTING .rst -> .md via rst2myst (#2041) --- CONTRIBUTING.md | 110 ++++++++++++++++++++++++++++++++++++++++++ CONTRIBUTING.rst | 121 ----------------------------------------------- 2 files changed, 110 insertions(+), 121 deletions(-) create mode 100644 CONTRIBUTING.md delete mode 100644 CONTRIBUTING.rst diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000000..ffc5d699b10 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,110 @@ +# Contributing + +As an open source project, Mesa welcomes contributions of many forms, and from beginners to experts. If you are +curious or just want to see what is happening, we post our development session agendas +and development session notes on [Mesa discussions]. We also have a threaded discussion forum on [Matrix] +for casual conversation. + +In no particular order, examples include: + +- Code patches +- Bug reports and patch reviews +- New features +- Documentation improvements +- Tutorials + +No contribution is too small. Although, contributions can be too big, so let's +discuss via [Matrix] OR via [an issue]. + +**To submit a contribution** + +- Create a ticket for the item that you are working on. +- Fork the Mesa repository. +- [Clone your repository] from Github to your machine. +- Create a new branch in your fork: `git checkout -b BRANCH_NAME` +- Run `git config pull.rebase true`. This prevents messy merge commits when updating your branch on top of Mesa main branch. +- Install an editable version with developer requirements locally: `pip install -e ".[dev]"` +- Edit the code. Save. +- Git add the new files and files with changes: `git add FILE_NAME` +- Git commit your changes with a meaningful message: `git commit -m "Fix issue X"` +- If implementing a new feature, include some documentation in docs folder. +- Make sure that your submission works with a few of the examples in the examples repository. If adding a new feature to mesa, please illustrate usage by implementing it in an example. +- Make sure that your submission passes the [GH Actions build]. See "Testing and Standards below" to be able to run these locally. +- Make sure that your code is formatted according to [the black] standard (you can do it via [pre-commit]). +- Push your changes to your fork on Github: `git push origin NAME_OF_BRANCH`. +- [Create a pull request]. +- Describe the change w/ ticket number(s) that the code fixes. +- Format your commit message as per [Tim Pope's guideline]. + +## Testing and Code Standards + +```{image} https://codecov.io/gh/projectmesa/mesa/branch/main/graph/badge.svg +:target: https://codecov.io/gh/projectmesa/mesa +``` + +```{image} https://img.shields.io/badge/code%20style-black-000000.svg +:target: https://github.com/psf/black +``` + +As part of our contribution process, we practice continuous integration and use GH Actions to help enforce best practices. + +If you're changing previous Mesa features, please make sure of the following: + +- Your changes pass the current tests. +- Your changes pass our style standards. +- Your changes don't break the models or your changes include updated models. +- Additional features or rewrites of current features are accompanied by tests. +- New features are demonstrated in a model, so folks can understand more easily. + +To ensure that your submission will not break the build, you will need to install Ruff and pytest. + +```bash +pip install ruff pytest pytest-cov +``` + +We test by implementing simple models and through traditional unit tests in the tests/ folder. The following only covers unit tests coverage. Ensure that your test coverage has not gone down. If it has and you need help, we will offer advice on how to structure tests for the contribution. + +```bash +py.test --cov=mesa tests/ +``` + +With respect to code standards, we follow [PEP8] and the [Google Style Guide]. We use [ruff format] (a more performant alternative to `black`) as an automated code formatter. You can automatically format your code using [pre-commit], which will prevent `git commit` of unstyled code and will automatically apply black style so you can immediately re-run `git commit`. To set up pre-commit run the following commands: + +```bash +pip install pre-commit +pre-commit install +``` + +You should no longer have to worry about code formatting. If still in doubt you may run the following command. If the command generates errors, fix all errors that are returned. + +```bash +ruff . +``` + +## Licensing + +The license of this project is located in [LICENSE]. By submitting a contribution to this project, you are agreeing that your contribution will be released under the terms of this license. + +## Special Thanks + +A special thanks to the following projects who offered inspiration for this contributing file. + +- [Django] +- [18F's FOIA] +- [18F's Midas] + +[18f's foia]: https://github.com/18F/foia-hub/blob/master/CONTRIBUTING.md +[18f's midas]: https://github.com/18F/midas/blob/devel/CONTRIBUTING.md +[an issue]: https://github.com/projectmesa/mesa/issues +[black]: https://github.com/psf/black +[clone your repository]: https://help.github.com/articles/cloning-a-repository/ +[create a pull request]: https://help.github.com/articles/creating-a-pull-request/ +[django]: https://github.com/django/django/blob/master/CONTRIBUTING.rst +[gh actions build]: https://github.com/projectmesa/mesa/actions/workflows/build_lint.yml +[google style guide]: https://google.github.io/styleguide/pyguide.html +[license]: https://github.com/projectmesa/mesa/blob/main/LICENSE +[matrix]: https://matrix.to/#/#project-mesa:matrix.org` +[mesa discussions]: https://github.com/projectmesa/mesa/discussions +[pep8]: https://www.python.org/dev/peps/pep-0008 +[pre-commit]: https://github.com/pre-commit/pre-commit +[tim pope's guideline]: https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index 839fcec8293..00000000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,121 +0,0 @@ -Contributing -========================= - -As an open source project, Mesa welcomes contributions of many forms, and from beginners to experts. If you are -curious or just want to see what is happening, we post our development session agendas -and development session notes on `Mesa discussions`_. We also have a threaded discussion forum on `Matrix`_ -for casual conversation. - -In no particular order, examples include: - -- Code patches -- Bug reports and patch reviews -- New features -- Documentation improvements -- Tutorials - -No contribution is too small. Although, contributions can be too big, so let's -discuss via `Matrix`_ OR via `an issue`_. - -.. _`Mesa discussions`: https://github.com/projectmesa/mesa/discussions -.. _`Matrix`: https://matrix.to/#/#project-mesa:matrix.org` -.. _`an issue` : https://github.com/projectmesa/mesa/issues - -**To submit a contribution** - -- Create a ticket for the item that you are working on. -- Fork the Mesa repository. -- `Clone your repository`_ from Github to your machine. -- Create a new branch in your fork: ``git checkout -b BRANCH_NAME`` -- Run ``git config pull.rebase true``. This prevents messy merge commits when updating your branch on top of Mesa main branch. -- Install an editable version with developer requirements locally: ``pip install -e ".[dev]"`` -- Edit the code. Save. -- Git add the new files and files with changes: ``git add FILE_NAME`` -- Git commit your changes with a meaningful message: ``git commit -m "Fix issue X"`` -- If implementing a new feature, include some documentation in docs folder. -- Make sure that your submission works with a few of the examples in the examples repository. If adding a new feature to mesa, please illustrate usage by implementing it in an example. -- Make sure that your submission passes the `GH Actions build`_. See "Testing and Standards below" to be able to run these locally. -- Make sure that your code is formatted according to `the black`_ standard (you can do it via `pre-commit`_). -- Push your changes to your fork on Github: ``git push origin NAME_OF_BRANCH``. -- `Create a pull request`_. -- Describe the change w/ ticket number(s) that the code fixes. -- Format your commit message as per `Tim Pope's guideline`_. - -.. _`Clone your repository` : https://help.github.com/articles/cloning-a-repository/ -.. _`GH Actions build` : https://github.com/projectmesa/mesa/actions/workflows/build_lint.yml -.. _`Create a pull request` : https://help.github.com/articles/creating-a-pull-request/ -.. _`pre-commit` : https://github.com/pre-commit/pre-commit -.. _`black` : https://github.com/psf/black -.. _`Tim Pope's guideline` : https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html - - -Testing and Code Standards --------- - -.. image:: https://codecov.io/gh/projectmesa/mesa/branch/main/graph/badge.svg - :target: https://codecov.io/gh/projectmesa/mesa - -.. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/psf/black - -As part of our contribution process, we practice continuous integration and use GH Actions to help enforce best practices. - -If you're changing previous Mesa features, please make sure of the following: - -- Your changes pass the current tests. -- Your changes pass our style standards. -- Your changes don't break the models or your changes include updated models. -- Additional features or rewrites of current features are accompanied by tests. -- New features are demonstrated in a model, so folks can understand more easily. - -To ensure that your submission will not break the build, you will need to install Ruff and pytest. - -.. code-block:: bash - - pip install ruff pytest pytest-cov - -We test by implementing simple models and through traditional unit tests in the tests/ folder. The following only covers unit tests coverage. Ensure that your test coverage has not gone down. If it has and you need help, we will offer advice on how to structure tests for the contribution. - -.. code-block:: bash - - py.test --cov=mesa tests/ - -With respect to code standards, we follow `PEP8`_ and the `Google Style Guide`_. We use `ruff format`_ (a more performant alternative to `black`) as an automated code formatter. You can automatically format your code using `pre-commit`_, which will prevent `git commit` of unstyled code and will automatically apply black style so you can immediately re-run `git commit`. To set up pre-commit run the following commands: - -.. code-block:: bash - - pip install pre-commit - pre-commit install - -You should no longer have to worry about code formatting. If still in doubt you may run the following command. If the command generates errors, fix all errors that are returned. - -.. code-block:: bash - - ruff . - - -.. _`PEP8` : https://www.python.org/dev/peps/pep-0008 -.. _`Google Style Guide` : https://google.github.io/styleguide/pyguide.html -.. _`pre-commit` : https://github.com/pre-commit/pre-commit -.. _`black` : https://github.com/psf/black - -Licensing --------- - -The license of this project is located in `LICENSE`_. By submitting a contribution to this project, you are agreeing that your contribution will be released under the terms of this license. - -.. _`LICENSE` : https://github.com/projectmesa/mesa/blob/main/LICENSE - - -Special Thanks --------- - -A special thanks to the following projects who offered inspiration for this contributing file. - -- `Django`_ -- `18F's FOIA`_ -- `18F's Midas`_ - -.. _`Django` : https://github.com/django/django/blob/master/CONTRIBUTING.rst -.. _`18F's FOIA` : https://github.com/18F/foia-hub/blob/master/CONTRIBUTING.md -.. _`18F's Midas` : https://github.com/18F/midas/blob/devel/CONTRIBUTING.md From 913dfb852ec61973616c690d5fb7b64c51688ec4 Mon Sep 17 00:00:00 2001 From: rht Date: Tue, 20 Feb 2024 21:48:22 -0500 Subject: [PATCH 14/25] docs: Rewrite howto.md using ChatGPT for clarity and conciseness (#2037) --- docs/howto.md | 72 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/docs/howto.md b/docs/howto.md index ae47e7f7225..7fbb08e3576 100644 --- a/docs/howto.md +++ b/docs/howto.md @@ -1,48 +1,63 @@ # How-to Guide -Here you can find code that allows you to get to get started on common tasks in Mesa. +This guide provides concise instructions and examples to help you start with common tasks in Mesa. ## Models with Discrete Time -If you have `Multiple` type agents and one of them has time attribute you can still build a model that is run by discrete time. In this example, each step of the model, and the agents have a time attribute that is equal to the discrete time to run its own step. +For models involving agents of multiple types, including those with a time attribute, you can construct a discrete-time model. This setup allows each agent to perform actions in steps that correspond to the model's discrete time. +Example: ```python if self.model.schedule.time in self.discrete_time: self.model.space.move_agent(self, new_pos) ``` -## Implementing Model Level Functions in Staged Activation +## Implementing Model-Level Functions with Staged Activation -In staged activation, if you may want a function to be implemented only on the model level and not at the level of agents. -For such functions, include the prefix "model." before the model function name, when defining the function list. -For example, consider a central employment exchange which adjust the wage rate common to all laborers -in the direction of excess demand. +In staged activation scenarios, to designate functions that should only operate +at the model level (and not at the agent level), prepend the function name with +"model." in the function list definition. This approach is useful for +model-wide operations, like adjusting a wage rate based on demand. +Example: ```python -stage_list=[Send_Labour_Supply, Send_Labour_Demand, model.Adjust_Wage_Rate] self.schedule = StagedActivation(self,stage_list,shuffle=True) +stage_list = [Send_Labour_Supply, Send_Labour_Demand, model.Adjust_Wage_Rate] +self.schedule = StagedActivation(self, stage_list, shuffle=True) ``` ## Using `numpy.random` -Sometimes you need to use `numpy`'s `random` library, for example to get a Poisson distribution. +To incorporate `numpy`'s random functions, such as for generating a Poisson +distribution, initialize a random number generator in your model's constructor. +Example: ```python -class MyModel(Model): - def __init__(self, ...): +import mesa +import numpy as np + +class MyModel(mesa.Model): + def __init__(self, seed=None): super().__init__() self.random = np.random.default_rng(seed) ``` -And just use `numpy`'s random as usual, e.g. `self.random.poisson()`. +Usage example: +```python +lambda_value = 5 +sample = self.random.poisson(lambda_value) +``` -## Using multi-process `batch_run` on Windows +## Multi-process `batch_run` on Windows -You will have an issue with `batch_run` and `number_processes = None`. Your cell will -show no progress, and in your terminal you will receive *AttributeError: Can't get attribute 'MoneyModel' on -\*. One way to overcome this is to take your code outside of Jupyter and adjust the above -code as follows. +When using `batch_run` with `number_processes = None` on Windows, you might +encounter progress display issues or `AttributeError: Can't get attribute +'MoneyModel' on `. To resolve this, run +your code outside of Jupyter notebooks and use the following pattern, +incorporating `freeze_support()` for multiprocessing support. +Example: ```python +from mesa.batchrunner import batch_run from multiprocessing import freeze_support params = {"width": 10, "height": 10, "N": range(10, 500, 10)} @@ -50,16 +65,19 @@ params = {"width": 10, "height": 10, "N": range(10, 500, 10)} if __name__ == '__main__': freeze_support() results = batch_run( - MoneyModel, - parameters=params, - iterations=5, - max_steps=100, - number_processes=None, - data_collection_period=1, - display_progress=True, + MoneyModel, + parameters=params, + iterations=5, + max_steps=100, + number_processes=None, + data_collection_period=1, + display_progress=True, ) ``` -If you would still like to run your code in Jupyter you will need to adjust the cell as noted above. Then you can -you can add the [nbmultitask library](https://nbviewer.org/github/micahscopes/nbmultitask/blob/39b6f31b047e8a51a0fcb5c93ae4572684f877ce/examples.ipynb) -or look at this [stackoverflow](https://stackoverflow.com/questions/50937362/multiprocessing-on-python-3-jupyter). +If you would still like to run your code in Jupyter, adjust your code as +described and consider integrating external libraries like +[nbmultitask](https://nbviewer.org/github/micahscopes/nbmultitask/blob/39b6f31b047e8a51a0fcb5c93ae4572684f877ce/examples.ipynb) +or refer to [Stack +Overflow](https://stackoverflow.com/questions/50937362/multiprocessing-on-python-3-jupyter) +for multiprocessing tips. From 3bafa1439038b82321bb52744bb6decb4f687d49 Mon Sep 17 00:00:00 2001 From: Jan Kwakkel Date: Wed, 21 Feb 2024 08:06:30 +0100 Subject: [PATCH 15/25] feature: Enable AgentSet.get to retrieve one or more than one attribute (#2044) * new feature: AgentSet.get can retrieve one or more than one attribute * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * minor docstring update * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * add AttributeError to docstring and fixes capital L in List * Update agent.py * Update agent.py --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- mesa/agent.py | 22 +++++++++++++++++----- tests/test_agent.py | 18 ++++++++++++++++++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/mesa/agent.py b/mesa/agent.py index 243a187337b..57edf1a032a 100644 --- a/mesa/agent.py +++ b/mesa/agent.py @@ -264,17 +264,29 @@ def do( return res if return_results else self - def get(self, attr_name: str) -> list[Any]: + def get(self, attr_names: str | list[str]) -> list[Any]: """ - Retrieve a specified attribute from each agent in the AgentSet. + Retrieve the specified attribute(s) from each agent in the AgentSet. Args: - attr_name (str): The name of the attribute to retrieve from each agent. + attr_names (str | list[str]): The name(s) of the attribute(s) to retrieve from each agent. Returns: - list[Any]: A list of attribute values from each agent in the set. + list[Any]: A list with the attribute value for each agent in the set if attr_names is a str + list[list[Any]]: A list with a list of attribute values for each agent in the set if attr_names is a list of str + + Raises: + AttributeError if an agent does not have the specified attribute(s) + """ - return [getattr(agent, attr_name) for agent in self._agents] + + if isinstance(attr_names, str): + return [getattr(agent, attr_names) for agent in self._agents] + else: + return [ + [getattr(agent, attr_name) for attr_name in attr_names] + for agent in self._agents + ] def __getitem__(self, item: int | slice) -> Agent: """ diff --git a/tests/test_agent.py b/tests/test_agent.py index 7ad538eba27..0cd211123e1 100644 --- a/tests/test_agent.py +++ b/tests/test_agent.py @@ -221,6 +221,24 @@ def test_agentset_get_attribute(): with pytest.raises(AttributeError): agentset.get("non_existing_attribute") + model = Model() + agents = [] + for i in range(10): + agent = TestAgent(model.next_id(), model) + agent.i = i**2 + agents.append(agent) + agentset = AgentSet(agents, model) + + values = agentset.get(["unique_id", "i"]) + + for value, agent in zip(values, agents): + ( + unique_id, + i, + ) = value + assert agent.unique_id == unique_id + assert agent.i == i + class OtherAgentType(Agent): def get_unique_identifier(self): From 0d01a538902be33a5169444e244c4ca5ca43cd95 Mon Sep 17 00:00:00 2001 From: Jack at Omen Apps <37490393+JackAtOmenApps@users.noreply.github.com> Date: Wed, 21 Feb 2024 23:52:00 -0600 Subject: [PATCH 16/25] benchmark: Correct wolf energy gained from eating sheep (#2048) --- benchmarks/WolfSheep/wolf_sheep.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/WolfSheep/wolf_sheep.py b/benchmarks/WolfSheep/wolf_sheep.py index 90948a0c588..5d4d9fef5ff 100644 --- a/benchmarks/WolfSheep/wolf_sheep.py +++ b/benchmarks/WolfSheep/wolf_sheep.py @@ -84,7 +84,7 @@ def feed(self): sheep = [obj for obj in agents if isinstance(obj, Sheep)] if len(sheep) > 0: sheep_to_eat = self.random.choice(sheep) - self.energy += self.energy + self.energy += self.energy_from_food # Kill the sheep sheep_to_eat.die() From 4bf4b528883fc10792b2af70f8d9556d3679437b Mon Sep 17 00:00:00 2001 From: rht Date: Thu, 22 Feb 2024 06:48:33 -0500 Subject: [PATCH 17/25] fix: Use model.schedule only when it is not None (#2050) --- mesa/datacollection.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mesa/datacollection.py b/mesa/datacollection.py index 3fcd205c9c5..f5f6ead235b 100644 --- a/mesa/datacollection.py +++ b/mesa/datacollection.py @@ -184,7 +184,9 @@ def get_reports(agent): agent_records = map( get_reports, - model.schedule.agents if hasattr(model, "schedule") else model.agents, + model.schedule.agents + if hasattr(model, "schedule") and model.schedule is not None + else model.agents, ) return agent_records From cf0b8f78ecbfc4e656cbc815893de9a092e51a82 Mon Sep 17 00:00:00 2001 From: rht Date: Mon, 22 Jan 2024 20:24:22 -0500 Subject: [PATCH 18/25] feat: Implement Altair version of grid visualization _draw_grid is derived from https://github.com/Princeton-CDH/simulating-risk/blob/907c290e12c97b28aa9ce9c80ea7fc52a4f280ae/simulatingrisk/hawkdove/server.py#L114-L171 Co-authored-by: rlskoeser --- mesa/experimental/components/altair.py | 52 ++++++++++++++++++++++++++ mesa/experimental/jupyter_viz.py | 9 +++++ 2 files changed, 61 insertions(+) create mode 100644 mesa/experimental/components/altair.py diff --git a/mesa/experimental/components/altair.py b/mesa/experimental/components/altair.py new file mode 100644 index 00000000000..3b249923b9e --- /dev/null +++ b/mesa/experimental/components/altair.py @@ -0,0 +1,52 @@ +import contextlib +from typing import Optional + +import pandas as pd +import solara + +with contextlib.suppress(ImportError): + import altair as alt + +@solara.component +def SpaceAltair(model, agent_portrayal, dependencies: Optional[list[any]] = None): + space = getattr(model, "grid", None) + if space is None: + # Sometimes the space is defined as model.space instead of model.grid + space = model.space + chart = _draw_grid(space, agent_portrayal) + solara.FigureAltair(chart) + + +def _draw_grid(space, agent_portrayal): + def portray(g): + all_agent_data = [] + for content, (x, y) in space.coord_iter(): + if not content: + continue + if not hasattr(content, "__iter__"): + # Is a single grid + content = [content] # noqa: PLW2901 + for agent in content: + # use all data from agent portrayal, and add x,y coordinates + agent_data = agent_portrayal(agent) + agent_data["x"] = x + agent_data["y"] = y + all_agent_data.append(agent_data) + return all_agent_data + + all_agent_data = portray(space) + df = pd.DataFrame(all_agent_data) + chart = ( + alt.Chart(df) + .mark_point(filled=True) + .encode( + # no x-axis label + x=alt.X("x", axis=None), + # no y-axis label + y=alt.Y("y", axis=None), + size=alt.Size("size"), + color=alt.Color("color"), + ) + # .configure_view(strokeOpacity=0) # hide grid/chart lines + ) + return chart diff --git a/mesa/experimental/jupyter_viz.py b/mesa/experimental/jupyter_viz.py index a6ae318a822..9d29e08fb60 100644 --- a/mesa/experimental/jupyter_viz.py +++ b/mesa/experimental/jupyter_viz.py @@ -6,6 +6,7 @@ import solara from solara.alias import rv +import mesa.experimental.components.altair as components_altair import mesa.experimental.components.matplotlib as components_matplotlib from mesa.experimental.UserParam import Slider @@ -28,6 +29,10 @@ def Card( components_matplotlib.SpaceMatplotlib( model, agent_portrayal, dependencies=[current_step.value] ) + elif space_drawer == "altair": + components_altair.SpaceAltair( + model, agent_portrayal, dependencies=[current_step.value] + ) elif space_drawer: # if specified, draw agent space with an alternate renderer space_drawer(model, agent_portrayal) @@ -113,6 +118,10 @@ def render_in_jupyter(): components_matplotlib.SpaceMatplotlib( model, agent_portrayal, dependencies=[current_step.value] ) + elif space_drawer == "altair": + components_altair.SpaceAltair( + model, agent_portrayal, dependencies=[current_step.value] + ) elif space_drawer: # if specified, draw agent space with an alternate renderer space_drawer(model, agent_portrayal) From 0374f495143d582187028f3614140fcaf721a45c Mon Sep 17 00:00:00 2001 From: rht Date: Sun, 28 Jan 2024 15:06:55 -0500 Subject: [PATCH 19/25] Make color and size optional --- mesa/experimental/components/altair.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/mesa/experimental/components/altair.py b/mesa/experimental/components/altair.py index 3b249923b9e..75e89efea5f 100644 --- a/mesa/experimental/components/altair.py +++ b/mesa/experimental/components/altair.py @@ -44,9 +44,16 @@ def portray(g): x=alt.X("x", axis=None), # no y-axis label y=alt.Y("y", axis=None), - size=alt.Size("size"), - color=alt.Color("color"), ) # .configure_view(strokeOpacity=0) # hide grid/chart lines ) + + has_color = hasattr(all_agent_data[0], "color") + if has_color: + chart = chart.encode(color=alt.Color("color")) + + has_size = hasattr(all_agent_data[0], "size") + if has_size: + chart = chart.encode(size=alt.Size("size")) + return chart From 9f60c91d7290b63a9b759999c214702c39b0d764 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 28 Jan 2024 20:17:10 +0000 Subject: [PATCH 20/25] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mesa/experimental/components/altair.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mesa/experimental/components/altair.py b/mesa/experimental/components/altair.py index 75e89efea5f..9d790dc3aa8 100644 --- a/mesa/experimental/components/altair.py +++ b/mesa/experimental/components/altair.py @@ -7,6 +7,7 @@ with contextlib.suppress(ImportError): import altair as alt + @solara.component def SpaceAltair(model, agent_portrayal, dependencies: Optional[list[any]] = None): space = getattr(model, "grid", None) From 52702e2d6c5ff21b05a4aa6899d9beee72090d29 Mon Sep 17 00:00:00 2001 From: rht Date: Sun, 28 Jan 2024 20:15:24 -0500 Subject: [PATCH 21/25] Altair viz: Convert from DF -> alt.Data --- mesa/experimental/components/altair.py | 32 ++++++++++++-------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/mesa/experimental/components/altair.py b/mesa/experimental/components/altair.py index 9d790dc3aa8..2d10fc30363 100644 --- a/mesa/experimental/components/altair.py +++ b/mesa/experimental/components/altair.py @@ -1,7 +1,6 @@ import contextlib from typing import Optional -import pandas as pd import solara with contextlib.suppress(ImportError): @@ -36,25 +35,24 @@ def portray(g): return all_agent_data all_agent_data = portray(space) - df = pd.DataFrame(all_agent_data) + encoding_dict = { + # no x-axis label + "x": alt.X("x", axis=None, type="ordinal"), + # no y-axis label + "y": alt.Y("y", axis=None, type="ordinal"), + } + has_color = "color" in all_agent_data[0] + if has_color: + encoding_dict["color"] = alt.Color("color", type="nominal") + has_size = "size" in all_agent_data[0] + if has_size: + encoding_dict["size"] = alt.Size("size", type="quantitative") + chart = ( - alt.Chart(df) + alt.Chart(alt.Data(values=all_agent_data), encoding=alt.Encoding(**encoding_dict)) .mark_point(filled=True) - .encode( - # no x-axis label - x=alt.X("x", axis=None), - # no y-axis label - y=alt.Y("y", axis=None), - ) + .properties(width=space.width * 15, height=space.height * 15) # .configure_view(strokeOpacity=0) # hide grid/chart lines ) - has_color = hasattr(all_agent_data[0], "color") - if has_color: - chart = chart.encode(color=alt.Color("color")) - - has_size = hasattr(all_agent_data[0], "size") - if has_size: - chart = chart.encode(size=alt.Size("size")) - return chart From 6cbe17a99da580cd528533af74ad2e5fff93fe26 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 5 Feb 2024 13:39:59 +0000 Subject: [PATCH 22/25] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mesa/experimental/components/altair.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mesa/experimental/components/altair.py b/mesa/experimental/components/altair.py index 2d10fc30363..bd220019f0e 100644 --- a/mesa/experimental/components/altair.py +++ b/mesa/experimental/components/altair.py @@ -49,7 +49,9 @@ def portray(g): encoding_dict["size"] = alt.Size("size", type="quantitative") chart = ( - alt.Chart(alt.Data(values=all_agent_data), encoding=alt.Encoding(**encoding_dict)) + alt.Chart( + alt.Data(values=all_agent_data), encoding=alt.Encoding(**encoding_dict) + ) .mark_point(filled=True) .properties(width=space.width * 15, height=space.height * 15) # .configure_view(strokeOpacity=0) # hide grid/chart lines From 777f42e8f8e59b196251a318f2fa1738325ce8f8 Mon Sep 17 00:00:00 2001 From: rht Date: Thu, 8 Feb 2024 03:30:07 -0500 Subject: [PATCH 23/25] Altair viz: Hardcode width/height consistent with Card width/height --- mesa/experimental/components/altair.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesa/experimental/components/altair.py b/mesa/experimental/components/altair.py index bd220019f0e..2b08485b848 100644 --- a/mesa/experimental/components/altair.py +++ b/mesa/experimental/components/altair.py @@ -53,7 +53,7 @@ def portray(g): alt.Data(values=all_agent_data), encoding=alt.Encoding(**encoding_dict) ) .mark_point(filled=True) - .properties(width=space.width * 15, height=space.height * 15) + .properties(width=280, height=280) # .configure_view(strokeOpacity=0) # hide grid/chart lines ) From 6dbe3e8572db4fa0b0db6fee1ee89d4123587ad4 Mon Sep 17 00:00:00 2001 From: rht Date: Thu, 22 Feb 2024 02:45:37 -0500 Subject: [PATCH 24/25] fix: Remove JupyterViz grid marker overlap for huge grid size --- mesa/experimental/components/matplotlib.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mesa/experimental/components/matplotlib.py b/mesa/experimental/components/matplotlib.py index c43ad964224..85f8df9cb1d 100644 --- a/mesa/experimental/components/matplotlib.py +++ b/mesa/experimental/components/matplotlib.py @@ -48,6 +48,9 @@ def portray(g): if "color" in data: c.append(data["color"]) out = {"x": x, "y": y} + # This is the default value for the marker size, which auto-scales + # according to the grid area. + out["s"] = (180 / min(g.width, g.height)) ** 2 if len(s) > 0: out["s"] = s if len(c) > 0: From 13938f712a75b5bdd08e2a4a0a4563c660a593d0 Mon Sep 17 00:00:00 2001 From: Jackie Kazil Date: Sat, 24 Feb 2024 13:43:12 -0500 Subject: [PATCH 25/25] Update CODE_OF_CONDUCT.md to version 2+ of contrib convenant Our CoC has been based on the https://www.contributor-covenant.org/, which has been updated since we last updated. It not includes more structure around enforcement. To keep in alignment, I am submitting this update. This update is an exact copy of this -- https://www.contributor-covenant.org/version/2/1/code_of_conduct/ Except the report section has been updated for methods of reporting. --- CODE_OF_CONDUCT.md | 129 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 107 insertions(+), 22 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index e89075532dd..63fd8cc5dde 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,46 +1,131 @@ -# Contributor Covenant Code of Conduct +# Contributor Covenant Code of Conduct ## Our Pledge -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. ## Our Standards -Examples of behavior that contributes to creating a positive environment include: +Examples of behavior that contributes to a positive environment for our +community include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community -Examples of unacceptable behavior by participants include: +Examples of unacceptable behavior include: -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting -## Our Responsibilities +## Enforcement Responsibilities -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. ## Scope -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official email address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by using Matrix to direct message a [Mesa administrator](@edgeofchaos:matrix.org). The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at [@jackiekazil](https://matrix.to/#/@jackiekazil:matrix.org) and/or [@edgeofchaos](https://matrix.to/#/@edgeofchaos:matrix.org). Violations posted as Github comments, discussion, etc maybe also be reported via the [report functionality](https://docs.github.com/en/communities/maintaining-your-safety-on-github/reporting-abuse-or-spam) +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations