From 0c85dd1994e1f9770b0ac011ad403ef9ee223b86 Mon Sep 17 00:00:00 2001 From: James Li Date: Mon, 16 Dec 2024 14:13:39 -0500 Subject: [PATCH 01/10] fix attribute error --- src/finaletoolkit/cli/main_cli.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/finaletoolkit/cli/main_cli.py b/src/finaletoolkit/cli/main_cli.py index 620b670..3e8be99 100644 --- a/src/finaletoolkit/cli/main_cli.py +++ b/src/finaletoolkit/cli/main_cli.py @@ -975,15 +975,18 @@ def main_cli(): parser = main_cli_parser() args = parser.parse_args() - try: - function = args.func - funcargs = vars(args) - funcargs.pop('func') + if hasattr(args, "func"): + try: + function = args.func + funcargs = vars(args) + funcargs.pop('func') - function(**funcargs) - except AttributeError as e: - stderr.write(f"FinaleToolkit recieved AttributeError: {e}\n") - stderr.write("Please see usage instructions below.\n") + function(**funcargs) + except AttributeError as e: + stderr.write(f"FinaleToolkit recieved AttributeError: {e}\n") + stderr.write("Please see usage instructions below.\n") + parser.print_help() + else: parser.print_help() From 980040c37b96298cd64a9a1678370ae580d81669 Mon Sep 17 00:00:00 2001 From: James Li Date: Mon, 16 Dec 2024 14:15:18 -0500 Subject: [PATCH 02/10] update changelog and version --- CHANGELOG.md | 4 ++++ src/finaletoolkit/version.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a9fd38..981ebe1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ The format is based on and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.9.1] - 2024-12-13 +### Fixed +- CLI no longer prints an error message if `finaletoolkit` is called without args. + ## [0.9.0] - 2024-12-13 ### Removed diff --git a/src/finaletoolkit/version.py b/src/finaletoolkit/version.py index f92507d..549e6e3 100644 --- a/src/finaletoolkit/version.py +++ b/src/finaletoolkit/version.py @@ -2,4 +2,4 @@ Single-source module for the package version number. """ -__version__ = "0.9.0" +__version__ = "0.9.1" From da27adee02370a36b2116e7757fcf659d580506c Mon Sep 17 00:00:00 2001 From: James Li Date: Mon, 16 Dec 2024 15:11:33 -0500 Subject: [PATCH 03/10] rename some CLI args to exclude underscores --- src/finaletoolkit/cli/main_cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/finaletoolkit/cli/main_cli.py b/src/finaletoolkit/cli/main_cli.py index 3e8be99..13f60f0 100644 --- a/src/finaletoolkit/cli/main_cli.py +++ b/src/finaletoolkit/cli/main_cli.py @@ -380,14 +380,14 @@ def main_cli_parser(): 'intervals specified in interval file.') cli_wps.add_argument( '-i', - '--interval_size', + '--interval-size', default=5000, type=int, help='Size in bp of each interval in the interval file. Default is ' '5000') cli_wps.add_argument( '-W', - '--window_size', + '--window-size', default=120, type=int, help='Size of the sliding window used to calculate WPS scores.' From e634d97d434ad1d5cfc63af86095c5db872eb21c Mon Sep 17 00:00:00 2001 From: James Li Date: Mon, 16 Dec 2024 15:14:09 -0500 Subject: [PATCH 04/10] rename more CLI args to not include underscores --- src/finaletoolkit/cli/main_cli.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/finaletoolkit/cli/main_cli.py b/src/finaletoolkit/cli/main_cli.py index 13f60f0..967233d 100644 --- a/src/finaletoolkit/cli/main_cli.py +++ b/src/finaletoolkit/cli/main_cli.py @@ -59,7 +59,7 @@ def main_cli_parser(): 'coverage over.') cli_coverage.add_argument( '-o', - '--output_file', + '--output-file', default='-', help='A BED file containing coverage values over the intervals ' 'specified in interval file.') @@ -93,7 +93,7 @@ def main_cli_parser(): ) cli_coverage.add_argument( '-p', - '--intersect_policy', + '--intersect-policy', choices=['midpoint', 'any'], default='midpoint', type=str, @@ -101,7 +101,7 @@ def main_cli_parser(): ' given interval. See User Guide for more information.') cli_coverage.add_argument( '-q', - '--quality_threshold', + '--quality-threshold', default=30, type=int, help='Minimum mapping quality threshold.') @@ -162,7 +162,7 @@ def main_cli_parser(): ) cli_frag_length_bins.add_argument( '-p', - '--intersect_policy', + '--intersect-policy', choices=['midpoint', 'any'], default='midpoint', type=str, @@ -176,7 +176,7 @@ def main_cli_parser(): 'into.') cli_frag_length_bins.add_argument( '-o', - '--output_file', + '--output-file', default='-', type=str, help='A .TSV file containing containing fragment lengths binned' @@ -188,7 +188,7 @@ def main_cli_parser(): ) cli_frag_length_bins.add_argument( '-q', - '--quality_threshold', + '--quality-threshold', default=30, type=int, help="Minimum mapping quality threshold.") @@ -231,7 +231,7 @@ def main_cli_parser(): ) cli_frag_length_intervals.add_argument( '-p', - '--intersect_policy', + '--intersect-policy', choices=['midpoint', 'any'], default='midpoint', type=str, @@ -374,7 +374,7 @@ def main_cli_parser(): help='A .chrom.sizes file containing chromosome names and sizes.') cli_wps.add_argument( '-o', - '--output_file', + '--output-file', default='-', help='A bigWig file containing the WPS results over the ' 'intervals specified in interval file.') @@ -422,7 +422,7 @@ def main_cli_parser(): 'calculation. Deprecated. Use --max-length instead.') cli_wps.add_argument( '-q', - '--quality_threshold', + '--quality-threshold', default=30, type=int, help="Minimum mapping quality threshold. Default is 30") @@ -861,7 +861,7 @@ def main_cli_parser(): help='Output BAM file path.') cli_filter_bam.add_argument( '-q', - '--quality_threshold', + '--quality-threshold', type=int, default=30, help='Minimum mapping quality threshold.') From 8a5e34ff6e64f524b6df53f3ffd044b2fb98030d Mon Sep 17 00:00:00 2001 From: James Li Date: Mon, 16 Dec 2024 15:27:10 -0500 Subject: [PATCH 05/10] correct wps descriptions and docstrings --- src/finaletoolkit/cli/main_cli.py | 7 ++++--- src/finaletoolkit/frag/multi_wps.py | 9 ++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/finaletoolkit/cli/main_cli.py b/src/finaletoolkit/cli/main_cli.py index 967233d..cf39b1a 100644 --- a/src/finaletoolkit/cli/main_cli.py +++ b/src/finaletoolkit/cli/main_cli.py @@ -365,7 +365,7 @@ def main_cli_parser(): 'data.') cli_wps.add_argument( 'site_bed', - help='Path to a BED file containing intervals to calculate WPS ' + help='Path to a BED file containing sites to calculate WPS ' 'over. The intervals in this BED file should be sorted, first ' 'by `contig` then `start`.') cli_wps.add_argument( @@ -383,8 +383,9 @@ def main_cli_parser(): '--interval-size', default=5000, type=int, - help='Size in bp of each interval in the interval file. Default is ' - '5000') + help='Size in bp of the intervals to calculate WPS over. These' + 'new intervals are centered over those specified in the site_bed.' + 'Default is 5000') cli_wps.add_argument( '-W', '--window-size', diff --git a/src/finaletoolkit/frag/multi_wps.py b/src/finaletoolkit/frag/multi_wps.py index 5719b61..0f60859 100644 --- a/src/finaletoolkit/frag/multi_wps.py +++ b/src/finaletoolkit/frag/multi_wps.py @@ -44,7 +44,7 @@ def multi_wps( BAM, SAM, or tabix file containing paired-end fragment reads or its path. `AlignmentFile` must be opened in read mode. site_bed: str - BED file containing intervals to perform WPS on. The intervals + BED file containing sites to perform WPS on. The intervals in this BED file should be sorted, first by `contig` then `start`. chrom_sizes: str or pathlike, optional @@ -55,8 +55,11 @@ def multi_wps( Size of window to calculate WPS. Default is k = 120, equivalent to L-WPS. interval_size : int, optional - Size of each interval specified in the bed file. Should be the - same for every interval. Default is 5000. + Size of intervals to calculate WPS over. A mid-point is calculated + for each interval in the BED file, and an interval of the specified + size is used. This is helpful especially when calculating a window + around a genomic feature like transcription start sites. Default + is 5000. min_length : int, optional Specifies lowest fragment length included in calculation. Default is 120, equivalent to long fraction. From f2569db3df9782b9ee327c9d4fa4e0e657484e97 Mon Sep 17 00:00:00 2001 From: James Li Date: Mon, 16 Dec 2024 15:46:16 -0500 Subject: [PATCH 06/10] add option to ignore savgol filter --- src/finaletoolkit/cli/main_cli.py | 7 +++++++ src/finaletoolkit/frag/adjust_wps.py | 13 ++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/finaletoolkit/cli/main_cli.py b/src/finaletoolkit/cli/main_cli.py index cf39b1a..ad2b55d 100644 --- a/src/finaletoolkit/cli/main_cli.py +++ b/src/finaletoolkit/cli/main_cli.py @@ -489,6 +489,13 @@ def main_cli_parser(): default=2, type=int, help='Degree polynomial for Savitsky-Golay filter.') + cli_adjust_wps.add_argument( + '-S', + '--exclude-savgol', + dest='savgol', + action='store_false' + help='Do not perform Savitsky-Golay filtering' + 'scores.') cli_adjust_wps.add_argument( '-w', '--workers', diff --git a/src/finaletoolkit/frag/adjust_wps.py b/src/finaletoolkit/frag/adjust_wps.py index 30dc334..fe72d06 100644 --- a/src/finaletoolkit/frag/adjust_wps.py +++ b/src/finaletoolkit/frag/adjust_wps.py @@ -64,6 +64,7 @@ def _single_adjust_wps( mean: bool, subtract_edges: bool, edge_size: int, + savgol: bool, ): """ Takes a wps WIG file and applies a median filter and a Savitsky- @@ -123,9 +124,11 @@ def _single_adjust_wps( else: adjusted_positions, adjusted_scores = _mean_filter( intervals['starts'], intervals['scores'], median_window_size) - - filtered_scores = savgol_filter( - adjusted_scores, savgol_window_size, savgol_poly_deg) + if savgol: + filtered_scores = savgol_filter( + adjusted_scores, savgol_window_size, savgol_poly_deg) + else: + filtered_scores = adjusted_scores assert len(adjusted_positions) == len(filtered_scores) @@ -161,6 +164,7 @@ def adjust_wps( median_window_size: int=1000, savgol_window_size: int=21, savgol_poly_deg: int=2, + savgol: bool=True, mean: bool=False, subtract_edges: bool=False, edge_size: int=500, @@ -191,6 +195,8 @@ def adjust_wps( Size of Savitsky Golay filter window. Default is 21. savgol_poly_deg : int, optional Degree polynomial for Savitsky Golay filter. Default is 2. + savgol : bool, optional + Set to true to perform Savitsky-Golay filtering. mean : bool, optional If true, a mean filter is used instead of median. Default is False. @@ -256,6 +262,7 @@ def adjust_wps( mean, subtract_edges, edge_size, + savgol )) else: raise ValueError('Invalid filetype for interval_file.') From 9890eff4df78298d5f448555c21c007c16101804 Mon Sep 17 00:00:00 2001 From: James Li Date: Mon, 16 Dec 2024 15:48:29 -0500 Subject: [PATCH 07/10] missing comma --- src/finaletoolkit/cli/main_cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/finaletoolkit/cli/main_cli.py b/src/finaletoolkit/cli/main_cli.py index ad2b55d..793f5fa 100644 --- a/src/finaletoolkit/cli/main_cli.py +++ b/src/finaletoolkit/cli/main_cli.py @@ -493,7 +493,7 @@ def main_cli_parser(): '-S', '--exclude-savgol', dest='savgol', - action='store_false' + action='store_false', help='Do not perform Savitsky-Golay filtering' 'scores.') cli_adjust_wps.add_argument( From 5d03c9c9378b2103af3034a9ae7707de537515f9 Mon Sep 17 00:00:00 2001 From: James Li Date: Mon, 16 Dec 2024 15:50:05 -0500 Subject: [PATCH 08/10] update help to include possibility of mean filter --- src/finaletoolkit/cli/main_cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/finaletoolkit/cli/main_cli.py b/src/finaletoolkit/cli/main_cli.py index 793f5fa..f85d2df 100644 --- a/src/finaletoolkit/cli/main_cli.py +++ b/src/finaletoolkit/cli/main_cli.py @@ -475,7 +475,7 @@ def main_cli_parser(): '--median-window-size', default=1000, type=int, - help='Size of the median filter window used to adjust WPS scores.') + help='Size of the median filter or mean filter window used to adjust WPS scores.') cli_adjust_wps.add_argument( '-s', '--savgol-window-size', From f9bf8a4b4f46c930bf58e119b50b3332e72cf447 Mon Sep 17 00:00:00 2001 From: jamesli124 <58196853+jamesli124@users.noreply.github.com> Date: Tue, 17 Dec 2024 15:11:35 -0500 Subject: [PATCH 09/10] frag_length prints results so that max is inclusive --- src/finaletoolkit/frag/frag_length.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/finaletoolkit/frag/frag_length.py b/src/finaletoolkit/frag/frag_length.py index 3d5f8a7..3168055 100644 --- a/src/finaletoolkit/frag/frag_length.py +++ b/src/finaletoolkit/frag/frag_length.py @@ -341,7 +341,7 @@ def frag_length_bins( out.write('min\tmax\tcount\n') for bin, count in zip(bins, counts): - out.write(f'{bin}\t{bin+bin_size}\t{count}\n') + out.write(f'{bin}\t{bin+bin_size-1}\t{count}\n') if histogram_path!=None: plot_histogram(frag_len_dict, num_bins=n_bins, From 15bacd7d41a86d067728391faaa8275dbc70e172 Mon Sep 17 00:00:00 2001 From: jamesli124 <58196853+jamesli124@users.noreply.github.com> Date: Tue, 17 Dec 2024 18:14:33 -0500 Subject: [PATCH 10/10] Update changelog --- CHANGELOG.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 981ebe1..e54b528 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,25 @@ The format is based on and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.9.1] - 2024-12-13 +## [0.9.1] - 2024-12-17 + ### Fixed - CLI no longer prints an error message if `finaletoolkit` is called without args. +- `frag-length-bins`, when writing a file, now writes the interval between +`min` and `max` as inclusive. That is, previously when `min=1` and `max=2`, +only fragments of length 1 are reported. Now when such a result is calculated, +the interval given is `min=1` and `max=1`. +- Updated some descriptions and docstrings. + +### Added +- `adjust-wps` now has an option `-S` or `--exclude-savgol` to not perform +Savitsky-Golay filtering. + +### Changed +- Several CLI options were renamed so that underscores become hyphens. This is +for consistency and to simplify writing commands. -## [0.9.0] - 2024-12-13 +## [0.9.0] - 2024-12-16 ### Removed - `strand_location` arg from `agg_bigwig`