A RePast Tutorial by John T. Murphy, University of Arizona & Arizona State University (contact)

Adding a Histogram

Adding a histogram is very much like adding a chart. The main difference is that instead of specifying a simple sequence of data, the histogram must use a different kind of source of data; it must use an object that implements the BinDataSource interface.

The BinDataSource interface demands that the object implementing it have a function called getBinValue, which takes an object as an argument. The OpenHistogram object is assigned a list of objects that it iterates through when and update is required; the BinDataSource object specifies a method that is called for each object; this method can vary, but the fastest implementation is to use the built-in getBinValue method. The value that is returned is the thing that forms the criteria on which the instances in the list are counted.

In our example, we will want a histogram that counts agents falling in particular wealth categories. When the histogram is created we specify (in addition to a title for the graph) the list to be used as the agent list, and the number of 'bins' we want our agents sorted into. We also specify a lower boundary (we use zero). RePast iterates through the list, finds the maximum value in the list, evenly distributes the range between the lower boundary and the maximum into the number of bins specified, and then counts the number of agents falling into each bin.

Another difference is that Histograms do not have to be registered with the model. Also, Histograms don't make use of sequences, so they do not have to have a sequence added; in lieu of this the 'CreateHistogramItem' method is used.

The things that must be done to add a histogram are:

  1. Create the variable to store the histogram instance
  2. Create the class extending 'BinDataSource' to provide the data for the histogram
  3. Tear down the histogram, if it exists, in the 'setup' function
  4. Create the histogram in the 'setup' function
  5. Schedule the updates to the histogram object, in the 'buildSchedule' method
  6. Add the histogram item to the histogram, using the bin data source, in the 'buildDisplay' method
  7. Display the histogram in the 'begin' method

The code to achieve this is:

CarryDropModel

// CarryDropModel
package demo;

import java.awt.Color;
import java.util.ArrayList;

import uchicago.src.sim.analysis.BinDataSource;
import uchicago.src.sim.analysis.DataSource;
import uchicago.src.sim.analysis.OpenHistogram;
import uchicago.src.sim.analysis.OpenSequenceGraph;
import uchicago.src.sim.analysis.Sequence;
import uchicago.src.sim.engine.BasicAction;
import uchicago.src.sim.engine.Schedule;
import uchicago.src.sim.engine.SimInit;
import uchicago.src.sim.engine.SimModelImpl;
import uchicago.src.sim.gui.DisplaySurface;
import uchicago.src.sim.gui.ColorMap;
import uchicago.src.sim.gui.Object2DDisplay;
import uchicago.src.sim.gui.Value2DDisplay;
import uchicago.src.sim.util.SimUtilities;

public class CarryDropModel extends SimModelImpl {
  // Default Values
  private static final int NUMAGENTS = 100;
  private static final int WORLDXSIZE = 40;
  private static final int WORLDYSIZE = 40;
  private static final int TOTALMONEY = 1000;
  private static final int AGENT_MIN_LIFESPAN = 30;
  private static final int AGENT_MAX_LIFESPAN = 50;

  private int numAgents = NUMAGENTS;
  private int worldXSize = WORLDXSIZE;
  private int worldYSize = WORLDYSIZE;
  private int money = TOTALMONEY;
  private int agentMinLifespan = AGENT_MIN_LIFESPAN;
  private int agentMaxLifespan = AGENT_MAX_LIFESPAN;

  private Schedule schedule;

  private CarryDropSpace cdSpace;

  private ArrayList agentList;

  private DisplaySurface displaySurf;

  private OpenSequenceGraph amountOfMoneyInSpace;
  private OpenHistogram agentWealthDistribution;

  class moneyInSpace implements DataSource, Sequence {

    public Object execute() {
      return new Double(getSValue());
    }

    public double getSValue() {
      return (double)cdSpace.getTotalMoney();
    }
  }

  class agentMoney implements BinDataSource{
    public double getBinValue(Object o) {
      CarryDropAgent cda = (CarryDropAgent)o;
      return (double)cda.getMoney();
    }
  }

  public String getName(){
    return "Carry And Drop";
  }

