From db1d59843b7d0da4bf010aa5a1e488e2d82b44e8 Mon Sep 17 00:00:00 2001 From: AlexBocken Date: Thu, 29 Jun 2023 17:16:31 +0200 Subject: [PATCH] update plotting functions --- agent.py | 5 ++-- hexplot.py | 12 ++++++--- main.py | 68 ++++++++++++++++++++++++++++++++++++--------------- model.py | 47 ++++++------------------------------ plot.py | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 139 insertions(+), 64 deletions(-) create mode 100644 plot.py diff --git a/agent.py b/agent.py index e0ebb79..6308ef5 100644 --- a/agent.py +++ b/agent.py @@ -160,6 +160,7 @@ class RandomWalkerAnt(Agent): # recruit new ants + print("RECRUITING") for agent_id in self.model.get_unique_ids(self.model.N_r): if self.model.schedule.get_agent_count() < self.model.N_m: agent = RandomWalkerAnt(unique_id=agent_id, model=self.model, look_for_pheromone="B", drop_pheromone="A") @@ -219,8 +220,8 @@ class RandomWalkerAnt(Agent): if self.energy < self.model.e_min: self.model.schedule.remove(self) #update list of dead agents for time step - self.model.dead_agents[self.model.schedule.steps-1] += 1 - + self.model.dying_agents += 1 + else: self._choose_next_pos() self._adjust_pheromone_drop_rate() diff --git a/hexplot.py b/hexplot.py index 0ec91cb..45c24cd 100755 --- a/hexplot.py +++ b/hexplot.py @@ -13,6 +13,9 @@ def plot_hexagon(A, title=None, block=True): Y[:,i] += 1 fig, ax = plt.subplots() + fig.set_figwidth(10) + fig.set_figheight(10) + fig.set_dpi(600) im = ax.hexbin( X.reshape(-1), Y.reshape(-1), @@ -24,8 +27,11 @@ def plot_hexagon(A, title=None, block=True): ax.set_aspect(1) ax.set(xlim=(-4, X.max()+4,), ylim=(-4, Y.max()+4)) ax.axis(False) - plt.colorbar(im) + ax.set_xmargin(0) + ax.set_ymargin(0) + #plt.colorbar(im, shrink=0.7) if(title is not None): - plt.title(title) - plt.show(block=block) + pass + #plt.title(title) + plt.savefig(f"{title}.png") diff --git a/main.py b/main.py index 5d1e33c..2c26603 100755 --- a/main.py +++ b/main.py @@ -310,41 +310,71 @@ def place_blocking_object(center, radius, model): model.grid.fields['res'][pos] = infinity -def plot_heatmap(): - from hexplot import plot_hexagon +def run_model(): from tqdm import tqdm # nests rather far away but also partially clumped. np.random.seed(6) from model import kwargs_paper_setup1 as kwargs - kwargs["gamma"] /= 3 # field decays slower - kwargs["beta"] /= 3 # drop rates decays slower - kwargs["d_e"] /= 3 # live longer, search longer - kwargs["d_s"] /= 3 # live longer, search longer + kwargs["gamma"] /= 2 + kwargs["beta"] /= 2 + kwargs["d_e"] /= 5 # live longer, search longer + kwargs["d_s"] /= 5 # live longer, search longer + kwargs["N_0"] *= 2 # more initial roamers/scouts + kwargs["max_steps"] *= 2 # more initial roamers/scouts model = ActiveWalkerModel(**kwargs) a = np.zeros_like(model.grid.fields['food']) a[np.nonzero(model.grid.fields['food'])] = 1 a[np.nonzero(model.grid.fields['nests'])] = -1 - plot_hexagon(a, title="food locations", block=False) for _ in tqdm(range(model.max_steps)): model.step() + return model - for time in np.arange(0, model.max_steps + 1, 1000): - pheromone_concentration = model.datacollector.get_model_vars_dataframe()["pheromone_a"][time] - a = pheromone_concentration - #plot_hexagon(a) - pheromone_concentration = model.datacollector.get_model_vars_dataframe()["pheromone_b"][time] - b = pheromone_concentration - #plot_hexagon(b) - c = np.max([a,b], axis=0) - c = a + b - c = np.clip(c, 0, 200) - plot_hexagon(c) +from model import kwargs_paper_setup1 as kwargs +kwargs["gamma"] /= 2 +kwargs["beta"] /= 2 +kwargs["d_e"] /= 5 # live longer, search longer +kwargs["d_s"] /= 5 # live longer, search longer +kwargs["N_0"] *= 2 # more initial roamers/scouts +kwargs["max_steps"] *= 2 # more initial roamers/scouts + +def run_model_objects(step, seed=None, title=None): + from tqdm import tqdm + # nests rather far away but also partially clumped. + np.random.seed(6) + from hexplot import plot_hexagon + model = ActiveWalkerModel(**kwargs) + a = np.zeros_like(model.grid.fields['food']) + a[np.nonzero(model.grid.fields['food'])] = 1 + a[np.nonzero(model.grid.fields['nests'])] = -1 + for current_step in tqdm(range(model.max_steps)): + if current_step == step: + if seed is not None: + np.random.seed(seed) + for _ in range(10): + coord = np.random.randint(0, 100, size=2) + coord = (coord[0], coord[1]) + place_blocking_object(center=coord,radius=5, model=model) + a = model.grid.fields["res"] + if title is not None: + plot_hexagon(a, title=title) + model.step() + return model + #if __name__ == "__main__": -plot_heatmap() +#plot_heatmap() +#res = run_model_no_objects() +for i in range(10): + res = run_model_objects(step=6000, seed=i+100, title=f"objects/blockings_run_{i}") + from plot import plot_alive_ants_vs_time, dead_ants_vs_time, plot_connectivity_vs_time + plot_alive_ants_vs_time(res, title=f"objects/run_{i}") + dead_ants_vs_time(res, title=f"objects/dead_ants_run_{i}") + plot_connectivity_vs_time(res, title=f"objects/conn_run_{i}") + + #print("DISTANCE TEST VS SUCCESSFUL ANTS OBJECT INBETWEEN") #res = fixed_distance_tests() #res = fixed_distance_object_between() diff --git a/model.py b/model.py index bd55d56..f1d944b 100644 --- a/model.py +++ b/model.py @@ -101,6 +101,7 @@ class ActiveWalkerModel(Model): self.N_f : int = N_f #num food sources self.successful_ants = 0 # for viviane's graph self.connectivity = 0 # for viviane's persistence + self.dying_agents = 0 fields=["A", "B", "nests", "food", "res"] self.schedule = SimultaneousActivation(self) @@ -129,8 +130,6 @@ class ActiveWalkerModel(Model): self.max_steps = max_steps self.grid.add_nest(nest_position) - self.dead_agents = [i*0 for i in range(self.max_steps)] - self.alive_agents = [self.N_r for i in range(self.max_steps)] for agent_id in self.get_unique_ids(N_0): if self.schedule.get_agent_count() < self.N_m: @@ -146,7 +145,8 @@ class ActiveWalkerModel(Model): model_reporters = {"pheromone_a": lambda m: m.grid.fields["A"], "pheromone_b": lambda m: m.grid.fields["B"], "alive_ants": lambda m: m.schedule.get_agent_count(), - "sucessful_walkers": lambda m: m.successful_ants, + "dying_ants": lambda m: m.dying_agents, + "successful_walkers": lambda m: m.successful_ants, "connectivity": lambda m: m.connectivity, }, agent_reporters={} @@ -154,10 +154,8 @@ class ActiveWalkerModel(Model): self.datacollector.collect(self) # keep at end of __init___ # Breadth-first-search algorithm for connectivity - # TODO: Implement pheromone B (take max of the two or sum?) - # alex: what's to say against max? def bfs(self): - threshold = 0.0000001 #the value of A + threshold = 0.5 # half of min sens connectivity = 0 #initial value of connectivity connected_food_sources = [] #empty list of connected food sources visited = [] #empty list of visited (by the algorithm) nodes @@ -186,7 +184,6 @@ class ActiveWalkerModel(Model): connected_food_sources = connected_food_sources + list([current_node]) #and it is added to the list of connected food sources # why not normalize to 0-1 ? - print(f"{connectivity=}") return connectivity #we want the connectivity (0-5) def agent_density(self): @@ -198,9 +195,11 @@ class ActiveWalkerModel(Model): def step(self): + self.dying_agents = 0 self.schedule.step() # step() and advance() all agents + if self.schedule.steps % 100 == 0: - self.connectivity = self.bfs() + pass # apply decay rate on pheromone levels for key in ("A", "B"): @@ -209,12 +208,8 @@ class ActiveWalkerModel(Model): self.datacollector.collect(self) - self.alive_agents[self.schedule.steps-1] = len(self.schedule.agents) - if self.schedule.steps >= self.max_steps: - self.plot_alive_agents() - self.plot_aliveDead_agents() self.running = False def get_unique_id(self) -> int: @@ -225,35 +220,7 @@ class ActiveWalkerModel(Model): for _ in range(num_ids): yield self.get_unique_id() - def plot_aliveDead_agents(self): - import matplotlib.pyplot as plt - - plt.figure() - x = [i for i in range(self.max_steps)] - plt.plot(x, self.dead_agents, label="dead ants") - plt.plot(x, self.alive_agents, label="alive ants") - plt.title("Number of ants alive and dead per time step") - plt.legend(loc="best") - plt.xlabel('time steps') - plt.ylabel('Number of ants') - - plt.show() - - def plot_alive_agents(self): - - import matplotlib.pyplot as plt - - plt.figure() - x = [i for i in range(self.max_steps)] - plt.plot(x, self.alive_agents, label="alive ants") - plt.title("Number of ants alive per time step") - plt.legend(loc="best") - plt.xlabel('time steps') - plt.ylabel('Number of ants') - - plt.show() - """ This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3. diff --git a/plot.py b/plot.py new file mode 100644 index 0000000..c2994d3 --- /dev/null +++ b/plot.py @@ -0,0 +1,71 @@ +#!/bin/python + +import matplotlib.pyplot as plt +import numpy as np +from hexplot import plot_hexagon + +def plot_alive_ants_vs_time(model, title=None): + y = model.datacollector.get_model_vars_dataframe()["alive_ants"] + plt.figure(figsize=(10,10), dpi=600) + plt.plot(y) + plt.xlabel("time step") + plt.ylabel("alive agents") + if title is None: + plt.savefig("alive_agents_over_time.eps") + else: + plt.savefig(f"{title}.png") + + +def plot_connectivity_vs_time(model, title=None): + y = model.datacollector.get_model_vars_dataframe()["connectivity"] + plt.figure(figsize=(10,10), dpi=600) + plt.plot(y) + plt.xlabel("time step") + plt.ylabel("No. of food sources connected to the nest") + if title is None: + plt.savefig("connectivity_over_time.eps") + else: + plt.savefig(f"{title}.png") + + +def dead_ants_vs_time(model, title=None): + y = np.cumsum(model.datacollector.get_model_vars_dataframe()["dying_ants"]) + plt.figure(figsize=(10,10), dpi=600) + plt.plot(y) + plt.xlabel("time step") + plt.ylabel("dead agents") + if title is None: + plt.savefig("dead_agents_over_time.eps") + else: + plt.savefig(f"{title}.png") + + +def cum_successful_ants_vs_time(model, title=None): + y = model.datacollector.get_model_vars_dataframe()["successful_walkers"] + plt.figure(figsize=(10,10), dpi=600) + plt.plot(y) + plt.xlabel("time step") + plt.ylabel("cummulative successful agents") + if title is None: + plt.savefig("cumsum_successful_agents_over_time.eps") + else: + plt.savefig(f"{title}.png") + + +def plot_heatmap(model, low=10, high=200): + for time in np.arange(0, model.max_steps + 1, 1000): + pheromone_concentration = model.datacollector.get_model_vars_dataframe()["pheromone_a"][time] + a = pheromone_concentration + #plot_hexagon(a) + pheromone_concentration = model.datacollector.get_model_vars_dataframe()["pheromone_b"][time] + b = pheromone_concentration + #plot_hexagon(b) + c = np.max([a,b], axis=0) + c = a + b + c = np.clip(c, 1, 1000000000) + c = np.log(c) + c = c/np.max(c) + food_locations = np.nonzero(model.grid.fields['food']) + x_food = [ food[0] for food in food_locations ] + y_food = [ food[1] for food in food_locations ] + plot_hexagon(c, title=f"cummulative pheromone density at timestep {time}")