<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Introduction to Mesa Tutorial Code
This Notebook contains code corresponding to the Intro to Mesa tutorial, which you should check out for the full explanation and documentation.
Step1:  Simple Model
This section corresponds to the code in the Running Your First Model section of the tutorial.
First, import the base classes we'll use
Step4:  Next, create the agent and model classes
Step5:  Create a model and run it for 10 steps
Step6:  And display a histogram of agent wealths
Step7:  Create and run 100 models, and visualize the wealth distribution across all of them
Step8:  Adding space
This section puts the agents on a grid, corresponding to the Adding Space section of the tutorial.
For this, we need to import the grid class
Step10:  Create the new model object. (Note that this overwrites the MoneyModel object created above)
Step12:  And create the agent to go along with it
Step13:  Create a model with 50 agents and a 10x10 grid, and run for 20 steps
Step14:  Visualize the number of agents on each grid cell
Step15:  Collecting Data
Add a Data Collector to the model, as explained in the corresponding section of the tutorial.
First, import the DataCollector
Step16:  Compute the agents' Gini coefficient, measuring inequality.
Step18:  This MoneyModel is identical to the one above, except for the self.datacollector = ... line at the end of the __init__ method, and the collection in step.
Step19:  Now instantiate a model, run it for 100 steps...
Step20:  ... And collect and plot the data it generated
Step21:  Batch Run
Run a parameter sweep, as explained in the Batch Run tutorial section.
Import the Mesa BatchRunner
Step22:  Set up the batch run
Step23:  Run the parameter sweep; this step might take a while
Step24:  Export and plot the results
<ASSISTANT_TASK:>
Python Code:
# Use matplotlib for inline graphing
import matplotlib.pyplot as plt
%matplotlib inline
Explanation: Introduction to Mesa Tutorial Code
This Notebook contains code corresponding to the Intro to Mesa tutorial, which you should check out for the full explanation and documentation.
End of explanation
from mesa import Agent, Model
from mesa.time import RandomActivation
import random
Explanation: Simple Model
This section corresponds to the code in the Running Your First Model section of the tutorial.
First, import the base classes we'll use
End of explanation
class MoneyAgent(Agent):
     An agent with fixed initial wealth.
    def __init__(self, unique_id):
        self.unique_id = unique_id
        self.wealth = 1
    def step(self, model):
        if self.wealth == 0:
            return
        other_agent = random.choice(model.schedule.agents)
        other_agent.wealth += 1
        self.wealth -= 1
class MoneyModel(Model):
    A model with some number of agents.
    def __init__(self, N):
        self.running = True
        self.num_agents = N
        self.schedule = RandomActivation(self)
        # Create agents
        for i in range(self.num_agents):
            a = MoneyAgent(i)
            self.schedule.add(a)
    def step(self):
        '''Advance the model by one step.'''
        self.schedule.step()
Explanation: Next, create the agent and model classes:
End of explanation
model = MoneyModel(10)
for i in range(10):
    model.step()
Explanation: Create a model and run it for 10 steps:
End of explanation
agent_wealth = [a.wealth for a in model.schedule.agents]
plt.hist(agent_wealth)
Explanation: And display a histogram of agent wealths:
End of explanation
all_wealth = []
for j in range(100):
    # Run the model
    model = MoneyModel(10)
    for i in range(10):
        model.step()
    # Store the results
    for agent in model.schedule.agents:
        all_wealth.append(agent.wealth)
plt.hist(all_wealth, bins=range(max(all_wealth)+1))
Explanation: Create and run 100 models, and visualize the wealth distribution across all of them:
End of explanation
from mesa.space import MultiGrid
Explanation: Adding space
This section puts the agents on a grid, corresponding to the Adding Space section of the tutorial.
For this, we need to import the grid class:
End of explanation
class MoneyModel(Model):
    A model with some number of agents.
    def __init__(self, N, width, height):
        self.running = True
        self.num_agents = N
        self.grid = MultiGrid(height, width, True)
        self.schedule = RandomActivation(self)
        # Create agents
        for i in range(self.num_agents):
            a = MoneyAgent(i)
            self.schedule.add(a)
            # Add the agent to a random grid cell
            x = random.randrange(self.grid.width)
            y = random.randrange(self.grid.height)
            self.grid.place_agent(a, (x, y))
    def step(self):
        self.schedule.step()
