From 65f7f0e3cc04f1a68dc6b2a4dbc3ef123cabfc5a Mon Sep 17 00:00:00 2001 From: mdbarnesUCSD Date: Thu, 1 Aug 2024 13:57:15 -0700 Subject: [PATCH 1/6] Fix: Ensure correct file path construction with os.path.join() --- sigProfilerPlotting/sigProfilerPlotting.py | 39 ++++++++++++++-------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/sigProfilerPlotting/sigProfilerPlotting.py b/sigProfilerPlotting/sigProfilerPlotting.py index 4228e76..6661b3f 100644 --- a/sigProfilerPlotting/sigProfilerPlotting.py +++ b/sigProfilerPlotting/sigProfilerPlotting.py @@ -105,7 +105,8 @@ def clear_plotting_memory(): # the figures are saved to a dictionary of buffers def output_results(savefig_format, output_path, project, figs, context_type, dpi=100): if savefig_format.lower() == "pdf": - pp = PdfPages(output_path + context_type + "_plots_" + project + ".pdf") + file_path = os.path.join(output_path, f"{context_type}_plots_{project}.pdf") + pp = PdfPages(file_path) for fig in figs: if context_type in ("CNV_48", "SV_32"): figs[fig].savefig(pp, format="pdf", bbox_inches="tight") @@ -3021,7 +3022,8 @@ def plotSBS( sys.exit( "The matrix does not match the correct SBS192 format. Please check you formatting and rerun this plotting function." ) - pp = PdfPages(output_path + "SBS_384_plots_" + project + ".pdf") + file_path = os.path.join(output_path, f"SBS_384_plots_{project}.pdf") + pp = PdfPages(file_path) mutations = OrderedDict() try: with open(matrix_path) as f: @@ -3537,7 +3539,8 @@ def plotSBS( "The matrix does not match the correct SBS288 format. Please check you formatting and rerun this plotting function." ) - pp = PdfPages(output_path + "SBS_384_extended_plots_" + project + ".pdf") + file_path = os.path.join(output_path, f"SBS_384_extended_plots_{project}.pdf") + pp = PdfPages(file_path) mutations = OrderedDict() try: with open(matrix_path) as f: @@ -4087,8 +4090,8 @@ def plotSBS( sys.exit( "The matrix does not match the correct SBS6 format. Please check you formatting and rerun this plotting function." ) - - pp = PdfPages(output_path + "SBS_6_plots_" + project + ".pdf") + file_path = os.path.join(output_path, f"SBS_6_plots_{project}.pdf") + pp = PdfPages(file_path) mutations = OrderedDict() total_count = [] @@ -4322,8 +4325,8 @@ def plotSBS( sys.exit( "The matrix does not match the correct SBS192 format. Please check you formatting and rerun this plotting function." ) - - pp = PdfPages(output_path + "SBS_24_plots_" + project + ".pdf") + file_path = os.path.join(output_path, f"SBS_24_plots_{project}.pdf") + pp = PdfPages(file_path) mutations = OrderedDict() try: @@ -4580,7 +4583,8 @@ def plotSBS( "The matrix does not match the correct SBS1536 format. Please check you formatting and rerun this plotting function." ) - pp = PdfPages(output_path + "SBS_1536_plots_" + project + ".pdf") + file_path = os.path.join(output_path, f"SBS_1536_plots_{project}.pdf") + pp = PdfPages(file_path) mutations_96 = OrderedDict() path_list = matrix_path.split("/") @@ -5911,7 +5915,8 @@ def plotSBS( "The matrix does not match the correct SBS4608 format. Please check you formatting and rerun this plotting function." ) - pp = PdfPages(output_path + "SBS_4608_plots_" + project + ".pdf") + file_path = os.path.join(output_path, f"SBS_4608_plots_{project}.pdf") + pp = PdfPages(file_path) path_list = matrix_path.split("/") extension = path_list[-1].split(".") @@ -7751,7 +7756,9 @@ def plotSBS( "The matrix does not match the correct SBS288 format. Please check you formatting and rerun this plotting function." ) - pp = PdfPages(output_path + "SBS_288_Normalized_plots_" + project + ".pdf") + file_path = os.path.join(output_path, f"SBS_288_Normalized_plots_{project}.pdf") + pp = PdfPages(file_path) + mutations = OrderedDict() mutations_TSB = OrderedDict() @@ -8676,7 +8683,9 @@ def plotID( sys.exit( "The matrix does not match the correct SBS96 format. Please check you formatting and rerun this plotting function." ) - pp = PdfPages(output_path + "ID_simple_plots_" + project + ".pdf") + file_path = os.path.join(output_path, f"ID_simple_plots_{project}.pdf") + pp = PdfPages(file_path) + indel_types = [ "1:Del:C:1", @@ -9229,7 +9238,9 @@ def plotID( "The matrix does not match the correct ID-96 format. Please check you formatting and rerun this plotting function." ) - pp = PdfPages(output_path + "ID_TSB_plots_" + project + ".pdf") + file_path = os.path.join(output_path, f"ID_TSB_plots_{project}.pdf") + pp = PdfPages(file_path) + indel_types_tsb = [] tsb_I = ["T", "U", "N", "B", "Q"] @@ -10736,7 +10747,9 @@ def plotDBS( "The matrix does not match the correct SBS96 format. Please check you formatting and rerun this plotting function." ) - pp = PdfPages(output_path + "DBS_186_plots_" + project + ".pdf") + file_path = os.path.join(output_path, f"DBS_186_plots_{project}.pdf") + pp = PdfPages(file_path) + dinucs = [ "TT>GG", From 630e241723e034f1f26c1798db4c3ef78504b295 Mon Sep 17 00:00:00 2001 From: mdbarnesUCSD Date: Thu, 1 Aug 2024 15:57:13 -0700 Subject: [PATCH 2/6] Add environmental variable SIGPROFILERPLOTTING_VOLUME --- sigProfilerPlotting/sigProfilerPlotting.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sigProfilerPlotting/sigProfilerPlotting.py b/sigProfilerPlotting/sigProfilerPlotting.py index 6661b3f..4b989d0 100644 --- a/sigProfilerPlotting/sigProfilerPlotting.py +++ b/sigProfilerPlotting/sigProfilerPlotting.py @@ -242,6 +242,12 @@ def get_default_96labels(): def make_pickle_file(context="SBS96", return_plot_template=False, volume=None): + + # The environmental variable takes precedence over the volume argument + # If the environmental variable is not set, the volume argument is used + volume = os.getenv('SIGPROFILERPLOTTING_VOLUME', volume) + + # Use the default volume when no environmental variable or volume argument is provided if volume is None: volume = SPP_TEMPLATES @@ -744,7 +750,6 @@ def make_pickle_file(context="SBS96", return_plot_template=False, volume=None): else: pickle.dump(plot1, open(path, "wb")) return plot1 - elif context == "DBS78": plot_custom_text = False pcawg = False @@ -1017,7 +1022,6 @@ def make_pickle_file(context="SBS96", return_plot_template=False, volume=None): else: pickle.dump(plot1, open(path, "wb")) return plot1 - elif context == "ID83": plt.rcParams["axes.linewidth"] = 2 plot1 = plt.figure(figsize=(43.93, 12)) From ab30fbd5d4121b3eec1827cac4de6d5690f548f9 Mon Sep 17 00:00:00 2001 From: mdbarnesUCSD Date: Thu, 1 Aug 2024 16:20:05 -0700 Subject: [PATCH 3/6] Improve CLI boolean handling --- .../controllers/cli_controller.py | 52 ++++++++++++++++--- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/sigProfilerPlotting/controllers/cli_controller.py b/sigProfilerPlotting/controllers/cli_controller.py index 8ce4b8d..280e49c 100644 --- a/sigProfilerPlotting/controllers/cli_controller.py +++ b/sigProfilerPlotting/controllers/cli_controller.py @@ -3,6 +3,17 @@ import sigProfilerPlotting as sigPlt +def str2bool(v): + if isinstance(v, bool): + return v + if v.lower() in ("yes", "true", "t", "y", "1"): + return True + elif v.lower() in ("no", "false", "f", "n", "0"): + return False + else: + raise argparse.ArgumentTypeError("Boolean value expected.") + + # Common parser setup for shared arguments def common_plotting_arguments(parser): parser.add_argument("matrix_path", help="The path to the input matrix file.") @@ -12,7 +23,12 @@ def common_plotting_arguments(parser): parser.add_argument("project", help="The name of the project.") parser.add_argument("plot_type", help="The type of plot to generate.") parser.add_argument( - "--percentage", action="store_true", help="Display percentages in the plot." + "--percentage", + type=str2bool, + nargs="?", + const=True, + default=False, + help="Display percentages in the plot.", ) parser.add_argument( "--custom_text_upper", help="Custom text to display at the top of the plot." @@ -40,7 +56,7 @@ def common_plotting_arguments(parser): def parse_arguments_sbs(args: List[str]) -> argparse.Namespace: parser = argparse.ArgumentParser( - prog="SigProfilerPlotting plotDBS", description="Generate DBS plots." + prog="SigProfilerPlotting plotSBS", description="Generate SBS plots." ) common_plotting_arguments(parser) return parser.parse_args(args) @@ -72,10 +88,20 @@ def parse_arguments_sv(args: List[str]) -> argparse.Namespace: ) parser.add_argument("project", help="The name of the project.") parser.add_argument( - "--percentage", action="store_true", help="Display percentages in the plot." + "--percentage", + type=str2bool, + nargs="?", + const=True, + default=False, + help="Display percentages in the plot.", ) parser.add_argument( - "--aggregate", action="store_true", help="Aggregate all samples." + "--aggregate", + type=str2bool, + nargs="?", + const=True, + default=False, + help="Aggregate all samples.", ) parser.add_argument( "--savefig_format", @@ -102,14 +128,26 @@ def parse_arguments_cnv(args: List[str]) -> argparse.Namespace: ) parser.add_argument("project", help="The name of the project.") parser.add_argument( - "--percentage", action="store_true", help="Display percentages in the plot." + "--percentage", + type=str2bool, + nargs="?", + const=True, + default=False, + help="Display percentages in the plot.", ) parser.add_argument( - "--aggregate", action="store_true", help="Aggregate data for the plot." + "--aggregate", + type=str2bool, + nargs="?", + const=True, + default=False, + help="Aggregate data for the plot.", ) parser.add_argument( "--read_from_file", - action="store_true", + type=str2bool, + nargs="?", + const=True, default=True, help="Read data from a file for the plot.", ) From 59b6d634b3143b6f54fb50d7272699b40a35e313 Mon Sep 17 00:00:00 2001 From: mdbarnesUCSD Date: Fri, 2 Aug 2024 13:45:21 -0700 Subject: [PATCH 4/6] Stop creating output directory when PIL_Image is the savefig_format --- sigProfilerPlotting/sigProfilerPlotting.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sigProfilerPlotting/sigProfilerPlotting.py b/sigProfilerPlotting/sigProfilerPlotting.py index 4b989d0..0760c95 100644 --- a/sigProfilerPlotting/sigProfilerPlotting.py +++ b/sigProfilerPlotting/sigProfilerPlotting.py @@ -2095,7 +2095,7 @@ def plot(counts, labels, sample, project, percentage, aggregate=False): return fig # create the output directory if it doesn't exist - if not os.path.exists(output_path): + if not os.path.exists(output_path) and savefig_format.lower() != "pil_image": os.makedirs(output_path) # To reindex the input data @@ -2630,7 +2630,7 @@ def plot(counts, labels, sample, project, percentage, aggregate=False): return fig # create the output directory if it doesn't exist - if not os.path.exists(output_path): + if not os.path.exists(output_path) and savefig_format.lower() != "pil_image": os.makedirs(output_path) df = pd.DataFrame() @@ -2715,7 +2715,7 @@ def plotSBS( load_custom_fonts() # create the output directory if it doesn't exist - if not os.path.exists(output_path): + if not os.path.exists(output_path) and savefig_format.lower() != "pil_image": os.makedirs(output_path) if plot_type == "96": @@ -8346,7 +8346,7 @@ def plotID( dpi=100, ): # create the output directory if it doesn't exist - if not os.path.exists(output_path): + if not os.path.exists(output_path) and savefig_format.lower() != "pil_image": os.makedirs(output_path) # load custom fonts for plotting @@ -10329,7 +10329,7 @@ def plotDBS( dpi=100, ): # create the output directory if it doesn't exist - if not os.path.exists(output_path): + if not os.path.exists(output_path) and savefig_format.lower() != "pil_image": os.makedirs(output_path) # load custom fonts for plotting From 4881b64554e10a9048eb2f8d1e129b5efb5328f7 Mon Sep 17 00:00:00 2001 From: mdbarnesUCSD Date: Fri, 2 Aug 2024 13:46:02 -0700 Subject: [PATCH 5/6] Upgrade v1.3.24 1. Resolve issues with CLI boolean handling 2. Add support for environmental variable SIGPROFILERPLOTTING_VOLUME 3. Improve file path construction 4. Stop creation of output directory for savefig_format PIL_Image 5. Add Changelog --- CHANGELOG.md | 17 +++++++++++++++++ README.md | 2 +- setup.py | 4 ++-- sigProfilerPlotting/version.py | 6 +++--- 4 files changed, 23 insertions(+), 6 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..a854ff0 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,17 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [1.3.24] - 2024-08-01 + +### Added +- Added environmental variable `SIGPROFILERPLOTTING_VOLUME` to enhance configurability. + +### Fixed +- Ensured correct file path construction with `os.path.join()`. +- Updated CLI to handle boolean arguments using `str2bool`, resolving an issue where boolean strings like `False` were incorrectly evaluated as `True`. +- Stopped unecessary output directory creation when the output format is PIL_Image. diff --git a/README.md b/README.md index 6d81c93..e038ff7 100755 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Docs](https://img.shields.io/badge/docs-latest-blue.svg)](https://osf.io/2aj6t/wiki/home/) [![License](https://img.shields.io/badge/License-BSD\%202--Clause-orange.svg)](https://opensource.org/licenses/BSD-2-Clause) [![Build Status](https://travis-ci.com/AlexandrovLab/SigProfilerPlotting.svg?branch=master)](https://app.travis-ci.com/AlexandrovLab/SigProfilerPlotting) +[![Docs](https://img.shields.io/badge/docs-latest-blue.svg)](https://osf.io/2aj6t/wiki/home/) [![License](https://img.shields.io/badge/License-BSD\%202--Clause-orange.svg)](https://opensource.org/licenses/BSD-2-Clause) [![Build Status](https://app.travis-ci.com/AlexandrovLab/SigProfilerPlotting.svg?branch=master)](https://app.travis-ci.com/AlexandrovLab/SigProfilerPlotting) # SigProfilerPlotting SigProfilerPlotting provides a standard tool for displaying all types of mutational signatures as well as all types of mutational patterns in cancer genomes. The tool seamlessly integrates with other SigProfiler tools. diff --git a/setup.py b/setup.py index af31773..d3c0695 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ def readme(): return f.read() -VERSION = "1.3.23" +VERSION = "1.3.24" def write_version_py(filename="sigProfilerPlotting/version.py"): @@ -23,7 +23,7 @@ def write_version_py(filename="sigProfilerPlotting/version.py"): # THIS FILE IS GENERATED FROM SIGPROFILERPLOTTING SETUP.PY short_version = '%(version)s' version = '%(version)s' -update = 'Upgrade v1.3.23: Update SBS4608 custom_text_upper, custom_text_lower, custom_text_middle.' +update = 'Upgrade v1.3.24: Make output path handling more robust with os.path.join() and add environmental variable SIGPROFILERPLOTTING_VOLUME' """ fh = open(filename, "w") diff --git a/sigProfilerPlotting/version.py b/sigProfilerPlotting/version.py index 5ac356e..d0ad33f 100644 --- a/sigProfilerPlotting/version.py +++ b/sigProfilerPlotting/version.py @@ -1,7 +1,7 @@ # THIS FILE IS GENERATED FROM SIGPROFILERPLOTTING SETUP.PY -short_version = '1.3.22' -version = '1.3.22' -update = 'Upgrade v1.3.22: Update input_processing index.name handling to be more robust.' +short_version = '1.3.24' +version = '1.3.24' +update = 'Upgrade v1.3.24: Make output path handling more robust with os.path.join() and add environmental variable SIGPROFILERPLOTTING_VOLUME' \ No newline at end of file From 1e541a4011b884faa585e45534465480a8690772 Mon Sep 17 00:00:00 2001 From: mdbarnesUCSD Date: Mon, 5 Aug 2024 10:47:48 -0700 Subject: [PATCH 6/6] Improve plotting plot_type error messages --- sigProfilerPlotting/sigProfilerPlotting.py | 25 ++++++++-------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/sigProfilerPlotting/sigProfilerPlotting.py b/sigProfilerPlotting/sigProfilerPlotting.py index 0760c95..68daaab 100644 --- a/sigProfilerPlotting/sigProfilerPlotting.py +++ b/sigProfilerPlotting/sigProfilerPlotting.py @@ -245,7 +245,7 @@ def make_pickle_file(context="SBS96", return_plot_template=False, volume=None): # The environmental variable takes precedence over the volume argument # If the environmental variable is not set, the volume argument is used - volume = os.getenv('SIGPROFILERPLOTTING_VOLUME', volume) + volume = os.getenv("SIGPROFILERPLOTTING_VOLUME", volume) # Use the default volume when no environmental variable or volume argument is provided if volume is None: @@ -7042,7 +7042,7 @@ def plotSBS( fontsize_custom = 25 fontweight_custom = "bold" - fontcolor_custom = ("black") + fontcolor_custom = "black" fontname_custom = "Arial" ha_custom = "left" @@ -7763,7 +7763,6 @@ def plotSBS( file_path = os.path.join(output_path, f"SBS_288_Normalized_plots_{project}.pdf") pp = PdfPages(file_path) - mutations = OrderedDict() mutations_TSB = OrderedDict() total_count = [] @@ -8326,9 +8325,9 @@ def plotSBS( else: print( - "The provided plot_type:", + "Error: The function plotSBS does not support plot_type", plot_type, - "is not supported by this plotting function", + "so no plot has been generated." ) @@ -8690,7 +8689,6 @@ def plotID( file_path = os.path.join(output_path, f"ID_simple_plots_{project}.pdf") pp = PdfPages(file_path) - indel_types = [ "1:Del:C:1", "1:Del:C:2", @@ -9224,10 +9222,7 @@ def plotID( os.remove(pdf_path) elif ( - plot_type == "96" - or plot_type == "ID96" - or plot_type == "96ID" - or plot_type == "IDSB" + plot_type == "IDSB" or plot_type == "415" ): with open(matrix_path) as f: @@ -9245,7 +9240,6 @@ def plotID( file_path = os.path.join(output_path, f"ID_TSB_plots_{project}.pdf") pp = PdfPages(file_path) - indel_types_tsb = [] tsb_I = ["T", "U", "N", "B", "Q"] indel_types = [ @@ -10309,9 +10303,9 @@ def plotID( else: print( - "The provided plot_type:", + "Error: The function plotID does not support plot_type", plot_type, - "is not supported by this plotting function", + "so no plot has been generated." ) @@ -10754,7 +10748,6 @@ def plotDBS( file_path = os.path.join(output_path, f"DBS_186_plots_{project}.pdf") pp = PdfPages(file_path) - dinucs = [ "TT>GG", "TT>CG", @@ -11239,7 +11232,7 @@ def plotDBS( else: print( - "The provided plot_type:", + "Error: The function plotDBS does not support plot_type", plot_type, - "is not supported by this plotting function", + "so no plot has been generated." )