aabpl 0.1.0__py3-none-any.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.
- aabpl/__init__.py +24 -0
- aabpl/doc/__init__.py +0 -0
- aabpl/doc/docstrings.py +12 -0
- aabpl/illustrations/__init__.py +4 -0
- aabpl/illustrations/distribution_plot.py +109 -0
- aabpl/illustrations/illustrate_cell_pattern.py +75 -0
- aabpl/illustrations/illustrate_nested_grid.py +90 -0
- aabpl/illustrations/illustrate_optimal_grid_spacing.py +294 -0
- aabpl/illustrations/illustrate_point_to_cell_region_assignment.py +368 -0
- aabpl/illustrations/illustrate_point_to_disk.py +148 -0
- aabpl/illustrations/plot_pt_vars.py +59 -0
- aabpl/illustrations/plot_utils.py +489 -0
- aabpl/main.py +317 -0
- aabpl/radius_search/__init__.py +0 -0
- aabpl/radius_search/grid_class.py +272 -0
- aabpl/radius_search/nested_search.py +557 -0
- aabpl/radius_search/offset_region_classes.py +752 -0
- aabpl/radius_search/offset_regions.py +904 -0
- aabpl/radius_search/optimal_grid_spacing.py +258 -0
- aabpl/radius_search/pts_radius_search.py +194 -0
- aabpl/radius_search/pts_to_cells.py +131 -0
- aabpl/radius_search/pts_to_offset_regions.py +591 -0
- aabpl/radius_search/radius_search_class.py +405 -0
- aabpl/radius_search/two_dimensional_weak_ordering_class.py +503 -0
- aabpl/random_distribution.py +218 -0
- aabpl/testing/__init__.py +0 -0
- aabpl/testing/test_performance.py +237 -0
- aabpl/utils/__init__.py +0 -0
- aabpl/utils/distances_to_cell.py +550 -0
- aabpl/utils/general.py +229 -0
- aabpl/utils/intersections.py +186 -0
- aabpl/utils/rotations.py +138 -0
- aabpl/valid_area.py +38 -0
- aabpl-0.1.0.dist-info/LICENSE +21 -0
- aabpl-0.1.0.dist-info/METADATA +171 -0
- aabpl-0.1.0.dist-info/RECORD +42 -0
- aabpl-0.1.0.dist-info/WHEEL +5 -0
- aabpl-0.1.0.dist-info/top_level.txt +1 -0
- primelocations/__init__.py +21 -0
- primelocations/main.py +273 -0
- primelocations/random_distribution.py +219 -0
- primelocations/valid_area.py +38 -0
aabpl/__init__.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# from importlib.metadata import version
|
|
2
|
+
# TODO replace * with more expliced exports for the final version of the package
|
|
3
|
+
# # from .radius_search import *
|
|
4
|
+
# import utils
|
|
5
|
+
# import testing
|
|
6
|
+
# import illustrations
|
|
7
|
+
# import radius_search
|
|
8
|
+
from . import main
|
|
9
|
+
# from .main import *
|
|
10
|
+
# from .radius_search.optimal_grid_spacing import *
|
|
11
|
+
# from .radius_search.offset_regions import *
|
|
12
|
+
# from ..utils.general import *
|
|
13
|
+
# from ..illustrations.illustrate_nested_grid import *
|
|
14
|
+
# from ..illustrations.illustrate_optimal_grid_spacing import *
|
|
15
|
+
# from ..illustrations.illustrate_point_to_cell_region_assignment import *
|
|
16
|
+
# # from .nested_search import *
|
|
17
|
+
# from .radius_search.radius_search_class import *
|
|
18
|
+
# from ..illustrations.plot_utils import *
|
|
19
|
+
# from .radius_search.two_dimensional_weak_ordering_class import *
|
|
20
|
+
# from .main import *
|
|
21
|
+
# from ..illustrations.plot_utils import *
|
|
22
|
+
# TODO ensure to no exports imports (like np.array)?
|
|
23
|
+
|
|
24
|
+
# __version__ = version('primelocations')
|
aabpl/doc/__init__.py
ADDED
|
File without changes
|
aabpl/doc/docstrings.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
arguments_to_replace = list({
|
|
2
|
+
'<y_coord_name>':(
|
|
3
|
+
"""x (numpy.array):
|
|
4
|
+
Array of x/longtitude coordinates"""
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
}.items())
|
|
8
|
+
|
|
9
|
+
def fixdocstring(func):
|
|
10
|
+
# for k,v in arguments_to_replace:
|
|
11
|
+
# func.__doc__ = func.__doc__.replace(k, v)
|
|
12
|
+
return func
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from pandas import DataFrame as _pd_DataFrame
|
|
2
|
+
from numpy import (
|
|
3
|
+
array as _np_array,
|
|
4
|
+
linspace as _np_linspace,
|
|
5
|
+
searchsorted as _np_searchsorted
|
|
6
|
+
)
|
|
7
|
+
from matplotlib.pyplot import (subplots as _plt_subplots)
|
|
8
|
+
|
|
9
|
+
def create_distribution_plot(
|
|
10
|
+
sums_df:_pd_DataFrame,
|
|
11
|
+
cluster_threshold_values:list,
|
|
12
|
+
k_th_percentiles:list,
|
|
13
|
+
radius=None,
|
|
14
|
+
plot_kwargs:dict={},
|
|
15
|
+
):
|
|
16
|
+
"""
|
|
17
|
+
TODO Descripiton
|
|
18
|
+
"""
|
|
19
|
+
(n_random_points, ncols) = sums_df.shape
|
|
20
|
+
# specify default plot kwargs and add defaults
|
|
21
|
+
default_kwargs = {
|
|
22
|
+
's':0.8,
|
|
23
|
+
'color':'#eaa',
|
|
24
|
+
|
|
25
|
+
'figsize': (5*ncols,5),
|
|
26
|
+
'fig':None,
|
|
27
|
+
'axs':None,
|
|
28
|
+
|
|
29
|
+
'hlines':{'color':'red', 'linewidth':1},
|
|
30
|
+
'vlines':{'color':'red', 'linewidth':1},
|
|
31
|
+
}
|
|
32
|
+
kwargs = {}
|
|
33
|
+
for k in plot_kwargs:
|
|
34
|
+
if k in [k for k,v in default_kwargs.items() if type(v)==dict]:
|
|
35
|
+
kwargs[k] = {**default_kwargs.pop(k), **plot_kwargs.pop(k)}
|
|
36
|
+
kwargs.update(default_kwargs)
|
|
37
|
+
kwargs.update(plot_kwargs)
|
|
38
|
+
figsize = kwargs.pop('figsize')
|
|
39
|
+
fig = kwargs.pop('fig')
|
|
40
|
+
axs = kwargs.pop('axs')
|
|
41
|
+
|
|
42
|
+
if fig is None or axs is None:
|
|
43
|
+
fig, axs = _plt_subplots(1,ncols, figsize=figsize)
|
|
44
|
+
|
|
45
|
+
fig.suptitle(
|
|
46
|
+
"Values for indicator" + ("" if ncols==1 else "s") +
|
|
47
|
+
("" if radius is None else (" within "+ str(radius) +" distance")) +
|
|
48
|
+
" around " + str(n_random_points)+ " randomly points drawn within valid area."
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
xmin, xmax = 0, 100
|
|
52
|
+
xs = _np_linspace(xmin,xmax,n_random_points)
|
|
53
|
+
vals = sums_df.values
|
|
54
|
+
colnames = sums_df.columns
|
|
55
|
+
|
|
56
|
+
for (i, colname, cluster_threshold_value, k_th_percentile) in zip(
|
|
57
|
+
range(ncols), colnames, cluster_threshold_values, k_th_percentiles):
|
|
58
|
+
ys = vals[:,i]
|
|
59
|
+
ys.sort()
|
|
60
|
+
ymin, ymax = ys.min(),ys.max()
|
|
61
|
+
# round percentile value as far as necessary only
|
|
62
|
+
# e.g. threshold value is 10.5328... and next smaller/larger in distribution are 10.51..., 10.6...
|
|
63
|
+
# rounding to threshold value to firrst digit s.t. thath it lies between those value is sufficient (e.g. 10.53)
|
|
64
|
+
idx = _np_searchsorted(ys, cluster_threshold_value)
|
|
65
|
+
next_smaller_val, next_larger_val = ys[max([0,idx-1])], ys[idx]
|
|
66
|
+
sufficient_digits = next((
|
|
67
|
+
i for i in range(100) if (
|
|
68
|
+
(
|
|
69
|
+
(next_smaller_val == next_larger_val or cluster_threshold_values==next_smaller_val) and
|
|
70
|
+
round(next_smaller_val,i)==next_smaller_val
|
|
71
|
+
) or (
|
|
72
|
+
round(next_larger_val, i) != round(cluster_threshold_value, i) and
|
|
73
|
+
round(next_smaller_val, i) != round(cluster_threshold_value, i)
|
|
74
|
+
)
|
|
75
|
+
)),100)
|
|
76
|
+
|
|
77
|
+
ax_title = (
|
|
78
|
+
"Threshold value for "+str(k_th_percentile)+"th-percentile is "+
|
|
79
|
+
str(round(cluster_threshold_value, sufficient_digits)) + " for "+ colname
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# SELECT AX (IF MULTIPLE)
|
|
83
|
+
ax = axs.flat[i] if ncols > 1 else axs
|
|
84
|
+
|
|
85
|
+
# SET TITLE
|
|
86
|
+
ax.set_title(ax_title)
|
|
87
|
+
|
|
88
|
+
# SET TICKS
|
|
89
|
+
xtick_steps, ytick_steps = 5, 5
|
|
90
|
+
xticks = _np_array(sorted(
|
|
91
|
+
[x for x in _np_linspace(xmin,xmax,xtick_steps) if abs(x-k_th_percentile) > (xmax-xmin)/(xtick_steps*2)] +
|
|
92
|
+
[k_th_percentile]
|
|
93
|
+
))
|
|
94
|
+
ax.set_xticks(xticks, labels=xticks)
|
|
95
|
+
yticks = _np_array(sorted([y for y in _np_linspace(ymin,ymax,ytick_steps) if abs(cluster_threshold_value-y)>(ymax-ymin)/(ytick_steps*10)] + [cluster_threshold_value]))
|
|
96
|
+
ax.set_yticks(yticks, labels=[round(t, sufficient_digits) for t in yticks])
|
|
97
|
+
|
|
98
|
+
# ADD CUTOFF LINES
|
|
99
|
+
ax.hlines(y=cluster_threshold_value, xmin=xmin,xmax=xmax, **kwargs.pop('hlines'))
|
|
100
|
+
ax.vlines(x=k_th_percentile, ymin=ymin,ymax=ymax, **kwargs.pop('vlines'))
|
|
101
|
+
|
|
102
|
+
# ADD DISTRIUBTION PLOT
|
|
103
|
+
ax.scatter(x=xs,y=ys, **plot_kwargs)
|
|
104
|
+
|
|
105
|
+
# SET LIMITS
|
|
106
|
+
ax.set_xlim([xmin,xmax])
|
|
107
|
+
ax.set_ylim([ymin,ymax])
|
|
108
|
+
#
|
|
109
|
+
#
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from numpy import (
|
|
2
|
+
array as _np_array,
|
|
3
|
+
unique as _np_unique,
|
|
4
|
+
linspace, invert, flip, transpose,
|
|
5
|
+
concatenate,
|
|
6
|
+
sign as _np_sign,
|
|
7
|
+
zeros, min, max, equal, where,
|
|
8
|
+
logical_or, logical_and, all, newaxis
|
|
9
|
+
)
|
|
10
|
+
from math import ceil as _math_ceil
|
|
11
|
+
from pandas import DataFrame as _pd_DataFrame
|
|
12
|
+
from matplotlib.pyplot import (subplots as _plt_subplots, figure as _plt_figure)
|
|
13
|
+
from matplotlib.patches import Circle as _plt_circle, Rectangle as _plt_Rectangle
|
|
14
|
+
from matplotlib.figure import Figure as _plt_Figure
|
|
15
|
+
from matplotlib.axes._axes import Axes as _plt_Axes
|
|
16
|
+
from .plot_utils import (
|
|
17
|
+
create_grid_cell_patches, create_grid_cell_patches_by_type, create_grid_cell_rectangles,
|
|
18
|
+
create_trgl1_patch, create_buffered_trgl1_patch, create_buffered_square_patch, create_debuffered_square_patch, create_debuffered_trgl1_patch, dual_circle_union_patch,
|
|
19
|
+
)
|
|
20
|
+
from .illustrate_point_to_cell_region_assignment import (add_grid_cell_rectangles_by_color,add_circle_patches,)
|
|
21
|
+
from ..utils.distances_to_cell import ( get_cells_relevant_for_disk_by_type, get_cell_farthest_vertex_to_point, )
|
|
22
|
+
from ..utils.general import ( flatten_list, )
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def plot_cell_pattern(
|
|
26
|
+
contained_cells,
|
|
27
|
+
overlapped_cells,
|
|
28
|
+
all_cells,
|
|
29
|
+
radius:float,
|
|
30
|
+
grid_spacing:float,
|
|
31
|
+
add_idxs:bool=True,
|
|
32
|
+
**plot_kwargs,
|
|
33
|
+
):
|
|
34
|
+
|
|
35
|
+
"""
|
|
36
|
+
Illustrate method
|
|
37
|
+
"""
|
|
38
|
+
# specify default plot kwargs and add defaults
|
|
39
|
+
plot_kwargs = {
|
|
40
|
+
'fig':None,
|
|
41
|
+
'ax':None,
|
|
42
|
+
's':0.8,
|
|
43
|
+
'color':'#eaa',
|
|
44
|
+
'figsize': (20,30),
|
|
45
|
+
**plot_kwargs
|
|
46
|
+
}
|
|
47
|
+
figsize = plot_kwargs.pop('figsize')
|
|
48
|
+
fig = plot_kwargs.pop('fig')
|
|
49
|
+
ax = plot_kwargs.pop('ax')
|
|
50
|
+
###### initialize plot ######################
|
|
51
|
+
|
|
52
|
+
if ax is None:
|
|
53
|
+
fig, ax = _plt_subplots(1,1, figsize=figsize)
|
|
54
|
+
################################################################################################################
|
|
55
|
+
colors = ['#ccc', 'green', 'red']
|
|
56
|
+
for (row, col), color in flatten_list(
|
|
57
|
+
[[((row, col), color) for row, col in cells] for cells,color in zip(
|
|
58
|
+
[all_cells, contained_cells, overlapped_cells],
|
|
59
|
+
colors)]):
|
|
60
|
+
ax.add_patch(_plt_Rectangle(
|
|
61
|
+
xy = (col-0.5, row-0.5),
|
|
62
|
+
width=1, height=1,
|
|
63
|
+
linewidth=.7, facecolor=color, edgecolor=color, alpha=0.3
|
|
64
|
+
))
|
|
65
|
+
if add_idxs and color == colors[0]:
|
|
66
|
+
ax.annotate(text=str(row)+","+str(col), xy=(col,row),horizontalalignment='center')
|
|
67
|
+
|
|
68
|
+
ratio = radius/grid_spacing
|
|
69
|
+
cell_steps_max = _math_ceil(ratio+1.5)
|
|
70
|
+
|
|
71
|
+
ax.set_xlim((-cell_steps_max,+cell_steps_max))
|
|
72
|
+
ax.set_ylim((-cell_steps_max,+cell_steps_max))
|
|
73
|
+
ax.set_aspect('equal', adjustable='box')
|
|
74
|
+
#
|
|
75
|
+
#
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from numpy import (
|
|
2
|
+
array,
|
|
3
|
+
unique as _np_unique,
|
|
4
|
+
ones as _np_ones,
|
|
5
|
+
linspace, invert, flip, transpose, concatenate, sign, zeros, min, max,
|
|
6
|
+
equal, where, logical_or, logical_and, all, newaxis
|
|
7
|
+
)
|
|
8
|
+
from matplotlib.pyplot import (get_cmap as _plt_get_cmap, subplots as _plt_subplots)
|
|
9
|
+
from matplotlib.patches import Rectangle as _plt_Rectangle
|
|
10
|
+
|
|
11
|
+
from .plot_utils import (
|
|
12
|
+
create_grid_cell_patches,
|
|
13
|
+
create_grid_cell_patches_by_type,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def illustrate_nested_grid(
|
|
18
|
+
grid:dict,
|
|
19
|
+
pts_lat_lon,
|
|
20
|
+
cell_ids,
|
|
21
|
+
y_min:float=None,
|
|
22
|
+
y_max:float=None,
|
|
23
|
+
x_min:float=None,
|
|
24
|
+
x_max:float=None,
|
|
25
|
+
):
|
|
26
|
+
|
|
27
|
+
"""
|
|
28
|
+
Illustrate method
|
|
29
|
+
"""
|
|
30
|
+
# unpack vals
|
|
31
|
+
grid_spacing = grid.spacing
|
|
32
|
+
nested_grid = grid['nested']
|
|
33
|
+
|
|
34
|
+
# filter pts to be inside bounds:
|
|
35
|
+
filter_mask = _np_ones(len(pts_lat_lon),dtype=bool)
|
|
36
|
+
if y_min != None:
|
|
37
|
+
filter_mask = filter_mask * (pts_lat_lon[:,0]>=y_min)
|
|
38
|
+
if y_max != None:
|
|
39
|
+
filter_mask = filter_mask * (pts_lat_lon[:,0]<=y_max)
|
|
40
|
+
if x_min != None:
|
|
41
|
+
filter_mask = filter_mask * (pts_lat_lon[:,1]>=x_min)
|
|
42
|
+
if x_max != None:
|
|
43
|
+
filter_mask = filter_mask * (pts_lat_lon[:,1]<=x_max)
|
|
44
|
+
|
|
45
|
+
pts_lat_lon = pts_lat_lon[filter_mask]
|
|
46
|
+
cell_ids = cell_ids[filter_mask]
|
|
47
|
+
print('N Pts:',len(cell_ids), 'in', len(_np_unique(cell_ids)),'cells.')
|
|
48
|
+
|
|
49
|
+
def unpackNestedGrid(cell_dict:dict, nest_lvl:int=0):
|
|
50
|
+
"""
|
|
51
|
+
TODO Check to move it outside as independent functions
|
|
52
|
+
"""
|
|
53
|
+
res = []
|
|
54
|
+
if 'quadrants' in cell_dict:
|
|
55
|
+
for quadrant in cell_dict['quadrants']:
|
|
56
|
+
res += unpackNestedGrid(cell_dict=quadrant,nest_lvl=nest_lvl+1)
|
|
57
|
+
res += [(nest_lvl, tuple([*tuple([*cell_dict['bounds']])]))]
|
|
58
|
+
return res
|
|
59
|
+
|
|
60
|
+
flat_nested_grid = []
|
|
61
|
+
for cell_id in _np_unique(cell_ids):
|
|
62
|
+
flat_nested_grid += unpackNestedGrid(nested_grid[cell_id],nest_lvl=0)
|
|
63
|
+
|
|
64
|
+
flat_nested_grid = sorted(flat_nested_grid)
|
|
65
|
+
max_nest_level = flat_nested_grid[-1][0]
|
|
66
|
+
print('max_nest_level',max_nest_level)
|
|
67
|
+
cmp = _plt_get_cmap("YlOrBr",max_nest_level)
|
|
68
|
+
# print(flat_nested_grid)
|
|
69
|
+
nested_patches = [_plt_Rectangle(
|
|
70
|
+
# x y width height
|
|
71
|
+
(x_min, y_min), x_max-x_min, y_max-y_min,
|
|
72
|
+
linewidth=.7, facecolor=(cmp(nest_lvl) if max_nest_level>0 else 'grey'), edgecolor='#444', alpha=1
|
|
73
|
+
) for nest_lvl, ((y_min, x_min), (y_max, x_max) ) in flat_nested_grid]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
fig, ax = _plt_subplots(figsize=(15,10))
|
|
77
|
+
|
|
78
|
+
for patchToAdd in nested_patches:
|
|
79
|
+
ax.add_patch(patchToAdd)
|
|
80
|
+
|
|
81
|
+
ax.scatter(x=pts_lat_lon[:,1], y=pts_lat_lon[:,0], s=0.2,color='black')
|
|
82
|
+
x_steps = grid.x_steps
|
|
83
|
+
y_steps = grid.y_steps
|
|
84
|
+
ax.set_xticks(x_steps)
|
|
85
|
+
ax.set_yticks(y_steps)
|
|
86
|
+
ax.set_xlim(left=x_min, right=x_max)
|
|
87
|
+
ax.set_ylim(bottom=y_min, top=y_max)
|
|
88
|
+
ax.set_aspect('equal', adjustable='box')
|
|
89
|
+
ax.grid()
|
|
90
|
+
#
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
from numpy import (array, unique, linspace, invert, flip, transpose, concatenate, sign, zeros,
|
|
2
|
+
min as _np_min, max as _np_max, equal, where, logical_or, logical_and, all, newaxis)
|
|
3
|
+
from pandas import DataFrame as _pd_DataFrame
|
|
4
|
+
from matplotlib import pyplot as plt
|
|
5
|
+
from matplotlib.animation import (FuncAnimation as _plt_FuncAnimation, PillowWriter as _plt_PillowWriter)
|
|
6
|
+
from matplotlib.figure import Figure as _plt_Figure
|
|
7
|
+
from matplotlib.axes._axes import Axes as _plt_Axes
|
|
8
|
+
# from math import ceil,asin,acos
|
|
9
|
+
from .plot_utils import (
|
|
10
|
+
create_grid_cell_patches,
|
|
11
|
+
create_grid_cell_patches_by_type,
|
|
12
|
+
create_circle_patches
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
## Animation / GIF for varying grid spacings
|
|
16
|
+
|
|
17
|
+
def set_animation_frames(
|
|
18
|
+
relevantGridSizes:_pd_DataFrame,
|
|
19
|
+
allGridSizes:_pd_DataFrame,
|
|
20
|
+
largest:float=400,
|
|
21
|
+
frames_between_relevant:int = 6
|
|
22
|
+
)->list:
|
|
23
|
+
"""
|
|
24
|
+
Returns vector of gridsizes -> each grid_spacing will be an iteration frame
|
|
25
|
+
"""
|
|
26
|
+
# define GIF steps
|
|
27
|
+
animation_frames = [largest]
|
|
28
|
+
allGridSizes_indexes = list(allGridSizes.index)
|
|
29
|
+
|
|
30
|
+
for gridsize_0,gridsize_1 in zip(relevantGridSizes.index[:-1], relevantGridSizes.index[1:]):
|
|
31
|
+
|
|
32
|
+
pos_0, pos_1 = allGridSizes_indexes.index(gridsize_0), allGridSizes_indexes.index(gridsize_1)
|
|
33
|
+
|
|
34
|
+
#
|
|
35
|
+
if (pos_1-pos_0) > frames_between_relevant:
|
|
36
|
+
# number of position that should moved along per allGridSizes_indexes frame
|
|
37
|
+
stepsize_factor = (pos_1-pos_0)//frames_between_relevant
|
|
38
|
+
# move an aditional positon for the n<stepsize_adjust frames
|
|
39
|
+
stepsize_adjust = (pos_1-pos_0)%frames_between_relevant
|
|
40
|
+
|
|
41
|
+
animation_frames += [
|
|
42
|
+
allGridSizes_indexes[pos_0+s*stepsize_factor+int(stepsize_adjust<s)]
|
|
43
|
+
for s in range(frames_between_relevant)
|
|
44
|
+
]
|
|
45
|
+
else:
|
|
46
|
+
#
|
|
47
|
+
animation_frames += allGridSizes_indexes[pos_0+1:pos_1+1]
|
|
48
|
+
|
|
49
|
+
print('Animate GIF with '+str(len(animation_frames))+' frames.')
|
|
50
|
+
|
|
51
|
+
return animation_frames
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def add_coverage_plot(
|
|
55
|
+
fig:_plt_Figure,
|
|
56
|
+
allGridSizes:_pd_DataFrame,
|
|
57
|
+
ymax:float=3,
|
|
58
|
+
yticks:list=[.5,1]
|
|
59
|
+
) -> _plt_Axes:
|
|
60
|
+
"""
|
|
61
|
+
adds new axis to fig and create a stackplot on it that shows:
|
|
62
|
+
- percent of area within grid cells that are completly within
|
|
63
|
+
- stacked percent of area within grid cells that are potetially intersected
|
|
64
|
+
-
|
|
65
|
+
Returns: axes
|
|
66
|
+
"""
|
|
67
|
+
ax_coverage = fig.add_axes([0.6, 0.63, 0.3, 0.25])
|
|
68
|
+
|
|
69
|
+
ax_coverage.stackplot(
|
|
70
|
+
allGridSizes['grid_spacing'],allGridSizes['share_contain']*100,allGridSizes['share_overlap']*100,
|
|
71
|
+
colors=['green', 'red']
|
|
72
|
+
)
|
|
73
|
+
ax_coverage.plot(allGridSizes['grid_spacing'], allGridSizes['share_overlap']*100, color='#000')
|
|
74
|
+
min_x, max_x = min(allGridSizes['grid_spacing']),max(allGridSizes['grid_spacing'])
|
|
75
|
+
ax_coverage.set_xlim(min_x,max_x)
|
|
76
|
+
ax_coverage.set_ylim(0,100*ymax)
|
|
77
|
+
|
|
78
|
+
ax_coverage.set_yticks([100*x for x in sorted(yticks+[round(ymax)])])
|
|
79
|
+
|
|
80
|
+
# add hline at 100%
|
|
81
|
+
ax_coverage.hlines(y=100,xmin=min_x,xmax=max_x,linewidth=2,color='#000')
|
|
82
|
+
|
|
83
|
+
return ax_coverage
|
|
84
|
+
#
|
|
85
|
+
|
|
86
|
+
def add_cell_counter_plot(
|
|
87
|
+
fig:_plt_Figure,
|
|
88
|
+
allGridSizes:_pd_DataFrame,
|
|
89
|
+
ymax:float=3,
|
|
90
|
+
yticks:list=[.5,1]
|
|
91
|
+
) -> _plt_Axes:
|
|
92
|
+
"""
|
|
93
|
+
adds new axis to fig and create a step plot on that counts number of cells:
|
|
94
|
+
- which are fully contained s.t. the sum of emplyoment will be requested
|
|
95
|
+
- which (might be) intersected s.t. all points within will need to be checked whether they are within radius
|
|
96
|
+
Returns: axes
|
|
97
|
+
"""
|
|
98
|
+
ax_counter = fig.add_axes([0.6, 0.43, 0.3, 0.25])
|
|
99
|
+
|
|
100
|
+
ax_counter.plot(
|
|
101
|
+
allGridSizes['grid_spacing'], allGridSizes['contain_count'], color='green'
|
|
102
|
+
)
|
|
103
|
+
ax_counter.plot(
|
|
104
|
+
allGridSizes['grid_spacing'], allGridSizes['overlap_count'], color='red'
|
|
105
|
+
)
|
|
106
|
+
ax_counter.plot(allGridSizes['grid_spacing'], allGridSizes['overlap_count'], color='#000')
|
|
107
|
+
minx, maxx = min(allGridSizes['grid_spacing']),max(allGridSizes['grid_spacing'])
|
|
108
|
+
ax_counter.set_xlim(minx,maxx)
|
|
109
|
+
ax_counter.set_ylim(0,max(allGridSizes['contain_count']+allGridSizes['overlap_count']))
|
|
110
|
+
|
|
111
|
+
ax_counter.set_yticks(yticks)
|
|
112
|
+
|
|
113
|
+
return ax_counter
|
|
114
|
+
#
|
|
115
|
+
|
|
116
|
+
def update_fig_title(fig, grid_spacing:float,it:dict):
|
|
117
|
+
"""
|
|
118
|
+
updates fig.suptitle with rounded grid_spacing of current frame
|
|
119
|
+
"""
|
|
120
|
+
# display grid_spacing as title
|
|
121
|
+
gridsize_rnd = round(grid_spacing,2)
|
|
122
|
+
fig.suptitle(
|
|
123
|
+
(' ' if gridsize_rnd >= 100 else '') +
|
|
124
|
+
str(gridsize_rnd)[:5+int(gridsize_rnd >= 100)] +
|
|
125
|
+
'0'*max(0,len(str(gridsize_rnd))-int(gridsize_rnd >= 100)-3) +
|
|
126
|
+
'. Frame: '+str(it)
|
|
127
|
+
)
|
|
128
|
+
#
|
|
129
|
+
|
|
130
|
+
def update_main_axis_frame(
|
|
131
|
+
allGridSizes:_pd_DataFrame,
|
|
132
|
+
grid_spacing:float,
|
|
133
|
+
ax_main,
|
|
134
|
+
ax_min:float=0,
|
|
135
|
+
ax_max:float=1,
|
|
136
|
+
radius:float=750,
|
|
137
|
+
) -> list:
|
|
138
|
+
# clear previous picture
|
|
139
|
+
ax_main.clear()
|
|
140
|
+
|
|
141
|
+
listOfPatches = []
|
|
142
|
+
# create patches for grid cell: green=overlapped, red= (potentially) intersected, grey=outside
|
|
143
|
+
listOfPatches += create_grid_cell_patches(
|
|
144
|
+
grid_spacing=grid_spacing,
|
|
145
|
+
ax_min=ax_min,
|
|
146
|
+
ax_max=ax_max,
|
|
147
|
+
contain_cells_row_col=allGridSizes.loc[grid_spacing, 'contain_ids'],
|
|
148
|
+
overlap_cells_row_col=allGridSizes.loc[grid_spacing, 'overlap_ids'],
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# create patches for circle around bottom left and top right corner of center grid cell
|
|
152
|
+
listOfPatches += create_circle_patches(
|
|
153
|
+
grid_spacing=grid_spacing,
|
|
154
|
+
radius=radius
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
for patchToAdd in listOfPatches:
|
|
158
|
+
ax_main.add_patch(patchToAdd)
|
|
159
|
+
|
|
160
|
+
points = [p[0] for p in [
|
|
161
|
+
ax_main.plot(0, 0, marker='x', color='black'),
|
|
162
|
+
]]
|
|
163
|
+
|
|
164
|
+
# set tickmarks and limits
|
|
165
|
+
ax_main.set_yticks([radius-grid_spacing/2, radius, radius+grid_spacing/2])
|
|
166
|
+
ax_main.set_xticks([radius-grid_spacing/2, radius, radius+grid_spacing/2])
|
|
167
|
+
ax_main.set_xlim(ax_min,ax_max)
|
|
168
|
+
ax_main.set_ylim(ax_min,ax_max)
|
|
169
|
+
ax_main.set_aspect('equal', adjustable='box')
|
|
170
|
+
|
|
171
|
+
return *listOfPatches, *points, #, point1,
|
|
172
|
+
#
|
|
173
|
+
|
|
174
|
+
def update_coverage_axis_frame(
|
|
175
|
+
grid_spacing:float,
|
|
176
|
+
max_gridsize:float,
|
|
177
|
+
min_gridsize:float,
|
|
178
|
+
ax_coverage,
|
|
179
|
+
vline,
|
|
180
|
+
) -> tuple:
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
"""
|
|
184
|
+
# update vline
|
|
185
|
+
if vline != None:
|
|
186
|
+
vline.remove()
|
|
187
|
+
vline = ax_coverage.vlines(x=grid_spacing, ymin=0, ymax=3)
|
|
188
|
+
ax_coverage.set_xticks([round(x,0) for x in set([min_gridsize, grid_spacing, max_gridsize])])
|
|
189
|
+
return (vline,)
|
|
190
|
+
#
|
|
191
|
+
|
|
192
|
+
def create_optimal_grid_spacing_gif (
|
|
193
|
+
relevantGridSizes:_pd_DataFrame,
|
|
194
|
+
allGridSizes:_pd_DataFrame,
|
|
195
|
+
largest:float=400,
|
|
196
|
+
smallest:float=80,
|
|
197
|
+
radius:float=750,
|
|
198
|
+
frames_between_relevant:int = 6,
|
|
199
|
+
FuncAnimation_interval:int=500,
|
|
200
|
+
FuncAnimation_repeat:bool=True,
|
|
201
|
+
FuncAnimation_repeat_delay:int=1500,
|
|
202
|
+
FuncAnimation_cache_frame_data:bool=True,
|
|
203
|
+
dpi:int=50,
|
|
204
|
+
PillowWriterFps:int=10,
|
|
205
|
+
output_dir:str='./opt_grid_'
|
|
206
|
+
)->tuple:
|
|
207
|
+
|
|
208
|
+
print('Create GIF')
|
|
209
|
+
# initialise plot and main axis
|
|
210
|
+
fig,ax_main = plt.subplots()
|
|
211
|
+
|
|
212
|
+
# define ax limits for main axis
|
|
213
|
+
min_gridsize = min(relevantGridSizes['grid_spacing'])
|
|
214
|
+
max_gridsize = max(relevantGridSizes['grid_spacing'])
|
|
215
|
+
max_relevant_cells = max(relevantGridSizes['contain_count']+relevantGridSizes['overlap_count'])
|
|
216
|
+
ax_min=-max_gridsize/2
|
|
217
|
+
ax_max= max_gridsize*(max(relevantGridSizes['cell_steps_max'])-.5)
|
|
218
|
+
|
|
219
|
+
# add stackplot to top right corner
|
|
220
|
+
ax_coverage = add_coverage_plot(
|
|
221
|
+
fig=fig, allGridSizes=allGridSizes,
|
|
222
|
+
ymax=1.01*max(relevantGridSizes['share_contain']+relevantGridSizes['share_overlap']),
|
|
223
|
+
yticks=[.5,1])
|
|
224
|
+
|
|
225
|
+
# ax_counter = add_cell_counter_plot(
|
|
226
|
+
# fig=fig,
|
|
227
|
+
# allGridSizes=allGridSizes,
|
|
228
|
+
# ymax=max_relevant_cells,
|
|
229
|
+
# yticks=[int(x*max_relevant_cells/4) for x in range(1,5)]
|
|
230
|
+
# )
|
|
231
|
+
|
|
232
|
+
#
|
|
233
|
+
an_dct={
|
|
234
|
+
'it':0,
|
|
235
|
+
'vline':None
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
def animate(grid_spacing):
|
|
239
|
+
"""
|
|
240
|
+
function to pass into FuncAnimation to create GIF.
|
|
241
|
+
Will be supplied with list of gridsizes to iterate over.
|
|
242
|
+
"""
|
|
243
|
+
an_dct['it']=an_dct['it']+1
|
|
244
|
+
|
|
245
|
+
update_fig_title(fig=fig,grid_spacing=grid_spacing,it=an_dct['it'])
|
|
246
|
+
|
|
247
|
+
# update main axis:
|
|
248
|
+
artistObjects = update_main_axis_frame(
|
|
249
|
+
allGridSizes=allGridSizes,
|
|
250
|
+
grid_spacing=grid_spacing,
|
|
251
|
+
ax_main=ax_main,
|
|
252
|
+
ax_min=ax_min,
|
|
253
|
+
ax_max=ax_max,
|
|
254
|
+
radius=radius,
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
#
|
|
258
|
+
an_dct['vline'], = update_coverage_axis_frame(
|
|
259
|
+
grid_spacing=grid_spacing,
|
|
260
|
+
max_gridsize=max_gridsize,
|
|
261
|
+
min_gridsize=min_gridsize,
|
|
262
|
+
ax_coverage=ax_coverage,
|
|
263
|
+
vline=an_dct['vline']
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
return artistObjects
|
|
267
|
+
#
|
|
268
|
+
|
|
269
|
+
animation_frames = set_animation_frames(
|
|
270
|
+
relevantGridSizes=relevantGridSizes,
|
|
271
|
+
allGridSizes=allGridSizes,
|
|
272
|
+
largest=largest,
|
|
273
|
+
frames_between_relevant=frames_between_relevant
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
ani = _plt_FuncAnimation(
|
|
277
|
+
fig,
|
|
278
|
+
animate,
|
|
279
|
+
interval=FuncAnimation_interval,
|
|
280
|
+
blit=True,
|
|
281
|
+
repeat=FuncAnimation_repeat, repeat_delay=FuncAnimation_repeat_delay,
|
|
282
|
+
cache_frame_data=FuncAnimation_cache_frame_data,
|
|
283
|
+
frames=animation_frames
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
print('Save GIF')
|
|
287
|
+
ani.save(
|
|
288
|
+
output_dir+str(largest)+"_"+str(smallest)+".gif",
|
|
289
|
+
dpi=dpi,
|
|
290
|
+
writer=_plt_PillowWriter(fps=PillowWriterFps)
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
return fig,ax_main,ax_coverage,#ax_counter,
|
|
294
|
+
#
|