From c4d0a9788968b72dfa1057c8d2fdaa5ddc58d6eb Mon Sep 17 00:00:00 2001 From: Erikpav Date: Wed, 7 Jun 2023 16:40:41 -0400 Subject: [PATCH 01/11] Added the DownsampleSam Picard Tool Matched this branch with changes made to the dev branch when Erik-Branch was merged. This will allow a simple merge in the future as this branch is basically a fork of dev now. Added new Picard tool DownsampleSam. The tool is in the DownsampleSamFile class and its supporting window class is called DownsampleSamFileWindow Added scroll functionality to the BAM Manipulation window in allow the user to select DownsampleSam --- .../scriptmanager/main/ScriptManagerGUI.java | 61 ++++-- .../objects/ToolDescriptions.java | 1 + .../scripts/BAM_Manipulation/BAIIndexer.java | 50 +++-- .../scripts/BAM_Manipulation/BAMFileSort.java | 34 ++-- .../BAM_Manipulation/DownsampleSamFile.java | 45 +++++ .../scripts/BAM_Manipulation/MergeBAM.java | 49 +++++ .../BAM_Manipulation/MergeSamFiles.java | 38 ---- .../scripts/BAM_Manipulation/ValidateSam.java | 33 ++++ .../BAM_Manipulation/BAIIndexerWindow.java | 25 ++- .../DownsampleSamFileWindow.java | 182 ++++++++++++++++++ .../BAM_Manipulation/MergeBAMWindow.java | 38 ++-- .../BAM_Manipulation/SortBAMWindow.java | 43 +++-- .../BAM_Manipulation/ValidateSamWindow.java | 4 + 13 files changed, 464 insertions(+), 139 deletions(-) create mode 100644 src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamFile.java create mode 100644 src/main/java/scriptmanager/scripts/BAM_Manipulation/MergeBAM.java delete mode 100644 src/main/java/scriptmanager/scripts/BAM_Manipulation/MergeSamFiles.java create mode 100644 src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSam.java create mode 100644 src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamFileWindow.java create mode 100644 src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java diff --git a/src/main/java/scriptmanager/main/ScriptManagerGUI.java b/src/main/java/scriptmanager/main/ScriptManagerGUI.java index fe3a0d593..4c586a5f1 100755 --- a/src/main/java/scriptmanager/main/ScriptManagerGUI.java +++ b/src/main/java/scriptmanager/main/ScriptManagerGUI.java @@ -1,29 +1,17 @@ package scriptmanager.main; -import java.awt.EventQueue; -import java.awt.FlowLayout; +import java.awt.*; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; -import javax.swing.JFrame; -import javax.swing.JButton; -import javax.swing.SpringLayout; -import javax.swing.UIManager; -import javax.swing.JTabbedPane; -import javax.swing.JPanel; -import javax.swing.JSplitPane; -import javax.swing.JTextArea; +import javax.swing.*; import scriptmanager.objects.ToolDescriptions; +import scriptmanager.window_interface.BAM_Manipulation.*; import scriptmanager.window_interface.BAM_Statistics.PEStatWindow; import scriptmanager.window_interface.BAM_Statistics.SEStatWindow; import scriptmanager.window_interface.BAM_Statistics.BAMGenomeCorrelationWindow; -import scriptmanager.window_interface.BAM_Manipulation.BAIIndexerWindow; -import scriptmanager.window_interface.BAM_Manipulation.BAMMarkDupWindow; -import scriptmanager.window_interface.BAM_Manipulation.FilterforPIPseqWindow; -import scriptmanager.window_interface.BAM_Manipulation.MergeBAMWindow; -import scriptmanager.window_interface.BAM_Manipulation.SortBAMWindow; import scriptmanager.window_interface.BAM_Format_Converter.BAMtoBEDWindow; import scriptmanager.window_interface.BAM_Format_Converter.BAMtoGFFWindow; import scriptmanager.window_interface.BAM_Format_Converter.BAMtobedGraphWindow; @@ -187,7 +175,18 @@ public void run() { JPanel pnlBamManip = new JPanel(); SpringLayout sl_pnlBamManip = new SpringLayout(); pnlBamManip.setLayout(sl_pnlBamManip); - tabbedPane.addTab("BAM Manipulation", null, pnlBamManip, null); + pnlBamManip.setPreferredSize(new Dimension(200,400)); + + // Wrapped pnlBamManip in a scrollPane to support scrolling + JScrollPane scrollPane = new JScrollPane(pnlBamManip); + scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); + + //This line control the speed of the scroll. Higher number - faster scroll + scrollPane.getVerticalScrollBar().setUnitIncrement(15); + + // Adds the Bam Manipulation tab to the main GUI + tabbedPane.addTab("BAM Manipulation", null, scrollPane, null); + // >BAMIndexer JTextArea txtBAIIndex = new JTextArea(); @@ -332,6 +331,36 @@ public void run() { sl_pnlBamManip.putConstraint(SpringLayout.WEST, txtFilterForPIPseq, 10, SpringLayout.EAST, btnFilterForPIPseq); pnlBamManip.add(btnFilterForPIPseq); + JTextArea txtDownsample = new JTextArea(); + initializeTextArea(txtDownsample); + sl_pnlBamManip.putConstraint(SpringLayout.NORTH, txtDownsample, 10, SpringLayout.SOUTH, txtFilterForPIPseq); + sl_pnlBamManip.putConstraint(SpringLayout.EAST, txtDownsample, -10, SpringLayout.EAST, pnlBamManip); + txtDownsample.setText(ToolDescriptions.downsample_sam_description); + pnlBamManip.add(txtDownsample); + + JButton btnDownsample = new JButton("Downsample SAM/BAM"); + btnDownsample.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + EventQueue.invokeLater(new Runnable() { + public void run() { + try { + DownsampleSamFileWindow frame = new DownsampleSamFileWindow(); + frame.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + }); + + sl_pnlBamManip.putConstraint(SpringLayout.SOUTH, btnDownsample, -45, SpringLayout.SOUTH, txtDownsample); + sl_pnlBamManip.putConstraint(SpringLayout.WEST, btnDownsample, 10, SpringLayout.WEST, pnlBamManip); + sl_pnlBamManip.putConstraint(SpringLayout.WEST, txtDownsample, 10, SpringLayout.EAST, btnDownsample); + sl_pnlBamManip.putConstraint(SpringLayout.SOUTH, pnlBamManip, 25, SpringLayout.SOUTH, btnDownsample); + pnlBamManip.add(btnDownsample); + + // >>>>>>>> BAM_Format_Converter <<<<<<<< JPanel pnlBamConvert = new JPanel(); SpringLayout sl_pnlBamConvert = new SpringLayout(); diff --git a/src/main/java/scriptmanager/objects/ToolDescriptions.java b/src/main/java/scriptmanager/objects/ToolDescriptions.java index b6105eceb..7c985a091 100644 --- a/src/main/java/scriptmanager/objects/ToolDescriptions.java +++ b/src/main/java/scriptmanager/objects/ToolDescriptions.java @@ -35,6 +35,7 @@ public class ToolDescriptions { public static final String remove_duplicates_description = "Removes duplicate reads in Paired-End sequencing given identical 5' read locations. RAM intensive process. If program freezes, increase JAVA heap size."; //* public static final String merge_bam_description = "Merges Multiple BAM files into single BAM file. Sorting is performed automatically. RAM intensive process. If program freezes, increase JAVA heap size."; //* public static final String filter_pip_seq_description = "Filter BAM file by -1 nucleotide. Requires genome FASTA file."; + public static final String downsample_sam_description = "This tool applies a downsampling algorithm to a SAM or BAM file to retain only a (deterministically random) subset of the reads"; // BAM Format Converter public static final String bam_to_scidx_description = "Convert BAM file to scIDX file."; diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/BAIIndexer.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/BAIIndexer.java index 16bb4c21b..03235c41a 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Manipulation/BAIIndexer.java +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/BAIIndexer.java @@ -1,46 +1,42 @@ package scriptmanager.scripts.BAM_Manipulation; -import htsjdk.samtools.*; import picard.sam.BuildBamIndex; import java.io.File; import java.io.IOException; -import java.lang.reflect.Array; -import java.text.NumberFormat; import java.util.ArrayList; -import javax.swing.JOptionPane; - /** + * Picard wrapper for BuildBamIndex + * * @author Erik Pavloski - * The following class is designed to index a BAM file and output said - * index to a file of the same name with a .bai tag + * @see scriptmanager.window_interface.BAM_Manipulation.BAIIndexerWIndow */ - -@SuppressWarnings("serial") public class BAIIndexer { + /** + * Index a BAM file and output said index to a file of the same name with a .bai + * extension + * + * @param input the BAM file to index + * @return the BAM index file (.bai) + * @throws IOException + */ public static File generateIndex(File input) throws IOException { - File retVal = null; - // Tells user that their file is being generated System.out.println("Generating Index File..."); - try { - String output = input.getCanonicalPath() + ".bai"; - retVal = new File(output); + // Build output filepath + String output = input.getCanonicalPath() + ".bai"; + File retVal = new File(output); + // Instatiate Picard object + final BuildBamIndex buildBamIndex = new BuildBamIndex(); + // Build input argument string + final ArrayList args = new ArrayList<>(); + args.add("INPUT=" + input.getAbsolutePath()); + args.add("OUTPUT=" + retVal.getAbsolutePath()); + // Call Picard with args + buildBamIndex.instanceMain(args.toArray(new String[args.size()])); - // Generates the index - final BuildBamIndex buildBamIndex = new BuildBamIndex(); - final ArrayList args = new ArrayList<>(); - args.add("INPUT=" + input.getAbsolutePath()); - args.add("OUTPUT=" + retVal.getAbsolutePath()); - buildBamIndex.instanceMain(args.toArray(new String[args.size()])); - System.out.println("Index File Generated"); - return retVal; - } catch (htsjdk.samtools.SAMException exception) { - System.out.println(exception.getMessage()); - retVal = null; - } - // Returns retVal + System.out.println("Index File Generated"); return retVal; } } diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/BAMFileSort.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/BAMFileSort.java index c46a05c1a..e91a28cde 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Manipulation/BAMFileSort.java +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/BAMFileSort.java @@ -1,12 +1,7 @@ package scriptmanager.scripts.BAM_Manipulation; +import htsjdk.samtools.SAMException; import htsjdk.samtools.SAMFileHeader; -import htsjdk.samtools.SAMFileWriter; -import htsjdk.samtools.SAMFileWriterFactory; -import htsjdk.samtools.SAMRecord; -import htsjdk.samtools.SamReader; -import htsjdk.samtools.SamReaderFactory; -import htsjdk.samtools.util.IOUtil; import picard.sam.SortSam; import java.io.File; @@ -14,28 +9,31 @@ import java.util.ArrayList; /** + * Picard wrapper for MergeSamFiles SortSam + * * @author Erik Pavloski - * The following code uses Picard's SortSam to sort a BAM file by coordinate + * @see scriptmanager.window_interface.BAM_Manipulation.SortBAMWindow */ public class BAMFileSort { - public static File sort(File input, File output) throws IOException { + /** + * The following code uses Picard's SortSam to sort a BAM file by coordinate + * + * @param input the BAM file to be sorted (corresponds to INPUT) + * @param output the file to write the sorted BAM to (corresponds to OUTPUT) + * @throws SAMException + * @throws IOException + */ + public static void sort(File input, File output) throws SAMException, IOException { // Tells user their File is being sorted System.out.println("Sorting Bam File..."); - try { - output = new File(input.getCanonicalPath() + "sorted.bam"); - // Sorts the BAM file + // Instatiate Picard object final SortSam sorter = new SortSam(); + // Build input argument string final ArrayList args = new ArrayList<>(); args.add("INPUT=" + input.getAbsolutePath()); args.add("OUTPUT=" + output.getAbsolutePath()); args.add("SORT_ORDER=" + SAMFileHeader.SortOrder.coordinate); + // Call Picard with args sorter.instanceMain(args.toArray(new String[args.size()])); - System.out.println("BAM File Sorted"); - return output; - } catch (htsjdk.samtools.SAMException exception) { - System.out.println(exception.getMessage()); - output = null; - } - return output; } } \ No newline at end of file diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamFile.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamFile.java new file mode 100644 index 000000000..fa7f4ec20 --- /dev/null +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamFile.java @@ -0,0 +1,45 @@ +package scriptmanager.scripts.BAM_Manipulation; + +import htsjdk.samtools.SAMException; +import scriptmanager.window_interface.BAM_Manipulation.DownsampleSamFileWindow; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +/** + * @author Erik Pavloski + * @see DownsampleSamFileWindow + * This code runs the Picard tool DownsampleSam + * + */ +public class DownsampleSamFile { + /** + * The following code uses Picard's downsampleSAM tool to shink the BAM/SAM file + * and retain a random subset of the reads based on the probability parameter + * Output reads = (probability) * (input reads) + * + * @param input - the BAM/SAM file to be down-sampled + * @param probability - the probability of keeping reads. + * 0.5 default -> 50% reduction in data. + * Smaller number -> less data once down-sampled + * @throws IOException + * @throws SAMException + */ + public static void run(File input, double probability) throws IOException, SAMException { + File retVal; + System.out.println("Down-sampling SAM/BAM file..."); + + String output = input.getAbsolutePath() + ".downsampled.bam"; + retVal = new File(output); + + // Downsamples the SAM/BAM file + final picard.sam.DownsampleSam downsampleSam = new picard.sam.DownsampleSam(); + final ArrayList args = new ArrayList<>(); + args.add("INPUT=" + input.getAbsolutePath()); + args.add("OUTPUT=" + retVal.getAbsolutePath()); + args.add("PROBABILITY=" + probability); + downsampleSam.instanceMain(args.toArray(new String[args.size()])); + + System.out.println("SAM/BAM file down-sampled"); + } +} diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/MergeBAM.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/MergeBAM.java new file mode 100644 index 000000000..ca7e3870b --- /dev/null +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/MergeBAM.java @@ -0,0 +1,49 @@ +package scriptmanager.scripts.BAM_Manipulation; + +import htsjdk.samtools.SAMException; +import picard.sam.MergeSamFiles; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; + +/** + * Picard wrapper for MergeSamFiles + * + * @author Erik Pavloski + * @see scriptmanager.window_interface.BAM_Manipulation + */ +public class MergeBAM { + /** + * Excecute the Picard MergeSamFiles command line tool after checking ever input file has been indexed. + * + * @param inputs the list of input files to merge (corresponds to several INPUT values) + * @param output the output file for the merged BAM file (corresponds to OUTPUT) + * @param useMultipleCpus whether to parallelize (corresponds to USE_THREADING) + * @throws SAMException + * @throws IOException + */ + public static void run(ArrayList inputs, File output, boolean useMultipleCpus) throws SAMException, IOException { + // Check all BAM files have an index + for (int x = 0; x args = new ArrayList<>(); + for (File input : inputs) { + args.add("INPUT=" + input.getAbsolutePath()); + } + args.add("OUTPUT=" + output.getAbsolutePath()); + if (useMultipleCpus) { + args.add("USE_THREADING=true"); + } + merger.instanceMain(args.toArray(new String[args.size()])); + System.out.println("BAM Files Merged."); + } +} \ No newline at end of file diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/MergeSamFiles.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/MergeSamFiles.java deleted file mode 100644 index eb4419ffc..000000000 --- a/src/main/java/scriptmanager/scripts/BAM_Manipulation/MergeSamFiles.java +++ /dev/null @@ -1,38 +0,0 @@ -package scriptmanager.scripts.BAM_Manipulation; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * @author Erik Pavloski - * This class merges BAM and/or SAM Files into a singular file - */ - -public class MergeSamFiles { - // Private constructor to prevent instantiation of the class - private MergeSamFiles() { - } - - public static void run(List inputs, File output, boolean useMultipleCpus) throws IOException { - // Tells the user their files are being merged - System.out.println("Merging BAM Files..."); - // Merges the files - try { - final picard.sam.MergeSamFiles merger = new picard.sam.MergeSamFiles(); - final ArrayList args = new ArrayList<>(); - for (File input : inputs) { - args.add("INPUT=" + input.getAbsolutePath()); - } - args.add("OUTPUT=" + output.getAbsolutePath()); - if (useMultipleCpus) { - args.add("USE_THREADING=true"); - } - merger.instanceMain(args.toArray(new String[args.size()])); - System.out.println("BAM Files Merged"); - } catch (htsjdk.samtools.SAMException exception) { - System.out.println(exception.getMessage()); - } - } -} \ No newline at end of file diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSam.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSam.java new file mode 100644 index 000000000..46fc865ad --- /dev/null +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSam.java @@ -0,0 +1,33 @@ +package scriptmanager.scripts.BAM_Manipulation; +import htsjdk.samtools.SAMException; +import picard.sam.ValidateSamFile; +import htsjdk.samtools.SAMException; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; + +/** + * @author Erik Pavloski + * @see scriptmanager.window_interface.BAM_Manipulation.ValidateSamWindow - class still missing code + * + */ + + +public class ValidateSam { + public static void run(File input) throws IOException, SAMException{ + /** + * This method runs the picard tool validateSAMFile + * @param input - The BAM/SAm file to be Validated + * @throws IOException + * @throws SAMException + */ + System.out.println("Validating SAM/BAM file..."); + // Validates the SAM/BAM file + final picard.sam.ValidateSamFile validateSam = new picard.sam.ValidateSamFile(); + final ArrayList args = new ArrayList<>(); + args.add("INPUT=" + input.getAbsolutePath()); + validateSam.instanceMain(args.toArray(new String[args.size()])); + System.out.println("SAM/BAM file validated"); + } +} diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/BAIIndexerWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/BAIIndexerWindow.java index 1e1481523..27dee2d46 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/BAIIndexerWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/BAIIndexerWindow.java @@ -1,5 +1,7 @@ package scriptmanager.window_interface.BAM_Manipulation; +import htsjdk.samtools.SAMException; + import java.awt.Component; import java.awt.Container; import java.awt.Cursor; @@ -47,13 +49,19 @@ class Task extends SwingWorker { @Override public Void doInBackground() throws IOException { setProgress(0); - for(int x = 0; x < BAMFiles.size(); x++) { - BAIIndexer.generateIndex(BAMFiles.get(x)); - int percentComplete = (int)(((double)(x + 1) / BAMFiles.size()) * 100); - setProgress(percentComplete); - } - setProgress(100); - JOptionPane.showMessageDialog(null, "Indexing Complete"); + try { + for(int x = 0; x < BAMFiles.size(); x++) { + // Execute Picard wrapper + BAIIndexer.generateIndex(BAMFiles.get(x)); + // Update progress + int percentComplete = (int)(((double)(x + 1) / BAMFiles.size()) * 100); + setProgress(percentComplete); + } + setProgress(100); + JOptionPane.showMessageDialog(null, "Indexing Complete"); + } catch (SAMException se) { + JOptionPane.showMessageDialog(null, se.getMessage()); + } return null; } @@ -158,6 +166,3 @@ public void massXable(Container con, boolean status) { } } } - - - diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamFileWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamFileWindow.java new file mode 100644 index 000000000..f520c8e9f --- /dev/null +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamFileWindow.java @@ -0,0 +1,182 @@ +package scriptmanager.window_interface.BAM_Manipulation; + +import htsjdk.samtools.SAMException; +import scriptmanager.scripts.BAM_Manipulation.DownsampleSamFile; +import scriptmanager.util.FileSelection; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.IOException; +import java.util.Vector; + +/** + * @author Erik Pavloski + * This is the window class for DownsampleSam + */ +public class DownsampleSamFileWindow extends JFrame implements ActionListener, PropertyChangeListener { + private JPanel contentPane; + protected JFileChooser fc = new JFileChooser(new File(System.getProperty("user.dir"))); + + final DefaultListModel expList; + + Vector BAMFiles = new Vector(); + private JButton btnLoad; + private JButton btnRemoveBam; + private JButton btnDownSample; + + private JProgressBar progressBar; + public Task task; + + class Task extends SwingWorker { + double probability; + + public Task (double probability) { + this.probability = probability; + } + + @Override + public Void doInBackground() throws IOException { + setProgress(0); + try { + for (int x = 0; x < BAMFiles.size(); x++) { + // Execute picard wrapper + DownsampleSamFile.run(BAMFiles.get(x), probability); + // Update Progress + int percentComplete = (int) (((double) (x + 1) / BAMFiles.size()) * 100); + setProgress(percentComplete); + + } + setProgress(100); + JOptionPane.showMessageDialog(null, "Down-sampling Complete"); + return null; + } catch (SAMException sme) { + JOptionPane.showMessageDialog(null, sme.getMessage()); + return null; + } + } + + public void done() { + massXable(contentPane, true); + setCursor(null); + } + } + + public DownsampleSamFileWindow() { + setTitle("Downsample SAM/BAM File"); + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + + setBounds(125, 125, 450, 360); + contentPane = new JPanel(); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + SpringLayout sl_contentPane = new SpringLayout(); + contentPane.setLayout(sl_contentPane); + + JScrollPane scrollPane = new JScrollPane(); + sl_contentPane.putConstraint(SpringLayout.WEST, scrollPane, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, scrollPane, -5, SpringLayout.EAST, contentPane); + contentPane.add(scrollPane); + + expList = new DefaultListModel(); + final JList listExp = new JList(expList); + listExp.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + scrollPane.setViewportView(listExp); + + btnLoad = new JButton("Load BAM Files"); + sl_contentPane.putConstraint(SpringLayout.WEST, btnLoad, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 6, SpringLayout.SOUTH, btnLoad); + + btnLoad.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File[] newBAMFiles = FileSelection.getFiles(fc,"bam"); + if(newBAMFiles != null) { + for(int x = 0; x < newBAMFiles.length; x++) { + BAMFiles.add(newBAMFiles[x]); + expList.addElement(newBAMFiles[x].getName()); + } + } + } + }); + contentPane.add(btnLoad); + + btnRemoveBam = new JButton("Remove BAM"); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoad, 0, SpringLayout.NORTH, btnRemoveBam); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnRemoveBam, 0, SpringLayout.NORTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnRemoveBam, -5, SpringLayout.EAST, contentPane); + btnRemoveBam.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + while(listExp.getSelectedIndex() > -1) { + BAMFiles.remove(listExp.getSelectedIndex()); + expList.remove(listExp.getSelectedIndex()); + } + } + }); + contentPane.add(btnRemoveBam); + + + JLabel probabilityLabel = new JLabel("Probability: "); + sl_contentPane.putConstraint(SpringLayout.NORTH, probabilityLabel, 6, SpringLayout.SOUTH, scrollPane); + sl_contentPane.putConstraint(SpringLayout.WEST, probabilityLabel, 0, SpringLayout.WEST, scrollPane); + contentPane.add(probabilityLabel); + + JTextField probabilityField = new JTextField("0.5"); + probabilityField.setPreferredSize(new Dimension(50, probabilityField.getPreferredSize().height)); + sl_contentPane.putConstraint(SpringLayout.EAST, probabilityField, 50, SpringLayout.EAST, probabilityLabel); + sl_contentPane.putConstraint(SpringLayout.NORTH, probabilityField, 203, SpringLayout.NORTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.SOUTH, scrollPane, -4, SpringLayout.NORTH, probabilityField); + contentPane.add(probabilityField); + + btnDownSample = new JButton("Down-sample"); + sl_contentPane.putConstraint(SpringLayout.WEST, btnDownSample, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.SOUTH, btnDownSample, -10, SpringLayout.SOUTH, contentPane); + btnDownSample.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + massXable(contentPane, false); + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + double probability = Double.parseDouble(probabilityField.getText()); + task = new Task(probability); + task.addPropertyChangeListener(DownsampleSamFileWindow.this); + task.execute(); + } + }); + contentPane.add(btnDownSample); + + progressBar = new JProgressBar(); + sl_contentPane.putConstraint(SpringLayout.NORTH, progressBar, 3, SpringLayout.NORTH, btnDownSample); + sl_contentPane.putConstraint(SpringLayout.EAST, progressBar, 0, SpringLayout.EAST, scrollPane); + progressBar.setStringPainted(true); + contentPane.add(progressBar); + } + @Override + public void actionPerformed(ActionEvent arg0) { + massXable(contentPane, false); + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + task = new DownsampleSamFileWindow().task; + task.addPropertyChangeListener(this); + task.execute(); + } + /** + * Invoked when task's progress property changes. + */ + public void propertyChange(PropertyChangeEvent evt) { + if ("progress" == evt.getPropertyName()) { + int progress = (Integer) evt.getNewValue(); + progressBar.setValue(progress); + } + } + public void massXable(Container con, boolean status) { + for(Component c : con.getComponents()) { + c.setEnabled(status); + if(c instanceof Container) { massXable((Container)c, status); } + } + } + +} diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/MergeBAMWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/MergeBAMWindow.java index cb17592e6..3d20bdf4f 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/MergeBAMWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/MergeBAMWindow.java @@ -1,5 +1,7 @@ package scriptmanager.window_interface.BAM_Manipulation; +import htsjdk.samtools.SAMException; + import java.awt.Component; import java.awt.Container; import java.awt.Cursor; @@ -10,7 +12,6 @@ import java.beans.PropertyChangeListener; import java.io.File; import java.util.ArrayList; -import java.util.List; import javax.swing.DefaultListModel; import javax.swing.JButton; @@ -31,7 +32,7 @@ import scriptmanager.util.FileSelection; import scriptmanager.scripts.BAM_Manipulation.BAIIndexer; -import scriptmanager.scripts.BAM_Manipulation.MergeSamFiles; +import scriptmanager.scripts.BAM_Manipulation.MergeBAM; @SuppressWarnings("serial") public class MergeBAMWindow extends JFrame implements ActionListener, PropertyChangeListener { @@ -39,9 +40,9 @@ public class MergeBAMWindow extends JFrame implements ActionListener, PropertyCh protected JFileChooser fc = new JFileChooser(new File(System.getProperty("user.dir"))); final DefaultListModel expList; - List BAMFiles = new ArrayList(); + ArrayList BAMFiles = new ArrayList(); private File OUTPUT = null; - private File OUTPUT_PATH = null; + private File OUT_DIR = null; private JButton btnLoad; private JButton btnRemoveBam; @@ -59,13 +60,21 @@ class Task extends SwingWorker { @Override public Void doInBackground() throws Exception { setProgress(0); - if(OUTPUT_PATH != null) { OUTPUT = new File(OUTPUT_PATH.getCanonicalPath() + File.separator + txtOutput.getText()); } - else { OUTPUT = new File(txtOutput.getText()); } - MergeSamFiles.run(BAMFiles, OUTPUT, chckbxUseMultipleCpus.isSelected()); - if(chckbxGenerateBaiindex.isSelected()) { - BAIIndexer.generateIndex(OUTPUT); - } - JOptionPane.showMessageDialog(null, "Merging Complete"); + try { + // Build output filepath + if(OUT_DIR != null) { OUTPUT = new File(OUT_DIR.getCanonicalPath() + File.separator + txtOutput.getText()); } + else { OUTPUT = new File(txtOutput.getText()); } + // Execute Picard wrapper + MergeBAM.run(BAMFiles, OUTPUT, chckbxUseMultipleCpus.isSelected()); + // Index if checkbox selected + if(chckbxGenerateBaiindex.isSelected()) { + BAIIndexer.generateIndex(OUTPUT); + } + setProgress(100); + JOptionPane.showMessageDialog(null, "Merging Complete"); + } catch (SAMException se) { + JOptionPane.showMessageDialog(null, se.getMessage()); + } return null; } @@ -185,9 +194,10 @@ public void actionPerformed(ActionEvent arg0) { sl_contentPane.putConstraint(SpringLayout.EAST, btnOutput, -150, SpringLayout.EAST, contentPane); btnOutput.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - OUTPUT_PATH = FileSelection.getOutputDir(fc); - if(OUTPUT_PATH != null) { - lblDefaultToLocal.setText(OUTPUT_PATH.getAbsolutePath()); + File temp = FileSelection.getOutputDir(fc); + if(temp != null) { + OUT_DIR = temp; + lblDefaultToLocal.setText(OUT_DIR.getAbsolutePath()); } } }); diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/SortBAMWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/SortBAMWindow.java index 97362eb81..2cf424940 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/SortBAMWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/SortBAMWindow.java @@ -1,5 +1,7 @@ package scriptmanager.window_interface.BAM_Manipulation; +import htsjdk.samtools.SAMException; + import java.awt.Cursor; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -35,9 +37,9 @@ public class SortBAMWindow extends JFrame implements ActionListener, PropertyChangeListener { private JPanel contentPane; protected JFileChooser fc = new JFileChooser(new File(System.getProperty("user.dir"))); - + final DefaultListModel expList; - private File OUTPUT_PATH = null; + private File OUT_DIR = null; List BAMFiles = new ArrayList(); private JButton btnLoad; @@ -54,17 +56,25 @@ class Task extends SwingWorker { @Override public Void doInBackground() throws Exception { setProgress(0); - for(int x = 0; x < BAMFiles.size(); x++) { - String[] NAME = BAMFiles.get(x).getName().split("\\."); - File OUTPUT = null; - if(OUTPUT_PATH != null) { OUTPUT = new File(OUTPUT_PATH.getCanonicalPath() + File.separator + NAME[0] + "_sorted.bam"); } - else { OUTPUT = new File(NAME[0] + "_sorted.bam"); } - BAMFileSort.sort(BAMFiles.get(x), OUTPUT); - int percentComplete = (int)(((double)(x + 1) / BAMFiles.size()) * 100); - setProgress(percentComplete); - } - setProgress(100); - JOptionPane.showMessageDialog(null, "Sorting Complete"); + try { + for(int x = 0; x < BAMFiles.size(); x++) { + // Build output filepath + String[] NAME = BAMFiles.get(x).getName().split("\\."); + File OUTPUT = null; + if(OUT_DIR != null) { OUTPUT = new File(OUT_DIR.getCanonicalPath() + File.separator + NAME[0] + "_sorted.bam"); } + else { OUTPUT = new File(NAME[0] + "_sorted.bam"); } + // Execute Picard wrapper + BAMFileSort.sort(BAMFiles.get(x), OUTPUT); + // Update progress + int percentComplete = (int)(((double)(x + 1) / BAMFiles.size()) * 100); + setProgress(percentComplete); + + } + setProgress(100); + JOptionPane.showMessageDialog(null, "Sorting Complete"); + } catch (SAMException se) { + JOptionPane.showMessageDialog(null, se.getMessage()); + } return null; } @@ -144,9 +154,10 @@ public void actionPerformed(ActionEvent arg0) { btnOutput = new JButton("Output Directory"); btnOutput.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - OUTPUT_PATH = FileSelection.getOutputDir(fc); - if(OUTPUT_PATH != null) { - lblDefaultToLocal.setText(OUTPUT_PATH.getAbsolutePath()); + File temp = FileSelection.getOutputDir(fc); + if(temp != null) { + OUT_DIR = temp; + lblDefaultToLocal.setText(OUT_DIR.getAbsolutePath()); } } }); diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java new file mode 100644 index 000000000..28609d9ef --- /dev/null +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java @@ -0,0 +1,4 @@ +package scriptmanager.window_interface.BAM_Manipulation; + +public class ValidateSamWindow { +} From 75763b18d02578ac3612d7bf4806cdcdb4eab52d Mon Sep 17 00:00:00 2001 From: Erikpav Date: Thu, 8 Jun 2023 16:56:57 -0400 Subject: [PATCH 02/11] Added new features to DownsampleSamWindow and Wrapper --- .../scriptmanager/main/ScriptManagerGUI.java | 18 +- .../objects/ToolDescriptions.java | 2 +- ...SamFile.java => DownsampleSamWrapper.java} | 16 +- ...teSam.java => ValidateSamFileWrapper.java} | 4 +- .../DownsampleSamFileWindow.java | 182 --------- .../BAM_Manipulation/DownsampleSamWindow.java | 345 ++++++++++++++++++ 6 files changed, 364 insertions(+), 203 deletions(-) rename src/main/java/scriptmanager/scripts/BAM_Manipulation/{DownsampleSamFile.java => DownsampleSamWrapper.java} (79%) rename src/main/java/scriptmanager/scripts/BAM_Manipulation/{ValidateSam.java => ValidateSamFileWrapper.java} (91%) delete mode 100644 src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamFileWindow.java create mode 100644 src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamWindow.java diff --git a/src/main/java/scriptmanager/main/ScriptManagerGUI.java b/src/main/java/scriptmanager/main/ScriptManagerGUI.java index 4c586a5f1..da6b9424d 100755 --- a/src/main/java/scriptmanager/main/ScriptManagerGUI.java +++ b/src/main/java/scriptmanager/main/ScriptManagerGUI.java @@ -175,7 +175,10 @@ public void run() { JPanel pnlBamManip = new JPanel(); SpringLayout sl_pnlBamManip = new SpringLayout(); pnlBamManip.setLayout(sl_pnlBamManip); - pnlBamManip.setPreferredSize(new Dimension(200,400)); + + // This line keeps the width at default but modifies the height. + // This is required to allow for scrolling. It is set at 500 pixels to provide room for future tools + pnlBamManip.setPreferredSize(new Dimension(pnlBamManip.getPreferredSize().width, 500)); // Wrapped pnlBamManip in a scrollPane to support scrolling JScrollPane scrollPane = new JScrollPane(pnlBamManip); @@ -331,10 +334,13 @@ public void run() { sl_pnlBamManip.putConstraint(SpringLayout.WEST, txtFilterForPIPseq, 10, SpringLayout.EAST, btnFilterForPIPseq); pnlBamManip.add(btnFilterForPIPseq); + // DownsampleSam + JTextArea txtDownsample = new JTextArea(); - initializeTextArea(txtDownsample); - sl_pnlBamManip.putConstraint(SpringLayout.NORTH, txtDownsample, 10, SpringLayout.SOUTH, txtFilterForPIPseq); + sl_pnlBamManip.putConstraint(SpringLayout.NORTH, txtDownsample, 20, SpringLayout.SOUTH, txtFilterForPIPseq); sl_pnlBamManip.putConstraint(SpringLayout.EAST, txtDownsample, -10, SpringLayout.EAST, pnlBamManip); + initializeTextArea(txtDownsample); + txtDownsample.setText(ToolDescriptions.downsample_sam_description); pnlBamManip.add(txtDownsample); @@ -344,7 +350,7 @@ public void actionPerformed(ActionEvent e) { EventQueue.invokeLater(new Runnable() { public void run() { try { - DownsampleSamFileWindow frame = new DownsampleSamFileWindow(); + DownsampleSamWindow frame = new DownsampleSamWindow(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); @@ -353,11 +359,9 @@ public void run() { }); } }); - - sl_pnlBamManip.putConstraint(SpringLayout.SOUTH, btnDownsample, -45, SpringLayout.SOUTH, txtDownsample); + sl_pnlBamManip.putConstraint(SpringLayout.NORTH, btnDownsample, 0, SpringLayout.NORTH, txtDownsample); sl_pnlBamManip.putConstraint(SpringLayout.WEST, btnDownsample, 10, SpringLayout.WEST, pnlBamManip); sl_pnlBamManip.putConstraint(SpringLayout.WEST, txtDownsample, 10, SpringLayout.EAST, btnDownsample); - sl_pnlBamManip.putConstraint(SpringLayout.SOUTH, pnlBamManip, 25, SpringLayout.SOUTH, btnDownsample); pnlBamManip.add(btnDownsample); diff --git a/src/main/java/scriptmanager/objects/ToolDescriptions.java b/src/main/java/scriptmanager/objects/ToolDescriptions.java index 7c985a091..f05a19175 100644 --- a/src/main/java/scriptmanager/objects/ToolDescriptions.java +++ b/src/main/java/scriptmanager/objects/ToolDescriptions.java @@ -35,7 +35,7 @@ public class ToolDescriptions { public static final String remove_duplicates_description = "Removes duplicate reads in Paired-End sequencing given identical 5' read locations. RAM intensive process. If program freezes, increase JAVA heap size."; //* public static final String merge_bam_description = "Merges Multiple BAM files into single BAM file. Sorting is performed automatically. RAM intensive process. If program freezes, increase JAVA heap size."; //* public static final String filter_pip_seq_description = "Filter BAM file by -1 nucleotide. Requires genome FASTA file."; - public static final String downsample_sam_description = "This tool applies a downsampling algorithm to a SAM or BAM file to retain only a (deterministically random) subset of the reads"; + public static final String downsample_sam_description = "Downsample a BAM file to a specified percentage or read count of deterministically random reads."; // BAM Format Converter public static final String bam_to_scidx_description = "Convert BAM file to scIDX file."; diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamFile.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamWrapper.java similarity index 79% rename from src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamFile.java rename to src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamWrapper.java index fa7f4ec20..238a7fc4c 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamFile.java +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamWrapper.java @@ -1,18 +1,18 @@ package scriptmanager.scripts.BAM_Manipulation; import htsjdk.samtools.SAMException; -import scriptmanager.window_interface.BAM_Manipulation.DownsampleSamFileWindow; +import scriptmanager.window_interface.BAM_Manipulation.DownsampleSamWindow; import java.io.File; import java.io.IOException; import java.util.ArrayList; /** * @author Erik Pavloski - * @see DownsampleSamFileWindow + * @see DownsampleSamWindow * This code runs the Picard tool DownsampleSam * */ -public class DownsampleSamFile { +public class DownsampleSamWrapper { /** * The following code uses Picard's downsampleSAM tool to shink the BAM/SAM file * and retain a random subset of the reads based on the probability parameter @@ -25,21 +25,17 @@ public class DownsampleSamFile { * @throws IOException * @throws SAMException */ - public static void run(File input, double probability) throws IOException, SAMException { - File retVal; + public static void run(File input, File output, double probability, Long seed) throws IOException, SAMException { System.out.println("Down-sampling SAM/BAM file..."); - String output = input.getAbsolutePath() + ".downsampled.bam"; - retVal = new File(output); - // Downsamples the SAM/BAM file final picard.sam.DownsampleSam downsampleSam = new picard.sam.DownsampleSam(); final ArrayList args = new ArrayList<>(); args.add("INPUT=" + input.getAbsolutePath()); - args.add("OUTPUT=" + retVal.getAbsolutePath()); + args.add("OUTPUT=" + output.getAbsolutePath()); args.add("PROBABILITY=" + probability); + args.add("RANDOM_SEED=" + seed); downsampleSam.instanceMain(args.toArray(new String[args.size()])); - System.out.println("SAM/BAM file down-sampled"); } } diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSam.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamFileWrapper.java similarity index 91% rename from src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSam.java rename to src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamFileWrapper.java index 46fc865ad..7577593d5 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSam.java +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamFileWrapper.java @@ -1,7 +1,5 @@ package scriptmanager.scripts.BAM_Manipulation; import htsjdk.samtools.SAMException; -import picard.sam.ValidateSamFile; -import htsjdk.samtools.SAMException; import java.io.File; import java.io.IOException; @@ -14,7 +12,7 @@ */ -public class ValidateSam { +public class ValidateSamFileWrapper { public static void run(File input) throws IOException, SAMException{ /** * This method runs the picard tool validateSAMFile diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamFileWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamFileWindow.java deleted file mode 100644 index f520c8e9f..000000000 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamFileWindow.java +++ /dev/null @@ -1,182 +0,0 @@ -package scriptmanager.window_interface.BAM_Manipulation; - -import htsjdk.samtools.SAMException; -import scriptmanager.scripts.BAM_Manipulation.DownsampleSamFile; -import scriptmanager.util.FileSelection; - -import javax.swing.*; -import javax.swing.border.EmptyBorder; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.io.File; -import java.io.IOException; -import java.util.Vector; - -/** - * @author Erik Pavloski - * This is the window class for DownsampleSam - */ -public class DownsampleSamFileWindow extends JFrame implements ActionListener, PropertyChangeListener { - private JPanel contentPane; - protected JFileChooser fc = new JFileChooser(new File(System.getProperty("user.dir"))); - - final DefaultListModel expList; - - Vector BAMFiles = new Vector(); - private JButton btnLoad; - private JButton btnRemoveBam; - private JButton btnDownSample; - - private JProgressBar progressBar; - public Task task; - - class Task extends SwingWorker { - double probability; - - public Task (double probability) { - this.probability = probability; - } - - @Override - public Void doInBackground() throws IOException { - setProgress(0); - try { - for (int x = 0; x < BAMFiles.size(); x++) { - // Execute picard wrapper - DownsampleSamFile.run(BAMFiles.get(x), probability); - // Update Progress - int percentComplete = (int) (((double) (x + 1) / BAMFiles.size()) * 100); - setProgress(percentComplete); - - } - setProgress(100); - JOptionPane.showMessageDialog(null, "Down-sampling Complete"); - return null; - } catch (SAMException sme) { - JOptionPane.showMessageDialog(null, sme.getMessage()); - return null; - } - } - - public void done() { - massXable(contentPane, true); - setCursor(null); - } - } - - public DownsampleSamFileWindow() { - setTitle("Downsample SAM/BAM File"); - setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - - setBounds(125, 125, 450, 360); - contentPane = new JPanel(); - contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); - setContentPane(contentPane); - SpringLayout sl_contentPane = new SpringLayout(); - contentPane.setLayout(sl_contentPane); - - JScrollPane scrollPane = new JScrollPane(); - sl_contentPane.putConstraint(SpringLayout.WEST, scrollPane, 5, SpringLayout.WEST, contentPane); - sl_contentPane.putConstraint(SpringLayout.EAST, scrollPane, -5, SpringLayout.EAST, contentPane); - contentPane.add(scrollPane); - - expList = new DefaultListModel(); - final JList listExp = new JList(expList); - listExp.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); - scrollPane.setViewportView(listExp); - - btnLoad = new JButton("Load BAM Files"); - sl_contentPane.putConstraint(SpringLayout.WEST, btnLoad, 5, SpringLayout.WEST, contentPane); - sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 6, SpringLayout.SOUTH, btnLoad); - - btnLoad.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - File[] newBAMFiles = FileSelection.getFiles(fc,"bam"); - if(newBAMFiles != null) { - for(int x = 0; x < newBAMFiles.length; x++) { - BAMFiles.add(newBAMFiles[x]); - expList.addElement(newBAMFiles[x].getName()); - } - } - } - }); - contentPane.add(btnLoad); - - btnRemoveBam = new JButton("Remove BAM"); - sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoad, 0, SpringLayout.NORTH, btnRemoveBam); - sl_contentPane.putConstraint(SpringLayout.NORTH, btnRemoveBam, 0, SpringLayout.NORTH, contentPane); - sl_contentPane.putConstraint(SpringLayout.EAST, btnRemoveBam, -5, SpringLayout.EAST, contentPane); - btnRemoveBam.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent arg0) { - while(listExp.getSelectedIndex() > -1) { - BAMFiles.remove(listExp.getSelectedIndex()); - expList.remove(listExp.getSelectedIndex()); - } - } - }); - contentPane.add(btnRemoveBam); - - - JLabel probabilityLabel = new JLabel("Probability: "); - sl_contentPane.putConstraint(SpringLayout.NORTH, probabilityLabel, 6, SpringLayout.SOUTH, scrollPane); - sl_contentPane.putConstraint(SpringLayout.WEST, probabilityLabel, 0, SpringLayout.WEST, scrollPane); - contentPane.add(probabilityLabel); - - JTextField probabilityField = new JTextField("0.5"); - probabilityField.setPreferredSize(new Dimension(50, probabilityField.getPreferredSize().height)); - sl_contentPane.putConstraint(SpringLayout.EAST, probabilityField, 50, SpringLayout.EAST, probabilityLabel); - sl_contentPane.putConstraint(SpringLayout.NORTH, probabilityField, 203, SpringLayout.NORTH, contentPane); - sl_contentPane.putConstraint(SpringLayout.SOUTH, scrollPane, -4, SpringLayout.NORTH, probabilityField); - contentPane.add(probabilityField); - - btnDownSample = new JButton("Down-sample"); - sl_contentPane.putConstraint(SpringLayout.WEST, btnDownSample, 5, SpringLayout.WEST, contentPane); - sl_contentPane.putConstraint(SpringLayout.SOUTH, btnDownSample, -10, SpringLayout.SOUTH, contentPane); - btnDownSample.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - massXable(contentPane, false); - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - - double probability = Double.parseDouble(probabilityField.getText()); - task = new Task(probability); - task.addPropertyChangeListener(DownsampleSamFileWindow.this); - task.execute(); - } - }); - contentPane.add(btnDownSample); - - progressBar = new JProgressBar(); - sl_contentPane.putConstraint(SpringLayout.NORTH, progressBar, 3, SpringLayout.NORTH, btnDownSample); - sl_contentPane.putConstraint(SpringLayout.EAST, progressBar, 0, SpringLayout.EAST, scrollPane); - progressBar.setStringPainted(true); - contentPane.add(progressBar); - } - @Override - public void actionPerformed(ActionEvent arg0) { - massXable(contentPane, false); - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - - task = new DownsampleSamFileWindow().task; - task.addPropertyChangeListener(this); - task.execute(); - } - /** - * Invoked when task's progress property changes. - */ - public void propertyChange(PropertyChangeEvent evt) { - if ("progress" == evt.getPropertyName()) { - int progress = (Integer) evt.getNewValue(); - progressBar.setValue(progress); - } - } - public void massXable(Container con, boolean status) { - for(Component c : con.getComponents()) { - c.setEnabled(status); - if(c instanceof Container) { massXable((Container)c, status); } - } - } - -} diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamWindow.java new file mode 100644 index 000000000..63fcc89bd --- /dev/null +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamWindow.java @@ -0,0 +1,345 @@ +package scriptmanager.window_interface.BAM_Manipulation; + +import htsjdk.samtools.*; +import scriptmanager.scripts.BAM_Manipulation.DownsampleSamWrapper; +import scriptmanager.util.FileSelection; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.IOException; +import java.util.Iterator; +import java.util.Vector; + +/** + * @author Erik Pavloski + * This is the window class for DownsampleSam + */ +public class DownsampleSamWindow extends JFrame implements ActionListener, PropertyChangeListener { + private JPanel contentPane; + protected JFileChooser fc = new JFileChooser(new File(System.getProperty("user.dir"))); + + final DefaultListModel expList; + + Vector BAMFiles = new Vector(); + private JButton btnLoad; + private JButton btnRemoveBam; + private JButton btnDownSample; + private Long desiredReadCount; + private Long totalreadCount = Long.valueOf(0); + + private JButton btnOutput; + + private JLabel outputLabel; + + private JLabel lblDefaultToLocal; + + private JCheckBox useCustomSeedBox; + private JTextField seedField; + + + private Long seed; + private JCheckBox setReadCountBox; + private JTextField readCountField; + private File OUT_DIR = null; + + private JProgressBar progressBar; + public Task task; + + + + class Task extends SwingWorker { + double probability; + + public Task (double probability) { + this.probability = probability; + } + + @Override + public Void doInBackground() throws IOException{ + setProgress(0); + try { + for (int x = 0; x < BAMFiles.size(); x++) { + // Build output filepath + String[] NAME = BAMFiles.get(x).getName().split("\\."); + File OUTPUT = null; + if (OUT_DIR != null) { + OUTPUT = new File(OUT_DIR.getCanonicalPath() + File.separator + NAME[0] + "_downsampled.bam"); + } else { + OUTPUT = new File(NAME[0] + "_downsampled.bam"); + } + if (probability > 1 || probability < 0) { + JOptionPane.showMessageDialog(null, "Must enter a value between 0 and 1"); + } + + // Open BAM file for reading + SamReader reader = SamReaderFactory.makeDefault().open(BAMFiles.get(x)); + + // Get the header and record iterator + SAMFileHeader header = reader.getFileHeader(); + Iterator iterator = reader.iterator(); + + // Count the number of reads + while (iterator.hasNext()) { + iterator.next(); + totalreadCount++; + } + + // Close the reader + reader.close(); + + // Execute picard wrapper + DownsampleSamWrapper.run(BAMFiles.get(x), OUTPUT, probability, seed); + // Update Progress + int percentComplete = (int) (((double) (x + 1) / BAMFiles.size()) * 100); + setProgress(percentComplete); + + } + setProgress(100); + JOptionPane.showMessageDialog(null, "Down-sampling Complete"); + return null; + } catch (SAMException sme) { + JOptionPane.showMessageDialog(null, sme.getMessage()); + return null; + } + } + + public void done() { + massXable(contentPane, true); + setCursor(null); + } + } + + public DownsampleSamWindow() { + setTitle("Downsample SAM/BAM File"); + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + + setBounds(125, 125, 580, 450); + contentPane = new JPanel(); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + SpringLayout sl_contentPane = new SpringLayout(); + contentPane.setLayout(sl_contentPane); + + JScrollPane scrollPane = new JScrollPane(); + sl_contentPane.putConstraint(SpringLayout.WEST, scrollPane, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, scrollPane, -5, SpringLayout.EAST, contentPane); + contentPane.add(scrollPane); + + expList = new DefaultListModel(); + final JList listExp = new JList(expList); + listExp.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + scrollPane.setViewportView(listExp); + + btnLoad = new JButton("Load BAM Files"); + sl_contentPane.putConstraint(SpringLayout.WEST, btnLoad, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 6, SpringLayout.SOUTH, btnLoad); + + btnLoad.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File[] newBAMFiles = FileSelection.getFiles(fc,"bam"); + if(newBAMFiles != null) { + for(int x = 0; x < newBAMFiles.length; x++) { + BAMFiles.add(newBAMFiles[x]); + expList.addElement(newBAMFiles[x].getName()); + } + } + } + }); + contentPane.add(btnLoad); + + btnRemoveBam = new JButton("Remove BAM"); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoad, 0, SpringLayout.NORTH, btnRemoveBam); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnRemoveBam, 0, SpringLayout.NORTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnRemoveBam, -5, SpringLayout.EAST, contentPane); + btnRemoveBam.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + while(listExp.getSelectedIndex() > -1) { + BAMFiles.remove(listExp.getSelectedIndex()); + expList.remove(listExp.getSelectedIndex()); + } + } + }); + contentPane.add(btnRemoveBam); + + + JLabel probabilityLabel = new JLabel("Probability: "); + sl_contentPane.putConstraint(SpringLayout.NORTH, probabilityLabel, 10, SpringLayout.SOUTH, scrollPane); + sl_contentPane.putConstraint(SpringLayout.WEST, probabilityLabel, 0, SpringLayout.WEST, scrollPane); + contentPane.add(probabilityLabel); + + JTextField probabilityField = new JTextField("0.5"); + probabilityField.setPreferredSize(new Dimension(50, probabilityField.getPreferredSize().height)); + sl_contentPane.putConstraint(SpringLayout.NORTH, probabilityField, 10, SpringLayout.SOUTH, scrollPane); + sl_contentPane.putConstraint(SpringLayout.WEST, probabilityField, 5, SpringLayout.EAST, probabilityLabel); + contentPane.add(probabilityField); + + btnOutput = new JButton("Output Directory"); + btnOutput.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File temp = FileSelection.getOutputDir(fc); + if(temp != null) { + OUT_DIR = temp; + lblDefaultToLocal.setText(OUT_DIR.getAbsolutePath()); + } + } + }); + sl_contentPane.putConstraint(SpringLayout.SOUTH, scrollPane, -3, SpringLayout.NORTH, btnOutput); + sl_contentPane.putConstraint(SpringLayout.WEST, btnOutput, 200, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.SOUTH, btnOutput, -50, SpringLayout.SOUTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnOutput, -200, SpringLayout.EAST, contentPane); + contentPane.add(btnOutput); + + useCustomSeedBox = new JCheckBox("Custom Seed?"); + sl_contentPane.putConstraint(SpringLayout.EAST, useCustomSeedBox, 0, SpringLayout.EAST, scrollPane); + sl_contentPane.putConstraint(SpringLayout.WEST, useCustomSeedBox, 50, SpringLayout.EAST, btnOutput); + sl_contentPane.putConstraint(SpringLayout.NORTH, useCustomSeedBox, 5, SpringLayout.SOUTH, scrollPane); + contentPane.add(useCustomSeedBox); + + useCustomSeedBox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + boolean isChecked = useCustomSeedBox.isSelected(); + seedField.setEnabled(isChecked); + seedField.setText(""); + if (!isChecked) { + seedField.setText("Enter Custom Seed"); + seed = null; + } + } + }); + + seedField = new JTextField("Enter Custom Seed"); + seedField.setPreferredSize(new Dimension(65, seedField.getPreferredSize().height)); + sl_contentPane.putConstraint(SpringLayout.EAST, seedField, 0, SpringLayout.EAST, scrollPane); + sl_contentPane.putConstraint(SpringLayout.WEST, seedField, 50, SpringLayout.EAST, btnOutput); + sl_contentPane.putConstraint(SpringLayout.NORTH, seedField, 30, SpringLayout.SOUTH, scrollPane); + contentPane.add(seedField); + + seedField.setEnabled(false); + + setReadCountBox = new JCheckBox("Set # of reads?"); + sl_contentPane.putConstraint(SpringLayout.EAST, setReadCountBox, 5, SpringLayout.EAST, scrollPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, setReadCountBox, 55,SpringLayout.SOUTH, scrollPane); + sl_contentPane.putConstraint(SpringLayout.EAST, setReadCountBox, 30, SpringLayout.WEST, btnOutput); + contentPane.add(setReadCountBox); + + setReadCountBox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + boolean isChecked = setReadCountBox.isSelected(); + readCountField.setEnabled(isChecked); + probabilityField.setEnabled(!isChecked); + readCountField.setText(""); + if (!isChecked) { + readCountField.setText("Enter # of Reads"); + } + } + }); + + + + readCountField = new JTextField("Enter # of Reads"); + readCountField.setPreferredSize(new Dimension(120, readCountField.getPreferredSize().height)); + sl_contentPane.putConstraint(SpringLayout.EAST, readCountField, 5, SpringLayout.EAST, scrollPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, readCountField, 58,SpringLayout.SOUTH, scrollPane); + sl_contentPane.putConstraint(SpringLayout.EAST, readCountField, 160, SpringLayout.WEST, btnOutput); + contentPane.add(readCountField); + + readCountField.setEnabled(false); + + + outputLabel = new JLabel("Current Output:"); + sl_contentPane.putConstraint(SpringLayout.WEST, outputLabel, 0, SpringLayout.WEST, scrollPane); + sl_contentPane.putConstraint(SpringLayout.SOUTH, outputLabel, -30, SpringLayout.SOUTH, contentPane); + contentPane.add(outputLabel); + + lblDefaultToLocal = new JLabel("Default to Local Directory"); + sl_contentPane.putConstraint(SpringLayout.NORTH, lblDefaultToLocal, 1, SpringLayout.NORTH, outputLabel); + sl_contentPane.putConstraint(SpringLayout.WEST, lblDefaultToLocal, 6, SpringLayout.EAST, outputLabel); + lblDefaultToLocal.setBackground(Color.WHITE); + contentPane.add(lblDefaultToLocal); + + btnDownSample = new JButton("Down-sample"); + sl_contentPane.putConstraint(SpringLayout.WEST, btnDownSample, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.SOUTH, btnDownSample, 0, SpringLayout.SOUTH, contentPane); + btnDownSample.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + massXable(contentPane, false); + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + // These lines ensure that the program will run even if the user enters a string or other invalid characters + // The program will just default to 0.5 + double probability = 0.5; + if (setReadCountBox.isSelected()) { + try { + desiredReadCount = Long.parseLong(readCountField.getText()); + // Compare read count to desired read count + if (totalreadCount > desiredReadCount) { + // Set the probability value relative to the desired read count + probability = (double) desiredReadCount / totalreadCount; + } else { + // Set a default probability value + probability = 0.5; + } + } catch (NumberFormatException ex) { + JOptionPane.showMessageDialog(null, "Invalid read count. Please enter an integer value."); + return; + } + } else { + try { + probability = Double.parseDouble(probabilityField.getText()); + } catch (NumberFormatException nfe) { + JOptionPane.showMessageDialog(null, "Must enter a double value between 0 and 1. Due to improper input program will default to 0.5 probability"); + } + } + try { + seed = Long.parseLong(seedField.getText()); + } catch (NumberFormatException nfe) { + seed = null; + } + if (seed != null) { + task = new Task(seed); + } + task = new Task(probability); + task.addPropertyChangeListener(DownsampleSamWindow.this); + task.execute(); + + } + }); + contentPane.add(btnDownSample); + + progressBar = new JProgressBar(); + sl_contentPane.putConstraint(SpringLayout.NORTH, progressBar, 3, SpringLayout.NORTH, btnDownSample); + sl_contentPane.putConstraint(SpringLayout.EAST, progressBar, 0, SpringLayout.EAST, scrollPane); + progressBar.setStringPainted(true); + contentPane.add(progressBar); + } + @Override + public void actionPerformed(ActionEvent arg0) { + massXable(contentPane, false); + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + task = new DownsampleSamWindow().task; + task.addPropertyChangeListener(this); + task.execute(); + } + /** + * Invoked when task's progress property changes. + */ + public void propertyChange(PropertyChangeEvent evt) { + if ("progress" == evt.getPropertyName()) { + int progress = (Integer) evt.getNewValue(); + progressBar.setValue(progress); + } + } + public void massXable(Container con, boolean status) { + for(Component c : con.getComponents()) { + c.setEnabled(status); + if(c instanceof Container) { massXable((Container)c, status); } + } + } + +} From cf1961e8619b3d505948d24bd1bc790f1ff59992 Mon Sep 17 00:00:00 2001 From: Erikpav Date: Fri, 9 Jun 2023 15:44:30 -0400 Subject: [PATCH 03/11] Added ValidateSam Picard tool #122 Added two classes. ValidateSamWrapper and ValidateSamWindow. The ValidateSam tool allows for customization of the validation mode, maximum output in verbose mode, whether to generate an index or not, and output destination. Currently outputs a html file. Minor bug fixing related to DownsampleSam. The program now works as intended. Reworded the javadocs. Still unsure if those javadocs are perfect. --- .../scriptmanager/main/ScriptManagerGUI.java | 29 ++ .../objects/ToolDescriptions.java | 1 + .../DownsampleSamWrapper.java | 14 +- .../ValidateSamFileWrapper.java | 31 -- .../BAM_Manipulation/ValidateSamWrapper.java | 46 +++ .../BAM_Manipulation/DownsampleSamWindow.java | 4 +- .../BAM_Manipulation/ValidateSamWindow.java | 284 +++++++++++++++++- 7 files changed, 370 insertions(+), 39 deletions(-) delete mode 100644 src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamFileWrapper.java create mode 100644 src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamWrapper.java diff --git a/src/main/java/scriptmanager/main/ScriptManagerGUI.java b/src/main/java/scriptmanager/main/ScriptManagerGUI.java index da6b9424d..3590e9da8 100755 --- a/src/main/java/scriptmanager/main/ScriptManagerGUI.java +++ b/src/main/java/scriptmanager/main/ScriptManagerGUI.java @@ -364,6 +364,35 @@ public void run() { sl_pnlBamManip.putConstraint(SpringLayout.WEST, txtDownsample, 10, SpringLayout.EAST, btnDownsample); pnlBamManip.add(btnDownsample); + // ValidateSamFile + + JTextArea txtValidateSamFile = new JTextArea(); + sl_pnlBamManip.putConstraint(SpringLayout.NORTH, txtValidateSamFile, 20, SpringLayout.SOUTH, txtDownsample); + sl_pnlBamManip.putConstraint(SpringLayout.EAST, txtValidateSamFile, -10, SpringLayout.EAST, pnlBamManip); + initializeTextArea(txtValidateSamFile); + + txtValidateSamFile.setText(ToolDescriptions.validate_sam_file_description); + pnlBamManip.add(txtValidateSamFile); + + JButton btnValidateSamFile = new JButton("Validate SAM/BAM"); + btnValidateSamFile.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + EventQueue.invokeLater(new Runnable() { + public void run() { + try { + ValidateSamWindow frame = new ValidateSamWindow(); + frame.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + }); + sl_pnlBamManip.putConstraint(SpringLayout.NORTH, btnValidateSamFile, 0, SpringLayout.NORTH, txtValidateSamFile); + sl_pnlBamManip.putConstraint(SpringLayout.WEST, btnValidateSamFile, 10, SpringLayout.WEST, pnlBamManip); + sl_pnlBamManip.putConstraint(SpringLayout.WEST, txtValidateSamFile, 10, SpringLayout.EAST, btnValidateSamFile); + pnlBamManip.add(btnValidateSamFile); // >>>>>>>> BAM_Format_Converter <<<<<<<< JPanel pnlBamConvert = new JPanel(); diff --git a/src/main/java/scriptmanager/objects/ToolDescriptions.java b/src/main/java/scriptmanager/objects/ToolDescriptions.java index f05a19175..fe1438213 100644 --- a/src/main/java/scriptmanager/objects/ToolDescriptions.java +++ b/src/main/java/scriptmanager/objects/ToolDescriptions.java @@ -36,6 +36,7 @@ public class ToolDescriptions { public static final String merge_bam_description = "Merges Multiple BAM files into single BAM file. Sorting is performed automatically. RAM intensive process. If program freezes, increase JAVA heap size."; //* public static final String filter_pip_seq_description = "Filter BAM file by -1 nucleotide. Requires genome FASTA file."; public static final String downsample_sam_description = "Downsample a BAM file to a specified percentage or read count of deterministically random reads."; + public static final String validate_sam_file_description = "Validate SAM/BAM files comprehensively, ensuring adherence to the SAM format specification and detecting errors or inconsistencies in alignment data."; // BAM Format Converter public static final String bam_to_scidx_description = "Convert BAM file to scIDX file."; diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamWrapper.java index 238a7fc4c..92efbc5d5 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamWrapper.java +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamWrapper.java @@ -7,9 +7,10 @@ import java.io.IOException; import java.util.ArrayList; /** - * @author Erik Pavloski - * @see DownsampleSamWindow + * + * @see scriptmanager.window_interface.BAM_Manipulation.DownsampleSamWindow * This code runs the Picard tool DownsampleSam + * @author Erik Pavloski * */ public class DownsampleSamWrapper { @@ -18,15 +19,18 @@ public class DownsampleSamWrapper { * and retain a random subset of the reads based on the probability parameter * Output reads = (probability) * (input reads) * - * @param input - the BAM/SAM file to be down-sampled + * @param input - the BAM/SAM file to be downsampled + * @param output - the downsampled file * @param probability - the probability of keeping reads. * 0.5 default -> 50% reduction in data. * Smaller number -> less data once down-sampled + * @param seed - the custom seed that the user entered. + * Defaults to null if no custom seed is entered which just spools a random seed * @throws IOException * @throws SAMException */ public static void run(File input, File output, double probability, Long seed) throws IOException, SAMException { - System.out.println("Down-sampling SAM/BAM file..."); + System.out.println("Downsampling SAM/BAM file..."); // Downsamples the SAM/BAM file final picard.sam.DownsampleSam downsampleSam = new picard.sam.DownsampleSam(); @@ -36,6 +40,6 @@ public static void run(File input, File output, double probability, Long seed) t args.add("PROBABILITY=" + probability); args.add("RANDOM_SEED=" + seed); downsampleSam.instanceMain(args.toArray(new String[args.size()])); - System.out.println("SAM/BAM file down-sampled"); + System.out.println("SAM/BAM file downsampled"); } } diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamFileWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamFileWrapper.java deleted file mode 100644 index 7577593d5..000000000 --- a/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamFileWrapper.java +++ /dev/null @@ -1,31 +0,0 @@ -package scriptmanager.scripts.BAM_Manipulation; -import htsjdk.samtools.SAMException; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; - -/** - * @author Erik Pavloski - * @see scriptmanager.window_interface.BAM_Manipulation.ValidateSamWindow - class still missing code - * - */ - - -public class ValidateSamFileWrapper { - public static void run(File input) throws IOException, SAMException{ - /** - * This method runs the picard tool validateSAMFile - * @param input - The BAM/SAm file to be Validated - * @throws IOException - * @throws SAMException - */ - System.out.println("Validating SAM/BAM file..."); - // Validates the SAM/BAM file - final picard.sam.ValidateSamFile validateSam = new picard.sam.ValidateSamFile(); - final ArrayList args = new ArrayList<>(); - args.add("INPUT=" + input.getAbsolutePath()); - validateSam.instanceMain(args.toArray(new String[args.size()])); - System.out.println("SAM/BAM file validated"); - } -} diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamWrapper.java new file mode 100644 index 000000000..83310060a --- /dev/null +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamWrapper.java @@ -0,0 +1,46 @@ +package scriptmanager.scripts.BAM_Manipulation; +import htsjdk.samtools.SAMException; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; + +/** + * + * @see scriptmanager.window_interface.BAM_Manipulation.ValidateSamWindow - class still missing code + * This code runs the picard tool validateSAMFile + * @author Erik Pavloski + * + */ + + +public class ValidateSamWrapper { + public static void run(File input, File output, boolean mode, File referenceGenome, int maxOutput) throws IOException, SAMException{ + /** + * + * @param input - The BAM/SAM file to be Validated + * @param output - the output of the validation + * @param mode - Allows the user to select verbose or summary mode. True = verbose - false = summary + * @param referenceGenome - Allows the user to add reference sequence if needed + * @param maxOutput - Allows customization of the maximum number of outputs in verbose mode + * + * @throws IOException + * @throws SAMException + * + */ + System.out.println("Validating SAM/BAM file..."); + // Validates the SAM/BAM file + final picard.sam.ValidateSamFile validateSam = new picard.sam.ValidateSamFile(); + final ArrayList args = new ArrayList<>(); + args.add("INPUT=" + input.getAbsolutePath()); + args.add("OUTPUT=" + output.getAbsolutePath()); + String modeString = mode ? "VERBOSE" : "SUMMARY"; + args.add("MODE=" + modeString); + args.add("MAX_OUTPUT=" + maxOutput); + if (referenceGenome != null) { + args.add("REFERENCE_SEQUENCE=" + referenceGenome.getAbsolutePath()); + } + validateSam.instanceMain(args.toArray(new String[args.size()])); + System.out.println("SAM/BAM file validated"); + } +} diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamWindow.java index 63fcc89bd..0d76f2b37 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamWindow.java @@ -101,7 +101,7 @@ public Void doInBackground() throws IOException{ } setProgress(100); - JOptionPane.showMessageDialog(null, "Down-sampling Complete"); + JOptionPane.showMessageDialog(null, "Downsampling Complete"); return null; } catch (SAMException sme) { JOptionPane.showMessageDialog(null, sme.getMessage()); @@ -263,7 +263,7 @@ public void actionPerformed(ActionEvent e) { lblDefaultToLocal.setBackground(Color.WHITE); contentPane.add(lblDefaultToLocal); - btnDownSample = new JButton("Down-sample"); + btnDownSample = new JButton("Downsample"); sl_contentPane.putConstraint(SpringLayout.WEST, btnDownSample, 5, SpringLayout.WEST, contentPane); sl_contentPane.putConstraint(SpringLayout.SOUTH, btnDownSample, 0, SpringLayout.SOUTH, contentPane); btnDownSample.addActionListener(new ActionListener() { diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java index 28609d9ef..5009314f2 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java @@ -1,4 +1,286 @@ package scriptmanager.window_interface.BAM_Manipulation; -public class ValidateSamWindow { +import htsjdk.samtools.SAMException; +import scriptmanager.scripts.BAM_Manipulation.BAIIndexer; +import scriptmanager.scripts.BAM_Manipulation.ValidateSamWrapper; +import scriptmanager.util.FileSelection; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.IOException; +import java.util.Vector; + +public class ValidateSamWindow extends JFrame implements ActionListener, PropertyChangeListener { + private JPanel contentPane; + protected JFileChooser fc = new JFileChooser(new File(System.getProperty("user.dir"))); + + final DefaultListModel expList; + + Vector BAMFiles = new Vector(); + private File OUT_DIR = null; + private File GENOME = null; + private JButton btnLoad; + private JButton btnRemoveBam; + private JCheckBox chckbxGenerateBaiIndex; + private JCheckBox chckbxSummaryMode; + private JButton btnLoadGenome; + private JLabel lblReferenceGenome; + private JButton btnOutput; + + private JLabel outputLabel; + private JLabel maxLabel; + + private JTextField maxField; + + private JLabel lblDefaultToLocal; + private boolean mode; + + private JButton btnValidate; + private int maxOutput = 100; + private JProgressBar progressBar; + public Task task; + + + class Task extends SwingWorker { + + int maxOutput; + + public Task (int maxOutput) { + this.maxOutput = maxOutput; + } + + @Override + public Void doInBackground() throws IOException { + + setProgress(0); + try { + for(int x = 0; x < BAMFiles.size(); x++) { + // Build output filepath + String[] NAME = BAMFiles.get(x).getName().split("\\."); + File OUTPUT = null; + if (OUT_DIR != null) { + OUTPUT = new File(OUT_DIR.getCanonicalPath() + File.separator + NAME[0] + "_validated.html"); + } else { + OUTPUT = new File(NAME[0] + "_validated.html"); + } + if (chckbxGenerateBaiIndex.isSelected()) { + BAIIndexer.generateIndex(BAMFiles.get(x)); + } + if (chckbxSummaryMode.isSelected()) { + mode = false; + } else { + mode = true; + } + // Execute Picard wrapper + ValidateSamWrapper.run(BAMFiles.get(x), OUTPUT, mode, GENOME, maxOutput); + // Update progress + int percentComplete = (int)(((double)(x + 1) / BAMFiles.size()) * 100); + setProgress(percentComplete); + } + setProgress(100); + JOptionPane.showMessageDialog(null, "Validation Complete"); + } catch (SAMException se) { + JOptionPane.showMessageDialog(null, se.getMessage()); + } + return null; + } + + public void done() { + massXable(contentPane, true); + setCursor(null); //turn off the wait cursor + } + } + public ValidateSamWindow() { + setTitle("Validate SAM/BAM file"); + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + + setBounds(125, 125, 580, 450); + contentPane = new JPanel(); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + SpringLayout sl_contentPane = new SpringLayout(); + contentPane.setLayout(sl_contentPane); + + JScrollPane scrollPane = new JScrollPane(); + sl_contentPane.putConstraint(SpringLayout.WEST, scrollPane, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, scrollPane, -5, SpringLayout.EAST, contentPane); + contentPane.add(scrollPane); + + expList = new DefaultListModel(); + final JList listExp = new JList(expList); + listExp.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + scrollPane.setViewportView(listExp); + + btnLoad = new JButton("Load BAM Files"); + sl_contentPane.putConstraint(SpringLayout.WEST, btnLoad, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 6, SpringLayout.SOUTH, btnLoad); + + btnLoad.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File[] newBAMFiles = FileSelection.getFiles(fc,"bam"); + if(newBAMFiles != null) { + for(int x = 0; x < newBAMFiles.length; x++) { + BAMFiles.add(newBAMFiles[x]); + expList.addElement(newBAMFiles[x].getName()); + } + } + } + }); + contentPane.add(btnLoad); + + btnRemoveBam = new JButton("Remove BAM"); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoad, 0, SpringLayout.NORTH, btnRemoveBam); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnRemoveBam, 0, SpringLayout.NORTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnRemoveBam, -5, SpringLayout.EAST, contentPane); + btnRemoveBam.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + while(listExp.getSelectedIndex() > -1) { + BAMFiles.remove(listExp.getSelectedIndex()); + expList.remove(listExp.getSelectedIndex()); + } + } + }); + contentPane.add(btnRemoveBam); + + chckbxGenerateBaiIndex = new JCheckBox("Generate BAI Index?"); + sl_contentPane.putConstraint(SpringLayout.WEST, chckbxGenerateBaiIndex, 0, SpringLayout.WEST, scrollPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, chckbxGenerateBaiIndex, 10, SpringLayout.SOUTH, scrollPane); + chckbxGenerateBaiIndex.setSelected(false); + contentPane.add(chckbxGenerateBaiIndex); + + chckbxSummaryMode = new JCheckBox("Use Summary Mode?"); + sl_contentPane.putConstraint(SpringLayout.WEST, chckbxSummaryMode, 0, SpringLayout.WEST, scrollPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, chckbxSummaryMode, 10, SpringLayout.SOUTH, scrollPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, chckbxSummaryMode, 1, SpringLayout.SOUTH, chckbxGenerateBaiIndex); + chckbxSummaryMode.setSelected(false); + contentPane.add(chckbxSummaryMode); + + chckbxSummaryMode.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + boolean isChecked = chckbxSummaryMode.isSelected(); + maxField.setEnabled(!isChecked); + maxField.setText(""); + if (isChecked) { + maxField.setText(""); + maxOutput = 100; + } + } + }); + + btnLoadGenome = new JButton("Load Genome"); + btnLoadGenome.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File temp = FileSelection.getFile(fc, "fa"); + if (temp != null) { + GENOME = temp; + lblReferenceGenome.setText("Reference Genome: " + GENOME.getName()); + } + } + }); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoadGenome, 0, SpringLayout.NORTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.WEST, btnLoadGenome, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoadGenome, 30, SpringLayout.NORTH, btnLoad); + sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 30, SpringLayout.NORTH, btnLoadGenome); + contentPane.add(btnLoadGenome); + + lblReferenceGenome = new JLabel("Reference Genome: "); + sl_contentPane.putConstraint(SpringLayout.NORTH, lblReferenceGenome, 5, SpringLayout.NORTH, btnLoadGenome); + sl_contentPane.putConstraint(SpringLayout.WEST, lblReferenceGenome, 6, SpringLayout.EAST, btnLoadGenome); + contentPane.add(lblReferenceGenome); + + btnOutput = new JButton("Output Directory"); + btnOutput.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File temp = FileSelection.getOutputDir(fc); + if(temp != null) { + OUT_DIR = temp; + lblDefaultToLocal.setText(OUT_DIR.getAbsolutePath()); + } + } + }); + sl_contentPane.putConstraint(SpringLayout.SOUTH, scrollPane, -3, SpringLayout.NORTH, btnOutput); + sl_contentPane.putConstraint(SpringLayout.WEST, btnOutput, 200, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.SOUTH, btnOutput, -50, SpringLayout.SOUTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnOutput, -200, SpringLayout.EAST, contentPane); + contentPane.add(btnOutput); + + outputLabel = new JLabel("Current Output:"); + sl_contentPane.putConstraint(SpringLayout.WEST, outputLabel, 0, SpringLayout.WEST, scrollPane); + sl_contentPane.putConstraint(SpringLayout.SOUTH, outputLabel, 0, SpringLayout.SOUTH, contentPane); + contentPane.add(outputLabel); + + lblDefaultToLocal = new JLabel("Default to Local Directory"); + sl_contentPane.putConstraint(SpringLayout.NORTH, lblDefaultToLocal, 0, SpringLayout.NORTH, outputLabel); + sl_contentPane.putConstraint(SpringLayout.WEST, lblDefaultToLocal, 6, SpringLayout.EAST, outputLabel); + lblDefaultToLocal.setBackground(Color.WHITE); + contentPane.add(lblDefaultToLocal); + + btnValidate = new JButton("Validate"); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnValidate, 30, SpringLayout.NORTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnValidate, -5, SpringLayout.EAST, contentPane); + contentPane.add(btnValidate); + + maxLabel = new JLabel("Maximum Output"); + sl_contentPane.putConstraint(SpringLayout.EAST, maxLabel, 0, SpringLayout.EAST, scrollPane); + sl_contentPane.putConstraint(SpringLayout.WEST, maxLabel, 50, SpringLayout.EAST, btnOutput); + sl_contentPane.putConstraint(SpringLayout.NORTH, maxLabel, 5, SpringLayout.SOUTH, scrollPane); + contentPane.add(maxLabel); + + maxField = new JTextField(""); + maxField.setPreferredSize(new Dimension(65, maxField.getPreferredSize().height)); + sl_contentPane.putConstraint(SpringLayout.EAST, maxField, 0, SpringLayout.EAST, scrollPane); + sl_contentPane.putConstraint(SpringLayout.WEST, maxField, 50, SpringLayout.EAST, btnOutput); + sl_contentPane.putConstraint(SpringLayout.NORTH, maxField, 30, SpringLayout.SOUTH, scrollPane); + contentPane.add(maxField); + + progressBar = new JProgressBar(); + sl_contentPane.putConstraint(SpringLayout.NORTH, progressBar, -3, SpringLayout.NORTH, lblDefaultToLocal); + sl_contentPane.putConstraint(SpringLayout.EAST, progressBar, 0, SpringLayout.EAST, scrollPane); + progressBar.setStringPainted(true); + contentPane.add(progressBar); + + btnValidate.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + try { + maxOutput = Integer.parseInt(maxField.getText()); + } catch (NumberFormatException nfe) { + maxOutput = 100; + } + + task = new Task(maxOutput); + task.addPropertyChangeListener(ValidateSamWindow.this); + task.execute(); + } + }); + } + @Override + public void actionPerformed(ActionEvent arg0) { + massXable(contentPane, false); + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + task = new Task(maxOutput); + task.addPropertyChangeListener(this); + task.execute(); + } + /** + * Invoked when task's progress property changes. + */ + public void propertyChange(PropertyChangeEvent evt) { + if ("progress" == evt.getPropertyName()) { + int progress = (Integer) evt.getNewValue(); + progressBar.setValue(progress); + } + } + public void massXable(Container con, boolean status) { + for(Component c : con.getComponents()) { + c.setEnabled(status); + if(c instanceof Container) { massXable((Container)c, status); } + } + } } From 3480a2da6641be9c5df300fb7c978b7e6a55fe7b Mon Sep 17 00:00:00 2001 From: Erikpav Date: Fri, 9 Jun 2023 17:24:53 -0400 Subject: [PATCH 04/11] Updated JavaDocs for Validate and Downsample #122 Removed the dashes from the JavaDocs in the Wrapper classes for ValidateSam and DownsampleSam. Added a short JavaDocs that references the Wrapper in the Window classes. Also, reworked the Max Output feature in ValidateSam a slight bit so it has 100 (default) in the text box to show the user what that default value is. --- .../BAM_Manipulation/DownsampleSamWrapper.java | 12 ++++++------ .../BAM_Manipulation/ValidateSamWrapper.java | 13 ++++++------- .../BAM_Manipulation/DownsampleSamWindow.java | 3 ++- .../BAM_Manipulation/ValidateSamWindow.java | 12 +++++++++--- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamWrapper.java index 92efbc5d5..ba43dd8a5 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamWrapper.java +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamWrapper.java @@ -7,10 +7,10 @@ import java.io.IOException; import java.util.ArrayList; /** - * + * @author Erik Pavloski * @see scriptmanager.window_interface.BAM_Manipulation.DownsampleSamWindow * This code runs the Picard tool DownsampleSam - * @author Erik Pavloski + * * */ public class DownsampleSamWrapper { @@ -19,12 +19,12 @@ public class DownsampleSamWrapper { * and retain a random subset of the reads based on the probability parameter * Output reads = (probability) * (input reads) * - * @param input - the BAM/SAM file to be downsampled - * @param output - the downsampled file - * @param probability - the probability of keeping reads. + * @param input the BAM/SAM file to be downsampled + * @param output the downsampled file + * @param probability the probability of keeping reads. * 0.5 default -> 50% reduction in data. * Smaller number -> less data once down-sampled - * @param seed - the custom seed that the user entered. + * @param seed the custom seed that the user entered. * Defaults to null if no custom seed is entered which just spools a random seed * @throws IOException * @throws SAMException diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamWrapper.java index 83310060a..a219d4a73 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamWrapper.java +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamWrapper.java @@ -6,10 +6,9 @@ import java.util.ArrayList; /** - * + * @author Erik Pavloski * @see scriptmanager.window_interface.BAM_Manipulation.ValidateSamWindow - class still missing code * This code runs the picard tool validateSAMFile - * @author Erik Pavloski * */ @@ -18,11 +17,11 @@ public class ValidateSamWrapper { public static void run(File input, File output, boolean mode, File referenceGenome, int maxOutput) throws IOException, SAMException{ /** * - * @param input - The BAM/SAM file to be Validated - * @param output - the output of the validation - * @param mode - Allows the user to select verbose or summary mode. True = verbose - false = summary - * @param referenceGenome - Allows the user to add reference sequence if needed - * @param maxOutput - Allows customization of the maximum number of outputs in verbose mode + * @param input The BAM/SAM file to be Validated + * @param output the output of the validation + * @param mode Allows the user to select verbose or summary mode. True = verbose - false = summary + * @param referenceGenome Allows the user to add reference sequence if needed + * @param maxOutput Allows customization of the maximum number of outputs in verbose mode * * @throws IOException * @throws SAMException diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamWindow.java index 0d76f2b37..37c633124 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamWindow.java @@ -18,7 +18,8 @@ /** * @author Erik Pavloski - * This is the window class for DownsampleSam + * This is the window class for DownsampleSamWrapper + * @see scriptmanager.scripts.BAM_Manipulation.DownsampleSamWrapper */ public class DownsampleSamWindow extends JFrame implements ActionListener, PropertyChangeListener { private JPanel contentPane; diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java index 5009314f2..bff1c8f56 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java @@ -16,6 +16,12 @@ import java.io.IOException; import java.util.Vector; +/** + * @author Erik Pavloski + * This is the window class for ValidateSamWrapper + * @see scriptmanager.scripts.BAM_Manipulation.ValidateSamWrapper + */ + public class ValidateSamWindow extends JFrame implements ActionListener, PropertyChangeListener { private JPanel contentPane; protected JFileChooser fc = new JFileChooser(new File(System.getProperty("user.dir"))); @@ -42,7 +48,7 @@ public class ValidateSamWindow extends JFrame implements ActionListener, Proper private boolean mode; private JButton btnValidate; - private int maxOutput = 100; + private int maxOutput; private JProgressBar progressBar; public Task task; @@ -165,7 +171,7 @@ public void actionPerformed(ActionEvent arg0) { public void actionPerformed(ActionEvent e) { boolean isChecked = chckbxSummaryMode.isSelected(); maxField.setEnabled(!isChecked); - maxField.setText(""); + maxField.setText("100"); if (isChecked) { maxField.setText(""); maxOutput = 100; @@ -232,7 +238,7 @@ public void actionPerformed(ActionEvent e) { sl_contentPane.putConstraint(SpringLayout.NORTH, maxLabel, 5, SpringLayout.SOUTH, scrollPane); contentPane.add(maxLabel); - maxField = new JTextField(""); + maxField = new JTextField("100"); maxField.setPreferredSize(new Dimension(65, maxField.getPreferredSize().height)); sl_contentPane.putConstraint(SpringLayout.EAST, maxField, 0, SpringLayout.EAST, scrollPane); sl_contentPane.putConstraint(SpringLayout.WEST, maxField, 50, SpringLayout.EAST, btnOutput); From 78754eca0447e44cbb5231c8c0517f7229bdf231 Mon Sep 17 00:00:00 2001 From: Erikpav Date: Mon, 12 Jun 2023 19:04:30 -0400 Subject: [PATCH 05/11] Added SamFormatConverter and SamtoFastq #122 Added two new tools. SamFormatConverter converts a SAM file to a BAM file or vice versa. SamtoFastq converts a BAM file to a FASTQ file. It has two features both of which are experiencing errors causing no output. However the default configuration runs fine. Did some minor code cleanup on ValidateSam as well. Along with an additial condition being handled in DownsampleSam. Before, when a user entered a desired maximum number of reads to be outputted that is larger than the total number of reads, the program would default to 0.5 probability without alerting the user. A JOptionPane now tells the user this fact. Also, added the option to load a SAM file instead of a BAM file for DownsampleSam and ValidateSam. --- .../scriptmanager/main/ScriptManagerGUI.java | 63 ++++- .../objects/ToolDescriptions.java | 2 + .../SamFormatConverterWrapper.java | 33 +++ .../SamtoFastqWrapper.java | 43 ++++ .../BAM_Manipulation/ValidateSamWrapper.java | 2 +- .../SamFormatConverterWindow.java | 221 +++++++++++++++++ .../SamtoFastqWindow.java | 231 ++++++++++++++++++ .../BAM_Manipulation/DownsampleSamWindow.java | 37 ++- .../BAM_Manipulation/ValidateSamWindow.java | 45 ++-- 9 files changed, 649 insertions(+), 28 deletions(-) create mode 100644 src/main/java/scriptmanager/scripts/BAM_Format_Converter/SamFormatConverterWrapper.java create mode 100644 src/main/java/scriptmanager/scripts/BAM_Format_Converter/SamtoFastqWrapper.java create mode 100644 src/main/java/scriptmanager/window_interface/BAM_Format_Converter/SamFormatConverterWindow.java create mode 100644 src/main/java/scriptmanager/window_interface/BAM_Format_Converter/SamtoFastqWindow.java diff --git a/src/main/java/scriptmanager/main/ScriptManagerGUI.java b/src/main/java/scriptmanager/main/ScriptManagerGUI.java index 3590e9da8..1ddbf2ca3 100755 --- a/src/main/java/scriptmanager/main/ScriptManagerGUI.java +++ b/src/main/java/scriptmanager/main/ScriptManagerGUI.java @@ -8,14 +8,11 @@ import scriptmanager.objects.ToolDescriptions; +import scriptmanager.window_interface.BAM_Format_Converter.*; import scriptmanager.window_interface.BAM_Manipulation.*; import scriptmanager.window_interface.BAM_Statistics.PEStatWindow; import scriptmanager.window_interface.BAM_Statistics.SEStatWindow; import scriptmanager.window_interface.BAM_Statistics.BAMGenomeCorrelationWindow; -import scriptmanager.window_interface.BAM_Format_Converter.BAMtoBEDWindow; -import scriptmanager.window_interface.BAM_Format_Converter.BAMtoGFFWindow; -import scriptmanager.window_interface.BAM_Format_Converter.BAMtobedGraphWindow; -import scriptmanager.window_interface.BAM_Format_Converter.BAMtoscIDXWindow; import scriptmanager.window_interface.Peak_Analysis.BEDPeakAligntoRefWindow; import scriptmanager.window_interface.Peak_Analysis.FilterBEDbyProximityWindow; import scriptmanager.window_interface.Peak_Analysis.RandomCoordinateWindow; @@ -515,6 +512,64 @@ public void run() { sl_pnlBamConvert.putConstraint(SpringLayout.WEST, txtBamToBedgraph, 10, SpringLayout.EAST, btnBamToBedgraph); pnlBamConvert.add(btnBamToBedgraph); + // >SamtoFastq + JTextArea txtSamtoFastq = new JTextArea(); + initializeTextArea(txtSamtoFastq); + txtSamtoFastq.setText(ToolDescriptions.sam_to_fastq_description); + sl_pnlBamConvert.putConstraint(SpringLayout.NORTH, txtSamtoFastq, 10, SpringLayout.SOUTH, txtBamToBedgraph); + sl_pnlBamConvert.putConstraint(SpringLayout.NORTH, txtSamtoFastq, 10, SpringLayout.SOUTH, btnBamToBedgraph); + sl_pnlBamConvert.putConstraint(SpringLayout.EAST, txtSamtoFastq, -10, SpringLayout.EAST, pnlBamConvert); + pnlBamConvert.add(txtSamtoFastq); + + JButton btnSamtoFastq = new JButton("BAM to FASTQ"); + btnSamtoFastq.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + EventQueue.invokeLater(new Runnable() { + public void run() { + try { + SamtoFastqWindow frame = new SamtoFastqWindow(); + frame.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + }); + sl_pnlBamConvert.putConstraint(SpringLayout.NORTH, btnSamtoFastq, 0, SpringLayout.NORTH, txtSamtoFastq); + sl_pnlBamConvert.putConstraint(SpringLayout.WEST, btnSamtoFastq, 10, SpringLayout.WEST, pnlBamConvert); + sl_pnlBamConvert.putConstraint(SpringLayout.WEST, txtSamtoFastq, 10, SpringLayout.EAST, btnSamtoFastq); + pnlBamConvert.add(btnSamtoFastq); + + // >SamFormatConverter + JTextArea txtSamFormatConverter = new JTextArea(); + initializeTextArea(txtSamtoFastq); + txtSamFormatConverter.setText(ToolDescriptions.sam_format_converter_description); + sl_pnlBamConvert.putConstraint(SpringLayout.NORTH, txtSamFormatConverter, 10, SpringLayout.SOUTH, txtSamtoFastq); + sl_pnlBamConvert.putConstraint(SpringLayout.NORTH, txtSamFormatConverter, 10, SpringLayout.SOUTH, btnSamtoFastq); + sl_pnlBamConvert.putConstraint(SpringLayout.EAST, txtSamFormatConverter, -10, SpringLayout.EAST, pnlBamConvert); + pnlBamConvert.add(txtSamFormatConverter); + + JButton btnSamFormatConverter = new JButton("SAM to BAM or BAM to SAM"); + btnSamFormatConverter.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + EventQueue.invokeLater(new Runnable() { + public void run() { + try { + SamFormatConverterWindow frame = new SamFormatConverterWindow(); + frame.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + }); + sl_pnlBamConvert.putConstraint(SpringLayout.NORTH, btnSamFormatConverter, 0, SpringLayout.NORTH, txtSamFormatConverter); + sl_pnlBamConvert.putConstraint(SpringLayout.WEST, btnSamFormatConverter, 10, SpringLayout.WEST, pnlBamConvert); + sl_pnlBamConvert.putConstraint(SpringLayout.WEST, txtSamFormatConverter, 10, SpringLayout.EAST, btnSamFormatConverter); + pnlBamConvert.add(btnSamFormatConverter); + // >>>>>>>> File_Utilities <<<<<<<< JPanel pnlFileUtility = new JPanel(); SpringLayout sl_pnlFileUtility = new SpringLayout(); diff --git a/src/main/java/scriptmanager/objects/ToolDescriptions.java b/src/main/java/scriptmanager/objects/ToolDescriptions.java index fe1438213..78aa98886 100644 --- a/src/main/java/scriptmanager/objects/ToolDescriptions.java +++ b/src/main/java/scriptmanager/objects/ToolDescriptions.java @@ -43,6 +43,8 @@ public class ToolDescriptions { public static final String bam_to_gff_description = "Convert BAM file to GFF file."; public static final String bam_to_bed_description = "Convert BAM file to BED file."; public static final String bam_to_bedgraph_description = "Convert BAM file to bedGraph file."; + public static final String sam_to_fastq_description = "Convert BAM file to FASTQ file"; + public static final String sam_format_converter_description = "Convert SAM file to Bam file or Bam file to Sam file"; // File Utilities public static final String md5checksum_description = "Calculate MD5 checksum for files."; diff --git a/src/main/java/scriptmanager/scripts/BAM_Format_Converter/SamFormatConverterWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Format_Converter/SamFormatConverterWrapper.java new file mode 100644 index 000000000..ac2055ae9 --- /dev/null +++ b/src/main/java/scriptmanager/scripts/BAM_Format_Converter/SamFormatConverterWrapper.java @@ -0,0 +1,33 @@ +package scriptmanager.scripts.BAM_Format_Converter; +import htsjdk.samtools.SAMException; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; + +/** + * @author Erik Pavloski + * @see scriptmanager.window_interface.BAM_Format_Converter.SamFormatConverterWindow + * This code runs the Picard tool SamFormatConverter + * It can swap a SAM file to a BAM file and vice versa + */ + +public class SamFormatConverterWrapper { + public static void run(File input, File output) throws IOException, SAMException { + /** + * @param input the BAM/SAM file to be converted + * @param output the output BAM/SAM file + * + * @throws IOException + * @throws SAMException + */ + System.out.println("Converting file..."); + // Converts the SAM/BAM file to fastq + final picard.sam.SamFormatConverter samFormatConverter = new picard.sam.SamFormatConverter(); + final ArrayList args = new ArrayList<>(); + args.add("INPUT=" + input.getAbsolutePath()); + args.add("OUTPUT=" + output.getAbsolutePath()); + samFormatConverter.instanceMain(args.toArray(new String[args.size()])); + System.out.println("File converted"); + } +} diff --git a/src/main/java/scriptmanager/scripts/BAM_Format_Converter/SamtoFastqWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Format_Converter/SamtoFastqWrapper.java new file mode 100644 index 000000000..e763f4282 --- /dev/null +++ b/src/main/java/scriptmanager/scripts/BAM_Format_Converter/SamtoFastqWrapper.java @@ -0,0 +1,43 @@ +package scriptmanager.scripts.BAM_Format_Converter; +import htsjdk.samtools.SAMException; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; + +/** + * @author Erik Pavloski + * @see scriptmanager.window_interface.BAM_Format_Converter.SamtoFastqWindow + * This code runs the Picard tool SamtoFastq + */ + +public class SamtoFastqWrapper { +public static void run(File input, File output, boolean compress, boolean perRG, File outputDir) throws IOException, SAMException { + /** + * @param input the BAM/SAM file to be converted + * @param output the output fastq file + * @param compress a boolean to determine whether to compress the output or not + * default = false = do not compress + * @param perRG a boolean to determine whether to output per read group. Compress does this as well + * @param outputDir the output directory + * @throws IOException + * @throws SAMException + */ + System.out.println("Converting file..."); + // Converts the SAM/BAM file to fastq + final picard.sam.SamToFastq samToFastq = new picard.sam.SamToFastq(); + final ArrayList args = new ArrayList<>(); + args.add("INPUT=" + input.getAbsolutePath()); + if (compress) { + args.add("COMPRESS_OUTPUTS_PER_RG=" + true); + args.add("OUTPUT_DIR=" + outputDir.getCanonicalPath()); + } else if (perRG) { + args.add("OUTPUT_PER_RG=" + true); + args.add("OUTPUT_DIR=" + outputDir.getCanonicalPath()); + } else { + args.add("FASTQ=" + output.getAbsolutePath()); + } + samToFastq.instanceMain(args.toArray(new String[args.size()])); + System.out.println("File converted"); + } +} diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamWrapper.java index a219d4a73..8df4e062f 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamWrapper.java +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamWrapper.java @@ -7,7 +7,7 @@ /** * @author Erik Pavloski - * @see scriptmanager.window_interface.BAM_Manipulation.ValidateSamWindow - class still missing code + * @see scriptmanager.window_interface.BAM_Manipulation.ValidateSamWindow * This code runs the picard tool validateSAMFile * */ diff --git a/src/main/java/scriptmanager/window_interface/BAM_Format_Converter/SamFormatConverterWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Format_Converter/SamFormatConverterWindow.java new file mode 100644 index 000000000..8f3a20f31 --- /dev/null +++ b/src/main/java/scriptmanager/window_interface/BAM_Format_Converter/SamFormatConverterWindow.java @@ -0,0 +1,221 @@ +package scriptmanager.window_interface.BAM_Format_Converter; + +import htsjdk.samtools.SAMException; +import scriptmanager.scripts.BAM_Format_Converter.SamFormatConverterWrapper; +import scriptmanager.scripts.BAM_Format_Converter.SamtoFastqWrapper; +import scriptmanager.util.FileSelection; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.IOException; +import java.util.Vector; + +public class SamFormatConverterWindow extends JFrame implements ActionListener, PropertyChangeListener { + private JPanel contentPane; + protected JFileChooser fc = new JFileChooser(new File(System.getProperty("user.dir"))); + + final DefaultListModel expList; + + Vector BAMFiles = new Vector(); + private File OUT_DIR = null; + + private JButton btnLoadBam; + private JButton btnLoadSam; + private JButton btnRemoveBam; + private JButton btnOutput; + private JLabel outputLabel; + private JLabel lblDefaultToLocal; + private JButton btnConvert; + private JProgressBar progressBar; + public SamFormatConverterWindow.Task task; + + class Task extends SwingWorker { + + @Override + public Void doInBackground() throws IOException { + setProgress(0); + try { + for(int x = 0; x < BAMFiles.size(); x++) { + // Build output filepath + String[] NAME = BAMFiles.get(x).getName().split("\\."); + File OUTPUT = null; + if (BAMFiles.get(x).getName().contains("sam")) { + if (OUT_DIR != null) { + OUTPUT = new File(OUT_DIR.getCanonicalPath() + File.separator + NAME[0] + "_converted.bam"); + } else { + OUTPUT = new File(NAME[0] + "_converted.bam"); + } + } else { + if (OUT_DIR != null) { + OUTPUT = new File(OUT_DIR.getCanonicalPath() + File.separator + NAME[0] + "_converted.sam"); + } else { + OUTPUT = new File(NAME[0] + "_converted.sam"); + } + } + + // Execute Picard wrapper + SamFormatConverterWrapper.run(BAMFiles.get(x), OUTPUT); + // Update progress + int percentComplete = (int)(((double)(x + 1) / BAMFiles.size()) * 100); + setProgress(percentComplete); + } + setProgress(100); + JOptionPane.showMessageDialog(null, "Conversion Complete"); + } catch (SAMException se) { + JOptionPane.showMessageDialog(null, se.getMessage()); + } + return null; + } + + public void done() { + massXable(contentPane, true); + setCursor(null); //turn off the wait cursor + } + } + public SamFormatConverterWindow() { + setTitle("Convert SAM to BAM or BAM to SAM"); + setBounds(125, 125, 480, 450); + contentPane = new JPanel(); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + SpringLayout sl_contentPane = new SpringLayout(); + contentPane.setLayout(sl_contentPane); + + JScrollPane scrollPane = new JScrollPane(); + sl_contentPane.putConstraint(SpringLayout.WEST, scrollPane, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, scrollPane, -5, SpringLayout.EAST, contentPane); + contentPane.add(scrollPane); + + expList = new DefaultListModel(); + final JList listExp = new JList(expList); + listExp.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + scrollPane.setViewportView(listExp); + + btnLoadBam = new JButton("Load BAM Files"); + sl_contentPane.putConstraint(SpringLayout.WEST, btnLoadBam, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 6, SpringLayout.SOUTH, btnLoadBam); + + btnLoadBam.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File[] newBAMFiles = FileSelection.getFiles(fc,"bam"); + if(newBAMFiles != null) { + for(int x = 0; x < newBAMFiles.length; x++) { + BAMFiles.add(newBAMFiles[x]); + expList.addElement(newBAMFiles[x].getName()); + } + } + } + }); + contentPane.add(btnLoadBam); + + btnRemoveBam = new JButton("Remove BAM"); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoadBam, 0, SpringLayout.NORTH, btnRemoveBam); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnRemoveBam, 0, SpringLayout.NORTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnRemoveBam, -5, SpringLayout.EAST, contentPane); + btnRemoveBam.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + while(listExp.getSelectedIndex() > -1) { + BAMFiles.remove(listExp.getSelectedIndex()); + expList.remove(listExp.getSelectedIndex()); + } + } + }); + contentPane.add(btnRemoveBam); + + btnLoadSam = new JButton("Load SAM Files"); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoadSam, 0, SpringLayout.NORTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.WEST, btnLoadSam, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoadSam, 30, SpringLayout.NORTH, btnLoadBam); + sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 30, SpringLayout.NORTH, btnLoadSam); + + btnLoadSam.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File[] newBAMFiles = FileSelection.getFiles(fc,"sam"); + if(newBAMFiles != null) { + for(int x = 0; x < newBAMFiles.length; x++) { + BAMFiles.add(newBAMFiles[x]); + expList.addElement(newBAMFiles[x].getName()); + } + } + } + }); + contentPane.add(btnLoadSam); + + btnOutput = new JButton("Output Directory"); + btnOutput.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File temp = FileSelection.getOutputDir(fc); + if(temp != null) { + OUT_DIR = temp; + lblDefaultToLocal.setText(OUT_DIR.getAbsolutePath()); + } + } + }); + sl_contentPane.putConstraint(SpringLayout.SOUTH, scrollPane, -3, SpringLayout.NORTH, btnOutput); + sl_contentPane.putConstraint(SpringLayout.WEST, btnOutput, 150, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.SOUTH, btnOutput, -50, SpringLayout.SOUTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnOutput, -150, SpringLayout.EAST, contentPane); + contentPane.add(btnOutput); + + outputLabel = new JLabel("Current Output:"); + sl_contentPane.putConstraint(SpringLayout.WEST, outputLabel, 0, SpringLayout.WEST, scrollPane); + sl_contentPane.putConstraint(SpringLayout.SOUTH, outputLabel, 0, SpringLayout.SOUTH, contentPane); + contentPane.add(outputLabel); + + lblDefaultToLocal = new JLabel("Default to Local Directory"); + sl_contentPane.putConstraint(SpringLayout.NORTH, lblDefaultToLocal, 0, SpringLayout.NORTH, outputLabel); + sl_contentPane.putConstraint(SpringLayout.WEST, lblDefaultToLocal, 6, SpringLayout.EAST, outputLabel); + lblDefaultToLocal.setBackground(Color.WHITE); + contentPane.add(lblDefaultToLocal); + + btnConvert = new JButton("Convert"); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnConvert, 2, SpringLayout.SOUTH, scrollPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnConvert, -5, SpringLayout.EAST, contentPane); + contentPane.add(btnConvert); + + progressBar = new JProgressBar(); + sl_contentPane.putConstraint(SpringLayout.NORTH, progressBar, -3, SpringLayout.NORTH, lblDefaultToLocal); + sl_contentPane.putConstraint(SpringLayout.EAST, progressBar, 0, SpringLayout.EAST, scrollPane); + progressBar.setStringPainted(true); + contentPane.add(progressBar); + + + btnConvert.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + task = new Task(); + task.addPropertyChangeListener(SamFormatConverterWindow.this); + task.execute(); + } + }); + } + @Override + public void actionPerformed(ActionEvent arg0) { + massXable(contentPane, false); + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + task = new Task(); + task.addPropertyChangeListener(this); + task.execute(); + } + /** + * Invoked when task's progress property changes. + */ + public void propertyChange(PropertyChangeEvent evt) { + if ("progress" == evt.getPropertyName()) { + int progress = (Integer) evt.getNewValue(); + progressBar.setValue(progress); + } + } + public void massXable(Container con, boolean status) { + for(Component c : con.getComponents()) { + c.setEnabled(status); + if(c instanceof Container) { massXable((Container)c, status); } + } + } +} diff --git a/src/main/java/scriptmanager/window_interface/BAM_Format_Converter/SamtoFastqWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Format_Converter/SamtoFastqWindow.java new file mode 100644 index 000000000..347acf844 --- /dev/null +++ b/src/main/java/scriptmanager/window_interface/BAM_Format_Converter/SamtoFastqWindow.java @@ -0,0 +1,231 @@ +package scriptmanager.window_interface.BAM_Format_Converter; + +import htsjdk.samtools.SAMException; +import scriptmanager.scripts.BAM_Format_Converter.SamtoFastqWrapper; +import scriptmanager.scripts.BAM_Manipulation.BAIIndexer; +import scriptmanager.scripts.BAM_Manipulation.ValidateSamWrapper; +import scriptmanager.util.FileSelection; +import scriptmanager.window_interface.BAM_Manipulation.ValidateSamWindow; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.IOException; +import java.util.Vector; + +public class SamtoFastqWindow extends JFrame implements ActionListener, PropertyChangeListener { + private JPanel contentPane; + protected JFileChooser fc = new JFileChooser(new File(System.getProperty("user.dir"))); + + final DefaultListModel expList; + + Vector BAMFiles = new Vector(); + private File OUT_DIR = null; + + private JButton btnLoad; + + private JButton btnRemoveBam; + private JButton btnOutput; + private JLabel outputLabel; + private JLabel lblDefaultToLocal; + private JCheckBox chckbxCompress; + private JCheckBox chckbxPerRG; + private JButton btnConvert; + private boolean compress; + private boolean perRG; + private JProgressBar progressBar; + public SamtoFastqWindow.Task task; + + class Task extends SwingWorker { + + @Override + public Void doInBackground() throws IOException { + setProgress(0); + try { + for(int x = 0; x < BAMFiles.size(); x++) { + // Build output filepath + String[] NAME = BAMFiles.get(x).getName().split("\\."); + File OUTPUT = null; + if (OUT_DIR != null) { + OUTPUT = new File(OUT_DIR.getCanonicalPath() + File.separator + NAME[0] + "_converted.fastq"); + } else { + OUTPUT = new File(NAME[0] + "_converted.fastq"); + } + compress = chckbxCompress.isSelected(); + perRG = chckbxPerRG.isSelected(); + // Execute Picard wrapper + SamtoFastqWrapper.run(BAMFiles.get(x), OUTPUT, compress, perRG, OUT_DIR); + // Update progress + int percentComplete = (int)(((double)(x + 1) / BAMFiles.size()) * 100); + setProgress(percentComplete); + } + setProgress(100); + JOptionPane.showMessageDialog(null, "Conversion Complete"); + } catch (SAMException se) { + JOptionPane.showMessageDialog(null, se.getMessage()); + } + return null; + } + + public void done() { + massXable(contentPane, true); + setCursor(null); //turn off the wait cursor + } + } + public SamtoFastqWindow(){ + setTitle("Convert BAM to Fastq"); + setBounds(125, 125, 480, 450); + contentPane = new JPanel(); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + SpringLayout sl_contentPane = new SpringLayout(); + contentPane.setLayout(sl_contentPane); + + JScrollPane scrollPane = new JScrollPane(); + sl_contentPane.putConstraint(SpringLayout.WEST, scrollPane, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, scrollPane, -5, SpringLayout.EAST, contentPane); + contentPane.add(scrollPane); + + expList = new DefaultListModel(); + final JList listExp = new JList(expList); + listExp.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + scrollPane.setViewportView(listExp); + + btnLoad = new JButton("Load BAM Files"); + sl_contentPane.putConstraint(SpringLayout.WEST, btnLoad, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 6, SpringLayout.SOUTH, btnLoad); + + btnLoad.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File[] newBAMFiles = FileSelection.getFiles(fc,"bam"); + if(newBAMFiles != null) { + for(int x = 0; x < newBAMFiles.length; x++) { + BAMFiles.add(newBAMFiles[x]); + expList.addElement(newBAMFiles[x].getName()); + } + } + } + }); + contentPane.add(btnLoad); + + + btnRemoveBam = new JButton("Remove BAM"); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoad, 0, SpringLayout.NORTH, btnRemoveBam); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnRemoveBam, 0, SpringLayout.NORTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnRemoveBam, -5, SpringLayout.EAST, contentPane); + btnRemoveBam.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + while(listExp.getSelectedIndex() > -1) { + BAMFiles.remove(listExp.getSelectedIndex()); + expList.remove(listExp.getSelectedIndex()); + } + } + }); + contentPane.add(btnRemoveBam); + + chckbxCompress = new JCheckBox("Compress output?"); + sl_contentPane.putConstraint(SpringLayout.WEST, chckbxCompress, 0, SpringLayout.WEST, scrollPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, chckbxCompress, 10, SpringLayout.SOUTH, scrollPane); + chckbxCompress.setSelected(false); + contentPane.add(chckbxCompress); + + chckbxCompress.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (chckbxCompress.isSelected()) { + chckbxPerRG.setSelected(false); + } + } + }); + + chckbxPerRG = new JCheckBox("Output per read group?"); + sl_contentPane.putConstraint(SpringLayout.WEST, chckbxPerRG, 0, SpringLayout.WEST, scrollPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, chckbxPerRG, 30, SpringLayout.SOUTH, scrollPane); + chckbxPerRG.setSelected(false); + contentPane.add(chckbxPerRG); + + chckbxPerRG.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (chckbxPerRG.isSelected()) { + chckbxCompress.setSelected(false); + } + } + }); + + btnOutput = new JButton("Output Directory"); + btnOutput.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File temp = FileSelection.getOutputDir(fc); + if(temp != null) { + OUT_DIR = temp; + lblDefaultToLocal.setText(OUT_DIR.getAbsolutePath()); + } + } + }); + sl_contentPane.putConstraint(SpringLayout.SOUTH, scrollPane, -3, SpringLayout.NORTH, btnOutput); + sl_contentPane.putConstraint(SpringLayout.WEST, btnOutput, 150, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.SOUTH, btnOutput, -50, SpringLayout.SOUTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnOutput, -150, SpringLayout.EAST, contentPane); + contentPane.add(btnOutput); + + outputLabel = new JLabel("Current Output:"); + sl_contentPane.putConstraint(SpringLayout.WEST, outputLabel, 0, SpringLayout.WEST, scrollPane); + sl_contentPane.putConstraint(SpringLayout.SOUTH, outputLabel, 0, SpringLayout.SOUTH, contentPane); + contentPane.add(outputLabel); + + lblDefaultToLocal = new JLabel("Default to Local Directory"); + sl_contentPane.putConstraint(SpringLayout.NORTH, lblDefaultToLocal, 0, SpringLayout.NORTH, outputLabel); + sl_contentPane.putConstraint(SpringLayout.WEST, lblDefaultToLocal, 6, SpringLayout.EAST, outputLabel); + lblDefaultToLocal.setBackground(Color.WHITE); + contentPane.add(lblDefaultToLocal); + + btnConvert = new JButton("Convert"); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnConvert, 2, SpringLayout.SOUTH, scrollPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnConvert, -5, SpringLayout.EAST, contentPane); + contentPane.add(btnConvert); + + progressBar = new JProgressBar(); + sl_contentPane.putConstraint(SpringLayout.NORTH, progressBar, -3, SpringLayout.NORTH, lblDefaultToLocal); + sl_contentPane.putConstraint(SpringLayout.EAST, progressBar, 0, SpringLayout.EAST, scrollPane); + progressBar.setStringPainted(true); + contentPane.add(progressBar); + + + btnConvert.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + task = new Task(); + task.addPropertyChangeListener(SamtoFastqWindow.this); + task.execute(); + } + }); + + } + @Override + public void actionPerformed(ActionEvent arg0) { + massXable(contentPane, false); + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + task = new Task(); + task.addPropertyChangeListener(this); + task.execute(); + } + /** + * Invoked when task's progress property changes. + */ + public void propertyChange(PropertyChangeEvent evt) { + if ("progress" == evt.getPropertyName()) { + int progress = (Integer) evt.getNewValue(); + progressBar.setValue(progress); + } + } + public void massXable(Container con, boolean status) { + for(Component c : con.getComponents()) { + c.setEnabled(status); + if(c instanceof Container) { massXable((Container)c, status); } + } + } +} diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamWindow.java index 37c633124..16374bd74 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamWindow.java @@ -28,7 +28,7 @@ public class DownsampleSamWindow extends JFrame implements ActionListener, Prope final DefaultListModel expList; Vector BAMFiles = new Vector(); - private JButton btnLoad; + private JButton btnLoadBam; private JButton btnRemoveBam; private JButton btnDownSample; private Long desiredReadCount; @@ -48,6 +48,7 @@ public class DownsampleSamWindow extends JFrame implements ActionListener, Prope private JCheckBox setReadCountBox; private JTextField readCountField; private File OUT_DIR = null; + private JButton btnLoadSam; private JProgressBar progressBar; public Task task; @@ -137,11 +138,11 @@ public DownsampleSamWindow() { listExp.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); scrollPane.setViewportView(listExp); - btnLoad = new JButton("Load BAM Files"); - sl_contentPane.putConstraint(SpringLayout.WEST, btnLoad, 5, SpringLayout.WEST, contentPane); - sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 6, SpringLayout.SOUTH, btnLoad); + btnLoadBam = new JButton("Load BAM Files"); + sl_contentPane.putConstraint(SpringLayout.WEST, btnLoadBam, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 6, SpringLayout.SOUTH, btnLoadBam); - btnLoad.addActionListener(new ActionListener() { + btnLoadBam.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { File[] newBAMFiles = FileSelection.getFiles(fc,"bam"); if(newBAMFiles != null) { @@ -152,10 +153,29 @@ public void actionPerformed(ActionEvent e) { } } }); - contentPane.add(btnLoad); + contentPane.add(btnLoadBam); + + btnLoadSam = new JButton("Load SAM Files"); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoadSam, 0, SpringLayout.NORTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.WEST, btnLoadSam, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoadSam, 30, SpringLayout.NORTH, btnLoadBam); + sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 30, SpringLayout.NORTH, btnLoadSam); + + btnLoadSam.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File[] newBAMFiles = FileSelection.getFiles(fc,"sam"); + if(newBAMFiles != null) { + for(int x = 0; x < newBAMFiles.length; x++) { + BAMFiles.add(newBAMFiles[x]); + expList.addElement(newBAMFiles[x].getName()); + } + } + } + }); + contentPane.add(btnLoadSam); btnRemoveBam = new JButton("Remove BAM"); - sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoad, 0, SpringLayout.NORTH, btnRemoveBam); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoadBam, 0, SpringLayout.NORTH, btnRemoveBam); sl_contentPane.putConstraint(SpringLayout.NORTH, btnRemoveBam, 0, SpringLayout.NORTH, contentPane); sl_contentPane.putConstraint(SpringLayout.EAST, btnRemoveBam, -5, SpringLayout.EAST, contentPane); btnRemoveBam.addActionListener(new ActionListener() { @@ -282,8 +302,7 @@ public void actionPerformed(ActionEvent e) { // Set the probability value relative to the desired read count probability = (double) desiredReadCount / totalreadCount; } else { - // Set a default probability value - probability = 0.5; + JOptionPane.showMessageDialog(null, "Invalid read count. The entered value is larger than the total number of reads. Defaulting to 0.5 probability"); } } catch (NumberFormatException ex) { JOptionPane.showMessageDialog(null, "Invalid read count. Please enter an integer value."); diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java index bff1c8f56..07e11fc75 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java @@ -31,7 +31,7 @@ public class ValidateSamWindow extends JFrame implements ActionListener, Proper Vector BAMFiles = new Vector(); private File OUT_DIR = null; private File GENOME = null; - private JButton btnLoad; + private JButton btnLoadBam; private JButton btnRemoveBam; private JCheckBox chckbxGenerateBaiIndex; private JCheckBox chckbxSummaryMode; @@ -40,6 +40,7 @@ public class ValidateSamWindow extends JFrame implements ActionListener, Proper private JButton btnOutput; private JLabel outputLabel; + private JButton btnLoadSam; private JLabel maxLabel; private JTextField maxField; @@ -78,11 +79,7 @@ public Void doInBackground() throws IOException { if (chckbxGenerateBaiIndex.isSelected()) { BAIIndexer.generateIndex(BAMFiles.get(x)); } - if (chckbxSummaryMode.isSelected()) { - mode = false; - } else { - mode = true; - } + mode = !chckbxSummaryMode.isSelected(); // Execute Picard wrapper ValidateSamWrapper.run(BAMFiles.get(x), OUTPUT, mode, GENOME, maxOutput); // Update progress @@ -123,11 +120,11 @@ public ValidateSamWindow() { listExp.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); scrollPane.setViewportView(listExp); - btnLoad = new JButton("Load BAM Files"); - sl_contentPane.putConstraint(SpringLayout.WEST, btnLoad, 5, SpringLayout.WEST, contentPane); - sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 6, SpringLayout.SOUTH, btnLoad); + btnLoadBam = new JButton("Load BAM Files"); + sl_contentPane.putConstraint(SpringLayout.WEST, btnLoadBam, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 6, SpringLayout.SOUTH, btnLoadBam); - btnLoad.addActionListener(new ActionListener() { + btnLoadBam.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { File[] newBAMFiles = FileSelection.getFiles(fc,"bam"); if(newBAMFiles != null) { @@ -138,10 +135,30 @@ public void actionPerformed(ActionEvent e) { } } }); - contentPane.add(btnLoad); + contentPane.add(btnLoadBam); + + btnLoadSam = new JButton("Load SAM Files"); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoadSam, 6, SpringLayout.SOUTH, btnLoadBam); + sl_contentPane.putConstraint(SpringLayout.WEST, btnLoadSam, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoadSam, 60, SpringLayout.NORTH, btnLoadBam); + + + + btnLoadSam.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File[] newBAMFiles = FileSelection.getFiles(fc,"sam"); + if(newBAMFiles != null) { + for(int x = 0; x < newBAMFiles.length; x++) { + BAMFiles.add(newBAMFiles[x]); + expList.addElement(newBAMFiles[x].getName()); + } + } + } + }); + contentPane.add(btnLoadSam); btnRemoveBam = new JButton("Remove BAM"); - sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoad, 0, SpringLayout.NORTH, btnRemoveBam); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoadBam, 0, SpringLayout.NORTH, btnRemoveBam); sl_contentPane.putConstraint(SpringLayout.NORTH, btnRemoveBam, 0, SpringLayout.NORTH, contentPane); sl_contentPane.putConstraint(SpringLayout.EAST, btnRemoveBam, -5, SpringLayout.EAST, contentPane); btnRemoveBam.addActionListener(new ActionListener() { @@ -191,8 +208,8 @@ public void actionPerformed(ActionEvent e) { }); sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoadGenome, 0, SpringLayout.NORTH, contentPane); sl_contentPane.putConstraint(SpringLayout.WEST, btnLoadGenome, 5, SpringLayout.WEST, contentPane); - sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoadGenome, 30, SpringLayout.NORTH, btnLoad); - sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 30, SpringLayout.NORTH, btnLoadGenome); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoadGenome, 30, SpringLayout.NORTH, btnLoadBam); + sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 60, SpringLayout.NORTH, btnLoadGenome); contentPane.add(btnLoadGenome); lblReferenceGenome = new JLabel("Reference Genome: "); From 52766121a81102cf93f374730ca1041e54812e84 Mon Sep 17 00:00:00 2001 From: Erikpav Date: Tue, 27 Jun 2023 16:02:11 -0400 Subject: [PATCH 06/11] Added New Tools Added NormalizeFasta and CollectBaseDistributionByCycle Picard tools and added the wrapper for the FilterSamReads tool. Refactored BAIIndexer to BAIIndexerWrapper and Window to match with other tools. The charting feature for CollectBaseDistributionByCycle experiences an unknown error on my end. I am unsure if this has something to do with my R install or the code itself. --- .../cli/BAM_Manipulation/BAIIndexerCLI.java | 3 +- .../scriptmanager/main/ScriptManagerGUI.java | 59 +++++ .../objects/ToolDescriptions.java | 3 +- .../SamtoFastqWrapper.java | 4 +- ...BAIIndexer.java => BAIIndexerWrapper.java} | 8 +- .../DownsampleSamWrapper.java | 1 - .../FilterSamReadsWrapper.java | 29 +++ .../NormalizeFastaWrapper.java | 34 +++ ...CollectBaseDistributionByCycleWrapper.java | 35 +++ .../SamtoFastqWindow.java | 3 - .../BAM_Manipulation/BAIIndexerWindow.java | 4 +- .../BAM_Manipulation/BAMMarkDupWindow.java | 4 +- .../FilterSamReadsWindow.java | 9 + .../FilterforPIPseqWindow.java | 4 +- .../BAM_Manipulation/MergeBAMWindow.java | 4 +- .../NormalizeFastaWindow.java | 196 +++++++++++++++++ .../BAM_Manipulation/ValidateSamWindow.java | 6 +- .../CollectBaseDistributionByCycleWindow.java | 204 ++++++++++++++++++ 18 files changed, 586 insertions(+), 24 deletions(-) rename src/main/java/scriptmanager/scripts/BAM_Manipulation/{BAIIndexer.java => BAIIndexerWrapper.java} (87%) create mode 100644 src/main/java/scriptmanager/scripts/BAM_Manipulation/FilterSamReadsWrapper.java create mode 100644 src/main/java/scriptmanager/scripts/BAM_Manipulation/NormalizeFastaWrapper.java create mode 100644 src/main/java/scriptmanager/scripts/BAM_Statistics/CollectBaseDistributionByCycleWrapper.java create mode 100644 src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterSamReadsWindow.java create mode 100644 src/main/java/scriptmanager/window_interface/BAM_Manipulation/NormalizeFastaWindow.java create mode 100644 src/main/java/scriptmanager/window_interface/BAM_Statistics/CollectBaseDistributionByCycleWindow.java diff --git a/src/main/java/scriptmanager/cli/BAM_Manipulation/BAIIndexerCLI.java b/src/main/java/scriptmanager/cli/BAM_Manipulation/BAIIndexerCLI.java index 798e75900..33fb5fd6c 100644 --- a/src/main/java/scriptmanager/cli/BAM_Manipulation/BAIIndexerCLI.java +++ b/src/main/java/scriptmanager/cli/BAM_Manipulation/BAIIndexerCLI.java @@ -5,12 +5,13 @@ import java.util.concurrent.Callable; import scriptmanager.objects.ToolDescriptions; +import scriptmanager.scripts.BAM_Manipulation.BAIIndexerWrapper; /** * Print a message redirecting user to the original CLI tool. * * @author Olivia Lang - * @see scriptmanager.scripts.BAM_Manipulation.BAIIndexer + * @see BAIIndexerWrapper */ @Command(name = "bam-indexer", mixinStandardHelpOptions = true, description = ToolDescriptions.bam_indexer_description + "\n"+ diff --git a/src/main/java/scriptmanager/main/ScriptManagerGUI.java b/src/main/java/scriptmanager/main/ScriptManagerGUI.java index 1ddbf2ca3..a93fbde9e 100755 --- a/src/main/java/scriptmanager/main/ScriptManagerGUI.java +++ b/src/main/java/scriptmanager/main/ScriptManagerGUI.java @@ -10,6 +10,7 @@ import scriptmanager.window_interface.BAM_Format_Converter.*; import scriptmanager.window_interface.BAM_Manipulation.*; +import scriptmanager.window_interface.BAM_Statistics.CollectBaseDistributionByCycleWindow; import scriptmanager.window_interface.BAM_Statistics.PEStatWindow; import scriptmanager.window_interface.BAM_Statistics.SEStatWindow; import scriptmanager.window_interface.BAM_Statistics.BAMGenomeCorrelationWindow; @@ -168,6 +169,34 @@ public void run() { btnBamGenomeCorrelation); pnlStat.add(btnBamGenomeCorrelation); + JTextArea txtCollectBase = new JTextArea(); + sl_pnlStat.putConstraint(SpringLayout.NORTH, txtCollectBase, 20, SpringLayout.SOUTH, txtBamGenomeCorrelation); + sl_pnlStat.putConstraint(SpringLayout.EAST, txtCollectBase, -10, SpringLayout.EAST, pnlStat); + initializeTextArea(txtCollectBase); + + txtCollectBase.setText(ToolDescriptions.collect_base_distribution_by_cycle_description); + pnlStat.add(txtCollectBase); + + JButton btnCollectBase = new JButton("Collect BAM Distribution"); + btnCollectBase.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + EventQueue.invokeLater(new Runnable() { + public void run() { + try { + CollectBaseDistributionByCycleWindow frame = new CollectBaseDistributionByCycleWindow(); + frame.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + }); + sl_pnlStat.putConstraint(SpringLayout.NORTH, btnCollectBase, 0, SpringLayout.NORTH, txtCollectBase); + sl_pnlStat.putConstraint(SpringLayout.WEST, btnCollectBase, 10, SpringLayout.WEST, pnlStat); + sl_pnlStat.putConstraint(SpringLayout.WEST, txtCollectBase, 10, SpringLayout.EAST, btnCollectBase); + pnlStat.add(btnCollectBase); + // >>>>>>>> BAM_Manipulation <<<<<<<< JPanel pnlBamManip = new JPanel(); SpringLayout sl_pnlBamManip = new SpringLayout(); @@ -391,6 +420,36 @@ public void run() { sl_pnlBamManip.putConstraint(SpringLayout.WEST, txtValidateSamFile, 10, SpringLayout.EAST, btnValidateSamFile); pnlBamManip.add(btnValidateSamFile); + // NormalizeFasta + + JTextArea txtNormalizeFasta = new JTextArea(); + sl_pnlBamManip.putConstraint(SpringLayout.NORTH, txtNormalizeFasta, 20, SpringLayout.SOUTH, txtValidateSamFile); + sl_pnlBamManip.putConstraint(SpringLayout.EAST, txtNormalizeFasta, -10, SpringLayout.EAST, pnlBamManip); + initializeTextArea(txtNormalizeFasta); + + txtNormalizeFasta.setText(ToolDescriptions.normalize_fasta_description); + pnlBamManip.add(txtNormalizeFasta); + + JButton btnNormalizeFasta = new JButton("Normalize FASTA File"); + btnNormalizeFasta.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + EventQueue.invokeLater(new Runnable() { + public void run() { + try { + NormalizeFastaWindow frame = new NormalizeFastaWindow(); + frame.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + }); + sl_pnlBamManip.putConstraint(SpringLayout.NORTH, btnNormalizeFasta, 0, SpringLayout.NORTH, txtNormalizeFasta); + sl_pnlBamManip.putConstraint(SpringLayout.WEST, btnNormalizeFasta, 10, SpringLayout.WEST, pnlBamManip); + sl_pnlBamManip.putConstraint(SpringLayout.WEST, txtNormalizeFasta, 10, SpringLayout.EAST, btnNormalizeFasta); + pnlBamManip.add(btnNormalizeFasta); + // >>>>>>>> BAM_Format_Converter <<<<<<<< JPanel pnlBamConvert = new JPanel(); SpringLayout sl_pnlBamConvert = new SpringLayout(); diff --git a/src/main/java/scriptmanager/objects/ToolDescriptions.java b/src/main/java/scriptmanager/objects/ToolDescriptions.java index 78aa98886..8c313efb5 100644 --- a/src/main/java/scriptmanager/objects/ToolDescriptions.java +++ b/src/main/java/scriptmanager/objects/ToolDescriptions.java @@ -28,7 +28,7 @@ public class ToolDescriptions { public static final String se_stat_description = "Output BAM Header including alignment statistics and parameters given any indexed (BAI) BAM File."; public static final String pe_stat_description = "Generates Insert-size Histogram statistics (GEO requirement) and outputs BAM Header including alignment statistics and parameters given a sorted and indexed (BAI) paired-end BAM File."; public static final String bam_correlation_description = "Genome-Genome correlations for replicate comparisons given multiple sorted and indexed (BAI) BAM files."; - + public static final String collect_base_distribution_by_cycle_description = "Chart the nucleotide distribution per cycle in a BAM file"; // BAM Manipulation public static final String bam_indexer_description = "Generates BAI Index for input BAM files. Output BAI is in the same directory as input BAM file."; //* public static final String sort_bam_description = "Sort BAM files in order to efficiently extract and manipulate.\nRAM intensive process. If program freezes, increase JAVA heap size."; //* @@ -37,6 +37,7 @@ public class ToolDescriptions { public static final String filter_pip_seq_description = "Filter BAM file by -1 nucleotide. Requires genome FASTA file."; public static final String downsample_sam_description = "Downsample a BAM file to a specified percentage or read count of deterministically random reads."; public static final String validate_sam_file_description = "Validate SAM/BAM files comprehensively, ensuring adherence to the SAM format specification and detecting errors or inconsistencies in alignment data."; + public static final String normalize_fasta_description = "Reduce redundant sequences and normalize read coverage in a FASTA file, improving downstream analysis accuracy"; // BAM Format Converter public static final String bam_to_scidx_description = "Convert BAM file to scIDX file."; diff --git a/src/main/java/scriptmanager/scripts/BAM_Format_Converter/SamtoFastqWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Format_Converter/SamtoFastqWrapper.java index e763f4282..42380ecab 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Format_Converter/SamtoFastqWrapper.java +++ b/src/main/java/scriptmanager/scripts/BAM_Format_Converter/SamtoFastqWrapper.java @@ -29,11 +29,11 @@ public static void run(File input, File output, boolean compress, boolean perRG, final ArrayList args = new ArrayList<>(); args.add("INPUT=" + input.getAbsolutePath()); if (compress) { - args.add("COMPRESS_OUTPUTS_PER_RG=" + true); args.add("OUTPUT_DIR=" + outputDir.getCanonicalPath()); + args.add("COMPRESS_OUTPUTS_PER_RG=" + true); } else if (perRG) { - args.add("OUTPUT_PER_RG=" + true); args.add("OUTPUT_DIR=" + outputDir.getCanonicalPath()); + args.add("OUTPUT_PER_RG=" + true); } else { args.add("FASTQ=" + output.getAbsolutePath()); } diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/BAIIndexer.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/BAIIndexerWrapper.java similarity index 87% rename from src/main/java/scriptmanager/scripts/BAM_Manipulation/BAIIndexer.java rename to src/main/java/scriptmanager/scripts/BAM_Manipulation/BAIIndexerWrapper.java index 03235c41a..d2b3eaeab 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Manipulation/BAIIndexer.java +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/BAIIndexerWrapper.java @@ -10,9 +10,9 @@ * Picard wrapper for BuildBamIndex * * @author Erik Pavloski - * @see scriptmanager.window_interface.BAM_Manipulation.BAIIndexerWIndow + * @see scriptmanager.window_interface.BAM_Manipulation.BAIIndexerWindow */ -public class BAIIndexer { +public class BAIIndexerWrapper { /** * Index a BAM file and output said index to a file of the same name with a .bai * extension @@ -25,7 +25,8 @@ public static File generateIndex(File input) throws IOException { // Tells user that their file is being generated System.out.println("Generating Index File..."); // Build output filepath - String output = input.getCanonicalPath() + ".bai"; + String[] NAME = input.getName().split("\\."); + String output = input.getParent() + File.separator + NAME[0] + "_index.bai"; File retVal = new File(output); // Instatiate Picard object final BuildBamIndex buildBamIndex = new BuildBamIndex(); @@ -35,7 +36,6 @@ public static File generateIndex(File input) throws IOException { args.add("OUTPUT=" + retVal.getAbsolutePath()); // Call Picard with args buildBamIndex.instanceMain(args.toArray(new String[args.size()])); - System.out.println("Index File Generated"); return retVal; } diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamWrapper.java index ba43dd8a5..3efef30d6 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamWrapper.java +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamWrapper.java @@ -1,7 +1,6 @@ package scriptmanager.scripts.BAM_Manipulation; import htsjdk.samtools.SAMException; -import scriptmanager.window_interface.BAM_Manipulation.DownsampleSamWindow; import java.io.File; import java.io.IOException; diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/FilterSamReadsWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/FilterSamReadsWrapper.java new file mode 100644 index 000000000..4551d9f5e --- /dev/null +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/FilterSamReadsWrapper.java @@ -0,0 +1,29 @@ +package scriptmanager.scripts.BAM_Manipulation; + +import htsjdk.samtools.SAMException; + +import java.io.IOException; +import java.io.File; + +/** + * @author Erik Pavloski + * This code runs the FilterSamReads Picard tool + * @see scriptmanager.window_interface.BAM_Manipulation.FilterSamReadsWindow + */ +public class FilterSamReadsWrapper { + /** + * @param input the file to be filtered + * @param output the file to be outputted + * @param filter which filter the user wants to use can be includeReadList or includePairIntervals + * true == includeReadList + * false == includePairIntervals + * @param readListFile the txt file output for the read list if that is the chosen filter + * @param intervalList the list of interval output file if that is the desired filter + * + * @throws IOException + * @throws SAMException + */ + public static void run(File input, File output, boolean filter, File readListFile, File intervalList) throws IOException, SAMException { + + } +} diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/NormalizeFastaWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/NormalizeFastaWrapper.java new file mode 100644 index 000000000..14ec0b966 --- /dev/null +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/NormalizeFastaWrapper.java @@ -0,0 +1,34 @@ +package scriptmanager.scripts.BAM_Manipulation; + +import htsjdk.samtools.SAMException; +import picard.reference.NormalizeFasta; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; + +/** + * @author Erik Pavloski + * This is the Wrapper class for the NormalizeFasta Picard tool + * @see scriptmanager.window_interface.BAM_Manipulation.NormalizeFastaWindow + */ +public class NormalizeFastaWrapper { + /** + * @param input the file to be filtered + * @param output the file to be outputted + * + * @throws IOException + * @throws SAMException + */ + public static void run(File input, File output) throws IOException, SAMException { + System.out.println("Normalizing FASTA file"); + + final picard.reference.NormalizeFasta normalizeFasta = new picard.reference.NormalizeFasta(); + final ArrayList args = new ArrayList<>(); + args.add("INPUT=" + input.getAbsolutePath()); + args.add("OUTPUT=" + output.getAbsolutePath()); + normalizeFasta.instanceMain(args.toArray(new String[args.size()])); + + System.out.println("File Normalized"); + } +} diff --git a/src/main/java/scriptmanager/scripts/BAM_Statistics/CollectBaseDistributionByCycleWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Statistics/CollectBaseDistributionByCycleWrapper.java new file mode 100644 index 000000000..6dea7fc00 --- /dev/null +++ b/src/main/java/scriptmanager/scripts/BAM_Statistics/CollectBaseDistributionByCycleWrapper.java @@ -0,0 +1,35 @@ +package scriptmanager.scripts.BAM_Statistics; +import htsjdk.samtools.SAMException; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; + +/** + * @author Erik Pavloski + * @see scriptmanager.window_interface.BAM_Statistics.CollectBaseDistributionByCycleWindow + * This code runs the Picard tool called CollectBaseDistributionByCycle + */ + +public class CollectBaseDistributionByCycleWrapper { + /** + * @param input the bam file to be analysed + * @param output the output text file + * @param chartOutput the pdf chart output + * + * @throws IOException + * @throws SAMException + */ + public static void run(File input, File output, File chartOutput) throws IOException, SAMException { + System.out.println("Analysing file..."); + + // Analysis of the file + final picard.analysis.CollectBaseDistributionByCycle collectBaseDistributionByCycle = new picard.analysis.CollectBaseDistributionByCycle(); + final ArrayList args = new ArrayList<>(); + args.add("INPUT=" + input.getAbsolutePath()); + args.add("OUTPUT=" + output.getAbsolutePath()); + args.add("CHART_OUTPUT=" + chartOutput.getAbsolutePath()); + collectBaseDistributionByCycle.instanceMain(args.toArray(new String[args.size()])); + System.out.println("Analysis complete"); + } +} diff --git a/src/main/java/scriptmanager/window_interface/BAM_Format_Converter/SamtoFastqWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Format_Converter/SamtoFastqWindow.java index 347acf844..af2f692ab 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Format_Converter/SamtoFastqWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Format_Converter/SamtoFastqWindow.java @@ -2,10 +2,7 @@ import htsjdk.samtools.SAMException; import scriptmanager.scripts.BAM_Format_Converter.SamtoFastqWrapper; -import scriptmanager.scripts.BAM_Manipulation.BAIIndexer; -import scriptmanager.scripts.BAM_Manipulation.ValidateSamWrapper; import scriptmanager.util.FileSelection; -import scriptmanager.window_interface.BAM_Manipulation.ValidateSamWindow; import javax.swing.*; import javax.swing.border.EmptyBorder; diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/BAIIndexerWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/BAIIndexerWindow.java index 27dee2d46..8dc983b84 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/BAIIndexerWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/BAIIndexerWindow.java @@ -28,7 +28,7 @@ import javax.swing.border.EmptyBorder; import scriptmanager.util.FileSelection; -import scriptmanager.scripts.BAM_Manipulation.BAIIndexer; +import scriptmanager.scripts.BAM_Manipulation.BAIIndexerWrapper; @SuppressWarnings("serial") public class BAIIndexerWindow extends JFrame implements ActionListener, PropertyChangeListener { @@ -52,7 +52,7 @@ public Void doInBackground() throws IOException { try { for(int x = 0; x < BAMFiles.size(); x++) { // Execute Picard wrapper - BAIIndexer.generateIndex(BAMFiles.get(x)); + BAIIndexerWrapper.generateIndex(BAMFiles.get(x)); // Update progress int percentComplete = (int)(((double)(x + 1) / BAMFiles.size()) * 100); setProgress(percentComplete); diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/BAMMarkDupWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/BAMMarkDupWindow.java index 1b4df7f4e..a722fd4e9 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/BAMMarkDupWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/BAMMarkDupWindow.java @@ -30,7 +30,7 @@ import javax.swing.border.EmptyBorder; import scriptmanager.util.FileSelection; -import scriptmanager.scripts.BAM_Manipulation.BAIIndexer; +import scriptmanager.scripts.BAM_Manipulation.BAIIndexerWrapper; import scriptmanager.scripts.BAM_Manipulation.BAMMarkDuplicates; @SuppressWarnings("serial") @@ -73,7 +73,7 @@ public Void doInBackground() throws Exception { BAMMarkDuplicates dedup = new BAMMarkDuplicates(BAMFiles.get(x), chckbxRemoveDuplicates.isSelected(), OUTPUT, METRICS); dedup.run(); - if(chckbxGenerateBaiIndex.isSelected()) { BAIIndexer.generateIndex(OUTPUT); } + if(chckbxGenerateBaiIndex.isSelected()) { BAIIndexerWrapper.generateIndex(OUTPUT); } int percentComplete = (int)(((double)(x + 1) / BAMFiles.size()) * 100); setProgress(percentComplete); diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterSamReadsWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterSamReadsWindow.java new file mode 100644 index 000000000..d8683c925 --- /dev/null +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterSamReadsWindow.java @@ -0,0 +1,9 @@ +package scriptmanager.window_interface.BAM_Manipulation; + +/** + * @author Erik Pavloski + * This is the window class for FilterSamReadsWrapper + * @see scriptmanager.scripts.BAM_Manipulation.FilterSamReadsWrapper + */ +public class FilterSamReadsWindow { +} diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterforPIPseqWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterforPIPseqWindow.java index 0cf64b8d1..8ea3518ac 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterforPIPseqWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterforPIPseqWindow.java @@ -33,7 +33,7 @@ import javax.swing.SwingConstants; import scriptmanager.util.FileSelection; -import scriptmanager.scripts.BAM_Manipulation.BAIIndexer; +import scriptmanager.scripts.BAM_Manipulation.BAIIndexerWrapper; @SuppressWarnings("serial") public class FilterforPIPseqWindow extends JFrame implements ActionListener, PropertyChangeListener { @@ -79,7 +79,7 @@ public Void doInBackground() throws Exception { filter.run(); if (chckbxGenerateBaiIndex.isSelected()) { - BAIIndexer.generateIndex(OUTPUT); + BAIIndexerWrapper.generateIndex(OUTPUT); } int percentComplete = (int) (((double) (x + 1) / BAMFiles.size()) * 100); diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/MergeBAMWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/MergeBAMWindow.java index 3d20bdf4f..75be85cc5 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/MergeBAMWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/MergeBAMWindow.java @@ -31,7 +31,7 @@ import javax.swing.border.EmptyBorder; import scriptmanager.util.FileSelection; -import scriptmanager.scripts.BAM_Manipulation.BAIIndexer; +import scriptmanager.scripts.BAM_Manipulation.BAIIndexerWrapper; import scriptmanager.scripts.BAM_Manipulation.MergeBAM; @SuppressWarnings("serial") @@ -68,7 +68,7 @@ public Void doInBackground() throws Exception { MergeBAM.run(BAMFiles, OUTPUT, chckbxUseMultipleCpus.isSelected()); // Index if checkbox selected if(chckbxGenerateBaiindex.isSelected()) { - BAIIndexer.generateIndex(OUTPUT); + BAIIndexerWrapper.generateIndex(OUTPUT); } setProgress(100); JOptionPane.showMessageDialog(null, "Merging Complete"); diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/NormalizeFastaWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/NormalizeFastaWindow.java new file mode 100644 index 000000000..0ce208c5d --- /dev/null +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/NormalizeFastaWindow.java @@ -0,0 +1,196 @@ +package scriptmanager.window_interface.BAM_Manipulation; + +import htsjdk.samtools.SAMException; +import scriptmanager.scripts.BAM_Manipulation.NormalizeFastaWrapper; +import scriptmanager.util.FileSelection; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.IOException; +import java.util.Vector; + +/** + * @author Erik Pavloski + * This is the window class for the NormalizeFasta Picard tool + * @see scriptmanager.scripts.BAM_Manipulation.NormalizeFastaWrapper + */ +public class NormalizeFastaWindow extends JFrame implements ActionListener, PropertyChangeListener { + private JPanel contentPane; + protected JFileChooser fc = new JFileChooser(new File(System.getProperty("user.dir"))); + + final DefaultListModel expList; + + Vector BAMFiles = new Vector(); + private File OUT_DIR = null; + + private JButton btnLoadFasta; + private JButton btnRemoveFasta; + private JLabel outputLabel; + private JLabel lblDefaultToLocal; + private JButton btnOutput; + private JButton btnNormalize; + private JProgressBar progressBar; + public Task task; + class Task extends SwingWorker { + @Override + public Void doInBackground() throws IOException { + + setProgress(0); + try { + for (int x = 0; x < BAMFiles.size(); x++) { + // Build output filepath + String[] NAME = BAMFiles.get(x).getName().split("\\."); + File OUTPUT = null; + if (OUT_DIR != null) { + OUTPUT = new File(OUT_DIR.getCanonicalPath() + File.separator + NAME[0] + "_normalized.fasta"); + } else { + OUTPUT = new File(NAME[0] + "_normalized.fasta"); + } + // Run Wrapper + NormalizeFastaWrapper.run(BAMFiles.get(x), OUTPUT); + // Update progress + int percentComplete = (int)(((double)(x + 1) / BAMFiles.size()) * 100); + setProgress(percentComplete); + } + setProgress(100); + JOptionPane.showMessageDialog(null, "Validation Complete"); + } catch (SAMException se) { + JOptionPane.showMessageDialog(null, se.getMessage()); + } + return null; + } + public void done() { + massXable(contentPane, true); + setCursor(null); //turn off the wait cursor + } + } + + public NormalizeFastaWindow() { + setTitle("Normalize FASTA File"); + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + + setBounds(125, 125, 580, 450); + contentPane = new JPanel(); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + SpringLayout sl_contentPane = new SpringLayout(); + contentPane.setLayout(sl_contentPane); + + JScrollPane scrollPane = new JScrollPane(); + sl_contentPane.putConstraint(SpringLayout.WEST, scrollPane, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, scrollPane, -5, SpringLayout.EAST, contentPane); + contentPane.add(scrollPane); + + expList = new DefaultListModel(); + final JList listExp = new JList(expList); + listExp.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + scrollPane.setViewportView(listExp); + + btnLoadFasta = new JButton("Load FASTA Files"); + sl_contentPane.putConstraint(SpringLayout.WEST, btnLoadFasta, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 6, SpringLayout.SOUTH, btnLoadFasta); + + btnLoadFasta.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File[] newBAMFiles = FileSelection.getFiles(fc,"fasta"); + if(newBAMFiles != null) { + for(int x = 0; x < newBAMFiles.length; x++) { + BAMFiles.add(newBAMFiles[x]); + expList.addElement(newBAMFiles[x].getName()); + } + } + } + }); + contentPane.add(btnLoadFasta); + + btnRemoveFasta = new JButton("Remove FASTA"); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoadFasta, 0, SpringLayout.NORTH, btnRemoveFasta); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnRemoveFasta, 0, SpringLayout.NORTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnRemoveFasta, -5, SpringLayout.EAST, contentPane); + btnRemoveFasta.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + while(listExp.getSelectedIndex() > -1) { + BAMFiles.remove(listExp.getSelectedIndex()); + expList.remove(listExp.getSelectedIndex()); + } + } + }); + contentPane.add(btnRemoveFasta); + + btnOutput = new JButton("Output Directory"); + btnOutput.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File temp = FileSelection.getOutputDir(fc); + if(temp != null) { + OUT_DIR = temp; + lblDefaultToLocal.setText(OUT_DIR.getAbsolutePath()); + } + } + }); + sl_contentPane.putConstraint(SpringLayout.SOUTH, scrollPane, -3, SpringLayout.NORTH, btnOutput); + sl_contentPane.putConstraint(SpringLayout.WEST, btnOutput, 200, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.SOUTH, btnOutput, -50, SpringLayout.SOUTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnOutput, -200, SpringLayout.EAST, contentPane); + contentPane.add(btnOutput); + + outputLabel = new JLabel("Current Output:"); + sl_contentPane.putConstraint(SpringLayout.WEST, outputLabel, 0, SpringLayout.WEST, scrollPane); + sl_contentPane.putConstraint(SpringLayout.SOUTH, outputLabel, 0, SpringLayout.SOUTH, contentPane); + contentPane.add(outputLabel); + + lblDefaultToLocal = new JLabel("Default to Local Directory"); + sl_contentPane.putConstraint(SpringLayout.NORTH, lblDefaultToLocal, 0, SpringLayout.NORTH, outputLabel); + sl_contentPane.putConstraint(SpringLayout.WEST, lblDefaultToLocal, 6, SpringLayout.EAST, outputLabel); + lblDefaultToLocal.setBackground(Color.WHITE); + contentPane.add(lblDefaultToLocal); + + btnNormalize = new JButton("Normalize"); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnNormalize, 2, SpringLayout.SOUTH, scrollPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnNormalize, -5, SpringLayout.EAST, contentPane); + contentPane.add(btnNormalize); + + btnNormalize.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + task = new Task(); + task.addPropertyChangeListener(NormalizeFastaWindow.this); + task.execute(); + } + }); + + progressBar = new JProgressBar(); + sl_contentPane.putConstraint(SpringLayout.NORTH, progressBar, -3, SpringLayout.NORTH, lblDefaultToLocal); + sl_contentPane.putConstraint(SpringLayout.EAST, progressBar, 0, SpringLayout.EAST, scrollPane); + progressBar.setStringPainted(true); + contentPane.add(progressBar); + } + @Override + public void actionPerformed(ActionEvent arg0) { + massXable(contentPane, false); + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + task = new Task(); + task.addPropertyChangeListener(this); + task.execute(); + } + /** + * Invoked when task's progress property changes. + */ + public void propertyChange(PropertyChangeEvent evt) { + if ("progress" == evt.getPropertyName()) { + int progress = (Integer) evt.getNewValue(); + progressBar.setValue(progress); + } + } + public void massXable(Container con, boolean status) { + for(Component c : con.getComponents()) { + c.setEnabled(status); + if(c instanceof Container) { massXable((Container)c, status); } + } + } +} diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java index 07e11fc75..1c4c3ef9a 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java @@ -1,7 +1,7 @@ package scriptmanager.window_interface.BAM_Manipulation; import htsjdk.samtools.SAMException; -import scriptmanager.scripts.BAM_Manipulation.BAIIndexer; +import scriptmanager.scripts.BAM_Manipulation.BAIIndexerWrapper; import scriptmanager.scripts.BAM_Manipulation.ValidateSamWrapper; import scriptmanager.util.FileSelection; @@ -77,7 +77,7 @@ public Void doInBackground() throws IOException { OUTPUT = new File(NAME[0] + "_validated.html"); } if (chckbxGenerateBaiIndex.isSelected()) { - BAIIndexer.generateIndex(BAMFiles.get(x)); + BAIIndexerWrapper.generateIndex(BAMFiles.get(x)); } mode = !chckbxSummaryMode.isSelected(); // Execute Picard wrapper @@ -142,8 +142,6 @@ public void actionPerformed(ActionEvent e) { sl_contentPane.putConstraint(SpringLayout.WEST, btnLoadSam, 5, SpringLayout.WEST, contentPane); sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoadSam, 60, SpringLayout.NORTH, btnLoadBam); - - btnLoadSam.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { File[] newBAMFiles = FileSelection.getFiles(fc,"sam"); diff --git a/src/main/java/scriptmanager/window_interface/BAM_Statistics/CollectBaseDistributionByCycleWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Statistics/CollectBaseDistributionByCycleWindow.java new file mode 100644 index 000000000..47d01e73e --- /dev/null +++ b/src/main/java/scriptmanager/window_interface/BAM_Statistics/CollectBaseDistributionByCycleWindow.java @@ -0,0 +1,204 @@ +package scriptmanager.window_interface.BAM_Statistics; + +import htsjdk.samtools.SAMException; +import scriptmanager.scripts.BAM_Statistics.CollectBaseDistributionByCycleWrapper; +import scriptmanager.util.FileSelection; +import scriptmanager.window_interface.BAM_Manipulation.ValidateSamWindow; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.IOException; +import java.util.Vector; + +/** + * @author Erik Pavloski + * This is the window class for the CollectBaseDistrubtionByCycleWinow + * @see scriptmanager.scripts.BAM_Statistics.CollectBaseDistributionByCycleWrapper + */ +public class CollectBaseDistributionByCycleWindow extends JFrame implements ActionListener, PropertyChangeListener { + private JPanel contentPane; + protected JFileChooser fc = new JFileChooser(new File(System.getProperty("user.dir"))); + + final DefaultListModel expList; + + Vector BAMFiles = new Vector(); + private File OUT_DIR = null; + + private JButton btnLoadBam; + private JButton btnRemoveBam; + private JButton btnAction; + private JButton btnOutput; + + private JLabel outputLabel; + private JLabel lblDefaultToLocal; + private JProgressBar progressBar; + public Task task; + + class Task extends SwingWorker { + @Override + public Void doInBackground() throws IOException { + setProgress(0); + try { + for(int x = 0; x < BAMFiles.size(); x++) { + // Build output filepath + String[] NAME = BAMFiles.get(x).getName().split("\\."); + File OUTPUT = null; + File chartOutput = null; + if (OUT_DIR != null) { + OUTPUT = new File(OUT_DIR.getCanonicalPath() + File.separator + NAME[0] + "_output.txt"); + chartOutput = new File(OUT_DIR.getCanonicalPath() + File.separator + NAME[0] + "_collect_base_dist_by_cycle.pdf"); + } else { + OUTPUT = new File(NAME[0] + "_output.txt"); + chartOutput = new File(NAME[0] + "_collect_base_dist_by_cycle.pdf"); + } + + // Execute Picard wrapper + CollectBaseDistributionByCycleWrapper.run(BAMFiles.get(x), OUTPUT, chartOutput); + // Update progress + int percentComplete = (int)(((double)(x + 1) / BAMFiles.size()) * 100); + setProgress(percentComplete); + } + setProgress(100); + JOptionPane.showMessageDialog(null, "Distribution Complete"); + } catch (SAMException se) { + JOptionPane.showMessageDialog(null, se.getMessage()); + } + return null; + } + public void done() { + massXable(contentPane, true); + setCursor(null); //turn off the wait cursor + } + + } + public CollectBaseDistributionByCycleWindow() { + setTitle("Collect Base Distribution By Cycle"); + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + + setBounds(125, 125, 580, 450); + contentPane = new JPanel(); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + SpringLayout sl_contentPane = new SpringLayout(); + contentPane.setLayout(sl_contentPane); + + JScrollPane scrollPane = new JScrollPane(); + sl_contentPane.putConstraint(SpringLayout.WEST, scrollPane, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, scrollPane, -5, SpringLayout.EAST, contentPane); + contentPane.add(scrollPane); + + expList = new DefaultListModel(); + final JList listExp = new JList(expList); + listExp.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + scrollPane.setViewportView(listExp); + + btnLoadBam = new JButton("Load BAM Files"); + sl_contentPane.putConstraint(SpringLayout.WEST, btnLoadBam, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 6, SpringLayout.SOUTH, btnLoadBam); + + btnRemoveBam = new JButton("Remove BAM"); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoadBam, 0, SpringLayout.NORTH, btnRemoveBam); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnRemoveBam, 0, SpringLayout.NORTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnRemoveBam, -5, SpringLayout.EAST, contentPane); + btnRemoveBam.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + while(listExp.getSelectedIndex() > -1) { + BAMFiles.remove(listExp.getSelectedIndex()); + expList.remove(listExp.getSelectedIndex()); + } + } + }); + contentPane.add(btnRemoveBam); + + btnLoadBam.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File[] newBAMFiles = FileSelection.getFiles(fc,"bam"); + if(newBAMFiles != null) { + for(int x = 0; x < newBAMFiles.length; x++) { + BAMFiles.add(newBAMFiles[x]); + expList.addElement(newBAMFiles[x].getName()); + } + } + } + }); + contentPane.add(btnLoadBam); + btnOutput = new JButton("Output Directory"); + btnOutput.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File temp = FileSelection.getOutputDir(fc); + if(temp != null) { + OUT_DIR = temp; + lblDefaultToLocal.setText(OUT_DIR.getAbsolutePath()); + } + } + }); + sl_contentPane.putConstraint(SpringLayout.SOUTH, scrollPane, -3, SpringLayout.NORTH, btnOutput); + sl_contentPane.putConstraint(SpringLayout.WEST, btnOutput, 200, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.SOUTH, btnOutput, -50, SpringLayout.SOUTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnOutput, -200, SpringLayout.EAST, contentPane); + contentPane.add(btnOutput); + + outputLabel = new JLabel("Current Output:"); + sl_contentPane.putConstraint(SpringLayout.WEST, outputLabel, 0, SpringLayout.WEST, scrollPane); + sl_contentPane.putConstraint(SpringLayout.SOUTH, outputLabel, 0, SpringLayout.SOUTH, contentPane); + contentPane.add(outputLabel); + + lblDefaultToLocal = new JLabel("Default to Local Directory"); + sl_contentPane.putConstraint(SpringLayout.NORTH, lblDefaultToLocal, 0, SpringLayout.NORTH, outputLabel); + sl_contentPane.putConstraint(SpringLayout.WEST, lblDefaultToLocal, 6, SpringLayout.EAST, outputLabel); + lblDefaultToLocal.setBackground(Color.WHITE); + contentPane.add(lblDefaultToLocal); + + btnAction = new JButton("Collect Base Distribution"); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnAction, 30, SpringLayout.NORTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnAction, -5, SpringLayout.EAST, contentPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 30, SpringLayout.NORTH, btnAction); + contentPane.add(btnAction); + + btnAction.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + task = new Task(); + task.addPropertyChangeListener(CollectBaseDistributionByCycleWindow.this); + task.execute(); + } + }); + progressBar = new JProgressBar(); + sl_contentPane.putConstraint(SpringLayout.NORTH, progressBar, -3, SpringLayout.NORTH, lblDefaultToLocal); + sl_contentPane.putConstraint(SpringLayout.EAST, progressBar, 0, SpringLayout.EAST, scrollPane); + progressBar.setStringPainted(true); + contentPane.add(progressBar); + } + @Override + public void actionPerformed(ActionEvent arg0) { + massXable(contentPane, false); + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + task = new Task(); + task.addPropertyChangeListener(this); + task.execute(); + } + /** + * Invoked when task's progress property changes. + */ + public void propertyChange(PropertyChangeEvent evt) { + if ("progress" == evt.getPropertyName()) { + int progress = (Integer) evt.getNewValue(); + progressBar.setValue(progress); + } + } + public void massXable(Container con, boolean status) { + for(Component c : con.getComponents()) { + c.setEnabled(status); + if(c instanceof Container) { massXable((Container)c, status); } + } + } + +} + + From c223950f5055b28ad432f8ccbd7562be196d994d Mon Sep 17 00:00:00 2001 From: Erikpav Date: Tue, 18 Jul 2023 15:24:32 -0400 Subject: [PATCH 07/11] Added FilterSamReads #122 Created a Wrapper and Window class for the Picard tool called FilterSamReads. --- .../scriptmanager/main/ScriptManagerGUI.java | 31 +++ .../objects/ToolDescriptions.java | 2 +- .../FilterSamReadsWrapper.java | 17 ++ .../FilterSamReadsWindow.java | 237 +++++++++++++++++- 4 files changed, 285 insertions(+), 2 deletions(-) diff --git a/src/main/java/scriptmanager/main/ScriptManagerGUI.java b/src/main/java/scriptmanager/main/ScriptManagerGUI.java index a93fbde9e..c1db77ac3 100755 --- a/src/main/java/scriptmanager/main/ScriptManagerGUI.java +++ b/src/main/java/scriptmanager/main/ScriptManagerGUI.java @@ -3,6 +3,7 @@ import java.awt.*; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; +import java.util.logging.Filter; import javax.swing.*; @@ -450,6 +451,36 @@ public void run() { sl_pnlBamManip.putConstraint(SpringLayout.WEST, txtNormalizeFasta, 10, SpringLayout.EAST, btnNormalizeFasta); pnlBamManip.add(btnNormalizeFasta); + // FilterSamReads + + JTextArea txtFilterSamReads = new JTextArea(); + sl_pnlBamManip.putConstraint(SpringLayout.NORTH, txtFilterSamReads, 20, SpringLayout.SOUTH, txtNormalizeFasta); + sl_pnlBamManip.putConstraint(SpringLayout.EAST, txtFilterSamReads, -10, SpringLayout.EAST, pnlBamManip); + initializeTextArea(txtFilterSamReads); + + txtFilterSamReads.setText(ToolDescriptions.filter_sam_reads_description); + pnlBamManip.add(txtFilterSamReads); + + JButton btnFilterSamReads = new JButton("Filter Bam Reads"); + btnFilterSamReads.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + EventQueue.invokeLater(new Runnable() { + public void run() { + try { + FilterSamReadsWindow frame = new FilterSamReadsWindow(); + frame.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + }); + sl_pnlBamManip.putConstraint(SpringLayout.NORTH, btnFilterSamReads, 0, SpringLayout.NORTH, txtFilterSamReads); + sl_pnlBamManip.putConstraint(SpringLayout.WEST, btnFilterSamReads, 10, SpringLayout.WEST, pnlBamManip); + sl_pnlBamManip.putConstraint(SpringLayout.WEST, txtFilterSamReads, 10, SpringLayout.EAST, btnFilterSamReads); + pnlBamManip.add(btnFilterSamReads); + // >>>>>>>> BAM_Format_Converter <<<<<<<< JPanel pnlBamConvert = new JPanel(); SpringLayout sl_pnlBamConvert = new SpringLayout(); diff --git a/src/main/java/scriptmanager/objects/ToolDescriptions.java b/src/main/java/scriptmanager/objects/ToolDescriptions.java index 8c313efb5..2a6c27530 100644 --- a/src/main/java/scriptmanager/objects/ToolDescriptions.java +++ b/src/main/java/scriptmanager/objects/ToolDescriptions.java @@ -38,7 +38,7 @@ public class ToolDescriptions { public static final String downsample_sam_description = "Downsample a BAM file to a specified percentage or read count of deterministically random reads."; public static final String validate_sam_file_description = "Validate SAM/BAM files comprehensively, ensuring adherence to the SAM format specification and detecting errors or inconsistencies in alignment data."; public static final String normalize_fasta_description = "Reduce redundant sequences and normalize read coverage in a FASTA file, improving downstream analysis accuracy"; - + public static final String filter_sam_reads_description = "Filter BAM files by applying user-defined filters to include or exclude specific reads based on read lists or genomic intervals"; // BAM Format Converter public static final String bam_to_scidx_description = "Convert BAM file to scIDX file."; public static final String bam_to_gff_description = "Convert BAM file to GFF file."; diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/FilterSamReadsWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/FilterSamReadsWrapper.java index 4551d9f5e..30ac1a014 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Manipulation/FilterSamReadsWrapper.java +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/FilterSamReadsWrapper.java @@ -1,9 +1,11 @@ package scriptmanager.scripts.BAM_Manipulation; import htsjdk.samtools.SAMException; +import picard.sam.FilterSamReads; import java.io.IOException; import java.io.File; +import java.util.ArrayList; /** * @author Erik Pavloski @@ -24,6 +26,21 @@ public class FilterSamReadsWrapper { * @throws SAMException */ public static void run(File input, File output, boolean filter, File readListFile, File intervalList) throws IOException, SAMException { + System.out.println("Filtering Reads"); + final picard.sam.FilterSamReads filterSamReads = new FilterSamReads(); + final ArrayList args = new ArrayList<>(); + args.add("INPUT=" + input.getAbsolutePath()); + args.add("OUTPUT=" + output.getAbsolutePath()); + if (filter) { + args.add("READ_LIST_FILE=" + readListFile.getAbsolutePath()); + args.add("FILTER=includeReadList"); + } else { + args.add("INTERVAL_LIST=" + intervalList.getAbsolutePath()); + args.add("FILTER=includePairedIntervals"); + } + filterSamReads.instanceMain(args.toArray(new String[args.size()])); + + System.out.println("Filtering Complete"); } } diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterSamReadsWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterSamReadsWindow.java index d8683c925..556045706 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterSamReadsWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterSamReadsWindow.java @@ -1,9 +1,244 @@ package scriptmanager.window_interface.BAM_Manipulation; + +import htsjdk.samtools.SAMException; +import scriptmanager.scripts.BAM_Manipulation.BAIIndexerWrapper; +import scriptmanager.scripts.BAM_Manipulation.BAMFileSort; +import scriptmanager.scripts.BAM_Manipulation.FilterSamReadsWrapper; +import scriptmanager.scripts.BAM_Manipulation.ValidateSamWrapper; +import scriptmanager.util.FileSelection; +import scriptmanager.window_interface.BAM_Statistics.CollectBaseDistributionByCycleWindow; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.IOException; +import java.util.Vector; + /** * @author Erik Pavloski * This is the window class for FilterSamReadsWrapper * @see scriptmanager.scripts.BAM_Manipulation.FilterSamReadsWrapper */ -public class FilterSamReadsWindow { +public class FilterSamReadsWindow extends JFrame implements ActionListener, PropertyChangeListener { + private JPanel contentPane; + protected JFileChooser fc = new JFileChooser(new File(System.getProperty("user.dir"))); + + final DefaultListModel expList; + + Vector BAMFiles = new Vector(); + private File OUT_DIR = null; + private File readListFile = null; + private File intervalList = null; + + private JButton btnLoadBam; + private JButton btnRemoveBam; + private JButton btnReadListFile; + private JButton btnIntervalList; + private JButton btnAction; + private JButton btnOutput; + private JCheckBox filterchbx; + + private JLabel outputLabel; + private JLabel lblDefaultToLocal; + private JProgressBar progressBar; + public Task task; + + class Task extends SwingWorker { + @Override + public Void doInBackground() throws IOException { + setProgress(0); + try { + for (int x = 0; x < BAMFiles.size(); x++) { + // Build output filepath + String[] NAME = BAMFiles.get(x).getName().split("\\."); + File OUTPUT = null; + if (OUT_DIR != null) { + OUTPUT = new File(OUT_DIR.getCanonicalPath() + File.separator + NAME[0] + "_filtered.bam"); + } else { + OUTPUT = new File(NAME[0] + "_filtered.bam"); + } + + // Execute Picard wrapper + FilterSamReadsWrapper.run(BAMFiles.get(x), OUTPUT, filterchbx.isSelected(), readListFile, intervalList); + // Update progress + int percentComplete = (int)(((double)(x + 1) / BAMFiles.size()) * 100); + setProgress(percentComplete); + } + setProgress(100); + JOptionPane.showMessageDialog(null, "Filtering Complete"); + } catch (SAMException se) { + JOptionPane.showMessageDialog(null, se.getMessage()); + } + return null; + } + public void done() { + massXable(contentPane, true); + setCursor(null); //turn off the wait cursor + } + } + + public FilterSamReadsWindow() { + setTitle("Filter BAM file reads"); + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + + setBounds(125, 125, 580, 450); + contentPane = new JPanel(); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + SpringLayout sl_contentPane = new SpringLayout(); + contentPane.setLayout(sl_contentPane); + + JScrollPane scrollPane = new JScrollPane(); + sl_contentPane.putConstraint(SpringLayout.WEST, scrollPane, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, scrollPane, -5, SpringLayout.EAST, contentPane); + contentPane.add(scrollPane); + + expList = new DefaultListModel(); + final JList listExp = new JList(expList); + listExp.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + scrollPane.setViewportView(listExp); + + btnLoadBam = new JButton("Load BAM Files"); + sl_contentPane.putConstraint(SpringLayout.WEST, btnLoadBam, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 6, SpringLayout.SOUTH, btnLoadBam); + + btnRemoveBam = new JButton("Remove BAM"); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoadBam, 0, SpringLayout.NORTH, btnRemoveBam); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnRemoveBam, 0, SpringLayout.NORTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnRemoveBam, -5, SpringLayout.EAST, contentPane); + btnRemoveBam.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + while(listExp.getSelectedIndex() > -1) { + BAMFiles.remove(listExp.getSelectedIndex()); + expList.remove(listExp.getSelectedIndex()); + } + } + }); + contentPane.add(btnRemoveBam); + + btnLoadBam.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File[] newBAMFiles = FileSelection.getFiles(fc,"bam"); + if(newBAMFiles != null) { + for(int x = 0; x < newBAMFiles.length; x++) { + BAMFiles.add(newBAMFiles[x]); + expList.addElement(newBAMFiles[x].getName()); + } + } + } + }); + contentPane.add(btnLoadBam); + btnOutput = new JButton("Output Directory"); + btnOutput.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File temp = FileSelection.getOutputDir(fc); + if(temp != null) { + OUT_DIR = temp; + lblDefaultToLocal.setText(OUT_DIR.getAbsolutePath()); + } + } + }); + sl_contentPane.putConstraint(SpringLayout.SOUTH, scrollPane, -3, SpringLayout.NORTH, btnOutput); + sl_contentPane.putConstraint(SpringLayout.WEST, btnOutput, 200, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.SOUTH, btnOutput, -50, SpringLayout.SOUTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnOutput, -200, SpringLayout.EAST, contentPane); + contentPane.add(btnOutput); + + outputLabel = new JLabel("Current Output:"); + sl_contentPane.putConstraint(SpringLayout.WEST, outputLabel, 0, SpringLayout.WEST, scrollPane); + sl_contentPane.putConstraint(SpringLayout.SOUTH, outputLabel, 0, SpringLayout.SOUTH, contentPane); + contentPane.add(outputLabel); + + lblDefaultToLocal = new JLabel("Default to Local Directory"); + sl_contentPane.putConstraint(SpringLayout.NORTH, lblDefaultToLocal, 0, SpringLayout.NORTH, outputLabel); + sl_contentPane.putConstraint(SpringLayout.WEST, lblDefaultToLocal, 6, SpringLayout.EAST, outputLabel); + lblDefaultToLocal.setBackground(Color.WHITE); + contentPane.add(lblDefaultToLocal); + + btnReadListFile = new JButton("Load Read List"); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnReadListFile, 6, SpringLayout.SOUTH, btnLoadBam); + sl_contentPane.putConstraint(SpringLayout.WEST, btnReadListFile, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnReadListFile, 30, SpringLayout.NORTH, btnLoadBam); + btnReadListFile.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File temp = FileSelection.getFile(fc, "txt"); + if (temp != null) { + readListFile = temp; + } + } + }); + contentPane.add(btnReadListFile); + + btnIntervalList = new JButton("Load Interval List"); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnIntervalList, 0, SpringLayout.NORTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.WEST, btnIntervalList, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnIntervalList, 60, SpringLayout.NORTH, btnLoadBam); + sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 60, SpringLayout.NORTH, btnIntervalList); + btnIntervalList.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File temp = FileSelection.getFile(fc, "interval_list"); + if (temp != null) { + intervalList = temp; + } + } + }); + contentPane.add(btnIntervalList); + + btnAction = new JButton("Filter"); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnAction, 30, SpringLayout.NORTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnAction, -5, SpringLayout.EAST, contentPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 60, SpringLayout.NORTH, btnAction); + contentPane.add(btnAction); + + btnAction.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + task = new Task(); + task.addPropertyChangeListener(FilterSamReadsWindow.this); + task.execute(); + } + }); + + filterchbx = new JCheckBox("Select for include read list or don't select for include pair intervals."); + sl_contentPane.putConstraint(SpringLayout.WEST, filterchbx, 0, SpringLayout.WEST, scrollPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, filterchbx, 30, SpringLayout.SOUTH, scrollPane); + filterchbx.setSelected(false); + contentPane.add(filterchbx); + + progressBar = new JProgressBar(); + sl_contentPane.putConstraint(SpringLayout.NORTH, progressBar, -3, SpringLayout.NORTH, lblDefaultToLocal); + sl_contentPane.putConstraint(SpringLayout.EAST, progressBar, 0, SpringLayout.EAST, scrollPane); + progressBar.setStringPainted(true); + contentPane.add(progressBar); + } + @Override + public void actionPerformed(ActionEvent arg0) { + massXable(contentPane, false); + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + task = new Task(); + task.addPropertyChangeListener(this); + task.execute(); + } + /** + * Invoked when task's progress property changes. + */ + public void propertyChange(PropertyChangeEvent evt) { + if ("progress" == evt.getPropertyName()) { + int progress = (Integer) evt.getNewValue(); + progressBar.setValue(progress); + } + } + public void massXable(Container con, boolean status) { + for(Component c : con.getComponents()) { + c.setEnabled(status); + if(c instanceof Container) { massXable((Container)c, status); } + } + } } + From 5d8ef73fc0e67a52f77c9336da971f3a40e85ea5 Mon Sep 17 00:00:00 2001 From: benjaminbeer256 Date: Sat, 16 Nov 2024 08:58:45 -0500 Subject: [PATCH 08/11] added @PG to BAM header --- .../BAM_Manipulation/FilterforPIPseq.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/FilterforPIPseq.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/FilterforPIPseq.java index b513f7bf4..b20b917fc 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Manipulation/FilterforPIPseq.java +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/FilterforPIPseq.java @@ -4,6 +4,7 @@ import htsjdk.samtools.SAMFileHeader; import htsjdk.samtools.SAMFileWriter; import htsjdk.samtools.SAMFileWriterFactory; +import htsjdk.samtools.SAMProgramRecord; import htsjdk.samtools.SAMRecord; import htsjdk.samtools.SAMSequenceRecord; import htsjdk.samtools.SamReader; @@ -16,7 +17,10 @@ import java.io.File; import java.io.IOException; import java.io.PrintStream; +import java.util.ArrayList; +import scriptmanager.cli.BAM_Manipulation.FilterforPIPseqCLI; +import scriptmanager.objects.ToolDescriptions; import scriptmanager.util.FASTAUtilities; public class FilterforPIPseq { @@ -48,6 +52,33 @@ public void run() throws IOException, InterruptedException { IOUtil.assertFileIsWritable(output); final SamReader reader = SamReaderFactory.makeDefault().open(bamFile); reader.getFileHeader().setSortOrder(SAMFileHeader.SortOrder.coordinate); + + Integer idNumber = -1; + String programName = "scriptmanager"; + String previousRecord = null; + //Determine if there are multiple instances of ScriptManager usage + for (SAMProgramRecord record: reader.getFileHeader().getProgramRecords()){ + previousRecord = record.getId(); + if (previousRecord.contains(programName)) { + String numerics = previousRecord.replaceAll("[^0-9]", ""); + if (numerics.isEmpty()) { + idNumber = 0; + } else { + idNumber = Math.max(idNumber, Integer.parseInt(numerics)); + } + } + } + //Create new SAMProgramRecord with appropriate details + String programID = (idNumber > -1)? programName + "." + (idNumber + 1): programName; + SAMProgramRecord record = new SAMProgramRecord(programID); + record.setCommandLine(FilterforPIPseqCLI.getCLIcommand(bamFile, genome, output, SEQ)); + record.setProgramVersion(ToolDescriptions.VERSION); + record.setProgramName(programName); + if (previousRecord != null){ + record.setPreviousProgramGroupId(previousRecord); + } + reader.getFileHeader().addProgramRecord(record); + final SAMFileWriter writer = new SAMFileWriterFactory().makeSAMOrBAMWriter(reader.getFileHeader(), false, output); From 0f28f2e2204a31b6094fdbcf66a2cd0dd499d603 Mon Sep 17 00:00:00 2001 From: benjaminbeer256 Date: Mon, 18 Nov 2024 20:23:19 -0500 Subject: [PATCH 09/11] updated baiindexer --- .classpath | 16 +--------------- .project | 11 +++++++++++ .settings/org.eclipse.buildship.core.prefs | 13 ++++++++++++- .../cli/BAM_Manipulation/BAIIndexerCLI.java | 4 ++-- .../{BAIIndexerWrapper.java => BAIIndexer.java} | 12 ++++++++---- .../BAM_Manipulation/BAIIndexerWindow.java | 2 +- .../BAM_Manipulation/FilterSamReadsWindow.java | 2 +- .../BAM_Manipulation/FilterforPIPseqWindow.java | 2 +- .../BAM_Manipulation/ValidateSamWindow.java | 4 ++-- 9 files changed, 39 insertions(+), 27 deletions(-) rename src/main/java/scriptmanager/scripts/BAM_Manipulation/{BAIIndexerWrapper.java => BAIIndexer.java} (81%) diff --git a/.classpath b/.classpath index 4165f5d79..c9bdbd45b 100644 --- a/.classpath +++ b/.classpath @@ -6,20 +6,6 @@ - - - - - - - - - - - - - - @@ -29,4 +15,4 @@ - \ No newline at end of file + diff --git a/.project b/.project index 7bd8d6639..9bd869e1e 100644 --- a/.project +++ b/.project @@ -20,4 +20,15 @@ org.eclipse.jdt.core.javanature org.eclipse.buildship.core.gradleprojectnature + + + 1731979070369 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + diff --git a/.settings/org.eclipse.buildship.core.prefs b/.settings/org.eclipse.buildship.core.prefs index 9d2efc8e7..18cd189d3 100644 --- a/.settings/org.eclipse.buildship.core.prefs +++ b/.settings/org.eclipse.buildship.core.prefs @@ -1,2 +1,13 @@ +arguments=--init-script /var/folders/vs/qy0cxq3x47v2gjsbgwxmt14r0000gn/T/db3b08fc4a9ef609cb16b96b200fa13e563f396e9bb1ed0905fdab7bc3bc513b.gradle --init-script /var/folders/vs/qy0cxq3x47v2gjsbgwxmt14r0000gn/T/52cde0cfcf3e28b8b7510e992210d9614505e0911af0c190bd590d7158574963.gradle +auto.sync=false +build.scans.enabled=false +connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) connection.project.dir= -eclipse.preferences.version=1 \ No newline at end of file +eclipse.preferences.version=1 +gradle.user.home= +java.home=/Library/Java/JavaVirtualMachines/jdk-22.jdk/Contents/Home +jvm.arguments= +offline.mode=false +override.workspace.settings=true +show.console.view=true +show.executions.view=true diff --git a/src/main/java/scriptmanager/cli/BAM_Manipulation/BAIIndexerCLI.java b/src/main/java/scriptmanager/cli/BAM_Manipulation/BAIIndexerCLI.java index 622c38d59..65c60bae4 100644 --- a/src/main/java/scriptmanager/cli/BAM_Manipulation/BAIIndexerCLI.java +++ b/src/main/java/scriptmanager/cli/BAM_Manipulation/BAIIndexerCLI.java @@ -6,14 +6,14 @@ import java.io.File; import scriptmanager.objects.ToolDescriptions; -import scriptmanager.scripts.BAM_Manipulation.BAIIndexerWrapper; +import scriptmanager.scripts.BAM_Manipulation.BAIIndexer; /** * Prints a message redirecting user to the original CLI tool (Picard * {@link picard.sam.BuildBamIndex}) * * @author Olivia Lang - * @see BAIIndexerWrapper + * @see BAIIndexer */ @Command(name = "bam-indexer", mixinStandardHelpOptions = true, description = ToolDescriptions.bam_indexer_description + "\n"+ diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/BAIIndexerWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/BAIIndexer.java similarity index 81% rename from src/main/java/scriptmanager/scripts/BAM_Manipulation/BAIIndexerWrapper.java rename to src/main/java/scriptmanager/scripts/BAM_Manipulation/BAIIndexer.java index d2b3eaeab..03b3928d3 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Manipulation/BAIIndexerWrapper.java +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/BAIIndexer.java @@ -12,21 +12,24 @@ * @author Erik Pavloski * @see scriptmanager.window_interface.BAM_Manipulation.BAIIndexerWindow */ -public class BAIIndexerWrapper { +public class BAIIndexer { + /** + * Creates a new BAIIndexer object (unnecessary becuase this class is a collection of static methods) + */ + public BAIIndexer(){} /** * Index a BAM file and output said index to a file of the same name with a .bai * extension * * @param input the BAM file to index * @return the BAM index file (.bai) - * @throws IOException + * @throws IOException Invalid file or parameters */ public static File generateIndex(File input) throws IOException { // Tells user that their file is being generated System.out.println("Generating Index File..."); // Build output filepath - String[] NAME = input.getName().split("\\."); - String output = input.getParent() + File.separator + NAME[0] + "_index.bai"; + String output = input.getCanonicalPath() + ".bai"; File retVal = new File(output); // Instatiate Picard object final BuildBamIndex buildBamIndex = new BuildBamIndex(); @@ -36,6 +39,7 @@ public static File generateIndex(File input) throws IOException { args.add("OUTPUT=" + retVal.getAbsolutePath()); // Call Picard with args buildBamIndex.instanceMain(args.toArray(new String[args.size()])); + System.out.println("Index File Generated"); return retVal; } diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/BAIIndexerWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/BAIIndexerWindow.java index 91a958e03..2284c567a 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/BAIIndexerWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/BAIIndexerWindow.java @@ -32,7 +32,7 @@ import scriptmanager.objects.LogItem; import scriptmanager.cli.BAM_Manipulation.BAIIndexerCLI; import scriptmanager.util.FileSelection; -import scriptmanager.scripts.BAM_Manipulation.BAIIndexerWrapper; +import scriptmanager.scripts.BAM_Manipulation.BAIIndexer; /** * GUI for collecting inputs to be processed by diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterSamReadsWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterSamReadsWindow.java index 556045706..8a173c69f 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterSamReadsWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterSamReadsWindow.java @@ -2,7 +2,7 @@ import htsjdk.samtools.SAMException; -import scriptmanager.scripts.BAM_Manipulation.BAIIndexerWrapper; +import scriptmanager.scripts.BAM_Manipulation.BAIIndexer; import scriptmanager.scripts.BAM_Manipulation.BAMFileSort; import scriptmanager.scripts.BAM_Manipulation.FilterSamReadsWrapper; import scriptmanager.scripts.BAM_Manipulation.ValidateSamWrapper; diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterforPIPseqWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterforPIPseqWindow.java index 17572bb6e..58097508b 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterforPIPseqWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterforPIPseqWindow.java @@ -40,7 +40,7 @@ import scriptmanager.objects.ToolDescriptions; import scriptmanager.util.ExtensionFileFilter; import scriptmanager.util.FileSelection; -import scriptmanager.scripts.BAM_Manipulation.BAIIndexerWrapper; +import scriptmanager.scripts.BAM_Manipulation.BAIIndexer; /** * GUI for collecting inputs to be processed by diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java index 1c4c3ef9a..84014987b 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java @@ -1,7 +1,7 @@ package scriptmanager.window_interface.BAM_Manipulation; import htsjdk.samtools.SAMException; -import scriptmanager.scripts.BAM_Manipulation.BAIIndexerWrapper; +import scriptmanager.scripts.BAM_Manipulation.BAIIndexer; import scriptmanager.scripts.BAM_Manipulation.ValidateSamWrapper; import scriptmanager.util.FileSelection; @@ -77,7 +77,7 @@ public Void doInBackground() throws IOException { OUTPUT = new File(NAME[0] + "_validated.html"); } if (chckbxGenerateBaiIndex.isSelected()) { - BAIIndexerWrapper.generateIndex(BAMFiles.get(x)); + BAIIndexer.generateIndex(BAMFiles.get(x)); } mode = !chckbxSummaryMode.isSelected(); // Execute Picard wrapper From 6720bc824bcfb9dd04cfc5f3082764c348c63ae4 Mon Sep 17 00:00:00 2001 From: benjaminbeer256 Date: Sun, 24 Nov 2024 20:52:30 -0500 Subject: [PATCH 10/11] Added logging and @PG headers to BAM tools --- .../cli/BAM_Manipulation/BAIIndexerCLI.java | 3 +- .../scriptmanager/main/ScriptManagerGUI.java | 32 +++ .../objects/ToolDescriptions.java | 4 + .../SamFormatConverterWrapper.java | 34 ++- .../SamtoFastqWrapper.java | 56 +++- .../AddCommentsToBamWrapper.java | 82 ++++++ .../DownsampleSamWrapper.java | 46 +++ .../FilterSamReadsWrapper.java | 32 +++ .../BAM_Manipulation/FilterforPIPseq.java | 33 +-- .../NormalizeFastaWrapper.java | 20 ++ .../BAM_Manipulation/ValidateSamWrapper.java | 54 +++- ...CollectBaseDistributionByCycleWrapper.java | 22 ++ .../java/scriptmanager/util/BAMUtilities.java | 20 ++ .../SamFormatConverterWindow.java | 30 +- .../SamtoFastqWindow.java | 30 +- .../AddCommentsToBamWindow.java | 271 ++++++++++++++++++ .../BAM_Manipulation/DownsampleSamWindow.java | 49 ++-- .../FilterSamReadsWindow.java | 31 +- .../NormalizeFastaWindow.java | 30 +- .../BAM_Manipulation/ValidateSamWindow.java | 31 +- .../CollectBaseDistributionByCycleWindow.java | 31 +- 21 files changed, 824 insertions(+), 117 deletions(-) create mode 100644 src/main/java/scriptmanager/scripts/BAM_Manipulation/AddCommentsToBamWrapper.java create mode 100644 src/main/java/scriptmanager/window_interface/BAM_Manipulation/AddCommentsToBamWindow.java diff --git a/src/main/java/scriptmanager/cli/BAM_Manipulation/BAIIndexerCLI.java b/src/main/java/scriptmanager/cli/BAM_Manipulation/BAIIndexerCLI.java index 65c60bae4..258d6271b 100644 --- a/src/main/java/scriptmanager/cli/BAM_Manipulation/BAIIndexerCLI.java +++ b/src/main/java/scriptmanager/cli/BAM_Manipulation/BAIIndexerCLI.java @@ -6,14 +6,13 @@ import java.io.File; import scriptmanager.objects.ToolDescriptions; -import scriptmanager.scripts.BAM_Manipulation.BAIIndexer; /** * Prints a message redirecting user to the original CLI tool (Picard * {@link picard.sam.BuildBamIndex}) * * @author Olivia Lang - * @see BAIIndexer + * @see scriptmanager.scripts.BAM_Manipulation.BAIIndexer */ @Command(name = "bam-indexer", mixinStandardHelpOptions = true, description = ToolDescriptions.bam_indexer_description + "\n"+ diff --git a/src/main/java/scriptmanager/main/ScriptManagerGUI.java b/src/main/java/scriptmanager/main/ScriptManagerGUI.java index 38fcbace8..bbd088895 100755 --- a/src/main/java/scriptmanager/main/ScriptManagerGUI.java +++ b/src/main/java/scriptmanager/main/ScriptManagerGUI.java @@ -115,6 +115,10 @@ public void run() { // CrossCorrelation pnlStat.add(initializeToolPanel("Cross Correlation", ToolDescriptions.archtex_crosscorrelation_description, Class.forName("scriptmanager.window_interface.BAM_Statistics.CrossCorrelationWindow"))); + + // CollectBaseDistributionByCycle + pnlStat.add(initializeToolPanel("Collect BAM Distribution", ToolDescriptions.collect_base_distribution_by_cycle_description, + Class.forName("scriptmanager.window_interface.BAM_Statistics.CollectBaseDistributionByCycleWindow"))); // ======== BAM_Manipulation ======== JPanel pnlBamManip = new JPanel(); @@ -138,6 +142,26 @@ public void run() { // FilterPIPseq pnlBamManip.add(initializeToolPanel("Filter for PIP-seq", ToolDescriptions.filter_pip_seq_description, Class.forName("scriptmanager.window_interface.BAM_Manipulation.FilterforPIPseqWindow"))); + + // DownsampleSAM + pnlBamManip.add(initializeToolPanel("Downsample SAM/BAM", ToolDescriptions.downsample_sam_description, + Class.forName("scriptmanager.window_interface.BAM_Manipulation.DownsampleSamWindow"))); + + // ValidateSAMFile + pnlBamManip.add(initializeToolPanel("Validate SAM/BAM", ToolDescriptions.validate_sam_file_description, + Class.forName("scriptmanager.window_interface.BAM_Manipulation.ValidateSamWindow"))); + + // NormalizeFasta + pnlBamManip.add(initializeToolPanel("Normalize FASTA File", ToolDescriptions.normalize_fasta_description, + Class.forName("scriptmanager.window_interface.BAM_Manipulation.NormalizeFastaWindow"))); + + // FilterSAMReads + pnlBamManip.add(initializeToolPanel("Filter BAM Reads", ToolDescriptions.filter_sam_reads_description, + Class.forName("scriptmanager.window_interface.BAM_Manipulation.FilterSamReadsWindow"))); + + // FilterSAMReads + pnlBamManip.add(initializeToolPanel("Add Comments to BAM", ToolDescriptions.add_comments_to_bam_description, + Class.forName("scriptmanager.window_interface.BAM_Manipulation.AddCommentsToBamWindow"))); // ======== BAM_Format_Converter ======== JPanel pnlBamConvert = new JPanel(); @@ -160,6 +184,14 @@ public void run() { pnlBamConvert.add(initializeToolPanel("BAM to bedGraph", ToolDescriptions.bam_to_bedgraph_description, Class.forName("scriptmanager.window_interface.BAM_Format_Converter.BAMtobedGraphWindow"))); + // SAMtoFASTQ + pnlBamConvert.add(initializeToolPanel("BAM to FASTQ", ToolDescriptions.sam_to_fastq_description, + Class.forName("scriptmanager.window_interface.BAM_Format_Converter.SamtoFastqWindow"))); + + // SAMFormatConverter + pnlBamConvert.add(initializeToolPanel("SAM to BAM or BAM to SAM", ToolDescriptions.sam_to_fastq_description, + Class.forName("scriptmanager.window_interface.BAM_Format_Converter.SamFormatConverterWindow"))); + // ======== File_Utilities ======== JPanel pnlFileUtility = new JPanel(); BoxLayout bl_pnlFileUtility = new BoxLayout(pnlFileUtility, BoxLayout.PAGE_AXIS); diff --git a/src/main/java/scriptmanager/objects/ToolDescriptions.java b/src/main/java/scriptmanager/objects/ToolDescriptions.java index d5adebea6..13f8fa3dd 100644 --- a/src/main/java/scriptmanager/objects/ToolDescriptions.java +++ b/src/main/java/scriptmanager/objects/ToolDescriptions.java @@ -33,6 +33,7 @@ public class ToolDescriptions { public static final String se_stat_description = "Output BAM Header including alignment statistics and parameters given any indexed (BAI) BAM File."; public static final String pe_stat_description = "Generates Insert-size Histogram statistics (GEO requirement) and outputs BAM Header including alignment statistics and parameters given a sorted and indexed (BAI) paired-end BAM File."; public static final String bam_correlation_description = "Genome-Genome correlations for replicate comparisons given multiple sorted and indexed (BAI) BAM files."; + public static final String collect_base_distribution_by_cycle_description = "Chart the nucleotide distribution per cycle in a BAM file"; public static final String archtex_crosscorrelation_description = ("Calculate optimal tag shift based on ArchTEx implementation (PMID:22302569)"); // BAM Manipulation @@ -45,6 +46,7 @@ public class ToolDescriptions { public static final String validate_sam_file_description = "Validate SAM/BAM files comprehensively, ensuring adherence to the SAM format specification and detecting errors or inconsistencies in alignment data."; public static final String normalize_fasta_description = "Reduce redundant sequences and normalize read coverage in a FASTA file, improving downstream analysis accuracy"; public static final String filter_sam_reads_description = "Filter BAM files by applying user-defined filters to include or exclude specific reads based on read lists or genomic intervals"; + public static final String add_comments_to_bam_description = "Adds comments to the header of a BAM file."; // BAM Format Converter public static final String bam_to_scidx_description = "Convert BAM file to scIDX file."; public static final String bam_to_gff_description = "Convert BAM file to GFF file."; @@ -106,4 +108,6 @@ public class ToolDescriptions { public static final String composite_description = "Generate a Composite Plot PNG from composite data like the output in TagPileup"; public static final String label_heatmap_description = "Create an SVG label for heatmap inputs"; + // Whether or not to log legacy Picard commands + public static final boolean picard_legacy_commends = true; } diff --git a/src/main/java/scriptmanager/scripts/BAM_Format_Converter/SamFormatConverterWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Format_Converter/SamFormatConverterWrapper.java index ac2055ae9..6b46f7f90 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Format_Converter/SamFormatConverterWrapper.java +++ b/src/main/java/scriptmanager/scripts/BAM_Format_Converter/SamFormatConverterWrapper.java @@ -5,6 +5,8 @@ import java.io.IOException; import java.util.ArrayList; +import org.broadinstitute.barclay.argparser.CommandLineParser; + /** * @author Erik Pavloski * @see scriptmanager.window_interface.BAM_Format_Converter.SamFormatConverterWindow @@ -13,14 +15,14 @@ */ public class SamFormatConverterWrapper { + /** + * @param input the BAM/SAM file to be converted + * @param output the output BAM/SAM file + * + * @throws IOException + * @throws SAMException + */ public static void run(File input, File output) throws IOException, SAMException { - /** - * @param input the BAM/SAM file to be converted - * @param output the output BAM/SAM file - * - * @throws IOException - * @throws SAMException - */ System.out.println("Converting file..."); // Converts the SAM/BAM file to fastq final picard.sam.SamFormatConverter samFormatConverter = new picard.sam.SamFormatConverter(); @@ -30,4 +32,22 @@ public static void run(File input, File output) throws IOException, SAMException samFormatConverter.instanceMain(args.toArray(new String[args.size()])); System.out.println("File converted"); } + + /** + * Reconstruct CLI command + * + * @param input the BAM/SAM file to be converted + * @param output the output BAM/SAM file + */ + public static String getCLIcommand(File input, File output) { + String command = "java -jar $PICARD "; + final CommandLineParser parser = new picard.sam.SamFormatConverter().getCommandLineParser(); + final ArrayList args = new ArrayList<>(); + args.add("INPUT=" + input.getAbsolutePath()); + args.add("OUTPUT=" + output.getAbsolutePath()); + String[] argv = args.toArray(new String[args.size()]); + parser.parseArguments(System.err, argv); + command += parser.getCommandLine(); + return command; + } } diff --git a/src/main/java/scriptmanager/scripts/BAM_Format_Converter/SamtoFastqWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Format_Converter/SamtoFastqWrapper.java index 42380ecab..4aeaffd6c 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Format_Converter/SamtoFastqWrapper.java +++ b/src/main/java/scriptmanager/scripts/BAM_Format_Converter/SamtoFastqWrapper.java @@ -5,6 +5,8 @@ import java.io.IOException; import java.util.ArrayList; +import org.broadinstitute.barclay.argparser.CommandLineParser; + /** * @author Erik Pavloski * @see scriptmanager.window_interface.BAM_Format_Converter.SamtoFastqWindow @@ -12,17 +14,18 @@ */ public class SamtoFastqWrapper { -public static void run(File input, File output, boolean compress, boolean perRG, File outputDir) throws IOException, SAMException { - /** - * @param input the BAM/SAM file to be converted - * @param output the output fastq file - * @param compress a boolean to determine whether to compress the output or not - * default = false = do not compress - * @param perRG a boolean to determine whether to output per read group. Compress does this as well - * @param outputDir the output directory - * @throws IOException - * @throws SAMException - */ + /** + * @param input the BAM/SAM file to be converted + * @param output the output fastq file + * @param compress a boolean to determine whether to compress the output or not + * default = false = do not compress + * @param perRG a boolean to determine whether to output per read group. Compress does this as well + * @param outputDir the output directory + * @throws IOException + * @throws SAMException + */ + public static void run(File input, File output, boolean compress, boolean perRG, File outputDir) throws IOException, SAMException { + System.out.println("Converting file..."); // Converts the SAM/BAM file to fastq final picard.sam.SamToFastq samToFastq = new picard.sam.SamToFastq(); @@ -40,4 +43,35 @@ public static void run(File input, File output, boolean compress, boolean perRG, samToFastq.instanceMain(args.toArray(new String[args.size()])); System.out.println("File converted"); } + + /** + * Reconstruct CLI command + * + * @param input the BAM/SAM file to be converted + * @param output the output fastq file + * @param compress a boolean to determine whether to compress the output or not + * default = false = do not compress + * @param perRG a boolean to determine whether to output per read group. Compress does this as well + * @param outputDir the output directory + * @throws IOException + */ + public static String getCLIcommand(File input, File output, boolean compress, boolean perRG, File outputDir) throws IOException { + String command = "java -jar $PICARD "; + final CommandLineParser parser = new picard.sam.SamToFastq().getCommandLineParser(); + final ArrayList args = new ArrayList<>(); + args.add("INPUT=" + input.getAbsolutePath()); + if (compress) { + args.add("OUTPUT_DIR=" + outputDir.getCanonicalPath()); + args.add("COMPRESS_OUTPUTS_PER_RG=" + true); + } else if (perRG) { + args.add("OUTPUT_DIR=" + outputDir.getCanonicalPath()); + args.add("OUTPUT_PER_RG=" + true); + } else { + args.add("FASTQ=" + output.getAbsolutePath()); + } + String[] argv = args.toArray(new String[args.size()]); + parser.parseArguments(System.err, argv); + command += parser.getCommandLine(); + return command; + } } diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/AddCommentsToBamWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/AddCommentsToBamWrapper.java new file mode 100644 index 000000000..95237775b --- /dev/null +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/AddCommentsToBamWrapper.java @@ -0,0 +1,82 @@ +package scriptmanager.scripts.BAM_Manipulation; + +import htsjdk.samtools.BamFileIoUtils; +import htsjdk.samtools.SAMException; +import htsjdk.samtools.SAMProgramRecord; +import htsjdk.samtools.SamReader; +import htsjdk.samtools.SamReaderFactory; +import picard.cmdline.CommandLineSyntaxTranslater; +import picard.sam.AddCommentsToBam; +import scriptmanager.objects.ToolDescriptions; +import scriptmanager.util.BAMUtilities; + +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.nio.file.Files; +import java.util.ArrayList; + +import org.broadinstitute.barclay.argparser.CommandLineParser; + +/** + * @author Erik Pavloski + * This is the Wrapper class for the AddCommentsToBam Picard tool + * @see scriptmanager.window_interface.BAM_Manipulation.AddCommentsToBamWindow + */ +public class AddCommentsToBamWrapper { + /** + * @param input the bam file to add comments to + * @param output the output file + * + * @throws IOException + * @throws SAMException + */ + public static void run(File input, File output, ArrayList comments) throws IOException, SAMException { + System.out.println("Add Comments To Bam"); + + final picard.sam.AddCommentsToBam addComments = new picard.sam.AddCommentsToBam(); + final ArrayList args = new ArrayList<>(); + args.add("INPUT=" + input.getAbsolutePath()); + args.add("OUTPUT=" + output.getAbsolutePath()); + for (String c: comments){ + args.add("C=" + c); + } + addComments.instanceMain(args.toArray(new String[args.size()])); + + // Copy output + File temp = new File(output.toPath() + "copy"); + Files.copy(output.toPath(), new PrintStream(temp)); + // Create and add new record + SamReader reader = SamReaderFactory.makeDefault().open(temp); + String command = AddCommentsToBamWrapper.getCLIcommand(input, output, comments); + SAMProgramRecord newRecord = BAMUtilities.getPGRecord(reader.getFileHeader(), addComments.getClass().getSimpleName(), command, addComments.getVersion()); + reader.getFileHeader().addProgramRecord(newRecord); + BamFileIoUtils.reheaderBamFile(reader.getFileHeader(), temp, output, false, false); + // Delete copy + temp.delete(); + System.out.println("SAM/BAM file downsampled"); + + System.out.println("Comments Added"); + } + + /** + * Reconstruct CLI command + * + * @param input the bam file to add comments to + * @param output the output file + */ + public static String getCLIcommand(File input, File output, ArrayList comments) { + String command = "java -jar $PICARD "; + final CommandLineParser parser = new picard.sam.AddCommentsToBam().getCommandLineParser(); + final ArrayList args = new ArrayList<>(); + args.add("INPUT=" + input.getAbsolutePath()); + args.add("OUTPUT=" + output.getAbsolutePath()); + for (String c: comments){ + args.add("C=" + c); + } + String[] argv = args.toArray(new String[args.size()]); + parser.parseArguments(System.err, argv); + command += parser.getCommandLine(); + return command; + } +} diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamWrapper.java index 3efef30d6..e449848f8 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamWrapper.java +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/DownsampleSamWrapper.java @@ -1,10 +1,19 @@ package scriptmanager.scripts.BAM_Manipulation; +import htsjdk.samtools.BamFileIoUtils; import htsjdk.samtools.SAMException; +import htsjdk.samtools.SAMProgramRecord; +import htsjdk.samtools.SamReader; +import htsjdk.samtools.SamReaderFactory; +import scriptmanager.util.BAMUtilities; import java.io.File; import java.io.IOException; +import java.io.PrintStream; +import java.nio.file.Files; import java.util.ArrayList; + +import org.broadinstitute.barclay.argparser.CommandLineParser; /** * @author Erik Pavloski * @see scriptmanager.window_interface.BAM_Manipulation.DownsampleSamWindow @@ -39,6 +48,43 @@ public static void run(File input, File output, double probability, Long seed) t args.add("PROBABILITY=" + probability); args.add("RANDOM_SEED=" + seed); downsampleSam.instanceMain(args.toArray(new String[args.size()])); + + // Copy output + File temp = new File(output.toPath() + "copy"); + Files.copy(output.toPath(), new PrintStream(temp)); + // Create and add new record + SamReader reader = SamReaderFactory.makeDefault().open(temp); + String command = DownsampleSamWrapper.getCLIcommand(input, output, probability, seed); + SAMProgramRecord newRecord = BAMUtilities.getPGRecord(reader.getFileHeader(), downsampleSam.getClass().getSimpleName(), command, downsampleSam.getVersion()); + reader.getFileHeader().addProgramRecord(newRecord); + BamFileIoUtils.reheaderBamFile(reader.getFileHeader(), temp, output, false, false); + // Delete copy + temp.delete(); System.out.println("SAM/BAM file downsampled"); } + + /** + * Reconstruct CLI command + * + * @param input the BAM/SAM file to be downsampled + * @param output the downsampled file + * @param probability the probability of keeping reads. + * 0.5 default -> 50% reduction in data. + * Smaller number -> less data once down-sampled + * @param seed the custom seed that the user entered. + * Defaults to null if no custom seed is entered which just spools a random seed + */ + public static String getCLIcommand(File input, File output, double probability, Long seed) { + String command = "java -jar $PICARD "; + final CommandLineParser parser = new picard.sam.DownsampleSam().getCommandLineParser(); + final ArrayList args = new ArrayList<>(); + args.add("INPUT=" + input.getAbsolutePath()); + args.add("OUTPUT=" + output.getAbsolutePath()); + args.add("PROBABILITY=" + probability); + args.add("RANDOM_SEED=" + seed); + String[] argv = args.toArray(new String[args.size()]); + parser.parseArguments(System.err, argv); + command += parser.getCommandLine(); + return command; + } } diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/FilterSamReadsWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/FilterSamReadsWrapper.java index 30ac1a014..8672c703a 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Manipulation/FilterSamReadsWrapper.java +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/FilterSamReadsWrapper.java @@ -7,6 +7,8 @@ import java.io.File; import java.util.ArrayList; +import org.broadinstitute.barclay.argparser.CommandLineParser; + /** * @author Erik Pavloski * This code runs the FilterSamReads Picard tool @@ -43,4 +45,34 @@ public static void run(File input, File output, boolean filter, File readListFil System.out.println("Filtering Complete"); } + + /** + * Reconstruct CLI command + * + * @param input the file to be filtered + * @param output the file to be outputted + * @param filter which filter the user wants to use can be includeReadList or includePairIntervals + * true == includeReadList + * false == includePairIntervals + * @param readListFile the txt file output for the read list if that is the chosen filter + * @param intervalList the list of interval output file if that is the desired filter + */ + public static String getCLIcommand(File input, File output, boolean filter, File readListFile, File intervalList) { + String command = "java -jar $PICARD "; + final CommandLineParser parser = new picard.sam.FilterSamReads().getCommandLineParser(); + final ArrayList args = new ArrayList<>(); + args.add("INPUT=" + input.getAbsolutePath()); + args.add("OUTPUT=" + output.getAbsolutePath()); + if (filter) { + args.add("READ_LIST_FILE=" + readListFile.getAbsolutePath()); + args.add("FILTER=includeReadList"); + } else { + args.add("INTERVAL_LIST=" + intervalList.getAbsolutePath()); + args.add("FILTER=includePairedIntervals"); + } + String[] argv = args.toArray(new String[args.size()]); + parser.parseArguments(System.err, argv); + command += parser.getCommandLine(); + return command; + } } diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/FilterforPIPseq.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/FilterforPIPseq.java index 4d810bcd5..ba45dc313 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Manipulation/FilterforPIPseq.java +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/FilterforPIPseq.java @@ -21,6 +21,7 @@ import scriptmanager.cli.BAM_Manipulation.FilterforPIPseqCLI; import scriptmanager.objects.ToolDescriptions; +import scriptmanager.util.BAMUtilities; import scriptmanager.util.FASTAUtilities; /** @@ -74,35 +75,11 @@ public void run() throws IOException, InterruptedException { IOUtil.assertFileIsWritable(output); final SamReader reader = SamReaderFactory.makeDefault().open(bamFile); reader.getFileHeader().setSortOrder(SAMFileHeader.SortOrder.coordinate); - - Integer idNumber = -1; - String programName = "scriptmanager"; - String previousRecord = null; - //Determine if there are multiple instances of ScriptManager usage - for (SAMProgramRecord record: reader.getFileHeader().getProgramRecords()){ - previousRecord = record.getId(); - if (previousRecord.contains(programName)) { - String numerics = previousRecord.replaceAll("[^0-9]", ""); - if (numerics.isEmpty()) { - idNumber = 0; - } else { - idNumber = Math.max(idNumber, Integer.parseInt(numerics)); - } - } - } - //Create new SAMProgramRecord with appropriate details - String programID = (idNumber > -1)? programName + "." + (idNumber + 1): programName; - SAMProgramRecord record = new SAMProgramRecord(programID); - record.setCommandLine(FilterforPIPseqCLI.getCLIcommand(bamFile, genome, output, SEQ)); - record.setProgramVersion(ToolDescriptions.VERSION); - record.setProgramName(programName); - if (previousRecord != null){ - record.setPreviousProgramGroupId(previousRecord); - } + // Append @PG annotation to header and instantiate writer + String command = FilterforPIPseqCLI.getCLIcommand(bamFile, genome, output, SEQ); + SAMProgramRecord record = BAMUtilities.getPGRecord(reader.getFileHeader(), "scriptmanager", command, ToolDescriptions.VERSION); reader.getFileHeader().addProgramRecord(record); - - final SAMFileWriter writer = new SAMFileWriterFactory().makeSAMOrBAMWriter(reader.getFileHeader(), false, - output); + final SAMFileWriter writer = new SAMFileWriterFactory().makeSAMOrBAMWriter(reader.getFileHeader(), false, output); printBoth(bamFile.getName()); // output file name to textarea diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/NormalizeFastaWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/NormalizeFastaWrapper.java index 14ec0b966..8874589d7 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Manipulation/NormalizeFastaWrapper.java +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/NormalizeFastaWrapper.java @@ -7,6 +7,8 @@ import java.io.IOException; import java.util.ArrayList; +import org.broadinstitute.barclay.argparser.CommandLineParser; + /** * @author Erik Pavloski * This is the Wrapper class for the NormalizeFasta Picard tool @@ -31,4 +33,22 @@ public static void run(File input, File output) throws IOException, SAMException System.out.println("File Normalized"); } + + /** + * Reconstruct CLI command + * + * @param input the file to be filtered + * @param output the file to be outputted + */ + public static String getCLIcommand(File input, File output) { + String command = "java -jar $PICARD "; + final CommandLineParser parser = new picard.reference.NormalizeFasta().getCommandLineParser(); + final ArrayList args = new ArrayList<>(); + args.add("INPUT=" + input.getAbsolutePath()); + args.add("OUTPUT=" + output.getAbsolutePath()); + String[] argv = args.toArray(new String[args.size()]); + parser.parseArguments(System.err, argv); + command += parser.getCommandLine(); + return command; + } } diff --git a/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamWrapper.java index 8df4e062f..54fb4b9c3 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamWrapper.java +++ b/src/main/java/scriptmanager/scripts/BAM_Manipulation/ValidateSamWrapper.java @@ -5,6 +5,8 @@ import java.io.IOException; import java.util.ArrayList; +import org.broadinstitute.barclay.argparser.CommandLineParser; + /** * @author Erik Pavloski * @see scriptmanager.window_interface.BAM_Manipulation.ValidateSamWindow @@ -14,19 +16,20 @@ public class ValidateSamWrapper { + /** + * + * @param input The BAM/SAM file to be Validated + * @param output the output of the validation + * @param mode Allows the user to select verbose or summary mode. True = verbose - false = summary + * @param referenceGenome Allows the user to add reference sequence if needed + * @param maxOutput Allows customization of the maximum number of outputs in verbose mode + * + * @throws IOException + * @throws SAMException + * + */ public static void run(File input, File output, boolean mode, File referenceGenome, int maxOutput) throws IOException, SAMException{ - /** - * - * @param input The BAM/SAM file to be Validated - * @param output the output of the validation - * @param mode Allows the user to select verbose or summary mode. True = verbose - false = summary - * @param referenceGenome Allows the user to add reference sequence if needed - * @param maxOutput Allows customization of the maximum number of outputs in verbose mode - * - * @throws IOException - * @throws SAMException - * - */ + System.out.println("Validating SAM/BAM file..."); // Validates the SAM/BAM file final picard.sam.ValidateSamFile validateSam = new picard.sam.ValidateSamFile(); @@ -42,4 +45,31 @@ public static void run(File input, File output, boolean mode, File referenceGeno validateSam.instanceMain(args.toArray(new String[args.size()])); System.out.println("SAM/BAM file validated"); } + + /** + * Reconstruct CLI command + * + * @param input The BAM/SAM file to be Validated + * @param output the output of the validation + * @param mode Allows the user to select verbose or summary mode. True = verbose - false = summary + * @param referenceGenome Allows the user to add reference sequence if needed + * @param maxOutput Allows customization of the maximum number of outputs in verbose mode + */ + public static String getCLIcommand(File input, File output, boolean mode, File referenceGenome, int maxOutput) { + String command = "java -jar $PICARD "; + final CommandLineParser parser = new picard.sam.ValidateSamFile().getCommandLineParser(); + final ArrayList args = new ArrayList<>(); + args.add("INPUT=" + input.getAbsolutePath()); + args.add("OUTPUT=" + output.getAbsolutePath()); + String modeString = mode ? "VERBOSE" : "SUMMARY"; + args.add("MODE=" + modeString); + args.add("MAX_OUTPUT=" + maxOutput); + if (referenceGenome != null) { + args.add("REFERENCE_SEQUENCE=" + referenceGenome.getAbsolutePath()); + } + String[] argv = args.toArray(new String[args.size()]); + parser.parseArguments(System.err, argv); + command += parser.getCommandLine(); + return command; + } } diff --git a/src/main/java/scriptmanager/scripts/BAM_Statistics/CollectBaseDistributionByCycleWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Statistics/CollectBaseDistributionByCycleWrapper.java index 6dea7fc00..004a0ca62 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Statistics/CollectBaseDistributionByCycleWrapper.java +++ b/src/main/java/scriptmanager/scripts/BAM_Statistics/CollectBaseDistributionByCycleWrapper.java @@ -5,6 +5,8 @@ import java.io.IOException; import java.util.ArrayList; +import org.broadinstitute.barclay.argparser.CommandLineParser; + /** * @author Erik Pavloski * @see scriptmanager.window_interface.BAM_Statistics.CollectBaseDistributionByCycleWindow @@ -32,4 +34,24 @@ public static void run(File input, File output, File chartOutput) throws IOExcep collectBaseDistributionByCycle.instanceMain(args.toArray(new String[args.size()])); System.out.println("Analysis complete"); } + + /** + * Reconstruct CLI command + * + * @param input the bam file to be analysed + * @param output the output text file + * @param chartOutput the pdf chart output + */ + public static String getCLIcommand(File input, File output, File chartOutput) { + String command = "java -jar $PICARD "; + final CommandLineParser parser = new picard.reference.NormalizeFasta().getCommandLineParser(); + final ArrayList args = new ArrayList<>(); + args.add("INPUT=" + input.getAbsolutePath()); + args.add("OUTPUT=" + output.getAbsolutePath()); + args.add("CHART_OUTPUT=" + chartOutput.getAbsolutePath()); + String[] argv = args.toArray(new String[args.size()]); + parser.parseArguments(System.err, argv); + command += parser.getCommandLine(); + return command; + } } diff --git a/src/main/java/scriptmanager/util/BAMUtilities.java b/src/main/java/scriptmanager/util/BAMUtilities.java index 305c14859..8cc289bd8 100644 --- a/src/main/java/scriptmanager/util/BAMUtilities.java +++ b/src/main/java/scriptmanager/util/BAMUtilities.java @@ -10,6 +10,8 @@ import java.util.Scanner; import htsjdk.samtools.AbstractBAMFileIndex; +import htsjdk.samtools.SAMFileHeader; +import htsjdk.samtools.SAMProgramRecord; import htsjdk.samtools.SAMRecord; import htsjdk.samtools.SAMSequenceRecord; import htsjdk.samtools.SamReader; @@ -19,6 +21,7 @@ import scriptmanager.objects.Exceptions.OptionException; import scriptmanager.objects.PileupParameters; +import scriptmanager.objects.ToolDescriptions; import scriptmanager.objects.CoordinateObjects.BEDCoord; /** @@ -287,4 +290,21 @@ private static HashMap> loadBlacklist(File BLACKFile scan.close(); return BLACKLIST; } + + /** + * Create program record with non-overlapping ID + * @param header Original header + * @param programName Name of the application + * @param command CLI command + * @param version Version of tool/command + * @return Program record with a non-overlapping ID + */ + public static SAMProgramRecord getPGRecord(final SAMFileHeader header, String programName, String command, String version) { + final SAMFileHeader.PgIdGenerator pgIdGenerator = new SAMFileHeader.PgIdGenerator(header); + final SAMProgramRecord programRecord = new SAMProgramRecord(pgIdGenerator.getNonCollidingId(programName)); + programRecord.setProgramName(programName); + programRecord.setCommandLine(command); + programRecord.setProgramVersion(version); + return programRecord; + } } diff --git a/src/main/java/scriptmanager/window_interface/BAM_Format_Converter/SamFormatConverterWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Format_Converter/SamFormatConverterWindow.java index 8f3a20f31..6ab30d20e 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Format_Converter/SamFormatConverterWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Format_Converter/SamFormatConverterWindow.java @@ -1,6 +1,7 @@ package scriptmanager.window_interface.BAM_Format_Converter; import htsjdk.samtools.SAMException; +import scriptmanager.objects.LogItem; import scriptmanager.scripts.BAM_Format_Converter.SamFormatConverterWrapper; import scriptmanager.scripts.BAM_Format_Converter.SamtoFastqWrapper; import scriptmanager.util.FileSelection; @@ -14,6 +15,8 @@ import java.beans.PropertyChangeListener; import java.io.File; import java.io.IOException; +import java.sql.Timestamp; +import java.util.Date; import java.util.Vector; public class SamFormatConverterWindow extends JFrame implements ActionListener, PropertyChangeListener { @@ -40,6 +43,7 @@ class Task extends SwingWorker { @Override public Void doInBackground() throws IOException { setProgress(0); + LogItem old_li = null; try { for(int x = 0; x < BAMFiles.size(); x++) { // Build output filepath @@ -58,13 +62,22 @@ public Void doInBackground() throws IOException { OUTPUT = new File(NAME[0] + "_converted.sam"); } } - + // Initialize log item + String command = SamFormatConverterWrapper.getCLIcommand(BAMFiles.get(x), OUTPUT); + System.err.println(command); + LogItem new_li = new LogItem(command); + firePropertyChange("log", old_li, new_li); // Execute Picard wrapper SamFormatConverterWrapper.run(BAMFiles.get(x), OUTPUT); // Update progress int percentComplete = (int)(((double)(x + 1) / BAMFiles.size()) * 100); setProgress(percentComplete); + // Update LogItem + new_li.setStopTime(new Timestamp(new Date().getTime())); + new_li.setStatus(0); + old_li = new_li; } + firePropertyChange("log", old_li, null); setProgress(100); JOptionPane.showMessageDialog(null, "Conversion Complete"); } catch (SAMException se) { @@ -206,12 +219,15 @@ public void actionPerformed(ActionEvent arg0) { /** * Invoked when task's progress property changes. */ - public void propertyChange(PropertyChangeEvent evt) { - if ("progress" == evt.getPropertyName()) { - int progress = (Integer) evt.getNewValue(); - progressBar.setValue(progress); - } - } + @Override + public void propertyChange(PropertyChangeEvent evt) { + if ("progress" == evt.getPropertyName()) { + int progress = (Integer) evt.getNewValue(); + progressBar.setValue(progress); + } else if ("log" == evt.getPropertyName()) { + firePropertyChange("log", evt.getOldValue(), evt.getNewValue()); + } + } public void massXable(Container con, boolean status) { for(Component c : con.getComponents()) { c.setEnabled(status); diff --git a/src/main/java/scriptmanager/window_interface/BAM_Format_Converter/SamtoFastqWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Format_Converter/SamtoFastqWindow.java index af2f692ab..bbffbdd3a 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Format_Converter/SamtoFastqWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Format_Converter/SamtoFastqWindow.java @@ -1,7 +1,9 @@ package scriptmanager.window_interface.BAM_Format_Converter; import htsjdk.samtools.SAMException; +import scriptmanager.objects.LogItem; import scriptmanager.scripts.BAM_Format_Converter.SamtoFastqWrapper; +import scriptmanager.scripts.BAM_Manipulation.ValidateSamWrapper; import scriptmanager.util.FileSelection; import javax.swing.*; @@ -13,6 +15,8 @@ import java.beans.PropertyChangeListener; import java.io.File; import java.io.IOException; +import java.sql.Timestamp; +import java.util.Date; import java.util.Vector; public class SamtoFastqWindow extends JFrame implements ActionListener, PropertyChangeListener { @@ -43,6 +47,7 @@ class Task extends SwingWorker { @Override public Void doInBackground() throws IOException { setProgress(0); + LogItem old_li = null; try { for(int x = 0; x < BAMFiles.size(); x++) { // Build output filepath @@ -55,12 +60,22 @@ public Void doInBackground() throws IOException { } compress = chckbxCompress.isSelected(); perRG = chckbxPerRG.isSelected(); + // Initialize log item + String command = SamtoFastqWrapper.getCLIcommand(BAMFiles.get(x), OUTPUT, compress, perRG, OUT_DIR); + System.err.println(command); + LogItem new_li = new LogItem(command); + firePropertyChange("log", old_li, new_li); // Execute Picard wrapper SamtoFastqWrapper.run(BAMFiles.get(x), OUTPUT, compress, perRG, OUT_DIR); // Update progress int percentComplete = (int)(((double)(x + 1) / BAMFiles.size()) * 100); setProgress(percentComplete); + // Update LogItem + new_li.setStopTime(new Timestamp(new Date().getTime())); + new_li.setStatus(0); + old_li = new_li; } + firePropertyChange("log", old_li, null); setProgress(100); JOptionPane.showMessageDialog(null, "Conversion Complete"); } catch (SAMException se) { @@ -213,12 +228,15 @@ public void actionPerformed(ActionEvent arg0) { /** * Invoked when task's progress property changes. */ - public void propertyChange(PropertyChangeEvent evt) { - if ("progress" == evt.getPropertyName()) { - int progress = (Integer) evt.getNewValue(); - progressBar.setValue(progress); - } - } + @Override + public void propertyChange(PropertyChangeEvent evt) { + if ("progress" == evt.getPropertyName()) { + int progress = (Integer) evt.getNewValue(); + progressBar.setValue(progress); + } else if ("log" == evt.getPropertyName()) { + firePropertyChange("log", evt.getOldValue(), evt.getNewValue()); + } + } public void massXable(Container con, boolean status) { for(Component c : con.getComponents()) { c.setEnabled(status); diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/AddCommentsToBamWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/AddCommentsToBamWindow.java new file mode 100644 index 000000000..6b0deb9e5 --- /dev/null +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/AddCommentsToBamWindow.java @@ -0,0 +1,271 @@ +package scriptmanager.window_interface.BAM_Manipulation; + +import htsjdk.samtools.SAMException; +import picard.sam.AddCommentsToBam; +import scriptmanager.cli.BAM_Format_Converter.BAMtobedGraphCLI; +import scriptmanager.objects.LogItem; +import scriptmanager.objects.PasteableTable; +import scriptmanager.scripts.BAM_Manipulation.AddCommentsToBamWrapper; +import scriptmanager.util.FileSelection; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.DefaultTableModel; + +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.IOException; +import java.sql.Timestamp; +import java.util.Vector; +import java.util.ArrayList; +import java.util.Date; + +/** + * @author Erik Pavloski + * This is the window class for the AddCommentsToBam Picard tool + * @see scriptmanager.scripts.BAM_Manipulation.AddCommentsToBamWrapper + */ +public class AddCommentsToBamWindow extends JFrame implements ActionListener, PropertyChangeListener { + private JPanel contentPane; + protected JFileChooser fc = new JFileChooser(new File(System.getProperty("user.dir"))); + + final DefaultListModel expList; + + Vector BAMFiles = new Vector(); + private File OUT_DIR = null; + + private JButton btnLoadBam; + private JButton btnRemoveBam; + private JButton btnAddComment; + private JButton btnRemoveComment; + private JLabel outputLabel; + private JLabel lblDefaultToLocal; + private JButton btnOutput; + private JButton btnComment; + private JProgressBar progressBar; + private DefaultTableModel commentTable; + public Task task; + class Task extends SwingWorker { + @Override + public Void doInBackground() throws IOException { + setProgress(0); + LogItem old_li = null; + try { + ArrayList comments = new ArrayList(); + for (int i = 0; i < commentTable.getRowCount(); i++){ + comments.add(commentTable.getValueAt(i, 0).toString()); + } + if (comments.size() == 0) { + JOptionPane.showMessageDialog(null, "No Comments Provided!!!"); + } else { + for (int x = 0; x < BAMFiles.size(); x++) { + // Build output filepath + String[] NAME = BAMFiles.get(x).getName().split("\\."); + File OUTPUT = null; + if (OUT_DIR != null) { + OUTPUT = new File(OUT_DIR.getCanonicalPath() + File.separator + NAME[0] + "_commented.bam"); + } else { + OUTPUT = new File(NAME[0] + "_commented.bam"); + } + // Initialize log item + String command = AddCommentsToBamWrapper.getCLIcommand(BAMFiles.get(x), OUTPUT, comments); + System.err.println(command); + LogItem new_li = new LogItem(command); + firePropertyChange("log", old_li, new_li); + // Run Wrapper + AddCommentsToBamWrapper.run(BAMFiles.get(x), OUTPUT, comments); + // Update progress + int percentComplete = (int)(((double)(x + 1) / BAMFiles.size()) * 100); + setProgress(percentComplete); + // Update LogItem + new_li.setStopTime(new Timestamp(new Date().getTime())); + new_li.setStatus(0); + old_li = new_li; + } + firePropertyChange("log", old_li, null); + setProgress(100); + JOptionPane.showMessageDialog(null, "Comments Added"); + } + } catch (SAMException se) { + JOptionPane.showMessageDialog(null, se.getMessage()); + } + return null; + } + public void done() { + massXable(contentPane, true); + setCursor(null); //turn off the wait cursor + } + } + + public AddCommentsToBamWindow() { + setTitle("Add Comments to BAM File"); + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + setBounds(125, 125, 580, 550); + + contentPane = new JPanel(); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + SpringLayout sl_contentPane = new SpringLayout(); + contentPane.setLayout(sl_contentPane); + + JScrollPane scrollPane = new JScrollPane(); + sl_contentPane.putConstraint(SpringLayout.WEST, scrollPane, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, scrollPane, -5, SpringLayout.EAST, contentPane); + sl_contentPane.putConstraint(SpringLayout.SOUTH, scrollPane, 200, SpringLayout.NORTH, contentPane); + contentPane.add(scrollPane); + + expList = new DefaultListModel<>(); + final JList listExp = new JList<>(expList); + listExp.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + scrollPane.setViewportView(listExp); + + btnLoadBam = new JButton("Load BAM Files"); + sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 6, SpringLayout.SOUTH, btnLoadBam); + sl_contentPane.putConstraint(SpringLayout.WEST, btnLoadBam, 0, SpringLayout.WEST, scrollPane); + btnLoadBam.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File[] newBAMFiles = FileSelection.getFiles(fc,"bam"); + if(newBAMFiles != null) { + for(int x = 0; x < newBAMFiles.length; x++) { + BAMFiles.add(newBAMFiles[x]); + expList.addElement(newBAMFiles[x].getName()); + } + } + } + }); + contentPane.add(btnLoadBam); + + btnRemoveBam = new JButton("Remove BAM"); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnLoadBam, 0, SpringLayout.NORTH, btnRemoveBam); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnRemoveBam, 0, SpringLayout.NORTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnRemoveBam, -5, SpringLayout.EAST, contentPane); + btnRemoveBam.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + while(listExp.getSelectedIndex() > -1) { + BAMFiles.remove(listExp.getSelectedIndex()); + expList.remove(listExp.getSelectedIndex()); + } + } + }); + contentPane.add(btnRemoveBam); + + btnAddComment = new JButton("Add Comment"); + btnAddComment.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + commentTable.addRow(new Object[] { "" }); + } + } + ); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnAddComment, 6, SpringLayout.SOUTH, scrollPane); + sl_contentPane.putConstraint(SpringLayout.WEST, btnAddComment, 0, SpringLayout.WEST, scrollPane); + contentPane.add(btnAddComment); + + btnRemoveComment = new JButton("Remove Comment"); + btnRemoveComment.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + commentTable.removeRow(commentTable.getRowCount() - 1); + } + } + ); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnRemoveComment, 6, SpringLayout.SOUTH, scrollPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnRemoveComment, 0, SpringLayout.EAST, scrollPane); + contentPane.add(btnRemoveComment); + + String[] TableHeader = { "Comments" }; + commentTable = new DefaultTableModel(null, TableHeader); + JTable tableScale = new JTable(commentTable); + // Allow for the selection of multiple OR individual cells across either rows or columns + tableScale.setCellSelectionEnabled(true); + tableScale.setColumnSelectionAllowed(true); + tableScale.setRowSelectionAllowed(true); + DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer(); + centerRenderer.setHorizontalAlignment( JLabel.CENTER ); + tableScale.setDefaultRenderer(Object.class, centerRenderer); + @SuppressWarnings("unused") + PasteableTable myAd = new PasteableTable(tableScale); + + scrollPane = new JScrollPane(tableScale); + sl_contentPane.putConstraint(SpringLayout.WEST, scrollPane, 5, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.NORTH, scrollPane, 6, SpringLayout.SOUTH, btnRemoveComment); + sl_contentPane.putConstraint(SpringLayout.EAST, scrollPane, -5, SpringLayout.EAST, contentPane); + contentPane.add(scrollPane); + + btnOutput = new JButton("Output Directory"); + btnOutput.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + File temp = FileSelection.getOutputDir(fc); + if(temp != null) { + OUT_DIR = temp; + lblDefaultToLocal.setText(OUT_DIR.getAbsolutePath()); + } + } + }); + sl_contentPane.putConstraint(SpringLayout.SOUTH, scrollPane, -3, SpringLayout.NORTH, btnOutput); + sl_contentPane.putConstraint(SpringLayout.WEST, btnOutput, 146, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.SOUTH, btnOutput, -50, SpringLayout.SOUTH, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnOutput, -146, SpringLayout.EAST, contentPane); + contentPane.add(btnOutput); + + outputLabel = new JLabel("Current Output:"); + sl_contentPane.putConstraint(SpringLayout.WEST, outputLabel, 0, SpringLayout.WEST, scrollPane); + sl_contentPane.putConstraint(SpringLayout.SOUTH, outputLabel, -30, SpringLayout.SOUTH, contentPane); + outputLabel.setFont(new Font("Lucida Grande", Font.BOLD, 13)); + contentPane.add(outputLabel); + + lblDefaultToLocal = new JLabel("Default to Local Directory"); + sl_contentPane.putConstraint(SpringLayout.NORTH, lblDefaultToLocal, 1, SpringLayout.NORTH, outputLabel); + sl_contentPane.putConstraint(SpringLayout.WEST, lblDefaultToLocal, 6, SpringLayout.EAST, outputLabel); + lblDefaultToLocal.setBackground(Color.WHITE); + contentPane.add(lblDefaultToLocal); + + btnComment = new JButton("Write Comments"); + sl_contentPane.putConstraint(SpringLayout.NORTH, btnComment, 6, SpringLayout.SOUTH, lblDefaultToLocal); + sl_contentPane.putConstraint(SpringLayout.WEST, btnComment, 200, SpringLayout.WEST, contentPane); + sl_contentPane.putConstraint(SpringLayout.EAST, btnComment, -200, SpringLayout.EAST, contentPane); + btnComment.addActionListener(e -> { + task = new Task(); + task.addPropertyChangeListener(AddCommentsToBamWindow.this); + task.execute(); + }); + contentPane.add(btnComment); + + progressBar = new JProgressBar(); + progressBar.setStringPainted(true); + contentPane.add(progressBar); + sl_contentPane.putConstraint(SpringLayout.NORTH, progressBar, 6, SpringLayout.SOUTH, lblDefaultToLocal); + sl_contentPane.putConstraint(SpringLayout.EAST, progressBar, 0, SpringLayout.EAST, scrollPane); + } + + @Override + public void actionPerformed(ActionEvent arg0) { + massXable(contentPane, false); + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + task = new Task(); + task.addPropertyChangeListener(this); + task.execute(); + } + /** + * Invoked when the task's progress changes + */ + @Override + public void propertyChange(PropertyChangeEvent evt) { + if ("progress" == evt.getPropertyName()) { + int progress = (Integer) evt.getNewValue(); + progressBar.setValue(progress); + } else if ("log" == evt.getPropertyName()) { + firePropertyChange("log", evt.getOldValue(), evt.getNewValue()); + } + } + public void massXable(Container con, boolean status) { + for(Component c : con.getComponents()) { + c.setEnabled(status); + if(c instanceof Container) { massXable((Container)c, status); } + } + } +} diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamWindow.java index 16374bd74..76f213c10 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/DownsampleSamWindow.java @@ -1,6 +1,8 @@ package scriptmanager.window_interface.BAM_Manipulation; import htsjdk.samtools.*; +import scriptmanager.objects.LogItem; +import scriptmanager.scripts.BAM_Manipulation.AddCommentsToBamWrapper; import scriptmanager.scripts.BAM_Manipulation.DownsampleSamWrapper; import scriptmanager.util.FileSelection; @@ -13,6 +15,8 @@ import java.beans.PropertyChangeListener; import java.io.File; import java.io.IOException; +import java.sql.Timestamp; +import java.util.Date; import java.util.Iterator; import java.util.Vector; @@ -65,6 +69,7 @@ public Task (double probability) { @Override public Void doInBackground() throws IOException{ setProgress(0); + LogItem old_li = null; try { for (int x = 0; x < BAMFiles.size(); x++) { // Build output filepath @@ -95,13 +100,23 @@ public Void doInBackground() throws IOException{ // Close the reader reader.close(); - // Execute picard wrapper - DownsampleSamWrapper.run(BAMFiles.get(x), OUTPUT, probability, seed); - // Update Progress - int percentComplete = (int) (((double) (x + 1) / BAMFiles.size()) * 100); - setProgress(percentComplete); - + // Initialize log item + String command = DownsampleSamWrapper.getCLIcommand(BAMFiles.get(x), OUTPUT, probability, seed); + System.err.println(command); + LogItem new_li = new LogItem(command); + firePropertyChange("log", old_li, new_li); + + // Execute picard wrapper + DownsampleSamWrapper.run(BAMFiles.get(x), OUTPUT, probability, seed); + // Update Progress + int percentComplete = (int) (((double) (x + 1) / BAMFiles.size()) * 100); + setProgress(percentComplete); + // Update LogItem + new_li.setStopTime(new Timestamp(new Date().getTime())); + new_li.setStatus(0); + old_li = new_li; } + firePropertyChange("log", old_li, null); setProgress(100); JOptionPane.showMessageDialog(null, "Downsampling Complete"); return null; @@ -244,9 +259,9 @@ public void actionPerformed(ActionEvent e) { seedField.setEnabled(false); setReadCountBox = new JCheckBox("Set # of reads?"); - sl_contentPane.putConstraint(SpringLayout.EAST, setReadCountBox, 5, SpringLayout.EAST, scrollPane); + setReadCountBox.setSize(new Dimension(120, setReadCountBox.getPreferredSize().height)); sl_contentPane.putConstraint(SpringLayout.NORTH, setReadCountBox, 55,SpringLayout.SOUTH, scrollPane); - sl_contentPane.putConstraint(SpringLayout.EAST, setReadCountBox, 30, SpringLayout.WEST, btnOutput); + sl_contentPane.putConstraint(SpringLayout.WEST, setReadCountBox, 167, SpringLayout.WEST, contentPane); contentPane.add(setReadCountBox); setReadCountBox.addActionListener(new ActionListener() { @@ -265,9 +280,8 @@ public void actionPerformed(ActionEvent e) { readCountField = new JTextField("Enter # of Reads"); readCountField.setPreferredSize(new Dimension(120, readCountField.getPreferredSize().height)); - sl_contentPane.putConstraint(SpringLayout.EAST, readCountField, 5, SpringLayout.EAST, scrollPane); sl_contentPane.putConstraint(SpringLayout.NORTH, readCountField, 58,SpringLayout.SOUTH, scrollPane); - sl_contentPane.putConstraint(SpringLayout.EAST, readCountField, 160, SpringLayout.WEST, btnOutput); + sl_contentPane.putConstraint(SpringLayout.WEST, readCountField, 5, SpringLayout.EAST, setReadCountBox); contentPane.add(readCountField); readCountField.setEnabled(false); @@ -349,12 +363,15 @@ public void actionPerformed(ActionEvent arg0) { /** * Invoked when task's progress property changes. */ - public void propertyChange(PropertyChangeEvent evt) { - if ("progress" == evt.getPropertyName()) { - int progress = (Integer) evt.getNewValue(); - progressBar.setValue(progress); - } - } + @Override + public void propertyChange(PropertyChangeEvent evt) { + if ("progress" == evt.getPropertyName()) { + int progress = (Integer) evt.getNewValue(); + progressBar.setValue(progress); + } else if ("log" == evt.getPropertyName()) { + firePropertyChange("log", evt.getOldValue(), evt.getNewValue()); + } + } public void massXable(Container con, boolean status) { for(Component c : con.getComponents()) { c.setEnabled(status); diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterSamReadsWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterSamReadsWindow.java index 8a173c69f..064f4239b 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterSamReadsWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/FilterSamReadsWindow.java @@ -2,6 +2,8 @@ import htsjdk.samtools.SAMException; +import scriptmanager.objects.LogItem; +import scriptmanager.scripts.BAM_Manipulation.AddCommentsToBamWrapper; import scriptmanager.scripts.BAM_Manipulation.BAIIndexer; import scriptmanager.scripts.BAM_Manipulation.BAMFileSort; import scriptmanager.scripts.BAM_Manipulation.FilterSamReadsWrapper; @@ -18,6 +20,8 @@ import java.beans.PropertyChangeListener; import java.io.File; import java.io.IOException; +import java.sql.Timestamp; +import java.util.Date; import java.util.Vector; /** @@ -53,6 +57,7 @@ class Task extends SwingWorker { @Override public Void doInBackground() throws IOException { setProgress(0); + LogItem old_li = null; try { for (int x = 0; x < BAMFiles.size(); x++) { // Build output filepath @@ -63,13 +68,22 @@ public Void doInBackground() throws IOException { } else { OUTPUT = new File(NAME[0] + "_filtered.bam"); } - + // Initialize log item + String command = FilterSamReadsWrapper.getCLIcommand(BAMFiles.get(x), OUTPUT, filterchbx.isSelected(), readListFile, intervalList); + System.err.println(command); + LogItem new_li = new LogItem(command); + firePropertyChange("log", old_li, new_li); // Execute Picard wrapper FilterSamReadsWrapper.run(BAMFiles.get(x), OUTPUT, filterchbx.isSelected(), readListFile, intervalList); // Update progress int percentComplete = (int)(((double)(x + 1) / BAMFiles.size()) * 100); setProgress(percentComplete); + // Update LogItem + new_li.setStopTime(new Timestamp(new Date().getTime())); + new_li.setStatus(0); + old_li = new_li; } + firePropertyChange("log", old_li, null); setProgress(100); JOptionPane.showMessageDialog(null, "Filtering Complete"); } catch (SAMException se) { @@ -228,12 +242,15 @@ public void actionPerformed(ActionEvent arg0) { /** * Invoked when task's progress property changes. */ - public void propertyChange(PropertyChangeEvent evt) { - if ("progress" == evt.getPropertyName()) { - int progress = (Integer) evt.getNewValue(); - progressBar.setValue(progress); - } - } + @Override + public void propertyChange(PropertyChangeEvent evt) { + if ("progress" == evt.getPropertyName()) { + int progress = (Integer) evt.getNewValue(); + progressBar.setValue(progress); + } else if ("log" == evt.getPropertyName()) { + firePropertyChange("log", evt.getOldValue(), evt.getNewValue()); + } + } public void massXable(Container con, boolean status) { for(Component c : con.getComponents()) { c.setEnabled(status); diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/NormalizeFastaWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/NormalizeFastaWindow.java index 0ce208c5d..25fb6d4d9 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/NormalizeFastaWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/NormalizeFastaWindow.java @@ -1,6 +1,8 @@ package scriptmanager.window_interface.BAM_Manipulation; import htsjdk.samtools.SAMException; +import scriptmanager.objects.LogItem; +import scriptmanager.scripts.BAM_Manipulation.AddCommentsToBamWrapper; import scriptmanager.scripts.BAM_Manipulation.NormalizeFastaWrapper; import scriptmanager.util.FileSelection; @@ -13,6 +15,8 @@ import java.beans.PropertyChangeListener; import java.io.File; import java.io.IOException; +import java.sql.Timestamp; +import java.util.Date; import java.util.Vector; /** @@ -40,8 +44,8 @@ public class NormalizeFastaWindow extends JFrame implements ActionListener, Prop class Task extends SwingWorker { @Override public Void doInBackground() throws IOException { - setProgress(0); + LogItem old_li = null; try { for (int x = 0; x < BAMFiles.size(); x++) { // Build output filepath @@ -52,12 +56,21 @@ public Void doInBackground() throws IOException { } else { OUTPUT = new File(NAME[0] + "_normalized.fasta"); } + // Initialize log item + String command = NormalizeFastaWrapper.getCLIcommand(BAMFiles.get(x), OUTPUT); + System.err.println(command); + LogItem new_li = new LogItem(command); // Run Wrapper NormalizeFastaWrapper.run(BAMFiles.get(x), OUTPUT); // Update progress int percentComplete = (int)(((double)(x + 1) / BAMFiles.size()) * 100); setProgress(percentComplete); + // Update LogItem + new_li.setStopTime(new Timestamp(new Date().getTime())); + new_li.setStatus(0); + old_li = new_li; } + firePropertyChange("log", old_li, null); setProgress(100); JOptionPane.showMessageDialog(null, "Validation Complete"); } catch (SAMException se) { @@ -181,12 +194,15 @@ public void actionPerformed(ActionEvent arg0) { /** * Invoked when task's progress property changes. */ - public void propertyChange(PropertyChangeEvent evt) { - if ("progress" == evt.getPropertyName()) { - int progress = (Integer) evt.getNewValue(); - progressBar.setValue(progress); - } - } + @Override + public void propertyChange(PropertyChangeEvent evt) { + if ("progress" == evt.getPropertyName()) { + int progress = (Integer) evt.getNewValue(); + progressBar.setValue(progress); + } else if ("log" == evt.getPropertyName()) { + firePropertyChange("log", evt.getOldValue(), evt.getNewValue()); + } + } public void massXable(Container con, boolean status) { for(Component c : con.getComponents()) { c.setEnabled(status); diff --git a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java index 84014987b..686de185b 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Manipulation/ValidateSamWindow.java @@ -1,7 +1,9 @@ package scriptmanager.window_interface.BAM_Manipulation; import htsjdk.samtools.SAMException; +import scriptmanager.objects.LogItem; import scriptmanager.scripts.BAM_Manipulation.BAIIndexer; +import scriptmanager.scripts.BAM_Manipulation.FilterSamReadsWrapper; import scriptmanager.scripts.BAM_Manipulation.ValidateSamWrapper; import scriptmanager.util.FileSelection; @@ -14,6 +16,8 @@ import java.beans.PropertyChangeListener; import java.io.File; import java.io.IOException; +import java.sql.Timestamp; +import java.util.Date; import java.util.Vector; /** @@ -64,8 +68,8 @@ public Task (int maxOutput) { @Override public Void doInBackground() throws IOException { - setProgress(0); + LogItem old_li = null; try { for(int x = 0; x < BAMFiles.size(); x++) { // Build output filepath @@ -80,12 +84,22 @@ public Void doInBackground() throws IOException { BAIIndexer.generateIndex(BAMFiles.get(x)); } mode = !chckbxSummaryMode.isSelected(); + // Initialize log item + String command = ValidateSamWrapper.getCLIcommand(BAMFiles.get(x), OUTPUT, mode, GENOME, maxOutput); + System.err.println(command); + LogItem new_li = new LogItem(command); + firePropertyChange("log", old_li, new_li); // Execute Picard wrapper ValidateSamWrapper.run(BAMFiles.get(x), OUTPUT, mode, GENOME, maxOutput); // Update progress int percentComplete = (int)(((double)(x + 1) / BAMFiles.size()) * 100); setProgress(percentComplete); + // Update LogItem + new_li.setStopTime(new Timestamp(new Date().getTime())); + new_li.setStatus(0); + old_li = new_li; } + firePropertyChange("log", old_li, null); setProgress(100); JOptionPane.showMessageDialog(null, "Validation Complete"); } catch (SAMException se) { @@ -292,12 +306,15 @@ public void actionPerformed(ActionEvent arg0) { /** * Invoked when task's progress property changes. */ - public void propertyChange(PropertyChangeEvent evt) { - if ("progress" == evt.getPropertyName()) { - int progress = (Integer) evt.getNewValue(); - progressBar.setValue(progress); - } - } + @Override + public void propertyChange(PropertyChangeEvent evt) { + if ("progress" == evt.getPropertyName()) { + int progress = (Integer) evt.getNewValue(); + progressBar.setValue(progress); + } else if ("log" == evt.getPropertyName()) { + firePropertyChange("log", evt.getOldValue(), evt.getNewValue()); + } + } public void massXable(Container con, boolean status) { for(Component c : con.getComponents()) { c.setEnabled(status); diff --git a/src/main/java/scriptmanager/window_interface/BAM_Statistics/CollectBaseDistributionByCycleWindow.java b/src/main/java/scriptmanager/window_interface/BAM_Statistics/CollectBaseDistributionByCycleWindow.java index 47d01e73e..e7544d01a 100644 --- a/src/main/java/scriptmanager/window_interface/BAM_Statistics/CollectBaseDistributionByCycleWindow.java +++ b/src/main/java/scriptmanager/window_interface/BAM_Statistics/CollectBaseDistributionByCycleWindow.java @@ -1,6 +1,8 @@ package scriptmanager.window_interface.BAM_Statistics; import htsjdk.samtools.SAMException; +import scriptmanager.objects.LogItem; +import scriptmanager.scripts.BAM_Manipulation.ValidateSamWrapper; import scriptmanager.scripts.BAM_Statistics.CollectBaseDistributionByCycleWrapper; import scriptmanager.util.FileSelection; import scriptmanager.window_interface.BAM_Manipulation.ValidateSamWindow; @@ -14,6 +16,8 @@ import java.beans.PropertyChangeListener; import java.io.File; import java.io.IOException; +import java.sql.Timestamp; +import java.util.Date; import java.util.Vector; /** @@ -44,6 +48,7 @@ class Task extends SwingWorker { @Override public Void doInBackground() throws IOException { setProgress(0); + LogItem old_li = null; try { for(int x = 0; x < BAMFiles.size(); x++) { // Build output filepath @@ -57,13 +62,22 @@ public Void doInBackground() throws IOException { OUTPUT = new File(NAME[0] + "_output.txt"); chartOutput = new File(NAME[0] + "_collect_base_dist_by_cycle.pdf"); } - + // Initialize log item + String command = CollectBaseDistributionByCycleWrapper.getCLIcommand(BAMFiles.get(x), OUTPUT, chartOutput); + System.err.println(command); + LogItem new_li = new LogItem(command); + firePropertyChange("log", old_li, new_li); // Execute Picard wrapper CollectBaseDistributionByCycleWrapper.run(BAMFiles.get(x), OUTPUT, chartOutput); // Update progress int percentComplete = (int)(((double)(x + 1) / BAMFiles.size()) * 100); setProgress(percentComplete); + // Update LogItem + new_li.setStopTime(new Timestamp(new Date().getTime())); + new_li.setStatus(0); + old_li = new_li; } + firePropertyChange("log", old_li, null); setProgress(100); JOptionPane.showMessageDialog(null, "Distribution Complete"); } catch (SAMException se) { @@ -186,12 +200,15 @@ public void actionPerformed(ActionEvent arg0) { /** * Invoked when task's progress property changes. */ - public void propertyChange(PropertyChangeEvent evt) { - if ("progress" == evt.getPropertyName()) { - int progress = (Integer) evt.getNewValue(); - progressBar.setValue(progress); - } - } + @Override + public void propertyChange(PropertyChangeEvent evt) { + if ("progress" == evt.getPropertyName()) { + int progress = (Integer) evt.getNewValue(); + progressBar.setValue(progress); + } else if ("log" == evt.getPropertyName()) { + firePropertyChange("log", evt.getOldValue(), evt.getNewValue()); + } + } public void massXable(Container con, boolean status) { for(Component c : con.getComponents()) { c.setEnabled(status); From ca44e689160b9544082e43dddf113a25551eba7e Mon Sep 17 00:00:00 2001 From: benjaminbeer256 Date: Tue, 3 Dec 2024 14:49:27 -0500 Subject: [PATCH 11/11] fixed formatting --- src/main/java/scriptmanager/objects/ToolDescriptions.java | 2 +- .../BAM_Statistics/CollectBaseDistributionByCycleWrapper.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/scriptmanager/objects/ToolDescriptions.java b/src/main/java/scriptmanager/objects/ToolDescriptions.java index 13f8fa3dd..b30c1a47b 100644 --- a/src/main/java/scriptmanager/objects/ToolDescriptions.java +++ b/src/main/java/scriptmanager/objects/ToolDescriptions.java @@ -47,6 +47,7 @@ public class ToolDescriptions { public static final String normalize_fasta_description = "Reduce redundant sequences and normalize read coverage in a FASTA file, improving downstream analysis accuracy"; public static final String filter_sam_reads_description = "Filter BAM files by applying user-defined filters to include or exclude specific reads based on read lists or genomic intervals"; public static final String add_comments_to_bam_description = "Adds comments to the header of a BAM file."; + // BAM Format Converter public static final String bam_to_scidx_description = "Convert BAM file to scIDX file."; public static final String bam_to_gff_description = "Convert BAM file to GFF file."; @@ -92,7 +93,6 @@ public class ToolDescriptions { public static final String aggregate_data_description = "Compile data from tab-delimited file into matrix according to user-specified metric."; public static final String transpose_matrix_description = "Interchange the rows and columns of tab-delimited matrix data."; - // Sequence Analysis public static final String fasta_extract_description = "Generate FASTA file from indexed Genome FASTA file and BED file. Script will generate FAI index if not present in Genome FASTA folder."; public static final String randomize_fasta_description = "Randomize FASTA sequence for each input entry."; diff --git a/src/main/java/scriptmanager/scripts/BAM_Statistics/CollectBaseDistributionByCycleWrapper.java b/src/main/java/scriptmanager/scripts/BAM_Statistics/CollectBaseDistributionByCycleWrapper.java index 004a0ca62..16fb8df73 100644 --- a/src/main/java/scriptmanager/scripts/BAM_Statistics/CollectBaseDistributionByCycleWrapper.java +++ b/src/main/java/scriptmanager/scripts/BAM_Statistics/CollectBaseDistributionByCycleWrapper.java @@ -44,7 +44,7 @@ public static void run(File input, File output, File chartOutput) throws IOExcep */ public static String getCLIcommand(File input, File output, File chartOutput) { String command = "java -jar $PICARD "; - final CommandLineParser parser = new picard.reference.NormalizeFasta().getCommandLineParser(); + final CommandLineParser parser = new picard.analysis.CollectBaseDistributionByCycle().getCommandLineParser(); final ArrayList args = new ArrayList<>(); args.add("INPUT=" + input.getAbsolutePath()); args.add("OUTPUT=" + output.getAbsolutePath());