From ddec2ce45cd80b052f4347e830bef4955a82a8ee Mon Sep 17 00:00:00 2001 From: adRn-s Date: Thu, 9 Jul 2026 09:22:22 +0200 Subject: [PATCH] Add data-output tests for plotPCA and plotFingerprint Both existing tests only compared the rendered PNG. Adds numeric assertions on the tabular outputs, filling gaps found while triaging the stalled #1372/#1374 tests: - plotPCA: verify --outFileNameData (the existing test passed this flag but the check was commented out). Asserts the sign-independent eigenvalue column and table shape. - plotFingerprint: verify --outQualityMetrics + --JSDsample (AUC and JS Distance), neither previously tested anywhere. Expected values derived by running the current tools; verified with `pixi run pytest`. Co-Authored-By: Claude Fable 5 --- .../deeptools/test/test_plotFingerprint.py | 36 +++++++++++++++++-- pydeeptools/deeptools/test/test_plotPCA.py | 31 +++++++++++++++- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/pydeeptools/deeptools/test/test_plotFingerprint.py b/pydeeptools/deeptools/test/test_plotFingerprint.py index a81a33eb2d..81e1df33fe 100644 --- a/pydeeptools/deeptools/test/test_plotFingerprint.py +++ b/pydeeptools/deeptools/test/test_plotFingerprint.py @@ -17,7 +17,37 @@ def test_plotFingerprint_default(): deeptools.plotFingerprint.main(args) res = compare_images(ROOT + 'test_plotFingerprint_default.png', plotfile.name, tolerance) - + assert res is None, res - - os.remove(plotfile.name) \ No newline at end of file + + os.remove(plotfile.name) + + +def test_plotFingerprint_quality_metrics_and_JSD(): + """ + Test --outQualityMetrics together with --JSDsample. Neither the quality + metrics table nor the JS-distance computation was covered elsewhere. + """ + plotfile = NamedTemporaryFile(suffix='.png', prefix='deeptools_testfile_', delete=False) + qcfile = NamedTemporaryFile(suffix='.tab', prefix='deeptools_testfile_', delete=False) + args = ("-b {0}test1.bam {0}test2.bam -o {1} --plotFileFormat png -l test1 test2 " + "--outQualityMetrics {2} --JSDsample {0}test1.bam".format(TEST_DATA, plotfile.name, qcfile.name)).split() + deeptools.plotFingerprint.main(args) + + with open(qcfile.name) as _foo: + lines = [line.rstrip("\n").split("\t") for line in _foo] + + # header + one row per sample + assert len(lines) == 3, f"expected 3 lines, got {len(lines)}" + header = lines[0] + auc = header.index("AUC") + jsd = header.index("JS Distance") + + rows = {row[0]: row for row in lines[1:]} + assert abs(float(rows["test1"][auc]) - 0.39310288701202156) < 1e-4 + assert abs(float(rows["test2"][auc]) - 0.3641251150405128) < 1e-4 + # JS distance of the JSDsample (test1) against itself is nan; test2 is finite + assert abs(float(rows["test2"][jsd]) - 0.078613413909822) < 1e-4 + + os.remove(plotfile.name) + os.remove(qcfile.name) \ No newline at end of file diff --git a/pydeeptools/deeptools/test/test_plotPCA.py b/pydeeptools/deeptools/test/test_plotPCA.py index 22d4c3bfaf..6f0e594894 100644 --- a/pydeeptools/deeptools/test/test_plotPCA.py +++ b/pydeeptools/deeptools/test/test_plotPCA.py @@ -1,5 +1,6 @@ import os import filecmp +import numpy as np from matplotlib.testing.compare import compare_images from tempfile import NamedTemporaryFile import deeptools.plotPCA @@ -20,6 +21,34 @@ def test_plotPCA_default(): res = compare_images(ROOT + 'test_plotPCA_default.png', plotfile.name, tolerance) assert res is None, res #assert filecmp.cmp(os.path.join(ROOT, 'test_plotPCA_default.tsv'), tsvfile.name) is True - + + os.remove(plotfile.name) + os.remove(tsvfile.name) + + +def test_plotPCA_outFileNameData(): + """ + Verify the numeric --outFileNameData output. The eigenvector sign is + arbitrary (and can flip across BLAS/platforms), so we assert on the + sign-independent eigenvalue column and the table shape rather than the + projected coordinates. + """ + plotfile = NamedTemporaryFile(suffix='.png', prefix='deeptools_testfile_', delete=False) + tsvfile = NamedTemporaryFile(suffix='.tsv', prefix='deeptools_testfile_', delete=False) + args = "-in {0}test_samples.npz -o {1} --outFileNameData {2}".format(TEST_DATA, plotfile.name, tsvfile.name).split() + deeptools.plotPCA.main(args) + + # Columns: Component, wt1, wt2, wt3, kd1, kd2, kd3, Eigenvalue + data = np.loadtxt(tsvfile.name, skiprows=1) + assert data.shape == (6, 8), f"unexpected shape {data.shape}" + # Component index column + np.testing.assert_array_equal(data[:, 0], np.arange(1, 7)) + eigenvalues = data[:, -1] + expected_eigenvalues = np.array([ + 5.807692278755936, 0.07423028883557825, 0.04897177773493676, + 0.03680941552538939, 0.026706723301448194, 0.017613563942900697, + ]) + np.testing.assert_allclose(eigenvalues, expected_eigenvalues, rtol=1e-5) + os.remove(plotfile.name) os.remove(tsvfile.name) \ No newline at end of file