diff --git a/src/cli/Figure_Generation/ThreeColorHeatMapCLI.java b/src/cli/Figure_Generation/ThreeColorHeatMapCLI.java index 40303a069..abf29e6a6 100644 --- a/src/cli/Figure_Generation/ThreeColorHeatMapCLI.java +++ b/src/cli/Figure_Generation/ThreeColorHeatMapCLI.java @@ -76,7 +76,7 @@ static class MaxGroup { @Option(names = {"-0", "--include-zeros"}, description = "used with `-p` flag, indicating exclusion of zero values when calculating percentile thresholds") private boolean includeZeros = false; - @ArgGroup(multiplicity = "0..1", heading = "%nSelect heatmap colors:%n") + @ArgGroup(multiplicity = "0..1", exclusive=false, heading = "%nSelect heatmap colors:%n") private ColorGroup color = new ColorGroup(); static class ColorGroup { @Option(names = {"-cn", "--color-min"}, description = "Color indicating minimum values (default=YELLOW) For custom color: type hexadecimal string to represent colors (e.g. \"FF0000\" is hexadecimal for red).\n See for some color options with their corresponding hex strings.\n") @@ -88,7 +88,20 @@ static class ColorGroup { @Option(names = {"-ca", "--color-nan"}, description = "Color indicating not-a-number values (default=GRAY) For custom color: type hexadecimal string to represent colors (e.g. \"FF0000\" is hexadecimal for red).\n See for some color options with their corresponding hex strings.\n") private String nan = null; } - + + @ArgGroup(multiplicity = "0..1", exclusive=false, heading = "%nSelect transparency of heatmap colors (alpha channel):%n") + private AlphaGroup alpha = new AlphaGroup(); + static class AlphaGroup { + @Option(names = {"-tn", "--transparent-min"}, description = "Value indicating transparency of minimum values, 0 to 255 (default=255)\n") + private int min = 255; + @Option(names = {"-td", "--transparent-mid"}, description = "Value indicating transparency of middle values, 0 to 255 (default=255)\n") + private int mid = 255; + @Option(names = {"-tx", "--transparent-max"}, description = "Value indicating transparency of maximum values, 0 to 255 (default=255)\n") + private int max = 255; + @Option(names = {"-ta", "--transparent-nan"}, description = "Value indicating transparency of not-a-number values, 0 to 255 (default=255)\n") + private int nan = 255; + } + String scaleType = "treeview"; //Colors from JavaTreeview microarray software Color CMAX = new Color(254,255,0,255); @@ -217,6 +230,16 @@ private String validateInput() throws IOException { System.err.println("Decoding NaN color: 0x" + color.nan); CNAN = Color.decode("0x" + color.nan); } + // check that Alpha channel/transparency values are formatted properly and decode/assign colors + if (alpha.max<0 || alpha.max>255) { r += "(!)Alpha/transparency value for higher values (max) must be a numeric 0 to 255\n"; } + else { CMAX = new Color(CMAX.getRed(), CMAX.getGreen(), CMAX.getBlue(), alpha.max); } + if (alpha.mid<0 || alpha.mid>255) { r += "(!)Alpha/transparency value for middling values (mid) must be a numeric 0 to 255\n"; } + else { CMID = new Color(CMID.getRed(), CMID.getGreen(), CMID.getBlue(), alpha.mid); } + if (alpha.min<0 || alpha.min>255) { r += "(!)Alpha/transparency value for lower values(min) must be a numeric 0 to 255\n"; } + else { CMIN = new Color(CMIN.getRed(), CMIN.getGreen(), CMIN.getBlue(), alpha.min); } + if (alpha.nan<0 || alpha.nan>255) { r += "(!)Alpha/transparency value for invalid/non-numeric values(NaN) must be a numeric 0 to 255\n"; } + else { CNAN = new Color(CNAN.getRed(), CNAN.getGreen(), CNAN.getBlue(), alpha.nan); } + // assign vals for contrast thresholds and set bools if(maxGroup.percentile!=null) { MAX = maxGroup.percentile; diff --git a/src/cli/Figure_Generation/TwoColorHeatMapCLI.java b/src/cli/Figure_Generation/TwoColorHeatMapCLI.java index 89088644c..5f756eb28 100644 --- a/src/cli/Figure_Generation/TwoColorHeatMapCLI.java +++ b/src/cli/Figure_Generation/TwoColorHeatMapCLI.java @@ -56,7 +56,6 @@ public class TwoColorHeatMapCLI implements Callable { @ArgGroup(exclusive = true, multiplicity = "0..1", heading = "%nSelect heatmap color:%n\t@|fg(red) (select no more than one of these options)|@%n") private ColorGroup color = new ColorGroup(); - static class ColorGroup { @Option(names = { "--black" }, description = "Use the color black for generating the heatmap (default)") private boolean black = false; @@ -68,6 +67,12 @@ static class ColorGroup { "--color" }, description = "For custom color: type hexadecimal string to represent colors (e.g. \"FF0000\" is hexadecimal for red).\n See for some color options with their corresponding hex strings.\n") private String custom = null; } + @Option(names = { "-t", "--transparent" }, description = "Value indicating transparency of heatmap, 0 to 255 (default=255)\n") + private int alpha = 255; + + @Option(names = { "-b", "--background" }, description = "Set a transparent background for the heatmap minimum values (default=white)\n") + private boolean transparentBackground = false; + String scaleType = "treeview"; Color MAXCOLOR = Color.BLACK; @@ -84,7 +89,7 @@ public Integer call() throws Exception { // Generate HeatMap TwoColorHeatMap script_object = new TwoColorHeatMap(CDT, MAXCOLOR, startROW, startCOL, pixelHeight, pixelWidth, - scaleType, absolute, percentile, output, true); + scaleType, absolute, percentile, output, true, transparentBackground); script_object.run(); System.err.println("Image Generated."); @@ -108,26 +113,12 @@ private String validateInput() throws IOException { r += "(!)CDT file does not exist: " + CDT.getName() + "\n"; return (r); } - // check input extensions - if (!"cdt".equals(ExtensionFileFilter.getExtension(CDT))) { - r += "(!)Is this a CDT file? Check extension: " + CDT.getName() + "\n"; - } // set default output filename if (output == null) { String NAME = ExtensionFileFilter.stripExtension(CDT); output = new File(NAME + "_" + scaleType + ".png"); // check output filename is valid } else { - // check ext - try { - if (!"png".equals(ExtensionFileFilter.getExtension(output))) { - r += "(!)Use PNG extension for output filename. Try: " + ExtensionFileFilter.stripExtension(output) - + ".png\n"; - } - } catch (NullPointerException e) { - r += "(!)Output filename must have extension: use PNG extension for output filename. Try: " + output - + ".png\n"; - } // check directory if (output.getParent() == null) { // System.err.println("default to current directory"); @@ -140,14 +131,7 @@ private String validateInput() throws IOException { if (compression < 1 || compression > 4) { r += "(!)Compression must be integer 1-4. Please select from the available compression types."; } - // check that hex string is formatted properly - if (color.custom != null) { - Pattern hexColorPat = Pattern.compile("[0-9A-Fa-f]{6}"); - Matcher m = hexColorPat.matcher(color.custom); - if (!m.matches()) { - r += "(!)Color must be formatted as a hexidecimal String!\n\tExpected input string format: \"[0-9A-Fa-f]{6}\""; - } - } + // check scaling is valid input if (absolute == -999 && percentile == -999) { absolute = 10; @@ -169,8 +153,16 @@ private String validateInput() throws IOException { MAXCOLOR = Color.BLUE; } else if (color.custom != null) { System.err.println("Decoding color: 0x" + color.custom); - MAXCOLOR = Color.decode("0x" + color.custom); + // check that hex string is formatted properly + Pattern hexColorPat = Pattern.compile("[0-9A-Fa-f]{6}"); + Matcher m = hexColorPat.matcher(color.custom); + if (!m.matches()) { + r += "(!)Color must be formatted as a hexidecimal String!\n\tExpected input string format: \"[0-9A-Fa-f]{6}\""; + } else { MAXCOLOR = Color.decode("0x" + color.custom); } } + // check that Alpha channel/transparency values are formatted properly and decode/assign colors + if (alpha<0 || alpha>255) { r += "(!)Alpha/transparency value for higher values (max) must be a numeric 0 to 255\n"; } + else { MAXCOLOR = new Color(MAXCOLOR.getRed(), MAXCOLOR.getGreen(), MAXCOLOR.getBlue(), alpha); } return (r); } diff --git a/src/scripts/Figure_Generation/ThreeColorHeatMap.java b/src/scripts/Figure_Generation/ThreeColorHeatMap.java index 59a85241c..179506e16 100644 --- a/src/scripts/Figure_Generation/ThreeColorHeatMap.java +++ b/src/scripts/Figure_Generation/ThreeColorHeatMap.java @@ -175,7 +175,7 @@ public static BufferedImage generateHeatMap(ArrayList matrix) throws F BufferedImage im = new BufferedImage(pixwidth, pixheight, BufferedImage.TYPE_INT_ARGB); Graphics g = im.getGraphics(); Graphics2D g2 = (Graphics2D) g; - g2.setColor(new Color(255, 255, 255)); + g2.setColor(new Color(255, 255, 255, 0)); g2.fillRect(0, 0, pixwidth, pixheight); int count = 0; @@ -196,7 +196,8 @@ public static BufferedImage generateHeatMap(ArrayList matrix) throws F int red = (int) (MAXCOLOR.getRed() * sVal + MIDCOLOR.getRed() * (1 - sVal)); int green = (int) (MAXCOLOR.getGreen() * sVal + MIDCOLOR.getGreen() * (1 - sVal)); int blue = (int) (MAXCOLOR.getBlue() * sVal + MIDCOLOR.getBlue() * (1 - sVal)); - g.setColor(new Color(red, green, blue)); + int alpha = (int) (MAXCOLOR.getAlpha() * sVal + MIDCOLOR.getAlpha() * (1 - sVal)); + g.setColor(new Color(red, green, blue, alpha)); } else if (IDj < MIDVAL) { double v = (MIDVAL - IDj) / LOWER_RATIO; double sVal = v > 1 ? 1 : v; @@ -206,7 +207,8 @@ public static BufferedImage generateHeatMap(ArrayList matrix) throws F int red = (int) (MINCOLOR.getRed() * sVal + MIDCOLOR.getRed() * (1 - sVal)); int green = (int) (MINCOLOR.getGreen() * sVal + MIDCOLOR.getGreen() * (1 - sVal)); int blue = (int) (MINCOLOR.getBlue() * sVal + MIDCOLOR.getBlue() * (1 - sVal)); - g.setColor(new Color(red, green, blue)); + int alpha = (int) (MINCOLOR.getAlpha() * sVal + MIDCOLOR.getAlpha() * (1 - sVal)); + g.setColor(new Color(red, green, blue, alpha)); } else { g.setColor(MIDCOLOR); } diff --git a/src/scripts/Figure_Generation/TwoColorHeatMap.java b/src/scripts/Figure_Generation/TwoColorHeatMap.java index 923ad9326..9bb83687f 100644 --- a/src/scripts/Figure_Generation/TwoColorHeatMap.java +++ b/src/scripts/Figure_Generation/TwoColorHeatMap.java @@ -47,7 +47,7 @@ public class TwoColorHeatMap { private JLabel picLabel = null; public TwoColorHeatMap(File in, Color c, int startR, int startC, int pHeight, int pWidth, String scale, double abs, - double quant, File output, boolean outstatus) { + double quant, File output, boolean outstatus, boolean trans) { SAMPLE = in; MAXCOLOR = c; @@ -62,6 +62,10 @@ public TwoColorHeatMap(File in, Color c, int startR, int startC, int pHeight, in OUTFILE = output; OUTPUTSTATUS = outstatus; + MINCOLOR = new Color(255, 255, 255, 255); + if (trans) { + MINCOLOR = new Color(MAXCOLOR.getRed(), MAXCOLOR.getGreen(), MAXCOLOR.getBlue(), 0); + } } public void run() throws IOException { @@ -120,7 +124,7 @@ public static BufferedImage generateHeatMap(ArrayList matrix) throws F BufferedImage im = new BufferedImage(pixwidth, pixheight, BufferedImage.TYPE_INT_ARGB); Graphics g = im.getGraphics(); Graphics2D g2 = (Graphics2D) g; - g2.setColor(new Color(255, 255, 255)); + g2.setColor(MINCOLOR); g2.fillRect(0, 0, pixwidth, pixheight); int count = 0; @@ -134,9 +138,10 @@ public static BufferedImage generateHeatMap(ArrayList matrix) throws F int red = (int) (MAXCOLOR.getRed() * sVal + MINCOLOR.getRed() * (1 - sVal)); int green = (int) (MAXCOLOR.getGreen() * sVal + MINCOLOR.getGreen() * (1 - sVal)); int blue = (int) (MAXCOLOR.getBlue() * sVal + MINCOLOR.getBlue() * (1 - sVal)); - g.setColor(new Color(red, green, blue)); + int alpha = (int) (MAXCOLOR.getAlpha() * sVal + MINCOLOR.getAlpha() * (1 - sVal)); + g.setColor(new Color(red, green, blue, alpha)); } else { - g.setColor(Color.WHITE); + g.setColor(MINCOLOR); } g.fillRect(j * width, count * height, width, height); } @@ -352,7 +357,7 @@ public static double getQuantile(ArrayList matrix, double percent) { ArrayList nonZero = new ArrayList(); for (int x = 0; x < matrix.size(); x++) { for (int y = 0; y < matrix.get(x).length; y++) { - if (matrix.get(x)[y] != 0) { + if (matrix.get(x)[y] != 0 && !Double.isNaN(matrix.get(x)[y])) { nonZero.add(Double.valueOf(matrix.get(x)[y])); } } diff --git a/src/window_interface/Figure_Generation/TwoColorHeatMapOutput.java b/src/window_interface/Figure_Generation/TwoColorHeatMapOutput.java index 2275a212a..dd8cf320b 100644 --- a/src/window_interface/Figure_Generation/TwoColorHeatMapOutput.java +++ b/src/window_interface/Figure_Generation/TwoColorHeatMapOutput.java @@ -28,8 +28,8 @@ public class TwoColorHeatMapOutput extends JFrame { protected static double quantile = 0.9; protected static double absolute = -999; - public static Color MINCOLOR = new Color(255, 255, 255); public static Color MAXCOLOR = new Color(255, 0, 0); + public boolean transparentBackground = false; protected static boolean OUTPUTSTATUS = false; protected static File OUT_DIR = null; @@ -39,7 +39,7 @@ public class TwoColorHeatMapOutput extends JFrame { JTabbedPane newpane; public TwoColorHeatMapOutput(ArrayList in, Color c, int startR, int startC, int pHeight, int pWidth, - String scale, double abs, double quant, File out_dir, boolean outstatus) { + String scale, double abs, double quant, File out_dir, boolean outstatus, boolean trans) { setTitle("Heatmap"); setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); setBounds(150, 150, 600, 800); @@ -49,6 +49,7 @@ public TwoColorHeatMapOutput(ArrayList in, Color c, int startR, int startC SAMPLE = in; MAXCOLOR = c; + transparentBackground = trans; startROW = startR; startCOL = startC; pixelHeight = pHeight; @@ -60,7 +61,6 @@ public TwoColorHeatMapOutput(ArrayList in, Color c, int startR, int startC OUT_DIR = out_dir; OUTPUTSTATUS = outstatus; - System.out.println(OUTPUTSTATUS); } public void run() throws IOException { @@ -72,7 +72,7 @@ public void run() throws IOException { // Execute script TwoColorHeatMap script_object = new TwoColorHeatMap(SAMPLE.get(x), MAXCOLOR, startROW, startCOL, - pixelHeight, pixelWidth, scaleType, absolute, quantile, OUTPUT, OUTPUTSTATUS); + pixelHeight, pixelWidth, scaleType, absolute, quantile, OUTPUT, OUTPUTSTATUS, transparentBackground); script_object.run(); JLabel picLabel = script_object.getImg(); diff --git a/src/window_interface/Figure_Generation/TwoColorHeatMapWindow.java b/src/window_interface/Figure_Generation/TwoColorHeatMapWindow.java index 8ec5aeebe..b010f48da 100644 --- a/src/window_interface/Figure_Generation/TwoColorHeatMapWindow.java +++ b/src/window_interface/Figure_Generation/TwoColorHeatMapWindow.java @@ -60,6 +60,7 @@ public class TwoColorHeatMapWindow extends JFrame implements ActionListener, Pro private JTextField txtHeight; private JTextField txtWidth; private JButton btnColor; + private JCheckBox chckbxTransparentBackground; private JRadioButton rdbtnAbsoluteValue; private JRadioButton rdbtnPercentileValue; private JRadioButton rdbtnTreeview; @@ -125,7 +126,7 @@ public Void doInBackground() throws IOException { double quantile = Double.parseDouble(txtPercent.getText()); TwoColorHeatMapOutput heat = new TwoColorHeatMapOutput(txtFiles, COLOR, startR, startC, pHeight, pWidth, - scaletype, absolute, quantile, OUT_DIR, chckbxOutputHeatmap.isSelected()); + scaletype, absolute, quantile, OUT_DIR, chckbxOutputHeatmap.isSelected(), chckbxTransparentBackground.isSelected()); heat.addPropertyChangeListener("heat", new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent propertyChangeEvent) { @@ -333,9 +334,14 @@ public void itemStateChanged(ItemEvent e) { } }); + chckbxTransparentBackground = new JCheckBox("Use transparent background"); + sl_contentPane.putConstraint(SpringLayout.NORTH, chckbxTransparentBackground, 8, SpringLayout.SOUTH, lblSelectColor); + sl_contentPane.putConstraint(SpringLayout.WEST, chckbxTransparentBackground, 10, SpringLayout.WEST, lblSelectColor); + contentPane.add(chckbxTransparentBackground); + JLabel lblPixelHeight = new JLabel("Image Height:"); - sl_contentPane.putConstraint(SpringLayout.NORTH, lblPixelHeight, 20, SpringLayout.SOUTH, btnColor); - sl_contentPane.putConstraint(SpringLayout.WEST, lblPixelHeight, 0, SpringLayout.WEST, lblSelectColor); + sl_contentPane.putConstraint(SpringLayout.NORTH, lblPixelHeight, 8, SpringLayout.SOUTH, chckbxTransparentBackground); + sl_contentPane.putConstraint(SpringLayout.WEST, lblPixelHeight, 15, SpringLayout.WEST, contentPane); contentPane.add(lblPixelHeight); JLabel lblPixelWidth = new JLabel("Image Width:"); @@ -425,7 +431,7 @@ public void itemStateChanged(ItemEvent e) { }); JLabel lblImageCompression = new JLabel("Image Compression:"); - sl_contentPane.putConstraint(SpringLayout.NORTH, lblImageCompression, 10, SpringLayout.SOUTH, txtAbsolute); + sl_contentPane.putConstraint(SpringLayout.NORTH, lblImageCompression, 5, SpringLayout.SOUTH, txtAbsolute); sl_contentPane.putConstraint(SpringLayout.WEST, lblImageCompression, 10, SpringLayout.WEST, contentPane); contentPane.add(lblImageCompression);