Giter Site home page Giter Site logo

jofmi / agentpy Goto Github PK

View Code? Open in Web Editor NEW
306.0 8.0 38.0 71.26 MB

AgentPy is an open-source framework for the development and analysis of agent-based models in Python.

Home Page: https://agentpy.readthedocs.io/

License: BSD 3-Clause "New" or "Revised" License

Python 98.04% TeX 1.96%
agent-based-modeling agent-based-simulation abm agentpy python networks complex-systems networkx salib

agentpy's Introduction

AgentPy - Agent-based modeling in Python

PyPI GitHub Documentation Status DOI

AgentPy is an open-source library for the development and analysis of agent-based models in Python. The framework integrates the tasks of model design, interactive simulations, numerical experiments, and data analysis within a single environment. The package is optimized for interactive computing with IPython, IPySimulate, and Jupyter.

Please cite this software as follows:

Foramitti, J., (2021). AgentPy: A package for agent-based modeling in Python.
Journal of Open Source Software, 6(62), 3065, https://doi.org/10.21105/joss.03065

Installation: pip install agentpy

Documentation: https://agentpy.readthedocs.io

JOSS publication: https://doi.org/10.21105/joss.03065

Discussion forum: https://github.com/JoelForamitti/agentpy/discussions

Tutorials and examples: https://agentpy.readthedocs.io/en/latest/model_library.html

Comparison with other frameworks: https://agentpy.readthedocs.io/en/latest/comparison.html

agentpy's People

Contributors

dependabot[bot] avatar ewouth avatar isabeaups avatar jofmi avatar tortar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

agentpy's Issues

calc_sobol() throws TypeError (seems related to Pandas >= 2.0)

Dear Developers:

Hello, first I want to thank you for developing and maintaining this great package!

I've been following the various examples and models, and when running the Virus Spread model, I get an error when getting to the Sensitivity Analysis section of the notebook. In particular, the results.calc_sobol() cell throws a TypeError that seems related to a change that was made in Pandas 2.0.

My environment is Linux Mint 21.3 (Ubuntu jammy 22.04 LTS), I installed agentpy by following the repo instructions (pip install agentpy). Pandas version in my environment is 2.2.1.

This is the error (long traceback, it goes across 3 screenshots):

Screenshot-1
Screenshot-2
Screenshot-3

This seems related to issue #57031 in Pandas, which happens when upgrading Pandas to >= 2.0.

Will you please see if you can reproduce this error? If so, it'd probably have an easy fix, since the resolution for the mentioned issue in Pandas simply requires to call .mean(numeric_only=True) instead of just .mean(), as it's currently done in calc_sobol() in the DataDict class in datadict.py.

Flocking behavior on python code

Hi,

I'm trying to run a simulation of the flocking behavior in PyCharm. My end goal, after I've checked that the simulation is to my liking, is to get the positions of all the points at all the frames.
Where can I find an example of the flocking behavior that works in PyCharm?

Thanks for your time.

When using `move_to` to go to the same position, a `KeyError` is thrown

I was playing around with the package trying to implement a simple sugar scape like environment, and got a confusing KeyError when using move_to on the Grid. Turns out that this happened when an agent tried to move_to its current location.

I'm not sure what the expected behaviour should be, but I can see two options that are both better than the current approach:

  1. Simply allow it to happen, and have move_to do nothing if the position to move to is the same as the current position for the agent. For my current use, this would be fine, but might cause problems for other people
  2. Throw a different, but more helpful error. An error like: "Agent {id} is trying to move to its current position" would have saved me some time debugging ;)

I have included a traceback of the error, just in case. But from what I can tell this occurs if the agents try to move to their current position.

KeyError                                  Traceback (most recent call last)
<ipython-input-125-dda3ba9185af> in <module>
      1 model = SugarScapeModel({'agents': 20, 'vision': 6, 'max_food': 6, 'spread': 20, 'width': 50, 'height': 50})
----> 2 model.run()

~/Source/SugarScape.py/.env/lib/python3.9/site-packages/agentpy/model.py in run(self, steps, seed, display)
    364         self.sim_setup(steps, seed)
    365         while self.running:
--> 366             self.sim_step()
    367             if display:
    368                 print(f"\rCompleted: {self.t} steps", end='')

