diff --git a/LICENSE b/LICENSE index 9cecc1d..7c057bf 100755 --- a/LICENSE +++ b/LICENSE @@ -659,7 +659,7 @@ notice like this when it starts in an interactive mode: The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". +might be different; for a org.damageprofiler.GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. diff --git a/README.md b/README.md index f2a87e7..7e114c5 100755 --- a/README.md +++ b/README.md @@ -85,6 +85,6 @@ Maximal value on y axis (Default: flexible, adapts to the calculated damage). -Running the jar file without any parameter starts a GUI to configure the run. +Running the jar file without any parameter starts a org.damageprofiler.GUI to configure the run. Stay tuned, a more detailed description, manual and tutorial of DamageProfiler is coming soon. \ No newline at end of file diff --git a/build.gradle b/build.gradle old mode 100644 new mode 100755 index 0386843..6af0c94 --- a/build.gradle +++ b/build.gradle @@ -1,105 +1,104 @@ -group 'com.uni-tuebingen.de.it.eager.damageprofiler' -version '0.4.9' + plugins { + id 'application' + id 'org.openjfx.javafxplugin' version '0.0.8' + id 'org.beryx.jlink' version '2.12.0' + } -buildscript { - repositories { - jcenter() - } - dependencies { - classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8+' - } -} +version '0.5.0-java11' -allprojects { - repositories { - jcenter() - } - apply plugin: 'maven' - apply plugin: 'maven-publish' - apply plugin: 'java' - apply plugin: 'idea' - apply plugin: 'com.jfrog.bintray' - apply plugin: 'jacoco' +repositories { + mavenCentral() + jcenter() } -sourceCompatibility = 1.8 - - -sourceSets { - main { - java { - srcDir 'src' - } - } -} - + javafx { + version = "14" + modules = [ 'javafx.controls', 'javafx.fxml', 'javafx.graphics', 'javafx.base', 'javafx.media', 'javafx.swing','javafx.web'] + } dependencies { + compile group: 'log4j', name: 'log4j', version: '1.+' compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.+' compile group: 'commons-cli', name: 'commons-cli', version: '1.3.+' compile group: 'com.itextpdf', name: 'itextpdf', version: '5.5.+' - compile group: 'org.jfree', name: 'jcommon', version: '1.0.+' - compile group: 'jfree', name: 'jfreechart', version: '1.0.13' compile group: 'com.github.samtools', name: 'htsjdk', version: '2.+' - compile group: 'com.intellij', name: 'forms_rt', version: '6.0.+' - compile group: 'log4j', name: 'log4j', version: '1.+' + compile group: 'com.intellij', name: 'forms_rt', version: '5.+' compile group: 'com.github.broadinstitute', name: 'picard', version: '2.+' + compile group: 'org.jfree', name: 'jfreesvg', version: '2.0' + compile group: 'org.apache.commons', name: 'commons-text', version: '1.+' + compile 'org.jfree:jfreechart-fx:1.+' } - - jar { manifest { - attributes("Implementation-Title": "DamageProfiler", - "Implementation-Version": version, "main-Class": "RunDamageProfiler") + attributes 'Main-Class': 'RunDamageProfiler' } - doFirst { - from { configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) } } + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } } } - - - -publishing { - publications { - MyPublication(MavenPublication) { - from components.java - groupId 'com.uni-tuebingen.de.it.eager' - artifactId 'DamageProfiler' - } - } -} - - -jacocoTestReport { - reports { - xml.enabled true - } -} - - -bintray { - user = System.getenv('BINTRAY_USER') - key = System.getenv('BINTRAY_API_KEY') - publications = ['MyPublication'] - publish = true - override = true - pkg { - repo = 'EAGER' - name = 'DamageProfiler' - licenses = ['GPL-3.0'] - vcsUrl = "https://github.com/apeltzer/DamageProfiler" - version { - name = project.version - desc = 'Damage calculations for mapped reads.' - released = new Date() - vcsTag = project.version - attributes = ['gradle-plugin': 'com.use.less:com.use.less.gradle:gradle-useless-plugin'] - } - - } -} +//// Uncomment when compiling with java8 +//version '0.5.0-java8' +//buildscript { +// repositories { +// jcenter() +// } +// dependencies { +// classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8+' +// } +//} +// +//allprojects { +// repositories { +// jcenter() +// } +// apply plugin: 'maven' +// apply plugin: 'maven-publish' +// apply plugin: 'java' +// apply plugin: 'idea' +// apply plugin: 'com.jfrog.bintray' +// apply plugin: 'jacoco' +//} +// +//sourceCompatibility = 1.8 +// +//sourceSets { +// main { +// java { +// srcDir 'src' +// } +// +// resources { +// srcDirs "src/main/resources" +// } +// } +//} +// +// +//dependencies { +// compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.+' +// compile group: 'commons-cli', name: 'commons-cli', version: '1.3.+' +// compile group: 'com.itextpdf', name: 'itextpdf', version: '5.5.+' +// compile group: 'com.github.samtools', name: 'htsjdk', version: '2.+' +// compile group: 'com.intellij', name: 'forms_rt', version: '6.0.+' +// compile group: 'log4j', name: 'log4j', version: '1.+' +// compile group: 'com.github.broadinstitute', name: 'picard', version: '2.+' +// compile group: 'org.jfree', name: 'jfreesvg', version: '2.0' +// compile group: 'org.apache.commons', name: 'commons-text', version: '1.+' +// compile 'org.jfree:jfreechart-fx:1.+' +//} +// +// +//jar { +// manifest { +// attributes("Implementation-Title": "DamageProfiler", +// "Implementation-Version": version, "main-Class": "RunDamageProfiler") +// } +// doFirst { +// from { configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) } } +// } +//} \ No newline at end of file diff --git a/docs/contents/generalUsage.rst b/docs/contents/generalUsage.rst index 015c723..a65769d 100755 --- a/docs/contents/generalUsage.rst +++ b/docs/contents/generalUsage.rst @@ -40,7 +40,7 @@ Options: DamageProfiler can be used in offline mode. -Running the jar file without any parameter starts a GUI to configure the run. +Running the jar file without any parameter starts a org.damageprofiler.GUI to configure the run. Log file diff --git a/src/main/java/GUI/CopyTask.java b/src/main/java/GUI/CopyTask.java deleted file mode 100755 index b2e068a..0000000 --- a/src/main/java/GUI/CopyTask.java +++ /dev/null @@ -1,37 +0,0 @@ -package GUI; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -import javafx.concurrent.Task; - -// Copy all file in C:/Windows -public class CopyTask extends Task> { - - @Override - protected List call() throws Exception { - - File dir = new File("C:/Windows"); - File[] files = dir.listFiles(); - int count = files.length; - - List copied = new ArrayList(); - int i = 0; - for (File file : files) { - if (file.isFile()) { - this.copy(file); - copied.add(file); - } - i++; - this.updateProgress(i, count); - } - return copied; - } - - private void copy(File file) throws Exception { - this.updateMessage("Copying: " + file.getAbsolutePath()); - Thread.sleep(500); - } - -} \ No newline at end of file diff --git a/src/main/java/GUI/MainGuiFX.java b/src/main/java/GUI/MainGuiFX.java deleted file mode 100755 index 3aefba8..0000000 --- a/src/main/java/GUI/MainGuiFX.java +++ /dev/null @@ -1,273 +0,0 @@ -package GUI; - -import IO.Communicator; -import calculations.StartCalculations; -import javafx.application.Application; - -import javafx.concurrent.WorkerStateEvent; -import javafx.event.EventHandler; -import javafx.geometry.Pos; -import javafx.scene.Scene; -import javafx.scene.control.*; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.control.TextField; -import javafx.scene.layout.GridPane; -import javafx.scene.text.Font; -import javafx.scene.text.FontWeight; -import javafx.stage.Stage; -import javafx.concurrent.Task; - - -public class MainGuiFX extends Application { - - private Button btn_inputfile; - private Button btn_reference; - private Button btn_output; - private Button btn_plotting_options; - private Button btn_run; - private Button btn_specieList; - private TextField textfield_threshold; - private TextField textfield_length; - private TextField textfield_specie; - private CheckBox checkbox_use_merged_reads; - private TextField textfield_title; - //private CheckBox checkbox_dynamic_y_axis_height; - private TextField textfield_y_axis_height; - private Communicator communicator = new Communicator(); - private StartCalculations starter = new StartCalculations(null); - private Stage primaryStage; - private ProgressBar progressBar; - private Task startCalculuations; - - @Override - public void start(Stage primaryStage) { - this.primaryStage = primaryStage; - - this.primaryStage.setTitle("DamageProfiler configuration"); - - GridPane root = new GridPane(); - root.setAlignment(Pos.CENTER); - root.setHgap(7); - root.setVgap(7); - - addComponents(root); - addListener(); - - this.primaryStage.setScene(new Scene(root, 650, 400)); - this.primaryStage.setResizable(true); - this.primaryStage.show(); - - - } - - - public Task startCalculuations(Communicator communicator) { - return new Task() { - @Override - protected Object call() throws Exception { - starter.start(communicator); - return true; - } - }; - } - - - private void addListener() { - -// checkbox_dynamic_y_axis_height.selectedProperty().addListener((ov, old_val, new_val) -> { -// if(new_val){ -// textfield_y_axis_height.setDisable(true); -// } else if(!new_val){ -// textfield_y_axis_height.setDisable(false); -// } -// }); - - - - btn_inputfile.setOnAction(e -> { - - BamFileChooserFX fqfc = new BamFileChooserFX(communicator); - //Check if some input was truly selected - - if (checkIfInputWasSelected()) { - btn_run.setDisable(false); - } else { - btn_run.setDisable(true); - } - - }); - - btn_reference.setOnAction(e -> { - ReferenceFileChooserFX rfc = new ReferenceFileChooserFX(communicator); - //Check if some input was truly selected - - if (checkIfInputWasSelected()) { - btn_run.setDisable(false); - } else { - btn_run.setDisable(true); - } - - }); - - btn_output.setOnAction(e -> { - - OutputDirChooserFX rfc = new OutputDirChooserFX(communicator); - - if (checkIfInputWasSelected()) { - btn_run.setDisable(false); - } else { - btn_run.setDisable(true); - } - - }); - - btn_specieList.setOnAction(e -> { - - SpeciesListFileChooser slfc = new SpeciesListFileChooser(communicator); - if (checkIfInputWasSelected()) { - btn_specieList.setDisable(false); - } else { - btn_specieList.setDisable(true); - } - - - }); - - - btn_run.setOnAction(e -> { - - // set all user options - communicator.setLength(Integer.parseInt(textfield_length.getText())); - communicator.setThreshold(Integer.parseInt(textfield_threshold.getText())); - communicator.setSpecies_ref_identifier(textfield_specie.getText()); -// if(!checkbox_dynamic_y_axis_height.isSelected()){ -// try { -// communicator.setyAxis_damageplot(Double.parseDouble(textfield_y_axis_height.getText())); -// } catch (Exception ex){ -// System.out.println("Height value not valid."); -// } -// } - - - if(!textfield_title.getText().equals("")){ - communicator.setTitle_plots(textfield_title.getText()); - } - - - try { - // add progress indicator - progressBar.setProgress(0); - startCalculuations = startCalculuations(communicator); - progressBar.progressProperty().unbind(); - progressBar.progressProperty().bind(startCalculuations.progressProperty()); - - startCalculuations.addEventHandler(WorkerStateEvent.WORKER_STATE_SUCCEEDED, // - (EventHandler) t -> { - if(starter.isCalculationsDone()){ - primaryStage.close(); - } - }); - new Thread(startCalculuations).start(); - - //this.primaryStage.close(); - } catch (Exception e1) { - e1.printStackTrace(); - } - - }); - - - } - - - - private void addComponents(GridPane root) { - - btn_inputfile = new Button("Select input file"); - btn_reference = new Button("Select reference"); - btn_output = new Button("Select output"); - btn_plotting_options = new Button("Plotting options"); - btn_specieList = new Button("Set list"); - btn_run = new Button("Run"); - - Label label_threshold = new Label("Number of bases (x-axis)"); - Label label_yaxis = new Label("Height y-axis"); - Label label_length = new Label("Set number of bases (calculations)"); - Label label_specie = new Label("Filter for specie"); - Label label_title = new Label("Set title"); - Label label_plot = new Label("Plot"); - label_plot.setFont(Font.font("Verdana", FontWeight.BOLD, 14)); - - Label label_calculations = new Label("Calculations"); - label_calculations.setFont(Font.font("Verdana", FontWeight.BOLD, 14)); - - progressBar = new ProgressBar(0); - - textfield_threshold = new TextField(); - textfield_length = new TextField(); - textfield_specie = new TextField(); - textfield_title = new TextField(); - textfield_y_axis_height = new TextField(); - - checkbox_use_merged_reads = new CheckBox("Use only merged reads"); - //checkbox_dynamic_y_axis_height = new CheckBox("Dynamic"); - - btn_run.setDisable(true); - textfield_length.setText("100"); - textfield_threshold.setText("25"); - textfield_y_axis_height.setText("0.4"); - //checkbox_dynamic_y_axis_height.setSelected(true); - //textfield_y_axis_height.setDisable(true); - - - // add components to grid - - int row = 0; - - root.add(btn_inputfile, 0, row,1,1); - root.add(btn_reference, 1, row,1,1); - root.add(btn_output, 2, row,1,1); - root.add(new Separator(), 0, ++row,3,1); - - // PLOT - - root.add(label_plot, 0, ++row, 1,1); - root.add(label_title, 0, ++row, 1,1); - root.add(textfield_title, 1, row, 2,1); - root.add(label_yaxis, 0, ++row, 1,1); - //root.add(checkbox_dynamic_y_axis_height, 1, row, 1,1); - root.add(textfield_y_axis_height, 1, row, 2,1); - root.add(label_threshold, 0, ++row, 1,1); - root.add(textfield_threshold, 1, row, 2,1); - root.add(label_specie, 0, ++row, 1,1); - root.add(textfield_specie, 1, row, 2,1); - root.add(btn_specieList, 3, row, 1,1); - root.add(checkbox_use_merged_reads, 0, ++row,1,1); - root.add(new Separator(), 0, ++row,3,1); - - // CALCULATIONS - - root.add(label_calculations, 0, ++row, 1,1); - root.add(label_length, 0, ++row, 1,1); - root.add(textfield_length, 1, row, 2,1); - root.add(new Separator(), 0, ++row,3,1); - root.add(btn_run, 0, ++row,1,1); - root.add(progressBar, 1, row,1,1); - - - } - - private boolean checkIfInputWasSelected() { - boolean tmp = false; - if (communicator.getInput() != null && communicator.getReference() != null && communicator.getOutfolder() != null) { - if (communicator.getInput().length() != 0) { - tmp = true; - } - } - return tmp; - } - - - -} diff --git a/src/main/java/GUI/Progress.java b/src/main/java/GUI/Progress.java deleted file mode 100755 index cbc5a63..0000000 --- a/src/main/java/GUI/Progress.java +++ /dev/null @@ -1,128 +0,0 @@ -package GUI; - -import javafx.application.Application; -import javafx.geometry.Insets; -import javafx.scene.Scene; -import javafx.scene.control.ProgressBar; -import javafx.scene.control.ProgressIndicator; -import javafx.scene.layout.FlowPane; -import javafx.stage.Stage; - -import java.io.File; -import java.util.List; - -import javafx.application.Application; -import javafx.concurrent.WorkerStateEvent; -import javafx.event.ActionEvent; -import javafx.event.EventHandler; -import javafx.geometry.Insets; -import javafx.scene.Scene; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.control.ProgressBar; -import javafx.scene.control.ProgressIndicator; -import javafx.scene.layout.FlowPane; -import javafx.scene.paint.Color; -import javafx.stage.Stage; - -public class Progress extends Application { - - private CopyTask copyTask; - - @Override - public void start(Stage primaryStage) { - - final Label label = new Label("Copy files:"); - final ProgressBar progressBar = new ProgressBar(0); - final ProgressIndicator progressIndicator = new ProgressIndicator(0); - - final Button startButton = new Button("Start"); - final Button cancelButton = new Button("Cancel"); - - final Label statusLabel = new Label(); - statusLabel.setMinWidth(250); - statusLabel.setTextFill(Color.BLUE); - - // Start Button. - startButton.setOnAction(new EventHandler() { - @Override - public void handle(ActionEvent event) { - startButton.setDisable(true); - progressBar.setProgress(0); - progressIndicator.setProgress(0); - cancelButton.setDisable(false); - - // Create a Task. - copyTask = new CopyTask(); - - // Unbind progress property - progressBar.progressProperty().unbind(); - - // Bind progress property - progressBar.progressProperty().bind(copyTask.progressProperty()); - - // Hủy bỏ kết nối thuộc tính progress - progressIndicator.progressProperty().unbind(); - - // Bind progress property. - progressIndicator.progressProperty().bind(copyTask.progressProperty()); - - // Unbind text property for Label. - statusLabel.textProperty().unbind(); - - // Bind the text property of Label - // with message property of Task - statusLabel.textProperty().bind(copyTask.messageProperty()); - - // When completed tasks - copyTask.addEventHandler(WorkerStateEvent.WORKER_STATE_SUCCEEDED, // - new EventHandler() { - - @Override - public void handle(WorkerStateEvent t) { - List copied = copyTask.getValue(); - statusLabel.textProperty().unbind(); - statusLabel.setText("Copied: " + copied.size()); - } - }); - - // Start the Task. - new Thread(copyTask).start(); - - } - }); - - // Cancel - cancelButton.setOnAction(new EventHandler() { - @Override - public void handle(ActionEvent event) { - startButton.setDisable(false); - cancelButton.setDisable(true); - copyTask.cancel(true); - progressBar.progressProperty().unbind(); - progressIndicator.progressProperty().unbind(); - statusLabel.textProperty().unbind(); - // - progressBar.setProgress(0); - progressIndicator.setProgress(0); - } - }); - - FlowPane root = new FlowPane(); - root.setPadding(new Insets(10)); - root.setHgap(10); - - root.getChildren().addAll(label, progressBar, progressIndicator, // - statusLabel, startButton, cancelButton); - - Scene scene = new Scene(root, 500, 120, Color.WHITE); - primaryStage.setTitle("ProgressBar & ProgressIndicator"); - primaryStage.setScene(scene); - primaryStage.show(); - } - - public static void main(String[] args) { - Application.launch(args); - } - -} \ No newline at end of file diff --git a/src/main/java/IO/Unzip.java b/src/main/java/IO/Unzip.java deleted file mode 100755 index b8a0869..0000000 --- a/src/main/java/IO/Unzip.java +++ /dev/null @@ -1,45 +0,0 @@ -package IO; - -import org.apache.log4j.Logger; - -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.OutputStream; -import java.util.zip.GZIPInputStream; - - -/** - * Created by neukamm on 25.07.2016. - */ -public class Unzip { - - private final Logger LOG; - - public Unzip(Logger LOG){ - this.LOG = LOG; - } - - - /** - * decompress zipped/compressed file - * - * @param infile - * @return - * @throws Exception - */ - public String decompress(String infile) throws Exception { - - GZIPInputStream in = new GZIPInputStream(new FileInputStream(infile)); - String outfile = infile.substring(0, infile.lastIndexOf('.')); - OutputStream out = new FileOutputStream(outfile); - byte[] buf = new byte[1024]; - int len; - while ((len = in.read(buf)) > 0) { - out.write(buf, 0, len); - } - in.close(); - out.close(); - - return outfile; - } -} diff --git a/src/main/java/IO/UserOptionsParser.java b/src/main/java/IO/UserOptionsParser.java deleted file mode 100755 index ace9a28..0000000 --- a/src/main/java/IO/UserOptionsParser.java +++ /dev/null @@ -1,218 +0,0 @@ -package IO; - -import org.apache.commons.cli.*; - - -/** - * Created by neukamm on 01.08.16. - */ -public class UserOptionsParser { - - private static final String CLASS_NAME = "User option parser"; - private final String version; - private String[] args; - private Communicator communicator; - - - public UserOptionsParser(String[] args, Communicator c, String version){ - this.args = args; - this.communicator = c; - this.version = version; - parse(); - } - - private void parse() { - - // create command line parameters - Options helpOptions = new Options(); - helpOptions.addOption("h", "help", false, "show this help page"); - Options options = new Options(); - options.addOption("h", "help", false, "show this help page"); - - Option version = new Option("version", "version", false, - "Show version of DamageProfiler"); - options.addOption(version); - - options.addOption(OptionBuilder.withLongOpt("input") - .withArgName("INPUT") - .withDescription("The input sam/bam file") - .hasArg() - .create("i")); - options.addOption(OptionBuilder.withLongOpt("reference") - .withArgName("REFERENCE") - .withDescription("The reference file") - .hasArg() - .create("r")); - options.addOption(OptionBuilder.withLongOpt("output") - .withArgName("OUTPUT") - .withDescription("The output folder") - .hasArg() - .create("o")); - options.addOption(OptionBuilder.withLongOpt("threshold") - .withArgName("THRESHOLD") - .withDescription("Number of bases which are considered for plotting nucleotide misincorporations") - .hasArg() - .create("t")); - options.addOption(OptionBuilder.withLongOpt("specie") - .withArgName("SPECIE") - .withDescription("RNAME flag SAM record (Reference sequence name)") - .hasArg() - .create("s")); - options.addOption(OptionBuilder.withLongOpt("specieslist file") - .withArgName("SPECIES LIST") - .withDescription("List with species for which damage profile has to be calculated.") - .hasArg() - .create("sf")); - options.addOption(OptionBuilder.withLongOpt("length") - .withArgName("LENGTH") - .withDescription("Number of bases which are considered for frequency computations.") - .hasArg() - .create("l")); - - options.addOption(OptionBuilder.withLongOpt("title") - .withArgName("TITLE") - .withDescription("Title used for all plots. Default: filepath of input SAM/BAM file.") - .hasArg() - .create("title")); - - options.addOption(OptionBuilder.withLongOpt("yaxis_damageplot") - .withArgName("YAXIS_DAMAGEPLOT") - .withDescription("Maximal value on y axis of damage plot.") - .hasArg() - .create("yaxis_damageplot")); - - options.addOption(OptionBuilder.withLongOpt("xaxis_histo_id_min") - .withArgName("XAXIS_HISTO_ID_MIN") - .withDescription("Minimal value x-axis of identity histogram.") - .hasArg() - .create("xaxis_histo_id_min")); - - options.addOption(OptionBuilder.withLongOpt("xaxis_histo_id_max") - .withArgName("XAXIS_HISTO_ID_MAX") - .withDescription("Maximal value x-axis of identity histogram.") - .hasArg() - .create("xaxis_histo_id_max")); - - options.addOption(OptionBuilder.withLongOpt("xaxis_histo_length_min") - .withArgName("XAXIS_HISTO_LENGTH_MIN") - .withDescription("Minimal value x-axis of length histogram.") - .hasArg() - .create("xaxis_histo_length_min")); - - options.addOption(OptionBuilder.withLongOpt("xaxis_histo_length_max") - .withArgName("XAXIS_HISTO_LENGTH_MAX") - .withDescription("Maximal value x-axis of length histogram.") - .hasArg() - .create("xaxis_histo_length_max")); - - Option mapped_and_merged = new Option("merged", "all_mapped_and_merged_reads", false, - "Use all mapped and merged reads to calculate damage plot instead of using all mapped reads. The SAM/BAM entry must start with 'M_', otherwise " + - " it will be skipped. Default: false "); - options.addOption(mapped_and_merged); - - Option use_all_reads = new Option("useall", "use_all_reads", false, - "Use all reads (mapped and unmapped) to calculate damage plot. Default: false "); - options.addOption(use_all_reads); - - - HelpFormatter helpformatter = new HelpFormatter(); - CommandLineParser parser = new BasicParser(); - - if (args[0].equals("-version") || args[0].equals("--version")){ - System.out.print("DamageProfiler v" + this.version); - System.exit(0); - } else if (args.length < 2) { - helpformatter.printHelp(CLASS_NAME, options); - System.exit(0); - } - try { - CommandLine cmd = parser.parse(helpOptions, args); - if (cmd.hasOption('h')) { - helpformatter.printHelp(CLASS_NAME, options); - System.exit(0); - } - } catch (ParseException e1) { - } - - - try { - CommandLine cmd = parser.parse(options, args); - - if(cmd.hasOption("version")) { - System.out.print("DamageProfiler v" + this.version + "\n"); - System.exit(0); - } - - // input files - - if (cmd.hasOption('i')) { - communicator.setInput(cmd.getOptionValue('i')); - } - if (cmd.hasOption('r')) { - communicator.setReference(cmd.getOptionValue('r')); - } - if (cmd.hasOption('o')) { - communicator.setOutfolder(cmd.getOptionValue('o')); - } - - // damage calculation - - if (cmd.hasOption('s')) { - communicator.setSpecies_ref_identifier(cmd.getOptionValue('s')); - } - if (cmd.hasOption("sf")) { - communicator.setSpecieslist_filepath(cmd.getOptionValue("sf")); - } - if (cmd.hasOption('l')) { - communicator.setLength(Integer.parseInt(cmd.getOptionValue('l'))); - } - if(cmd.hasOption("all_mapped_and_merged_reads")) { - communicator.setUse_merged_and_mapped_reads(true); - } - - if(cmd.hasOption("use_all_reads")) { - communicator.setUse_all_reads(false); - } - - // Plotting - - if(cmd.hasOption("title")) { - communicator.setTitle_plots(cmd.getOptionValue("title")); - } - - if(cmd.hasOption("yaxis_damageplot")) { - communicator.setyAxis_damageplot(Double.parseDouble(cmd.getOptionValue("yaxis_damageplot"))); - } - - if(cmd.hasOption("xaxis_histo_id_min")) { - communicator.setXaxis_histo_id_min(Double.parseDouble(cmd.getOptionValue("xaxis_histo_id_min"))); - } - - - if(cmd.hasOption("xaxis_histo_id_max")) { - communicator.setXaxis_histo_id_max(Double.parseDouble(cmd.getOptionValue("xaxis_histo_id_max"))); - } - - if(cmd.hasOption("xaxis_histo_length_min")) { - communicator.setXaxis_histo_length_min(Double.parseDouble(cmd.getOptionValue("xaxis_histo_length_min"))); - } - - - if(cmd.hasOption("xaxis_histo_length_max")) { - communicator.setXaxis_histo_length_max(Double.parseDouble(cmd.getOptionValue("xaxis_histo_length_max"))); - } - - - if (cmd.hasOption('t')) { - communicator.setThreshold(Integer.parseInt(cmd.getOptionValue('t'))); - } - - - } catch (ParseException e) { - helpformatter.printHelp(CLASS_NAME, options); - System.err.println(e.getMessage()); - System.exit(0); - } - - } -} diff --git a/src/main/java/RunDamageProfiler.java b/src/main/java/RunDamageProfiler.java old mode 100644 new mode 100755 index 446cef6..3315488 --- a/src/main/java/RunDamageProfiler.java +++ b/src/main/java/RunDamageProfiler.java @@ -1,6 +1,3 @@ -import GUI.MainGuiFX; -import IO.*; -import calculations.StartCalculations; import javafx.application.Application; /** @@ -8,37 +5,24 @@ */ public class RunDamageProfiler { - private static final String VERSION = "0.4.9"; + private static final String VERSION = "0.5.0"; - - @SuppressWarnings("static-access") public static void main(String[] args) throws Exception { /* - get input parameters - $ damageprofiler : starts GUI + $ damageprofiler : starts org.damageprofiler.GUI $ damageprofiler -i <> -o <> .... : parse command line arguments - */ - if(args.length==0){ - //MainDP damageProfilerGUI = new MainDP(c, starter, VERSION); - System.out.println(VERSION); - new Thread(() -> Application.launch(MainGuiFX.class)).start(); + new Thread(() -> Application.launch(StarterGUI.class)).start(); } else { - Communicator c = new Communicator(); - StartCalculations starter = new StartCalculations(VERSION); - UserOptionsParser userOptions = new UserOptionsParser(args, c, VERSION); - starter.start(c); - + System.setProperty("java.awt.headless", "true"); + StarterCLI starterCLI = new StarterCLI(VERSION, args); } - - } - } diff --git a/src/main/java/StarterCLI.java b/src/main/java/StarterCLI.java new file mode 100755 index 0000000..46caa76 --- /dev/null +++ b/src/main/java/StarterCLI.java @@ -0,0 +1,15 @@ +import org.damageprofiler.calculations.StartCalculations; +import org.damageprofiler.IO.Communicator; +import org.damageprofiler.IO.UserOptionsParser; + +public class StarterCLI { + + public StarterCLI(String version, String[] args) throws Exception { + Communicator c = new Communicator(); + StartCalculations starter = new StartCalculations(); + starter.setVERSION(version); + UserOptionsParser userOptions = new UserOptionsParser(args, c, version); + starter.start(c); + System.exit(0); + } +} diff --git a/src/main/java/StarterGUI.java b/src/main/java/StarterGUI.java new file mode 100755 index 0000000..e37b4e0 --- /dev/null +++ b/src/main/java/StarterGUI.java @@ -0,0 +1,28 @@ +import org.damageprofiler.controller.DamageProfilerMainController; +import org.damageprofiler.GUI.DamageProfilerMainGUI; +import org.damageprofiler.controller.PlottingSettingController; +import org.damageprofiler.controller.ProgressBarController; +import javafx.application.Application; +import javafx.stage.Stage; + + +public class StarterGUI extends Application { + + private static final String VERSION = "0.5.0"; + + @Override + public void start(Stage primaryStage) { + + ProgressBarController progressBarController = new ProgressBarController(); + progressBarController.create(); + + DamageProfilerMainGUI damageProfilerMainGUI = new DamageProfilerMainGUI(VERSION, progressBarController); + damageProfilerMainGUI.init(primaryStage); + + PlottingSettingController plottingSettingController = new PlottingSettingController(); + new DamageProfilerMainController(damageProfilerMainGUI, progressBarController, plottingSettingController); + + } + + +} diff --git a/src/main/java/calculations/Aligner.java b/src/main/java/calculations/Aligner.java deleted file mode 100755 index 38b0f5f..0000000 --- a/src/main/java/calculations/Aligner.java +++ /dev/null @@ -1,97 +0,0 @@ -package calculations; - -import htsjdk.samtools.CigarElement; -import htsjdk.samtools.SAMRecord; -import org.apache.commons.lang3.StringUtils; -import org.apache.log4j.Logger; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Created by neukamm on 06.10.2016. - */ -public class Aligner { - - private final Logger LOG; - - public Aligner(Logger LOG){ - this.LOG = LOG; - - } - - /* - # from Martin Kircher, description of CIGAR operations - # BAM Description - #M 0 alignment match (can be a sequence match or mismatch) - #I 1 insertion to the reference - #D 2 deletion from the reference - #N 3 skipped region from the reference - #S 4 soft clipping (clipped sequences present in SEQ) - #H 5 hard clipping (clipped sequences NOT present in SEQ) - #P 6 padding (silent deletion from padded reference) - #= 7 sequence match - #X 8 sequence mismatch - */ - - /** - * align reference and read according cigar string - * - * @param seq - * @param ref - * @param record - * @return - */ - public String[] align(String seq, String ref, SAMRecord record){ - - List cigar_elements = record.getCigar().getCigarElements(); - - String ref_aligned = ref; - List coord = parseCigar(cigar_elements,1); - for(int i = 0; i < coord.size(); i++){ - double[] entry = coord.get(i); - ref_aligned = new StringBuilder(ref_aligned).insert((int)entry[1], StringUtils.repeat("-", (int)entry[0])).toString(); - } - String read_aligned = seq; - coord.clear(); - coord = parseCigar(cigar_elements,2); - for(int i = 0; i < coord.size(); i++){ - double[] entry = coord.get(i); - read_aligned = new StringBuilder(read_aligned).insert((int)entry[1]-1, StringUtils.repeat("-", (int)entry[0])).toString(); - } - - return new String[]{read_aligned, ref_aligned}; - - } - - - /** - * parse CIGAR string, get length of each operation and position of operation in read - * - * @param cigar - * @param ope - * @return double[] coordinates = position in record sequence and number of occurrences - */ - private List parseCigar(List cigar, int ope){ - List coordinates = new ArrayList<>(); - int tlength = 0; - - //count matches, indels and mismatches - List oplist = Arrays.asList(0, 1, 2, 7, 8); - - for(int i = 0; i < cigar.size(); i++){ - int length = cigar.get(i).getLength(); - int op = cigar.get(i).getOperator().ordinal(); - if(op == ope){ - coordinates.add(new double[]{length, tlength}); - - } - if(oplist.contains(op)){ - tlength+= length; - } - } - - return coordinates; - } -} diff --git a/src/main/java/calculations/Functions.java b/src/main/java/calculations/Functions.java deleted file mode 100755 index 2a62748..0000000 --- a/src/main/java/calculations/Functions.java +++ /dev/null @@ -1,46 +0,0 @@ -package calculations; - -import org.apache.log4j.Logger; - -/** - * Created by neukamm on 13.03.17. - */ -public class Functions { - - private final Logger LOG; - - public Functions(Logger LOG){ - this.LOG = LOG; - } - - - /** - * Get the hamming distance between two string sequences - * - * @param sequence1 - the first sequence - * @param sequence2 - the second sequence - * @return the hamming distance - */ - public static int getHammingDistance(String sequence1, String sequence2){ - int distance =0; - if(sequence1 == null || sequence2==null) - System.exit(0); - - sequence1 = sequence1.toUpperCase(); - sequence2 = sequence2.toUpperCase(); - - if(sequence1.length() != sequence2.length()) - { - System.out.println("The string are not equal in length ,Please enter the strings wit equal lengths "); - } - - for(int i=0;i < sequence1.length();i++) - { - if(sequence1.charAt(i)!=sequence2.charAt(i)) - distance++; - } - - return distance; - - } -} diff --git a/src/main/java/GUI/BamFileChooserFX.java b/src/main/java/org/damageprofiler/GUI/BamFileChooser.java similarity index 75% rename from src/main/java/GUI/BamFileChooserFX.java rename to src/main/java/org/damageprofiler/GUI/BamFileChooser.java index c91b333..81fbd0c 100755 --- a/src/main/java/GUI/BamFileChooserFX.java +++ b/src/main/java/org/damageprofiler/GUI/BamFileChooser.java @@ -1,6 +1,6 @@ -package GUI; +package org.damageprofiler.GUI; -import IO.Communicator; +import org.damageprofiler.IO.Communicator; import javafx.stage.FileChooser; import javafx.stage.Stage; @@ -8,11 +8,11 @@ import java.util.ArrayList; import java.util.List; -public class BamFileChooserFX { +public class BamFileChooser { private FileChooser fileChooser = new FileChooser(); - public BamFileChooserFX(Communicator c){ + public BamFileChooser(Communicator c){ fileChooser.getExtensionFilters().addAll( new FileChooser.ExtensionFilter("BAM", "*.bam"), @@ -31,9 +31,10 @@ public BamFileChooserFX(Communicator c){ } c.setInput(files.get(0)); - System.out.println(files.get(0)); + System.out.println("Input file: " + files.get(0)); } catch (Exception e){ + System.err.println(e); } diff --git a/src/main/java/org/damageprofiler/GUI/DamageProfilerMainGUI.java b/src/main/java/org/damageprofiler/GUI/DamageProfilerMainGUI.java new file mode 100755 index 0000000..f1f096e --- /dev/null +++ b/src/main/java/org/damageprofiler/GUI/DamageProfilerMainGUI.java @@ -0,0 +1,132 @@ +package org.damageprofiler.GUI; + +import org.damageprofiler.GUI.Dialogues.ConfigurationDialogue; +import org.damageprofiler.IO.Communicator; +import org.damageprofiler.controller.ProgressBarController; +import javafx.geometry.Insets; +import javafx.scene.Scene; +import javafx.scene.control.*; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; + +import java.io.InputStream; + +public class DamageProfilerMainGUI { + + + private final String version; + private final ProgressBarController progressBarController; + private Stage primaryStage; + private Communicator communicator = new Communicator(); + private BorderPane root; + private ConfigurationDialogue config_dialogue; + private Button btn_leftpane_identityDist; + private Button btn_leftpane_info; + private Button btn_leftpane_damageProfile; + private Button btn_leftpane_lengthDist; + private Button btn_help; + + + public DamageProfilerMainGUI(String version, ProgressBarController progressBarController) { + this.version = version; + this.progressBarController = progressBarController; + } + + public void init(Stage primaryStage) { + + this.primaryStage = primaryStage; + this.primaryStage.setTitle("DamageProfiler v" + version); + + root = new BorderPane(); + + config_dialogue = new ConfigurationDialogue(progressBarController.getProgressBar()); + + ScrollPane scrollPane_adv_config = new ScrollPane(); + scrollPane_adv_config.setPadding(new Insets(10,10,10,10)); + scrollPane_adv_config.setContent(config_dialogue.getConfig_gridpane()); + root.setCenter(scrollPane_adv_config); + root.setLeft(generateLeftPane()); + + this.primaryStage.setScene(new Scene(root, 950, 700)); + this.primaryStage.setResizable(true); + this.primaryStage.show(); + + } + + private VBox generateLeftPane() { + + // Image Source + InputStream input= getClass().getClassLoader().getResourceAsStream("logo.png"); + Image image = new Image(input); + ImageView imageView = new ImageView(image); + + // Create a Label with label and Icon + Label label = new Label("", imageView); + + + + VBox leftPanel = new VBox(); + btn_leftpane_damageProfile = new Button("Damage Plot"); + btn_leftpane_info = new Button("Run Configuration"); + btn_help = new Button("Show help"); + btn_leftpane_lengthDist = new Button("Length Distribution"); + btn_leftpane_identityDist = new Button("Edit distance"); + + // style buttons + btn_leftpane_info.setPrefHeight(30); + btn_leftpane_info.setPrefWidth(200); + + btn_help.setPrefHeight(30); + btn_help.setPrefWidth(200); + + btn_leftpane_damageProfile.setPrefHeight(30); + btn_leftpane_damageProfile.setPrefWidth(200); + btn_leftpane_damageProfile.setDisable(true); + + btn_leftpane_lengthDist.setPrefHeight(30); + btn_leftpane_lengthDist.setPrefWidth(200); + btn_leftpane_lengthDist.setDisable(true); + + btn_leftpane_identityDist.setPrefHeight(30); + btn_leftpane_identityDist.setPrefWidth(200); + btn_leftpane_identityDist.setDisable(true); + + leftPanel.getChildren().addAll(label, btn_leftpane_info, btn_leftpane_damageProfile, btn_leftpane_lengthDist, btn_leftpane_identityDist, btn_help); + leftPanel.setPadding(new Insets(10,10,10,10)); + + return leftPanel; + } + + + + public Communicator getCommunicator() { + return communicator; + } + + public BorderPane getRoot() { + return root; + } + + public Button getBtn_leftpane_identityDist() { + return btn_leftpane_identityDist; + } + + public Button getBtn_leftpane_info() { return btn_leftpane_info; } + + public Button getBtn_leftpane_damageProfile() { + return btn_leftpane_damageProfile; + } + + public Button getBtn_leftpane_lengthDist() { + return btn_leftpane_lengthDist; + } + + public Button getBtn_help() { return btn_help; } + + public ConfigurationDialogue getConfig_dialogue() { return config_dialogue; } + + public String getVersion() { return version; } +} diff --git a/src/main/java/org/damageprofiler/GUI/Dialogues/AbstractApplication.java b/src/main/java/org/damageprofiler/GUI/Dialogues/AbstractApplication.java new file mode 100755 index 0000000..117d430 --- /dev/null +++ b/src/main/java/org/damageprofiler/GUI/Dialogues/AbstractApplication.java @@ -0,0 +1,48 @@ +package org.damageprofiler.GUI.Dialogues; + +import javafx.geometry.Pos; +import javafx.scene.Scene; +import javafx.scene.control.Label; +import javafx.scene.control.Separator; +import javafx.scene.layout.GridPane; +import javafx.stage.Modality; +import javafx.stage.Stage; + +public class AbstractApplication { + + private final Stage stage; + protected GridPane gridPane; + protected int row; + + public AbstractApplication(String header, String message){ + + stage = new Stage(); + stage.setTitle(header); + stage.initModality(Modality.APPLICATION_MODAL); + stage.initOwner(new Stage()); + + gridPane = new GridPane(); + gridPane.setAlignment(Pos.CENTER); + gridPane.setHgap(10); + gridPane.setVgap(10); + + fillGrid(message); + + } + + private void fillGrid(String message) { + row = 0; + gridPane.add(new Label(message), 0,row,2,1); + gridPane.add(new Separator(), 0,++row,2,1); + } + + public void show(){ + Scene dialogScene = new Scene(gridPane, 600, 200); + stage.setScene(dialogScene); + stage.show(); + } + + public void close() { + stage.close(); + } +} diff --git a/src/main/java/org/damageprofiler/GUI/Dialogues/AbstractDialogue.java b/src/main/java/org/damageprofiler/GUI/Dialogues/AbstractDialogue.java new file mode 100755 index 0000000..535f52b --- /dev/null +++ b/src/main/java/org/damageprofiler/GUI/Dialogues/AbstractDialogue.java @@ -0,0 +1,39 @@ +package org.damageprofiler.GUI.Dialogues; + +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.control.Label; +import javafx.scene.control.Separator; +import javafx.scene.layout.GridPane; +import javafx.scene.text.Font; +import javafx.scene.text.FontWeight; + +public class AbstractDialogue { + + protected GridPane gridPane; + protected int row; + + public AbstractDialogue(String message){ + gridPane = new GridPane(); + gridPane.setAlignment(Pos.CENTER); + gridPane.setHgap(10); + gridPane.setVgap(10); + gridPane.setPadding(new Insets(15,15,15,15)); + + fillGrid(message); + } + + private void fillGrid(String message) { + + Label label_message = new Label(message); + label_message.setFont(Font.font("Verdana", FontWeight.BOLD, 14)); + + row = 0; + gridPane.add(label_message, 0,row,2,1); + gridPane.add(new Separator(), 0,++row,2,1); + } + + public GridPane getGridPane() { + return gridPane; + } +} diff --git a/src/main/java/org/damageprofiler/GUI/Dialogues/AdvancedPlottingOptionsDialogue.java b/src/main/java/org/damageprofiler/GUI/Dialogues/AdvancedPlottingOptionsDialogue.java new file mode 100755 index 0000000..8f52061 --- /dev/null +++ b/src/main/java/org/damageprofiler/GUI/Dialogues/AdvancedPlottingOptionsDialogue.java @@ -0,0 +1,45 @@ +package org.damageprofiler.GUI.Dialogues; + +import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; + + +public class AdvancedPlottingOptionsDialogue { + + private TabPane tabPane; + private Tab tab_DP; + private TabAdvancedSettingsDamagePlot tabAdvancedSettingsDamagePlot; + + /** + * Tab for the configuration of all colours of the damage patterns + */ + public AdvancedPlottingOptionsDialogue(){ + + fill(); + } + + /** + * Fill the empty tab pane with all components + */ + private void fill() { + + tabAdvancedSettingsDamagePlot = new TabAdvancedSettingsDamagePlot("Damage Profile"); + tab_DP = tabAdvancedSettingsDamagePlot.getTab(); + + tabPane = new TabPane(); + tabPane.getTabs().addAll(tab_DP); + + } + + + /* + Getter + */ + public TabPane getGridPane() { + return tabPane; + } + public TabAdvancedSettingsDamagePlot getTabAdvancedSettingsDamagePlot() { + return tabAdvancedSettingsDamagePlot; + } + +} diff --git a/src/main/java/org/damageprofiler/GUI/Dialogues/ColorPickerPane.java b/src/main/java/org/damageprofiler/GUI/Dialogues/ColorPickerPane.java new file mode 100755 index 0000000..c71d232 --- /dev/null +++ b/src/main/java/org/damageprofiler/GUI/Dialogues/ColorPickerPane.java @@ -0,0 +1,17 @@ +package org.damageprofiler.GUI.Dialogues; + +import javafx.scene.control.ColorPicker; +import javafx.scene.paint.Color; + +public class ColorPickerPane { + private ColorPicker colorPicker; + + public ColorPickerPane(Color color){ + colorPicker = new ColorPicker(); + colorPicker.setValue(color); + } + + public ColorPicker getPicker() { + return colorPicker; + } +} diff --git a/src/main/java/org/damageprofiler/GUI/Dialogues/ConfigurationDialogue.java b/src/main/java/org/damageprofiler/GUI/Dialogues/ConfigurationDialogue.java new file mode 100755 index 0000000..ddcc4fe --- /dev/null +++ b/src/main/java/org/damageprofiler/GUI/Dialogues/ConfigurationDialogue.java @@ -0,0 +1,220 @@ +package org.damageprofiler.GUI.Dialogues; + +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.control.*; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import javafx.scene.text.Font; +import javafx.scene.text.FontWeight; + +public class ConfigurationDialogue { + + + private GridPane config_gridpane; + + private Button btn_inputfile; + private Button btn_reference; + private Button btn_output; + private Button btn_run; + private Button btn_estimate_runtime; + private Button btn_speciesList; + + private TextField textfield_threshold; + private TextField textfield_length; + private TextField textfield_species; + private CheckBox checkbox_use_merged_reads; + private CheckBox checkbox_ssLibs_protocol; + private TextField textfield_title; + private TextField textfield_y_axis_height; + + private ProgressBar progressBar; + private AdvancedPlottingOptionsDialogue advancedPlottingOptionsDialogue; + private Button btn_loadSpecies; + + + public ConfigurationDialogue(ProgressBar progressBar){ + + config_gridpane = new GridPane(); + config_gridpane.setAlignment(Pos.CENTER); + config_gridpane.setHgap(7); + config_gridpane.setVgap(7); + config_gridpane.setPadding(new Insets(10,10,10,10)); + + this.progressBar = progressBar; + addComponents(); + + } + + private void addComponents() { + + btn_inputfile = new Button("Select input file"); + btn_reference = new Button("Select reference"); + btn_output = new Button("Select output"); + btn_speciesList = new Button("Set species file"); + btn_loadSpecies = new Button("Load Species"); + btn_run = new Button("Run"); + btn_estimate_runtime = new Button("Estimate Runtime"); + + Label label_threshold = new Label("Number of bases (x-axis)"); + Label label_yaxis = new Label("Height y-axis"); + Label label_length = new Label("Set number of bases"); + Label label_specie = new Label("Enter RefSeq ID "); + Label label_title = new Label("Set title"); + + Label label_plot = new Label("Plot"); + label_plot.setFont(Font.font("Verdana", FontWeight.BOLD, 14)); + + Label label_files = new Label("Files"); + label_files.setFont(Font.font("Verdana", FontWeight.BOLD, 14)); + + Label label_calculations = new Label("Calculations"); + label_calculations.setFont(Font.font("Verdana", FontWeight.BOLD, 14)); + + Label label_title_config = new Label("Configuration"); + label_title_config.setFont(Font.font("Verdana", FontWeight.BOLD, 14)); + + textfield_threshold = new TextField(); + textfield_length = new TextField(); + textfield_species = new TextField(); + textfield_title = new TextField(); + textfield_y_axis_height = new TextField(); + + checkbox_use_merged_reads = new CheckBox("Only merged reads"); + checkbox_ssLibs_protocol = new CheckBox("Single-stranded library protocol"); + + btn_run.setDisable(true); + btn_estimate_runtime.setDisable(true); + textfield_length.setText("100"); + textfield_threshold.setText("25"); + textfield_y_axis_height.setText("0.4"); + + TitledPane pane_advanced_plotting_options = new TitledPane(); + pane_advanced_plotting_options.setText("Advanced options (Plotting)"); + + + advancedPlottingOptionsDialogue = new AdvancedPlottingOptionsDialogue(); + pane_advanced_plotting_options.setContent(advancedPlottingOptionsDialogue.getGridPane()); + pane_advanced_plotting_options.setExpanded(false); + + TitledPane pane_advanced_calculation_options = new TitledPane(); + pane_advanced_calculation_options.setText("Advanced options (Calculation)"); + HBox hbox_length_calc = new HBox(); + hbox_length_calc.setPadding(new Insets(10,10,10,10)); + hbox_length_calc.getChildren().addAll(label_length, textfield_length); + pane_advanced_calculation_options.setContent(hbox_length_calc); + pane_advanced_calculation_options.setExpanded(false); + + + // add components to grid + + int row = 0; + + config_gridpane.add(label_title_config, 0, row, 1,1); + config_gridpane.add(new Separator(), 0, ++row,3,1); + + + config_gridpane.add(label_files, 0, ++row, 1,1); + config_gridpane.add(btn_inputfile, 0, ++row,1,1); + config_gridpane.add(btn_reference, 1, row,1,1); + config_gridpane.add(btn_output, 2, row,1,1); + config_gridpane.add(new Separator(), 0, ++row,3,1); + + // PLOT + + config_gridpane.add(label_plot, 0, ++row, 1,1); + config_gridpane.add(label_title, 0, ++row, 1,1); + config_gridpane.add(textfield_title, 1, row, 2,1); + config_gridpane.add(label_yaxis, 0, ++row, 1,1); + //config_gridpane.add(checkbox_dynamic_y_axis_height, 1, row, 1,1); + config_gridpane.add(textfield_y_axis_height, 1, row, 2,1); + config_gridpane.add(label_threshold, 0, ++row, 1,1); + config_gridpane.add(textfield_threshold, 1, row, 2,1); + config_gridpane.add(pane_advanced_plotting_options, 0,++row, 3,1); + config_gridpane.add(new Separator(), 0, ++row,3,1); + + // CALCULATIONS + config_gridpane.add(label_calculations, 0, ++row, 1,1); + config_gridpane.add(checkbox_use_merged_reads, 0, ++row,1,1); + config_gridpane.add(checkbox_ssLibs_protocol, 0, ++row, 1,1); + config_gridpane.add(label_specie, 0, ++row, 1,1); + config_gridpane.add(textfield_species, 1, row, 2,1); + config_gridpane.add(btn_speciesList, 1, ++row, 1,1); + //config_gridpane.add(btn_loadSpecies, 3, row, 1,1); + config_gridpane.add(pane_advanced_calculation_options, 0,++row, 3,1); + + config_gridpane.add(new Separator(), 0, ++row,3,1); + config_gridpane.add(btn_estimate_runtime, 0, ++row,1,1); + config_gridpane.add(btn_run, 1, row,1,1); + config_gridpane.add(progressBar, 2, row,1,1); + + } + + public GridPane getConfig_gridpane() { + return config_gridpane; + } + + public Button getBtn_inputfile() { + return btn_inputfile; + } + + public Button getBtn_reference() { + return btn_reference; + } + + public Button getBtn_output() { + return btn_output; + } + + public Button getBtn_run() { + return btn_run; + } + + public Button getBtn_speciesList() { + return btn_speciesList; + } + + public TextField getTextfield_threshold() { + return textfield_threshold; + } + + public TextField getTextfield_length() { + return textfield_length; + } + + public TextField getTextfield_species() { + return textfield_species; + } + + public CheckBox getCheckbox_use_merged_reads() { + return checkbox_use_merged_reads; + } + + public CheckBox getCheckbox_ssLibs_protocol() { + return checkbox_ssLibs_protocol; + } + + public TextField getTextfield_title() { + return textfield_title; + } + + public void setTextfield_title(String textfield_title) { + this.textfield_title.setText(textfield_title); + } + + public TextField getTextfield_y_axis_height() { + return textfield_y_axis_height; + } + + public Button getBtn_estimate_runtime() { + return btn_estimate_runtime; + } + + public AdvancedPlottingOptionsDialogue getAdvancedPlottingOptionsDialogue() { + return advancedPlottingOptionsDialogue; + } + + public Button getBtn_loadSpecies() { + return btn_loadSpecies; + } +} diff --git a/src/main/java/org/damageprofiler/GUI/Dialogues/HelpDialogue.java b/src/main/java/org/damageprofiler/GUI/Dialogues/HelpDialogue.java new file mode 100755 index 0000000..4862a61 --- /dev/null +++ b/src/main/java/org/damageprofiler/GUI/Dialogues/HelpDialogue.java @@ -0,0 +1,101 @@ +package org.damageprofiler.GUI.Dialogues; + + +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.control.Hyperlink; +import javafx.scene.control.Label; +import javafx.scene.control.Separator; +import javafx.scene.layout.GridPane; +import javafx.scene.text.Font; +import javafx.scene.text.FontWeight; + +import java.awt.*; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +public class HelpDialogue { + + private final GridPane gridPane; + private Hyperlink link; + + public HelpDialogue(){ + + gridPane = new GridPane(); + gridPane.setAlignment(Pos.CENTER); + gridPane.setHgap(10); + gridPane.setVgap(10); + gridPane.setPadding(new Insets(15,15,15,15)); + + fill(); + } + + /** + * Fill dialogue with help content + */ + private void fill() { + Label label_title = new Label("Welcome to DamageProfiler help page"); + label_title.setFont(Font.font("Verdana", FontWeight.BOLD, 14)); + + Label label_usage = new Label("Usage:\n"); + label_usage.setFont(Font.font("Verdana", FontWeight.BOLD, 12)); + + Label label_help = new Label(); + label_help.setText("DamageProfiler [-h] [-version] [-i ] [-r ] [-o ] [-t ]\n[-s ] [-sf ] " + + "[-l ] [-title ] [-yaxis_dp_max <MAX_VALUE>]\n[-xaxis_id_min <MIN_VALUE>] [-xaxis_id_max <MAX_VALUE>] [-xaxis_length_min <MIN_VALUE>]\n" + + "[-xaxis_length_max <MAX_VALUE>] [-only_merged] [-ssLib]" + + "\n\n" ); + + Label label_details = new Label("Detailed description:\n"); + label_details.setFont(Font.font("Verdana", FontWeight.BOLD, 12)); + + link = new Hyperlink(); + link.setText("Documentation"); + link.setOnAction(event -> new Thread(() -> { + try { + Desktop.getDesktop().browse(new URI("http://damageprofiler.readthedocs.io/en/latest/")); + } catch (IOException | URISyntaxException e1) { + e1.printStackTrace(); + } + }).start()); + + Label label_helppage = new Label(" -h\t\t\t\t\t\t\tShows this help page.\n" + + " -version\t\t\t\t\t\tShows the version of DamageProfiler.\n" + + " -i <INPUT>\t\t\t\t\tREQUIRED: The input sam/bam/cram file.\n" + + " -r <REFERENCE>\t\t\t\tThe reference file (fasta format).\n" + + " -o <OUTPUT>\t\t\t\t\tREQUIRED: The output folder.\n" + + " -t <THRESHOLD>\t\t\t\tDamagePlot: Number of bases which are considered for plotting\n\t\t\t\t\t\t\tnucleotide misincorporations. Default: 25\n" + + " -s <SPECIES>\t\t\t\t\tReference sequence name (RNAME flag of SAM record).\n\t\t\t\t\t\t\tFor more details see Documentation.\n" + + " -sf <SPECIES LIST>\t\t\t\tList with species for which damage profile has to be calculated.\n\t\t\t\t\t\t\tFor more details see Documentation.\n" + + " -l <LENGTH>\t\t\t\t\tNumber of bases which are considered for frequency\n\t\t\t\t\t\t\tcomputations. Default: 100.\n" + + " -title <TITLE>\t\t\t\t\tTitle used for all plots. Default: input filename.\n" + + " -yaxis_dp_max <MAX_VALUE>\tDamagePlot: Maximal y-axis value.\n" + + " -xaxis_id_min <MIN_VALUE>\t\tIdentity Distribution: Minimal value x-axis.\n" + + " -xaxis_id_max <MAX_VALUE>\tIdentity Distribution: Maximal value x-axis.\n" + + " -xaxis_length_min <MIN_VALUE>\tLength Distribution: Minimal value x-axis.\n" + + " -xaxis_length_max <MAX_VALUE>\tLength Distribution: Maximal value x-axis.\n" + + " -only_merged\t\t\t\t\tUse only mapped and merged reads to calculate damage plot\n\t\t\t\t\t\t\tinstead of using all mapped reads.\n\t\t\t\t\t\t\tThe SAM/BAM entry must start with 'M_', otherwise it will\n\t\t\t\t\t\t\tbe skipped. Default: false\n" + + " -ssLib\t\t\t\t\t\tSingle-stranded library protocol was used. Default: false"); + + int row=0; + + gridPane.add(label_title,0,row,2,1); + gridPane.add(new Label("If you need more information, please check the documentation or contact the developers."),0, ++row,2,1); + gridPane.add(link,0, ++row,2,1); + gridPane.add(new Separator(),0, ++row,2,1); + + gridPane.add(label_usage,0, ++row,2,1); + gridPane.add(label_help,0, ++row,2,1); + gridPane.add(label_details,0, ++row,2,1); + gridPane.add(label_helppage, 0,++row, 2,1); + + } + + + // Getter + + public GridPane getGridPane() { + return this.gridPane; + } +} diff --git a/src/main/java/org/damageprofiler/GUI/Dialogues/RunInfoDialogue.java b/src/main/java/org/damageprofiler/GUI/Dialogues/RunInfoDialogue.java new file mode 100755 index 0000000..9821f0f --- /dev/null +++ b/src/main/java/org/damageprofiler/GUI/Dialogues/RunInfoDialogue.java @@ -0,0 +1,65 @@ +package org.damageprofiler.GUI.Dialogues; + +import org.damageprofiler.IO.Communicator; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.Separator; + +public class RunInfoDialogue extends AbstractDialogue { + + private final Communicator communicator; + private Button btn_new_config; + private ScrollPane scrollPaneRef; + private ScrollPane scrollPaneInput; + private ScrollPane scrollPaneOutput; + + public RunInfoDialogue(String message, Communicator communicator){ + super(message); + this.communicator = communicator; + btn_new_config = new Button("New configuration"); + init(); + } + + + public void init() { + + scrollPaneInput = new ScrollPane( new Label(communicator.getInput())); + scrollPaneOutput = new ScrollPane( new Label(communicator.getOutfolder())); + scrollPaneRef = new ScrollPane( new Label(communicator.getReference())); + + + Label label_input = new Label("Input file: "); + Label label_output = new Label("Output folder: "); + Label label_ref = new Label("Reference file: "); + + + gridPane.add(label_input, 0,++row, 1,1); + gridPane.add(scrollPaneInput, 1,row, 2,1); + + gridPane.add(label_output, 0,++row, 1,1); + gridPane.add(scrollPaneOutput, 1,row, 2,1); + + gridPane.add(label_ref, 0,++row, 1,1); + gridPane.add(scrollPaneRef, 1,row, 2,1); + + gridPane.add(new Separator(), 0,++row, 1,2); + + + + gridPane.add(btn_new_config, 0, ++row, 1,1); + + } + + public void updateParameters(){ + scrollPaneInput.setContent(new Label(communicator.getInput())); + scrollPaneOutput.setContent( new Label(communicator.getOutfolder())); + scrollPaneRef.setContent(new Label(communicator.getReference())); + + } + + + public Button getBtn_new_config() { + return btn_new_config; + } +} diff --git a/src/main/java/org/damageprofiler/GUI/Dialogues/RuntimeEstimatorDialogue.java b/src/main/java/org/damageprofiler/GUI/Dialogues/RuntimeEstimatorDialogue.java new file mode 100755 index 0000000..10b9e0e --- /dev/null +++ b/src/main/java/org/damageprofiler/GUI/Dialogues/RuntimeEstimatorDialogue.java @@ -0,0 +1,49 @@ +package org.damageprofiler.GUI.Dialogues; + +import javafx.scene.control.Button; +import javafx.scene.control.Label; + +public class RuntimeEstimatorDialogue extends AbstractApplication { + + private final Button btn_proceed; + private final Button btn_cancel; + private int numberOfRecords; + private String text_estimatedRuntime; + + public RuntimeEstimatorDialogue(String header, String message) { + super(header, message); + + + btn_proceed = new Button("Proceed"); + btn_cancel = new Button("Cancel"); + + + } + + public void setNumberOfRecords(int numberOfRecords) { + this.numberOfRecords = numberOfRecords; + } + + public void setResultText(String text_estimatedRuntime) { + this.text_estimatedRuntime = text_estimatedRuntime; + } + + public void addComponents(){ + this.gridPane.add(new Label("Number of reads: " + numberOfRecords), 0, ++row, 2,1); + this.gridPane.add(new Label(text_estimatedRuntime), 0, ++row, 2,1); + this.gridPane.add(btn_cancel, 0, ++row, 1,1); + this.gridPane.add(btn_proceed, 1, row, 1,1); + + + } + + + public Button getBtn_proceed() { + return btn_proceed; + } + + public Button getBtn_cancel() { + return btn_cancel; + } + +} diff --git a/src/main/java/org/damageprofiler/GUI/Dialogues/TabAdvancedSettingsDamagePlot.java b/src/main/java/org/damageprofiler/GUI/Dialogues/TabAdvancedSettingsDamagePlot.java new file mode 100755 index 0000000..dd67833 --- /dev/null +++ b/src/main/java/org/damageprofiler/GUI/Dialogues/TabAdvancedSettingsDamagePlot.java @@ -0,0 +1,143 @@ +package org.damageprofiler.GUI.Dialogues; + +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.control.Button; +import javafx.scene.control.ColorPicker; +import javafx.scene.control.Label; +import javafx.scene.control.Tab; +import javafx.scene.layout.GridPane; +import javafx.scene.paint.Color; + +public class TabAdvancedSettingsDamagePlot { + + private final Tab tab; + private ColorPicker colorPicker_C_to_T; + private ColorPicker colorPicker_G_to_A; + private ColorPicker colorPicker_insertions; + private ColorPicker colorPicker_deletions; + private ColorPicker colorPicker_others; + private Button btn_reset; + private GridPane gridpane; + + /** + * Tab pane to configure the visualization of the damage profile + * (misincorporation frequencies) + * @param title + */ + public TabAdvancedSettingsDamagePlot(String title){ + + this.tab = new Tab(title); + btn_reset = new Button("Reset"); + + fill( generateColorPicker(Color.RED), + generateColorPicker(Color.BLUE), + generateColorPicker(Color.valueOf("FF00FF")), + generateColorPicker(Color.GREEN), + generateColorPicker(Color.GREY)); + + } + + + + /** + * Fill grid pane with all components + * + * @param c_t + * @param g_a + * @param insertions + * @param deletions + * @param others + */ + public void fill(ColorPicker c_t, ColorPicker g_a, ColorPicker insertions, ColorPicker deletions, ColorPicker others) { + gridpane = new GridPane(); + gridpane.setAlignment(Pos.BOTTOM_LEFT); + gridpane.setHgap(7); + gridpane.setVgap(7); + gridpane.setPadding(new Insets(10,10,10,10)); + + + colorPicker_C_to_T = c_t; + colorPicker_G_to_A = g_a; + colorPicker_insertions = insertions; + colorPicker_deletions = deletions; + colorPicker_others = others; + + gridpane.add(new Label("C->T"), 0,0,1,1); + gridpane.add(colorPicker_C_to_T, 0,1,1,1); + + gridpane.add(new Label("G->A"), 1,0,1,1); + gridpane.add(colorPicker_G_to_A, 1,1,1,1); + + gridpane.add(new Label("Insertions"), 0,2,1,1); + gridpane.add(colorPicker_insertions, 0,3,1,1); + + gridpane.add(new Label("Deletions"), 1,2,1,1); + gridpane.add(colorPicker_deletions, 1,3,1,1); + + gridpane.add(new Label("Others"), 0,4,1,1); + gridpane.add(colorPicker_others, 0,5,1,1); + + gridpane.add(btn_reset, 2,5,1,1); + + tab.setContent(gridpane); + } + + + /** + * Generate and return color picker + * + * @param color + * @return + */ + public ColorPicker generateColorPicker(Color color) { + ColorPickerPane colorPickerPane = new ColorPickerPane(color); + return colorPickerPane.getPicker(); + } + + /* + Getter + */ + public Tab getTab() { + return tab; + } + + public ColorPicker getColorPicker_C_to_T() { + return colorPicker_C_to_T; + } + + public ColorPicker getColorPicker_G_to_A() { + return colorPicker_G_to_A; + } + + public ColorPicker getColorPicker_insertions() { + return colorPicker_insertions; + } + + public ColorPicker getColorPicker_deletions() { + return colorPicker_deletions; + } + + public ColorPicker getColorPicker_others() { + return colorPicker_others; + } + + public Button getBtn_reset() { + return btn_reset; + } + + public GridPane getGridpane() { + return gridpane; + } + + public void reset() { + + this.gridpane.getChildren().clear(); + fill( generateColorPicker(Color.RED), + generateColorPicker(Color.BLUE), + generateColorPicker(Color.valueOf("FF00FF")), + generateColorPicker(Color.GREEN), + generateColorPicker(Color.GREY)); + + } +} diff --git a/src/main/java/GUI/OutputDirChooserFX.java b/src/main/java/org/damageprofiler/GUI/OutputDirChooser.java similarity index 57% rename from src/main/java/GUI/OutputDirChooserFX.java rename to src/main/java/org/damageprofiler/GUI/OutputDirChooser.java index 9141f5f..b9ab610 100755 --- a/src/main/java/GUI/OutputDirChooserFX.java +++ b/src/main/java/org/damageprofiler/GUI/OutputDirChooser.java @@ -1,20 +1,20 @@ -package GUI; +package org.damageprofiler.GUI; -import IO.Communicator; +import org.damageprofiler.IO.Communicator; import javafx.stage.DirectoryChooser; import javafx.stage.Stage; import java.io.File; -public class OutputDirChooserFX { +public class OutputDirChooser { private DirectoryChooser dirChooser = new DirectoryChooser(); - public OutputDirChooserFX(Communicator c) { + public OutputDirChooser(Communicator c) { File f = dirChooser.showDialog(new Stage()); if (f != null){ c.setOutfolder(f.getAbsolutePath()); - System.out.println(f.getAbsolutePath()); + System.out.println("Output folder: " + f.getAbsolutePath()); } } diff --git a/src/main/java/GUI/ReferenceFileChooserFX.java b/src/main/java/org/damageprofiler/GUI/ReferenceFileChooser.java similarity index 73% rename from src/main/java/GUI/ReferenceFileChooserFX.java rename to src/main/java/org/damageprofiler/GUI/ReferenceFileChooser.java index 632458b..384df7b 100755 --- a/src/main/java/GUI/ReferenceFileChooserFX.java +++ b/src/main/java/org/damageprofiler/GUI/ReferenceFileChooser.java @@ -1,16 +1,16 @@ -package GUI; +package org.damageprofiler.GUI; -import IO.Communicator; +import org.damageprofiler.IO.Communicator; import javafx.stage.FileChooser; import javafx.stage.Stage; import java.io.File; -public class ReferenceFileChooserFX { +public class ReferenceFileChooser { private FileChooser fileChooser = new FileChooser(); - public ReferenceFileChooserFX(Communicator c){ + public ReferenceFileChooser(Communicator c){ fileChooser.getExtensionFilters().addAll( new FileChooser.ExtensionFilter("Fasta", "*.fa","*.fasta", ".fas") diff --git a/src/main/java/GUI/SpeciesListFileChooser.java b/src/main/java/org/damageprofiler/GUI/SpeciesListFileChooser.java similarity index 83% rename from src/main/java/GUI/SpeciesListFileChooser.java rename to src/main/java/org/damageprofiler/GUI/SpeciesListFileChooser.java index a9e894a..c33feb9 100755 --- a/src/main/java/GUI/SpeciesListFileChooser.java +++ b/src/main/java/org/damageprofiler/GUI/SpeciesListFileChooser.java @@ -1,6 +1,6 @@ -package GUI; +package org.damageprofiler.GUI; -import IO.Communicator; +import org.damageprofiler.IO.Communicator; import javafx.stage.FileChooser; import javafx.stage.Stage; @@ -16,6 +16,5 @@ public SpeciesListFileChooser(Communicator c){ if(f != null){ c.setSpecieslist_filepath(f.getAbsolutePath()); } - } } diff --git a/src/main/java/IO/Communicator.java b/src/main/java/org/damageprofiler/IO/Communicator.java similarity index 66% rename from src/main/java/IO/Communicator.java rename to src/main/java/org/damageprofiler/IO/Communicator.java index 88226d1..faf04db 100755 --- a/src/main/java/IO/Communicator.java +++ b/src/main/java/org/damageprofiler/IO/Communicator.java @@ -1,4 +1,6 @@ -package IO; +package org.damageprofiler.IO; + +import javafx.scene.paint.Color; /** * Created by neukamm on 11.11.2016. @@ -14,27 +16,28 @@ public class Communicator { // damage calculation private int threshold = 25; - private double yAxis_damageplot=0.4; - private double xaxis_histo_id_min =-1; - private double xaxis_histo_id_max =-1; - private double xaxis_histo_length_min=-1; - private double xaxis_histo_length_max=-1; + private double yAxis_damageplot = 0.4; + private double xaxis_histo_id_min = -1; + private double xaxis_histo_id_max = -1; + private double xaxis_histo_length_min = -1; + private double xaxis_histo_length_max = -1; private int length = 100; private boolean use_merged_and_mapped_reads = false; private boolean use_all_reads = false; + private boolean ssLibsProtocolUsed = false; // specie filtering private String species_ref_identifier = null; // plot settings private String title_plots; + private Color color_DP_C_to_T = Color.RED; + private Color color_DP_G_to_A = Color.BLUE; + private Color color_DP_insertions = Color.valueOf("FF00FF"); + private Color color_DP_deletions = Color.GREEN; + private Color color_DP_other = Color.GREY; - - public Communicator(){ - - } - public String getInput() { return input; } @@ -99,6 +102,14 @@ public void setUse_all_reads(boolean use_all_reads) { this.use_all_reads = use_all_reads; } + public boolean isSsLibsProtocolUsed() { + return ssLibsProtocolUsed; + } + + public void setSsLibsProtocolUsed(boolean ssLibsProtocolUsed) { + this.ssLibsProtocolUsed = ssLibsProtocolUsed; + } + public void setyAxis_damageplot(double yAxis_damageplot) { this.yAxis_damageplot = yAxis_damageplot; } @@ -123,7 +134,6 @@ public void setSpecieslist_filepath(String specieslist_filepath) { this.specieslist_filepath = specieslist_filepath; } - public double getXaxis_histo_id_min() { return xaxis_histo_id_min; } @@ -155,4 +165,45 @@ public double getXaxis_histo_length_max() { public void setXaxis_histo_length_max(double xaxis_histo_length_max) { this.xaxis_histo_length_max = xaxis_histo_length_max; } + + public void setColor_DP_C_to_T(Color color_c_to_t) { + this.color_DP_C_to_T = color_c_to_t; + } + + public void setColor_DP_G_to_A(Color color_g_to_a) { + this.color_DP_G_to_A = color_g_to_a; + } + + public void setColor_DP_insertions(Color color_insertions) { + this.color_DP_insertions = color_insertions; + } + + public void setColor_DP_deletions(Color color_deletions) { + this.color_DP_deletions = color_deletions; + } + + public void setColor_DP_other(Color color_other) { + this.color_DP_other = color_other; + } + + public Color getColor_DP_C_to_T() { + return color_DP_C_to_T; + } + + public Color getColor_DP_G_to_A() { + return color_DP_G_to_A; + } + + public Color getColor_DP_insertions() { + return color_DP_insertions; + } + + public Color getColor_DP_deletions() { + return color_DP_deletions; + } + + public Color getColor_DP_other() { + return color_DP_other; + } + } diff --git a/src/main/java/IO/DOMParser.java b/src/main/java/org/damageprofiler/IO/DOMParser.java similarity index 89% rename from src/main/java/IO/DOMParser.java rename to src/main/java/org/damageprofiler/IO/DOMParser.java index 71dd54b..fc30ae0 100755 --- a/src/main/java/IO/DOMParser.java +++ b/src/main/java/org/damageprofiler/IO/DOMParser.java @@ -1,4 +1,4 @@ -package IO; +package org.damageprofiler.IO; import org.apache.log4j.Logger; import org.w3c.dom.Document; @@ -25,6 +25,13 @@ public DOMParser(Logger LOG){ this.LOG = LOG; } + + /** + * Parse file from NCBI with species information to filter species name information. + * + * @param filepathXML + * @return + */ public String parse(String filepathXML) { String species = null; diff --git a/src/main/java/IO/FastACacher.java b/src/main/java/org/damageprofiler/IO/FastACacher.java similarity index 71% rename from src/main/java/IO/FastACacher.java rename to src/main/java/org/damageprofiler/IO/FastACacher.java index 99c8929..31dfffe 100755 --- a/src/main/java/IO/FastACacher.java +++ b/src/main/java/org/damageprofiler/IO/FastACacher.java @@ -1,10 +1,9 @@ -package IO; +package org.damageprofiler.IO; import htsjdk.samtools.reference.*; import org.apache.log4j.Logger; import java.io.File; -import java.io.FileNotFoundException; import java.util.HashMap; /** @@ -12,10 +11,11 @@ */ public class FastACacher { private final Logger LOG; + private final ReferenceSequenceFile refSeq; private HashMap<String,byte[]> data = new HashMap<>(); - public FastACacher(File f, Logger LOG) throws FileNotFoundException { - ReferenceSequenceFile refSeq = ReferenceSequenceFileFactory.getReferenceSequenceFile(f); + public FastACacher(File f, Logger LOG) { + refSeq = ReferenceSequenceFileFactory.getReferenceSequenceFile(f); this.LOG = LOG; @@ -24,7 +24,6 @@ public FastACacher(File f, Logger LOG) throws FileNotFoundException { if(rs == null){ break; } else { - data.put(getKeyName(rs.getName()), rs.getBases()); } } @@ -34,6 +33,11 @@ public HashMap<String, byte[]> getData() { return data; } + public ReferenceSequence getSubSequence(String chr, int start, int end){ + ReferenceSequence subsequenceAt = refSeq.getSubsequenceAt(chr, start, end); + return subsequenceAt; + } + public String getKeyName(String reference_name){ String name=reference_name; String[] reference_name_splitted = reference_name.split("ref"); @@ -42,10 +46,7 @@ public String getKeyName(String reference_name){ name = reference_name_splitted[1].substring(1, reference_name_splitted[1].length()-1); } - return name; - - } } diff --git a/src/main/java/IO/LogClass.java b/src/main/java/org/damageprofiler/IO/LogClass.java similarity index 96% rename from src/main/java/IO/LogClass.java rename to src/main/java/org/damageprofiler/IO/LogClass.java index b657234..458dc74 100755 --- a/src/main/java/IO/LogClass.java +++ b/src/main/java/org/damageprofiler/IO/LogClass.java @@ -1,4 +1,4 @@ -package IO; +package org.damageprofiler.IO; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; diff --git a/src/main/java/org/damageprofiler/IO/MetagenomicOutput.java b/src/main/java/org/damageprofiler/IO/MetagenomicOutput.java new file mode 100644 index 0000000..5043674 --- /dev/null +++ b/src/main/java/org/damageprofiler/IO/MetagenomicOutput.java @@ -0,0 +1,98 @@ +package org.damageprofiler.IO; + +import com.itextpdf.awt.PdfGraphics2D; +import com.itextpdf.text.*; +import com.itextpdf.text.Font; +import com.itextpdf.text.pdf.PdfContentByte; +import com.itextpdf.text.pdf.PdfTemplate; +import com.itextpdf.text.pdf.PdfWriter; +import org.jfree.chart.JFreeChart; + +import java.awt.*; +import java.awt.geom.Rectangle2D; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.util.HashMap; +import java.util.List; + +public class MetagenomicOutput { + + /** + * Writes summary of the metagenomic results. Only a overview of the results is presented for + * each species. + * + * @param output_folder + * @param species_output_summary + * @param sample_name + * @param mapped_reads + * @throws FileNotFoundException + * @throws DocumentException + */ + public void generate(String output_folder, HashMap<String, List<JFreeChart>> species_output_summary, String sample_name, + HashMap<String, Integer> mapped_reads) + throws FileNotFoundException, DocumentException { + + // step 1 + Document document = new Document(PageSize.A4); + + // step 2 + PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(output_folder + File.separator + sample_name +"_summary.pdf")); + // step 3 + document.open(); + + Font fontbold = FontFactory.getFont("Times-Roman", 24, Font.BOLD); + + Paragraph para = new Paragraph(); + Chunk c_title = new Chunk("\n\n\n\nSummary of damage patterns\n\n" + sample_name, fontbold); + + Phrase p1 = new Phrase(c_title); + para.add(p1); + para.setAlignment(1); + + document.add(para); + document.addTitle("Summary_damage_patterns"); + + + + document.newPage(); + + PdfContentByte cb = writer.getDirectContent(); + float height = PageSize.A4.getHeight() * (float)0.25; + float width = PageSize.A4.getWidth() / 2; + + for(String species : species_output_summary.keySet()){ + Paragraph para2 = new Paragraph(); + Phrase p2 = new Phrase("Results for species:\n\n" + species, FontFactory.getFont("Times-Roman", 22)); + Phrase p3 = new Phrase("\n\nNumber of mapped reads:" + mapped_reads.get(species), FontFactory.getFont("Times-Roman", 18)); + para2.add(p2); + para2.add(p3); + document.add(para2); + + double xpos = 0; + for(int i = 0; i < species_output_summary.get(species).size(); i++){ + JFreeChart chart = species_output_summary.get(species).get(i); + PdfTemplate plot = cb.createTemplate(width, height); + Graphics2D g2d = new PdfGraphics2D(plot, width, height); + Rectangle2D r2d = new Rectangle2D.Double(0, 0, width, height); + chart.draw(g2d, r2d); + g2d.dispose(); + + + if(i==0){ + cb.addTemplate(plot, xpos, 500); + } else if(i==1){ + cb.addTemplate(plot, width, 500); + } else if(i==2){ + cb.addTemplate(plot, xpos, 500-height); + } else if(i==3){ + cb.addTemplate(plot, width, 500-height); + } + + } + document.newPage(); + } + // step 5 + document.close(); + } +} diff --git a/src/main/java/IO/OutputGenerator.java b/src/main/java/org/damageprofiler/IO/OutputGenerator.java similarity index 81% rename from src/main/java/IO/OutputGenerator.java rename to src/main/java/org/damageprofiler/IO/OutputGenerator.java index 32e15eb..3a9ae86 100755 --- a/src/main/java/IO/OutputGenerator.java +++ b/src/main/java/org/damageprofiler/IO/OutputGenerator.java @@ -1,7 +1,9 @@ -package IO; +package org.damageprofiler.IO; -import calculations.DamageProfiler; -import calculations.Frequencies; +import org.damageprofiler.IO.PDFoutput.Histogram; +import org.damageprofiler.IO.PDFoutput.LinePlot; +import org.damageprofiler.calculations.DamageProfiler; +import org.damageprofiler.calculations.Frequencies; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.itextpdf.awt.PdfGraphics2D; @@ -10,14 +12,19 @@ import com.itextpdf.text.pdf.PdfContentByte; import com.itextpdf.text.pdf.PdfTemplate; import com.itextpdf.text.pdf.PdfWriter; +import javafx.scene.paint.Color; import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics; import org.apache.log4j.Logger; import org.jfree.chart.JFreeChart; +import org.jfree.chart.title.LegendTitle; +import org.jfree.chart.ui.RectangleEdge; import org.jfree.data.statistics.HistogramDataset; import org.jfree.data.xy.XYDataset; - +import org.jfree.graphics2d.svg.SVGGraphics2D; +import org.jfree.graphics2d.svg.SVGUtils; import java.awt.*; +import java.awt.Rectangle; import java.io.*; import java.math.BigDecimal; import java.text.DecimalFormat; @@ -37,25 +44,44 @@ public class OutputGenerator { private final double x_axis_max_id_histo; private final double x_axis_min_length_histo; private final double x_axis_max_length_histo; + private final boolean ssLibProtocolUsed; private int numberOfUsedReads; private final double height; private final Logger LOG; private String outpath; private Frequencies frequencies; private DamageProfiler damageProfiler; - private int max_length; - private int min_length; - private String specie; + private int numberOfRecords; + private double max_length; + private double min_length; + private String species; private int threshold; private int length; private String input; private HashMap<String,Object> json_map = new HashMap<>(); + private double[] three_C_to_T_reverse; + private double[] three_G_to_A_reverse; + private JFreeChart chart_DP_5prime; + private JFreeChart chart_DP_3prime; + private JFreeChart length_chart_all; + private JFreeChart length_chart_separated; + private JFreeChart editDist_chart; + + private Color color_DP_C_to_T; + private Color color_DP_G_to_A; + private Color color_DP_insertions; + private Color color_DP_deletions; + private Color color_DP_other; + - public OutputGenerator(String outputFolder, DamageProfiler damageProfiler, String specie, int threshold, + public OutputGenerator(String outputFolder, DamageProfiler damageProfiler, String species, int threshold, int length, double height, double x_axis_min_id_histo, double x_axis_max_id_histo, - double x_axis_min_length_histo, double x_axis_max_length_histo, String input, Logger LOG) { + double x_axis_min_length_histo, double x_axis_max_length_histo, String input, Logger LOG, + int numberOfRecords, boolean ssLibProtocolUsed, Color color_DP_C_to_T, + Color color_DP_deletions, Color color_DP_G_to_A, Color color_DP_insertions, + Color color_DP_other) { this.outpath = outputFolder; this.frequencies = damageProfiler.getFrequencies(); @@ -70,10 +96,18 @@ public OutputGenerator(String outputFolder, DamageProfiler damageProfiler, Strin this.x_axis_max_length_histo = x_axis_max_length_histo; this.input = input; this.LOG = LOG; + this.numberOfRecords = numberOfRecords; + this.ssLibProtocolUsed = ssLibProtocolUsed; + + this.color_DP_C_to_T = color_DP_C_to_T; + this.color_DP_deletions = color_DP_deletions; + this.color_DP_G_to_A = color_DP_G_to_A; + this.color_DP_other = color_DP_other; + this.color_DP_insertions = color_DP_insertions; // set tax id if specified by user - if(specie != null && !specie.equals("")){ - this.specie = specie; + if(species != null && !species.equals("")){ + this.species = species; } } @@ -117,10 +151,10 @@ public void writeJSON(String version) throws IOException { public void writeLengthDistribution() throws IOException{ BufferedWriter lgdist = new BufferedWriter(new FileWriter(this.outpath + "/lgdistribution.txt")); - HashMap<Integer, Integer> map_forward = damageProfiler.getLength_distribution_map_forward(); - HashMap<Integer, Integer> map_reverse = damageProfiler.getLength_distribution_map_reverse(); + HashMap<Double, Integer> map_forward = damageProfiler.getLength_distribution_map_forward(); + HashMap<Double, Integer> map_reverse = damageProfiler.getLength_distribution_map_reverse(); - lgdist.write("# table produced by calculations.DamageProfiler\n"); + lgdist.write("# table produced by org.damageprofiler.calculations.DamageProfiler\n"); lgdist.write("# using mapped file " + input + "\n"); lgdist.write("# Sample ID: " + input.split("/")[input.split("/").length-1] + "\n"); lgdist.write("# Std: strand of reads\n"); @@ -128,17 +162,17 @@ public void writeLengthDistribution() throws IOException{ // fill file - List<Integer> key_list = new ArrayList<>(); + List<Double> key_list = new ArrayList<>(); key_list.addAll(map_forward.keySet()); Collections.sort(key_list); - HashMap<Integer,Integer> yaml_dump_fw = new HashMap<>(); + HashMap<Double,Integer> yaml_dump_fw = new HashMap<>(); if(key_list.size()>0){ min_length = key_list.get(0); max_length = key_list.get(key_list.size()-1); - for(int key : key_list){ + for(double key : key_list){ lgdist.write("+\t" + key + "\t" + map_forward.get(key) + "\n"); yaml_dump_fw.put(key, map_forward.get(key)); } @@ -149,7 +183,7 @@ public void writeLengthDistribution() throws IOException{ key_list.addAll(map_reverse.keySet()); Collections.sort(key_list); - HashMap<Integer,Integer> yaml_dump_rv = new HashMap<>(); + HashMap<Double,Integer> yaml_dump_rv = new HashMap<>(); if(key_list.size()>0){ @@ -160,7 +194,7 @@ public void writeLengthDistribution() throws IOException{ max_length = key_list.get(key_list.size()-1); } - for(int key : key_list){ + for(double key : key_list){ lgdist.write("-\t" + key + "\t" + map_reverse.get(key) + "\n"); yaml_dump_rv.put(key, map_reverse.get(key)); } @@ -176,7 +210,7 @@ public void writeDNAcomp_genome(Frequencies frequencies) throws IOException{ BufferedWriter file_dna_comp = new BufferedWriter(new FileWriter(outpath + File.separator + "DNA_comp_genome.txt")); - file_dna_comp.write("# table produced by calculations.DamageProfiler\n"); + file_dna_comp.write("# table produced by org.damageprofiler.calculations.DamageProfiler\n"); file_dna_comp.write("# using mapped file " + input + "\n"); file_dna_comp.write("# Sample ID: " + input.split("/")[input.split("/").length-1] + "\n"); file_dna_comp.write("DNA base frequencies Sample\n"); @@ -224,7 +258,7 @@ public void writeDNAComp(Frequencies frequencies) throws IOException{ */ - freq_file_sample.write("# table produced by calculations.DamageProfiler\n"); + freq_file_sample.write("# table produced by org.damageprofiler.calculations.DamageProfiler\n"); freq_file_sample.write("# using mapped file " + input + "\n"); freq_file_sample.write("# Sample ID: " + input.split("/")[input.split("/").length-1] + "\n"); @@ -252,7 +286,6 @@ public void writeDNAComp(Frequencies frequencies) throws IOException{ +(int)frequencies.getCountG_reverse_3()[i]+"\t"+(int)frequencies.getCountT_reverse_3()[i]+"\t" +(int)sum+"\n" ); - } @@ -286,7 +319,7 @@ public void writeFrequenciesReference(Frequencies frequencies) throws IOExceptio BufferedWriter freq_file_ref = new BufferedWriter(new FileWriter(outpath + File.separator + "misincorporation.txt")); - freq_file_ref.write("# table produced by calculations.DamageProfiler\n"); + freq_file_ref.write("# table produced by org.damageprofiler.calculations.DamageProfiler\n"); freq_file_ref.write("# using mapped file " + input + "\n"); freq_file_ref.write("# Sample ID: " + input.split("/")[input.split("/").length-1] + "\n"); @@ -360,6 +393,7 @@ public void writeFrequenciesReference(Frequencies frequencies) throws IOExceptio } + // fill '5p +' for(int i = 0; i < this.length; i++){ double sum = frequencies.getCountA_ref_forward_5()[i]+frequencies.getCountC_ref_forward_5()[i]+ @@ -434,8 +468,8 @@ public void plotLengthHistogram(List<Double> length_all, List<Double> length_for Histogram hist_all = new Histogram(LOG); hist_all.addData(length_all); HistogramDataset dataset_all = hist_all.createDataset(new String[]{"all reads"}, max_length); - JFreeChart chart_all = hist_all.createChart(dataset_all, "Read length distribution", "Read length", - "Occurrences", x_axis_min_length_histo, x_axis_max_length_histo); + length_chart_all = hist_all.createChart(dataset_all, "", "Read length", + "Occurrences", x_axis_min_length_histo, x_axis_max_length_histo, false); Histogram hist_separated = new Histogram(LOG); if(length_forward.size()>0){ @@ -445,10 +479,15 @@ public void plotLengthHistogram(List<Double> length_all, List<Double> length_for hist_separated.addData(length_reverse); } HistogramDataset dataset_separated = hist_separated.createDataset(new String[]{"+ strand", "- strand"}, max_length); - JFreeChart chart_separated = hist_separated.createChart(dataset_separated, "Read length distribution", - "Read length", "Occurrences", x_axis_min_length_histo, x_axis_max_length_histo); + length_chart_separated = hist_separated.createChart(dataset_separated, "", + "Read length", "Occurrences", x_axis_min_length_histo, x_axis_max_length_histo, true); + + LegendTitle lt = length_chart_separated.getLegend(); + lt.setPosition(RectangleEdge.RIGHT); - createPdf("/Length_plot.pdf", new JFreeChart[]{chart_all, chart_separated}, file); + createPdf("/Length_plot.pdf", new JFreeChart[]{length_chart_all, length_chart_separated}, file); + createSVG("/Length_plot_combined_data.svg", length_chart_all); + createSVG("/Length_plot_forward_reverse_separated.svg", length_chart_separated); } @@ -462,16 +501,20 @@ public void plotLengthHistogram(List<Double> length_all, List<Double> length_for * @throws DocumentException * @throws IOException */ - public void plotIdentitiyHistogram(ArrayList distances, String title, String file) throws DocumentException, IOException{ + public void plotEditDistanceHistogram(List<Double> distances, String title, String file) throws DocumentException, IOException{ Histogram hist_all = new Histogram(LOG); hist_all.addData(distances); + HistogramDataset dataset = hist_all.createDataset(new String[]{title}, 100); - JFreeChart chart_all = hist_all.createChart(dataset, "Read identity distribution", "Identity", "Occurrences", - x_axis_min_id_histo, x_axis_max_id_histo); - createPdf("/identity_histogram.pdf", new JFreeChart[]{chart_all}, file); + editDist_chart = hist_all.createChart(dataset, "", "Edit distance", "Occurrences", + x_axis_min_id_histo, x_axis_max_id_histo, false); + + createPdf("/edit_distance.pdf", new JFreeChart[]{editDist_chart}, file); + createSVG("/edit_distance.svg", editDist_chart); } + /** * write percentage of misincorporations per read position * @@ -481,28 +524,30 @@ public void plotIdentitiyHistogram(ArrayList distances, String title, String fil */ public void writeDamageFiles(double[] gToA_reverse, double[] cToT) throws IOException{ + BufferedWriter writer3Prime; + - BufferedWriter writer3Prime = new BufferedWriter(new FileWriter(this.outpath + "/3pGtoA_freq.txt")); BufferedWriter writer5Prime = new BufferedWriter(new FileWriter(this.outpath + "/5pCtoT_freq.txt")); //Add stuff to json output file json_map.put("dmg_5p",getSubArray(cToT, this.threshold)); + + // 3p end always included in json file, as it's needed for EAGER2.0 report json_map.put("dmg_3p",getSubArray(gToA_reverse,this.threshold)); - writer3Prime.write("# table produced by calculations.DamageProfiler\n"); + writer3Prime = new BufferedWriter(new FileWriter(this.outpath + "/3pGtoA_freq.txt")); + writer3Prime.write("# table produced by DamageProfiler\n"); writer3Prime.write("# using mapped file " + input + "\n"); writer3Prime.write("# Sample ID: " + input.split("/")[input.split("/").length-1] + "\n"); + writeDamagePattern("pos\t3pG>A\n", getSubArray(gToA_reverse, this.threshold), writer3Prime); + writer3Prime.close(); - writer5Prime.write("# table produced by calculations.DamageProfiler\n"); + writer5Prime.write("# table produced by DamageProfiler\n"); writer5Prime.write("# using mapped file " + input + "\n"); writer5Prime.write("# Sample ID: " + input.split("/")[input.split("/").length-1] + "\n"); - writeDamagePattern("pos\t5pC>T\n", getSubArray(cToT, this.threshold), writer5Prime); - writeDamagePattern("pos\t3pG>A\n", getSubArray(gToA_reverse, this.threshold), writer3Prime); - - writer3Prime.close(); writer5Prime.close(); } @@ -523,20 +568,20 @@ private void writeDamagePattern(String title, double[] values, BufferedWriter wr } public void computeSummaryMetrics(){ - HashMap<Integer,Integer> forwardMap = damageProfiler.getLength_distribution_map_forward(); // key = length, value = occurences - HashMap<Integer, Integer>reverseMap = damageProfiler.getLength_distribution_map_reverse(); + HashMap<Double,Integer> forwardMap = damageProfiler.getLength_distribution_map_forward(); // key = length, value = occurrences + HashMap<Double, Integer>reverseMap = damageProfiler.getLength_distribution_map_reverse(); //Create ArrayList<Integer> of read lengths DescriptiveStatistics descriptiveStatistics = new DescriptiveStatistics(); - for (int key : forwardMap.keySet()){ + for (double key : forwardMap.keySet()){ int occurences = forwardMap.get(key); for (int i = 0; i <= occurences; i++) { descriptiveStatistics.addValue(key); } } - for (int key : reverseMap.keySet()){ + for (double key : reverseMap.keySet()){ int occurences = reverseMap.get(key); for (int i = 0; i <= occurences; i++) { descriptiveStatistics.addValue(key); @@ -564,17 +609,11 @@ public void writeMisincorporations(Frequencies frequencies, int threshold) throw Locale.setDefault(Locale.US); BufferedWriter writer5PrimeAll = new BufferedWriter(new FileWriter(this.outpath + "/5p_freq_misincorporations.txt")); - BufferedWriter writer3PrimeAll = new BufferedWriter(new FileWriter(this.outpath + "/3p_freq_misincorporations.txt")); - writer5PrimeAll.write("# table produced by calculations.DamageProfiler\n"); + writer5PrimeAll.write("# table produced by org.damageprofiler.calculations.DamageProfiler\n"); writer5PrimeAll.write("# using mapped file " + input + "\n"); writer5PrimeAll.write("# Sample ID: " + input.split("/")[input.split("/").length-1] + "\n"); - writer3PrimeAll.write("# table produced by calculations.DamageProfiler\n"); - writer3PrimeAll.write("# using mapped file " + input + "\n"); - writer3PrimeAll.write("# Sample ID: " + input.split("/")[input.split("/").length-1] + "\n"); - - /* 5 prime end @@ -629,13 +668,18 @@ public void writeMisincorporations(Frequencies frequencies, int threshold) throw String.format("%.6f",deletions_mean5[pos])+ "\n"); } - + writer5PrimeAll.close(); /* 3 prime end */ + BufferedWriter writer3PrimeAll = new BufferedWriter(new FileWriter(this.outpath + "/3p_freq_misincorporations.txt")); + writer3PrimeAll.write("# table produced by DamageProfiler\n"); + writer3PrimeAll.write("# using mapped file " + input + "\n"); + writer3PrimeAll.write("# Sample ID: " + input.split("/")[input.split("/").length-1] + "\n"); + double[] three_A_to_C_reverse = getSubArray(frequencies.getCount_A_C_3_norm(),threshold); double[] three_A_to_G_reverse = getSubArray(frequencies.getCount_A_G_3_norm(),threshold); @@ -653,21 +697,6 @@ public void writeMisincorporations(Frequencies frequencies, int threshold) throw double[] three_T_to_C_reverse = getSubArray(frequencies.getCount_T_C_3_norm(),threshold); double[] three_T_to_G_reverse = getSubArray(frequencies.getCount_T_G_3_norm(),threshold); -// three_A_to_C_reverse = reverseArray(three_A_to_C_reverse); -// three_A_to_G_reverse = reverseArray(three_A_to_G_reverse); -// three_A_to_T_reverse = reverseArray(three_A_to_T_reverse); -// -// three_C_to_A_reverse = reverseArray(three_C_to_A_reverse); -// three_C_to_G_reverse = reverseArray(three_C_to_G_reverse); -// three_C_to_T_reverse = reverseArray(three_C_to_T_reverse); -// -// three_G_to_A_reverse = reverseArray(three_G_to_A_reverse); -// three_G_to_C_reverse = reverseArray(three_G_to_C_reverse); -// three_G_to_T_reverse = reverseArray(three_G_to_T_reverse); -// -// three_T_to_A_reverse = reverseArray(three_T_to_A_reverse); -// three_T_to_C_reverse = reverseArray(three_T_to_C_reverse); -// three_T_to_G_reverse = reverseArray(three_T_to_G_reverse); double[] insertions_mean_3 = getMean(frequencies.getCount_0_A_3_norm(),frequencies.getCount_0_C_3_norm(), @@ -701,12 +730,32 @@ public void writeMisincorporations(Frequencies frequencies, int threshold) throw } writer3PrimeAll.close(); - writer5PrimeAll.close(); + + } + public void writeEditDistance(List<Double> editDistances) throws IOException { + Collections.sort(editDistances); + Set<Double> distances_sorted = new HashSet<Double>(editDistances); + HashMap<Double, Integer> edit_occurrences_map = new HashMap<>(); + for(double dist : distances_sorted){ + int occurrences = Collections.frequency(editDistances, dist); + edit_occurrences_map.put(dist, occurrences); + + } + + BufferedWriter writerEditDistance = new BufferedWriter(new FileWriter(this.outpath + "/editDistance.txt")); + writerEditDistance.write("#Edit distances for file:" + input + "\n"); + writerEditDistance.write("Edit distance\tOccurrences\n"); + + for(double dist : edit_occurrences_map.keySet()) + writerEditDistance.write(dist + "\t" + edit_occurrences_map.get(dist) + "\n"); + + writerEditDistance.close(); + } /** * create damage plot @@ -724,9 +773,9 @@ public void plotMisincorporations(String file) throws IOException, DocumentExcep double[] three_C_to_A_reverse = getSubArray(frequencies.getCount_C_A_3_norm(), threshold); double[] three_C_to_G_reverse = getSubArray(frequencies.getCount_C_G_3_norm(), threshold); - double[] three_C_to_T_reverse = getSubArray(frequencies.getCount_C_T_3_norm(), threshold); + three_C_to_T_reverse = getSubArray(frequencies.getCount_C_T_3_norm(), threshold); - double[] three_G_to_A_reverse = getSubArray(frequencies.getCount_G_A_3_norm(),threshold); + three_G_to_A_reverse = getSubArray(frequencies.getCount_G_A_3_norm(),threshold); double[] three_G_to_C_reverse = getSubArray(frequencies.getCount_G_C_3_norm(),threshold); double[] three_G_to_T_reverse = getSubArray(frequencies.getCount_G_T_3_norm(),threshold); @@ -750,11 +799,45 @@ public void plotMisincorporations(String file) throws IOException, DocumentExcep three_T_to_C_reverse = reverseArray(three_T_to_C_reverse); three_T_to_G_reverse = reverseArray(three_T_to_G_reverse); - + LinePlot damagePlot_three=null; // create plots - LinePlot damagePlot_three = new LinePlot("3' end", threshold, height, LOG); - LinePlot damagePlot_five = new LinePlot("5' end", threshold, height, LOG); + damagePlot_three = new LinePlot(threshold, height, LOG, color_DP_C_to_T, color_DP_G_to_A, + color_DP_insertions, color_DP_deletions, color_DP_other); + + // three prime end + // red + damagePlot_three.addData(three_C_to_T_reverse, "3'C>T"); + // blue + damagePlot_three.addData(three_G_to_A_reverse, "3'G>A"); + + // purple (insertions) + double[] insertions_mean_3 = getMean(frequencies.getCount_0_A_3_norm(),frequencies.getCount_0_C_3_norm(), + frequencies.getCount_0_G_3_norm(),frequencies.getCount_0_T_3_norm()); + damagePlot_three.addData(insertions_mean_3, "insertions"); + + // green (deletions) + double[] deletions_mean_3 = getMean(frequencies.getCount_A_0_3_norm(), frequencies.getCount_C_0_3_norm() , + frequencies.getCount_G_0_3_norm(), frequencies.getCount_T_0_3_norm()); + damagePlot_three.addData(deletions_mean_3, "deletions"); + + + // gray + damagePlot_three.addData(three_A_to_C_reverse, "others"); + damagePlot_three.addData(three_A_to_G_reverse, "3'A>G"); + damagePlot_three.addData(three_A_to_T_reverse, "3'A>T"); + damagePlot_three.addData(three_C_to_A_reverse, "3'C>A"); + damagePlot_three.addData(three_C_to_G_reverse, "3'C>G"); + damagePlot_three.addData(three_G_to_C_reverse, "3'G>C"); + damagePlot_three.addData(three_G_to_T_reverse, "3'G>T"); + damagePlot_three.addData(three_T_to_A_reverse, "3'T>A"); + damagePlot_three.addData(three_T_to_C_reverse, "3'T>C"); + damagePlot_three.addData(three_T_to_G_reverse, "3'T>G"); + + + + LinePlot damagePlot_five = new LinePlot(threshold, height, LOG, color_DP_C_to_T, + color_DP_G_to_A, color_DP_insertions, color_DP_deletions, color_DP_other); /* add data to plots @@ -799,48 +882,28 @@ public void plotMisincorporations(String file) throws IOException, DocumentExcep damagePlot_five.addData(frequencies.getCount_T_C_5_norm(), "5'T>C" ); damagePlot_five.addData(frequencies.getCount_T_G_5_norm(), "5'T>G" ); - // three prime end - // red - damagePlot_three.addData(three_C_to_T_reverse, "3'C>T"); - // blue - damagePlot_three.addData(three_G_to_A_reverse, "3'G>A"); - - // purple (insertions) - double[] insertions_mean_3 = getMean(frequencies.getCount_0_A_3_norm(),frequencies.getCount_0_C_3_norm(), - frequencies.getCount_0_G_3_norm(),frequencies.getCount_0_T_3_norm()); - damagePlot_three.addData(insertions_mean_3, "insertions"); - - // green (deletions) - double[] deletions_mean_3 = getMean(frequencies.getCount_A_0_3_norm(), frequencies.getCount_C_0_3_norm() , - frequencies.getCount_G_0_3_norm(), frequencies.getCount_T_0_3_norm()); - damagePlot_three.addData(deletions_mean_3, "deletions"); - - - // gray - damagePlot_three.addData(three_A_to_C_reverse, "others"); - damagePlot_three.addData(three_A_to_G_reverse, "3'A>G"); - damagePlot_three.addData(three_A_to_T_reverse, "3'A>T"); - damagePlot_three.addData(three_C_to_A_reverse, "3'C>A"); - damagePlot_three.addData(three_C_to_G_reverse, "3'C>G"); - damagePlot_three.addData(three_G_to_C_reverse, "3'G>C"); - damagePlot_three.addData(three_G_to_T_reverse, "3'G>T"); - damagePlot_three.addData(three_T_to_A_reverse, "3'T>A"); - damagePlot_three.addData(three_T_to_C_reverse, "3'T>C"); - damagePlot_three.addData(three_T_to_G_reverse, "3'T>G"); - // create Dataset - XYDataset dataset_three = damagePlot_three.createDataset(); XYDataset dataset_five = damagePlot_five.createDataset(); + double ymax; + // set equal y axis range - double ymax = Math.max(damagePlot_five.getY_max(), damagePlot_three.getY_max()); + ymax = Math.max(damagePlot_five.getY_max(), damagePlot_three.getY_max()); + + JFreeChart[] charts; // create damage plot five prime - JFreeChart chart = damagePlot_five.createChart(dataset_five, ymax, threshold); + chart_DP_5prime = damagePlot_five.createChart("5' end", dataset_five, ymax, threshold, ssLibProtocolUsed); + XYDataset dataset_three = damagePlot_three.createDataset(); // create damage plot three prime - JFreeChart chart1 = damagePlot_three.createChart(dataset_three, ymax, threshold); + chart_DP_3prime = damagePlot_three.createChart("3' end", dataset_three, ymax, threshold, ssLibProtocolUsed); + charts = new JFreeChart[]{chart_DP_5prime, chart_DP_3prime}; + createSVG("/DamagePlot_three_prime.svg", chart_DP_3prime); + + + createPdf("/DamagePlot.pdf", charts, file); + createSVG("/DamagePlot_five_prime.svg", chart_DP_5prime); - createPdf("/DamagePlot.pdf", new JFreeChart[]{chart, chart1}, file); } @@ -900,6 +963,24 @@ private double[] getSubArray(double[] array, int n){ } + /** + * Save images sc svg. This is only possible when using JFreeChart library. + * @param filename + * @param chart + * @throws IOException + */ + public void createSVG(String filename, JFreeChart chart) throws IOException { + + int height = (int)(PageSize.A4.getWidth() * (float)0.8); + int width = (int)(PageSize.A4.getHeight() / 2); + + SVGGraphics2D g2 = new SVGGraphics2D(width, height); + Rectangle r = new Rectangle(0, 0, width, height); + chart.draw(g2, r); + File f = new File(outpath + "/" + filename); + SVGUtils.writeToSVG(f, g2.getSVGElement()); + + } /** * Creates a PDF document. * @@ -918,15 +999,22 @@ public void createPdf(String filename, JFreeChart[] charts, String file) throws document.open(); // compute percentage of used reads - double ratio_used_reads = damageProfiler.getNumberOfUsedReads() / (double) damageProfiler.getNumberOfAllReads(); + double ratio_used_reads = damageProfiler.getNumberOfUsedReads() / (double)numberOfRecords; // draw text String[] splitted = file.split("/"); String title = splitted[splitted.length-1]; NumberFormat nf = NumberFormat.getNumberInstance(Locale.ENGLISH); DecimalFormat df = (DecimalFormat)nf; - String read_per = Chunk.NEWLINE + "Number of used reads: " + df.format(damageProfiler.getNumberOfUsedReads()) + " (" + - (double)(Math.round(ratio_used_reads*10000))/100 + "% of all input reads) | Specie: " + this.specie; + + String read_per; + if(this.species == null){ + read_per = Chunk.NEWLINE + "Number of used reads: " + df.format(damageProfiler.getNumberOfUsedReads()) + " (" + + (double)(Math.round(ratio_used_reads*10000))/100 + "% of all input reads)"; + } else{ + read_per = Chunk.NEWLINE + "Number of used reads: " + df.format(damageProfiler.getNumberOfUsedReads()) + " (" + + (double)(Math.round(ratio_used_reads*10000))/100 + "% of all input reads) | Species: " + this.species; + } Font fontbold = FontFactory.getFont("Times-Roman", 18, Font.BOLD); Font font = FontFactory.getFont("Times-Roman", 14); @@ -963,4 +1051,35 @@ public void createPdf(String filename, JFreeChart[] charts, String file) throws } + /* + Getter + */ + public JFreeChart[] getDP_chart() { + if(chart_DP_3prime!=null){ + return new JFreeChart[]{chart_DP_5prime, chart_DP_3prime}; + } else { + return new JFreeChart[]{chart_DP_5prime}; + } + } + + public JFreeChart[] getLengthDistPlots() { + return new JFreeChart[]{length_chart_all, length_chart_separated}; + + } + public JFreeChart getEditDist_chart() { + return editDist_chart; + } + + public JFreeChart getChart_DP_5prime() { + return chart_DP_5prime; + } + + public JFreeChart getChart_DP_3prime() { + return chart_DP_3prime; + } + + public JFreeChart getLength_chart_all() { + return length_chart_all; + } + } diff --git a/src/main/java/IO/Histogram.java b/src/main/java/org/damageprofiler/IO/PDFoutput/Histogram.java similarity index 83% rename from src/main/java/IO/Histogram.java rename to src/main/java/org/damageprofiler/IO/PDFoutput/Histogram.java index c36cf7c..7e4079e 100755 --- a/src/main/java/IO/Histogram.java +++ b/src/main/java/org/damageprofiler/IO/PDFoutput/Histogram.java @@ -1,4 +1,4 @@ -package IO; +package org.damageprofiler.IO.PDFoutput; import org.apache.log4j.Logger; import org.jfree.chart.ChartFactory; @@ -6,8 +6,8 @@ import org.jfree.chart.axis.ValueAxis; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.XYPlot; -import org.jfree.chart.renderer.xy.StandardXYBarPainter; import org.jfree.chart.renderer.xy.XYBarRenderer; +import org.jfree.chart.renderer.xy.XYItemRenderer; import org.jfree.data.statistics.HistogramDataset; import org.jfree.data.statistics.HistogramType; @@ -36,17 +36,16 @@ public void addData(List<Double> data){ for(int i = 0; i < data.size(); i++){ d[i] = data.get(i); } - data_collected.add(d); } - public HistogramDataset createDataset(String[] title, int max){ + public HistogramDataset createDataset(String[] title, double max){ HistogramDataset dataset = new HistogramDataset(); dataset.setType(HistogramType.FREQUENCY); - int bin = max; + int bin = (int) max; for(int i = 0; i < data_collected.size(); i++){ dataset.addSeries(title[i], data_collected.get(i), bin); @@ -58,26 +57,26 @@ public HistogramDataset createDataset(String[] title, int max){ public JFreeChart createChart(HistogramDataset dataset, String title, String xlab, String ylab, - double xmin, double xmax){ + double xmin, double xmax, boolean legend){ JFreeChart chart = ChartFactory.createHistogram( - title,//"Histogram read length", + title,//"Histogram edit distance", xlab, //"Read length", ylab, // "Occurrences", dataset, PlotOrientation.VERTICAL, - true, + legend, false, false ); - chart.setBackgroundPaint(new Color(230,230,230)); XYPlot xyplot = (XYPlot)chart.getPlot(); xyplot.setForegroundAlpha(0.7F); xyplot.setBackgroundPaint(Color.WHITE); xyplot.setDomainGridlinePaint(new Color(150,150,150)); xyplot.setRangeGridlinePaint(new Color(150,150,150)); + if(xmin > -1){ ValueAxis axis = xyplot.getDomainAxis(); axis.setLowerBound(xmin); @@ -90,8 +89,6 @@ public JFreeChart createChart(HistogramDataset dataset, String title, String xla XYBarRenderer xybarrenderer = (XYBarRenderer)xyplot.getRenderer(); xybarrenderer.setShadowVisible(false); - xybarrenderer.setBarPainter(new StandardXYBarPainter()); - xybarrenderer.setMargin(0.2); return chart; diff --git a/src/main/java/IO/LinePlot.java b/src/main/java/org/damageprofiler/IO/PDFoutput/LinePlot.java similarity index 66% rename from src/main/java/IO/LinePlot.java rename to src/main/java/org/damageprofiler/IO/PDFoutput/LinePlot.java index 89caf7f..5ac4db7 100755 --- a/src/main/java/IO/LinePlot.java +++ b/src/main/java/org/damageprofiler/IO/PDFoutput/LinePlot.java @@ -1,4 +1,4 @@ -package IO; +package org.damageprofiler.IO.PDFoutput; import org.apache.log4j.Logger; import org.jfree.chart.ChartFactory; @@ -27,17 +27,44 @@ public class LinePlot { private double y_max=0.0; private double y_min=0.0; private ArrayList<XYSeries> all_data; - private String title; private int threshold; + private Color awtColor_DP_C_to_T; + private Color awtColor_DP_G_to_A; + private Color awtColor_DP_insertions; + private Color awtColor_DP_deletions; + private Color awtColor_DP_other; - public LinePlot(String title, int threshold, double height, Logger LOG) { + + public LinePlot(int threshold, double height, Logger LOG, javafx.scene.paint.Color color_DP_C_to_T, + javafx.scene.paint.Color color_DP_G_to_A, javafx.scene.paint.Color color_DP_insertions, + javafx.scene.paint.Color color_DP_deletions, javafx.scene.paint.Color color_DP_other) { this.LOG = LOG; all_data = new ArrayList<>(); - this.title = title; this.threshold = threshold; this.height = height; + awtColor_DP_C_to_T = new java.awt.Color((float) color_DP_C_to_T.getRed(), + (float) color_DP_C_to_T.getGreen(), + (float) color_DP_C_to_T.getBlue(), + (float) color_DP_C_to_T.getOpacity()); + awtColor_DP_G_to_A = new java.awt.Color((float) color_DP_G_to_A.getRed(), + (float) color_DP_G_to_A.getGreen(), + (float) color_DP_G_to_A.getBlue(), + (float) color_DP_G_to_A.getOpacity()); + awtColor_DP_insertions = new java.awt.Color((float) color_DP_insertions.getRed(), + (float) color_DP_insertions.getGreen(), + (float) color_DP_insertions.getBlue(), + (float) color_DP_insertions.getOpacity()); + awtColor_DP_deletions = new java.awt.Color((float) color_DP_deletions.getRed(), + (float) color_DP_deletions.getGreen(), + (float) color_DP_deletions.getBlue(), + (float) color_DP_deletions.getOpacity()); + awtColor_DP_other = new java.awt.Color((float) color_DP_other.getRed(), + (float) color_DP_other.getGreen(), + (float) color_DP_other.getBlue(), + (float) color_DP_other.getOpacity()); + } @@ -51,7 +78,7 @@ public void addData(double[] data, String name){ final XYSeries series = new XYSeries(name); for(int i = 0; i < threshold; i++){ - series.add((double)i, data[i]); + series.add(i, data[i]); } all_data.add(series); @@ -71,7 +98,6 @@ public XYDataset createDataset() { for(XYSeries series : all_data){ dataset.addSeries(series); if(series.getMaxY() > y_max){y_max=series.getMaxY();} - //if(series.getMinY() < y_min){y_min=series.getMinY();} } y_min = 0.0; @@ -88,9 +114,10 @@ public XYDataset createDataset() { * Creates a chart. * * @param dataset the data for the chart. + * @param ssLibProtocolUsed * @return a chart. */ - public JFreeChart createChart(final XYDataset dataset, double yMax, int threshold) { + public JFreeChart createChart(String title, final XYDataset dataset, double yMax, int threshold, boolean ssLibProtocolUsed) { // create the chart... final JFreeChart chart = ChartFactory.createXYLineChart( @@ -127,26 +154,27 @@ public JFreeChart createChart(final XYDataset dataset, double yMax, int threshol legendItemsNew.add(legendItemsOld.get(3)); legendItemsNew.add(legendItemsOld.get(4)); - legendItemsNew.get(0).setLinePaint(Color.RED); - legendItemsNew.get(1).setLinePaint(Color.BLUE); - legendItemsNew.get(2).setLinePaint(new Color(255, 0, 255)); - legendItemsNew.get(3).setLinePaint(Color.GREEN); - legendItemsNew.get(4).setLinePaint(Color.GRAY); + legendItemsNew.get(0).setLinePaint(this.awtColor_DP_C_to_T); + legendItemsNew.get(1).setLinePaint(this.awtColor_DP_G_to_A); + legendItemsNew.get(2).setLinePaint(this.awtColor_DP_insertions); + legendItemsNew.get(3).setLinePaint(this.awtColor_DP_deletions); + legendItemsNew.get(4).setLinePaint(this.awtColor_DP_other); renderer.setSeriesStroke(0, new BasicStroke(3.0f)); - renderer.setSeriesStroke(1, new BasicStroke(3.0f)); + if(!ssLibProtocolUsed) + renderer.setSeriesStroke(1, new BasicStroke(3.0f)); renderer.setAutoPopulateSeriesStroke(false); plot.setFixedLegendItems(legendItemsNew); // set colour of line - renderer.setSeriesPaint(0, Color.RED); - renderer.setSeriesPaint(1, Color.BLUE); - renderer.setSeriesPaint(2, new Color(255, 0, 255)); - renderer.setSeriesPaint(3, Color.GREEN); - renderer.setSeriesPaint(4, Color.GRAY); + renderer.setSeriesPaint(0, this.awtColor_DP_C_to_T); + renderer.setSeriesPaint(1, this.awtColor_DP_G_to_A); + renderer.setSeriesPaint(2, this.awtColor_DP_insertions); + renderer.setSeriesPaint(3, this.awtColor_DP_deletions); + renderer.setSeriesPaint(4, this.awtColor_DP_other); for(int i=5; i < all_data.size(); i++){ - renderer.setSeriesPaint(i, Color.GRAY); + renderer.setSeriesPaint(i, this.awtColor_DP_other); } plot.setRenderer(renderer); @@ -172,13 +200,13 @@ public JFreeChart createChart(final XYDataset dataset, double yMax, int threshol } - switch (this.title){ + switch (title){ case ("3' end"): String[] axis_three_prime = new String[threshold]; int position_three_prime=0; for(int i=threshold; i > 0; i--){ - axis_three_prime[position_three_prime] = "-" + String.valueOf(i); + axis_three_prime[position_three_prime] = "-" + i; position_three_prime++; } diff --git a/src/main/java/org/damageprofiler/IO/UserOptionsParser.java b/src/main/java/org/damageprofiler/IO/UserOptionsParser.java new file mode 100755 index 0000000..05a412a --- /dev/null +++ b/src/main/java/org/damageprofiler/IO/UserOptionsParser.java @@ -0,0 +1,224 @@ +package org.damageprofiler.IO; + +import org.apache.commons.cli.*; + + +/** + * Created by neukamm on 01.08.16. + */ +public class UserOptionsParser { + + private static final String CLASS_NAME = "User option parser"; + private final String version; + private String[] args; + private Communicator communicator; + + + public UserOptionsParser(String[] args, Communicator c, String version){ + this.args = args; + this.communicator = c; + this.version = version; + parse(); + } + + private void parse() { + + // create command line parameters + Options helpOptions = new Options(); + helpOptions.addOption("h", "help", false, "show this help page"); + + Options options = new Options(); + + options.addOption("h", false, "Shows this help page."); + + options.addOption(new Option("version", false, + "Shows the version of DamageProfiler.")); + + options.addOption(Option.builder("i") + .argName("INPUT") + .desc("The input sam/bam/cram file.") + .hasArg() + .build()); + + options.addOption(Option.builder("r") + .argName("REFERENCE") + .desc("The reference file (fasta format).") + .hasArg() + .build()); + + options.addOption(Option.builder("o") + .argName("OUTPUT") + .desc("The output folder.") + .hasArg() + .build()); + + options.addOption(Option.builder("t") + .argName("THRESHOLD") + .desc("DamagePlot: Number of bases which are considered for plotting nucleotide misincorporations. Default: 25") + .hasArg() + .build()); + + options.addOption(Option.builder("s") + .argName("SPECIES") + .desc("Reference sequence name (Reference NAME flag of SAM record). For more details see Documentation.") + .hasArg() + .build()); + + options.addOption(Option.builder("sf") + .argName("SPECIES LIST") + .desc("List with species for which damage profile has to be calculated. For more details see Documentation.") + .hasArg() + .build()); + + options.addOption(Option.builder("l") + .argName("LENGTH") + .desc("Number of bases which are considered for frequency computations. Default: 100.") + .hasArg() + .build()); + + + /* + plotting options + */ + + options.addOption(Option.builder("title") + .argName("TITLE") + .desc("Title used for all plots. Default: input filename.") + .hasArg() + .build()); + + // damage plot + + options.addOption(Option.builder("yaxis_dp_max") + .argName("MAX_VALUE") + .desc("DamagePlot: Maximal y-axis value.") + .hasArg() + .build()); + + options.addOption(Option.builder("color_c_t") + .argName("COLOR_C_T") + .desc("DamagePlot: Color for C to T misincoporation frequency.") + .hasArg() + .build()); + + options.addOption(Option.builder("color_g_a") + .argName("COLOR_G_A") + .desc("DamagePlot: Color for G to A misincoporation frequency.") + .hasArg() + .build()); + + options.addOption(Option.builder("color_instertions") + .argName("COLOR_C_T") + .desc("DamagePlot: Color for base insertions.") + .hasArg() + .build()); + + options.addOption(Option.builder("color_deletions") + .argName("COLOR_DELETIONS") + .desc("DamagePlot: Color for base deletions.") + .hasArg() + .build()); + + options.addOption(Option.builder("color_other") + .argName("COLOR_OTHER") + .desc("DamagePlot: Color for other bases different to reference.") + .hasArg() + .build()); + + + // others + + options.addOption(Option.builder("only_merged") + .desc("Use only mapped and merged (in case of paired-end sequencing) reads to calculate damage plot " + + "instead of using all mapped reads. The SAM/BAM entry must start with 'M_', otherwise " + + "it will be skipped. Default: false ") + .build()); + + options.addOption(Option.builder("sslib") + .desc("Single-stranded library protocol was used. Default: false") + .build()); + + String header = "\nDetailed description:\n\n"; + + HelpFormatter formatter = new HelpFormatter(); + formatter.setOptionComparator(null); + formatter.setWidth(130); + CommandLineParser parser = new BasicParser(); + + +// --------------------------------------------------------------------------------------- + + + try { + + CommandLine cmd = parser.parse(options, args); + + if (cmd.hasOption('h')) { + formatter.printHelp("DamageProfiler", header, options, null, true); + System.exit(0); + } + + if(cmd.hasOption("version")) { + System.out.print("DamageProfiler v" + this.version + "\n"); + System.exit(0); + } + + // input files + + if (cmd.hasOption('i')) { + communicator.setInput(cmd.getOptionValue('i')); + } + if (cmd.hasOption('r')) { + communicator.setReference(cmd.getOptionValue('r')); + } + if (cmd.hasOption('o')) { + communicator.setOutfolder(cmd.getOptionValue('o')); + } + + // damage calculation + + if (cmd.hasOption('s')) { + communicator.setSpecies_ref_identifier(cmd.getOptionValue('s')); + } + if (cmd.hasOption("sf")) { + communicator.setSpecieslist_filepath(cmd.getOptionValue("sf")); + } + if (cmd.hasOption('l')) { + communicator.setLength(Integer.parseInt(cmd.getOptionValue('l'))); + } + if(cmd.hasOption("all_mapped_and_merged_reads")) { + communicator.setUse_merged_and_mapped_reads(true); + } + + if(cmd.hasOption("use_all_reads")) { + communicator.setUse_all_reads(false); + } + + if(cmd.hasOption("sslib")) { + communicator.setSsLibsProtocolUsed(true); + } + + // Plotting + + if(cmd.hasOption("title")) { + communicator.setTitle_plots(cmd.getOptionValue("title")); + } + + if(cmd.hasOption("yaxis_dp_max")) { + communicator.setyAxis_damageplot(Double.parseDouble(cmd.getOptionValue("yaxis_dp_max"))); + } + + + if (cmd.hasOption('t')) { + communicator.setThreshold(Integer.parseInt(cmd.getOptionValue('t'))); + } + + + } catch (ParseException e) { + formatter.printHelp(CLASS_NAME, options); + System.err.println(e.getMessage()); + System.exit(1); + } + + } +} diff --git a/src/main/java/calculations/DamageProfiler.java b/src/main/java/org/damageprofiler/calculations/DamageProfiler.java similarity index 56% rename from src/main/java/calculations/DamageProfiler.java rename to src/main/java/org/damageprofiler/calculations/DamageProfiler.java index 3312e3a..15ab029 100755 --- a/src/main/java/calculations/DamageProfiler.java +++ b/src/main/java/org/damageprofiler/calculations/DamageProfiler.java @@ -1,15 +1,12 @@ -package calculations; +package org.damageprofiler.calculations; -import IO.FastACacher; +import org.damageprofiler.IO.FastACacher; import htsjdk.samtools.*; -import htsjdk.samtools.reference.IndexedFastaSequenceFile; import htsjdk.samtools.util.SequenceUtil; import org.apache.log4j.Logger; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; +import java.io.*; import java.util.*; @@ -18,29 +15,30 @@ */ public class DamageProfiler { + private final FastACacher cache; private SamReader inputSam=null; private Functions useful_functions=null; - private String specie=null; + private String species =null; private Logger LOG=null; - private IndexedFastaSequenceFile fastaSequenceFile; private int numberOfUsedReads; - private int numberOfAllReads; + private int numberOfRecords; private int threshold; private int length; private Frequencies frequencies; private File reference; - private FastACacher cache; LengthDistribution lengthDistribution; private ArrayList<Double> identity; - private SpecieHandler specieHandler; + private SpeciesHandler speciesHandler; + private List<Double> editDistances; /** * constructor - * @param specieHandler + * @param speciesHandler + * @param cache */ - public DamageProfiler(SpecieHandler specieHandler) { - this.specieHandler = specieHandler; - + public DamageProfiler(SpeciesHandler speciesHandler, FastACacher cache) { + this.speciesHandler = speciesHandler; + this.cache = cache; } /** @@ -53,18 +51,31 @@ public DamageProfiler(SpecieHandler specieHandler) { * @param LOG */ public void init(File input, File reference, int threshold, int length, String specie, Logger LOG){ - // read bam/sam file + // read bam/sam/cram file if (!input.exists()){ System.err.println("SAM/BAM file not found. Please check your file path.\nInput: " + input.getAbsolutePath()); System.exit(0); } else { try{ + if(input.getAbsolutePath().endsWith(".sam") || input.getAbsolutePath().endsWith(".bam") ) { + + inputSam = SamReaderFactory.make().enable(SamReaderFactory.Option.DONT_MEMORY_MAP_INDEX). + validationStringency(ValidationStringency.SILENT).open(input); + + } else if(input.getAbsolutePath().endsWith(".cram")){ + if(!reference.isFile()){ + System.err.println("Reference file is needed to reads CRAM files."); + System.exit(1); + } else { + inputSam = SamReaderFactory.make().enable(SamReaderFactory.Option.DONT_MEMORY_MAP_INDEX). + referenceSequence(reference).validationStringency(ValidationStringency.SILENT).open(input); + + } + } - inputSam = SamReaderFactory.make().enable(SamReaderFactory.Option.DONT_MEMORY_MAP_INDEX). - validationStringency(ValidationStringency.LENIENT).open(input); numberOfUsedReads = 0; - numberOfAllReads = 0; + numberOfRecords = 0; this.LOG = LOG; this.threshold = threshold; this.length = length; @@ -73,15 +84,16 @@ public void init(File input, File reference, int threshold, int length, String s this.lengthDistribution = new LengthDistribution(this.LOG); this.lengthDistribution.init(); this.identity = new ArrayList(); - this.specie = specie; - useful_functions = new Functions(this.LOG); + this.editDistances = new ArrayList(); + this.species = specie; + useful_functions = new Functions(); } catch (Exception e){ System.err.println("Invalid SAM/BAM file. Please check your file."); LOG.error("Invalid SAM/BAM file. Please check your file."); - System.out.println(e.toString()); - System.exit(0); + System.err.println(e.toString()); + System.exit(-1); } } } @@ -89,7 +101,7 @@ public void init(File input, File reference, int threshold, int length, String s /** * get all sam records of input sam/bam file, * distinguish between mapped and mapped/merged and normalize values - * after all calculations + * after all org.damageprofiler.calculations * * * @param use_only_merged_reads @@ -101,43 +113,34 @@ public void extractSAMRecords(boolean use_only_merged_reads, boolean use_all_rea if(use_all_reads && use_only_merged_reads){ LOG.info("-------------------"); LOG.info("0 reads processed.\nRunning not possible. 'use_only_merged_reads' and 'use_all_reads' was set to 'true'"); - System.exit(0); + System.exit(1); } else { + for(SAMRecord record : inputSam) { - if (this.specie == null) { + numberOfRecords++; - numberOfAllReads++; + if (this.species == null) { handleRecord(use_only_merged_reads, use_all_reads, record); - - // print number of processed reads - if (numberOfUsedReads % 100 == 0) { - LOG.info(numberOfUsedReads + " Reads processed."); - } - } else { - - if (record.getReferenceName().contains(this.specie)) { - numberOfAllReads++; + if (record.getReferenceName().contains(this.species)) { handleRecord(use_only_merged_reads, use_all_reads, record); - - // print number of processed reads - if (numberOfUsedReads % 100 == 0) { - LOG.info(numberOfUsedReads + " Reads processed."); - } } } } + frequencies.normalizeValues(); LOG.info("-------------------"); LOG.info("# reads used for damage calculation: " + (numberOfUsedReads )); } - } + + private void handleRecord(boolean use_only_merged_reads, boolean use_all_reads, SAMRecord record) throws Exception { + if(use_all_reads && !use_only_merged_reads){ // process all reads processRecord(record); @@ -147,12 +150,13 @@ private void handleRecord(boolean use_only_merged_reads, boolean use_all_reads, if (!record.getReadUnmappedFlag() && record.getReadName().startsWith("M_")) { processRecord(record); } - } else if(!use_only_merged_reads && !use_all_reads) + } else if(!use_only_merged_reads && !use_all_reads) { // process only mapped reads if (!record.getReadUnmappedFlag()) { // get all mapped reads processRecord(record); } + } } @@ -168,12 +172,12 @@ private void handleRecord(boolean use_only_merged_reads, boolean use_all_reads, * @throws IOException */ - private void processRecord(SAMRecord record) throws Exception{ + private void processRecord(SAMRecord record) { numberOfUsedReads++; /* If MD value is set, use it to reconstruct reference - Otherwise reconstruct reference it based on the CIGAR string + Otherwise reconstruct it based on reference. */ @@ -182,98 +186,76 @@ private void processRecord(SAMRecord record) throws Exception{ // check if record has MD tag and no reference file is specified - if(record.getStringAttribute(SAMTag.MD.name()) == null && this.reference == null){ + if(record.getStringAttribute(SAMTag.MD.name()) == null && (this.reference == null || !reference.isFile())){ - LOG.error("SAM/BAM file has no MD tag. Please specify reference file "); - System.exit(0); + LOG.error("SAM/BAM file has no MD tag. Please specify reference file which is needed for MD tag calculations."); + System.exit(1); - } else if (record.getStringAttribute(SAMTag.MD.name()) == null){ + } else { - readReferenceInCache(); - Aligner aligner = new Aligner(LOG); - // SAMRecord has 1-based coordinate system -> closed interval [..,..] - // normal Array 0-based coordinate system -> interval half-cloded-half-open [...,...) - int start = record.getAlignmentStart() - 1; - int stop = record.getAlignmentEnd(); + // MD tag needs to be calculated --> REF needs to be specified + if (record.getStringAttribute(SAMTag.MD.name()) == null){ + SequenceUtil.calculateMdAndNmTags(record, cache.getData().get(record.getReferenceName()), true, true); + } - // get reference sequence - byte[] refSeq = Arrays.copyOfRange(cache.getData().get(cache.getKeyName(record.getReferenceName())), start, stop); - String reference = new String(refSeq, "UTF-8"); - // align record and reference + try{ + byte[] ref_seq = SequenceUtil.makeReferenceFromAlignment(record, false); + reference_aligned = new String(ref_seq, "UTF-8"); + record_aligned = record.getReadString(); + proceed(record, record_aligned, reference_aligned); - if (record.getReadLength() != reference.length()) { - String[] record_reference = aligner.align(record.getReadString(), reference, record); - reference_aligned = record_reference[1]; - record_aligned = record_reference[0]; + } catch (Exception e){ - } else { - reference_aligned = record.getReadString(); - record_aligned = record.getReadString(); - } + System.err.println(record.getReadName() + "\nMD and NM value will be re-calculated. Error: \n" + e); + if(!reference.isFile()){ + System.err.println("No MD tag defined. Please specify reference file which is needed for MD tag org.damageprofiler.calculations."); + System.exit(1); + } - } else if(record.getStringAttribute(SAMTag.MD.name()) != null){ - // get reference corresponding to the record - if(record.getCigar().getReadLength() != 0 && record.getCigar().getReadLength() == record.getReadLength()){ -// if(record.getCigarString().contains("S")){ -// System.out.println("Cigar contains soft clipping"); -// } else if(record.getCigarString().contains("D")){ -// System.out.println("Cigar contains deletion"); -// } else { + try{ + SequenceUtil.calculateMdAndNmTags(record, cache.getData().get(record.getReferenceName()), true, true); byte[] ref_seq = SequenceUtil.makeReferenceFromAlignment(record, false); reference_aligned = new String(ref_seq, "UTF-8"); record_aligned = record.getReadString(); - // } + proceed(record, record_aligned, reference_aligned); + System.err.println("Re-calculation was successful!\n"); - - - } else { - LOG.info("Skipped record (length does not match): " + record.getReadName()); + } catch (Exception e1){ + System.err.println("Re-calculation failed. Record " + record.getReadName() + " will be skipped.\n"); + } } - } + } + private void proceed(SAMRecord record, String record_aligned, String reference_aligned) throws Exception { // report length distribution this.lengthDistribution.fillDistributionTable(record,record_aligned); - int hamming = useful_functions.getHammingDistance(record_aligned, reference_aligned); + + // calculate distance between record and reference + double hamming = useful_functions.getHammingDistance(record_aligned, reference_aligned); + double id = (double)(record_aligned.length()-hamming) / (double)record_aligned.length(); this.identity.add(id); + this.editDistances.add(hamming); // calculate frequencies frequencies.count(record, record_aligned, reference_aligned); - frequencies.calculateMisincorporations(record, record_aligned, reference_aligned); - - - } - - /** - * index reference file and put it in cache to get faster - * access - * - * @throws FileNotFoundException - */ - - private void readReferenceInCache() throws FileNotFoundException{ - // read reference file as indexed reference - fastaSequenceFile = new IndexedFastaSequenceFile(reference); - // store reference in cache to get faster access - cache = new FastACacher(reference, LOG); + // calculate base misincorporations + frequencies.calculateMisincorporations(record, record_aligned, reference_aligned); } - - /* * Getter */ - public Frequencies getFrequencies() { return frequencies; } - public HashMap<Integer, Integer> getLength_distribution_map_forward() {return lengthDistribution.getLength_distribution_map_forward(); } - public HashMap<Integer, Integer> getLength_distribution_map_reverse() {return lengthDistribution.getLength_distribution_map_reverse(); } + public HashMap<Double, Integer> getLength_distribution_map_forward() {return lengthDistribution.getLength_distribution_map_forward(); } + public HashMap<Double, Integer> getLength_distribution_map_reverse() {return lengthDistribution.getLength_distribution_map_reverse(); } public List<Double> getLength_forward() { return lengthDistribution.getLength_forward(); } @@ -284,25 +266,32 @@ public List<Double> getLength_all() { public int getNumberOfUsedReads() { return numberOfUsedReads; } - public int getNumberOfAllReads() { - return numberOfAllReads; - } - public ArrayList<Double> getIdentity() { return identity; } + /** + * Determines the name of the species based on the NCBI ref ID. + * + * @param file + * @param ref + * @return + */ public String getSpeciesname(File file, String ref) { SamReader input = SamReaderFactory.make().enable(SamReaderFactory.Option.DONT_MEMORY_MAP_INDEX). - validationStringency(ValidationStringency.LENIENT).open(file); + validationStringency(ValidationStringency.SILENT).open(file); for(SAMRecord record : input) { if(record.getReferenceName().contains(ref)){ - specieHandler.getSpecie(record.getReferenceName()); - String spe = specieHandler.getSpecie_name(); + String spe = speciesHandler.getSpecies(record.getReferenceName()); return spe.replace(" ", "_").trim(); } } return null; } - + public int getNumberOfRecords() { + return numberOfRecords; + } + public List<Double> getEditDistances() { + return editDistances; + } } diff --git a/src/main/java/calculations/Frequencies.java b/src/main/java/org/damageprofiler/calculations/Frequencies.java similarity index 99% rename from src/main/java/calculations/Frequencies.java rename to src/main/java/org/damageprofiler/calculations/Frequencies.java index ba08833..3858bb6 100755 --- a/src/main/java/calculations/Frequencies.java +++ b/src/main/java/org/damageprofiler/calculations/Frequencies.java @@ -1,10 +1,7 @@ -package calculations; +package org.damageprofiler.calculations; import htsjdk.samtools.SAMRecord; import htsjdk.samtools.util.SequenceUtil; import org.apache.log4j.Logger; - -import java.util.LinkedList; -import java.util.List; import java.util.stream.IntStream; /** @@ -601,7 +598,14 @@ public void count(SAMRecord record, String record_aligned, String ref_aligned){ countG_ref_forward_3, countT_ref_forward_3, count0_ref_forward_3, null); } + } + /** + * Count purine bases + * @param ref_left bases left of record + * @param ref_right bases right of record + */ + public void countRecordFlankingRegions(String ref_left, String ref_right) { } @@ -693,7 +697,6 @@ public void calculateMisincorporations(SAMRecord record, String record_aligned, * compare each position in aligned record with reference to get misincorporations * @param seq * @param ref - * @param mis_positions * @param a_c * @param a_g * @param a_t diff --git a/src/main/java/org/damageprofiler/calculations/Functions.java b/src/main/java/org/damageprofiler/calculations/Functions.java new file mode 100755 index 0000000..c3ee1ad --- /dev/null +++ b/src/main/java/org/damageprofiler/calculations/Functions.java @@ -0,0 +1,22 @@ +package org.damageprofiler.calculations; + +import org.apache.commons.text.similarity.HammingDistance; + +/** + * Created by neukamm on 13.03.17. + */ +public class Functions { + + /** + * Get the hamming distance between two string sequences + * + * @param sequence1 - the first sequence + * @param sequence2 - the second sequence + * @return the hamming distance + */ + public int getHammingDistance(String sequence1, String sequence2){ + HammingDistance hammingDistance = new HammingDistance(); + return hammingDistance.apply(sequence1, sequence2); + } + +} diff --git a/src/main/java/calculations/LengthDistribution.java b/src/main/java/org/damageprofiler/calculations/LengthDistribution.java similarity index 67% rename from src/main/java/calculations/LengthDistribution.java rename to src/main/java/org/damageprofiler/calculations/LengthDistribution.java index 2780967..f8798e8 100755 --- a/src/main/java/calculations/LengthDistribution.java +++ b/src/main/java/org/damageprofiler/calculations/LengthDistribution.java @@ -1,4 +1,4 @@ -package calculations; +package org.damageprofiler.calculations; import htsjdk.samtools.SAMRecord; import org.apache.log4j.Logger; @@ -13,8 +13,8 @@ public class LengthDistribution { private final Logger LOG; - private HashMap<Integer, Integer> length_distribution_map_forward; - private HashMap<Integer, Integer> length_distribution_map_reverse; + private HashMap<Double, Integer> length_distribution_map_forward; + private HashMap<Double, Integer> length_distribution_map_reverse; private HashMap<Double, Double> length_distribution_map; private List<Double> length_forward; private List<Double> length_reverse; @@ -47,8 +47,8 @@ public void init(){ public void fillDistributionTable(SAMRecord record, String record_aligned){ // int record_length = record.getReadLength(); - int record_length = record_aligned.length(); - length_all.add((double)record_length); + double record_length = record_aligned.length(); + length_all.add(record_length); // check if record is on forward or reverse strand if(record.getReadNegativeStrandFlag()){ @@ -58,7 +58,7 @@ public void fillDistributionTable(SAMRecord record, String record_aligned){ int count = length_distribution_map_reverse.get(record_length); length_distribution_map_reverse.put(record_length, count + 1); } - length_reverse.add((double)record_length); + length_reverse.add(record_length); @@ -69,7 +69,7 @@ public void fillDistributionTable(SAMRecord record, String record_aligned){ int count = length_distribution_map_forward.get(record_length); length_distribution_map_forward.put(record_length, count + 1); } - length_forward.add((double)record_length); + length_forward.add(record_length); } @@ -82,42 +82,18 @@ public void fillDistributionTable(SAMRecord record, String record_aligned){ } } - /* - * Getter - * + Getter */ - - public HashMap<Integer, Integer> getSeqLen(LengthDistribution lengthDistribution) { - - List<Double> length_all = lengthDistribution.getLength_all(); - HashMap<Integer, Integer> map_length_occurrences_all = new HashMap<>(); - - for(double d : length_all){ - if(!map_length_occurrences_all.containsKey(d)){ - map_length_occurrences_all.put((int)d, 1); - } else { - int count = map_length_occurrences_all.get(d); - map_length_occurrences_all.put((int)d, count + 1); - } - } - return map_length_occurrences_all; - } - - - public HashMap<Integer, Integer> getLength_distribution_map_forward() { + public HashMap<Double, Integer> getLength_distribution_map_forward() { return length_distribution_map_forward; } - public HashMap<Integer, Integer> getLength_distribution_map_reverse() { + public HashMap<Double, Integer> getLength_distribution_map_reverse() { return length_distribution_map_reverse; } - public HashMap<Double, Double> getLength_distribution_map() { - return length_distribution_map; - } - public List<Double> getLength_forward() { return length_forward; } diff --git a/src/main/java/org/damageprofiler/calculations/RuntimeEstimator.java b/src/main/java/org/damageprofiler/calculations/RuntimeEstimator.java new file mode 100755 index 0000000..f5ae95a --- /dev/null +++ b/src/main/java/org/damageprofiler/calculations/RuntimeEstimator.java @@ -0,0 +1,66 @@ +package org.damageprofiler.calculations; + +import htsjdk.samtools.SamReader; +import htsjdk.samtools.SamReaderFactory; +import htsjdk.samtools.ValidationStringency; + +import java.io.File; + +public class RuntimeEstimator { + + private SamReader input; + private long numberOfRecords; + private double timePer100000RecordsInSeconds = 2; + private long estimatedRuntimeInSeconds; + + public RuntimeEstimator(String inputfile){ + input = SamReaderFactory.make().enable(SamReaderFactory.Option.DONT_MEMORY_MAP_INDEX). + validationStringency(ValidationStringency.LENIENT).open(new File(inputfile)); + + estimate(inputfile); + + } + + /** + * Estimate runtime based on the time needed in previous runs and the number of reads in the + * current input file. + * + * @param inputfile + */ + public void estimate(String inputfile) { + // estimate runtime: + + double bytes = new File (inputfile).length(); + double kilobytes = (bytes / 1024); + double megabytes = (kilobytes / 1024); + double gigabytes = (megabytes / 1024); + + double sizeSamRecordInBytes = 50; + + double estimatedNumberOfRecords = bytes/sizeSamRecordInBytes; + System.out.println("Estimated number of records to process: " + estimatedNumberOfRecords); + +// numberOfRecords = input.iterator().toList().size(); + numberOfRecords = (long)estimatedNumberOfRecords; + System.out.println("Number of records to process: " + numberOfRecords); + + estimatedRuntimeInSeconds = (long) (numberOfRecords/100000 * timePer100000RecordsInSeconds); + + if(estimatedRuntimeInSeconds > 60) { + long minutes = estimatedRuntimeInSeconds / 60; + long seconds = estimatedRuntimeInSeconds % 60; + System.out.println("Estimated Runtime: " + minutes + " minutes, and " + seconds + " seconds."); + } else { + System.out.println("Estimated Runtime: " + estimatedRuntimeInSeconds + " seconds."); + } + + } + + public long getEstimatedRuntimeInSeconds() { + return estimatedRuntimeInSeconds; + } + + public int getNumberOfRecords() { + return (int)numberOfRecords; + } +} diff --git a/src/main/java/calculations/SpecieHandler.java b/src/main/java/org/damageprofiler/calculations/SpeciesHandler.java similarity index 83% rename from src/main/java/calculations/SpecieHandler.java rename to src/main/java/org/damageprofiler/calculations/SpeciesHandler.java index 6869d16..cc3c84a 100755 --- a/src/main/java/calculations/SpecieHandler.java +++ b/src/main/java/org/damageprofiler/calculations/SpeciesHandler.java @@ -1,32 +1,39 @@ -package calculations; +package org.damageprofiler.calculations; import java.io.*; import java.util.Random; -import IO.DOMParser; +import org.damageprofiler.IO.DOMParser; import org.apache.log4j.Logger; /** * Created by neukamm on 25.07.16. */ -public class SpecieHandler { +public class SpeciesHandler { private Logger LOG; private String gi; - private String specie_name; - public SpecieHandler(){ + /** + * This class accesses NCBI to find the name of a species based on the RefSeqID. + */ + public SpeciesHandler(){ } - public void getSpecie(String rname){ - if (rname != null) { + /** + * + * @param ref_name + */ + public String getSpecies(String ref_name){ + String species_name = ""; + if (ref_name != null) { String tax = ""; // get tax id from RNAME string - String[] rname_split = rname.split("\\|"); + String[] rname_split = ref_name.split("\\|"); for (int i = 0; i < rname_split.length; i++) { switch (rname_split[i]) { case "gi": @@ -44,10 +51,10 @@ public void getSpecie(String rname){ "Please make sure that the SAM/BAM file reference tag contains the tax ID"); } if(!tax.equals("")){ - specie_name = getSpeciesByID(Integer.parseInt(tax)); - // specie_name = specie_name.replaceAll(" ", "_"); + species_name = getSpeciesByID(Integer.parseInt(tax)); } } + return species_name; } @@ -96,16 +103,9 @@ private String getSpeciesByID(int id) { System.out.println("'Curl' is not installed. If you would like to use this option, please install it."); } - - return species; } - - public String getSpecie_name() { - return specie_name; - } - public void setLOG(Logger LOG) { this.LOG = LOG; } diff --git a/src/main/java/IO/SpeciesListParser.java b/src/main/java/org/damageprofiler/calculations/SpeciesListParser.java similarity index 68% rename from src/main/java/IO/SpeciesListParser.java rename to src/main/java/org/damageprofiler/calculations/SpeciesListParser.java index e3ce623..c27ee39 100755 --- a/src/main/java/IO/SpeciesListParser.java +++ b/src/main/java/org/damageprofiler/calculations/SpeciesListParser.java @@ -1,6 +1,5 @@ -package IO; +package org.damageprofiler.calculations; -import calculations.SpecieHandler; import org.apache.log4j.Logger; import java.io.BufferedReader; @@ -15,26 +14,20 @@ public class SpeciesListParser { private Logger LOG; private String speciesFile; - private SpecieHandler specieHandler; + private SpeciesHandler speciesHandler; public SpeciesListParser(String speciesListFile, Logger LOG) { this.speciesFile = speciesListFile; this.LOG = LOG; - specieHandler = new SpecieHandler(); + speciesHandler = new SpeciesHandler(); } - public String getSingleSpecie(String rname) { - - specieHandler.getSpecie(rname); - return specieHandler.getSpecie_name(); - } - - public List<String> getList() { - - return readFile(); - } - + /** + * Read file with species listed by the user. + * + * @return + */ private List<String> readFile() { try { @@ -42,15 +35,15 @@ private List<String> readFile() { FileReader fileReader = new FileReader(file); BufferedReader bufferedReader = new BufferedReader(fileReader); String line; - List<String> list = new ArrayList<>(); + List<String> list_species = new ArrayList<>(); while ((line = bufferedReader.readLine()) != null) { - list.add(line.trim()); + list_species.add(line.trim()); } fileReader.close(); - return list; + return list_species; } catch (IOException e) { e.printStackTrace(); } @@ -60,9 +53,18 @@ private List<String> readFile() { } + /* + Getter and Setter + */ public void setLOG(Logger LOG) { this.LOG = LOG; - specieHandler.setLOG(LOG); + speciesHandler.setLOG(LOG); + } + + + public List<String> getSpeciesList() { + + return readFile(); } } diff --git a/src/main/java/calculations/StartCalculations.java b/src/main/java/org/damageprofiler/calculations/StartCalculations.java old mode 100644 new mode 100755 similarity index 59% rename from src/main/java/calculations/StartCalculations.java rename to src/main/java/org/damageprofiler/calculations/StartCalculations.java index c088b1c..c99c728 --- a/src/main/java/calculations/StartCalculations.java +++ b/src/main/java/org/damageprofiler/calculations/StartCalculations.java @@ -1,14 +1,18 @@ -package calculations; - -import IO.*; +package org.damageprofiler.calculations; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import com.itextpdf.text.DocumentException; +import htsjdk.samtools.reference.IndexedFastaSequenceFile; +import javafx.scene.paint.Color; import org.apache.log4j.*; +import org.damageprofiler.IO.*; +import org.jfree.chart.JFreeChart; /** @@ -16,14 +20,12 @@ */ public class StartCalculations { - private final String VERSION; + private String VERSION; private LogClass logClass; private long currtime_prior_execution; // start time to get overall runtime - private boolean calculationsDone = true; + private boolean calculationsDone = false; private Logger LOG; private List<String> specieslist = null; - private List<String> species_name_list; - private SpeciesListParser speciesListParser; private boolean use_only_merged_reads; private double height_damageplot; //= 0.4; // set yaxis height to 40% as default private int threshold; @@ -33,22 +35,49 @@ public class StartCalculations { private String reference; private String outfolder; private String input; - private SpecieHandler specieHandler; + private SpeciesHandler speciesHandler = new SpeciesHandler(); private boolean use_all_reads; private double xaxis_min_id_histogram; private double xaxis_max_id_histogram; private double xaxis_min_length_histogram; private double xaxis_max_length_histogram; + private boolean ssLibProtocolUsed; + private DamageProfiler damageProfiler; + private OutputGenerator outputGenerator; + private String inputfileNameWithOutExtension; + private Communicator communicator; + private IndexedFastaSequenceFile fastaSequenceFile; + private FastACacher cache; + private HashMap<String, List<JFreeChart>> species_output_summary; + private HashMap<String, Integer> number_of_used_reads_summary; + + + // plot settings + private Color color_DP_C_to_T; + private Color color_DP_G_to_A; + private Color color_DP_insertions; + private Color color_DP_deletions; + private Color color_DP_other; + private String output_folder; + private String speciesname = null; - public StartCalculations(String version){ + public StartCalculations(){ + + } + + public void setVERSION(String version){ VERSION = version; } + /** + * Start all calculations. + * @param c + * @throws Exception + */ public void start(Communicator c) throws Exception { currtime_prior_execution = System.currentTimeMillis(); - input = c.getInput(); outfolder = c.getOutfolder(); reference = c.getReference(); @@ -63,9 +92,16 @@ public void start(Communicator c) throws Exception { xaxis_max_length_histogram = c.getXaxis_histo_length_max(); use_only_merged_reads = c.isUse_merged_and_mapped_reads(); use_all_reads = c.isUse_all_reads(); - speciesListParser=null; - species_name_list=null; - specieHandler = new SpecieHandler(); + ssLibProtocolUsed = c.isSsLibsProtocolUsed(); + + color_DP_C_to_T = c.getColor_DP_C_to_T(); + color_DP_G_to_A = c.getColor_DP_G_to_A(); + color_DP_insertions = c.getColor_DP_insertions(); + color_DP_deletions = c.getColor_DP_deletions(); + color_DP_other = c.getColor_DP_other(); + + this.inputfileNameWithOutExtension = input.substring(0, input.lastIndexOf('.')); + this.communicator = c; SpeciesListParser speciesListParser = new SpeciesListParser( specieslist_filepath, @@ -73,66 +109,46 @@ public void start(Communicator c) throws Exception { ); + if(!this.reference.equals("")) + readReferenceInCache(); + if(specieslist_filepath != null){ + species_output_summary = new HashMap<>(); + number_of_used_reads_summary = new HashMap<>(); + speciesHandler = new SpeciesHandler(); /* parse species references (-sf) and run DP for each reference in the file */ specieslist = new ArrayList<>(); - specieslist.addAll(speciesListParser.getList()); + specieslist.addAll(speciesListParser.getSpeciesList()); for (int i = 0; i < specieslist.size(); i++) { String specie_input_string = specieslist.get(i); //String specie_name = species_real_name_list.get(i); - - - // start DamageProfiler - File file = new File(input); - DamageProfiler damageProfiler = new DamageProfiler(specieHandler); - + // start DamageProfiler + damageProfiler = new DamageProfiler(speciesHandler, cache); String ref = specie_input_string.split("\\|")[0].trim(); - String speciesname = damageProfiler.getSpeciesname(file, ref); + speciesname = damageProfiler.getSpeciesname(new File(input), ref); - String inputfileNameWithOutExtension = input.substring(0, input.lastIndexOf('.')); - String output_folder = createOutputFolder( + createOutputFolder( outfolder, inputfileNameWithOutExtension.split("/")[inputfileNameWithOutExtension.split("/").length - 1] + File.separator + ref + "_" + speciesname); - - - if (c.getTitle_plots() == null) { - inputfileNameWithOutExtension = input.substring(0, input.lastIndexOf('.')); - } else { - inputfileNameWithOutExtension = c.getTitle_plots(); - } - - + initPlot(); // init Logger - logClass = new LogClass(); - logClass.updateLog4jConfiguration(output_folder + "/DamageProfiler_" + ref + "_" + speciesname +".log"); - logClass.setUp(); - - LOG = logClass.getLogger(this.getClass()); - System.out.println("DamageProfiler v" + VERSION); - LOG.info("DamageProfiler v" + VERSION); - LOG.info("Calculate damage profile for species " + ref + " (" + speciesname + ")"); - - + initLogger(output_folder + "/DamageProfiler_" + ref + "_" + speciesname +".log", + "Calculate damage profile for species " + ref + " (" + speciesname + ")"); - // decompress input file if necessary - if (input.endsWith(".gz")) { - Unzip unzip = new Unzip(LOG); - input = unzip.decompress(input); - } // create new output folder // log settings - LOG.info("Analysis of file (-i):" + file + "\n" + LOG.info("\nAnalysis of file (-i):" + input + "\n" + "Output folder (-o):" + output_folder + "\n" + "Reference (-r, optional) :" + reference + "\n" + "Specie (-s, optional):" + specie_input_string + "\n" @@ -145,8 +161,7 @@ parse species references (-sf) and run DP for each reference in the file + "x-axis min length histogram (-xaxis_histo_length_min): " + xaxis_min_length_histogram + "\n" + "x-axis max length histogram (-xaxis_histo_length_max): " + xaxis_max_length_histogram + "\n"); - - damageProfiler.init(file, + damageProfiler.init(new File(input), new File(reference), threshold, length, @@ -154,17 +169,33 @@ parse species references (-sf) and run DP for each reference in the file LOG); damageProfiler.extractSAMRecords(use_only_merged_reads, use_all_reads); - - generateOutput(damageProfiler, output_folder, inputfileNameWithOutExtension, speciesname); + generateOutput(); + String spec_no_space = specie_input_string.replace(" ","_"); + species_output_summary.put(spec_no_space + " (" + speciesname + ")", + List.of(outputGenerator.getChart_DP_5prime(), + outputGenerator.getChart_DP_3prime(), + outputGenerator.getEditDist_chart(), + outputGenerator.getLength_chart_all()) + ); + + number_of_used_reads_summary.put( + spec_no_space + " (" + speciesname + ")", + damageProfiler.getNumberOfUsedReads()); } + // generate metagenomic output summary + MetagenomicOutput metagenomicOutput = new MetagenomicOutput(); + String[] splitted = input.split("/"); + String filename = splitted[splitted.length-1]; + metagenomicOutput.generate(outfolder + File.separator + + inputfileNameWithOutExtension.split("/")[inputfileNameWithOutExtension.split("/").length - 1], + species_output_summary, filename, number_of_used_reads_summary); + } else if(species_ref_identifier != null){ // start DamageProfiler - DamageProfiler damageProfiler = new DamageProfiler( - - specieHandler); + damageProfiler = new DamageProfiler(speciesHandler, cache); /* parse species reference (-s) and run DP @@ -172,44 +203,23 @@ parse species reference (-s) and run DP this.specieslist = new ArrayList<>(); specieslist.add(species_ref_identifier); - String speciesname = damageProfiler.getSpeciesname(new File(input), species_ref_identifier); + speciesname = damageProfiler.getSpeciesname(new File(input), species_ref_identifier); String inputfileNameWithOutExtension = input.substring(0, input.lastIndexOf('.')); - String output_folder = createOutputFolder( + createOutputFolder( outfolder, inputfileNameWithOutExtension.split("/")[inputfileNameWithOutExtension.split("/").length - 1] + File.separator + species_ref_identifier + "_" + speciesname); - - if (c.getTitle_plots() == null) { - inputfileNameWithOutExtension = input.substring(0, input.lastIndexOf('.')); - } - else { - inputfileNameWithOutExtension = c.getTitle_plots(); - } - - + initPlot(); // init Logger - logClass = new LogClass(); - logClass.updateLog4jConfiguration(output_folder + "/DamageProfiler.log"); - logClass.setUp(); - LOG = logClass.getLogger(this.getClass()); - System.out.println("DamageProfiler v" + VERSION); - LOG.info("DamageProfiler v" + VERSION); - - - // decompress input file if necessary - if (input.endsWith(".gz")) { - Unzip unzip = new Unzip(LOG); - input = unzip.decompress(input); - } + initLogger(output_folder + "/DamageProfiler.log", "DamageProfiler v" + VERSION); + - // create new output folder - File file = new File(input); // log settings - LOG.info("Analysis of file (-i):" + file + "\n" + LOG.info("Analysis of file (-i):" + input + "\n" + "Output folder (-o):" + output_folder + "\n" + "Reference (-r, optional) :" + reference + "\n" + "Specie (-s, optional):" + specieslist + "\n" @@ -222,10 +232,7 @@ parse species reference (-s) and run DP + "x-axis min length histogram (-xaxis_histo_length_min): " + xaxis_min_length_histogram + "\n" + "x-axis max length histogram (-xaxis_histo_length_max): " + xaxis_max_length_histogram + "\n"); - - - - damageProfiler.init(file, + damageProfiler.init(new File(input), new File(reference), threshold, length, @@ -233,45 +240,29 @@ parse species reference (-s) and run DP LOG); damageProfiler.extractSAMRecords(use_only_merged_reads, use_all_reads); - speciesListParser.setLOG(LOG); - generateOutput(damageProfiler,output_folder, inputfileNameWithOutExtension, null); + generateOutput(); + } else { /* - No species specified --> use all (mapping) reads + No species specified --> use all mapped reads */ String inputfileNameWithOutExtension = input.substring(0, input.lastIndexOf('.')); - String output_folder = createOutputFolder( + // create output folder based on file name + createOutputFolder( outfolder, inputfileNameWithOutExtension.split("/")[inputfileNameWithOutExtension.split("/").length - 1]); - if (c.getTitle_plots() == null) { - inputfileNameWithOutExtension = input.substring(0, input.lastIndexOf('.')); - } else { - inputfileNameWithOutExtension = c.getTitle_plots(); - } + initPlot(); // init Logger - logClass = new LogClass(); - logClass.updateLog4jConfiguration(output_folder + "/DamageProfiler.log"); - logClass.setUp(); - LOG = logClass.getLogger(this.getClass()); - System.out.println("DamageProfiler v" + VERSION); - LOG.info("DamageProfiler v" + VERSION); - - - // decompress input file if necessary - if (input.endsWith(".gz")) { - Unzip unzip = new Unzip(LOG); - input = unzip.decompress(input); - } + initLogger(output_folder + "/DamageProfiler.log", "DamageProfiler v" + VERSION); + - // create new output folder - File file = new File(input); // log settings - LOG.info("Analysis of file (-i):" + file + "\n" + LOG.info("Analysis of file (-i):" + input + "\n" + "Output folder (-o):" + output_folder + "\n" + "Reference (-r, optional) :" + reference + "\n" + "Specie (-s, optional):" + specieslist + "\n" @@ -284,52 +275,58 @@ parse species reference (-s) and run DP + "x-axis min length histogram (-xaxis_histo_length_min): " + xaxis_min_length_histogram + "\n" + "x-axis max length histogram (-xaxis_histo_length_max): " + xaxis_max_length_histogram + "\n"); - - // start DamageProfiler - DamageProfiler damageProfiler = new DamageProfiler(specieHandler); + damageProfiler = new DamageProfiler(speciesHandler, cache); - damageProfiler.init(file, + damageProfiler.init(new File(input), new File(reference), threshold, length, null, LOG); damageProfiler.extractSAMRecords(use_only_merged_reads, use_all_reads); - speciesListParser.setLOG(LOG); - - generateOutput(damageProfiler, output_folder, inputfileNameWithOutExtension, null); - + generateOutput(); } + calculationsDone=true; + + } - // print runtime - long currtime_post_execution = System.currentTimeMillis(); - long diff = currtime_post_execution - currtime_prior_execution; - long runtime_s = diff / 1000; - if(runtime_s > 60) { - long minutes = runtime_s / 60; - long seconds = runtime_s % 60; - LOG.info("Runtime of Module was: " + minutes + " minutes, and " + seconds + " seconds."); + private void initPlot() { + if (communicator.getTitle_plots() == null) { + inputfileNameWithOutExtension = input.substring(0, input.lastIndexOf('.')); } else { - LOG.info("Runtime of Module was: " + runtime_s + " seconds."); + inputfileNameWithOutExtension = communicator.getTitle_plots(); } + } - calculationsDone=true; + private void initLogger(String outfolder, String log) { + logClass = new LogClass(); + logClass.updateLog4jConfiguration(outfolder); + logClass.setUp(); + + LOG = logClass.getLogger(this.getClass()); + System.out.println("DamageProfiler v" + VERSION); + LOG.info(log); } - private void generateOutput(DamageProfiler damageProfiler, String output_folder, String inputfileNameWithOutExtension, String spe) - throws IOException, DocumentException { + /** + * Generate output files. + * + * @throws IOException + * @throws DocumentException + */ + private void generateOutput() throws IOException, DocumentException { if (damageProfiler.getNumberOfUsedReads() != 0) { - OutputGenerator outputGenerator = new OutputGenerator( + outputGenerator = new OutputGenerator( output_folder, damageProfiler, - spe, + speciesname, threshold, length, height_damageplot, @@ -338,7 +335,10 @@ private void generateOutput(DamageProfiler damageProfiler, String output_folder, xaxis_min_length_histogram, xaxis_max_length_histogram, input, - LOG + LOG, + damageProfiler.getNumberOfRecords(), + ssLibProtocolUsed, + color_DP_C_to_T, color_DP_deletions, color_DP_G_to_A, color_DP_insertions, color_DP_other ); outputGenerator.writeLengthDistribution(); @@ -367,11 +367,12 @@ private void generateOutput(DamageProfiler damageProfiler, String output_folder, damageProfiler.getLength_reverse(), inputfileNameWithOutExtension ); - outputGenerator.plotIdentitiyHistogram( - damageProfiler.getIdentity(), + outputGenerator.plotEditDistanceHistogram( + damageProfiler.getEditDistances(), // damageProfiler.getIdentity(), "Identity distribution", inputfileNameWithOutExtension ); + outputGenerator.writeEditDistance(damageProfiler.getEditDistances()); LOG.info("Output files generated"); @@ -380,6 +381,7 @@ private void generateOutput(DamageProfiler damageProfiler, String output_folder, } } + /** * create output folder. * Save all files in subfolder, which has the same name as the input file @@ -388,7 +390,7 @@ private void generateOutput(DamageProfiler damageProfiler, String output_folder, * @param path * @throws IOException */ - private static String createOutputFolder(String path, String inputfileNameWithOutExtension) { + private void createOutputFolder(String path, String inputfileNameWithOutExtension) { // use Pattern.quote(File.separator) to split file path File f = new File(path + File.separator + inputfileNameWithOutExtension); @@ -398,11 +400,33 @@ private static String createOutputFolder(String path, String inputfileNameWithOu f.mkdirs(); } - return f.getAbsolutePath(); + this.output_folder = f.getAbsolutePath(); } + /** + * index reference file and put it in cache to get faster + * access + * + * @throws FileNotFoundException + */ + + private void readReferenceInCache() throws FileNotFoundException{ + // read reference file as indexed reference + fastaSequenceFile = new IndexedFastaSequenceFile(new File(this.reference)); + // store reference in cache to get faster access + cache = new FastACacher(new File(reference), LOG); + + } public boolean isCalculationsDone() { return calculationsDone; } + + public void setCalculationsDone(boolean calculationsDone) { + this.calculationsDone = calculationsDone; + } + + public OutputGenerator getOutputGenerator() { + return outputGenerator; + } } diff --git a/src/main/java/org/damageprofiler/controller/DamageProfilerMainController.java b/src/main/java/org/damageprofiler/controller/DamageProfilerMainController.java new file mode 100755 index 0000000..f65e7c7 --- /dev/null +++ b/src/main/java/org/damageprofiler/controller/DamageProfilerMainController.java @@ -0,0 +1,431 @@ +package org.damageprofiler.controller; + +import org.damageprofiler.GUI.*; +import org.damageprofiler.GUI.Dialogues.AdvancedPlottingOptionsDialogue; +import org.damageprofiler.GUI.Dialogues.HelpDialogue; +import org.damageprofiler.GUI.Dialogues.RunInfoDialogue; +import org.damageprofiler.GUI.Dialogues.RuntimeEstimatorDialogue; +import org.damageprofiler.calculations.RuntimeEstimator; +import org.damageprofiler.calculations.StartCalculations; +import org.damageprofiler.IO.Communicator; +import javafx.concurrent.Task; +import javafx.event.Event; +import javafx.event.EventHandler; +import javafx.scene.control.*; +import javafx.scene.paint.Color; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.fx.ChartViewer; + +public class DamageProfilerMainController { + + private final Button btn_leftpane_run_config; + private final Button btn_leftpane_identityDist; + private final Button btn_leftpane_damageProfile; + private final Button btn_leftpane_lengthDist; + private final ProgressBarController progressBarController; + private final Button btn_estimate_runtime; + private final Button btn_help; + private final HelpDialogue help_dialogue; + private final AdvancedPlottingOptionsDialogue advancedPlottingOptionsDialogue; + private final PlottingSettingController plottingSettingController; + private RunInfoDialogue runInfoDialogue; + private Communicator communicator; + private Button btn_inputfile; + private Button btn_reference; + private Button btn_output; + private Button btn_run; + private Button btn_speciesList; + private TextField textfield_threshold; + private TextField textfield_length; + private TextField textfield_species; + private CheckBox checkbox_use_merged_reads; + private CheckBox checkbox_ssLibs_protocol; + private TextField textfield_title; + private TextField textfield_y_axis_height; + private StartCalculations starter = new StartCalculations(); + private DamageProfilerMainGUI mainGUI; + private RuntimeEstimatorDialogue runtimeInfoDialogue; + /** + * Constructor + * @param damageProfilerMainGUI + * @param progressBarController + * @param plottingSettingController + */ + public DamageProfilerMainController(DamageProfilerMainGUI damageProfilerMainGUI, + ProgressBarController progressBarController, + PlottingSettingController plottingSettingController){ + + this.mainGUI = damageProfilerMainGUI; + this.progressBarController = progressBarController; + this.communicator = mainGUI.getCommunicator(); + runInfoDialogue = new RunInfoDialogue("Run configuration", communicator); + starter.setVERSION(damageProfilerMainGUI.getVersion()); + this.help_dialogue = new HelpDialogue(); + + this.btn_inputfile = mainGUI.getConfig_dialogue().getBtn_inputfile(); + this.btn_reference = mainGUI.getConfig_dialogue().getBtn_reference(); + this.btn_output = mainGUI.getConfig_dialogue().getBtn_output(); + this.btn_run = mainGUI.getConfig_dialogue().getBtn_run(); + this.btn_estimate_runtime = mainGUI.getConfig_dialogue().getBtn_estimate_runtime(); + this.btn_speciesList = mainGUI.getConfig_dialogue().getBtn_speciesList(); + this.btn_leftpane_identityDist = mainGUI.getBtn_leftpane_identityDist(); + this.btn_leftpane_run_config = mainGUI.getBtn_leftpane_info(); + this.btn_help = mainGUI.getBtn_help(); + this.btn_leftpane_damageProfile = mainGUI.getBtn_leftpane_damageProfile(); + this.btn_leftpane_lengthDist = mainGUI.getBtn_leftpane_lengthDist(); + + this.textfield_threshold = mainGUI.getConfig_dialogue().getTextfield_threshold(); + this.textfield_length = mainGUI.getConfig_dialogue().getTextfield_length(); + this.textfield_species = mainGUI.getConfig_dialogue().getTextfield_species(); + this.textfield_title = mainGUI.getConfig_dialogue().getTextfield_title(); + this.textfield_y_axis_height = mainGUI.getConfig_dialogue().getTextfield_y_axis_height(); + + this.checkbox_use_merged_reads = mainGUI.getConfig_dialogue().getCheckbox_use_merged_reads(); + this.checkbox_ssLibs_protocol = mainGUI.getConfig_dialogue().getCheckbox_ssLibs_protocol(); + + + // attributes of advanced plotting settings + this.plottingSettingController = plottingSettingController; + this.advancedPlottingOptionsDialogue = this.mainGUI.getConfig_dialogue().getAdvancedPlottingOptionsDialogue(); + this.plottingSettingController.addListener(this.advancedPlottingOptionsDialogue); + + + runtimeInfoDialogue = new RuntimeEstimatorDialogue("Runtime information", + "This gives you an estimate of the runtime. For large files with a long runtime,\n" + + "it's recommended to use the command line version of DamageProfiler."); + + setColorsPlotting(); + addListener(); + + } + + private void setColorsPlotting() { + + communicator.setColor_DP_C_to_T(this.advancedPlottingOptionsDialogue.getTabAdvancedSettingsDamagePlot().getColorPicker_C_to_T().getValue()); + communicator.setColor_DP_G_to_A(this.advancedPlottingOptionsDialogue.getTabAdvancedSettingsDamagePlot().getColorPicker_G_to_A().getValue()); + communicator.setColor_DP_insertions(this.advancedPlottingOptionsDialogue.getTabAdvancedSettingsDamagePlot().getColorPicker_insertions().getValue()); + communicator.setColor_DP_deletions(this.advancedPlottingOptionsDialogue.getTabAdvancedSettingsDamagePlot().getColorPicker_deletions().getValue()); + communicator.setColor_DP_other(this.advancedPlottingOptionsDialogue.getTabAdvancedSettingsDamagePlot().getColorPicker_others().getValue()); + + } + + private void addListener() { + + btn_inputfile.setOnAction(e -> { + + BamFileChooser fqfc = new BamFileChooser(communicator); + if (communicator.getInput() != null){ + Tooltip tooltip_input = new Tooltip(communicator.getInput()); + //setTooltipDelay(tooltip_input); + btn_inputfile.setTooltip(tooltip_input); + + String filepath = communicator.getInput().substring(0, communicator.getInput().lastIndexOf('.')); + String filename = filepath.split("/")[filepath.split("/").length-1]; + mainGUI.getConfig_dialogue().setTextfield_title(filename); + + if (checkIfInputWasSelected()) { + btn_run.setDisable(false); + btn_estimate_runtime.setDisable(false); + + } else { + btn_run.setDisable(true); + btn_estimate_runtime.setDisable(true); + } + } + + + }); + + btn_help.setOnAction(e -> { + mainGUI.getRoot().setCenter(new ScrollPane(this.help_dialogue.getGridPane())); + }); + + btn_reference.setOnAction(e -> { + + ReferenceFileChooser rfc = new ReferenceFileChooser(communicator); + Tooltip tooltip_ref = new Tooltip(communicator.getReference()); + //setTooltipDelay(tooltip_ref); + btn_reference.setTooltip(tooltip_ref); + + if (checkIfInputWasSelected()) { + btn_run.setDisable(false); + btn_estimate_runtime.setDisable(false); + } else { + btn_run.setDisable(true); + btn_estimate_runtime.setDisable(true); + } + + }); + + + + btn_output.setOnAction(e -> { + + OutputDirChooser rfc = new OutputDirChooser(communicator); + Tooltip tooltip_output = new Tooltip(communicator.getOutfolder()); + //setTooltipDelay(tooltip_output); + btn_output.setTooltip(tooltip_output); + + if (checkIfInputWasSelected()) { + btn_run.setDisable(false); + btn_estimate_runtime.setDisable(false); + + } else { + btn_run.setDisable(true); + btn_estimate_runtime.setDisable(true); + } + + }); + + + + btn_estimate_runtime.setOnAction(e -> { + + RuntimeEstimator runtimeEstimator = new RuntimeEstimator(communicator.getInput()); + long estimatedRuntimeInSeconds = runtimeEstimator.getEstimatedRuntimeInSeconds(); + String text_estimatedRuntime; + + + if(estimatedRuntimeInSeconds > 60) { + long minutes = estimatedRuntimeInSeconds / 60; + long seconds = estimatedRuntimeInSeconds % 60; + text_estimatedRuntime = "Estimated Runtime: " + minutes + " minutes, and " + seconds + " seconds."; + } else { + if(estimatedRuntimeInSeconds == 0 ){ + text_estimatedRuntime = "Estimated Runtime: Insignificant"; + } else { + text_estimatedRuntime = "Estimated Runtime: " + estimatedRuntimeInSeconds + " seconds."; + } + + } + + runtimeInfoDialogue.setNumberOfRecords(runtimeEstimator.getNumberOfRecords()); + runtimeInfoDialogue.setResultText(text_estimatedRuntime); + runtimeInfoDialogue.addComponents(); + runtimeInfoDialogue.show(); + }); + + runtimeInfoDialogue.getBtn_proceed().setOnAction(e_start -> { + runtimeInfoDialogue.close(); + runDamageProfiler(); + }); + + runtimeInfoDialogue.getBtn_cancel().setOnAction(e_cancel -> runtimeInfoDialogue.close()); + + btn_run.setOnAction(e -> { + runDamageProfiler(); + }); + + btn_speciesList.setOnAction(e -> { + + SpeciesListFileChooser slfc = new SpeciesListFileChooser(communicator); + if (checkIfInputWasSelected()) { + btn_speciesList.setDisable(false); + } else { + btn_speciesList.setDisable(true); + } + + }); + +// btn_loadSpecies.setOnAction(e -> { +// LoadSpeciesDialogue loadSpeciesDialogue = new LoadSpeciesDialogue(communicator.getInput()); +// +// +// }); + + + btn_leftpane_damageProfile.setOnAction(e -> { + if(starter.isCalculationsDone()){ + // generate plot + generateDamageProfile(); + } + }); + + + btn_leftpane_identityDist.setOnAction(e -> { + + if(starter.isCalculationsDone()){ + // generate plot + generateIdentityDist(); + } + + }); + + btn_leftpane_lengthDist.setOnAction(e -> { + + + if(starter.isCalculationsDone()){ + // generate plot + generateLengthDist(); + } + + }); + + btn_leftpane_run_config.setOnAction(e -> { + if(starter.isCalculationsDone()){ + mainGUI.getRoot().setCenter(runInfoDialogue.getGridPane()); + // show info (parameter / input / output / ...) + // ask for new configuration + } else { + mainGUI.getRoot().setCenter(mainGUI.getConfig_dialogue().getConfig_gridpane()); + } + }); + + runInfoDialogue.getBtn_new_config().setOnAction(e -> { + mainGUI.getRoot().setCenter(mainGUI.getConfig_dialogue().getConfig_gridpane()); + clear(); + }); + + + } + + private void clear() { + btn_leftpane_lengthDist.setDisable(true); + btn_leftpane_identityDist.setDisable(true); + btn_leftpane_damageProfile.setDisable(true); + starter.setCalculationsDone(false); + btn_inputfile.setTooltip(null); + btn_output.setTooltip(null); + btn_reference.setTooltip(null); + } + + private void runDamageProfiler() { + + // set all user options + communicator.setLength(Integer.parseInt(textfield_length.getText())); + communicator.setThreshold(Integer.parseInt(textfield_threshold.getText())); + communicator.setSsLibsProtocolUsed(checkbox_ssLibs_protocol.isSelected()); + communicator.setUse_merged_and_mapped_reads(checkbox_use_merged_reads.isSelected()); + communicator.setyAxis_damageplot(Double.parseDouble(textfield_y_axis_height.getText())); + communicator.setTitle_plots(textfield_title.getText()); + + // set colors + communicator.setColor_DP_C_to_T(this.advancedPlottingOptionsDialogue.getTabAdvancedSettingsDamagePlot().getColorPicker_C_to_T().getValue()); + communicator.setColor_DP_G_to_A(this.advancedPlottingOptionsDialogue.getTabAdvancedSettingsDamagePlot().getColorPicker_G_to_A().getValue()); + communicator.setColor_DP_insertions(this.advancedPlottingOptionsDialogue.getTabAdvancedSettingsDamagePlot().getColorPicker_insertions().getValue()); + communicator.setColor_DP_deletions(this.advancedPlottingOptionsDialogue.getTabAdvancedSettingsDamagePlot().getColorPicker_deletions().getValue()); + communicator.setColor_DP_other(this.advancedPlottingOptionsDialogue.getTabAdvancedSettingsDamagePlot().getColorPicker_others().getValue()); + + + if(textfield_species.getText().equals("")) + communicator.setSpecies_ref_identifier(null); + else + communicator.setSpecies_ref_identifier(textfield_species.getText()); + + if(!textfield_title.getText().equals("")){ + communicator.setTitle_plots(textfield_title.getText()); + } + + + try { + // add progress indicator + Task startCalculuations = new Task() { + @Override + protected Object call() throws Exception { + starter.start(communicator); + runInfoDialogue.updateParameters(); + return true; + } + }; + + progressBarController.activate(startCalculuations); + + startCalculuations.setOnSucceeded((EventHandler<Event>) event -> { + // replace config with result org.damageprofiler.GUI + btn_leftpane_lengthDist.setDisable(false); + btn_leftpane_identityDist.setDisable(false); + btn_leftpane_damageProfile.setDisable(false); + generateDamageProfile(); + progressBarController.stop(); + }); + + new Thread(startCalculuations).start(); + + } catch (Exception e1) { + e1.printStackTrace(); + } + + } + + /** + * The following methods generate the result plots after successful damage profile calculations. + * todo: if plot already created, just reload + */ + + private void generateLengthDist() { + + JFreeChart[] lengthCharts = starter.getOutputGenerator().getLengthDistPlots(); + + TabPane tabPane_lengthDist = new TabPane(); + Tab allData = new Tab("All data"); + Tab splitData = new Tab("Forward vs. Reverse"); + + ChartViewer viewerLengthAll = new ChartViewer(lengthCharts[0]); + ChartViewer viewerLengthSep = new ChartViewer(lengthCharts[1]); + + // disable zoom on x-axis + viewerLengthAll.getCanvas().setDomainZoomable(false); + viewerLengthAll.getCanvas().setDomainZoomable(false); + + allData.setContent(viewerLengthAll); + splitData.setContent(viewerLengthSep); + + tabPane_lengthDist.getTabs().addAll(allData, splitData); + + mainGUI.getRoot().setCenter(tabPane_lengthDist); + + } + + private void generateIdentityDist() { + ChartViewer viewerEditDistance = new ChartViewer(starter.getOutputGenerator().getEditDist_chart()); + mainGUI.getRoot().setCenter(viewerEditDistance); + + } + + private void generateDamageProfile() { + + JFreeChart[] dpCharts = starter.getOutputGenerator().getDP_chart(); + if(dpCharts.length==1){ + ChartViewer viewer5prime = new ChartViewer(dpCharts[0]); + viewer5prime.getCanvas().setDomainZoomable(false); + mainGUI.getRoot().setCenter(viewer5prime); + } else if(dpCharts.length == 2){ + + TabPane tabPane_damagePlot = new TabPane(); + Tab fivePrime = new Tab("5'end"); + Tab threePrime = new Tab("3'end"); + + ChartViewer viewer5prime = new ChartViewer(dpCharts[0]); + ChartViewer viewer3prime = new ChartViewer(dpCharts[1]); + + // disable zoom on x-axis + viewer5prime.getCanvas().setDomainZoomable(false); + viewer3prime.getCanvas().setDomainZoomable(false); + + fivePrime.setContent(viewer5prime); + threePrime.setContent(viewer3prime); + + tabPane_damagePlot.getTabs().addAll(fivePrime, threePrime); + + mainGUI.getRoot().setCenter(tabPane_damagePlot); + } + } + + + /** + * This method checks if all mandatory fields are set. Otherwise, it's not possible to run the tool. + * @return + */ + private boolean checkIfInputWasSelected() { + boolean tmp = false; + if (communicator.getInput() != null && communicator.getReference() != null && communicator.getOutfolder() != null) { + if (communicator.getInput().length() != 0) { + tmp = true; + } + } + return tmp; + } + + + +} diff --git a/src/main/java/org/damageprofiler/controller/PlottingSettingController.java b/src/main/java/org/damageprofiler/controller/PlottingSettingController.java new file mode 100644 index 0000000..43dcda7 --- /dev/null +++ b/src/main/java/org/damageprofiler/controller/PlottingSettingController.java @@ -0,0 +1,25 @@ +package org.damageprofiler.controller; + +import org.damageprofiler.GUI.Dialogues.AdvancedPlottingOptionsDialogue; +import org.damageprofiler.GUI.Dialogues.TabAdvancedSettingsDamagePlot; + +public class PlottingSettingController { + + public PlottingSettingController(){ + + } + + /** + * Adding all listener to advancedPlottingOptionsDialogue + * + * @param advancedPlottingOptionsDialogue + */ + public void addListener(AdvancedPlottingOptionsDialogue advancedPlottingOptionsDialogue) { + TabAdvancedSettingsDamagePlot dp_settings_pane = advancedPlottingOptionsDialogue.getTabAdvancedSettingsDamagePlot(); + dp_settings_pane.getBtn_reset().setOnAction(e ->{ + dp_settings_pane.reset(); + + }); + + } +} diff --git a/src/main/java/org/damageprofiler/controller/ProgressBarController.java b/src/main/java/org/damageprofiler/controller/ProgressBarController.java new file mode 100755 index 0000000..e1d04e4 --- /dev/null +++ b/src/main/java/org/damageprofiler/controller/ProgressBarController.java @@ -0,0 +1,34 @@ +package org.damageprofiler.controller; + +import javafx.concurrent.Task; +import javafx.geometry.Insets; +import javafx.scene.control.ProgressBar; + +public class ProgressBarController { + + private ProgressBar progressBar; + + + public void create(){ + progressBar = new ProgressBar(0); + progressBar.setDisable(true); + progressBar.setPadding(new Insets(5,5,5,5)); + } + + public void activate(Task task){ + progressBar.progressProperty().unbind(); + progressBar.setProgress(0); + progressBar.progressProperty().bind(task.progressProperty()); + + } + + public void stop(){ + progressBar.progressProperty().unbind(); + progressBar.setProgress(0); + progressBar.setDisable(true); + } + + public ProgressBar getProgressBar() { + return progressBar; + } +} diff --git a/src/main/java/org/damageprofiler/controller/TabPaneAdvPlottingController.java b/src/main/java/org/damageprofiler/controller/TabPaneAdvPlottingController.java new file mode 100755 index 0000000..4f85de9 --- /dev/null +++ b/src/main/java/org/damageprofiler/controller/TabPaneAdvPlottingController.java @@ -0,0 +1,4 @@ +package org.damageprofiler.controller; + +public class TabPaneAdvPlottingController { +} diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png new file mode 100755 index 0000000..7c839a9 Binary files /dev/null and b/src/main/resources/logo.png differ