Visualization Tutorial#

Important:

  • If you are just exploring Mesa and want the fastest way to execute the code we recommend executing this tutorial online in a Colab notebook. Colab

  • If you have installed mesa and are running locally, please ensure that your Mesa version is up-to-date in order to run this tutorial.

Adding visualization#

So far, we’ve built a model, run it, and analyzed some output afterwards. However, one of the advantages of agent-based models is that we can often watch them run step by step, potentially spotting unexpected patterns, behaviors or bugs, or developing new intuitions, hypotheses, or insights. Other times, watching a model run can explain it to an unfamiliar audience better than static explanations. Like many ABM frameworks, Mesa allows you to create an interactive visualization of the model. In this section we’ll walk through creating a visualization using built-in components, and (for advanced users) how to create a new visualization element.

First, a quick explanation of how Mesa’s interactive visualization works. The visualization is done in a browser window, using the Solara framework, a pure Python, React-style web framework. Running solara run app.py will launch a web server, which runs the model, and displays model detail at each step via the Matplotlib plotting library. Alternatively, you can execute everything inside a Jupyter environment.

Grid Visualization#

To start with, let’s have a visualization where we can watch the agents moving around the grid. Let us use the same MoneyModel created in the Introductory Tutorial.

%pip install --quiet mesa
import mesa

# You can either define the BoltzmannWealthModel (aka MoneyModel) or install mesa-models:
%pip install --quiet -U git+https://github.com/projectmesa/mesa-examples#egg=mesa-models

from mesa_models.boltzmann_wealth_model.model import BoltzmannWealthModel
Note: you may need to restart the kernel to use updated packages.
Note: you may need to restart the kernel to use updated packages.

Mesa’s grid visualizer works by looping over every cell in a grid, and generating a portrayal for every agent it finds. A portrayal is a dictionary (which can easily be turned into a JSON object) which tells Matplotlib the color and size of the scatterplot markers (each signifying an agent). The only thing we need to provide is a function which takes an agent, and returns a portrayal dictionary. Here’s the simplest one: it’ll draw each agent as a blue, filled circle, with a radius size of 50.

def agent_portrayal(agent):
    return {
        "color": "tab:blue",
        "size": 50,
    }

In addition to the portrayal method, we instantiate the model parameters, some of which are modifiable by user inputs. In this case, the number of agents, N, is specified as a slider of integers.

model_params = {
    "N": {
        "type": "SliderInt",
        "value": 50,
        "label": "Number of agents:",
        "min": 10,
        "max": 100,
        "step": 1,
    },
    "width": 10,
    "height": 10,
}

Next, we instantiate the visualization object which (by default) displays the grid containing the agents, and timeseries of of values computed by the model’s data collector. In this example, we specify the Gini coefficient.

There are 3 buttons:

  • the step button, which advances the model by 1 step

  • the play button, which advances the model indefinitely until it is paused, or until model.running is False (you may specify the stopping condition)

  • the pause button, which pauses the model

To reset the model, simply change the model parameter from the user input (e.g. the “Number of agents” slider).

from mesa.experimental import JupyterViz

page = JupyterViz(
    BoltzmannWealthModel,
    model_params,
    measures=["Gini"],
    name="Money Model",
    agent_portrayal=agent_portrayal,
)
# This is required to render the visualization in the Jupyter notebook
page
/home/docs/checkouts/readthedocs.org/user_builds/mesa/envs/stable/lib/python3.12/site-packages/mesa/time.py:82: FutureWarning: The AgentSet is experimental. It may be changed or removed in any and all future releases, including patch releases.
We would love to hear what you think about this new feature. If you have any thoughts, share them with us here: https://github.com/projectmesa/mesa/discussions/1919
  self._agents: AgentSet = AgentSet(agents, model)

Changing the agents#

In the visualization above, all we could see is the agents moving around – but not how much money they had, or anything else of interest. Let’s change it so that agents who are broke (wealth 0) are drawn in red, smaller. (TODO: currently, we can’t predict the drawing order of the circles, so a broke agent may be overshadowed by a wealthy agent. We should fix this by doing a hollow circle instead)

To do this, we go back to our agent_portrayal code and add some code to change the portrayal based on the agent properties and launch the server again.

def agent_portrayal(agent):
    size = 10
    color = "tab:red"
    if agent.wealth > 0:
        size = 50
        color = "tab:blue"
    return {"size": size, "color": color}
page = JupyterViz(
    BoltzmannWealthModel,
    model_params,
    measures=["Gini"],
    name="Money Model",
    agent_portrayal=agent_portrayal,
)
# This is required to render the visualization in the Jupyter notebook
page

Building your own visualization component#

Note: This section is for users who have a basic familiarity with Python’s Matplotlib plotting library.

If the visualization elements provided by Mesa aren’t enough for you, you can build your own and plug them into the model server.

For this example, let’s build a simple histogram visualization, which can count the number of agents with each value of wealth.

import solara
from matplotlib.figure import Figure


def make_histogram(model):
    # Note: you must initialize a figure using this method instead of
    # plt.figure(), for thread safety purpose
    fig = Figure()
    ax = fig.subplots()
    wealth_vals = [agent.wealth for agent in model.schedule.agents]
    # Note: you have to use Matplotlib's OOP API instead of plt.hist
    # because plt.hist is not thread-safe.
    ax.hist(wealth_vals, bins=10)
    solara.FigureMatplotlib(fig)

Next, we reinitialize the visualization object, but this time with the histogram (see the measures argument).

page = JupyterViz(
    BoltzmannWealthModel,
    model_params,
    measures=["Gini", make_histogram],
    name="Money Model",
    agent_portrayal=agent_portrayal,
)
# This is required to render the visualization in the Jupyter notebook
page

Happy Modeling!#

This document is a work in progress. If you see any errors, exclusions or have any problems please contact us.