  public void setup(){
    System.out.println("Running setup");
    cdSpace = null;
    agentList = new ArrayList();
    schedule = new Schedule(1);

    // Tear down Displays
    if (displaySurf != null){
      displaySurf.dispose();
    }
    displaySurf = null;

    if (amountOfMoneyInSpace != null){
      amountOfMoneyInSpace.dispose();
    }
    amountOfMoneyInSpace = null;

    if (agentWealthDistribution != null){
      agentWealthDistribution.dispose();
    }
    agentWealthDistribution = null;


    // Create Displays
    displaySurf = new DisplaySurface(this, "Carry Drop Model Window 1");
    amountOfMoneyInSpace = new OpenSequenceGraph("Amount Of Money In Space",this);
    agentWealthDistribution = new OpenHistogram("Agent Wealth", 8, 0);

    // Register Displays
    registerDisplaySurface("Carry Drop Model Window 1", displaySurf);
    this.registerMediaProducer("Plot", amountOfMoneyInSpace);
  }

  public void begin(){
    buildModel();
    buildSchedule();
    buildDisplay();

    displaySurf.display();
    amountOfMoneyInSpace.display();
    agentWealthDistribution.display();
  }

  public void buildModel(){
    System.out.println("Running BuildModel");
    cdSpace = new CarryDropSpace(worldXSize, worldYSize);
    cdSpace.spreadMoney(money);

    for(int i = 0; i < numAgents; i++){
      addNewAgent();
    }
    for(int i = 0; i < agentList.size(); i++){
      CarryDropAgent cda = (CarryDropAgent)agentList.get(i);
      cda.report();
    }
  }

  public void buildSchedule(){
    System.out.println("Running BuildSchedule");

    class CarryDropStep extends BasicAction {
      public void execute() {
        SimUtilities.shuffle(agentList);
        for(int i =0; i < agentList.size(); i++){
          CarryDropAgent cda = (CarryDropAgent)agentList.get(i);
          cda.step();
        }

        int deadAgents = reapDeadAgents();
        for(int i =0; i < deadAgents; i++){
          addNewAgent();
        }

        displaySurf.updateDisplay();
      }
    }

    schedule.scheduleActionBeginning(0, new CarryDropStep());

    class CarryDropCountLiving extends BasicAction {
      public void execute(){
        countLivingAgents();
      }
    }

    schedule.scheduleActionAtInterval(10, new CarryDropCountLiving());

    class CarryDropUpdateMoneyInSpace extends BasicAction {
      public void execute(){
        amountOfMoneyInSpace.step();
      }
    }

    schedule.scheduleActionAtInterval(10, new CarryDropUpdateMoneyInSpace());

    class CarryDropUpdateAgentWealth extends BasicAction {
      public void execute(){
        agentWealthDistribution.step();
      }
    }

    schedule.scheduleActionAtInterval(10, new CarryDropUpdateAgentWealth());

  }

  public void buildDisplay(){
    System.out.println("Running BuildDisplay");

    ColorMap map = new ColorMap();

    for(int i = 1; i<16; i++){
      map.mapColor(i, new Color((int)(i * 8 + 127), 0, 0));
    }
    map.mapColor(0, Color.white);

    Value2DDisplay displayMoney =
        new Value2DDisplay(cdSpace.getCurrentMoneySpace(), map);

    Object2DDisplay displayAgents = new Object2DDisplay(cdSpace.getCurrentAgentSpace());
    displayAgents.setObjectList(agentList);

    displaySurf.addDisplayableProbeable(displayMoney, "Money");
    displaySurf.addDisplayableProbeable(displayAgents, "Agents");

    amountOfMoneyInSpace.addSequence("Money In Space", new moneyInSpace());
    agentWealthDistribution.createHistogramItem("Agent Wealth",agentList,new agentMoney());

  }

  private void addNewAgent(){
    CarryDropAgent a = new CarryDropAgent(agentMinLifespan, agentMaxLifespan);
    agentList.add(a);
    cdSpace.addAgent(a);
  }

  private int reapDeadAgents(){
    int count = 0;
    for(int i = (agentList.size() - 1); i >= 0 ; i--){
      CarryDropAgent cda = (CarryDropAgent)agentList.get(i);
      if(cda.getStepsToLive() < 1){
        cdSpace.removeAgentAt(cda.getX(), cda.getY());
        cdSpace.spreadMoney(cda.getMoney());
        agentList.remove(i);
        count++;
      }
    }
    return count;
  }

