Beispiel #1
0
def load_or_generate_components(hemi, out_dir='.', plot_dir=None, force=False,
                                *args, **kwargs):
    """Load an image and return if it exists, otherwise compute via ICA"""
    # Only re-run if image doesn't exist.
    img_path = op.join(out_dir, '%s_ica_components.nii.gz' % hemi)
    if not force and op.exists(img_path):
        img = NiftiImageWithTerms.from_filename(img_path)

    else:
        img = generate_components(hemi=hemi, out_dir=out_dir, *args, **kwargs)
        png_dir = op.join(out_dir, 'png')
        plot_components(img, hemi=hemi, out_dir=png_dir)
        plot_components_summary(img, hemi=hemi, out_dir=png_dir)
    return img
def generate_components(
    images,
    hemi,
    term_scores=None,
    n_components=20,
    random_state=42,
    out_dir=None,
    memory=Memory(cachedir="nilearn_cache"),
):
    """
        images: list
            Can be nibabel images, can be file paths.
    """
    # Create grey matter mask from mni template
    target_img = datasets.load_mni152_template()

    # Reshape & mask images
    print("%s: Reshaping and masking images; may take time." % hemi)
    if hemi == "wb":
        masker = GreyMatterNiftiMasker(target_affine=target_img.affine, target_shape=target_img.shape, memory=memory)

    else:  # R and L maskers
        masker = HemisphereMasker(
            target_affine=target_img.affine, target_shape=target_img.shape, memory=memory, hemisphere=hemi
        )
    masker = masker.fit()

    # Images may fail to be transformed, and are of different shapes,
    # so we need to trasnform one-by-one and keep track of failures.
    X = []  # noqa
    xformable_idx = np.ones((len(images),), dtype=bool)
    for ii, im in enumerate(images):
        img = cast_img(im, dtype=np.float32)
        img = clean_img(img)
        try:
            X.append(masker.transform(img))
        except Exception as e:
            print("Failed to mask/reshape image %d/%s: %s" % (im.get("collection_id", 0), op.basename(im), e))
            xformable_idx[ii] = False

    # Now reshape list into 2D matrix
    X = np.vstack(X)  # noqa

    # Run ICA and map components to terms
    print("%s: Running ICA; may take time..." % hemi)
    fast_ica = FastICA(n_components=n_components, random_state=random_state)
    fast_ica = memory.cache(fast_ica.fit)(X.T)
    ica_maps = memory.cache(fast_ica.transform)(X.T).T

    # Tomoki's suggestion to normalize components_
    # X ~ ica_maps * fast_ica.components_
    #   = (ica_maps * f) * (fast_ica.components_ / f)
    #   = new_ica_map * new_components_
    C = fast_ica.components_
    factor = np.sqrt(np.multiply(C, C).sum(axis=1, keepdims=True))  # (n_components x 1)
    ica_maps = np.multiply(ica_maps, factor)
    fast_ica.components_ = np.multiply(C, 1.0 / (factor + 1e-12))

    if term_scores is not None:
        terms = term_scores.keys()
        term_matrix = np.asarray(term_scores.values())
        term_matrix[term_matrix < 0] = 0
        term_matrix = term_matrix[:, xformable_idx]  # terms x images
        # Don't use the transform method as it centers the data
        ica_terms = np.dot(term_matrix, fast_ica.components_.T).T

    # 2015/12/26 - sign matters for comparison, so don't do this!
    # 2016/02/01 - sign flipping is ok for R-L comparison, but RL concat
    #              may break this.
    # Pretty up the results
    for idx, ic in enumerate(ica_maps):
        if -ic.min() > ic.max():
            # Flip the map's sign for prettiness
            ica_maps[idx] = -ic
            if term_scores:
                ica_terms[idx] = -ica_terms[idx]

    # Create image from maps, save terms to the image directly
    ica_image = NiftiImageWithTerms.from_image(masker.inverse_transform(ica_maps))
    if term_scores:
        ica_image.terms = dict(zip(terms, ica_terms.T))

    # Write to disk
    if out_dir is not None:
        out_path = op.join(out_dir, "%s_ica_components.nii.gz" % hemi)
        if not op.exists(op.dirname(out_path)):
            os.makedirs(op.dirname(out_path))
        ica_image.to_filename(out_path)
    return ica_image
