Plotting agents in a domain#

Summary

On this page, you will see how to

  • use .plot.abm to plot snapshots and animations of agents in a domain

  • plot data variables onto the agent marker size, orientation, and color

  • add fading trails to the agents moving around the domain

  • adjust the plot for periodic boundary conditions

  • adjust the plot domain

Agent-based models (ABMs) are a common type of model to simulate and analyze the behaviour of individual agents moving around in space, interacting with each other, and adapting their behaviour or even learning in the process. Utopia uses utopya’s .plot.abm plot (implemented in utopya as abmplot()) to visualize the behavior of such agents. We will use the SimpleFlocking ABM to illustrate its functionality.

See also

The implementation of this plot is in utopya.eval, which is where you can find details about the available arguments and their behavior:

Animated agents in a domain#

Below is an example animation of flocking dynamics in a square domain with periodic boundary conditions:

The agents’ color represents their orientation angle, and the fading trails their trajectory over a number of past steps. Such animations can be easily generated using the .plot.abm base plot.

The plot requires a single xarray.Dataset or an xarray.DataArray to be passed containing all the plotting data. Base your plot on the universe creator (.creator.universe), .plot.abm, as well as an animation base configuration (see the animations page for more details on these, including on adjusting the animation resolution):

agents_in_domain:
  based_on:
    - .creator.universe
    - .plot.abm
    - .animations.ffmpeg
  select:
    agents: path/to/agent/data

Next, specify what to plot, and where to plot the variables:

agents_in_domain:

  # Everything from above ...

  to_plot:
    agents:
      marker: wedge

  x: x
  y: y
  frames: time
  orientation: orientation
  hue: orientation

This plots the variables onto the corresponding dimensions. The to_plot argument is required; it can also contain information on the agent markers, colors, and size scales – see below. Naturally, this requires the data we selected to contain variables called x, y, time, and orientation (which can be mapped to other variables using the corresponding keyword arguments).

Hint

Arguments on the top-level of the plot config are used as defaults for all entries within to_plot. If the individual to_plot entries have different encodings, you can also specify those arguments there:

agents_in_domain:
  # ...
  to_plot:
    agents:
      # custom parameters for this layer
      x: y
      y: x

If you have saved these datasets separately, use the transformation DAG to combine them into a single xarray.Dataset:

agents_in_domain:
  based_on:
    # As before ...

  select:
    x:
      path: path/to/x/coordinates
      transform: [.data] # Transform into a xr.DataArray
    y:
      path: path/to/y/coordinates
      transform: [.data]
    # analogously for other variables ...

  # Combine data into one dataset
  transform:
    - xr.Dataset:
      - x: !dag_tag x
        y: !dag_tag y
        # other variables ...
      tag: agents

  to_plot:
    agents:
      marker: wedge

Hint

You can turn off the time stamp by setting

suptitle_fstr: False

Plotting frames and snapshots#

You can of course choose specific time steps to use for the animation. To do this, pass the frames_isel keyword:

agents_in_domain:

  # Everything else as above ...

  frames_isel: !range [10]

This will plot the first ten time steps. Alternatively, you can pass a list of frames. If you base the plot on animation.frames and do not pass frames_isel, all frames will be plotted as individual images.

You can also plot snapshots instead of an animation. To do this, add the .plot.abm.snapshot base configuration; then, select the time frames to plot with frames_isel:

agents_in_domain:
  based_on:
    - .creator.universe
    - .plot.abm
    - .plot.abm.snapshot

  # Snapshot of the final state (default)
  frames_isel: -1

Agent hue, orientation, size, and markers#

As we saw above, the orientation and hue of the agents can be used to visualize data variables. You can then specify a colormap using the ColorManager:

agents_in_domain:

  # Everything as above

  cmap:
    continuous: true
    from_values:
      0.0: darkgreen
      0.333: yellow
      0.666: brickred
      1.0: darkgreen

Colors can also be specified e.g. as hex or rgb values. You can also simply pass the name of a colormap, use a norm, and include limits: take a look at the style section for more details.

Additionally, you can plot data dimensions onto the agent size. The size scale and marker style of the agents is determined via the size_scale key in the to_plot entry, which roughly corresponds to the area of the marker in relation to the whole domain:

agents_in_domain:

  # Everything as above ...

  size: some_dimension

  to_plot:
    agents:
      size_scale: 0.0002
      marker: fish2

The marker argument can be any one of wedge, fish (a basic fish shape), and fish2 (a more complex fish shape); see MARKERS for more information and other available marker paths:

ABM plot with fish

Hint

See AgentCollection for more possibilities on how to set up the marker.

Adding trails#

Trails can be useful to visualize the trajectories of the agents, especially in flocking or chemotaxis models. You can control the length of the tail with the tail_length entry. The aesthetics of the tail are controlled via the tail_kwargs dict:

agents_in_domain:

  tail_length: 12
  tail_kwargs:
    color: black
    linewidth: 0.5
    alpha: .6
    zorder: -10

This sets the tail_length to 12 frames of the animation.

The alpha value is applied uniformly along the length of the tail. To get a fading effect, add the following key:

agents_in_domain:

  tail_decay: 0.12

This will set the alpha value of each tail segment to 1 - tail_decay times the alpha value of the previous segment, giving an exponential fade.

Periodic boundary conditions#

The tail_max_segment_length parameter is useful if you plan on drawing tails of agents that move in a periodic space. In such a case, agent positions may jump aprubtly when crossing a boundary. Ordinarily, this would lead to the tail segment going across the whole domain.

To avoid this, set the tail_max_segment_length parameter to half the domain size; this typically suffices to detect jumps in x- or y- position and leads to these segments not being drawn. (To be precise, the length refers not to that of the segment but to the differences in x- and/or y-position.)

Adjusting the plot domain#

Instead of using the PlotHelper to adjust the x- and y-extent, we recommend using the domain/extent key; this way, marker size will be kept constant. This key also allows setting the padding to the border of the domain, the height, and the aspect of the domain:

agents_in_domain:
  domain:
    extent: [0, 4, 1, 10]
    pad: 0.5
    height: 3  # height in data units
    aspect: 2  # can also be 'auto' if height is not given

The extent entry should be a tuple of the form (left, right, bottom, top). Alternatively, a 2-tuple will be interpreted as (0, right, 0, top).

Finally, you can also add a mode key to the domain dictionary to control automatic deduction of boundaries. The domain mode can be auto, manual, fixed, and follow. In fixed mode, all available data is inspected to derive domain bounds. In follow mode, boundaries are adjusted from frame to frame. In auto mode, will use a fixed domain if no extent was given, otherwise manual mode is used.