import java.lang.Integer; import java.lang.StringBuilder; import java.lang.Math; import java.awt.Desktop; import java.util.logging.Level; import java.util.logging.Logger; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.geometry.HPos; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.GridPane; import javafx.scene.layout.Pane; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.scene.text.Text; import javafx.scene.control.TextField; import javafx.scene.control.TextArea; import javafx.scene.control.ComboBox; import javafx.stage.FileChooser; import javafx.stage.Stage; /** * MSA Gap Remover * * Given a FASTA format Multiple Sequence Alignment and a * Reference sequence from that Alignment, it will remove any positions * that correspond to gaps in the reference * * @author Devin Camenares, PhD * * @version 5-25-16 * @since 1-19-16 */ public final class MsaGapRemover extends Application { private Desktop desktop = Desktop.getDesktop(); /** * This method was written by CC and modified by DJC, based upon code from StackOverflow user Kip. * It takes a string and writes it to a specified file, appending said file, with another line break included. * The purpose of this method is to save information and results as they are generated, reducing memory load. * * @param content The string to be written * @param file The destination file for the string output */ private void writeFileN(String content, File file){ try (FileWriter fw = new FileWriter(file, true)) { content += "" + System.lineSeparator(); fw.write(content);// } catch (IOException ex) { Logger.getLogger(MsaGapRemover.class.getName()).log(Level.SEVERE, null, ex); } } /** * This method was written by CC and modified by DJC, based upon code from StackOverflow user Kip. * It takes a string and writes it to a specified file, appending said file, with another line break included. * The purpose of this method is to save information and results as they are generated, reducing memory load. * * @param content The string to be written * @param file The destination file for the string output */ private void writeFile(String content, File file){ try (FileWriter fw = new FileWriter(file, true)) { fw.write(content);// } catch (IOException ex) { Logger.getLogger(MsaGapRemover.class.getName()).log(Level.SEVERE, null, ex); } } /** * This method was written by CC * * @param file The desired file to be opened. */ private void openFile(File file) { try { desktop.open(file); } catch (IOException ex) { Logger.getLogger( MsaGapRemover.class.getName()).log( Level.SEVERE, null, ex ); } } // Initialize All Global Variables public static String flName1 = ""; final long timeUnique = System.currentTimeMillis(); public String dirName = Long.toString(timeUnique); public int seqCount = 0; /** * Container for first file information / path */ File file1 = new File(""); @Override public void start(final Stage stage) { stage.setTitle("Remove Gaps from MSA"); // Initialize Filechooser, Buttons final FileChooser fileChooser = new FileChooser(); final Button openButton1 = new Button("Open MSA File"); final Button processingButton = new Button("Process File"); final Button idButton = new Button("Generate New Job ID"); // Initialize Gridpane final GridPane inputGridPane = new GridPane(); // Set Master Style Strings String bigText = "-fx-font: 35px Tahoma"; // Initialize Texts. Contributed by Christopher Camenares, with Modification Text lbl1 = new Text(" MSA for Gap Removal " + System.lineSeparator()); lbl1.setStyle(bigText); Text lbl2 = new Text("Input Reference Sequence " + System.lineSeparator()); lbl2.setStyle(bigText); Text lbl3 = new Text("No File Loaded"); Text lbl4 = new Text(System.lineSeparator() + "Output Parameters"); lbl4.setStyle(bigText); Text lbl5 = new Text("Job ID#: "); Text lbl6 = new Text("Job Status Pending"); Text lbl7 = new Text(" * " + System.lineSeparator() + " * " + System.lineSeparator() + " * " + System.lineSeparator()); // Text Field and Text Area. Contributed by Christopher Camenares TextArea refSeq; refSeq = new TextArea(); refSeq.setText(""); refSeq.setMinHeight(250); refSeq.setMinWidth(350); refSeq.setWrapText(true); TextField jobID; jobID = new TextField(); jobID.setText(dirName); jobID.setMinHeight(50); // Setup the Grid, Populate with items // 1st Header: Load MSA inputGridPane.add(lbl1, 0, 0); inputGridPane.setHalignment(lbl1, HPos.CENTER); // Open Button inputGridPane.add(openButton1, 0, 1); inputGridPane.setHalignment(openButton1, HPos.CENTER); // Filename inputGridPane.add(lbl3, 0, 2); inputGridPane.setHalignment(lbl3, HPos.CENTER); // Output Header inputGridPane.add(lbl4, 0, 3); inputGridPane.setHalignment(lbl4, HPos.CENTER); inputGridPane.add(lbl5, 0, 4); inputGridPane.setHalignment(lbl5, HPos.CENTER); inputGridPane.add(jobID, 0, 5); inputGridPane.setHalignment(jobID, HPos.CENTER); inputGridPane.add(idButton, 0, 6); inputGridPane.setHalignment(idButton, HPos.CENTER); inputGridPane.add(processingButton, 0, 7); inputGridPane.setHalignment(processingButton, HPos.CENTER); inputGridPane.add(lbl6, 0, 8); inputGridPane.setHalignment(lbl6, HPos.CENTER); // Spacer inputGridPane.add(lbl7, 1, 0); inputGridPane.setRowSpan(lbl7, 9); // Ref Seq Header inputGridPane.add(lbl2, 2, 0); inputGridPane.setHalignment(lbl4, HPos.CENTER); // Reference Sequence Input inputGridPane.add(refSeq, 2, 1); inputGridPane.setRowSpan(refSeq, 8); inputGridPane.setHgap(6); inputGridPane.setVgap(6); final Pane rootGroup = new VBox(12); rootGroup.getChildren().addAll(inputGridPane); rootGroup.setPadding(new Insets(12, 12, 12, 12)); idButton.setOnAction( new EventHandler() { @Override public void handle(final ActionEvent e) { final long timeButton = System.currentTimeMillis(); jobID.setText(Long.toString(timeButton)); } } ); openButton1.setOnAction( new EventHandler() { @Override public void handle(final ActionEvent e) { configureFileChooser(fileChooser); file1 = fileChooser.showOpenDialog(stage); if (file1 != null) { flName1 = file1.getName(); lbl3.setText(flName1); } } }); processingButton.setOnAction( new EventHandler() { @Override public void handle(final ActionEvent e) { if (file1 != null) { /** * Timestamp used to mark the beginning of processing time. */ final long timeStart = System.currentTimeMillis(); lbl6.setText("Processing."); // Get new name for directory dirName = jobID.getText(); /** * A string containing the entire reference sequence */ String refSeqS = refSeq.getText(); refSeqS = refSeqS.replaceAll("\n", ""); /** * Extraction of header information for reference sequence */ String[] refHead = extHeader(refSeqS); refSeqS = refSeqS.replaceAll("(?m)^(.*)\\|", ""); /** * An array representing the parts of the reference sequence */ char[] refArr = refSeqS.toCharArray(); /** * Array for representing blanks positions in reference sequence */ boolean[] blanks = new boolean[refArr.length]; /** * Count of blanks found in reference sequence */ int blnkCount = 0; for (int i = 0; i < refArr.length; i++) { if(refArr[i] == '-') { blanks[i] = true; blnkCount++; } else { blanks[i] = false; } } // Remove Blanks from Size calculation int trimSize = refArr.length - blnkCount; // Make a new directory, specify file destinations File dir = new File(dirName); dir.mkdir(); /** * File for results */ File file3 = new File(dirName + "\\MsaGapRemover_result.txt"); /** * File with runtime information */ File file7 = new File(dirName + "\\MsaGapRemover_report.txt"); /** * Container for resulting strings, to be written to files. */ String resF1 = ""; /** * Container for runtime information. */ String repF = ""; // Read the second file, process each step try (BufferedReader br = new BufferedReader(new FileReader(file1))) { /** * The line being read from a file at the moment */ String line; /** * Toggle to add sequence body information or not */ boolean addBody = false; /** * Temporary container to hold or build sequence header */ String seqHead = ""; /** * Temporary container to hold or build the sequence body from lines */ String seqBody = ""; while ((line = br.readLine()) != null) { if (line.contains(">") && addBody) { // This block if next sequence is encountered. Used to write previous sequence writeFileN(seqHead, file3); seqBody = removeGaps(seqBody, blanks); writeFileN(seqBody, file3); addBody = false; } if (line.contains(">")) { seqHead = line; addBody = true; seqBody = ""; seqCount++; } else if(addBody) { seqBody += line; } } // This code is for the last sequence block in collection 2 writeFileN(seqHead, file3); seqBody = removeGaps(seqBody, blanks); writeFileN(seqBody, file3); } catch (FileNotFoundException ex) { Logger.getLogger(MsaGapRemover.class.getName()).log(Level.SEVERE, null, ex); } catch (IOException ex) { Logger.getLogger(MsaGapRemover.class.getName()).log(Level.SEVERE, null, ex); } final long timeEnd = System.currentTimeMillis(); repF += "Source #1 Filename: " + flName1 + System.lineSeparator(); repF += System.lineSeparator(); repF += "Reference Sequence: " + System.lineSeparator() + refSeqS + System.lineSeparator(); repF += System.lineSeparator(); repF += "Blanks Removed: " + Integer.toString(blnkCount) + System.lineSeparator(); repF += Long.toString(timeEnd - timeStart) + " milliseconds of runtime"; // Write the result to the file, report success writeFile(repF, file7); lbl6.setText("Files Saved!"); openFile(dir); } else { lbl6.setText("Error! Please verify file input"); } } }); stage.setScene(new Scene(rootGroup)); stage.show(); } public static void main(String[] args) { Application.launch(args); } private static void configureFileChooser( final FileChooser fileChooser) { fileChooser.setTitle("View Files"); fileChooser.setInitialDirectory( new File(System.getProperty("user.home")) ); fileChooser.getExtensionFilters().addAll( new FileChooser.ExtensionFilter("Plain Text", "*.txt"), new FileChooser.ExtensionFilter("FASTA", "*.fasta"), new FileChooser.ExtensionFilter("Rich Text Format", "*.rtf"), new FileChooser.ExtensionFilter("All Files", "*.*") ); } private static String[] extHeader(String seq){ String seqA = seq.toUpperCase(); seqA = seqA.replaceFirst(">", ""); String[] seqB = seqA.split(">"); char[][] seqC = new char[seqB.length][]; for (int i = 0; i < seqB.length; i++) { seqB[i] = seqB[i].replaceFirst("GI", ">GI"); seqB[i] = seqB[i].replaceFirst("\\|", "@@"); seqB[i] = seqB[i].replaceFirst("\\|", "@@"); seqB[i] = seqB[i].replaceFirst("\\|", "@@"); seqB[i] = seqB[i].replaceAll("\\|(.*)", "\\|"); seqB[i] = seqB[i].replaceAll("@@", "\\|"); } return seqB; } /** * Method for removing the gaps from a sequence string, based on reference array precreated * @param aln The aligned sequence containing one or more positions to be removed * @param gaps The array containing information about positions that can be kept or removed * @return The aligned sequence after gap removal. */ private static String removeGaps (String aln, boolean[] gaps){ char[] alnArr = aln.toCharArray(); aln = ""; for (int i = 0; i < gaps.length; i++) { if (!gaps[i]) { aln += alnArr[i]; } } return aln; } }