~/Source/SugarScape.py/.env/lib/python3.9/site-packages/agentpy/model.py in sim_step(self)
    316         and then calling :func:`Model.step` and :func:`Model.update`."""
    317         self.t += 1
--> 318         self.step()
    319         self.update()
    320         if self.t >= self._steps:

<ipython-input-122-0b943fbda284> in step(self)
     17 
     18     def step(self):
---> 19         self.agents.step()

~/Source/SugarScape.py/.env/lib/python3.9/site-packages/agentpy/sequences.py in __call__(self, *args, **kwargs)
     83 
     84     def __call__(self, *args, **kwargs):
---> 85         return [func_obj(*args, **kwargs) for func_obj in self]
     86 
     87     def __eq__(self, other):

~/Source/SugarScape.py/.env/lib/python3.9/site-packages/agentpy/sequences.py in <listcomp>(.0)
     83 
     84     def __call__(self, *args, **kwargs):
---> 85         return [func_obj(*args, **kwargs) for func_obj in self]
     86 
     87     def __eq__(self, other):

<ipython-input-124-3a612e74c815> in step(self)
     22                 best_pos = (x, y)
     23         print(f"Agent {self.id}, pos {best_pos}")
---> 24         self.scape.move_to(self, best_pos)
     25         self.food = self.scape['food'][best_pos[0]][best_pos[1]]
     26         self.scape['food'][best_pos[0]][best_pos[1]] = 0

~/Source/SugarScape.py/.env/lib/python3.9/site-packages/agentpy/grid.py in move_to(self, agent, pos)
    284             pos = self._border_behavior(pos, self.shape, self._torus)
    285         if self._track_empty:
--> 286             self.empty.replace(pos, pos_old)
    287 
    288         self.grid.agents[pos_old].remove(agent)

~/Source/SugarScape.py/.env/lib/python3.9/site-packages/agentpy/tools.py in replace(self, old_item, new_item)
    134 
    135     def replace(self, old_item, new_item):
--> 136         position = self.item_to_position.pop(old_item)
    137         self.item_to_position[new_item] = position
    138         self.items[position] = new_item

KeyError: (42, 0)

Error in multiprocessing on Windows.

Dear developers,

Recently I tried to integrate an agentpy model with the EMA workbench, the example that was on the documentation was helpful, and I was able to make that run (this example: https://agentpy.readthedocs.io/en/latest/guide_ema.html?highlight=ema ).

However, when I tried to run the model on multiple cores, using the MultiprocessingEvaluater (see https://emaworkbench.readthedocs.io/en/latest/ema_documentation/em_framework/evaluators.html ). I was not able to run my model anymore. The code that I used to run the my model, as well as the example model was:

from ema_workbench import (MultiprocessingEvaluator, ema_logging)
from ema_problem_definitions import ema_problem

model = ema_problem(1)
with MultiprocessingEvaluator(model) as evaluator:
    experiments, outcomes = evaluator.perform_experiments(scenarios=5)

Wherin ema_problem(1) is a function to define the agenpty model as a function. The function is implemented as follows:

from ema_workbench import (Model, RealParameter,
                           ScalarOutcome,  
                           Constant, IntegerParameter)
from model import EtmEVsModel

def ema_problem(problem):
    
    # convert model to function
    EtmEVs = EtmEVsModel.as_function()

    
    model = Model('EtmEVsModel', function=EtmEVs)

I left out the specification of the uncertainties, constants and levers as my post would be rather long if I were to include that.
This code resulted in the following error:
Can't pickle local object 'Model.as_function.<locals>.agentpy_model_as_function

This error does not occur when I try to run the multiprocessing evaluator with a basic example model from the EMA workbench. However, it does occur with my custom model and the example model from the documentation.
Also, it is noteworthy to mention is that I've tested this code on two different windows 11 machines, which both had the same error. However, a Linux machine that we have tried worked and was able to execute the code.

*I don't really have much experience writing an issue, this is my first attempt in my career as a coder. So if something is wrong in the way I write this issue, please let me know.

Agent creation order and color-coding with ipysimulate

I'm not sure if this is necessarily a bug, but I've found that when I'm using ipysimulate to visualize multiple types of agents, color coding is assigned to agents not by their ID, but by the order they appear in self.agents. In other words, if the order of agents in the model's self.agents does not match the order they were initialized in, then the color of an agent is associated with an entirely different agent's attributes.

It's entirely possible that this was intentional and just could use some more documentation, but it was confusing to me at first so I thought I'd point it out. (I'm also not sure whether this is more of an agentpy or an ipysimulate thing.)

In case there's any confusion, I should note that I also posted about this model in the discussion forums (#22). I've since implemented your suggestions for splitting my agents into multiple spaces, and have been able to get the visualization working using the code you provided. However, I noticed the same color-coding issue I've described happening there too. The code below is from the version of my model where agents are in a single space- at the end I've included some notes on what specifically happened with multiple spaces.

Local setup
OS Catalina 10.15.5, using jupyter notebooks
agentpy version 0.1.2
ipysimulate version 0.2.0

Context:
Below is a part of my model class. The resources, the hive, and the bees are all different types of agents, but they all have a self.state.

class ForagingModel(ap.Model):
    """ 
    ABM simulating a very simplified version of bee foraging behavior 
    """

    def setup(self):
        
        # Create ground
        self.space = ap.Space(self, shape=[self.p.land_size]*2, Torus = False)
        
        # Create flowering plants
        self.resources = ap.AgentList(self, self.p.n_resources, Resource)
        self.space.add_agents(self.resources, random=True) # Scatter them randomly
        self.resources.setup_pos(self.space)
        
        # Create hive
        self.hive= ap.AgentList(self, 1, Hive)
        self.space.add_agents(self.hive, [(self.p.land_size/2,self.p.land_size/2)], random=False)
        
        # Create bees
        self.bees = ap.AgentList(self, self.p.population, Bee)
        # Place them at the hive
        self.space.add_agents(self.bees, [[self.p.land_size/2,self.p.land_size/2]]*self.p.population , random=False) 
        self.bees.setup_pos(self.space)
        
        self.agents = self.resources +  self.hive + self.bees 

I visualized the positions and movement of the agents using

scatterplot = ips.Scatterplot(
    control,
    xy=lambda m: m.space.positions.values(),
    c=lambda m: m.agents.state
)

In my model, the bees change their state (ex. inactive, searching, returning), but the hive and the resources do not.

Issue (with agents in one space)
In the above code, the order agents are added to self.agents:
self.agents = self.resources + self.hive + self.bees
matches the order they're created, so everything works as expected. The bees change color when they switch between states (ex. when they switch from foraging to returning to the hive), and both the hive and resource agents stay the same color.

However, if I replace this line with:
self.agents = self.bees + self.hive + self.resources
then suddenly the resources are changing their colors instead of the bees. If I have more bees than resources, then all the resources change color and a couple of the bees do too. However, those bees have their colors determined by other bees' states (ex. bee 150 might have its color determined by the state of bee 20).

Issue (with agents in two spaces)
As you recommended in the discussion forum, I've since changed my code so that resource and bee agents are placed in separate spaces. Following the code you provided, I've changed my visualization code to include:

model47 = ForagingModel(parameters)
control = ips.Control(model47, parameters, variables = ('t', 'num_searching'))

def both_space_positions(m):
    i1 = m.plantspace.positions.values()
    i2 = m.beespace.positions.values()
    return itertools.chain(i1, i2)

scatterplot = ips.Scatterplot(
    control,
    xy=lambda m: both_space_positions(model47), 
    c=lambda m: m.agents.state
)

I noticed that if I switched the order of i1 and i2 like:

def both_space_positions(m):
    i1 = m.beespace.positions.values()
    i2 = m.plantspace.positions.values()
    return itertools.chain(i1, i2)

I encountered the same type of issue- because I initialize the plants before I create the bees, in the visualization the plants change color according to the states of the bees.

Let me know if any other details or code would be helpful. Thank you so much!

Parallelism Not Working as expected

I was trying to use parallelism through experiment.run() and multiprocessing. It properly generated all of the separate processes, but in my task manager none of the processes registered as using any CPU. Doing it this way resulted in no speedup and I think the process got stuck.

I know it isn't just overhead because I was able to run experiments parallel myself using joblib with this wrapper function:

def job(model,n,param):
return ap.Experiment(model,param,iterations=n,record=True).run()

And I would just loop through the parameter combinations in the sample. Doing it this way each process did use CPU and the speedup was about what I would expect. I'm not sure why joblib would work and mulitprocessing wouldn't.

The problem might be because I am running the problem natively on Windows. I can try to replicate the problem in WSL if that would be helpful.

Tutorial example: Virus network cannot animate

Trying to replicate the animation for virus network:

ttributeError Traceback (most recent call last)
in
15 fig, axs = plt.subplots(1, 2, figsize=(8, 4)) # Prepare figure
16 parameters['population'] = 50 # Lower population for better visibility
---> 17 animation = ap.animate(VirusModel(parameters), fig, axs, animation_plot)

~/monocondaNew/lib/python3.7/site-packages/agentpy/analysis.py in animate(model, fig, axs, plot, steps, skip, fargs, **kwargs)
136 plot(m, axs, *fargs) # Perform plot
137
--> 138 ani = matplotlib.animation.FuncAnimation(
139 fig, update, frames=frames, fargs=(model, axs, *fargs), **kwargs) # noqa
140

AttributeError: module 'matplotlib' has no attribute 'animation'

what am I missing here?
Thanks

Fail to use pickle loading a saved Model

When I try to use pickle to save a completed model as a binary file and then load it in the next time, it raises a recursion error:

RecursionError                            Traceback (most recent call last)
Input In [3], in <cell line: 1>()
      1 with open("tests/test.pkl", "rb") as pkl:
----> 2     model = pickle.load(pkl)
      4 model.state

File ~/opt/anaconda3/envs/AgentBasedSHM/lib/python3.9/site-packages/dill/_dill.py:373, in load(file, ignore, **kwds)
    367 def load(file, ignore=None, **kwds):
    368     """
    369     Unpickle an object from a file.
    370 
    371     See :func:`loads` for keyword arguments.
    372     """
--> 373     return Unpickler(file, ignore=ignore, **kwds).load()

File ~/opt/anaconda3/envs/AgentBasedSHM/lib/python3.9/site-packages/dill/_dill.py:646, in Unpickler.load(self)
    645 def load(self): #NOTE: if settings change, need to update attributes
--> 646     obj = StockUnpickler.load(self)
    647     if type(obj).__module__ == getattr(_main_module, '__name__', '__main__'):
    648         if not self._ignore:
    649             # point obj class to main

File ~/opt/anaconda3/envs/AgentBasedSHM/lib/python3.9/site-packages/agentpy/objects.py:27, in Object.__getattr__(self, key)
     26 def __getattr__(self, key):
---> 27     raise AttributeError(f"{self} Has no attribute '{key}'.")

File ~/opt/anaconda3/envs/AgentBasedSHM/lib/python3.9/site-packages/agentpy/objects.py:24, in Object.__repr__(self)
     23 def __repr__(self):
---> 24     return f"{self.type} (Obj {self.id})"

File ~/opt/anaconda3/envs/AgentBasedSHM/lib/python3.9/site-packages/agentpy/objects.py:27, in Object.__getattr__(self, key)
     26 def __getattr__(self, key):
---> 27     raise AttributeError(f"{self} Has no attribute '{key}'.")

File ~/opt/anaconda3/envs/AgentBasedSHM/lib/python3.9/site-packages/agentpy/objects.py:24, in Object.__repr__(self)
     23 def __repr__(self):
---> 24     return f"{self.type} (Obj {self.id})"

    [... skipping similar frames: Object.__getattr__ at line 27 (740 times), Object.__repr__ at line 24 (739 times)]

File ~/opt/anaconda3/envs/AgentBasedSHM/lib/python3.9/site-packages/agentpy/objects.py:24, in Object.__repr__(self)
     23 def __repr__(self):
---> 24     return f"{self.type} (Obj {self.id})"

File ~/opt/anaconda3/envs/AgentBasedSHM/lib/python3.9/site-packages/agentpy/objects.py:27, in Object.__getattr__(self, key)
     26 def __getattr__(self, key):
---> 27     raise AttributeError(f"{self} Has no attribute '{key}'.")

RecursionError: maximum recursion depth exceeded while getting the str of an object

To my opinion, it is because when pickle try to getattr, it raises AttributeError(f"{self} has no attribute '{key}'."), and because of referring to self which is not loaded... then there is a recursion. I don't believe it is necessary to re-write the getattr magic method in this class. Therefore, in my project, I simply changed the __getattr__ magic method of your basic Object class to fix this problem:

def __getattr__(self, key):
    raise AttributeError(f"No attribute '{key}'.")

I'm not sure if anyone else has similar confusion with me; I suggest changing this function in future versions. I think pickle object is more helpful than detailed AttrNotFound error raising...

Empty cell tracking with multiple agents per cell throws error

If a grid is initiated with empty cell tracking, and an agent moves to a cell where there already is another agent, the second agent will try to remove that cell from the empty cells list. This throws a KeyError because the cell is already not in the empty cells list because the first agent previously removed it from the list.

Expected Behavior

The model recognizes that the cell is already not empty.

Current Behavior

An agent tries to remove a cell from the empty cells list when it moves there. If there already is an agent in that cell, this throws a KeyError since the cell is not in the empty cells list anymore.

Possible Solution

Check if any other agents are in the cell, and consider that in https://github.com/JoelForamitti/agentpy/blob/480da12abc19e5c511e0e2e09ee5be44d285e69d/agentpy/grid.py#L286

Steps to Reproduce

See attached notebook and data file. If you set the simulation steps to 10, you can see the agents move towards each other (and the cell marked with a green dot).

Context (Environment)

I am implementing the Sugarscape in AgentPy. Windows 10 Enterprise, Python stuff:

agentpy 0.1.2 pypi_0 pypi
ipysimulate 0.2.0 pypi_0 pypi
jupyterlab 3.0.16 pyhd8ed1ab_0 conda-forge
numpy 1.20.3 py39ha4e8547_0
python 3.9.6 h7840368_1_cpython conda-forge

EDIT: seems similar to #21 and might be related (and therefore fixed?).

Unable to Access Predecessor Nodes in Agentpy Network

Dear Developers:

Hello, first I want to thank you for creating such a fantastic package! It has helped me immensely in my research! Recently, I've had an issue accessing the predecessor nodes in the network. I've created a scale-free network (directed) using a similar code as in the tutorial (https://agentpy.readthedocs.io/en/latest/agentpy_virus_spread.html); however, my network needs to be directed so I can access the predecessors as well as the successors of each node. However, I am having trouble accessing both as an error reads: "The node Person (Obj 9) is not in the digraph." when my code is for n in self.network.graph.predecessors(self) I've also attached my full code below. Thank you so much for your help and I apologize if this seems to be a dumb question!

Best,
Huizi

# Model design
import agentpy as ap
import networkx as nx
import random
import pandas as pd
import numpy as np
from scipy.stats import truncnorm

# Visualization
import matplotlib.pyplot as plt
import seaborn as sns
import IPython

class Person(ap.Agent):

    def setup(self):
        """ Initialize a new variable at agent creation. """
        self.condition = 0  # Susceptible = 0, Infected = 1, Recovered = 2

    def being_sick(self):
        """ Spread disease to peers in the network. """
        rng = self.model.random
        for n in self.network.graph.predecessors(self):
            if n.condition == 0 and self.p.infection_chance > rng.random():
                n.condition = 1  # Infect susceptible peer
        if self.p.recovery_chance > rng.random():
            self.condition = 2  # Recover from infection

class VirusModel(ap.Model):

    def setup(self):
        """ Initialize the agents and network of the model. """

        # Prepare a scale free network
        graph = nx.scale_free_graph(
            self.p.population)

        # Create agents and network
        self.agents = ap.AgentList(self, self.p.population, Person)
        self.network = self.agents.network = ap.Network(self, graph)
        self.network.add_agents(self.agents, self.network.nodes)

        # Infect a random share of the population
        I0 = int(self.p.initial_infection_share * self.p.population)
        self.agents.random(I0).condition = 1

    def update(self):
        """ Record variables after setup and each step. """

        # Record share of agents with each condition
        for i, c in enumerate(('S', 'I', 'R')):
            n_agents = len(self.agents.select(self.agents.condition == i))
            self[c] = n_agents / self.p.population
            self.record(c)

        # Stop simulation if disease is gone
        if self.I == 0:
            self.stop()

    def step(self):
        """ Define the models' events per simulation step. """

        # Call 'being_sick' for infected agents
        self.agents.select(self.agents.condition == 1).being_sick()

    def end(self):
        """ Record evaluation measures at the end of the simulation. """

        # Record final evaluation measures
        self.report('Total share infected', self.I + self.R)
        self.report('Peak share infected', max(self.log['I']))

