`activations` can be a list of ndarrays. In that case a list of layouts is returned.

def aligned_umap(activations, umap_options={}, normalize=True, verbose=False):
    """`activations` can be a list of ndarrays. In that case a list of layouts is returned."""

    umap_defaults = dict(
        n_components=2, n_neighbors=50, min_dist=0.05, verbose=verbose, metric="cosine"
    )
    umap_defaults.update(umap_options)

    # if passed a list of activations, we combine them and later split the layouts
    if type(activations) is list or type(activations) is tuple:
        num_activation_groups = len(activations)
        combined_activations = np.concatenate(activations)
    else:
        num_activation_groups = 1
        combined_activations = activations
    try:
        layout = UMAP(**umap_defaults).fit_transform(combined_activations)
    except (RecursionError, SystemError) as exception:
        log.error("UMAP failed to fit these activations. We're not yet sure why this sometimes occurs.")
        raise ValueError("UMAP failed to fit activations: %s", exception)

    if normalize:
        layout = normalize_layout(layout)

    if num_activation_groups > 1:
        layouts = np.split(layout, num_activation_groups, axis=0)
        return layouts
    else:
        return layout