Skip to content

Commit 190598d

Browse files
authored
Merge pull request #94 from CEGRcode/bugfix
Bugfix for #79 #85 #83
2 parents 892f2fb + 54f47b3 commit 190598d

18 files changed

Lines changed: 755 additions & 250 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
/bin
33
/.gradle/
44
/build/
5+
.metadata

src/cli/Figure_Generation/CompositePlotCLI.java

Lines changed: 26 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,21 @@
55
import picocli.CommandLine.Parameters;
66

77
import java.awt.Color;
8-
import java.lang.NullPointerException;
98
import java.io.File;
109
import java.io.IOException;
11-
import java.io.OutputStream;
12-
import java.io.FileOutputStream;
13-
import java.io.FileNotFoundException;
1410
import java.util.ArrayList;
15-
import java.util.Scanner;
1611
import java.util.concurrent.Callable;
1712
import java.util.regex.Matcher;
1813
import java.util.regex.Pattern;
1914

20-
import org.jfree.chart.JFreeChart;
21-
import org.jfree.chart.ChartUtils;
22-
import org.jfree.data.xy.XYSeriesCollection;
23-
import org.jfree.data.xy.XYSeries;
24-
25-
import charts.CompositePlot;
2615
import objects.ToolDescriptions;
27-
import util.ExtensionFileFilter;
16+
import scripts.Figure_Generation.PlotComposite;
2817

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

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

43-
@Option(names = { "-o",
44-
"--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")
35+
@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")
4536
private File output = null;
4637
@Option(names = { "-t", "--title" }, description = "set title (default=<composite-file-name>)")
4738
private String title = null;
@@ -55,37 +46,11 @@ public class CompositePlotCLI implements Callable<Integer> {
5546
"--custom-colors" }, description = "indicate colors to use for each series. Must indicate a number of colors that matches number of dataseries\n"
5647
+ "default behavior:\n" + "if one series input, use black\n"
5748
+ "if two series input, use blue(sense) and red(anti)\n"
58-
+ "if greater than two series, cycle through a set of 20 preset colors.", arity = "1..")
49+
+ "if greater than two series, cycle through a set of 10 preset colors based on Rossi et al, 2021 (PMID:33692541).", arity = "1..")
5950
private String[] colors = null;
6051

61-
XYSeriesCollection xydata = null;
6252
private ArrayList<Color> COLORS = new ArrayList<Color>();
6353

64-
// Colors copied from response on StackOverflow:
65-
// https://stackoverflow.com/questions/470690/how-to-automatically-generate-n-distinct-colors
66-
String[] KELLY_COLORS_HEX = { "0xFFB300", // Vivid Yellow
67-
"0x803E75", // Strong Purple
68-
"0xFF6800", // Vivid Orange
69-
"0xA6BDD7", // Very Light Blue
70-
"0xC10020", // Vivid Red
71-
"0xCEA262", // Grayish Yellow
72-
"0x817066", // Medium Gray
73-
// The following don't work well for people with defective color vision
74-
"0x007D34", // Vivid Green
75-
"0xF6768E", // Strong Purplish Pink
76-
"0x00538A", // Strong Blue
77-
"0xFF7A5C", // Strong Yellowish Pink
78-
"0x53377A", // Strong Violet
79-
"0xFF8E00", // Vivid Orange Yellow
80-
"0xB32851", // Strong Purplish Red
81-
"0xF4C800", // Vivid Greenish Yellow
82-
"0x7F180D", // Strong Reddish Brown
83-
"0x93AA00", // Vivid Yellowish Green
84-
"0x593315", // Deep Yellowish Brown
85-
"0xF13A13", // Vivid Reddish Orange
86-
"0x232C16", // Dark Olive Green
87-
};
88-
8954
@Override
9055
public Integer call() throws Exception {
9156
System.err.println(">CompositePlotCLI.call()");
@@ -97,98 +62,52 @@ public Integer call() throws Exception {
9762
}
9863

9964
// Generate Composite Plot
100-
JFreeChart chart = CompositePlot.createChart(xydata, title, COLORS, legend);
101-
// Save Composite Plot
102-
OutputStream OUT = new FileOutputStream(output);
103-
ChartUtils.writeChartAsPNG(OUT, chart, pixelWidth, pixelHeight);
65+
PlotComposite.plotCompositeFile(inputComposite, output, true, title, COLORS, legend, pixelWidth, pixelHeight);
10466

10567
System.err.println("Image Generated.");
10668
return (0);
10769
}
10870