  private int countLivingAgents(){
    int livingAgents = 0;
    for(int i = 0; i < agentList.size(); i++){
      CarryDropAgent cda = (CarryDropAgent)agentList.get(i);
      if(cda.getStepsToLive() > 0) livingAgents++;
    }
    System.out.println("Number of living agents is: " + livingAgents);

    return livingAgents;
  }

  public Schedule getSchedule(){
    return schedule;
  }

  public String[] getInitParam(){
    String[] initParams = { "NumAgents", "WorldXSize", "WorldYSize", "Money", "AgentMinLifespan", "AgentMaxLifespan"};
    return initParams;
  }

  public int getNumAgents(){
    return numAgents;
  }

  public void setNumAgents(int na){
    numAgents = na;
  }

  public int getWorldXSize(){
    return worldXSize;
  }

  public void setWorldXSize(int wxs){
    worldXSize = wxs;
  }

  public int getWorldYSize(){
    return worldYSize;
  }

  public void setWorldYSize(int wys){
    worldYSize = wys;
  }

  public int getMoney() {
    return money;
  }

  public void setMoney(int i) {
    money = i;
  }

  public int getAgentMaxLifespan() {
    return agentMaxLifespan;
  }

  public int getAgentMinLifespan() {
    return agentMinLifespan;
  }

  public void setAgentMaxLifespan(int i) {
    agentMaxLifespan = i;
  }

  public void setAgentMinLifespan(int i) {
    agentMinLifespan = i;
  }

  public static void main(String[] args) {
    SimInit init = new SimInit();
    CarryDropModel model = new CarryDropModel();
    init.loadModel(model, "", false);
  }

}

CarryDropAgent

// CarryDropAgent
package demo;

import java.awt.Color;

import uchicago.src.sim.gui.Drawable;
import uchicago.src.sim.gui.SimGraphics;
import uchicago.src.sim.space.Object2DGrid;

public class CarryDropAgent implements Drawable{
  private int x;
  private int y;
  private int vX;
  private int vY;
  private int money;
  private int stepsToLive;
  private static int IDNumber = 0;
  private int ID;
  private CarryDropSpace cdSpace;

  public CarryDropAgent(int minLifespan, int maxLifespan){
    x = -1;
    y = -1;
    money = 0;
    setVxVy();
    stepsToLive =
        (int)((Math.random() * (maxLifespan - minLifespan)) + minLifespan);
    IDNumber++;
    ID = IDNumber;
  }

  private void setVxVy(){
    vX = 0;
    vY = 0;
    while((vX == 0) && ( vY == 0)){
      vX = (int)Math.floor(Math.random() * 3) - 1;
      vY = (int)Math.floor(Math.random() * 3) - 1;
    }
  }

  public void setXY(int newX, int newY){
    x = newX;
    y = newY;
  }

  public void setCarryDropSpace(CarryDropSpace cds){
    cdSpace = cds;
  }

  public String getID(){
    return "A-" + ID;
  }

  public int getMoney(){
    return money;
  }

  public int getStepsToLive(){
    return stepsToLive;
  }

  public void report(){
    System.out.println(getID() +
                       " at " +
                       x + ", " + y +
                       " has " +
                       getMoney() + " dollars" +
                       " and " +
                       getStepsToLive() + " steps to live.");
  }

  public int getX(){
    return x;
  }

  public int getY(){
    return y;
  }

  public void draw(SimGraphics G){
    if(stepsToLive > 10)
      G.drawFastRoundRect(Color.green);
    else
      G.drawFastRoundRect(Color.blue);
  }

  public void step(){
    int newX = x + vX;
    int newY = y + vY;

    Object2DGrid grid = cdSpace.getCurrentAgentSpace();
    newX = (newX + grid.getSizeX()) % grid.getSizeX();
    newY = (newY + grid.getSizeY()) % grid.getSizeY();

    if(tryMove(newX, newY)){
      money += cdSpace.takeMoneyAt(x, y);
    }
    else{
      CarryDropAgent cda = cdSpace.getAgentAt(newX, newY);
      if (cda!= null){
        if(money > 0){
          cda.receiveMoney(1);
          money--;
        }
      }
      setVxVy();
    }
    stepsToLive--;
  }

