diff --git a/.gitignore b/.gitignore index fe1ef1eb62f..e82b6c6b6d9 100644 --- a/.gitignore +++ b/.gitignore @@ -56,4 +56,8 @@ docs/_build/ # PyBuilder target/ +# Jupyter and iPython notebook checkpoints *.ipynb_checkpoints + +# Spyder app workspace config file +.spyderworkspace diff --git a/examples/ColorPatches/Readme.md b/examples/ColorPatches/Readme.md new file mode 100644 index 00000000000..b63725e8c44 --- /dev/null +++ b/examples/ColorPatches/Readme.md @@ -0,0 +1,33 @@ +## Color Patches: +Is a cellulat automaton model where each agent lives in a cell on a 2D grid, and never moves.
+An agent's state represents its "opinion" and is shown by the color of the cell the agent lives in. Each color represents an opinion - there are 16 of them.
+At each time step, an agent's opinion is influenced by that of its neighbors, and changes to the most common one found; ties are randomly arbitrated.
+As an agent adapts its thinking to that of its neighbors, the cell color changes. + + +### Parameters you can play with: +(you must change the code to alter the parameters at this stage) +* Vary the number of opinions. +* Vary the size of the grid +* Change the grid from fixed borders to a torus continuum + + +### Observe +* how groups of like minded agents form and evolve +* how sometimes a single opinion prevails +* how some minority or fragmented opinions rapidly disappear + + +### Sources and Attribution +Inspired from [this model](http://www.cs.sjsu.edu/~pearce/modules/lectures/abs/as/ca.htm) from San Jose University
+Other similar models: [Schelling Segregation Model](https://github.com/projectmesa/mesa/tree/master/examples/Schelling) + + +### To run this example + +* Launch the model +```python +python color_patches.py +``` +* Visit your browser: http://127.0.0.1:8888/ +* In your browser hit *reset*, then *run* diff --git a/examples/ColorPatches/color_cell.py b/examples/ColorPatches/color_cell.py new file mode 100644 index 00000000000..e3b86789f09 --- /dev/null +++ b/examples/ColorPatches/color_cell.py @@ -0,0 +1,67 @@ +""" +Subclassing Agent to represent a cell +""" + + +from collections import Counter +import random + +from mesa import Agent + + + +class ColorCell(Agent): + ''' + Represents a cell's opinion (visualized by a color) + ''' + + OPINIONS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] + + + def __init__(self, pos, model, initial_state): + ''' + Create a cell, in the given state, at the given row, col position. + ''' + Agent.__init__(self, pos, model) + self._row = pos[1] + self._col = pos[0] + self._state = initial_state + self._next_state = None + + def get_col(self): + '''Return the col location of this cell.''' + return self._col + + def get_row(self): + '''Return the row location of this cell.''' + return self._row + + def get_state(self): + '''Return the current state (OPINION) of this cell.''' + return self._state + + def step(self, model): + ''' + Determines the agent opinion for the next step by polling its neighbors + The opinion is determined by the majority of the 8 neighbors' opinion + A choice is made at random in case of a tie + The next state is stored until all cells have been polled + ''' + neighbors_opinion = Counter(n.get_state() \ + for n in model.grid.neighbor_iter((self._col, self._row), True)) + polled_opinions = neighbors_opinion.most_common() #a tuple (attribute, occurrences) + tied_opinions = [] + for neighbor in polled_opinions: + if neighbor[1] == polled_opinions[0][1]: + tied_opinions.append(neighbor) + + self._next_state = random.choice(tied_opinions)[0] + + + # model argument is unused + def advance(self, model): + ''' + Set the state of the agent to the next state + ''' + self._state = self._next_state + diff --git a/examples/ColorPatches/color_patch_model.py b/examples/ColorPatches/color_patch_model.py new file mode 100644 index 00000000000..921c973f8af --- /dev/null +++ b/examples/ColorPatches/color_patch_model.py @@ -0,0 +1,80 @@ +""" +The model - a 2D lattice where agents live and have an opinion +""" + + +import random + +from mesa import Model +from mesa.time import SimultaneousActivation +from mesa.space import Grid +from color_cell import ColorCell + + + +class ColorPatchModel(Model): + ''' + represents a 2D lattice where agents live + ''' + + def __init__(self, height, width): + ''' + Create a 2D lattice with strict borders where agents live + The agents next state is first determined before updating the grid + ''' + + self._grid = Grid(height, width, torus=False) + self._schedule = SimultaneousActivation(self) + + # self._grid.coord_iter() + # --> should really not return content + col + row + # -->but only col & row + # for (contents, col, row) in self._grid.coord_iter(): + # replaced content with _ to appease linter + for (_, col, row) in self._grid.coord_iter(): + cell = ColorCell((col, row), self, ColorCell.OPINIONS[random.randrange(0, 16)]) + self._grid.place_agent(cell, (col, row)) + self._schedule.add(cell) + + self.running = True + + def step(self): + ''' + Advance the model one step. + ''' + self._schedule.step() + + + + # the following is a temporary fix for the framework classes accessing model + # attributes directly + # I don't think it should + # --> it imposes upon the model builder to use the attributes names that + # the framework expects. + # + # Traceback included in docstrings + + @property + def grid(self): + """ + /mesa/visualization/modules/CanvasGridVisualization.py + is directly accessing Model.grid + 76 def render(self, model): + 77 grid_state = defaultdict(list) + ---> 78 for y in range(model.grid.height): + 79 for x in range(model.grid.width): + 80 cell_objects = model.grid.get_cell_list_contents([(x, y)]) + + AttributeError: 'ColorPatchModel' object has no attribute 'grid' + """ + return self._grid + + @property + def schedule(self): + """ + mesa_ABM/examples_ABM/color_patches/mesa/visualization/ModularVisualization.py", + line 278, in run_model + while self.model.schedule.steps < self.max_steps and self.model.running: + AttributeError: 'NoneType' object has no attribute 'steps' + """ + return self._schedule diff --git a/examples/ColorPatches/color_patches.py b/examples/ColorPatches/color_patches.py new file mode 100644 index 00000000000..02713e19088 --- /dev/null +++ b/examples/ColorPatches/color_patches.py @@ -0,0 +1,50 @@ +""" +handles the definition of the canvas parameters and +the drawing of the model representation on the canvas +""" + + +from color_patch_model import ColorPatchModel +from mesa.visualization.modules import CanvasGrid +from mesa.visualization.ModularVisualization import ModularServer + + +_COLORS = ['Aqua', 'Blue', 'Fuchsia', 'Gray', 'Green', + 'Lime', 'Maroon', 'Navy', 'Olive', 'Orange', 'Purple', + 'Red', 'Silver', 'Teal', 'White', 'Yellow'] + + +GRID_ROWS = 25 +GRID_COLS = 50 +CELL_SIZE = 10 +CANVAS_HEIGHT = GRID_ROWS * CELL_SIZE +CANVAS_WIDTH = GRID_COLS * CELL_SIZE + + +def color_patch_draw(cell): + ''' + This function is registered with the visualization server to be called + each tick to indicate how to draw the cell in its current state. + + :param cell: the cell in the simulation + + :return: the portrayal dictionary. + + ''' + assert cell is not None + portrayal = {"Shape": "rect", "w": 1, "h": 1, "Filled": "true", "Layer": 0} + portrayal["x"] = cell.get_col() + portrayal["y"] = cell.get_row() + portrayal["Color"] = _COLORS[cell.get_state()] + return portrayal + + +CANVAS_ELEMENT = CanvasGrid(color_patch_draw, + GRID_COLS, GRID_ROWS, + CANVAS_HEIGHT, CANVAS_WIDTH) + +SERVER = ModularServer(ColorPatchModel, + [CANVAS_ELEMENT], "Color Patches", + GRID_ROWS, GRID_COLS) + +SERVER.launch() diff --git a/examples/Readme.md b/examples/Readme.md index 0b46a9962c6..04719f670a3 100644 --- a/examples/Readme.md +++ b/examples/Readme.md @@ -2,6 +2,9 @@ This directory contains example models meant to test and demonstrate Mesa's features, and provide demonstrations for how to build and analyze agent-based models. For more information on each model, see its own Readme and documentation. +### Color Patches +A cellular automaton model where agents opinions are influenced by that of their neighbors. As the model evolves, color patches representing the prevailing opinion in a given area expand, contract, and sometimes disappear. + ### Conway's Game Of Life An implementation of the Famous Pr. Conway's Game Of Life