//  [python]
def pca_gmm(
    args, data: t.Dict[str, t.Dict[str, np.ndarray]], summary: tensorboard.Summary
):
    """
    run PCA on HDRS-YMRS, then run GMM on PCs
    """

    true = np.concatenate(
        [np.expand_dims(data["y_train"][item], axis=1) for item in args.selected_items],
        axis=1,
    )
    sessions = np.unique(data["y_train"]["Session_Code"])
    if (len(args.selected_items) == 28) and (len(sessions) > len(args.selected_items)):
        indexes = [
            np.where(data["y_train"]["Session_Code"] == s)[0][0]
            for s in np.unique(sessions)
        ]
        session_scores = true[indexes]
        scaler = StandardScaler().fit(session_scores)
        X = scaler.transform(session_scores)
        # fit models with 1-10 components
        N = np.arange(1, 11)
        models = [None for i in range(len(N))]
        for i in range(len(N)):
            models[i] = GaussianMixture(
                n_components=N[i], n_init=5, random_state=args.seed
            ).fit(X)
        BIC = [m.bic(X) for m in models]
        gmm = GaussianMixture(
            n_components=np.argmin(BIC) + 1, n_init=5, random_state=args.seed
        ).fit(X)
        pca = PCA().fit(X)

        membership = gmm.predict(X)
        log_likelihood = gmm.score_samples(X)
        pc1_coord = pca.transform(X)[:, 0]
        pc2_coord = pca.transform(X)[:, 1]

        figure, axs = plt.subplots(5, 1, figsize=(9, 7 * 5), dpi=args.dpi)

        ### ax0

        exp_var = pca.explained_variance_ratio_
        loadings = pca.components_
        num_pc = pca.n_features_in_
        pc_list = ["PC" + str(i) for i in list(range(1, num_pc + 1))]
        loadings_df = pd.DataFrame.from_dict(dict(zip(pc_list, loadings)))
        loadings_df["scale_item"] = args.selected_items
        loadings_df = loadings_df.set_index("scale_item")

        axs[0].bar(pc_list, exp_var)
        axs[0].set_ylabel("Proportion of explained variance", fontsize=label_fontsize)
        axs[0].set_title("Scree plot", fontsize=title_fontsize)
        axs[0].yaxis.set_major_formatter(mtick.PercentFormatter(1.0))
        axs[0].set_xticks(list(np.arange(len(pc_list))))
        axs[0].set_xticklabels(pc_list, rotation=90)

        ### ax1

        cmap = sns.color_palette("rocket_r", as_cmap=True)
        sns.heatmap(
            loadings_df.iloc[:, :5],
            annot=np.round(loadings_df.iloc[:, :5], 2).astype(str),
            cmap=cmap,
            fmt="",
            ax=axs[1],
        )
        axs[1].set_title("Correlation matrix for loadings", fontsize=title_fontsize)
        axs[1].set_ylabel("Items", fontsize=label_fontsize)

        ### ax2
        coord_d = pd.DataFrame(
            {"PC1": pc1_coord, "PC2": pc2_coord, "membership": membership}
        )
        membership_plot = sns.scatterplot(
            x="PC1",
            y="PC2",
            data=coord_d,
            hue="membership",
            ax=axs[2],
            s=15,
            palette="deep",
        )
        plt.setp(axs[2].get_legend().get_texts(), fontsize="14")
        plt.setp(axs[2].get_legend().get_title(), fontsize="16")
        axs[2].set_xlabel("PC1", fontsize=label_fontsize)
        axs[2].set_ylabel("PC2", fontsize=label_fontsize)
        axs[2].set_title("PC projection - GMM membership", fontsize=title_fontsize)
        membership_plot.legend(loc="best", edgecolor="white", facecolor="white")

        ### ax3

        axs3 = axs[3].scatter(
            x=pc1_coord, y=pc2_coord, c=log_likelihood, s=15, cmap="viridis"
        )
        norm = plt.Normalize(log_likelihood.min(), log_likelihood.max())
        sm = plt.cm.ScalarMappable(cmap="viridis", norm=norm)
        sm.set_array([])
        figure.colorbar(axs3, ax=axs[3])
        axs[3].set_xlabel("PC1", fontsize=label_fontsize)
        axs[3].set_ylabel("PC2", fontsize=label_fontsize)
        axs[3].set_title("PC projection - log_likelihood", fontsize=title_fontsize)

        ### axs4

        means = pd.DataFrame(
            data=gmm.means_,
            index=np.unique(membership),
            columns=args.selected_items,
        )
        means.index.names = ["Gaussian_no"]
        sns.heatmap(
            means.T,
            annot=np.round(means.T, 2).astype(str),
            cmap=cmap,
            fmt="",
            ax=axs[4],
        )
        axs[4].set_title("Guassian distributions' mean", fontsize=title_fontsize)
        axs[4].set_ylabel("Items", fontsize=label_fontsize)

        summary.figure(tag="pca_gmm", figure=figure, step=0, mode=0)