Beispiel #3
0
def image_analyses(components, dataset, memory=Memory(cachedir='nilearn_cache'),
                   **kwargs):
    """
    1) Plot sparsity of ICA images for wb, R, and L.
    2) Plot Hemispheric Participation Index (HPI) for wb ICA images
    """
    out_dir = op.join('ica_imgs', dataset)
    images_key = ["R", "L", "wb"]
    sparsity_levels = ['pos_005', 'neg_005', 'abs_005']

    # For calculating hemispheric participation index (HPI) from wb components,
    # prepare hemisphere maskers
    hemi_maskers = [HemisphereMasker(hemisphere=hemi, memory=memory).fit()
                    for hemi in ['R', 'L']]

    # Store sparsity (and hpi for wb) vals in a DF
    columns = ["n_comp"] + sparsity_levels
    wb_columns = columns + ["pos_hpi", "neg_hpi"]
    hemi_dfs = {hemi: pd.DataFrame(columns=wb_columns if hemi == "wb" else columns)
                for hemi in images_key}

    # Loop over components
    for c in components:
        print("Simply loading component images for n_component = %s" % c)
        nii_dir = op.join('ica_nii', dataset, str(c))
        for hemi in images_key:
            img_path = op.join(nii_dir, '%s_ica_components.nii.gz' % (hemi))
            img = NiftiImageWithTerms.from_filename(img_path)
            data = pd.DataFrame({"n_comp": [c] * c}, columns=columns)
            # get mean sparsity for the ica iamge and store in sparsity dict
            for s in sparsity_levels:
                thresh = float('0.%s' % (re.findall('\d+', s)[0]))
                # sparsity is # of voxels above the given sparsity level for each component
                if 'pos' in s:
                    data[s] = (img.get_data() > thresh).sum(axis=0).sum(axis=0).sum(axis=0)
                elif 'neg' in s:
                    data[s] = (img.get_data() < -thresh).sum(axis=0).sum(axis=0).sum(axis=0)
                elif 'abs' in s:
                    data[s] = (abs(img.get_data()) > thresh).sum(axis=0).sum(axis=0).sum(axis=0)

            # get hpi values for wb components
            if hemi == "wb":
                hemi_vectors = [masker.transform(img) for masker in hemi_maskers]
                # transform back so that values for each component can be calculated
                hemi_imgs = [masker.inverse_transform(vec) for masker, vec in
                             zip(hemi_maskers, hemi_vectors)]
                # pos/neg_vals[0] = # voxels in R, pos/neg_vals[1] = # voxels in L
                pos_vals = [(hemi_img.get_data() > 0.005).sum(axis=0).sum(axis=0).sum(axis=0)
                            for hemi_img in hemi_imgs]
                neg_vals = [(hemi_img.get_data() < -0.005).sum(axis=0).sum(axis=0).sum(axis=0)
                            for hemi_img in hemi_imgs]

                for sign, val in zip(['pos', 'neg'], [pos_vals, neg_vals]):
                    with np.errstate(divide="ignore", invalid="ignore"):
                        # pos/neg HPI vals, calculated as (R-L)/(R+L) for num. of voxels above
                        # the given threshold
                        hpi = (val[0].astype(float) - val[1]) / (val[0] + val[1])
                    data["%s_hpi" % (sign)] = hpi

            hemi_dfs[hemi] = hemi_dfs[hemi].append(data)

    # Now plot:
    # 1) Sparsity for wb, R and L ICA images
    fh, axes = plt.subplots(1, 3, sharex=True, sharey=True, figsize=(18, 6))
    sparsity_styles = {'pos_005': ['b', 'lightblue'],
                       'neg_005': ['r', 'lightpink'],
                       'abs_005': ['g', 'lightgreen']}
    for ax, hemi in zip(axes, images_key):
        df = hemi_dfs[hemi]
        by_comp = df.groupby('n_comp')
        for s in sparsity_levels:
            mean, sd = by_comp.mean()[s], by_comp.std()[s]
            ax.fill_between(components, mean + sd, mean - sd, linewidth=0,
                            facecolor=sparsity_styles[s][1], alpha=0.5)
            ax.plot(components, mean, color=sparsity_styles[s][0], label=s)
        # Overlay individual points for absolute threshold
        ax.scatter(df.n_comp, df.abs_005, c=sparsity_styles['abs_005'][0])
        ax.set_title("Sparsity of the %s components" % (hemi))
        ax.set_xlim(xmin=components[0] - 1, xmax=components[-1] + 1)
        ax.set_xticks(components)
    plt.legend()
    fh.text(0.5, 0.04, "# of components", ha="center")
    fh.text(0.04, 0.5, "# of voxels above the threshold", va='center', rotation='vertical')

    out_path = op.join(out_dir, 'sparsity.png')
    save_and_close(out_path, fh=fh)

    # 2) HPI plot for wb components
    fh, axes = plt.subplots(1, 2, sharex=True, sharey=True, figsize=(12, 6))
    fh.suptitle("Hemispheric Participation Index for each component", fontsize=16)
    hpi_styles = {'pos': ['b', 'lightblue', 'above 0.005'],
                  'neg': ['r', 'lightpink', 'below -0.005']}
    df = hemi_dfs["wb"]
    by_comp = df.groupby("n_comp")
    for ax, sign in zip(axes, ['pos', 'neg']):
        mean, sd = by_comp.mean()["%s_hpi" % sign], by_comp.std()["%s_hpi" % sign]
        ax.fill_between(components, mean + sd, mean - sd, linewidth=0,
                        facecolor=hpi_styles[sign][1], alpha=0.5)
        size = df['%s_005' % (sign)]
        ax.scatter(df.n_comp, df["%s_hpi" % sign], label=sign, c=hpi_styles[sign][0], s=size / 20)
        ax.plot(components, mean, c=hpi_styles[sign][0])
        ax.set_title("%s" % (sign))
        ax.set_xlim((0, components[-1] + 5))
        ax.set_ylim((-1, 1))
        ax.set_xticks(components)
        ax.set_ylabel("HPI((R-L)/(R+L) for # of voxels %s" % (hpi_styles[sign][2]))

    fh.text(0.5, 0.04, "# of components", ha="center")

    out_path = op.join(out_dir, 'wb_HPI.png')
    save_and_close(out_path, fh=fh)

    # Save sparsity and HPI vals for all the components
    for hemi in images_key:
        hemi_dfs[hemi].index.name = "idx"
        hemi_dfs[hemi].to_csv(op.join(out_dir, "%s_summary.csv" % (hemi)))