From 9049082c20363a5a464a88202193ddb04a28d5eb Mon Sep 17 00:00:00 2001 From: samebdon <33068203+samebdon@users.noreply.github.com> Date: Sat, 6 Dec 2025 08:58:58 +0000 Subject: [PATCH 1/8] cibuildwheel fix (#245) 0.5.3 release ready * Edit homepage and description * Update README.md * Update pyproject.toml * Create build_pip.yml * Delete .github/workflows/build_pip.yml * Update build.yml * adding a rule on creating the directory if does not exist yet * develop->dev in build.yml * amend setup.py to force BinaryDistribution * Min macosx deployment target for c libraries in pyproject.toml * Update README.md * Update README.md * Update publish.yml with pypi pwd from secrets * minimum required macos dev target * beta testing 0.5.3b for pypi * args.format -> plot task * version -> 3b * svg support for people who really want it * updating macos-13 to macos-15-intel due to depreciation * macos-13 depreciation * python 3.13 and 3.14 * python 3.13 and 3.14 * Update README.md * Update pyproject.toml * Typo cli.py * remove dev branch build and testing * API token obsolete with trusted publishing * add smudgeplot pypi url to publish environment --------- Co-authored-by: KamilSJaron --- .github/workflows/build.yml | 6 +++--- .github/workflows/publish.yml | 6 ++++-- Makefile | 5 ++++- README.md | 23 +++++++++++++++-------- pyproject.toml | 5 ++++- setup.py | 8 ++++++-- src/smudgeplot/cli.py | 6 +++--- 7 files changed, 39 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a30dc58..49e3b78 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,7 +2,7 @@ name: Build and Test on: push: - branches: [main, master, develop] + branches: [main, master] pull_request: branches: [main, master] @@ -14,7 +14,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest] - python-version: ["3.9", "3.10", "3.11", "3.12"] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13","3.14"] steps: - uses: actions/checkout@v4 @@ -50,7 +50,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-13, macos-14] # macos-13=x86, macos-14=arm64 + os: [ubuntu-latest, macos-15-intel, macos-14] # macos-15-intel=x86, macos-14=arm64 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 8ad5979..1170dae 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -10,7 +10,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-13, macos-14] + os: [ubuntu-latest, macos-15-intel, macos-14] steps: - uses: actions/checkout@v4 @@ -48,7 +48,9 @@ jobs: name: Publish to PyPI needs: [build-wheels, build-sdist] runs-on: ubuntu-latest - environment: pypi + environment: + name: pypi + url: https://pypi.org/project/smudgeplot permissions: id-token: write # Required for trusted publishing diff --git a/Makefile b/Makefile index bb4da2b..4834060 100644 --- a/Makefile +++ b/Makefile @@ -8,11 +8,14 @@ endif HET_KMERS_INST = $(INSTALL_PREFIX)/bin/hetmers $(INSTALL_PREFIX)/bin/extract_kmer_pairs .PHONY : default -default: exec/hetmers exec/extract_kmer_pairs +default: exec/ exec/hetmers exec/extract_kmer_pairs .PHONY : install install : $(HET_KMERS_INST) +exec/: + mkdir -p exec + $(INSTALL_PREFIX)/bin/% : exec/% install -C $< $(INSTALL_PREFIX)/bin diff --git a/README.md b/README.md index 10bd1d0..c82d04a 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,12 @@ # Smudgeplot -**_Version: 0.5.1 Skylight_** +**_Version: 0.5.3 Skylight_** **_Authors: Sam Ebdon, [Gene W Myers](https://github.com/thegenemyers) and [Kamil S. Jaron](https://github.com/KamilSJaron), Tianyi Ma._** -We keep the same pythonic interface; the interface of this and previous versions are very similar and largely compatible. - -Current state: RUNNING; beta-testing; - ## Installation -This version of smudgeplot operates on FastK k-mer databases. The smudgeplot installation consists of a python package and C-backend to search for all the k-mer pairs (hetmers) and extract sequences of k-mer pairs (extract_kmer_pairs). +This version of smudgeplot operates on FastK k-mer databases. The smudgeplot installation consists of a python package and C-backend to search for all the k-mer pairs (smudgeplot hetmers) and extract sequences of k-mer pairs (smudgeplot extract). We recommend installing smudgeplot within a [conda](https://conda-forge.org/download/) environment. @@ -19,7 +15,10 @@ We recommend installing smudgeplot within a [conda](https://conda-forge.org/down conda create -n smudgeplot && conda activate smudgeplot conda install pip -#download and install +# install via pypi +pip install smudgeplot + +# or download and install directly. See below if you need to compile the C dependencies. git clone https://github.com/KamilSJaron/smudgeplot.git cd smudgeplot && pip install . smudgeplot -h # check installation succeeded @@ -31,7 +30,7 @@ Note the smudgeplot version downloadable from conda itself is not currently up t ### Compiling the C code -The process above install everything including compilation of the C backend. If you would like to know how to compile the code yourself you can simply run +The process above should install everything including compilation of the C backend. If you need or would like to know how to compile the code yourself you can simply run ``` make @@ -39,6 +38,14 @@ make This will not, however, install the smudgeplot python package. +### Pypi installation [EXPERIMENTAL] + +We are working on packaging smudgeplot for pypi. You are welcome to try installing from pypi if you are interested and please open an issue if you have problems. If it fails please follow the main instructions above to install for now. + +``` +pip install smudgeplot +``` + ## Example run on Saccharomyces data Requires ~2.1GB of space and `FastK` and `smudgeplot` installed. diff --git a/pyproject.toml b/pyproject.toml index 7220e30..ade4459 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "smudgeplot" -version = "0.5.1" +version = "0.5.3" description = "Inference of ploidy and heterozygosity structure using whole genome sequencing data" readme = "README.md" license = "Apache-2.0" @@ -38,6 +38,8 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Operating System :: POSIX :: Linux", "Operating System :: MacOS", "Intended Audience :: Science/Research", @@ -67,6 +69,7 @@ smudgeplot = ["bin/*"] # Skip 32-bit, PyPy, musllinux, and Windows (no Windows support for now) skip = ["*-win32", "*-win_amd64", "*-manylinux_i686", "pp*", "*-musllinux*"] build = ["cp39-*", "cp310-*", "cp311-*", "cp312-*"] +environment = { MACOSX_DEPLOYMENT_TARGET = "11.0" } # Test that the CLI works after building test-command = "smudgeplot --version" diff --git a/setup.py b/setup.py index add6518..de1df16 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ from setuptools import setup from setuptools.command.build_py import build_py from setuptools.command.develop import develop - +from setuptools.dist import Distribution class CompilationError(Exception): """Raised when C binary compilation fails.""" @@ -132,10 +132,14 @@ def run(self): print("Continuing with editable install, but binaries will not work.", file=sys.stderr) super().run() +class BinaryDistribution(Distribution): + def has_ext_modules(self): + return True setup( cmdclass={ "build_py": BuildPyWithBinaries, "develop": DevelopWithBinaries, - } + }, + distclass=BinaryDistribution ) diff --git a/src/smudgeplot/cli.py b/src/smudgeplot/cli.py index 086e851..8eebf1b 100755 --- a/src/smudgeplot/cli.py +++ b/src/smudgeplot/cli.py @@ -78,7 +78,7 @@ def __init__(self): tasks: cutoff Calculate meaningful values for lower kmer histogram cutoff. hetmers Calculate unique kmer pairs from a FastK k-mer database. peak_aggregation Agregates smudges using local aggregation algorithm; prints assignments to stdout. - plot Generate 2d histogram; infere ploidy and plot a smudgeplot. + plot Generate 2d histogram; infer ploidy and plot a smudgeplot. all Runs all the steps (with default options) extract Extract kmer pair sequences from a FastK k-mer database. """ @@ -301,7 +301,7 @@ def add_plotting_arguments(self, argparser): "--format", default="png", help="Output format for the plots (default png)", - choices=["pdf", "png"], + choices=["pdf", "png", "svg"], ) argparser.add_argument( "--json_report", @@ -372,7 +372,7 @@ def main(): smudge_tab = smg.read_csv(args.smudgefile, sep="\t", names=["structure", "size", "rel_size"]) cov_tab = smg.load_hetmers(args.infile) smudgeplot_data = smg.SmudgeplotData(cov_tab, smudge_tab, args.n) - smg.prepare_smudgeplot_data_for_plotting(smudgeplot_data, args.o, title, upper_ylim=args.ylim) + smg.prepare_smudgeplot_data_for_plotting(smudgeplot_data, args.o, title, upper_ylim=args.ylim, fmt=args.format) smg.smudgeplot(smudgeplot_data, log=False, palette=args.col_ramp, invert_cols=args.invert_cols) smg.smudgeplot(smudgeplot_data, log=True, palette=args.col_ramp, invert_cols=args.invert_cols) From 399e0bf68af48c3ed4f7f49dfebec4dba3a78245 Mon Sep 17 00:00:00 2001 From: James Gilbert Date: Tue, 27 Jan 2026 18:09:27 +0000 Subject: [PATCH 2/8] Check subprocess exit and tidy up command line generation --- src/lib/PloidyList.c | 2 +- src/lib/PloidyPlot.c | 2 +- src/smudgeplot/cli.py | 90 +++++++++++++++++++++---------------------- 3 files changed, 46 insertions(+), 48 deletions(-) diff --git a/src/lib/PloidyList.c b/src/lib/PloidyList.c index 6f1d9e7..55410fa 100644 --- a/src/lib/PloidyList.c +++ b/src/lib/PloidyList.c @@ -1222,7 +1222,7 @@ int main(int argc, char *argv[]) int flags[128]; char *eptr; - ARG_INIT("PloidyList"); + ARG_INIT("extract_kmer_pairs"); OUT = NULL; ETHRESH = 4; diff --git a/src/lib/PloidyPlot.c b/src/lib/PloidyPlot.c index 298ddd3..34953cd 100644 --- a/src/lib/PloidyPlot.c +++ b/src/lib/PloidyPlot.c @@ -1247,7 +1247,7 @@ int main(int argc, char *argv[]) int flags[128]; char *eptr; - ARG_INIT("PloidyPlot"); + ARG_INIT("hetmers"); OUT = NULL; ETHRESH = 4; diff --git a/src/smudgeplot/cli.py b/src/smudgeplot/cli.py index 8eebf1b..b12a4e1 100755 --- a/src/smudgeplot/cli.py +++ b/src/smudgeplot/cli.py @@ -2,10 +2,13 @@ import argparse import os +import shlex import shutil +import subprocess import sys from importlib.metadata import version from pathlib import Path +from typing import Any import numpy as np @@ -41,30 +44,32 @@ def get_binary_path(name: str) -> str: if system_binary: return system_binary - raise FileNotFoundError( - f"Binary '{name}' not found. Please ensure smudgeplot is properly installed. " + msg = ( + f"Binary '{name}' not found. Please ensure smudgeplot is properly installed.\n" f"Checked locations:\n" - f" - Package: {bundled_binary}\n" - f" - System PATH: (not found)\n" + f" - Package: {bundled_binary.parent}\n" + f" - System PATH: {os.get_exec_path()}\n" f"\nYou may need to reinstall smudgeplot or install the binaries manually." ) + raise FileNotFoundError(msg) -def run_binary(name: str, args: str) -> int: +def run_binary(name: str, args: list[Any]) -> None: """ Run a binary with the given arguments. Args: name: Name of the binary - args: Space-separated argument string + args: List of (stringify-able) arguments - Returns: - Return code from the binary + Throws: + subprocess.CalledProcessError on non-zero exit of the command """ - binary_path = get_binary_path(name) - cmd = f"{binary_path} {args}" - sys.stderr.write(f"Calling: {name} {args}\n") - return os.system(cmd) + cmd_line = [get_binary_path(name)] + for x in args: + cmd_line.append(str(x)) + sys.stderr.write(f"Calling: {shlex.join(cmd_line)}\n") + subprocess.run(cmd_line, check=True) class Parser: @@ -332,41 +337,38 @@ def main(): fin() if _parser.task == "hetmers": - # PloidyPlot is expected to be installed in the system as well as the R library supporting it - plot_args = " -o" + str(args.o) - plot_args += " -e" + str(args.L) - plot_args += " -T" + str(args.t) + hetmer_args = [ + f"-o{args.o}", + f"-e{args.L}", + f"-T{args.t}", + ] if args.verbose: - plot_args += " -v" + hetmer_args.append("-v") if args.tmp != ".": - plot_args += " -P" + args.tmp - plot_args += " " + args.infile + hetmer_args.append(f"-P{args.tmp}") + hetmer_args.append(args.infile) - run_binary("hetmers", plot_args) + run_binary("hetmers", hetmer_args) fin() if _parser.task == "extract": - plot_args = " -o" + str(args.o) - plot_args += " -T" + str(args.t) + extract_args = [ + f"-o{args.o}", + f"-T{args.t}", + ] if args.verbose: - plot_args += " -v" + extract_args.append("-v") if args.tmp != ".": - plot_args += " -P" + args.tmp - plot_args += " " + args.infile - if args.sma.endswith(".sma"): - plot_args += " " + args.sma.removesuffix(".sma") - else: - plot_args += " " + args.sma + extract_args.append(f"-P{args.tmp}") + extract_args.append(args.infile) + extract_args.append(args.sma.removesuffix(".sma")) - run_binary("extract_kmer_pairs", plot_args) + run_binary("extract_kmer_pairs", extract_args) fin() - if args.title: - title=args.title - else: - title = ".".join(args.infile.split("/")[-1].split(".")[0:2]) + title = args.title or str(Path(args.infile).with_suffix("").name) if _parser.task == "plot": smudge_tab = smg.read_csv(args.smudgefile, sep="\t", names=["structure", "size", "rel_size"]) @@ -396,12 +398,11 @@ def main(): coverages.local_aggregation(distance=args.d, noise_filter=1000, mask_errors=True) coverages.count_kmers() sys.stderr.write( - f"\t\ - Total kmers: {coverages.total_kmers}\n\t \ - Genomic kmers: {coverages.total_genomic_kmers}\n\t \ - Genomic kmers in smudges: {coverages.total_genomic_kmers_in_smudges}\n\t \ - Sequencing errors: {coverages.total_error_kmers}\n\t \ - Fraction of errors: {round(coverages.total_error_kmers/coverages.total_kmers, 3)}" + f"\nTotal kmers: {coverages.total_kmers}\n" + f"Genomic kmers: {coverages.total_genomic_kmers}\n" + f"Genomic kmers in smudges: {coverages.total_genomic_kmers_in_smudges}\n" + f"Sequencing errors: {coverages.total_error_kmers}\n" + f"Fraction of errors: {coverages.error_fraction:.3f}\n" ) smudge_size_cutoff = ( @@ -420,11 +421,7 @@ def main(): delimiter="\t", ) - limit = 0.7 - if coverages.error_fraction < limit: - cov = smudges.cov - else: - cov = 0 + cov = smudges.cov if coverages.error_fraction < 0.7 else 0 sys.stderr.write("\nCreating centrality plot\n") smudges.centrality_plot(args.o, args.format) @@ -459,10 +456,11 @@ def main(): json_report=args.json_report, input_params=vars(args), palette=args.col_ramp, - invert_cols=args.invert_cols + invert_cols=args.invert_cols, ) fin() + if __name__ == "__main__": main() From 0b0c5178fb11ea46bec8a268e216e9ababee954a Mon Sep 17 00:00:00 2001 From: James Gilbert Date: Wed, 28 Jan 2026 12:04:14 +0000 Subject: [PATCH 3/8] Include packaging >= 25.0 dependency for GitHub wheel builds --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index ade4459..a6b1f3e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,6 +28,7 @@ maintainers = [ dependencies = [ "numpy>=1.20.0", "matplotlib>=3.4.0", + "packaging >= 25.0", "pandas>=1.3.0", ] From cde1340f585b365b9f013053726bc6abab2b2df5 Mon Sep 17 00:00:00 2001 From: James Gilbert Date: Wed, 28 Jan 2026 12:58:17 +0000 Subject: [PATCH 4/8] Move packaging into build system requirements --- pyproject.toml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a6b1f3e..c5ab0f5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,9 @@ [build-system] -requires = ["setuptools>=61.0", "wheel"] +requires = [ + "packaging >= 25.0", + "setuptools>=61.0", + "wheel", +] build-backend = "setuptools.build_meta" [project] @@ -28,7 +32,6 @@ maintainers = [ dependencies = [ "numpy>=1.20.0", "matplotlib>=3.4.0", - "packaging >= 25.0", "pandas>=1.3.0", ] From ca763e52ffc027a39d364006b6e5cf38f2f9a79b Mon Sep 17 00:00:00 2001 From: James Gilbert Date: Wed, 28 Jan 2026 13:21:16 +0000 Subject: [PATCH 5/8] Try latest version of cibuildwheel --- .github/workflows/build.yml | 4 ++-- pyproject.toml | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 49e3b78..acf05fe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest] - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13","3.14"] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] steps: - uses: actions/checkout@v4 @@ -56,7 +56,7 @@ jobs: - uses: actions/checkout@v4 - name: Build wheels - uses: pypa/cibuildwheel@v2.21.3 + uses: pypa/cibuildwheel@v3.3.1 # Config is read from pyproject.toml [tool.cibuildwheel] - uses: actions/upload-artifact@v4 diff --git a/pyproject.toml b/pyproject.toml index c5ab0f5..766db9a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,5 @@ [build-system] requires = [ - "packaging >= 25.0", "setuptools>=61.0", "wheel", ] @@ -72,7 +71,7 @@ smudgeplot = ["bin/*"] [tool.cibuildwheel] # Skip 32-bit, PyPy, musllinux, and Windows (no Windows support for now) skip = ["*-win32", "*-win_amd64", "*-manylinux_i686", "pp*", "*-musllinux*"] -build = ["cp39-*", "cp310-*", "cp311-*", "cp312-*"] +build = ["cp39-*", "cp310-*", "cp311-*", "cp312-*", "cp313-*", "cp314-*"] environment = { MACOSX_DEPLOYMENT_TARGET = "11.0" } # Test that the CLI works after building From 5d33d7be51f941d3bb9536dea7e9b24553d9b177 Mon Sep 17 00:00:00 2001 From: James Gilbert Date: Thu, 29 Jan 2026 14:30:45 +0000 Subject: [PATCH 6/8] Optionally write JSON report file alongside kmerpairs.smu file --- src/smudgeplot/cli.py | 15 ++++++++++++- src/smudgeplot/smudgeplot.py | 42 ++++++++++++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/smudgeplot/cli.py b/src/smudgeplot/cli.py index b12a4e1..7601ef4 100755 --- a/src/smudgeplot/cli.py +++ b/src/smudgeplot/cli.py @@ -99,6 +99,7 @@ def __init__(self): default=False, help="Print the version and exit.", ) + # print version is a special case if len(sys.argv) > 1: if sys.argv[1] in ["-v", "--version"]: @@ -149,6 +150,7 @@ def hetmers(self): "-L", help="Count threshold below which k-mers are considered erroneous.", type=int, + required=True, ) argparser.add_argument("-t", help="Number of threads (default 4).", type=int, default=4) argparser.add_argument( @@ -162,6 +164,13 @@ def hetmers(self): default=".", ) argparser.add_argument("--verbose", action="store_true", default=False, help="Verbose mode.") + argparser.add_argument( + "--json_report", + action="store_true", + default=False, + help="Write a JSON format report recording the selected parameters (default False)", + ) + self.arguments = argparser.parse_args(sys.argv[2:]) def peak_aggregation(self): @@ -337,6 +346,7 @@ def main(): fin() if _parser.task == "hetmers": + hetmer_args = [ f"-o{args.o}", f"-e{args.L}", @@ -350,6 +360,9 @@ def main(): run_binary("hetmers", hetmer_args) + if args.json_report: + smg.save_hetmers_json_report(args.o, input_params=vars(args)) + fin() if _parser.task == "extract": @@ -368,7 +381,7 @@ def main(): fin() - title = args.title or str(Path(args.infile).with_suffix("").name) + title = args.title or Path(args.infile).stem if _parser.task == "plot": smudge_tab = smg.read_csv(args.smudgefile, sep="\t", names=["structure", "size", "rel_size"]) diff --git a/src/smudgeplot/smudgeplot.py b/src/smudgeplot/smudgeplot.py index 59a123d..5d7a553 100644 --- a/src/smudgeplot/smudgeplot.py +++ b/src/smudgeplot/smudgeplot.py @@ -1,10 +1,12 @@ #!/usr/bin/env python3 import json +import shlex import sys from collections import defaultdict from importlib.metadata import version from math import ceil, log +from pathlib import Path from statistics import fmean import matplotlib as mpl @@ -12,7 +14,7 @@ import numpy as np from matplotlib.collections import PatchCollection from numpy import arange, argmin, concatenate -from pandas import DataFrame, Series, concat, read_csv # type: ignore +from pandas import DataFrame, Series, concat, read_csv class Coverages: @@ -376,11 +378,14 @@ def generate_plots( if json_report: write_json_report(smudgeplot_data, input_params) + def write_json_report(smg_data, input_params=None, min_size=0.03): + hetmers_report = read_hetmers_report_json(input_params["infile"]) report = { "version": version("smudgeplot"), - "commandline_arguments": sys.argv[1:], + "commandline_arguments": shlex.join(sys.argv[1:]), "input_parameters": input_params, + "hetmers": hetmers_report, "haploid_coverage": float(f"{smg_data.cov:.3f}"), "error_fraction": smg_data.error_fraction, "top_smudges": [ @@ -400,8 +405,37 @@ def write_json_report(smg_data, input_params=None, min_size=0.03): for row in smg_data.smudge_tab.itertuples(index=False) ], } - with open(smg_data.json_report_file, "w") as fh: - fh.write(json.dumps(report, indent=2) + "\n") + write_json_file(smg_data.json_report_file, report) + + +def save_hetmers_json_report(outfile, input_params=None): + report = { + "version": version("smudgeplot"), + "commandline_arguments": shlex.join(sys.argv[1:]), + "input_parameters": input_params, + } + write_json_file(f"{outfile}_report.json", report) + + +def write_json_file(filename: str, data): + Path(filename).write_text(json.dumps(data, indent=2) + "\n") + + +def read_hetmers_report_json(hetmers: str): + """ + Returns the parsed contents of the hetmers report JSON file if it exists + and its modification time is the same as or more recent than the hetmers + file itself. + """ + hetmers_file = Path(hetmers) + report_file = Path(f"{hetmers_file.stem}_report.json") + + if ( + report_file.exists() + and report_file.stat().st_mtime >= hetmers_file.stat().st_mtime + ): + return json.loads(report_file.read_text()) + return None def prepare_smudgeplot_data_for_plotting(smudgeplot_data, output, title, fmt=None, upper_ylim=None): From 2c7d74ca7535139cdfa951ddbaf11ecda1c19467 Mon Sep 17 00:00:00 2001 From: James Gilbert Date: Thu, 29 Jan 2026 15:42:18 +0000 Subject: [PATCH 7/8] Rename JSON report hetmers key to hetmers_input --- src/smudgeplot/smudgeplot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smudgeplot/smudgeplot.py b/src/smudgeplot/smudgeplot.py index 5d7a553..f7aa7b5 100644 --- a/src/smudgeplot/smudgeplot.py +++ b/src/smudgeplot/smudgeplot.py @@ -385,7 +385,7 @@ def write_json_report(smg_data, input_params=None, min_size=0.03): "version": version("smudgeplot"), "commandline_arguments": shlex.join(sys.argv[1:]), "input_parameters": input_params, - "hetmers": hetmers_report, + "hetmers_input": hetmers_report, "haploid_coverage": float(f"{smg_data.cov:.3f}"), "error_fraction": smg_data.error_fraction, "top_smudges": [ From 8a71b8ec99ab31368947c9701f720b642917617f Mon Sep 17 00:00:00 2001 From: James Gilbert Date: Fri, 30 Jan 2026 10:03:32 +0000 Subject: [PATCH 8/8] Fix coverages typo --- playground/alternative_fitting/pair_clustering.py | 2 +- src/smudgeplot/cli.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/playground/alternative_fitting/pair_clustering.py b/playground/alternative_fitting/pair_clustering.py index 1cd3eb3..059b40c 100644 --- a/playground/alternative_fitting/pair_clustering.py +++ b/playground/alternative_fitting/pair_clustering.py @@ -13,7 +13,7 @@ #### parser = argparse.ArgumentParser() -parser.add_argument('infile', nargs='?', help='name of the input tsv file with covarages and frequencies.') +parser.add_argument('infile', nargs='?', help='name of the input tsv file with coverages and frequencies.') parser.add_argument('-nf', '-noise_filter', help='Do not agregate into smudge k-mer pairs with frequency lower than this parameter', type=int, default=50) parser.add_argument('-d', '-distance', help='Manthattan distance of k-mer pairs that are considered neioboring for the local agregation purposes.', type=int, default=5) parser.add_argument('--mask_errors', help='instead of reporting assignments to individual smudges, just remove all monotonically decreasing points from the error line', action="store_true", default = False) diff --git a/src/smudgeplot/cli.py b/src/smudgeplot/cli.py index 7601ef4..30f0cec 100755 --- a/src/smudgeplot/cli.py +++ b/src/smudgeplot/cli.py @@ -182,7 +182,7 @@ def peak_aggregation(self): description="Aggregates smudges using local aggregation algorithm.") argparser.add_argument( "infile", - help="Name of the input smu file with covarages and frequencies.", + help="Name of the input smu file with coverages and frequencies.", ) argparser.add_argument( "-nf", @@ -261,7 +261,7 @@ def all(self): description="Runs all the steps (with default options).") argparser.add_argument( "infile", - help="Name of the input tsv file with covarages and frequencies.", + help="Name of the input tsv file with coverages and frequencies.", ) argparser.add_argument( "-o",