piegy 2.1.0__cp38-cp38-win32.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
piegy/figures.py ADDED
@@ -0,0 +1,491 @@
1
+ '''
2
+ Contains all the major plot functions.
3
+
4
+ Plots for population:
5
+ - UV_heatmap: Used for 2D space (both N, M > 1), plot distribution of U, V in all patches within a specified time interval.
6
+ Average population over that interval is taken.
7
+ - UV_bar: Used for 1D space (N or M == 1), counterpart of UV_heatmap.
8
+ Plot average distribution of U, V in a specified time interval in a barplot.
9
+ - UV_dyna: Plot change of total U, V overtime.
10
+ - UV_hist: Make a histogram of U, V in a specified time interval.
11
+ - UV_std: Plot change of standard deviation of U, V over time.
12
+ - UV_expected: Calculate expected distribution of U, V based on matrices, assuming no migration.
13
+
14
+
15
+ Plots for payoff:
16
+ - pi_heatmap: Used for 2D space, plot distribution of Upi & Vpiwithin a specified time interval.
17
+ Average payoff over that interval is taken.
18
+ - pi_bar: Used for 1D space, counterpart of pi_heatmap.
19
+ Plot average distribution of Upi & Vpiin a specified time interval in a bar plot.
20
+ - pi_dyna: Plot change of total Upi, Vpiovertime.
21
+ - pi_hist: Make a histogram of Upi, Vpiin a specified time interval.
22
+ - pi_std: Plot change of standard deviation of Upi, Vpiover time.
23
+
24
+
25
+ Popu-payoff correlation:
26
+ - UV_pi: Make two scatter plots: x-axes are U, V, y-axes are U's and V's payoff, in a specified time interval.
27
+ Reveals relationship between population and payoff.
28
+
29
+ '''
30
+
31
+
32
+ from .tools import figure_tools as figure_t
33
+ from . import simulation
34
+
35
+ import matplotlib.pyplot as plt
36
+ import numpy as np
37
+
38
+
39
+ # curve type in plot
40
+ # used by UV_dyna, UV_std, and pi_dyna
41
+ CURVE_TYPE = '-'
42
+
43
+
44
+
45
+ def UV_heatmap(mod, ax_U = None, ax_V = None, U_color = 'Purples', V_color = 'Greens', start = 0.95, end = 1.0, annot = False, fmt = '.3g'):
46
+ '''
47
+ Makes two heatmaps for U, V average distribution over a time interval, respectively. Works best for 2D space.
48
+ 1D works as well, but figures look bad.
49
+
50
+ Inputs:
51
+ mod: A simulation.model object.
52
+ ax_U, ax_V: matplotlib axes to plot on. New axes will be created if None is given.
53
+ U_color: Color for U's heatmap, uses matplotlib color maps.
54
+ V_color: Color for V's heatmap.
55
+ start: (0,1) float, where the interval should start from. Intended as a 'percentage'.
56
+ For example, start = 0.8 means the interval should start from the 80% point of mod.maxtime.
57
+ end: (0,1) float, where the interval ends.
58
+ annot: bool, whether to add annotations (show exact numbers for every patch).
59
+ fmt: Number format for annotations. How many digits you want to keep. Please set annot = True first and then use fmt.
60
+
61
+ Returns:
62
+ ax_U, ax_V: matplotlib axes with heatmaps of U, V distribution plotted upon.
63
+ '''
64
+
65
+ start_index = int(start * mod.max_record)
66
+ end_index = int(end * mod.max_record)
67
+
68
+ # see ave_interval below
69
+ U_ave = figure_t.ave_interval(mod.U, start_index, end_index)
70
+ V_ave = figure_t.ave_interval(mod.V, start_index, end_index)
71
+
72
+ #### plot ####
73
+
74
+ U_title = figure_t.gen_title('Popu U', start, end)
75
+ U_text = figure_t.gen_text(np.mean(U_ave), np.std(U_ave))
76
+ V_title = figure_t.gen_title('Popu V', start, end)
77
+ V_text = figure_t.gen_text(np.mean(V_ave), np.std(V_ave))
78
+
79
+ ax_U = figure_t.heatmap(U_ave, ax_U, U_color, annot, fmt, U_title, U_text)
80
+ ax_V = figure_t.heatmap(V_ave, ax_V, V_color, annot, fmt, V_title, V_text)
81
+
82
+ return ax_U, ax_V
83
+
84
+
85
+
86
+ def UV_bar(mod, ax_U = None, ax_V = None, U_color = 'purple', V_color = 'green', start = 0.95, end = 1.0):
87
+ '''
88
+ Makes two barplots for U, V average distribution over a time interval. Works best for 1D space.
89
+ 2D works as well, but figures look bad.
90
+
91
+ Inputs:
92
+ mod: A simulation.model object.
93
+ ax_U, ax_V: matplotlib axes to plot on. New axes will be created if None is given.
94
+ U_color: Color of U's barplot. Uses Matplotlib colors.
95
+ See available colors at: https://matplotlib.org/stable/gallery/color/named_colors.html
96
+ V_color: Color of V's barplot. Uses Matplotlib colors.
97
+ start: (0,1) float. How much proportion of mod.maxtime you want the interval to start from.
98
+ end: (0,1) float. Where you want the interval to end.
99
+
100
+ Returns:
101
+ ax_U, ax_V: matplotlib axes with bar plots for U and V plotted upon.
102
+ '''
103
+
104
+ start_index = int(start * mod.max_record)
105
+ end_index = int(end * mod.max_record)
106
+
107
+ U_ave = figure_t.ave_interval_1D(mod.U, start_index, end_index)
108
+ V_ave = figure_t.ave_interval_1D(mod.V, start_index, end_index)
109
+
110
+ #### plot ####
111
+
112
+ U_title = figure_t.gen_title('Population U', start, end)
113
+ U_text = figure_t.gen_text(np.mean(U_ave), np.std(U_ave))
114
+ V_title = figure_t.gen_title('Population V', start, end)
115
+ V_text = figure_t.gen_text(np.mean(V_ave), np.std(V_ave))
116
+
117
+ ax_U = figure_t.bar(U_ave, ax = ax_U, color = U_color, xlabel = 'patches', ylabel = 'U', title = U_title, text = U_text)
118
+ ax_V = figure_t.bar(V_ave, ax = ax_V, color = V_color, xlabel = 'patches', ylabel = 'V', title = V_title, text = V_text)
119
+
120
+ return ax_U, ax_V
121
+
122
+
123
+
124
+
125
+ def UV_dyna(mod, ax = None, interval = 20, grid = True):
126
+ '''
127
+ Plots how total U, V change overtime.
128
+ The curves are not directly based on every single data point.
129
+ Rather, it takes the average over many intervals of points to smooth out local fluctuations.
130
+ For example, interval = 20 means the first point on the curves are based on the average value of data points 0~19.
131
+ So if there are 2000 data points in total, then there will be 2000 / 20 = 100 points on the curves.
132
+
133
+ Inputs:
134
+ mod: A simulation.model object.
135
+ ax: matplotlib ax to plot on. New ax will be created if None is given.
136
+ interval: How many data points to take average over. Larger value makes curves smoother, but also loses local fluctuations.
137
+ NOTE: this interval doesn't overlap with mod.compress_itv.
138
+ e.g. you already took average over every 20 data points, then using interval <= 20 here has no smoothing effect.
139
+ grid: Whether to add grid lines to plot.
140
+
141
+ Returns:
142
+ ax: matplotlib ax, contains U's, V's, and sum of U & V population.
143
+ '''
144
+
145
+ # store the average values in lists
146
+ U_curve = []
147
+ V_curve = []
148
+ total_curve = []
149
+
150
+ interval = figure_t.scale_interval(interval, mod.compress_itv)
151
+ interval_num = int(mod.max_record / interval)
152
+
153
+ for i in range(interval_num):
154
+ U_ave = figure_t.ave_interval(mod.U, i * interval, (i + 1) * interval)
155
+ V_ave = figure_t.ave_interval(mod.V, i * interval, (i + 1) * interval)
156
+
157
+ U_curve.append(np.sum(U_ave))
158
+ V_curve.append(np.sum(V_ave))
159
+ total_curve.append(U_curve[-1] + V_curve[-1])
160
+
161
+ #### plot ####
162
+ xaxis = np.linspace(0, mod.maxtime, len(U_curve))
163
+
164
+ if ax == None:
165
+ _, ax = plt.subplots()
166
+ ax.grid(grid)
167
+ ax.plot(xaxis, U_curve, CURVE_TYPE, label = 'U')
168
+ ax.plot(xaxis, V_curve, CURVE_TYPE, label = 'V')
169
+ ax.plot(xaxis, total_curve, CURVE_TYPE, label = 'total')
170
+ ax.set_xlabel('Time')
171
+ ax.set_ylabel('Population')
172
+ ax.set_title('Population U & V Over Time')
173
+ ax.legend()
174
+
175
+ return ax
176
+
177
+
178
+
179
+
180
+ def UV_hist(mod, ax_U = None, ax_V = None, U_color = 'purple', V_color = 'green', start = 0.95, end = 1.0):
181
+ '''
182
+ Makes density histograms for U, V's average distribution over an interval.
183
+ Sometimes it may not be shown in density plots due to matplotlib features.
184
+
185
+ Returns:
186
+ ax_U, ax_V: matplotlib axes with heatmaps of U, V population density plotted upon.
187
+ '''
188
+
189
+ start_index = int(start * mod.max_record)
190
+ end_index = int(end * mod.max_record)
191
+
192
+ U_ave = figure_t.ave_interval_1D(mod.U, start_index, end_index)
193
+ V_ave = figure_t.ave_interval_1D(mod.V, start_index, end_index)
194
+
195
+ #### plot ####
196
+
197
+ if ax_U == None:
198
+ _, ax_U = plt.subplots()
199
+ ax_U.set_xlabel('Population U')
200
+ ax_U.set_ylabel('Density')
201
+ ax_U.hist(U_ave, color = U_color, density = True)
202
+ ax_U.set_title(figure_t.gen_title('U Hist', start, end))
203
+
204
+ if ax_V == None:
205
+ _, ax_V = plt.subplots()
206
+ ax_V.set_xlabel('Population V')
207
+ ax_V.set_ylabel('Density')
208
+ ax_V.hist(V_ave, color = V_color, density = True)
209
+ ax_V.set_title(figure_t.gen_title('V Hist', start, end))
210
+
211
+ return ax_U, ax_V
212
+
213
+
214
+
215
+
216
+ def UV_std(mod, ax = None, interval = 20, grid = True):
217
+ '''
218
+ Plots how standard deviation of U, V change over time.
219
+ Takes average over many small interval to smooth out local fluctuations.
220
+
221
+ Returns:
222
+ ax: matplotlib ax, contains U's and V's std curves.
223
+ '''
224
+
225
+ interval = figure_t.scale_interval(interval, mod.compress_itv)
226
+ interval_num = int(mod.max_record / interval)
227
+
228
+ U_std = []
229
+ V_std = []
230
+
231
+ for i in range(interval_num):
232
+ U_ave = figure_t.ave_interval(mod.U, i * interval, (i + 1) * interval)
233
+ V_ave = figure_t.ave_interval(mod.V, i * interval, (i + 1) * interval)
234
+
235
+ U_std.append(np.std(U_ave))
236
+ V_std.append(np.std(V_ave))
237
+
238
+ #### plot ####
239
+ xaxis = np.linspace(0, mod.maxtime, len(U_std))
240
+
241
+ if ax == None:
242
+ _, ax = plt.subplots()
243
+ ax.grid(grid)
244
+ ax.plot(xaxis, U_std, CURVE_TYPE, label = 'U std')
245
+ ax.plot(xaxis, V_std, CURVE_TYPE, label = 'V std')
246
+ ax.legend()
247
+ ax.set_xlabel('Time')
248
+ ax.set_ylabel('Std Dev')
249
+ ax.set_title('Population Std-Dev Dynamics')
250
+
251
+ return ax
252
+
253
+
254
+
255
+ def UV_expected(mod, ax_U = None, ax_V = None, U_color = 'Purples', V_color = 'Greens', annot = False, fmt = '.3g'):
256
+ '''
257
+ Calculate expected population distribution based on matrices, assuming no migration.
258
+ For the formulas, see stochastic_mode.expected_UV
259
+
260
+ Some Inputs:
261
+ Note the colors are color maps.
262
+
263
+ Returns:
264
+ ax_U, ax_V: If 2D (N and M both > 1), then ax_U and ax_V are heatmaps.
265
+ If 1D (N or M == 1), then ax_U and ax_V are barplots.
266
+ '''
267
+
268
+ U_expected, V_expected = simulation.UV_expected_val(mod)
269
+
270
+ U_text = figure_t.gen_text(np.mean(U_expected), np.std(U_expected))
271
+ V_text = figure_t.gen_text(np.mean(V_expected), np.std(V_expected))
272
+
273
+ #### plot ####
274
+
275
+ if (mod.N != 1) and (mod.M != 1):
276
+ # 2D
277
+ ax_U = figure_t.heatmap(U_expected, ax_U, U_color, annot, fmt, title = 'Expected U', text = U_text)
278
+ ax_V = figure_t.heatmap(V_expected, ax_V, V_color, annot, fmt, title = 'Expected V', text = V_text)
279
+
280
+ else:
281
+ # 1D
282
+ ax_U = figure_t.bar(U_expected.flatten(), ax_U, color = U_color, xlabel = 'patches', ylabel = 'popu', title = 'Expected Population U', text = U_text)
283
+ ax_V = figure_t.bar(V_expected.flatten(), ax_V, color = V_color, xlabel = 'patches', ylabel = 'popu', title = 'Expected Population V', text = V_text)
284
+
285
+ return ax_U, ax_V
286
+
287
+
288
+
289
+
290
+ def pi_heatmap(mod, ax_U = None, ax_V = None, U_color = 'BuPu', V_color = 'YlGn', start = 0.95, end = 1.0, annot = False, fmt = '.3g'):
291
+ '''
292
+ Make heatmaps for payoff in a specified interval.
293
+ Works best for 2D. 1D works as well, but figures look bad.
294
+
295
+ Some Inputs:.
296
+ Note the colors are matplotlib color maps.
297
+
298
+ Returns:
299
+ ax_U, ax_V: Seaborn heatmaps, for U's & V's payoff distribution, respectively.
300
+ '''
301
+
302
+ start_index = int(mod.max_record * start)
303
+ end_index = int(mod.max_record * end)
304
+
305
+ Upi_ave = figure_t.ave_interval(mod.Upi, start_index, end_index)
306
+ V_pi_ave = figure_t.ave_interval(mod.Vpi, start_index, end_index)
307
+
308
+ U_title = figure_t.gen_title('Payoff ' + r'$p_U$', start, end)
309
+ U_text = figure_t.gen_text(np.mean(Upi_ave), np.std(Upi_ave))
310
+ V_title = figure_t.gen_title('Payoff ' + r'$p_V$', start, end)
311
+ V_text = figure_t.gen_text(np.mean(V_pi_ave), np.std(V_pi_ave))
312
+
313
+ ax_U = figure_t.heatmap(Upi_ave, ax_U, U_color, annot, fmt, U_title, U_text)
314
+ ax_V = figure_t.heatmap(V_pi_ave, ax_V, V_color, annot, fmt, V_title, V_text)
315
+
316
+ return ax_U, ax_V
317
+
318
+
319
+
320
+
321
+ def pi_bar(mod, ax_U = None, ax_V = None, U_color = 'violet', V_color = 'yellowgreen', start = 0.95, end = 1.0):
322
+ '''
323
+ Make barplot for payoff in a specified interval.
324
+ Works best for 1D. 2D works as well, but figures look bad.
325
+
326
+ Returns:
327
+ ax_U, ax_V: matplotlib axes with barplots of U and V payoff distribution plotted upon.
328
+ '''
329
+
330
+ start_index = int(mod.max_record * start)
331
+ end_index = int(mod.max_record * end)
332
+
333
+ Upi_ave = figure_t.ave_interval_1D(mod.Upi, start_index, end_index)
334
+ V_pi_ave = figure_t.ave_interval_1D(mod.Vpi, start_index, end_index)
335
+
336
+ U_title = figure_t.gen_title(r'$p_U$', start, end)
337
+ U_text = figure_t.gen_text(np.mean(Upi_ave), np.std(Upi_ave))
338
+ V_title = figure_t.gen_title(r'$p_V$', start, end)
339
+ V_text = figure_t.gen_text(np.mean(V_pi_ave), np.std(V_pi_ave))
340
+
341
+ ax_U = figure_t.bar(Upi_ave, ax_U, U_color, 'Patches', 'Payoff ' + r'$p_U$', U_title, U_text)
342
+ ax_V = figure_t.bar(V_pi_ave, ax_V, V_color, 'Patches', 'Payoff ' + r'$p_V$', V_title, V_text)
343
+
344
+ return ax_U, ax_V
345
+
346
+
347
+
348
+
349
+ def pi_dyna(mod, ax = None, interval = 20, grid = True):
350
+ '''
351
+ Plot how payoffs change over time.
352
+
353
+ Returns:
354
+ ax: matplotlib ax of U's, V's, and sum of U & V payoff.
355
+ '''
356
+
357
+ U_curve = []
358
+ V_curve = []
359
+ total_curve = []
360
+
361
+ interval = figure_t.scale_interval(interval, mod.compress_itv)
362
+ interval_num = int(mod.max_record / interval)
363
+
364
+ for i in range(interval_num):
365
+ U_ave = figure_t.ave_interval(mod.Upi, i * interval, (i + 1) * interval)
366
+ V_ave = figure_t.ave_interval(mod.Vpi, i * interval, (i + 1) * interval)
367
+
368
+ U_curve.append(np.sum(U_ave))
369
+ V_curve.append(np.sum(V_ave))
370
+ total_curve.append(U_curve[-1] + V_curve[-1])
371
+
372
+ #### plot ####
373
+ xaxis = np.linspace(0, mod.maxtime, len(U_curve))
374
+
375
+ if ax == None:
376
+ _, ax = plt.subplots()
377
+ ax.grid(grid)
378
+ ax.plot(xaxis, U_curve, CURVE_TYPE, label = r'$p_U$')
379
+ ax.plot(xaxis, V_curve, CURVE_TYPE, label = r'$p_V$')
380
+ ax.plot(xaxis, total_curve, CURVE_TYPE, label = 'total')
381
+ ax.set_xlabel('Time')
382
+ ax.set_ylabel('Payoff')
383
+ ax.set_title('Payoff ' + r'$p_U$' + ' & ' + r'$p_V$' + ' over time')
384
+ ax.legend()
385
+
386
+ return ax
387
+
388
+
389
+
390
+
391
+ def pi_hist(mod, ax_U = None, ax_V = None, U_color = 'violet', V_color = 'yellowgreen', start = 0.95, end = 1.0):
392
+ '''
393
+ Makes deensity histograms of U's and V's payoffs in a sepcified interval.
394
+ Sometimes it may not be shown in density plots due to matplotlib features.
395
+
396
+ Returns:
397
+ ax_U, ax_V: histogram of U's and V's payoff.
398
+ '''
399
+
400
+ start_index = int(start * mod.max_record)
401
+ end_index = int(end * mod.max_record)
402
+
403
+ Upi_ave = figure_t.ave_interval_1D(mod.Upi, start_index, end_index)
404
+ V_pi_ave = figure_t.ave_interval_1D(mod.Vpi, start_index, end_index)
405
+
406
+ #### plot ####
407
+
408
+ if ax_U == None:
409
+ _, ax_U = plt.subplots()
410
+ ax_U.set_xlabel('Payoff ' + r'$p_U$')
411
+ ax_U.set_ylabel('Density')
412
+ ax_U.hist(Upi_ave, color = U_color, density = True)
413
+ ax_U.set_title(figure_t.gen_title('Payoff ' + r'$p_U$' + ' Hist', start, end))
414
+
415
+ if ax_V == None:
416
+ _, ax_V = plt.subplots()
417
+ ax_V.set_xlabel('Payoff ' + r'$p_V$')
418
+ ax_V.set_ylabel('Density')
419
+ ax_V.hist(V_pi_ave, color = V_color, density = True)
420
+ ax_V.set_title(figure_t.gen_title('Payoff ' + r'$p_V$' + ' Hist', start, end))
421
+
422
+ return ax_U, ax_V
423
+
424
+
425
+
426
+
427
+ def pi_std(mod, ax = None, interval = 20, grid = True):
428
+ '''
429
+ Plots how standard deviation of payoff change over time.
430
+
431
+ Returns:
432
+ ax: matplotlib ax of the std of payoffs.
433
+ '''
434
+
435
+
436
+ interval = figure_t.scale_interval(interval, mod.compress_itv)
437
+ interval_num = int(mod.max_record / interval)
438
+
439
+ Upi_std = []
440
+ V_pi_std = []
441
+
442
+ for i in range(interval_num):
443
+ Upi_ave = figure_t.ave_interval(mod.Upi, i * interval, (i + 1) * interval)
444
+ V_pi_ave = figure_t.ave_interval(mod.Vpi, i * interval, (i + 1) * interval)
445
+
446
+ Upi_std.append(np.std(Upi_ave))
447
+ V_pi_std.append(np.std(V_pi_ave))
448
+
449
+ #### plot ####
450
+ xaxis = np.linspace(0, mod.maxtime, len(Upi_std))
451
+
452
+ if ax == None:
453
+ _, ax = plt.subplots()
454
+ ax.grid(grid)
455
+ ax.plot(xaxis, Upi_std, CURVE_TYPE, label = r'$p_U$' + ' std')
456
+ ax.plot(xaxis, V_pi_std, CURVE_TYPE, label = r'$p_V$' + ' std')
457
+ ax.legend()
458
+ ax.set_xlabel('Time')
459
+ ax.set_ylabel('Std Dev')
460
+ ax.set_title('Payoff Std-Dev Dynamics')
461
+
462
+ return ax
463
+
464
+
465
+
466
+
467
+ def UV_pi(mod, ax_U = None, ax_V = None, U_color = 'violet', V_color = 'yellowgreen', alpha = 0.5, start = 0.95, end = 1.0):
468
+ '''
469
+ Make two scatter plots: x-axes are population and y-axes are payoff in a specified time interval.
470
+ Reveals relationship between population and payoff.
471
+
472
+ Returns:
473
+ ax_U, ax_V: matplotlib axes with U and V population-payoff scatter plots.
474
+ '''
475
+
476
+ start_index = int(start * mod.max_record)
477
+ end_index = int(end * mod.max_record)
478
+
479
+ U_ave = figure_t.ave_interval_1D(mod.U, start_index, end_index)
480
+ V_ave = figure_t.ave_interval_1D(mod.V, start_index, end_index)
481
+
482
+ Upi_ave = figure_t.ave_interval(mod.Upi, start_index, end_index)
483
+ V_pi_ave = figure_t.ave_interval(mod.Vpi, start_index, end_index)
484
+
485
+
486
+ ax_U = figure_t.scatter(U_ave, Upi_ave, ax_U, U_color, alpha, xlabel = 'U', ylabel = 'Payoff ' + r'$p_U$', title = 'U - ' + r'$p_U$')
487
+ ax_V = figure_t.scatter(V_ave, V_pi_ave, ax_V, V_color, alpha, xlabel = 'V', ylabel = 'Payoff ' + r'$p_V$', title = 'V - ' + r'$p_V$')
488
+
489
+ return ax_U, ax_V
490
+
491
+