Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
/bin
/.gradle/
/build/
.metadata
184 changes: 26 additions & 158 deletions src/cli/Figure_Generation/CompositePlotCLI.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,21 @@
import picocli.CommandLine.Parameters;

import java.awt.Color;
import java.lang.NullPointerException;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.concurrent.Callable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jfree.chart.JFreeChart;
import org.jfree.chart.ChartUtils;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.data.xy.XYSeries;

import charts.CompositePlot;
import objects.ToolDescriptions;
import util.ExtensionFileFilter;
import scripts.Figure_Generation.PlotComposite;

/**
* Figure_GenerationCLI/CompositePlotCLI
* Command line interface class for scripts.Figure_Generation.PlotComposite to create line plot images based on the output files of scripts.Figure_Generation.TagPileup.
* @author Olivia Lang
* @see scripts.Figure_Generation.PlotComposite
* @see scripts.Figure_Generation.TagPileup
*/
@Command(name = "composite-plot", mixinStandardHelpOptions = true,
description = ToolDescriptions.composite_description,
Expand All @@ -38,10 +30,9 @@
public class CompositePlotCLI implements Callable<Integer> {

@Parameters(index = "0", description = "Composite data to plot. (formatted like TagPileup composite output)")
private File compositeData;
private File inputComposite;

@Option(names = { "-o",
"--output" }, description = "specify output filename, please use PNG extension\n(default=Input filename with \"_compositePlot.png\" appended to the name in working directory of ScriptManager")
@Option(names = { "-o", "--output" }, description = "specify output filename, please use PNG extension\n(default=Input filename with \"_compositePlot.png\" appended to the name in working directory of ScriptManager")
private File output = null;
@Option(names = { "-t", "--title" }, description = "set title (default=<composite-file-name>)")
private String title = null;
Expand All @@ -55,37 +46,11 @@ public class CompositePlotCLI implements Callable<Integer> {
"--custom-colors" }, description = "indicate colors to use for each series. Must indicate a number of colors that matches number of dataseries\n"
+ "default behavior:\n" + "if one series input, use black\n"
+ "if two series input, use blue(sense) and red(anti)\n"
+ "if greater than two series, cycle through a set of 20 preset colors.", arity = "1..")
+ "if greater than two series, cycle through a set of 10 preset colors based on Rossi et al, 2021 (PMID:33692541).", arity = "1..")
private String[] colors = null;

XYSeriesCollection xydata = null;
private ArrayList<Color> COLORS = new ArrayList<Color>();

// Colors copied from response on StackOverflow:
// https://stackoverflow.com/questions/470690/how-to-automatically-generate-n-distinct-colors
String[] KELLY_COLORS_HEX = { "0xFFB300", // Vivid Yellow
"0x803E75", // Strong Purple
"0xFF6800", // Vivid Orange
"0xA6BDD7", // Very Light Blue
"0xC10020", // Vivid Red
"0xCEA262", // Grayish Yellow
"0x817066", // Medium Gray
// The following don't work well for people with defective color vision
"0x007D34", // Vivid Green
"0xF6768E", // Strong Purplish Pink
"0x00538A", // Strong Blue
"0xFF7A5C", // Strong Yellowish Pink
"0x53377A", // Strong Violet
"0xFF8E00", // Vivid Orange Yellow
"0xB32851", // Strong Purplish Red
"0xF4C800", // Vivid Greenish Yellow
"0x7F180D", // Strong Reddish Brown
"0x93AA00", // Vivid Yellowish Green
"0x593315", // Deep Yellowish Brown
"0xF13A13", // Vivid Reddish Orange
"0x232C16", // Dark Olive Green
};

@Override
public Integer call() throws Exception {
System.err.println(">CompositePlotCLI.call()");
Expand All @@ -97,98 +62,52 @@ public Integer call() throws Exception {
}

// Generate Composite Plot
JFreeChart chart = CompositePlot.createChart(xydata, title, COLORS, legend);
// Save Composite Plot
OutputStream OUT = new FileOutputStream(output);
ChartUtils.writeChartAsPNG(OUT, chart, pixelWidth, pixelHeight);
PlotComposite.plotCompositeFile(inputComposite, output, true, title, COLORS, legend, pixelWidth, pixelHeight);

System.err.println("Image Generated.");
return (0);
}

