Skip to content

pelinker.dim_selection.summary

Summary artifacts for PCA/UMAP dimension selection.

write_dim_dbcv_vs_ari(grid_df, report_path)

DBCV vs ARI scatter (one point / ellipse per PCA×UMAP cell).

Source code in pelinker/dim_selection/summary.py
def write_dim_dbcv_vs_ari(
    grid_df: pd.DataFrame, report_path: pathlib.Path
) -> list[str]:
    """DBCV vs ARI scatter (one point / ellipse per PCA×UMAP cell)."""
    if grid_df.empty:
        return []
    out = report_path / DIM_SELECTION_DBCV_VS_ARI_STEM
    if not plot_dbcv_vs_ari_from_grid(grid_df, out):
        return []
    written: list[str] = []
    for fmt in ("png", "pdf"):
        path = report_path / f"{DIM_SELECTION_DBCV_VS_ARI_STEM}.{fmt}"
        if path.is_file():
            written.append(path.name)
    return written

write_dim_metrics_violin(grid_df, report_path)

Two-panel violin of per-bootstrap DBCV / ARI across PCA×UMAP cells.

Source code in pelinker/dim_selection/summary.py
def write_dim_metrics_violin(
    grid_df: pd.DataFrame, report_path: pathlib.Path
) -> list[str]:
    """Two-panel violin of per-bootstrap DBCV / ARI across PCA×UMAP cells."""
    points = _grid_points_with_dims(grid_df)
    if points.empty:
        return []
    if points["sample_idx"].nunique() < 2:
        return []
    if "dbcv" not in points.columns or "ari" not in points.columns:
        return []

    plot_df = points.dropna(subset=["dbcv", "ari", "pca_components", "umap_dim"]).copy()
    if plot_df.empty:
        return []
    plot_df["cell"] = [
        _cell_label(p, u)
        for p, u in zip(plot_df["pca_components"], plot_df["umap_dim"], strict=True)
    ]
    cell_order = (
        plot_df.groupby("cell", as_index=False)[["pca_components", "umap_dim"]]
        .first()
        .sort_values(["pca_components", "umap_dim"])["cell"]
        .tolist()
    )

    fig, axes = plt.subplots(1, 2, figsize=(max(8, len(cell_order) * 0.7), 5))
    for ax, metric, title in (
        (axes[0], "dbcv", "DBCV at pooled MCS"),
        (axes[1], "ari", "ARI at pooled MCS"),
    ):
        sns.violinplot(
            data=plot_df,
            x="cell",
            y=metric,
            order=cell_order,
            inner="quartile",
            cut=0,
            ax=ax,
            color="#6BAED6",
        )
        if plot_df["sample_idx"].nunique() <= 5:
            sns.stripplot(
                data=plot_df,
                x="cell",
                y=metric,
                order=cell_order,
                ax=ax,
                color="black",
                size=3,
                alpha=0.65,
            )
        ax.set_xlabel("pca × umap")
        ax.set_ylabel(metric.upper() if metric == "ari" else "DBCV")
        ax.set_title(title)
        ax.tick_params(axis="x", labelrotation=45)
        for label in ax.get_xticklabels():
            label.set_ha("right")

    fig.tight_layout()
    try:
        paths = _save_figure_multi_format(
            fig, report_path / DIM_SELECTION_METRICS_VIOLIN_STEM
        )
    finally:
        plt.close(fig)
    return _figure_basenames(paths)

write_dim_outer_surface(df, report_path)

Pseudo-3D surface of outer_score over PCA × UMAP (PNG + PDF).

Source code in pelinker/dim_selection/summary.py
def write_dim_outer_surface(df: pd.DataFrame, report_path: pathlib.Path) -> list[str]:
    """Pseudo-3D surface of ``outer_score`` over PCA × UMAP (PNG + PDF)."""
    if df.empty or "pca_components" not in df.columns or "umap_dim" not in df.columns:
        return []
    scored = attach_outer_scores(df, use_minmax=True)
    if OUTER_SCORE_COL not in scored.columns or scored[OUTER_SCORE_COL].isna().all():
        return []

    agg = (
        scored.groupby(["pca_components", "umap_dim"], as_index=False)[OUTER_SCORE_COL]
        .mean()
        .dropna(subset=[OUTER_SCORE_COL])
    )
    if agg.empty:
        return []

    winner = pick_winner_row(scored)
    win_pca = float(winner["pca_components"])
    win_umap = float(winner["umap_dim"])
    win_z = float(winner.get(OUTER_SCORE_COL) or winner["best_score"])

    pca_vals = np.sort(agg["pca_components"].unique().astype(np.float64))
    umap_vals = np.sort(agg["umap_dim"].unique().astype(np.float64))
    pivot = agg.pivot_table(
        index="umap_dim",
        columns="pca_components",
        values=OUTER_SCORE_COL,
        aggfunc="mean",
    ).reindex(index=umap_vals, columns=pca_vals)
    rectangular = (
        bool(pivot.notna().all().all()) and pivot.shape[0] >= 2 and pivot.shape[1] >= 2
    )

    fig = plt.figure(figsize=(9, 7))
    ax = fig.add_subplot(111, projection="3d")
    if rectangular:
        xx, yy = np.meshgrid(pca_vals, umap_vals)
        zz = pivot.to_numpy(dtype=np.float64)
        surf = ax.plot_surface(
            xx,
            yy,
            zz,
            cmap="RdBu_r",
            edgecolor="white",
            linewidth=0.3,
            alpha=0.92,
            antialiased=True,
        )
        fig.colorbar(surf, ax=ax, shrink=0.65, label="Outer DBCV+ARI (minmax)")
    else:
        xs = agg["pca_components"].to_numpy(dtype=np.float64)
        ys = agg["umap_dim"].to_numpy(dtype=np.float64)
        zs = agg[OUTER_SCORE_COL].to_numpy(dtype=np.float64)
        if len(xs) < 3:
            ax.scatter(xs, ys, zs, c=zs, cmap="RdBu_r", s=60)
        else:
            surf = ax.plot_trisurf(
                xs,
                ys,
                zs,
                cmap="RdBu_r",
                edgecolor="white",
                linewidth=0.2,
                alpha=0.92,
            )
            fig.colorbar(surf, ax=ax, shrink=0.65, label="Outer DBCV+ARI (minmax)")

    ax.scatter(
        [win_pca],
        [win_umap],
        [win_z],
        color="black",
        s=80,
        depthshade=False,
        label="winner",
        zorder=10,
    )
    ax.set_xlabel("pca_components")
    ax.set_ylabel("umap_dim")
    ax.set_zlabel("outer_score")
    ax.set_title("Outer DBCV+ARI surface (minmax)")
    ax.legend(loc="upper left")
    fig.tight_layout()
    try:
        paths = _save_figure_multi_format(
            fig, report_path / DIM_SELECTION_OUTER_SURFACE_STEM
        )
    finally:
        plt.close(fig)
    return _figure_basenames(paths)