71+
/**
72+
* Validate input values and create user-readable error messages.
73+
* @return
74+
* @throws IOException
75+
*/
10976
private String validateInput() throws IOException {
11077
String r = "";
11178

112-
// check inputs exist
113-
if (!compositeData.exists()) {
114-
r += "(!)Composite Data file does not exist: " + compositeData.getName() + "\n";
115-
return (r);
116-
}
117-
// check input extensions
118-
if (!"out".equals(ExtensionFileFilter.getExtension(compositeData))) {
119-
r += "(!)Is this a \".out\" file? Check extension: " + compositeData.getName() + "\n";
79+
// Input file check
80+
if (!inputComposite.exists()) {
81+
r += "(!)Composite Data file does not exist: " + inputComposite.getName() + "\n";
82+
} else if (inputComposite.isDirectory()) {
83+
r += "(!)Composite Data file is a directory: " + inputComposite.getName() + "\n";
12084
}
121-
// set default output filename
122-
if (output == null) {
123-
output = new File(ExtensionFileFilter.stripExtension(compositeData) + "_compositePlot.png");
124-
// check output filename is valid
125-
} else {
126-
// check ext
127-
try {
128-
if (!"png".equals(ExtensionFileFilter.getExtension(output))) {
129-
r += "(!)Use PNG extension for output filename. Try: " + ExtensionFileFilter.stripExtension(output)
130-
+ ".png\n";
131-
}
132-
} catch (NullPointerException e) {
133-
r += "(!)Output filename must have extension: use PNG extension for output filename. Try: "
134-
+ ExtensionFileFilter.stripExtension(output) + ".png\n";
135-
}
136-
// check directory
85+
86+
// Output file check
87+
if (output != null) {
13788
if (output.getParent() == null) {
13889
// System.err.println("default to current directory");
13990
} else if (!new File(output.getParent()).exists()) {
14091
r += "(!)Check output directory exists: " + output.getParent() + "\n";
14192
}
14293
}
14394

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

152-
// Parse Datafile
153-
try {
154-
xydata = parseData();
155-
if (xydata == null) {
156-
r += "(!)The number of y-values don't match the number of x-values";
157-
}
158-
} catch (FileNotFoundException e) {
159-
e.printStackTrace();
160-
}
161-
162-
// Set Color
163-
if (colors == null) { // set defaults based on number of dataseries (n=1 -> black, n=2 -> blue,red,
164-
// n=3 -> cycle through kelly colors)
165-
if (xydata.getSeriesCount() == 1) {
166-
// set color to black default unless otherwise indicated
167-
COLORS.add(Color.BLACK);
168-
} else if (xydata.getSeriesCount() == 2) {
169-
// set colors to blue and red default unless otherwise indicated
170-
COLORS.add(Color.BLUE);
171-
COLORS.add(Color.RED);
172-
} else if (xydata.getSeriesCount() > 2) {
173-
// assign a diverse set of colors (as many as there are series)
174-
for (int i = 0; i < xydata.getSeriesCount(); i++) {
175-
int index = i % KELLY_COLORS_HEX.length;
176-
COLORS.add(Color.decode(KELLY_COLORS_HEX[index]));
177-
}
178-
}
179-
} else { // set user specified values and check they match number of data series
180-
// assert custom colors have been assigned and length matches number of series
181-
if (colors.length != xydata.getSeriesCount()) {
182-
r += "(!)Number of colors specified(" + colors.length + ") must match number of dataseries("
183-
+ xydata.getSeriesCount() + ")\n";
184-
}
103+
// Set Colors (customized)
104+
if (colors != null) {
185105
// check color input format and decode
186106
Pattern hexColorPat = Pattern.compile("[0-9A-Fa-f]{6}");
187107
for (int i = 0; i < colors.length; i++) {
188108
Matcher m = hexColorPat.matcher(colors[i]);
189109
if (!m.matches()) {
190-
r += "(!)Color(" + colors[i]
191-
+ ") must be formatted as a hexidecimal String!\n\tExpected input string format: \"[0-9A-Fa-f]{6}\"\n";
110+
r += "(!)Color(" + colors[i] + ") must be formatted as a hexidecimal String!\n\tExpected input string format: \"[0-9A-Fa-f]{6}\"\n";
192111
} else {
193112
System.err.println("Decoding color: 0x" + colors[i]);
194113
COLORS.add(Color.decode("0x" + colors[i]));
@@ -197,55 +116,4 @@ private String validateInput() throws IOException {
197116
}
198117
return (r);
199118
}
200-
201-
public XYSeriesCollection parseData() throws FileNotFoundException {
202-
// parse input into XYDataset obj
203-
XYSeriesCollection dataset = new XYSeriesCollection();
204-
Scanner scan = new Scanner(compositeData);
205-
// parse x values
206-
String[] tokens = scan.nextLine().split("\t");
207-
if (!tokens[0].equals("")) {
208-
scan.close();
209-
System.err.println("(!) First row of input file must have an empty first column (as x-values)");
210-
return null;
211-
}
212-
double[] x = new double[tokens.length - 1];
213-
for (int i = 1; i < tokens.length; i++) {
214-
x[i - 1] = Double.parseDouble(tokens[i]);
215-
}
216-
217-
XYSeries s;
218-
// line-by-line through file
219-
while (scan.hasNextLine()) {
220-
tokens = scan.nextLine().split("\t");
221-
// check for format consistency: number of x-values matches y-values
222-
if (tokens.length - 1 != x.length) {
223-
System.err.println("(!) Check number of x-values matches number of y-values");
224-
scan.close();
225-
return null;
226-
}
227-
// skip any rows with blank labels
228-
if (tokens[0].equals("")) {
229-
for (int i = 1; i < tokens.length; i++) {
230-
if (x[i - 1] != Double.parseDouble(tokens[i])) {
231-
System.err.println(x[i - 1]);
232-
System.err.println(tokens[i]);
233-
System.err.println("(!) Check dataseries based on same x-scale file");
234-
scan.close();
235-
return null;
236-
}
237-
}
238-
continue;
239-
}
240-
// initialize series based on rowname column of input file
241-
s = new XYSeries(tokens[0]);
242-
// parse y-values of current row
243-
for (int i = 1; i < tokens.length; i++) {
244-
s.add(x[i - 1], Double.parseDouble(tokens[i]));
245-
}
246-
dataset.addSeries(s);
247-
}
248-
scan.close();
249-
return (dataset);
250-
}
251119
}

src/cli/Figure_Generation/TwoColorHeatMapCLI.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,9 @@ private String validateInput() throws IOException {
108108
r += "(!)CDT file does not exist: " + CDT.getName() + "\n";
109109
return (r);
110110
}
111-
// check input extensions
112-
if (!"cdt".equals(ExtensionFileFilter.getExtension(CDT))) {
113-
r += "(!)Is this a CDT file? Check extension: " + CDT.getName() + "\n";
114-
}
115111
// set default output filename
116112
if (output == null) {
117-
String NAME = ExtensionFileFilter.stripExtension(CDT);
113+
String NAME = ExtensionFileFilter.stripExtensionIgnoreGZ(CDT);
118114
output = new File(NAME + "_" + scaleType + ".png");
119115
// check output filename is valid
120116
} else {

src/cli/Read_Analysis/TagPileupCLI.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ else if(readType.midpoint){
218218

219219
//validate smooth params
220220
if(smoothType.winVals!=-9999 && smoothType.winVals<1){ r += "(!)Invalid Smoothing Window Size. Must be larger than 0 bins, winSize=" + smoothType.winVals + "\n"; }
221+
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"; }
221222
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"; }
222223
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"; }
223224

src/main/ScriptManagerGUI.java

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import window_interface.Figure_Generation.TwoColorHeatMapWindow;
5959
import window_interface.Figure_Generation.ThreeColorHeatMapWindow;
6060
import window_interface.Figure_Generation.MergeHeatMapWindow;
61+
import window_interface.Figure_Generation.PlotCompositeWindow;
6162
import window_interface.Figure_Generation.LabelHeatMapWindow;
6263

6364
public class ScriptManagerGUI {
@@ -1405,12 +1406,40 @@ public void run() {
14051406
});
14061407
}
14071408
});
1408-
sl_pnlFigure.putConstraint(SpringLayout.NORTH, btncolorSequencePlot, 0, SpringLayout.NORTH,
1409-
txtcolorSequencePlot);
1409+
sl_pnlFigure.putConstraint(SpringLayout.NORTH, btncolorSequencePlot, 0, SpringLayout.NORTH, txtcolorSequencePlot);
14101410
sl_pnlFigure.putConstraint(SpringLayout.WEST, btncolorSequencePlot, 10, SpringLayout.WEST, pnlFigure);
1411-
sl_pnlFigure.putConstraint(SpringLayout.WEST, txtcolorSequencePlot, 10, SpringLayout.EAST,
1412-
btncolorSequencePlot);
1411+
sl_pnlFigure.putConstraint(SpringLayout.WEST, txtcolorSequencePlot, 10, SpringLayout.EAST, btncolorSequencePlot);
14131412
pnlFigure.add(btncolorSequencePlot);
1413+
1414+
1415+
// >FourColorPlot
1416+
JTextArea txtMakeCompositePlot = new JTextArea();
1417+
initializeTextArea(txtMakeCompositePlot);
1418+
txtMakeCompositePlot.setText(ToolDescriptions.composite_description);
1419+
sl_pnlFigure.putConstraint(SpringLayout.NORTH, txtMakeCompositePlot, 10, SpringLayout.SOUTH, txtcolorSequencePlot);
1420+
sl_pnlFigure.putConstraint(SpringLayout.NORTH, txtMakeCompositePlot, 10, SpringLayout.SOUTH, btncolorSequencePlot);
1421+
sl_pnlFigure.putConstraint(SpringLayout.EAST, txtMakeCompositePlot, -10, SpringLayout.EAST, pnlFigure);
1422+
pnlFigure.add(txtMakeCompositePlot);
1423+
1424+
JButton btnMakeCompositePlot = new JButton("Composite Plot");
1425+
btnMakeCompositePlot.addActionListener(new ActionListener() {
1426+
public void actionPerformed(ActionEvent e) {
1427+
EventQueue.invokeLater(new Runnable() {
1428+
public void run() {
1429+
try {
1430+
PlotCompositeWindow frame = new PlotCompositeWindow();
1431+
frame.setVisible(true);
1432+
} catch (Exception e) {
1433+
e.printStackTrace();
1434+
}
1435+
}
1436+
});
1437+
}
1438+
});
1439+
sl_pnlFigure.putConstraint(SpringLayout.NORTH, btnMakeCompositePlot, 0, SpringLayout.NORTH, txtMakeCompositePlot);
1440+
sl_pnlFigure.putConstraint(SpringLayout.WEST, btnMakeCompositePlot, 10, SpringLayout.WEST, pnlFigure);
1441+
sl_pnlFigure.putConstraint(SpringLayout.WEST, txtMakeCompositePlot, 10, SpringLayout.EAST, btnMakeCompositePlot);
1442+
pnlFigure.add(btnMakeCompositePlot);
14141443

14151444
// Set default tab to open to...
14161445
// 0=BAM_Statistics 5=Peak_Analysis

0 commit comments

Comments
 (0)