parameters = {
    'population': 1000,
    'infection_chance': 0.3,
    'recovery_chance': 0.1,
    'initial_infection_share': 0.1,
    'number_of_neighbors': 20,
    'network_randomness': 0.5
    #'steps':10
}

model = VirusModel(parameters)
results = model.run()

FileExistsError when saving data to existing directory outside current path

I've encountered an issue with the save() method in the DataDict class, where it fails to properly handle saving data to a directory outside the current working directory. The result is FileExistsError because the folder data already exists one level above the program file location. Here is the code that caused the error:

results.save(exp_name='firm_dynamics', path=os.path.join('..','data'))

Looking into the .save() method, I believe the problematic code snippet is as follows:

# Create output directory if it doesn't exist
if path not in os.listdir():
    os.makedirs(path)

This logic checks if the path is in the current directory's listing (os.listdir()), leading to a FileExistsError when attempting to save data to an existing directory located outside the current directory, e.g., path='../'. A potential solution would be to directly check for the existence of the specified path and create it if it does not exist, avoiding the assumption that path should be within the current directory's listing:

if not os.path.exists(path):
    os.makedirs(path)

error when removing agents

Assume we have an agent that removes other agents from the simulation e.g. for simulating predator-prey I think I might have encountered a bug.
When removing an agent from the model/environment in step 1, the method is called on the agent again in the next step which leads to an

