-
-
Notifications
You must be signed in to change notification settings - Fork 394
/
traversal.py
130 lines (115 loc) · 4.18 KB
/
traversal.py
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
"""
Advanced utilities for traversing nesting/hierarchical Dimensioned
objects either to inspect the structure of their declared dimensions
or mutate the matching elements.
"""
from collections import defaultdict
from operator import itemgetter
from .dimension import Dimension, OrderedDict
from .util import merge_dimensions
try:
import itertools.izip as zip
except ImportError:
pass
def create_ndkey(length, indexes, values):
key = [None] * length
for i, v in zip(indexes, values):
key[i] = v
return tuple(key)
def uniform(obj):
"""
Finds all common dimension keys in the object including subsets of
dimensions. If there are is no common subset of dimensions, None
is returned.
"""
from .spaces import HoloMap
dim_groups = obj.traverse(lambda x: tuple(x.kdims),
(HoloMap,))
if dim_groups:
dgroups = [frozenset(d.name for d in dg) for dg in dim_groups]
return all(g1 <= g2 or g1 >= g2 for g1 in dgroups for g2 in dgroups)
return True
def unique_dimkeys(obj, default_dim='Frame'):
"""
Finds all common dimension keys in the object including subsets of
dimensions. If there are is no common subset of dimensions, None
is returned.
Returns the list of dimensions followed by the list of unique
keys.
"""
from .ndmapping import NdMapping
from .spaces import HoloMap
key_dims = obj.traverse(lambda x: (tuple(x.kdims),
list(x.data.keys())), (HoloMap,))
if not key_dims:
return [Dimension(default_dim)], [(0,)]
dim_groups, keys = zip(*sorted(key_dims, key=lambda x: -len(x[0])))
dgroups = [frozenset(d.name for d in dg) for dg in dim_groups]
subset = all(g1 <= g2 or g1 >= g2 for g1 in dgroups for g2 in dgroups)
# Find unique keys
if subset:
dims = merge_dimensions(dim_groups)
all_dims = sorted(dims, key=lambda x: dim_groups[0].index(x))
else:
all_dims = [default_dim]
ndims = len(all_dims)
unique_keys = []
for group, keys in zip(dim_groups, keys):
dim_idxs = [all_dims.index(dim) for dim in group]
for key in keys:
padded_key = create_ndkey(ndims, dim_idxs, key)
matches = [item for item in unique_keys
if padded_key == tuple(k if k is None else i
for i, k in zip(item, padded_key))]
if not matches:
unique_keys.append(padded_key)
sorted_keys = NdMapping({key: None for key in unique_keys},
kdims=all_dims).data.keys()
if subset:
return all_dims, list(sorted_keys)
else:
return all_dims, [(i,) for i in range(len(unique_keys))]
def bijective(keys):
ndims = len(keys[0])
if ndims <= 1:
return True
for idx in range(ndims):
getter = itemgetter(*(i for i in range(ndims) if i != idx))
store = []
for key in keys:
subkey = getter(key)
if subkey in store:
return False
store.append(subkey)
return True
def hierarchical(keys):
"""
Iterates over dimension values in keys, taking two sets
of dimension values at a time to determine whether two
consecutive dimensions have a one-to-many relationship.
If they do a mapping between the first and second dimension
values is returned. Returns a list of n-1 mappings, between
consecutive dimensions.
"""
ndims = len(keys[0])
if ndims <= 1:
return True
dim_vals = list(zip(*keys))
combinations = (zip(*dim_vals[i:i+2])
for i in range(ndims-1))
hierarchies = []
for combination in combinations:
hierarchy = True
store1 = defaultdict(list)
store2 = defaultdict(list)
for v1, v2 in combination:
if v2 not in store2[v1]:
store2[v1].append(v2)
previous = store1[v2]
if previous and previous[0] != v1:
hierarchy = False
break
if v1 not in store1[v2]:
store1[v2].append(v1)
hierarchies.append(store2 if hierarchy else {})
return hierarchies