  private boolean tryMove(int newX, int newY){
    return cdSpace.moveAgentAt(x, y, newX, newY);
  }

  public void receiveMoney(int amount){
    money += amount;
  }
}

CarryDropSpace

// CarryDropSpace
package demo;

import uchicago.src.sim.space.Object2DGrid;


public class CarryDropSpace {
private Object2DGrid moneySpace;
private Object2DGrid agentSpace;

  public CarryDropSpace(int xSize, int ySize){
    moneySpace = new Object2DGrid(xSize, ySize);
    agentSpace = new Object2DGrid(xSize, ySize);

    for(int i = 0; i < xSize; i++){
      for(int j = 0; j < ySize; j++){
        moneySpace.putObjectAt(i,j,new Integer(0));
      }
    }
  }

  public void spreadMoney(int money){
    // Randomly place money in moneySpace
    for(int i = 0; i < money; i++){

      // Choose coordinates
      int x = (int)(Math.random()*(moneySpace.getSizeX()));
      int y = (int)(Math.random()*(moneySpace.getSizeY()));

      // Get the value of the object at those coordinates
      int currentValue = getMoneyAt(x, y);
      // Replace the Integer object with another one with the new value
      moneySpace.putObjectAt(x,y,new Integer(currentValue + 1));
    }
  }

  public int getMoneyAt(int x, int y){
    int i;
    if(moneySpace.getObjectAt(x,y)!= null){
      i = ((Integer)moneySpace.getObjectAt(x,y)).intValue();
    }
    else{
      i = 0;
    }
    return i;
  }

  public CarryDropAgent getAgentAt(int x, int y){
    CarryDropAgent retVal = null;
    if(agentSpace.getObjectAt(x, y) != null){
      retVal = (CarryDropAgent)agentSpace.getObjectAt(x,y);
    }
    return retVal;
  }

  public Object2DGrid getCurrentMoneySpace(){
    return moneySpace;
  }

  public Object2DGrid getCurrentAgentSpace(){
    return agentSpace;
  }

  public boolean isCellOccupied(int x, int y){
    boolean retVal = false;
    if(agentSpace.getObjectAt(x, y)!=null) retVal = true;
    return retVal;
  }

  public boolean addAgent(CarryDropAgent agent){
    boolean retVal = false;
    int count = 0;
    int countLimit = 10 * agentSpace.getSizeX() * agentSpace.getSizeY();

    while((retVal==false) && (count < countLimit)){
      int x = (int)(Math.random()*(agentSpace.getSizeX()));
      int y = (int)(Math.random()*(agentSpace.getSizeY()));
      if(isCellOccupied(x,y) == false){
        agentSpace.putObjectAt(x,y,agent);
        agent.setXY(x,y);
        agent.setCarryDropSpace(this);
        retVal = true;
      }
      count++;
    }

    return retVal;
  }

  public void removeAgentAt(int x, int y){
    agentSpace.putObjectAt(x, y, null);
  }

  public int takeMoneyAt(int x, int y){
    int money = getMoneyAt(x, y);
    moneySpace.putObjectAt(x, y, new Integer(0));
    return money;
  }

  public boolean moveAgentAt(int x, int y, int newX, int newY){
    boolean retVal = false;
    if(!isCellOccupied(newX, newY)){
      CarryDropAgent cda = (CarryDropAgent)agentSpace.getObjectAt(x, y);
      removeAgentAt(x,y);
      cda.setXY(newX, newY);
      agentSpace.putObjectAt(newX, newY, cda);
      retVal = true;
    }
    return retVal;
  }

  public int getTotalMoney(){
    int totalMoney = 0;
    for(int i = 0; i < agentSpace.getSizeX(); i++){
      for(int j = 0; j < agentSpace.getSizeY(); j++){
        totalMoney += getMoneyAt(i,j);
      }
    }
    return totalMoney;
  }
}

Previous: Adding a Chart

Conclusion

Go to Table of Contents


A RePast Tutorial by John T. Murphy, University of Arizona & Arizona State University (contact)