AgentpyError
Agent 17 has no environment with topology '['grid', 'space', 'network']'

Here is a minimal example to reproduce the error:

import agentpy as ap

class SomeAgent(ap.Agent):

    def do_things(self):
        for n in self.neighbors():
            print(f"removing: {n}")
            n.delete()
            break

class SomeModel(ap.Model):
    def setup(self, **kwargs):
        self.grid = self.add_grid([self.p.size] * 2)
        self.grid.add_agents(self.p.agent_count, SomeAgent, random=True)

    def step(self):
        self.agents.do_things()


if __name__ == "__main__":
    params ={
        "agent_count": 100,
        "size": 20,
        "steps": 100
    }

    model = SomeModel(params)
    results = model.run()

I also tried to call the remove_agents function on the grid and model, but no luck.

Is this a bug, or am I doing it wrong?

Cheers

Recording Space

I am trying to record the positions of each agent each time step using the record function. When I do so, it just repeatedly records the positions of the Agents in the first time step. In my testing calling self.space.positions.values() each step does give the correct values when printed but not when recorded. For reference I am working on making animations of already completed experiments, if that is useful let me know. See attached file for examples:
agentpy_flocking_positions.zip

add attribution to Grid by ".add_field" method not work as expected.

I'm trying to make an inheritance of class "Grid".