/**
* Validate input values and create user-readable error messages.
* @return
* @throws IOException
*/
private String validateInput() throws IOException {
String r = "";

// check inputs exist
if (!compositeData.exists()) {
r += "(!)Composite Data file does not exist: " + compositeData.getName() + "\n";
return (r);
}
// check input extensions
if (!"out".equals(ExtensionFileFilter.getExtension(compositeData))) {
r += "(!)Is this a \".out\" file? Check extension: " + compositeData.getName() + "\n";
// Input file check
if (!inputComposite.exists()) {
r += "(!)Composite Data file does not exist: " + inputComposite.getName() + "\n";
} else if (inputComposite.isDirectory()) {
r += "(!)Composite Data file is a directory: " + inputComposite.getName() + "\n";
}
// set default output filename
if (output == null) {
output = new File(ExtensionFileFilter.stripExtension(compositeData) + "_compositePlot.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: "
+ ExtensionFileFilter.stripExtension(output) + ".png\n";
}
// check directory

// Output file check
if (output != null) {
if (output.getParent() == null) {
// System.err.println("default to current directory");
} else if (!new File(output.getParent()).exists()) {
r += "(!)Check output directory exists: " + output.getParent() + "\n";
}
}

// check pixel ranges are valid
// Pixel ranges must be valid
if (pixelHeight <= 0) {
r += "(!)Cell height must be a positive integer value! check \"-y\" flag.\"";
}
if (pixelWidth <= 0) {
r += "(!)Cell width must be a positive integer value! check \"-x\" flag.\"";
}

// Parse Datafile
try {
xydata = parseData();
if (xydata == null) {
r += "(!)The number of y-values don't match the number of x-values";
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}

// Set Color
if (colors == null) { // set defaults based on number of dataseries (n=1 -> black, n=2 -> blue,red,
// n=3 -> cycle through kelly colors)
if (xydata.getSeriesCount() == 1) {
// set color to black default unless otherwise indicated
COLORS.add(Color.BLACK);
} else if (xydata.getSeriesCount() == 2) {
// set colors to blue and red default unless otherwise indicated
COLORS.add(Color.BLUE);
COLORS.add(Color.RED);
} else if (xydata.getSeriesCount() > 2) {
// assign a diverse set of colors (as many as there are series)
for (int i = 0; i < xydata.getSeriesCount(); i++) {
int index = i % KELLY_COLORS_HEX.length;
COLORS.add(Color.decode(KELLY_COLORS_HEX[index]));
}
}
} else { // set user specified values and check they match number of data series
// assert custom colors have been assigned and length matches number of series
if (colors.length != xydata.getSeriesCount()) {
r += "(!)Number of colors specified(" + colors.length + ") must match number of dataseries("
+ xydata.getSeriesCount() + ")\n";
}
// Set Colors (customized)
if (colors != null) {
// check color input format and decode
Pattern hexColorPat = Pattern.compile("[0-9A-Fa-f]{6}");
for (int i = 0; i < colors.length; i++) {
Matcher m = hexColorPat.matcher(colors[i]);
if (!m.matches()) {
r += "(!)Color(" + colors[i]
+ ") must be formatted as a hexidecimal String!\n\tExpected input string format: \"[0-9A-Fa-f]{6}\"\n";
r += "(!)Color(" + colors[i] + ") must be formatted as a hexidecimal String!\n\tExpected input string format: \"[0-9A-Fa-f]{6}\"\n";
} else {
System.err.println("Decoding color: 0x" + colors[i]);
COLORS.add(Color.decode("0x" + colors[i]));
Expand All @@ -197,55 +116,4 @@ private String validateInput() throws IOException {
}
return (r);
}

public XYSeriesCollection parseData() throws FileNotFoundException {
// parse input into XYDataset obj
XYSeriesCollection dataset = new XYSeriesCollection();
Scanner scan = new Scanner(compositeData);
// parse x values
String[] tokens = scan.nextLine().split("\t");
if (!tokens[0].equals("")) {
scan.close();
System.err.println("(!) First row of input file must have an empty first column (as x-values)");
return null;
}
double[] x = new double[tokens.length - 1];
for (int i = 1; i < tokens.length; i++) {
x[i - 1] = Double.parseDouble(tokens[i]);
}

XYSeries s;
// line-by-line through file
while (scan.hasNextLine()) {
tokens = scan.nextLine().split("\t");
// check for format consistency: number of x-values matches y-values
if (tokens.length - 1 != x.length) {
System.err.println("(!) Check number of x-values matches number of y-values");
scan.close();
return null;
}
// skip any rows with blank labels
if (tokens[0].equals("")) {
for (int i = 1; i < tokens.length; i++) {
if (x[i - 1] != Double.parseDouble(tokens[i])) {
System.err.println(x[i - 1]);
System.err.println(tokens[i]);
System.err.println("(!) Check dataseries based on same x-scale file");
scan.close();
return null;
}
}
continue;
}
// initialize series based on rowname column of input file
s = new XYSeries(tokens[0]);
// parse y-values of current row
for (int i = 1; i < tokens.length; i++) {
s.add(x[i - 1], Double.parseDouble(tokens[i]));
}
dataset.addSeries(s);
}
scan.close();
return (dataset);
}
}
6 changes: 1 addition & 5 deletions src/cli/Figure_Generation/TwoColorHeatMapCLI.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,9 @@ 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);
String NAME = ExtensionFileFilter.stripExtensionIgnoreGZ(CDT);
output = new File(NAME + "_" + scaleType + ".png");
// check output filename is valid
} else {
Expand Down
1 change: 1 addition & 0 deletions src/cli/Read_Analysis/TagPileupCLI.java
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ else if(readType.midpoint){

//validate smooth params
if(smoothType.winVals!=-9999 && smoothType.winVals<1){ r += "(!)Invalid Smoothing Window Size. Must be larger than 0 bins, winSize=" + smoothType.winVals + "\n"; }
if(smoothType.winVals!=-9999 && smoothType.winVals%2==0){ r += "(!)Invalid Smoothing Window Size. Must be odd for symmetrical smoothing (so that the window is centered properly), winSize=" + smoothType.winVals + "\n"; }
if(smoothType.gaussVals[0]!=-9999 && smoothType.gaussVals[0]<1){ r += "(!)Invalid Standard Deviation Size. Must be larger than 0 bins, stdSize=" + smoothType.gaussVals[0] + "\n"; }
if(smoothType.gaussVals[1]!=-9999 && smoothType.gaussVals[1]<1){ r += "(!)Invalid Number of Standard Deviations. Must be larger than 0 standard deviations, stdNum=" + smoothType.gaussVals[1] + "\n"; }

Expand Down
37 changes: 33 additions & 4 deletions src/main/ScriptManagerGUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import window_interface.Figure_Generation.TwoColorHeatMapWindow;
import window_interface.Figure_Generation.ThreeColorHeatMapWindow;
import window_interface.Figure_Generation.MergeHeatMapWindow;
import window_interface.Figure_Generation.PlotCompositeWindow;
import window_interface.Figure_Generation.LabelHeatMapWindow;

public class ScriptManagerGUI {
Expand Down Expand Up @@ -1347,12 +1348,40 @@ public void run() {
});
}
});
sl_pnlFigure.putConstraint(SpringLayout.NORTH, btncolorSequencePlot, 0, SpringLayout.NORTH,
txtcolorSequencePlot);
sl_pnlFigure.putConstraint(SpringLayout.NORTH, btncolorSequencePlot, 0, SpringLayout.NORTH, txtcolorSequencePlot);
sl_pnlFigure.putConstraint(SpringLayout.WEST, btncolorSequencePlot, 10, SpringLayout.WEST, pnlFigure);
sl_pnlFigure.putConstraint(SpringLayout.WEST, txtcolorSequencePlot, 10, SpringLayout.EAST,
btncolorSequencePlot);
sl_pnlFigure.putConstraint(SpringLayout.WEST, txtcolorSequencePlot, 10, SpringLayout.EAST, btncolorSequencePlot);
pnlFigure.add(btncolorSequencePlot);


// >FourColorPlot
JTextArea txtMakeCompositePlot = new JTextArea();
initializeTextArea(txtMakeCompositePlot);
txtMakeCompositePlot.setText(ToolDescriptions.composite_description);
sl_pnlFigure.putConstraint(SpringLayout.NORTH, txtMakeCompositePlot, 10, SpringLayout.SOUTH, txtcolorSequencePlot);
sl_pnlFigure.putConstraint(SpringLayout.NORTH, txtMakeCompositePlot, 10, SpringLayout.SOUTH, btncolorSequencePlot);
sl_pnlFigure.putConstraint(SpringLayout.EAST, txtMakeCompositePlot, -10, SpringLayout.EAST, pnlFigure);
pnlFigure.add(txtMakeCompositePlot);

JButton btnMakeCompositePlot = new JButton("Composite Plot");
btnMakeCompositePlot.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
PlotCompositeWindow frame = new PlotCompositeWindow();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
});
sl_pnlFigure.putConstraint(SpringLayout.NORTH, btnMakeCompositePlot, 0, SpringLayout.NORTH, txtMakeCompositePlot);
sl_pnlFigure.putConstraint(SpringLayout.WEST, btnMakeCompositePlot, 10, SpringLayout.WEST, pnlFigure);
sl_pnlFigure.putConstraint(SpringLayout.WEST, txtMakeCompositePlot, 10, SpringLayout.EAST, btnMakeCompositePlot);
pnlFigure.add(btnMakeCompositePlot);

// Set default tab to open to...
// 0=BAM_Statistics 5=Peak_Analysis
Expand Down
Loading