2

If you don't know what is Schelling's model of segregation, you can read it here.

I have written the following code to run the Schelling's model of segregation simulation.

import matplotlib.pyplot as plt
import matplotlib.animation
import itertools
import random
import copy


class Schelling:

    def __init__(self, width, height, empty_ratio, similarity_threshold, n_iterations, ratio,dataframe,county_num, races = 2):
        self.width = width 
        self.height = height 
        self.races = races
        self.empty_ratio = empty_ratio
        self.similarity_threshold = similarity_threshold
        self.n_iterations = n_iterations
        self.ratio=ratio
        self.county_num=county_num
        self.dataframe=dataframe

    def populate(self):
        """
        Populate the square randomly with the two races.
        """

        self.empty_houses = []
        self.agents = {}
        self.all_houses = list(itertools.product(range(self.width),range(self.height)))
        random.shuffle(self.all_houses)
        self.n_empty = int(self.empty_ratio * len(self.all_houses))
        self.empty_houses = self.all_houses[:self.n_empty]
        self.remaining_houses = self.all_houses[self.n_empty:]
        divider=int(round(len(self.remaining_houses)*self.ratio)) #divides the list in two different parts according to the ratio between white and the minority given in two different states
        houses_white=self.remaining_houses[:divider]
        houses_black=self.remaining_houses[divider:]
        self.agents.update(dict(zip(houses_white,[1]*divider)))
        self.agents.update(dict(zip(houses_black,[2]*int(len(self.remaining_houses)-divider))))
        return self.remaining_houses #for debugging purposes         

    def is_unsatisfied(self, x, y):
        """
        Checking if an agent is unsatisfied or satisified at its current
        position.
        """

        race = self.agents[(x,y)]
        count_similar = 0
        count_different = 0

        if x > 0 and y > 0 and (x-1, y-1) not in self.empty_houses:
            if self.agents[(x-1, y-1)] == race:
                count_similar += 1
            else:
                count_different += 1
        if y > 0 and (x,y-1) not in self.empty_houses:
            if self.agents[(x,y-1)] == race:
                count_similar += 1
            else:
                count_different += 1
        if x < (self.width-1) and y > 0 and (x+1,y-1) not in self.empty_houses:
            if self.agents[(x+1,y-1)] == race:
                count_similar += 1
            else:
                count_different += 1
        if x > 0 and (x-1,y) not in self.empty_houses:
            if self.agents[(x-1,y)] == race:
                count_similar += 1
            else:
                count_different += 1        
        if x < (self.width-1) and (x+1,y) not in self.empty_houses:
            if self.agents[(x+1,y)] == race:
                count_similar += 1
            else:
                count_different += 1
        if x > 0 and y < (self.height-1) and (x-1,y+1) not in self.empty_houses:
            if self.agents[(x-1,y+1)] == race:
                count_similar += 1
            else:
                count_different += 1        
        if x > 0 and y < (self.height-1) and (x,y+1) not in self.empty_houses:
            if self.agents[(x,y+1)] == race:
                count_similar += 1
            else:
                count_different += 1        
        if x < (self.width-1) and y < (self.height-1) and (x+1,y+1) not in self.empty_houses:
            if self.agents[(x+1,y+1)] == race:
                count_similar += 1
            else:
                count_different += 1

        if (count_similar+count_different) == 0:
            return False
        else:
            return float(count_similar)/(count_similar+count_different) < self.similarity_threshold

    def plot(self):
        """
        plot the square with below function to show where the agents at
        """ 

        fig, ax = plt.subplots()
        agent_colors = {1:'b', 2:'r'}
        for agent in self.agents:
            ax.scatter(agent[0]+0.5, agent[1]+0.5, color=agent_colors[self.agents[agent]])
        ax.set_title("Need to change it later", fontsize=10, fontweight='bold')
        ax.set_xlim([0, self.width])
        ax.set_ylim([0, self.height])
        ax.set_xticks([])
        ax.set_yticks([])

    def update(self):
        """
        Update the square on the basis of similarity threshhold. This is the 
        function which actually runs the simulation.
        """

        fig, ax = plt.subplots()
        agent_colors = {1:'b', 2:'r'}
        ax.set_xlim([0, self.width])
        ax.set_ylim([0, self.height])
        ax.set_xticks([])
        ax.set_yticks([])
        def update(i):
            self.old_agents = copy.deepcopy(self.agents)
            n_changes = 0
            for agent in self.old_agents:
                ax.scatter(agent[0]+0.5, agent[1]+0.5, color=agent_colors[self.agents[agent]])
                ax.set_title(str(n_changes), fontsize=10, fontweight='bold')
                if self.is_unsatisfied(agent[0], agent[1]):
                    agent_race = self.agents[agent]
                    empty_house = random.choice(self.empty_houses)
                    self.agents[empty_house] = agent_race
                    del self.agents[agent]
                    self.empty_houses.remove(empty_house)
                    self.empty_houses.append(agent)
                    n_changes += 1
            if n_changes==0:
                return
        ani = matplotlib.animation.FuncAnimation(fig, update, frames= self.n_iterations,repeat=False)   
        plt.show()

    def move_to_empty(self, x, y):
        """
        Moves an unsatisfied agent to an empty house.
        """

        race = self.agents[(x,y)]
        empty_house = random.choice(self.empty_houses)
        self.updated_agents[empty_house] = race
        del self.updated_agents[(x, y)]
        self.empty_houses.remove(empty_house)
        self.empty_houses.append((x, y))             

    def calculate_similarity(self):
        """
        Calculates the mean similarity after the update.
        """

        similarity = []
        for agent in self.agents:
            count_similar = 0
            count_different = 0
            x = agent[0]
            y = agent[1]
            race = self.agents[(x,y)]
            if x > 0 and y > 0 and (x-1, y-1) not in self.empty_houses:
                if self.agents[(x-1, y-1)] == race:
                    count_similar += 1
                else:
                    count_different += 1
            if y > 0 and (x,y-1) not in self.empty_houses:
                if self.agents[(x,y-1)] == race:
                    count_similar += 1
                else:
                    count_different += 1
            if x < (self.width-1) and y > 0 and (x+1,y-1) not in self.empty_houses:
                if self.agents[(x+1,y-1)] == race:
                    count_similar += 1
                else:
                    count_different += 1
            if x > 0 and (x-1,y) not in self.empty_houses:
                if self.agents[(x-1,y)] == race:
                    count_similar += 1
                else:
                    count_different += 1        
            if x < (self.width-1) and (x+1,y) not in self.empty_houses:
                if self.agents[(x+1,y)] == race:
                    count_similar += 1
                else:
                    count_different += 1
            if x > 0 and y < (self.height-1) and (x-1,y+1) not in self.empty_houses:
                if self.agents[(x-1,y+1)] == race:
                    count_similar += 1
                else:
                    count_different += 1        
            if x > 0 and y < (self.height-1) and (x,y+1) not in self.empty_houses:
                if self.agents[(x,y+1)] == race:
                    count_similar += 1
                else:
                    count_different += 1        
            if x < (self.width-1) and y < (self.height-1) and (x+1,y+1) not in self.empty_houses:
                if self.agents[(x+1,y+1)] == race:
                    count_similar += 1
                else:
                    count_different += 1
            try:
                similarity.append(float(count_similar)/(count_similar+count_different))
            except:
                similarity.append(1)
        return sum(similarity)/len(similarity)


schelling= Schelling(20, 20, 0.3, 0.6, 1000, 0.5,90,2)
schelling.populate()
schelling.update()


I am running the simulation here on matplotlib grid or plot. Like shown below enter image description here

But the thing I want to do is to run the simulation on an American State or Some countries map. I have tried the mesa-geo module but it doesn't work well. I just want to change the square grid with the map.

Is it possible to achieve it with matplotlib library by changing the shape of the current plot to the shape of a state (say Arizona) or country (say Germany). Or is there any other module present in python to do it. I really want to do it with python as i need to do further calculations which are easier to do in python. Also I would like to get a solution which is easier to integrate with the current methods I have. Also someone can share there experience if they ever did a schellings simulation on geographical area or map.

  • 2
    what do you mean by "it doesn't work well"? – Ian Turton Jul 10 at 8:07
  • It doesn't work the way i wanted it to work. When you run the simulation you are not even able to see any agents in the region. I am thinking of use something like basemap. Do you think that can be a possibility. For example plotting the agents on an Arizona state map. – Kartikeya Sharma Jul 10 at 8:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.