Explanation: Create the new model object. (Note that this overwrites the MoneyModel object created above)
End of explanation
class MoneyAgent(Agent):
     An agent with fixed initial wealth.
    def __init__(self, unique_id):
        self.unique_id = unique_id
        self.wealth = 1
    def move(self, model):
        possible_steps = model.grid.get_neighborhood(self.pos, moore=True, include_center=False)
        new_position = random.choice(possible_steps)
        model.grid.move_agent(self, new_position)
    def give_money(self, model):
        cellmates = model.grid.get_cell_list_contents([self.pos])
        if len(cellmates) > 1:
            other = random.choice(cellmates)
            other.wealth += 1
            self.wealth -= 1
    def step(self, model):
        self.move(model)
        if self.wealth > 0:
            self.give_money(model)
Explanation: And create the agent to go along with it:
End of explanation
model = MoneyModel(50, 10, 10)
for i in range(20):
    model.step()
Explanation: Create a model with 50 agents and a 10x10 grid, and run for 20 steps
End of explanation
import numpy as np
agent_counts = np.zeros((model.grid.width, model.grid.height))
for cell in model.grid.coord_iter():
    cell_content, x, y = cell
    agent_count = len(cell_content)
    agent_counts[x][y] = agent_count
plt.imshow(agent_counts, interpolation='nearest')
plt.colorbar()
 
Explanation: Visualize the number of agents on each grid cell:
End of explanation
from mesa.datacollection import DataCollector
Explanation: Collecting Data
Add a Data Collector to the model, as explained in the corresponding section of the tutorial.
First, import the DataCollector
End of explanation
def compute_gini(model):
    '''
    Compute the current Gini coefficient.
    
    Args:
        model: A MoneyModel instance
    Returns:
        The Gini Coefficient for the model's current step.
    '''
    agent_wealths = [agent.wealth for agent in model.schedule.agents]
    x = sorted(agent_wealths)
    N = model.num_agents
    B = sum( xi * (N-i) for i,xi in enumerate(x) ) / (N*sum(x))
    return (1 + (1/N) - 2*B)
Explanation: Compute the agents' Gini coefficient, measuring inequality.
End of explanation
class MoneyModel(Model):
    A model with some number of agents.
    def __init__(self, N, width, height):
        self.running = True
        self.num_agents = N
        self.grid = MultiGrid(height, width, True)
        self.schedule = RandomActivation(self)
        # Create agents
        for i in range(self.num_agents):
            a = MoneyAgent(i)
            self.schedule.add(a)
            # Add the agent to a random grid cell
            x = random.randrange(self.grid.width)
            y = random.randrange(self.grid.height)
            self.grid.place_agent(a, (x, y))
            
        # New addition: add a DataCollector:
        self.datacollector = DataCollector(model_reporters={"Gini": compute_gini},
            agent_reporters={"Wealth": lambda a: a.wealth})
    def step(self):
        self.datacollector.collect(self) # Collect the data before the agents run.
        self.schedule.step()
Explanation: This MoneyModel is identical to the one above, except for the self.datacollector = ... line at the end of the __init__ method, and the collection in step.
End of explanation
model = MoneyModel(50, 10, 10)
for i in range(100):
    model.step()
Explanation: Now instantiate a model, run it for 100 steps...
End of explanation
gini = model.datacollector.get_model_vars_dataframe()
gini.head()
gini.plot()
agent_wealth = model.datacollector.get_agent_vars_dataframe()
agent_wealth.head()
end_wealth = agent_wealth.xs(99, level="Step")["Wealth"]
end_wealth.hist(bins=range(agent_wealth.Wealth.max()+1))
one_agent_wealth = agent_wealth.xs(14, level="AgentID")
one_agent_wealth.Wealth.plot()
Explanation: ... And collect and plot the data it generated:
End of explanation
from mesa.batchrunner import BatchRunner
Explanation: Batch Run
Run a parameter sweep, as explained in the Batch Run tutorial section.
Import the Mesa BatchRunner:
End of explanation
parameters = {"height": 10, "width": 10, "N": range(10, 500, 10)}
batch_run = BatchRunner(MoneyModel, parameters, iterations=5, max_steps=100,
           model_reporters={"Gini": compute_gini})
Explanation: Set up the batch run:
End of explanation
batch_run.run_all()
Explanation: Run the parameter sweep; this step might take a while:
End of explanation
run_data = batch_run.get_model_vars_dataframe()
run_data.head()
plt.scatter(run_data.N, run_data.Gini)
plt.xlabel("Number of agents")
plt.ylabel("Gini Coefficient")
Explanation: Export and plot the results:
End of explanation
<END_TASK>