When I try to use the method add_field() to add attr to my Grid, I found that from the 3rd row, it works really strange.
Then, I ran some demo to test:

import agentpy as ap
import numpy as np

model = ap.Model()
shape = (4, 4)
world = ap.Grid(model, shape)
world.add_field("test", 0)
world.test

Out[8]:
array([[ 0, 0, 0, 0],
[ 0, 0, 0, 0],
[999999, 999999, 999999, 999999],
[999999, 999999, 999999, 999999]])

world.add_field("test", np.zeros(shape))

world.test2
Out[11]:
array([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])

world.add_field("test3", False)
world.test3

Out[13]:
array([[False, False, False, False],
[False, False, False, False],
[ True, True, True, True],
[ True, True, True, True]])

world.add_field("test4", True)
world.test4

Out[16]:
array([[ True, True, True, True],
[ True, True, True, True],
[ True, True, True, True],
[ True, True, True, True]])

Error in Google Colaboratory

Hey!
First, thank you for the wonderful project. I was trying out your notebook on segregation in Colab.
The example notebook https://agentpy.readthedocs.io/en/latest/agentpy_segregation.html gives for line

animation = ap.animate(model, fig, ax, animation_plot)

The error

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/var/folders/hy/zyr6jvld6rscmbnqml0fvq1c0000gn/T/ipykernel_45243/1434696550.py in <module>
      7 fig, ax = plt.subplots()
      8 model = SegregationModel(parameters)
