Skip to content

feat(custom/clustermetrics, custom/clustervisualization): accept PLIN… - #12906

Merged
dbaku42 merged 4 commits into
nf-core:masterfrom
dbaku42:feat/custom-cluster-modules-eigenvec-clean
Sep 8, 2026
Merged

feat(custom/clustermetrics, custom/clustervisualization): accept PLIN…#12906
dbaku42 merged 4 commits into
nf-core:masterfrom
dbaku42:feat/custom-cluster-modules-eigenvec-clean

Conversation

@dbaku42

@dbaku42 dbaku42 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

This PR updates load_features in both modules so they accept the same
inputs as custom/pcaclustering:

  • TSV/TXT with a sample_id column (unchanged)
  • PLINK2 .eigenvec (#FID IID PC1 ... or #IID PC1 ...); FID/SID
    are dropped and IID is used as sample_id

Also:

  • custom/clustermetrics: k-distance plot (*.k_distance.png) to help
    choose DBSCAN eps. Optional ext.args: --k-neighbors, --eps.
  • custom/clustervisualization: n_jobs=1 on UMAP and t-SNE (with the
    existing random_state=42) to stabilize embeddings across runners.

main.nf input signatures are unchanged (path(features)). Docs in
meta.yml now list *.{tsv,txt,eigenvec}.

Related

@erikrikarddaniel erikrikarddaniel left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude didn't find complete test coverage: "Missing test coverage — the new IID/FID/SID PLINK2-header parsing branch in load_features isn't exercised by any test in either module; both still only feed the plain-TSV fixture, and even custom/pcaclustering's existing "eigenvec" test turns out to reuse that same TSV rather than a real .eigenvec-shaped file."

Two more comments in the code.

Not blocking, but worth thinking about.

if "IID" in df.columns:
df = df.rename(columns={"IID": "sample_id"})
elif "sample_id" not in df.columns:
df = df.rename(columns={df.columns[0]: "sample_id"})

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth double-checking: when neither IID nor sample_id is present, this now silently renames whichever column happens to be first to sample_id, instead of the previous behavior of raising the ValueError below (line 48) immediately. A genuinely malformed/mislabeled input (columns in the wrong order, or an ID column named something other than sample_id/IID) would now be used as-is rather than failing with the old, clear "features file must have a 'sample_id' column" message — any mismatch would instead surface later as a confusing empty join or a garbage plot. Is the silent fallback intentional (e.g. to support a headerless first-column-is-ID convention), or should this elif just keep raising, with only the two known PLINK2 header shapes special-cased above it?

if "IID" in df.columns:
df = df.rename(columns={"IID": "sample_id"})
elif "sample_id" not in df.columns:
df = df.rename(columns={df.columns[0]: "sample_id"})

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same fallback question as in clustermetrics/templates/cluster_metrics.py — see that comment.

… on missing sample_id column

Remove the silent first-column fallback in load_features; only IID is
special-cased for PLINK2 headers, everything else without sample_id
still raises the explicit ValueError.

Add eigenvec-based test coverage using the existing test.eigenvec
fixture in test-datasets, exercising the PLINK2 header-parsing branch.
@dbaku42

dbaku42 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

Good catch — that silent fallback wasn't intentional. Removed the elif branch in both cluster_metrics.py and cluster_viz.py; now only IID is special-cased, and anything without sample_id/IID raises the original ValueError again instead of silently renaming the first column.

Also added a test in each module (clustermetrics - features from eigenvec and clustervisualization - features from eigenvec) using test.eigenvec from test-datasets, which exercises the actual PLINK2 header-parsing branch — turns out it was already sitting unused in the popgen/clustering folder. Snapshots updated accordingly.

@dbaku42

dbaku42 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

thanks @erikrikarddaniel,
All tests pass now, let me know if you have any other obsevations.

@erikrikarddaniel

Copy link
Copy Markdown
Member

thanks @erikrikarddaniel, All tests pass now, let me know if you have any other obsevations.

You have my approval, just go ahead and merge!

@dbaku42
dbaku42 added this pull request to the merge queue Sep 8, 2026
Merged via the queue into nf-core:master with commit 9f93628 Sep 8, 2026
37 checks passed
@dbaku42
dbaku42 deleted the feat/custom-cluster-modules-eigenvec-clean branch September 8, 2026 14:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants