diff --git a/uk/ac/sanger/artemis/components/alignment/BamUtils.java b/uk/ac/sanger/artemis/components/alignment/BamUtils.java index a870c46e29a0a57e48fedecf04e23e0f56fe66cb..ee271b58f4444c5e16def47dbb5011a0d659bdbb 100644 --- a/uk/ac/sanger/artemis/components/alignment/BamUtils.java +++ b/uk/ac/sanger/artemis/components/alignment/BamUtils.java @@ -23,130 +23,20 @@ */ package uk.ac.sanger.artemis.components.alignment; -import java.awt.Container; -import java.awt.Frame; -import java.text.DecimalFormat; -import java.util.Arrays; import java.util.Hashtable; -import java.util.List; import java.util.Vector; -import javax.swing.JFrame; - import net.sf.samtools.SAMFileReader; import net.sf.samtools.SAMRecord; import net.sf.samtools.util.CloseableIterator; import uk.ac.sanger.artemis.Feature; import uk.ac.sanger.artemis.FeatureSegmentVector; -import uk.ac.sanger.artemis.FeatureVector; -import uk.ac.sanger.artemis.components.EntryEdit; -import uk.ac.sanger.artemis.components.FileViewer; -import uk.ac.sanger.artemis.components.MultiComparator; import uk.ac.sanger.artemis.io.Range; class BamUtils { - /** - * Read count for selected reads. - * @param features - * @param refName - * @param samFileReaderHash - * @param bamList - * @param seqNames - * @param offsetLengths - * @param concatSequences - * @param seqLengths - * @param samRecordFlagPredicate - * @param samRecordMapQPredicate - * @param contained - * @param useIntrons - * @param mappedReads - */ - protected static void countReads(final FeatureVector features, - final String refName, - final Hashtable<String, SAMFileReader> samFileReaderHash, - final List<String> bamList, - final Vector<String> seqNames, - final Hashtable<String, Integer> offsetLengths, - final boolean concatSequences, - final Hashtable<String, Integer> seqLengths, - final SAMRecordPredicate samRecordFlagPredicate, - final SAMRecordMapQPredicate samRecordMapQPredicate, - final boolean contained, - final boolean useIntrons, - final int mappedReads[]) - { - Hashtable<String, List<Float>> featureReadCount = new Hashtable<String, List<Float>>(); - - for(int i=0; i<features.size(); i++) - { - Feature f = features.elementAt(i); - - int start = f.getRawFirstBase(); - int end = f.getRawLastBase(); - float fLen = getFeatureLength(f); - List<Float> sampleCounts = new Vector<Float>(); - - for(int j=0; j<bamList.size(); j++) - { - String bam = bamList.get(j); - float cnt = 0; - if(!useIntrons && f.getSegments().size() > 1) - { - for(int k=0; k<f.getSegments().size(); k++) - { - start = f.getSegments().elementAt(k).getRawRange().getStart(); - end = f.getSegments().elementAt(k).getRawRange().getEnd(); - cnt += getCount(start, end, bam, refName, samFileReaderHash, - seqNames, offsetLengths, concatSequences, seqLengths, - samRecordFlagPredicate, samRecordMapQPredicate, contained); - } - } - else - cnt = getCount(start, end, bam, refName, samFileReaderHash, - seqNames, offsetLengths, concatSequences, seqLengths, - samRecordFlagPredicate, samRecordMapQPredicate, contained); - if(mappedReads != null) - cnt = (cnt / ( ((float)mappedReads[j]/1000000.f) * (fLen/1000.f) )) ; - - sampleCounts.add(cnt); - } - featureReadCount.put(f.getSystematicName(), sampleCounts); - } - - DecimalFormat df = new DecimalFormat("0.00##"); - StringBuffer buff = new StringBuffer(); - for(int j=0; j<bamList.size(); j++) - { - String bam = bamList.get(j); - buff.append("#BAM: "+bam); - if(mappedReads != null) - buff.append(" Mapped Reads/million: "+ df.format( ((float)mappedReads[j]) / 1000000.f) ); - buff.append("\n"); - } - buff.append("\n"); - - Object[] readKey = featureReadCount.keySet().toArray(); - Arrays.sort(readKey); - - for (Object fId : readKey ) { - buff.append(fId+"\t"); - List<Float> cnts = featureReadCount.get(fId); - for(int i=0; i<cnts.size(); i++) - buff.append(df.format(cnts.get(i)) + (i<cnts.size()-1 ? "\t" : "")); - buff.append("\n"); - } - - FileViewer viewer; - if(mappedReads != null) - viewer = new FileViewer ("RPKM", true, false, true); - else - viewer = new FileViewer ("Read Count", true, false, true); - viewer.getTextPane().setText(buff.toString()); - } - - private static float getFeatureLength(Feature f) + protected static float getFeatureLength(Feature f) { FeatureSegmentVector segs = f.getSegments(); int len = 0; @@ -174,7 +64,7 @@ class BamUtils * @param contained * @return */ - private static int getCount( + protected static int getCount( final int start, final int end, final String bam, @@ -226,82 +116,7 @@ class BamUtils return cnt; } - /** - * Calculate the total number of mapped reads. - * @param refName - * @param samFileReaderHash - * @param bamList - * @param seqNames - * @param offsetLengths - * @param concatSequences - * @param seqLengths - * @param sequenceLength - * @return - */ - protected static int[] getTotalMappedReads( - final String refName, - final Hashtable<String, SAMFileReader> samFileReaderHash, - final List<String> bamList, - final Vector<String> seqNames, - final Hashtable<String, Integer> offsetLengths, - final boolean concatSequences, - final Hashtable<String, Integer> seqLengths, - final int sequenceLength, - final SAMRecordPredicate samRecordFlagPredicate, - SAMRecordMapQPredicate samRecordMapQPredicate) - { - int MAX_BASE_CHUNK = 2000*60; - int mapped[] = new int[bamList.size()]; - boolean contained = false; - - for (int i = 0; i < sequenceLength; i += MAX_BASE_CHUNK) - { - int sbegc = i; - int sendc = i + MAX_BASE_CHUNK - 1; - - for (int j=0; j<bamList.size(); j++) - { - String bam = bamList.get(j); - if (concatSequences) - { - int len = 0; - int lastLen = 1; - for (String name : seqNames) - { - int thisLength = seqLengths.get(name); - len += thisLength; - - if ((lastLen >= sbegc && lastLen < sendc) - || (len >= sbegc && len < sendc) - || (sbegc >= lastLen && sbegc < len) - || (sendc >= lastLen && sendc < len)) - { - int offset = offsetLengths.get(name); - int thisStart = sbegc - offset; - if (thisStart < 1) - thisStart = 1; - int thisEnd = sendc - offset; - if (thisEnd > thisLength) - thisEnd = thisLength; - - mapped[j] += count(bam, samFileReaderHash, name, thisStart, thisEnd, - samRecordFlagPredicate, samRecordMapQPredicate, contained); - - } - lastLen = len; - } - } - else - { - mapped[j] += count(bam, samFileReaderHash, refName, sbegc, sendc, - samRecordFlagPredicate, samRecordMapQPredicate, contained); - } - } - } - return mapped; - } - - private static int count(String bam, + protected static int count(String bam, Hashtable<String, SAMFileReader> samFileReaderHash, String refName, int start, @@ -330,18 +145,6 @@ class BamUtils it.close(); return cnt; } - - protected static Container getBamContainer(BamView bamView) - { - Frame fs[] = JFrame.getFrames(); - for(Frame f: fs) - { - if( f instanceof JFrame && - ((JFrame)f) instanceof EntryEdit || - ((JFrame)f) instanceof MultiComparator) - return ((JFrame)f).getContentPane(); - } - return bamView; - } + } diff --git a/uk/ac/sanger/artemis/components/alignment/BamView.java b/uk/ac/sanger/artemis/components/alignment/BamView.java index 608c75128fba7d8d6f25e3f0ccb707037d735eb7..ace4e38e56d0098403eb1a76f20ef330186ddf14 100644 --- a/uk/ac/sanger/artemis/components/alignment/BamView.java +++ b/uk/ac/sanger/artemis/components/alignment/BamView.java @@ -29,8 +29,6 @@ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Composite; -import java.awt.Container; -import java.awt.Cursor; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.FontMetrics; @@ -2016,10 +2014,8 @@ public class BamView extends JPanel { public void actionPerformed(ActionEvent e) { - Container c = BamUtils.getBamContainer(BamView.this); - c.setCursor(new Cursor(Cursor.WAIT_CURSOR)); FeatureVector features = feature_display.getSelection().getAllFeatures(); - + JCheckBox overlap = new JCheckBox("Include all overlapping reads", true); overlap.setToolTipText("Include reads that partially overlap the feature"); JCheckBox spliced = new JCheckBox("Introns included", true); @@ -2028,11 +2024,10 @@ public class BamView extends JPanel yBox.add(spliced); JOptionPane.showMessageDialog(null, yBox, "Read Count Option", JOptionPane.INFORMATION_MESSAGE); - BamUtils.countReads(features, (String)combo.getSelectedItem(), samFileReaderHash, bamList, + new MappedReads(features, (String)combo.getSelectedItem(), samFileReaderHash, bamList, seqNames, offsetLengths, concatSequences, seqLengths, samRecordFlagPredicate, samRecordMapQPredicate, - !overlap.isSelected(), spliced.isSelected(), null); - c.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + !overlap.isSelected(), spliced.isSelected()); } }); @@ -2044,10 +2039,8 @@ public class BamView extends JPanel { public void actionPerformed(ActionEvent e) { - Container c = BamUtils.getBamContainer(BamView.this); - c.setCursor(new Cursor(Cursor.WAIT_CURSOR)); FeatureVector features = feature_display.getSelection().getAllFeatures(); - + JCheckBox overlap = new JCheckBox("Include all overlapping reads", true); overlap.setToolTipText("Include reads that partially overlap the feature"); JCheckBox spliced = new JCheckBox("Introns included", true); @@ -2061,18 +2054,11 @@ public class BamView extends JPanel seqlen = feature_display.getSequenceLength(); else if(bases != null) seqlen = bases.getLength(); - - int mappedReads[] = - BamUtils.getTotalMappedReads((String)combo.getSelectedItem(), - samFileReaderHash, bamList, seqNames, offsetLengths, concatSequences, - offsetLengths, seqlen, samRecordFlagPredicate, samRecordMapQPredicate); - - logger4j.debug("TOTAL MAPPED READS "+mappedReads); - BamUtils.countReads(features, (String)combo.getSelectedItem(), samFileReaderHash, bamList, - seqNames, offsetLengths, concatSequences, seqLengths, - samRecordFlagPredicate, samRecordMapQPredicate, - !overlap.isSelected(), spliced.isSelected(), mappedReads); - c.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + + new MappedReads(features, (String)combo.getSelectedItem(), + samFileReaderHash, bamList, seqNames, offsetLengths, concatSequences, + offsetLengths, seqlen, samRecordFlagPredicate, samRecordMapQPredicate, + !overlap.isSelected(), spliced.isSelected()); } }); diff --git a/uk/ac/sanger/artemis/components/alignment/MappedReads.java b/uk/ac/sanger/artemis/components/alignment/MappedReads.java new file mode 100644 index 0000000000000000000000000000000000000000..ca71b7e99a375667375f9ebfb4951cef8f00231e --- /dev/null +++ b/uk/ac/sanger/artemis/components/alignment/MappedReads.java @@ -0,0 +1,327 @@ +package uk.ac.sanger.artemis.components.alignment; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Toolkit; +import java.text.DecimalFormat; +import java.util.Arrays; +import java.util.Hashtable; +import java.util.List; +import java.util.Vector; + +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JProgressBar; + +import uk.ac.sanger.artemis.Feature; +import uk.ac.sanger.artemis.FeatureVector; +import uk.ac.sanger.artemis.components.FileViewer; +import uk.ac.sanger.artemis.components.SwingWorker; + +import net.sf.samtools.SAMFileReader; + +public class MappedReads +{ + private JProgressBar progressBar; + private JLabel progressTxt = new JLabel(); + + private FeatureVector features; + private String refName; + private Hashtable<String, SAMFileReader> samFileReaderHash; + private List<String> bamList; + private Vector<String> seqNames; + private Hashtable<String, Integer> offsetLengths; + private boolean concatSequences; + private Hashtable<String, Integer> seqLengths; + private int sequenceLength; + private SAMRecordPredicate samRecordFlagPredicate; + private SAMRecordMapQPredicate samRecordMapQPredicate; + private boolean contained; + private boolean useIntrons; + private JDialog dialog = new JDialog((JFrame)null, "Calculating", true);; + + private int mappedReads[]; + + /** + * Calculate the total number of mapped reads. + * @param refName + * @param samFileReaderHash + * @param bamList + * @param seqNames + * @param offsetLengths + * @param concatSequences + * @param seqLengths + * @param sequenceLength + */ + public MappedReads( + final FeatureVector features, + final String refName, + final Hashtable<String, SAMFileReader> samFileReaderHash, + final List<String> bamList, + final Vector<String> seqNames, + final Hashtable<String, Integer> offsetLengths, + final boolean concatSequences, + final Hashtable<String, Integer> seqLengths, + final int sequenceLength, + final SAMRecordPredicate samRecordFlagPredicate, + SAMRecordMapQPredicate samRecordMapQPredicate, + final boolean contained, + final boolean useIntrons) + { + this.features = features; + this.refName = refName; + this.samFileReaderHash = samFileReaderHash; + this.bamList = bamList; + this.seqNames = seqNames; + this.offsetLengths = offsetLengths; + this.concatSequences = concatSequences; + this.seqLengths = seqLengths; + this.sequenceLength = sequenceLength; + this.samRecordFlagPredicate = samRecordFlagPredicate; + this.samRecordMapQPredicate = samRecordMapQPredicate; + this.contained = contained; + this.useIntrons = useIntrons; + + progressBar = new JProgressBar(0, sequenceLength); + progressBar.setValue(0); + progressBar.setStringPainted(true); + + JPanel panel = new JPanel(new BorderLayout()); + progressTxt.setText("Total number of mapped reads"); + panel.add(progressTxt, BorderLayout.NORTH); + panel.add(progressBar, BorderLayout.CENTER); + + dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + panel.setOpaque(true); + dialog.setContentPane(panel); + dialog.pack(); + centerDialog(); + + CalculateTotalMappedReads cmr = new CalculateTotalMappedReads(); + cmr.start(); + dialog.setVisible(true); + } + + /** + * Read count for selected features. + * @param features + * @param refName + * @param samFileReaderHash + * @param bamList + * @param seqNames + * @param offsetLengths + * @param concatSequences + * @param seqLengths + * @param samRecordFlagPredicate + * @param samRecordMapQPredicate + * @param contained + * @param useIntrons + */ + public MappedReads( + final FeatureVector features, + final String refName, + final Hashtable<String, SAMFileReader> samFileReaderHash, + final List<String> bamList, + final Vector<String> seqNames, + final Hashtable<String, Integer> offsetLengths, + final boolean concatSequences, + final Hashtable<String, Integer> seqLengths, + final SAMRecordPredicate samRecordFlagPredicate, + final SAMRecordMapQPredicate samRecordMapQPredicate, + final boolean contained, + final boolean useIntrons) + { + this.features = features; + this.refName = refName; + this.samFileReaderHash = samFileReaderHash; + this.bamList = bamList; + this.seqNames = seqNames; + this.offsetLengths = offsetLengths; + this.concatSequences = concatSequences; + this.seqLengths = seqLengths; + this.samRecordFlagPredicate = samRecordFlagPredicate; + this.samRecordMapQPredicate = samRecordMapQPredicate; + this.contained = contained; + this.useIntrons = useIntrons; + + progressBar = new JProgressBar(0, features.size()); + progressBar.setValue(0); + progressBar.setStringPainted(true); + + JPanel panel = new JPanel(new BorderLayout()); + progressTxt.setText("Number of mapped reads for "+features.size()+" features"); + panel.add(progressTxt, BorderLayout.NORTH); + panel.add(progressBar, BorderLayout.CENTER); + + panel.setOpaque(true); + dialog.setContentPane(panel); + dialog.pack(); + centerDialog(); + + CalculateMappedReads cmr = new CalculateMappedReads(); + cmr.start(); + dialog.setVisible(true); + } + + private void centerDialog() + { + final Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); + final int x_position =(screen.width - dialog.getSize().width) / 2; + int y_position =(screen.height - dialog.getSize().height) / 2; + + if(y_position < 10) + y_position = 10; + dialog.setLocation(new Point(x_position, y_position)); + } + + class CalculateMappedReads extends SwingWorker + { + Hashtable<String, List<Float>> featureReadCount; + public Object construct() + { + featureReadCount = new Hashtable<String, List<Float>>(); + for (int i = 0; i < features.size(); i++) + { + Feature f = features.elementAt(i); + progressBar.setValue(i); + + int start = f.getRawFirstBase(); + int end = f.getRawLastBase(); + float fLen = BamUtils.getFeatureLength(f); + List<Float> sampleCounts = new Vector<Float>(); + + for (int j = 0; j < bamList.size(); j++) + { + String bam = bamList.get(j); + float cnt = 0; + if (!useIntrons && f.getSegments().size() > 1) + { + for (int k = 0; k < f.getSegments().size(); k++) + { + start = f.getSegments().elementAt(k).getRawRange().getStart(); + end = f.getSegments().elementAt(k).getRawRange().getEnd(); + cnt += BamUtils.getCount(start, end, bam, refName, samFileReaderHash, + seqNames, offsetLengths, concatSequences, seqLengths, + samRecordFlagPredicate, samRecordMapQPredicate, contained); + } + } + else + cnt = BamUtils.getCount(start, end, bam, refName, samFileReaderHash, seqNames, + offsetLengths, concatSequences, seqLengths, + samRecordFlagPredicate, samRecordMapQPredicate, contained); + + if (mappedReads != null) + cnt = (cnt / (((float) mappedReads[j] / 1000000.f) * (fLen / 1000.f))); + + sampleCounts.add(cnt); + } + featureReadCount.put(f.getSystematicName(), sampleCounts); + } + return null; + } + + public void finished() + { + DecimalFormat df = new DecimalFormat("0.00##"); + StringBuffer buff = new StringBuffer(); + for (int j = 0; j < bamList.size(); j++) + { + String bam = bamList.get(j); + buff.append("#BAM: " + bam); + if (mappedReads != null) + buff.append(" Mapped Reads/million: " + + df.format(((float) mappedReads[j]) / 1000000.f)); + buff.append("\n"); + } + buff.append("\n"); + + Object[] readKey = featureReadCount.keySet().toArray(); + Arrays.sort(readKey); + + for (Object fId : readKey) + { + buff.append(fId + "\t"); + List<Float> cnts = featureReadCount.get(fId); + for (int i = 0; i < cnts.size(); i++) + buff.append(df.format(cnts.get(i)) + (i < cnts.size() - 1 ? "\t" : "")); + buff.append("\n"); + } + + FileViewer viewer; + if (mappedReads != null) + viewer = new FileViewer("RPKM", true, false, true); + else + viewer = new FileViewer("Read Count", true, false, true); + viewer.getTextPane().setText(buff.toString()); + + dialog.dispose(); + } + } + + class CalculateTotalMappedReads extends SwingWorker + { + public Object construct() + { + int MAX_BASE_CHUNK = 2000 * 60; + mappedReads = new int[bamList.size()]; + boolean contained = false; + for (int i = 0; i < sequenceLength; i += MAX_BASE_CHUNK) + { + progressBar.setValue(i); + int sbegc = i; + int sendc = i + MAX_BASE_CHUNK - 1; + + for (int j = 0; j < bamList.size(); j++) + { + String bam = bamList.get(j); + if (concatSequences) + { + int len = 0; + int lastLen = 1; + for (String name : seqNames) + { + int thisLength = seqLengths.get(name); + len += thisLength; + + if ((lastLen >= sbegc && lastLen < sendc) + || (len >= sbegc && len < sendc) + || (sbegc >= lastLen && sbegc < len) + || (sendc >= lastLen && sendc < len)) + { + int offset = offsetLengths.get(name); + int thisStart = sbegc - offset; + if (thisStart < 1) + thisStart = 1; + int thisEnd = sendc - offset; + if (thisEnd > thisLength) + thisEnd = thisLength; + + mappedReads[j] += BamUtils.count(bam, samFileReaderHash, name, + thisStart, thisEnd, samRecordFlagPredicate, + samRecordMapQPredicate, contained); + + } + lastLen = len; + } + } + else + { + mappedReads[j] += BamUtils.count(bam, samFileReaderHash, refName, sbegc, + sendc, samRecordFlagPredicate, samRecordMapQPredicate, + contained); + } + } + } + + progressBar.setValue(0); + progressBar.setMaximum(features.size()); + progressTxt.setText("RPKM values for "+features.size()+" features"); + CalculateMappedReads cmr = new CalculateMappedReads(); + cmr.start(); + return null; + } + } +}