----> 9 animation = ap.animate(model, fig, ax, animation_plot)
     10 IPython.display.HTML(animation.to_jshtml())

~/opt/anaconda3/envs/ABM/lib/python3.10/site-packages/agentpy/visualization.py in animate(model, fig, axs, plot, steps, seed, skip, fargs, **kwargs)
     83     save_count = 10000 if model._steps is np.nan else model._steps
     84 
---> 85     ani = matplotlib.animation.FuncAnimation(
     86         fig, update,
     87         frames=frames,

~/opt/anaconda3/envs/ABM/lib/python3.10/site-packages/matplotlib/_api/__init__.py in __getattr__(name)
    220         if name in props:
    221             return props[name].__get__(instance)
--> 222         raise AttributeError(
    223             f"module {cls.__module__!r} has no attribute {name!r}")
    224 

AttributeError: module 'matplotlib' has no attribute 'animation'

The package was installed with

!pip install agentpy

Flocking notebook - Question

Hey,

awesome library!

A question. In your flocking notebook, where the parameters 'wall_avoidance_distance' and 'wall_avoidance_strength' (of the 3D case) are used? I don't think they are actually used.

Animation only goes up to 100 time steps in Boids Model

I was running the default boids model in two dimensions and when I was using the provided animation functions the animation only goes up to time step 100. This happens even if I hardcode steps at say 200 in animation = ap.animate(m(p), fig, ax, animation_plot_single,steps=200) and when I change the steps parameter in the parameters. The animation will render less than 100 steps if I set the parameters to less than 100. When I run the model with model.run() it properly records all of the time steps that I set in the parameters. Is there a parameter I forgot to set to get it all time steps to render in the animation?

JOSS Review (JM)

Submission: openjournals/joss-reviews#3065
Status: Conditional accept

I was very interested to see this new agent-based modelling package and am glad to have had the opportunity to review it. The quality of the work here seems great and, as my comments show below, I was easily able to get this installed and work with the example models. As it is a package for agent-based simulation there are lots of moving parts and I do not have time to go into detail checking every class and function. However, I am quite happy from my use with the example models that everything is working as claimed. Nice work @JoelForamitti

Below I list comment based on the JOSS review checklist. At this point I have not been able to check off all items - see bold comments below for those still outstanding. I think it should be relatively easy to address my comments (most of which are about documentation) and then I can change my status to accept.

Cheers, JM

General checks

All good

Functionality

Installation

Installation via pip install agentpy into new conda env worked fine. I have not tried developer installation.

Functionality

Functionality as tested by running all examples models in the model library shows everything works as expected. I have not tried coding up my own model.

Performance

There are no claims to performance that I can see (so this is checked off the JOSS review checklist)

Documentation

Statement of Need

The 'statement of need' checkbox on the JOSS review checklist seems a little out of place (it refers to 'the paper' and seems to duplicate (to all intents and purposes) the checkbox for 'statement of need' in the Software Paper section. So I have checked this off (but see comments below about Comparison)

Installation instructions

Installation instructions are clear.

Example usage

Example usage is very good, via the excellent Models Library. The example models demonstrate the range of current functionality (as shown in the Overview of the docs).

Functionality documentation

This is not yet checked off in the JOSS review checklist. Please see issues below

The API reference seems complete and is useful. One minor comment is that in the contents of the API reference, I think it might be useful to add (Grid) to the title entry for Discrete spaces (to make the entry Discrete spaces (Grid) and even clearer the link to how this is described in the Overview - see comment about environments below).

Throughout the docs, the word separate is frequently misspelled as seperate (also in the Flocking example model) - it's a minor issue but as you edit documentation in future you might fix this.

Most of my comments are for clarification in the Overview:

The Using Environments section is a little confusing as it states, "There are three different types of environments:" then presents four items in the list following. I think this section could clarify better the relationship of Environment to the other types. For example, you might also highlight here that the Wealth Transfer example model does not use any of Network, Grid, or Space (it just assumes an env with no topology). Also, you might state explicitly here that multiple types of environment can operate simultaneously (I infer this is true from the documentation on Agent.neighbours which states "If an agent has the same neighbors in multiple environments, ..."

The Recording data section: it might be useful in this section to emphasise (even more clearly) that this is about recording the model state for output to file and later analysis. I initially mistakenly thought it referred to what information might be accessed at runtime (e.g. I wonder why agents would not be able to access aggregate level information about the state of the system dynamically, but the model examples show this is clearly possible). Once I understood the intention of agentpy is to be used for experiments with multiple runs the importance of this section became clear (but see my comments below on making that intention more prominent). One way to make this clearer might be to refer to the Output and analysis section and make clear how record() and Model.measure() are related to DataDict.

The comparison with Mesa is very useful, both in the paper and in the documentation. I think you should emphasise this more, to make clear why people might want to use agentpy:

  • in the paper, highlighting that agentpy has been designed for scientific use with experiments from multiple runs would be useful in the Introduction, rather than leaving it to the final paragraph of the paper
  • in the documentation, I suggest you link to the Comparison page from the User Guide page (and emphasise what sorts of modelling purposes you have in mind for agentpy on the User Guide page also)

I wonder if in future you could also provide a comparison to NetLogo. NetLogo is a very useful starting point for people learning agent-based simulation. To attract people from NetLogo to use agentpy a comparison would be useful I think. Building on this, some brief thoughts from someone (myself) coming at this with a background in using NetLogo:

  • make clear your Grid and Space environments are not toroidal (which is the default case in NetLogo)
  • highlight that experiments are akin to NetLogo's behaviour space
  • comment on how patches and patchsets (NetLogo's grid) would be implemented in agentpy

Automated tests

This is not yet checked off in the JOSS review checklist. Please comment

I cannot see any reference currently to automated tests in the documentation. I can see that such tests might be possible given the stochastic nature of ABM. You might recommend users run the Example Models to check their output is generally the same as that in the examples shown on the docs webpages. Please comment

Community guidelines

This is good and I have checked off. However, one addition to the contributions page might be to welcome contributions of (simple) models to the Model Library to expand the examples available?

Software Paper

Summary

This is not yet checked off in the JOSS review checklist.

A summary is provided by the Overview section of the paper and provides a clear description. However, I think you should make clearer in the Introduction that agentpy has been designed for scientific use with experiments from multiple runs. Currently this only becomes clear in the final paragraph of the paper.

Statement of Need

This is not yet checked off in the JOSS review checklist.

I have commented on this in the JOSS review thread:

Although you do include related information elsewhere in the paper, there does not seem to be "a section titled 'Statement of Need' that clearly states what problems the software is designed to solve and who the target audience is". @whedon also discovered this (on 26 Feb). I think the section is required for the journal.

@JoelForamitti has responded and currently we are currently waiting for response to check if this is explicitly needed.

State of the Field

This is not yet checked off in the JOSS review checklist.

The comparison to other packages is present and useful. However, while the Abar et al. (2017) paper is good, it is not open access. Could you either:

  • add an open-access equivalent review paper, or
  • add links to webpages for the frameworks mentioned (NetLogo, Repast, MASON)

Quality of Writing

This is good.

References

This seems fine

GPU Support

Hi @JoelForamitti, do you plan to make agentpy running on GPU?

[JOSS review] Manuscript corrections

Statement of need

AFAIK, this section must be explicit in the manuscript. I suppose that such a section would include the sentence of lines 13-14. I would further suggest to make it a "self-contained" sentence (that does not require reading any other part of the manuscript to fully understand it), hence I would add:

The aim of agentpy is to provide an intuitive syntax for the creation of **agent-based** models together with
advanced tools for scientific applications.

Figure and code snippets

  • Figure 1: it may be better to use a code snippet rather than a figure to display code, e.g., users might want to copy-paste them
  • lines 27-30: it is better that the text refers to some code snippet in the manuscript (e.g., Figure 1). For instance: from the current manuscript, one may ask: what is agents? I had to open a notebook, instantiate some example agentpy.Model, inspect the class via dir and it is only then that I found the agents attribute

Clarify some concepts and definitions

  • line 30: what is the "record" action? I needed to go to the docstring of the record method to fully understand what it means. It may be a good idea to add a brief sentence to clarify it within the manuscript so that the reader can get a clearer picture there.
  • line 45: "direct integration of analysis tools within the same framework" as somebody familiar with scientific Python, I suppose that you mean NumPy, pandas, NetworkX and the like, but it may be better to make it more explicit.

Other

  • line 29: IMHO "attribute" seems more Pythonic than "variable"
  • links: it might be better to put URLs explicitly (e.g., although unlikely in JOSS, people might print the paper). Line 18 is fine since we can easily find the documentation without clicking the link, but not so much for line 46, where I believe that the word "here" should be replaced by the actual URL.

[JOSS Review] Scenario comparison example

The docstring of the scenarios argument in Experiment does not give enough information, I have to go to the code to understand how it works. Additionally, I would highly recommend including the "scenario comparison" functionality in one of the example notebooks.

KDTree not refreshed after remove_agents() called

I think I may have found a bug in space.py

In my model, I have many agents, potentially removing each other on the same timestep.
I'm also trying to directly use the KDTree's query() function to find the nearest neighbor, since this is not yet a feature. (hope I can be able to implement this functionality soon)

What I've realised is that although I have removed agents in a given step, the KDTree still contains the agents' locations. This manifests as an IndexError when I try to run my nearest neighbor lookup - the agent is in the tree, but already removed from env._sorted_agents.

     49         dist, nb_idx = self.env.KDTree.query(self.position(), k=2)
     50         nb_idx = nb_idx[1]
---> 51         self.target = self.env._sorted_agents[nb_idx]
IndexError: list index out of range

I think a similar error would be caused calling space.neighbors() when an agent in range was removed beforehand in the same timestep.

I looked into space.py and noticed the line

        self._cKDTree = None  # Reset KDTree

which is present in move_agents(), is not present in remove_agents(), nor in add_agents().

I understand redrawing the whole KDTree is costly so it wouldn't be practical to do so upon each of these function calls. I even checked scipy.spacial.cKDTree and I believe I have found it does not implement inserting nor removing nodes, which is what we would ideally use, am I right?

I wish I could propose a workaround, but have not been able to think of an alternative. Just wanted to document this issue and confirm if I am understanding the implementation at present.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.