"""
Module containing utility functions
"""
# Authors: Joseph Knox josephk@alleninstitute.org
# License: Allen Institute Software License
import numpy as np
from allensdk.core.mouse_connectivity_cache import MouseConnectivityCache
[docs]def get_experiment_ids(mcc, structure_ids, cre=None):
"""Returns all experiment ids with injection in structure_ids.
Parameters
----------
mcc : MouseConnectivityCache object
structure_ids: list
Only return experiments that were injected in the structures provided here.
If None, return all experiments. Default None.
cre: boolean or list
If True, return only cre-positive experiments. If False, return only
cre-negative experiments. If None, return all experiments. If list, return
all experiments with cre line names in the supplied list. Default None.
Returns
-------
List of experiment ids satisfying the parameters.
"""
#filters injections by structure id or Decendent
experiments = mcc.get_experiments(dataframe=False, cre=cre,
injection_structure_ids=structure_ids)
return [experiment['id'] for experiment in experiments]
[docs]def nonzero_unique(ar, **unique_kwargs):
"""np.unique returning only nonzero unique elements.
Parameters
----------
ar : array_like
Input array. Unless `axis` is specified, this will be flattened if it
is not already 1-D.
return_index : bool, optional
If True, also return the indices of `ar` (along the specified axis,
if provided, or in the flattened array) that result in the unique array.
return_counts : bool, optional
If True, also return the number of times each unique item appears
in `ar`.
axis : int or None, optional
The axis to operate on. If None, `ar` will be flattened beforehand.
Otherwise, duplicate items will be removed along the provided axis,
with all the other axes belonging to the each of the unique elements.
Object arrays or structured arrays that contain objects are not
supported if the `axis` kwarg is used.
Returns
-------
unique : array
Unique values sorted in the order in which they occur
unique_indices : array, optional
Indices of the first occurance of the unique values. Only returned if
return_indices kwarg is specified as True.
unique_counts : array
Counts of the unique values. Only returned if return_counts kwarg is
specified as True.
See Also
--------
ordered_unique
lex_ordered_unique
"""
if 'return_inverse' in unique_kwargs:
raise NotImplementedError("returning inverse array not yet implemented")
if np.all(ar):
return np.unique(ar, **unique_kwargs)
unique = np.unique(ar, **unique_kwargs)
if unique_kwargs:
return map(lambda x: x[1:], unique)
return unique[1:]
[docs]def ordered_unique(ar, **unique_kwargs):
"""np.unique in the order in which the unique values occur.
Similar outuput to pd.unique(), although probably not as fast.
Parameters
----------
ar : array_like
Input array. Unless `axis` is specified, this will be flattened if it
is not already 1-D.
return_index : bool, optional
If True, also return the indices of `ar` (along the specified axis,
if provided, or in the flattened array) that result in the unique array.
return_counts : bool, optional
If True, also return the number of times each unique item appears
in `ar`.
axis : int or None, optional
The axis to operate on. If None, `ar` will be flattened beforehand.
Otherwise, duplicate items will be removed along the provided axis,
with all the other axes belonging to the each of the unique elements.
Object arrays or structured arrays that contain objects are not
supported if the `axis` kwarg is used.
Returns
-------
unique : array
Unique values sorted in the order in which they occur
unique_indices : array, optional
Indices of the first occurrence of the unique values. Only returned if
return_indices kwarg is specified as True.
unique_counts : array
Counts of the unique values. Only returned if return_counts kwarg is
specified as True.
See Also
--------
nonzero_unique
lex_ordered_unique
"""
if 'return_inverse' in unique_kwargs:
raise NotImplementedError("returning inverse array not yet implemented")
_return_index = unique_kwargs.pop('return_index', False)
unique = np.unique(ar, return_index=True, **unique_kwargs)
# need indices (always @ index 1)
unique = list(unique)
indices = unique[1] if _return_index else unique.pop(1)
permutation = np.argsort(indices)
if unique_kwargs or _return_index:
return map(lambda x: x[permutation], unique)
return unique[0][permutation]
[docs]def lex_ordered_unique(ar, lex_order, allow_extra=False, **unique_kwargs):
"""np.unique in a given order.
Parameters
----------
ar : array_like
Input array. Unless `axis` is specified, this will be flattened if it
is not already 1-D.
return_index : bool, optional
If True, also return the indices of `ar` (along the specified axis,
if provided, or in the flattened array) that result in the unique array.
return_counts : bool, optional
If True, also return the number of times each unique item appears
in `ar`.
axis : int or None, optional
The axis to operate on. If None, `ar` will be flattened beforehand.
Otherwise, duplicate items will be removed along the provided axis,
with all the other axes belonging to the each of the unique elements.
Object arrays or structured arrays that contain objects are not
supported if the `axis` kwarg is used.
Returns
-------
unique : array
Unique values sorted in the order in which they occur
unique_indices : array, optional
Indices of the first occurrence of the unique values. Only returned if
return_indices kwarg is specified as True.
unique_counts : array
Counts of the unique values. Only returned if return_counts kwarg is
specified as True.
See Also
--------
nonzero_unique
ordered_unique
"""
if 'return_inverse' in unique_kwargs:
raise NotImplementedError("returning inverse array not yet implemented")
if len(set(lex_order)) < len(lex_order):
raise ValueError("lex_order must not contain duplicates")
unique = np.unique(ar, **unique_kwargs)
if not unique_kwargs:
unique = (unique,)
if len(unique[0]) < len(lex_order):
if allow_extra:
# view, does not write to array lex_order
# cast to np.array in order to index with boolean array
lex_order = np.array(lex_order)[np.isin(lex_order, unique[0])]
else:
raise ValueError("lex_order contains elements not found in ar, "
"call with allow_extra=True")
# generate a permutation order for unique
permutation = np.argsort(np.argsort(lex_order))
if len(unique) > 1:
return tuple(map(lambda x: x[permutation], unique))
return unique[0][permutation]
[docs]def padded_diagonal_fill(arrays):
"""Returns array filled with uneven arrays padding with zeros.
Arrays are placed in the return array such that each row/column only
contains the elements of a single array. Can be thought of as representing
disconnected subgraphs.
Parameters
----------
arrays : list
List of 2D arrays with which to fill the return array.
Returns
-------
padded : array
Return array containing each of the input arrays, padded with zeros.
"""
shapes = [x.shape for x in arrays]
padded = np.zeros(tuple(map(sum, zip(*shapes))))
i, j = 0, 0
for (n_rows, n_cols), arr in zip(shapes, arrays):
# fill padded with arr
padded[i:i+n_rows, j:j+n_cols] = arr
i += n_rows
j += n_cols
return padded
def squared_norm(arr):
"""Compute the square frobenius/vector norm.
Parameters
----------
arr : np.ndarray
Array of which we compute the norm.
Returns
-------
norm: float
"""
arr = arr.ravel(order='K')
return np.dot(arr, arr)
[docs]def unionize(volume, key, return_regions=False):
"""Unionize voxel data to regional data.
Parameters
----------
volume : array, shape (n, m)
Possibly stacked flattened volume(s) such as projection densities or
injection densities.
key : array, shape (m,)
1D Array with length equal to the number of columns in volume. This array
has integer values corresponding to the region to which each voxel belongs.
return_regions : boolean, optional (default: False)
If True, return an array of the unique values of key in addition to the
unionized volume array.
Returns
-------
result : array, shape (n, len(unique(key)))
The unionized volume.
regions : array, optional, shape (len(unique(key)),)
The unique values of key.
"""
volume = np.atleast_2d(volume)
if volume.shape[1] != key.size:
raise ValueError("volume (%s) and key (%s) shapes are incompatible"
% (volume.shape[1], key.size))
regions = nonzero_unique(key)
result = np.empty((volume.shape[0], regions.size))
for j, k in enumerate(regions):
result[:, j] = volume[:, np.where(key == k)[0]].sum(axis=1)
if return_regions:
return result, regions
return result