From f3e91d1490bf5045acefe8ab366d27ca115a72a9 Mon Sep 17 00:00:00 2001 From: niekwit <41302859+niekwit@users.noreply.github.com> Date: Thu, 21 May 2026 10:10:04 +0100 Subject: [PATCH] plotHeatmap: add --plotColors argument for profile plot line colors Allows users to set custom colors for the profile/summary plot lines when --whatToShow includes a plot. Colors are recycled if fewer are given than the number of lines. Accepts any matplotlib named color or hex value. Consistent with the existing --colorList approach. --- deeptools/parserCommon.py | 21 +++++++++++++++++++++ deeptools/plotHeatmap.py | 26 +++++++++++++++++++------- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/deeptools/parserCommon.py b/deeptools/parserCommon.py index 9849d9c431..e8798c9228 100755 --- a/deeptools/parserCommon.py +++ b/deeptools/parserCommon.py @@ -2,6 +2,7 @@ import os from importlib.metadata import version import multiprocessing +import matplotlib.colors def check_float_0_1(value): @@ -22,6 +23,15 @@ def check_list_of_comma_values(value): return value +def check_color(value): + """Validate that a string is a recognised matplotlib color (named or hex).""" + if not matplotlib.colors.is_color_like(value): + raise argparse.ArgumentTypeError( + "'{}' is not a valid matplotlib color. Use a named color " + "(e.g. 'red') or a hex value (e.g. '#ff0000').".format(value)) + return value + + def output(args=None): parser = argparse.ArgumentParser(add_help=False) group = parser.add_argument_group('Output') @@ -704,6 +714,17 @@ def heatmapperOptionalArgs(mode=['heatmap', 'profile'][0]): type=int, default=256) + optional.add_argument( + '--plotColors', + help='Colors for the profile lines in the summary plot shown above the heatmap. ' + 'Only applies when --whatToShow is set to "plot, heatmap and colorbar" or ' + '"plot and heatmap". One color per group (or per sample when --perGroup is set) ' + 'can be specified. Colors are recycled if fewer are given than the number of lines. ' + 'Accepts named matplotlib colors (e.g. red, blue) and hex values (e.g. #ff0000). ' + 'Example: --plotColors red blue green', + type=check_color, + nargs='+') + optional.add_argument('--zMin', '-min', default=None, help='Minimum value for the heatmap intensities. Multiple values, separated by ' diff --git a/deeptools/plotHeatmap.py b/deeptools/plotHeatmap.py index a2149f8299..359bc303f6 100755 --- a/deeptools/plotHeatmap.py +++ b/deeptools/plotHeatmap.py @@ -379,7 +379,7 @@ def plotlyMatrix(hm, def plotMatrix(hm, outFileName, - colorMapDict={'colorMap': ['binary'], 'missingDataColor': 'black', 'alpha': 1.0}, + colorMapDict={'colorMap': ['binary'], 'missingDataColor': 'black', 'alpha': 1.0, 'plotColors': None}, plotTitle='', xAxisLabel='', yAxisLabel='', regionsLabel='', zMin=None, zMax=None, @@ -531,13 +531,24 @@ def plotMatrix(hm, outFileName, fig ) - # color map for the summary plot (profile) on top of the heatmap - cmap_plot = plt.get_cmap('jet') + # colors for the profile lines in the summary plot above the heatmap numgroups = hm.matrix.get_num_groups() - if perGroup: - color_list = cmap_plot(np.arange(hm.matrix.get_num_samples()) / hm.matrix.get_num_samples()) + if colorMapDict.get('plotColors'): + # user-supplied colors: one per group (or per sample when perGroup), + # recycled with modulo if fewer colors are given than lines + user_colors = colorMapDict['plotColors'] + if perGroup: + n_lines = hm.matrix.get_num_samples() + else: + n_lines = numgroups + color_list = [user_colors[i % len(user_colors)] for i in range(n_lines)] else: - color_list = cmap_plot(np.arange(numgroups) / numgroups) + # default: evenly-spaced colors from the jet colormap + cmap_plot = plt.get_cmap('jet') + if perGroup: + color_list = cmap_plot(np.arange(hm.matrix.get_num_samples()) / hm.matrix.get_num_samples()) + else: + color_list = cmap_plot(np.arange(numgroups) / numgroups) alpha = colorMapDict['alpha'] if image_format == 'plotly': return plotlyMatrix(hm, @@ -867,7 +878,8 @@ def main(args=None): 'colorList': args.colorList, 'colorNumber': args.colorNumber, 'missingDataColor': args.missingDataColor, - 'alpha': args.alpha} + 'alpha': args.alpha, + 'plotColors': args.plotColors} plotMatrix(hm, args.outFileName,