Add a common interface to all spaces for getting agents
Closed this issue · 7 comments
What's the problem this feature will solve?
Depending on the type of space, how you have to get the agents in the space differs. This is shown below with pseudo code and represents my current best guess. This makes the plotting of spaces much more complicated than it needs to be because it requires you to write custom agent getters for at least 4 cases.
old_style_grids = _Grid() # and thus all its subclasses
coordinates = [(x,y) for x in range(self.height)] for y in range(self.width)]
agents = list(old_style_grids.iter_cell_list_contents(coordinates))
cont_space = ContinuousSpace()
agents = [entry for entry in cont_space._agent_to_index]
old_style_network = NetworkGrid()
agents = list(old_style_network.iter_cell_list_contents(old_style_network.nodes)) # my best guess ATM, I might be wrong
new_style_spaces = DiscreteGrid() # and thus all its subclasses
agents =list(new_style_spaces.all_cells.agents)
Describe the solution you'd like
I propose to add an agents
property to all spaces (new and old) that returns an iterator over the agents in the space. This would enable cleaning up the matplotlib and altair code for plotting spaces quite a bit. Implementing this would be a stepping stone in in addressing #2401.
Do you want only the agents, or also an identifier/coordinate in this iterator in a tuple or dict form? In the former case I’m curious how this would differ from model.agents in most cases, and in the latter, we should think a bit about its structure.
Do you want only the agents, or also an identifier/coordinate in this iterator in a tuple or dict form? In the former case I’m curious how this would differ from model.agents in most cases, and in the latter, we should think a bit about its structure.
I thought about having an iterator that would return (x, y), Agent
and could be convinced that doing so is better. I initially decided against it because agents in networks don't have x,y, coordinates but a node_id (true for both old style and new style networks), and you don't necessarily use this just for visualization.
I deliberately did not want to go the model.agents
route because it would hard code that models can only have a single space. I, however, want to keep open the possibility of building this type of model in MESA (which I did in 2020 when first learning MESA).
What about returning an iterator with (something, agent)
tuples? Then something can be space specific, a coordinate where applicable but a node id for Network etc. If you only use the agents, you can just do _, agent
.
I agree multiple grid support should be designed for.
You know what, I’m pivoting on this. .agents
return should be consistent in Mesa, so I would suggest it only returning the agents, but in an AgentSet, just like model.agents
.
If we want to add something with coordinates/identifiers we can always do that separately.
I am still not convinced. At a minimum, it would imply a weird mismatch between the name of the property agents
and what is returned. Moreover, I can see this agent property being broadly useful, so why design it for the specific use case of getting the coordinates and the agent as used in the solara plotting context? With this property in place, you can do
# if you need the coordinates
for agent in space.agents:
match agent:
case CellAgent():
pos = agent.cell.coordinate
case _:
pos = agent.pos
# some other purpose
agents = AgentSet(space.agents, random=self.random)
and move on depending on what you are trying to achieve.
.agent_locations
could return a dict, Agent: location
.location_agents
could return a dict, location: [agent, agent, …]
in both location can be space specific, either a coordinate or a identifier.
You know what, I’m pivoting on this. .agents return should be consistent in Mesa, so I would suggest it only returning the agents, but in an AgentSet, just like model.agents.
Fair point. I'll give that a go. I was hesitant about this in the first place because of performance concerns based on some tests I have done on Cell.agents
, but that won't really apply here.
.agent_locations could return a dict, Agent: location
.location_agents could return a dict, location: [agent, agent, …]in both location can be space specific, either a coordinate or a identifier.
I like the general idea of this but I want to hold of on that for now. In preperation for 3.1, I would like to refactor ContinuousSpace and add the agent movement as mixins analous to how its done with FixedAgent
and CellAgent
. That would be a good moment to look at some kind of Locatable mixin that would return e.g., x
, y
, position
. An idea like this could be build on that. Or with space.agents
returning an agentset, you can simply do space.agents.get(['x', 'y'])
.