@@ -123,6 +123,26 @@ def leaves(self):
123
123
leaves = np .setxor1d (self .id , self .parent )
124
124
return self .get (np .int64 (leaves [~ np .isnan (leaves )]))
125
125
126
+ def propagate_down (self , acronyms , values ):
127
+ """
128
+ This function remaps a set of user specified acronyms and values to the
129
+ swanson map, by filling down the child nodes when higher up values are
130
+ provided.
131
+ :param acronyms: list or array of allen ids or acronyms
132
+ :param values: list or array of associated values
133
+ :return:
134
+ """
135
+ user_aids = self .parse_acronyms_argument (acronyms )
136
+ _ , user_indices = ismember (user_aids , self .id )
137
+ self .compute_hierarchy ()
138
+ ia , ib = ismember (self .hierarchy , user_indices )
139
+ v = np .zeros_like (ia , dtype = np .float64 ) * np .NaN
140
+ v [ia ] = values [ib ]
141
+ all_values = np .nanmedian (v , axis = 0 )
142
+ indices = np .where (np .any (ia , axis = 0 ))[0 ]
143
+ all_values = all_values [indices ]
144
+ return indices , all_values
145
+
126
146
def _mapping_from_regions_list (self , new_map , lateralize = False ):
127
147
"""
128
148
From a vector of regions id, creates a mapping such as
@@ -429,7 +449,7 @@ def _compute_mappings(self):
429
449
"""
430
450
Recomputes the mapping indices for all mappings
431
451
This is left mainly as a reference for adding future mappings as this take a few seconds
432
- to execute. In production,we use the MAPPING_FILES pqt to avoid recompuing at each \
452
+ to execute. In production,we use the MAPPING_FILES pqt to avoid recomputing at each \
433
453
instantiation
434
454
"""
435
455
beryl = np .load (Path (__file__ ).parent .joinpath ('beryl.npy' ))
@@ -447,6 +467,33 @@ def _compute_mappings(self):
447
467
}
448
468
pd .DataFrame (self .mappings ).to_parquet (FILE_MAPPINGS )
449
469
470
+ def compute_hierarchy (self ):
471
+ """
472
+ Creates a self.hierarchy attributes that is a n_levels by n_region array
473
+ of indices. This is useful to perform fast vectorized computations of
474
+ ancestors and descendants.
475
+ :return:
476
+ """
477
+ if hasattr (self , 'hierarchy' ):
478
+ return
479
+ n_levels = np .max (self .level )
480
+ n_regions = self .id .size
481
+ # creates the parent index. Void and root are omitted from intersection
482
+ # as they figure as NaN
483
+ pmask , i_p = ismember (self .parent , self .id )
484
+ self .iparent = np .arange (n_regions )
485
+ self .iparent [pmask ] = i_p
486
+ # the last level of the hierarchy is the actual mapping, then going up level per level
487
+ # we assign the parend index
488
+ self .hierarchy = np .tile (np .arange (n_regions ), (n_levels , 1 ))
489
+ _mask = np .zeros (n_regions , bool )
490
+ for lev in np .flipud (np .arange (n_levels )):
491
+ if lev < (n_levels - 1 ):
492
+ self .hierarchy [lev , _mask ] = self .iparent [self .hierarchy [lev + 1 , _mask ]]
493
+ sel = self .level == (lev + 1 )
494
+ self .hierarchy [lev , sel ] = np .where (sel )[0 ]
495
+ _mask [sel ] = True
496
+
450
497
def remap (self , region_ids , source_map = 'Allen' , target_map = 'Beryl' ):
451
498
"""
452
499
Remap atlas regions ids from source map to target map
0 commit comments