Pages
▼
Monday, October 31, 2016
Tuesday, October 11, 2016
Tuesday, October 4, 2016
Visualize the Behavior Space in Netlogo: 1.1
Last month, I posted code for visualizing the behavior-space using Python to process data from NetLogo. See that post for the netlogo template you will want to use. The py file I posted before was not the easiest to interpret or to work with. It required that a programmer plan ahead, noting the position of runs with particular values for exogenously determined parameters. I rewrote the code so that the data processing is more efficient and easier to work with. The instance I am posting works with a behavior space where only two variables have been set exogenously across runs. However, if it was necessary, a third or fourth variable could be altered in the same set of runs so long as that third and/or fourth variable was assigned a particular value as runs are collected in lines 196-209. Also note that I have reduced the variety of heatmaps presented since only one is required to convey the process. I loop the image generator code to create a series of frames.
I may eventually post such an extension of the code if I generate output that requires this in the future. For now, I wanted to leave you with something easier to work with. Remember, you should end up with something that looks like this (from earlier post):
See the updated code below:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | from __future__ import print_function import numpy as np import matplotlib.pyplot as plt import matplotlib.cm as cm import pandas as pd from matplotlib.backends.backend_pdf import PdfPages # of csv files generated by netlogo = # of runs files = 1280 # length of each run of the model ticks = 50 # these are the values of interest # in this case we adjusted water metabolism and sugar metabolism axis_values = np.array([.45, .5, .55, .6, .65, .7, .75, .8]) # length of x-axis and y-axis for heatmap num_x = len(axis_values) num_y = num_x runs_per_setting = 20 # min and max x and y parameters for heatmap min_sugar_metabolism = .45 max_sugar_metabolism = .8 min_water_metabolism = .45 max_water_metabolism = .8 # increments tested (here we assume constant increment, could be logged, quadratic, etc...) inc_sugar = .05 inc_water = .05 # set up names of each column of data from csv names = pd.Series([ 'sugar_metabolism_rate', 'water_metabolism_rate', 'sugar', 'water', 'mean_price', 'price_variance', 'population', 'basic_only', 'basic_herder', 'basic_arbitrageur', 'basic_herder_arbitrageur', 'switcher_only', 'switcher_herder', 'switcher_arbitrageur', 'switcher_herder_arbitrageur', 'percent_basic', 'percent_arbitrageur', 'percent_herder', 'percent_switcher', 'basic_only_wealth', 'basic_herder_wealth', 'basic_arbitrageur_wealth', 'basic_herder_arbitrageur_wealth', 'switcher_only_wealth', 'switcher_herder_wealth', 'switcher_arbitrageur_wealth', 'switcher_herder_arbitrageur_wealth', 'sugar_flow', 'water_flow', 'distance_from_equilibrium_price', 'fifty_period_RAP', 'mean_rate_of_price_change']) # names dict used to instantiate an m X n array that will be used # to keep track of the average value of each variable at each tick for each category # will be inserted into mean_values dataframe names_dict = { 'sugar_metabolism_rate': [np.arange(ticks)], 'water_metabolism_rate': [np.arange(ticks)], 'sugar': [np.arange(ticks)], 'water': [np.arange(ticks)], 'mean_price': [np.arange(ticks)], 'price_variance': [np.arange(ticks)], 'population': [np.arange(ticks)], 'basic_only': [np.arange(ticks)], 'basic_herder': [np.arange(ticks)], 'basic_arbitrageur': [np.arange(ticks)], 'basic_herder_arbitrageur': [np.arange(ticks)], 'switcher_only': [np.arange(ticks)], 'switcher_herder': [np.arange(ticks)], 'switcher_arbitrageur': [np.arange(ticks)], 'switcher_herder_arbitrageur': [np.arange(ticks)], 'percent_basic': [np.arange(ticks)], 'percent_arbitrageur': [np.arange(ticks)], 'percent_herder': [np.arange(ticks)], 'percent_switcher': [np.arange(ticks)], 'basic_only_wealth': [np.arange(ticks)], 'basic_herder_wealth': [np.arange(ticks)], 'basic_arbitrageur_wealth': [np.arange(ticks)], 'basic_herder_arbitrageur_wealth': [np.arange(ticks)], 'switcher_only_wealth': [np.arange(ticks)], 'switcher_herder_wealth': [np.arange(ticks)], 'switcher_arbitrageur_wealth': [np.arange(ticks)], 'switcher_herder_arbitrageur_wealth': [np.arange(ticks)], 'sugar_flow': [np.arange(ticks)], 'water_flow': [np.arange(ticks)], 'distance_from_equilibrium_price': [np.arange(ticks)], 'fifty_period_RAP': [np.arange(ticks)], 'basic_only_wealth_per_capita': [np.arange(ticks)], 'basic_herder_wealth_per_capita': [np.arange(ticks)], 'basic_arbitrageur_wealth_per_capita': [np.arange(ticks)], 'basic_herder_arbitrageur_wealth_per_capita': [np.arange(ticks)], 'switcher_only_wealth_per_capita': [np.arange(ticks)], 'switcher_herder_wealth_per_capita': [np.arange(ticks)], 'switcher_arbitrageur_wealth_per_capita': [np.arange(ticks)], 'switcher_herder_arbitrageur_wealth_per_capita': [np.arange(ticks)], 'percent_basic_only': [np.arange(ticks)], 'percent_basic_herder': [np.arange(ticks)], 'percent_basic_arbitraguer': [np.arange(ticks)], 'percent_basic_herder_arbitraguer': [np.arange(ticks)], 'percent_switcher_only': [np.arange(ticks)], 'percent_switcher_herder': [np.arange(ticks)], 'percent_switcher_arbitraguer': [np.arange(ticks)], 'percent_switcher_herder_arbitraguer': [np.arange(ticks)], } # Lists for used to generate new categories of data new_category = pd.Series([ 'basic_only_wealth_per_capita', 'basic_herder_wealth_per_capita', 'basic_arbitrageur_wealth_per_capita', 'basic_herder_arbitrageur_wealth_per_capita', 'switcher_only_wealth_per_capita', 'switcher_herder_wealth_per_capita', 'switcher_arbitrageur_wealth_per_capita', 'switcher_herder_arbitrageur_wealth_per_capita', 'percent_basic_only', 'percent_basic_herder', 'percent_basic_arbitrageur', 'percent_basic_herder_arbitrageur', 'percent_switcher_only', 'percent_switcher_herder', 'percent_switcher_arbitrageur', 'percent_switcher_herder_arbitrageur']) numerator_category = pd.Series([ 'basic_only_wealth', 'basic_herder_wealth', 'basic_arbitrageur_wealth', 'basic_herder_arbitrageur_wealth', 'switcher_only_wealth', 'switcher_herder_wealth', 'switcher_arbitrageur_wealth', 'switcher_herder_arbitrageur_wealth', 'basic_only', 'basic_herder', 'basic_arbitrageur', 'basic_herder_arbitrageur', 'switcher_only', 'switcher_herder', 'switcher_arbitrageur', 'switcher_herder_arbitrageur']) denominator_category = pd.Series([ 'basic_only', 'basic_herder', 'basic_arbitrageur', 'basic_herder_arbitrageur', 'switcher_only_wealth', 'switcher_herder_wealth', 'switcher_arbitrageur_wealth', 'switcher_herder_arbitrageur', 'population', 'population', 'population', 'population', 'population', 'population', 'population', 'population']) def process_data(): # Dataframe will house the average values of each variable across runs for some given # pair of parameters mean_values = pd.DataFrame(columns = [np.arange(num_x)], index = [np.arange(num_y)]) for x in range(0,num_x): for y in range(0,num_y): mean_values[x][y] = pd.DataFrame(names_dict) # import csvs using names array as headers for each column # order of elements in names array should match order of objects recorded # during runs in NetLogo for i in range(1, files + 1): filename = str(i) + 'sugarscapeGlobalTradeBasics.csv' runs = pd.read_csv(filename, names = names) for x in range(len(new_category)): add_per_capita_categories(runs, new_category[x], numerator_category[x], denominator_category[x]) c = 0 # Find runs whose fixed parameter values match the values for the target # coordinates in mean values, will eventually transfer to heatmap for a in axis_values: if runs.iloc[0]['sugar_metabolism_rate'] == a: # round(a,2): for b in axis_values: if runs.iloc[0]['water_metabolism_rate'] == b: # round(b,2): x = int(round(((b - min_water_metabolism) / inc_water),0)) y = int(round(((a - min_sugar_metabolism) / inc_sugar),0)) if c < 1: # avoid error in 0th element of each category mean_values[x][y] = runs else: # once the first run data has been placed mean_values[x][y] = mean_values[x][y].add(runs, fill_value = 0) c += 1 mean_values = mean_values / runs_per_setting print_behavior_space_representation(mean_values) ############################################################################################## ############################################################################################## def add_per_capita_categories(target_array, per_capita_name, per_capita_numerator, population_denominator): target_array[per_capita_name] = target_array[per_capita_numerator] / target_array[population_denominator] def initialize_image(num_x, num_y): image = [] for i in range(num_y): x_colors = [] for j in range(num_x): x_colors.append(0) image.append(x_colors) return image def color_points(title, filename, category, mean_values,pp, tick, min_val, max_val): # x_p = num_x # y_p = num_y image = initialize_image(num_x, num_y) for i in range(0, num_x): for j in range(0, num_y): image[i][j] = mean_values[i][j].iloc[tick][category] print(image) plt.imshow(image, origin='lower', extent=(min_sugar_metabolism, max_sugar_metabolism, min_water_metabolism, max_water_metabolism), cmap=cm.Greys_r, interpolation = 'nearest') plt.colorbar() plt.clim(min_val, max_val) plt.xlabel('Water Consumption Rate') plt.ylabel('Sugar Consumption Rate') plt.title(title + " " + str(tick + 1) + " Ticks") fig = plt.gcf() plt.show() plt.draw() pp.savefig(fig) # fig.savefig(filename + ".pdf") def print_behavior_space_representation(data): interval = 1 pp = PdfPages('population_local_basic_tick_50.pdf') for q in range(1, ticks, interval): color_points("Population\nGlobal Trade Basic","Population Global Trade Basic", "population", data, pp, q, 0, 300) plt.close('all') pp.close() if __name__ == '__main__': np.save('data', process_data()) np.load('data.npy') |