Newer
Older
*
* created: 2009
*
* This file is part of Artemis
*
* Copyright(C) 2009 Genome Research Limited
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or(at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Composite;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JRadioButton;
import javax.swing.JSeparator;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
tjc
committed
import org.apache.log4j.Level;
import net.sf.picard.reference.ReferenceSequenceFile;
import net.sf.picard.sam.BuildBamIndex;
import net.sf.samtools.AlignmentBlock;
import net.sf.samtools.SAMException;
import net.sf.samtools.SAMFileHeader;
import net.sf.samtools.SAMFileReader;
import net.sf.samtools.SAMRecord;
import net.sf.samtools.SAMSequenceRecord;
import net.sf.samtools.SAMFileReader.ValidationStringency;
import net.sf.samtools.util.CloseableIterator;
import uk.ac.sanger.artemis.Entry;
import uk.ac.sanger.artemis.EntryGroup;
import uk.ac.sanger.artemis.FeatureVector;
import uk.ac.sanger.artemis.Selection;
import uk.ac.sanger.artemis.SelectionChangeEvent;
import uk.ac.sanger.artemis.SelectionChangeListener;
import uk.ac.sanger.artemis.circular.TextFieldInt;
import uk.ac.sanger.artemis.components.DisplayAdjustmentEvent;
import uk.ac.sanger.artemis.components.DisplayAdjustmentListener;
import uk.ac.sanger.artemis.components.EntryEdit;
import uk.ac.sanger.artemis.components.FeatureDisplay;
tjc
committed
import uk.ac.sanger.artemis.components.FileViewer;
import uk.ac.sanger.artemis.components.IndexReferenceEvent;
import uk.ac.sanger.artemis.components.NonModalDialog;
import uk.ac.sanger.artemis.components.SequenceComboBox;
import uk.ac.sanger.artemis.components.SwingWorker;
import uk.ac.sanger.artemis.editor.MultiLineToolTipUI;
import uk.ac.sanger.artemis.sequence.MarkerRange;
import uk.ac.sanger.artemis.sequence.NoSequenceException;
import uk.ac.sanger.artemis.util.Document;
import uk.ac.sanger.artemis.util.DocumentFactory;
import uk.ac.sanger.artemis.util.FTPSeekableStream;
public class BamView extends JPanel
implements DisplayAdjustmentListener, SelectionChangeListener
private List<BamViewRecord> readsInView;
private Hashtable<String, SAMFileReader> samFileReaderHash = new Hashtable<String, SAMFileReader>();
private HashMap<String, Integer> seqLengths = new HashMap<String, Integer>();
private HashMap<String, Integer> offsetLengths;
tjc
committed
protected List<String> bamList;
private boolean isSingle = false;
private boolean isSNPs = false;
private FeatureDisplay feature_display;
private Selection selection;
private Ruler ruler;
private int startBase = -1;
private int endBase = -1;
private boolean showBaseAlignment = false;
private JMenu bamFilesMenu = new JMenu("BAM files");
private JCheckBoxMenuItem logMenuItem = new JCheckBoxMenuItem("Use Log Scale", logScale);
private JCheckBoxMenuItem cbStackView = new JCheckBoxMenuItem("Stack", true);
private JCheckBoxMenuItem cbPairedStackView = new JCheckBoxMenuItem("Paired Stack");
private JCheckBoxMenuItem cbStrandStackView = new JCheckBoxMenuItem("Strand Stack");
private JCheckBoxMenuItem cbIsizeStackView = new JCheckBoxMenuItem("Inferred Size", false);
private JCheckBoxMenuItem cbCoverageView = new JCheckBoxMenuItem("Coverage", false);
private JCheckBoxMenuItem cbCoverageStrandView = new JCheckBoxMenuItem("Coverage by Strand", false);
private JCheckBoxMenuItem cbCoverageHeatMap = new JCheckBoxMenuItem("Coverage Heat Map", false);
private JCheckBoxMenuItem cbLastSelected;
private ButtonGroup buttonGroup = new ButtonGroup();
private JCheckBoxMenuItem colourByCoverageColour = new JCheckBoxMenuItem("Coverage Plot Colours");
private JCheckBoxMenuItem baseQualityColour = new JCheckBoxMenuItem("Base Quality");
private JCheckBoxMenuItem markInsertions = new JCheckBoxMenuItem("Mark Insertions", true);
tjc
committed
private AlphaComposite translucent =
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.6f);
private CoveragePanel coverageView = new CoveragePanel();
protected static String BAM_SUFFIX = ".*\\.(bam|cram)$";
private static Color LIGHT_GREY = new Color(200, 200, 200);
private static Color DARK_GREEN = new Color(0, 150, 0);
private static Color DARK_ORANGE = new Color(255,140,0);
private static Color DEEP_PINK = new Color(139,10,80);
private BamViewRecord mouseOverSAMRecord = null;
private BamViewRecord highlightSAMRecord = null;
private String mouseOverInsertion;
// record of where a mouse drag starts
private static int MAX_BASES = 26000;
private int maxHeight = 800;
tjc
committed
private int BASE_HEIGHT;
private PopupMessageFrame popFrame = new PopupMessageFrame();
private PopupMessageFrame waitingFrame = new PopupMessageFrame("waiting...");
private ExecutorService bamReadTaskExecutor;
private int MAX_COVERAGE = Integer.MAX_VALUE;
public static org.apache.log4j.Logger logger4j =
org.apache.log4j.Logger.getLogger(BamView.class);
public BamView(List<String> bamList,
String reference,
int nbasesInView,
final EntryEdit entry_edit,
final FeatureDisplay feature_display,
final Bases bases,
final JPanel containerPanel,
final JFrame frame)
{
this(bamList, reference, nbasesInView, feature_display, bases, containerPanel, frame);
this.entry_edit = entry_edit;
}
public BamView(List<String> bamList,
int nbasesInView,
final FeatureDisplay feature_display,
final Bases bases,
this.bamList = bamList;
this.feature_display = feature_display;
this.bases = bases;
containerPanel.setLayout(new BoxLayout(containerPanel, BoxLayout.Y_AXIS));
containerPanel.add(mainPanel);
// filter out unmapped reads by default
setSamRecordFlagPredicate(
new SAMRecordFlagPredicate(SAMRecordFlagPredicate.READ_UNMAPPED_FLAG));
System.setProperty("reference", reference); // for CRAM
try
{
getEntry(reference,entryGroup);
}
catch (NoSequenceException e)
{
e.printStackTrace();
}
}
if(Options.getOptions().getIntegerProperty("bam_read_thread") != null)
{
logger4j.debug("BAM READ THREADS="+Options.getOptions().getIntegerProperty("bam_read_thread"));
bamReadTaskExecutor = Executors.newFixedThreadPool(
Options.getOptions().getIntegerProperty("bam_read_thread"));
}
else
bamReadTaskExecutor = Executors.newFixedThreadPool(1);
if(Options.getOptions().getIntegerProperty("bam_max_coverage") != null)
{
logger4j.debug("BAM MAX COVERAGE="+Options.getOptions().getIntegerProperty("bam_max_coverage"));
MAX_COVERAGE = Options.getOptions().getIntegerProperty("bam_max_coverage");
}
try
{
readHeaderPicard();
}
catch(java.lang.UnsupportedClassVersionError err)
{
JOptionPane.showMessageDialog(null,
"This requires Java 1.6 or higher.",
"Check Java Version", JOptionPane.WARNING_MESSAGE);
}
catch (IOException e)
{
e.printStackTrace();
}
final javax.swing.plaf.FontUIResource font_ui_resource =
Options.getOptions().getFontUIResource();
while(keys.hasMoreElements())
{
Object key = keys.nextElement();
Object value = UIManager.get(key);
if(value instanceof javax.swing.plaf.FontUIResource)
UIManager.put(key, font_ui_resource);
}
setFont(Options.getOptions().getFont());
ALIGNMENT_PIX_PER_BASE = fm.charWidth('M');
BASE_HEIGHT = fm.getMaxAscent();
MultiLineToolTipUI.initialize();
setToolTipText("");
buttonGroup.add(cbStackView);
buttonGroup.add(cbPairedStackView);
buttonGroup.add(cbStrandStackView);
buttonGroup.add(cbIsizeStackView);
buttonGroup.add(cbCoverageView);
buttonGroup.add(cbCoverageStrandView);
jspView = new JScrollPane(this,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
jspView.setViewportBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.DARK_GRAY));
Border empty = new EmptyBorder(0,0,0,0);
jspView.setBorder(empty);
jspView.getVerticalScrollBar().setUnitIncrement(8);
}
public String getToolTipText()
{
tjc
committed
if(mouseOverSAMRecord == null)
return null;
String msg =
mouseOverSAMRecord.sam.getReadName() + "\n" +
mouseOverSAMRecord.sam.getAlignmentStart() + ".." +
mouseOverSAMRecord.sam.getAlignmentEnd() + "\nisize=" +
mouseOverSAMRecord.sam.getInferredInsertSize() + "\nmapq=" +
mouseOverSAMRecord.sam.getMappingQuality()+"\nrname="+
mouseOverSAMRecord.sam.getReferenceName();
tjc
committed
if( mouseOverSAMRecord.sam.getReadPairedFlag() &&
mouseOverSAMRecord.sam.getProperPairFlag() &&
!mouseOverSAMRecord.sam.getMateUnmappedFlag())
tjc
committed
{
msg = msg +
(mouseOverSAMRecord.sam.getReadNegativeStrandFlag() ? "-" : "+")+" / "+
(mouseOverSAMRecord.sam.getMateNegativeStrandFlag() ? "-" : "+");
tjc
committed
}
else
msg = msg +
(mouseOverSAMRecord.sam.getReadNegativeStrandFlag() ? "-" : "+");
if(msg != null && mouseOverInsertion != null)
msg = msg + "\nInsertion at:" +mouseOverInsertion;
return msg;
/**
* Get the BAM index file from the list
* @param bam
* @return
* @throws IOException
*/
private File getBamIndexFile(String bam) throws IOException
{
File bamIndexFile = null;
if (bam.startsWith("http") || bam.startsWith("ftp"))
{
final URL urlBamIndexFile = new URL(bam + ".bai");
InputStream is = urlBamIndexFile.openStream();
// Create temp file.
bamIndexFile = File.createTempFile(urlBamIndexFile.getFile().replaceAll(
"[\\/\\s]", "_"), ".bai");
bamIndexFile.deleteOnExit();
FileOutputStream out = new FileOutputStream(bamIndexFile);
int c;
while ((c = is.read()) != -1)
out.write(c);
out.flush();
out.close();
is.close();
logger4j.debug("create... " + bamIndexFile.getAbsolutePath());
{
final File cramIndexFile = new File(bam + ".crai");
if(cramIndexFile.exists())
return cramIndexFile;
}
/**
* Get the SAM file reader.
* @param bam
* @return
* @throws IOException
*/
private SAMFileReader getSAMFileReader(final String bam) throws IOException
{
// parsing of the header happens during SAMFileReader construction,
// so need to set the default stringency
SAMFileReader.setDefaultValidationStringency(ValidationStringency.LENIENT);
if(samFileReaderHash.containsKey(bam))
return samFileReaderHash.get(bam);
if(!bamIndexFile.exists())
{
try
{
logger4j.warn("Index file not found so using picard to index the BAM.");
// Use Picard to index the file
// requires reads to be sorted by coordinate
new BuildBamIndex().instanceMain(
new String[]{ "I="+bam, "O="+bamIndexFile.getAbsolutePath(), "MAX_RECORDS_IN_RAM=50000", "VALIDATION_STRINGENCY=SILENT" });
}
catch(SAMException e)
{
String ls = System.getProperty("line.separator");
String msg =
"BAM index file is missing. The BAM file needs to be sorted and indexed"+ls+
"This can be done using samtools (http://samtools.sf.net/):"+ls+ls+
"samtools sort <in.bam> <out.prefix>"+ls+
"samtools index <sorted.bam>";
throw new SAMException(msg);
}
if(feature_display != null && bam.endsWith("cram"))
{
final CRAMReferenceSequenceFile ref = new CRAMReferenceSequenceFile(
feature_display.getEntryGroup().getSequenceEntry(), this);
final Map<Object, ReferenceSequenceFile> referenceFactory =
new HashMap<Object, ReferenceSequenceFile>();
referenceFactory.put(bamIndexFile, ref);
try
{
Class<?> cls = getClass().getClassLoader().loadClass("net.sf.samtools.ReferenceDiscovery");
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
Field f = cls.getDeclaredField("referenceFactory");
f.set(null, referenceFactory);
}
catch (ClassNotFoundException e)
{
System.err.println("Check cramtools.jar is in the CLASSPATH. "+e.getMessage());
}
catch (SecurityException e)
{
e.printStackTrace();
}
catch (NoSuchFieldException e)
{
e.printStackTrace();
}
catch (IllegalArgumentException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
//net.sf.samtools.ReferenceDiscovery.referenceFactory.put(bamIndexFile, ref);
}
if(bam.startsWith("ftp"))
{
FTPSeekableStream fss = new FTPSeekableStream(new URL(bam));
samFileReader = new SAMFileReader(fss, bamIndexFile, false);
}
else if(!bam.startsWith("http"))
samFileReader = new SAMFileReader(bamFile, bamIndexFile);
}
else
{
final URL urlBamFile = new URL(bam);
samFileReader = new SAMFileReader(urlBamFile, bamIndexFile, false);
samFileReader.setValidationStringency(ValidationStringency.SILENT);
samFileReaderHash.put(bam, samFileReader);
return samFileReader;
final SAMFileReader inputSam = getSAMFileReader(bamList.get(0));
final SAMFileHeader header = inputSam.getFileHeader();
for(SAMSequenceRecord seq: header.getSequenceDictionary().getSequences())
seqLengths.put(seq.getSequenceName(),
seq.getSequenceLength());
seqNames.add(seq.getSequenceName());
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
class BamReadTask implements Runnable
{
private int start;
private int end;
private short bamIndex;
private float pixPerBase;
private CountDownLatch latch;
BamReadTask(int start, int end, short bamIndex, float pixPerBase, CountDownLatch latch)
{
this.start = start;
this.end = end;
this.bamIndex = bamIndex;
this.pixPerBase = pixPerBase;
this.latch = latch;
}
public void run()
{
try
{
readFromBamPicard(start, end, bamIndex, pixPerBase) ;
}
catch (OutOfMemoryError ome)
{
throw ome;
}
catch(IOException me)
{
me.printStackTrace();
}
finally
{
latch.countDown();
}
}
}
private void readFromBamPicard(int start, int end, short bamIndex, float pixPerBase)
{
// Open the input file. Automatically detects whether input is SAM or BAM
// and delegates to a reader implementation for the appropriate format.
final SAMFileReader inputSam = getSAMFileReader(bam);
//final SAMFileReader inputSam = new SAMFileReader(bamFile, indexFile);
int sBeg = offset+1;
int sEnd = sBeg+sLen-1;
if( (sBeg >= start && sBeg <= end) ||
(sBeg <= start && sEnd >= start) )
{
int thisStart = start - offset;
if(thisStart < 1)
thisStart = 1;
int thisEnd = end - offset;
if(thisEnd > sLen)
thisEnd = sLen;
iterateOverBam(inputSam, seq, thisStart, thisEnd, bamIndex, pixPerBase, bam);
//System.out.println("READ "+seq+" "+thisStart+".."+thisEnd+" "+start+" --- "+offset);
}
}
}
else
{
String refName = (String) combo.getSelectedItem();
iterateOverBam(inputSam, refName, start, end, bamIndex, pixPerBase, bam);
}
/**
* Iterate over BAM file and load into the <code>List</code> of
* <code>SAMRecord</code>.
* @param inputSam
* @param refName
* @param start
* @param end
*/
private void iterateOverBam(final SAMFileReader inputSam,
final String refName, final int start, final int end,
final short bamIndex, final float pixPerBase,
final String bam)
{
final MemoryMXBean memory = ManagementFactory.getMemoryMXBean();
final int seqOffset = getSequenceOffset(refName);
final int offset = seqOffset- getBaseAtStartOfView();
final boolean isCoverageView = isCoverageView(pixPerBase);
int nbins = 800;
int binSize = ((end-start)/nbins)+1;
if(binSize < 1)
{
binSize = 1;
nbins = end-start+1;
}
int max = MAX_COVERAGE*binSize;
if(max < 1)
max = Integer.MAX_VALUE;
final int cov[] = new int[nbins];
for(int i=0; i<nbins; i++)
cov[i] = 0;
final CloseableIterator<SAMRecord> it = inputSam.queryOverlapping(refName, start, end);
try
{
cnt++;
SAMRecord samRecord = it.next();
if( samRecordFlagPredicate == null ||
!samRecordFlagPredicate.testPredicate(samRecord))
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
if(samRecordMapQPredicate == null ||
samRecordMapQPredicate.testPredicate(samRecord))
{
int abeg = samRecord.getAlignmentStart();
int aend = samRecord.getAlignmentEnd();
boolean over = false;
for(int i=abeg; i<aend; i++)
{
int bin = ((i-start)/binSize)-1;
if(bin < 0)
bin = 0;
else if(bin > nbins-1)
bin = nbins-1;
cov[bin]++;
if(cov[bin] > max)
{
over = true;
break;
}
}
if(over)
continue;
if(isCoverageView)
coverageView.addRecord(samRecord, offset, bam);
if(isCoverage)
coveragePanel.addRecord(samRecord, offset, bam);
if(isSNPplot)
snpPanel.addRecord(samRecord, seqOffset);
if(!isCoverageView)
readsInView.add(new BamViewRecord(samRecord, bamIndex));
}
cnt = 0;
float heapFraction =
(float)((float)memory.getHeapMemoryUsage().getUsed()/
(float)memory.getHeapMemoryUsage().getMax());
logger4j.debug("Heap memory usage (used/max): "+heapFraction);
if(readsInView.size() > checkMemAfter*2 && !waitingFrame.isVisible())
waitingFrame.showWaiting("loading...", mainPanel);
if(heapFraction > 0.90)
{
popFrame.show(
"Using > 90 % of the maximum memory limit:"+
(memory.getHeapMemoryUsage().getMax()/1000000.f)+" Mb.\n"+
"Not all reads in this range have been read in. Zoom in or\n"+
"consider increasing the memory for this application.",
mainPanel,
15000);
break;
}
catch(Exception e)
{
System.err.println(e.getMessage());
}
finally
{
it.close();
}
return len;
}
else
return seqLengths.get((String) combo.getSelectedItem());
}
/**
* For BAM files with multiple references sequences, calculate
* the offset from the start of the concatenated sequence for
* a given reference.
* @param refName
* @return
*/
protected int getSequenceOffset(String refName)
{
if(offsetLengths == null)
{
/* offsetLengths = new Hashtable<String, Integer>(combo.getItemCount());
int offset = 0;
for(int i=0; i<combo.getItemCount(); i++)
{
String thisSeqName = (String) combo.getItemAt(i);
offsetLengths.put(thisSeqName, offset);
offset += seqLengths.get(combo.getItemAt(i));
final FeatureVector features = feature_display.getEntryGroup().getAllFeatures();
final HashMap<String, Integer> lookup = new HashMap<String, Integer>();
for(int i=0; i<features.size(); i++)
lookup.put(features.elementAt(i).getIDString(), features.elementAt(i).getFirstBase());
offsetLengths = new HashMap<String, Integer>(seqNames.size());
for(int i=0; i<seqNames.size(); i++)
{
final Integer pos = lookup.get(seqNames.get(i));
if(pos != null)
offsetLengths.put(seqNames.get(i), pos-1);
/*final FeatureContigPredicate predicate = new FeatureContigPredicate(seqNames.get(i).trim());
for(int j=0; j<features.size(); j++)
{
if(predicate.testPredicate(features.elementAt(j)))
{
offsetLengths.put(seqNames.get(i), features.elementAt(j).getFirstBase()-1);
break;
}
if(offsetLengths.size() != seqNames.size())
System.err.println("Found: "+offsetLengths.size() +" of "+ seqNames.size());
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
JOptionPane.showMessageDialog(BamView.this,
"There is a problem matching the reference sequences\n"+
"to the names in the BAM file. This may mean the labels\n"+
"on the reference features do not match those in the in\n"+
"the BAM file.",
"Problem Found", JOptionPane.WARNING_MESSAGE);
}
});
int offset = 0;
for(int i=0; i<combo.getItemCount(); i++)
{
String thisSeqName = (String) combo.getItemAt(i);
offsetLengths.put(thisSeqName, offset);
offset += seqLengths.get(combo.getItemAt(i));
}
//return 0;
return offsetLengths.get(refName);
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
if(startBase > 0)
start = startBase;
else
if(endBase > 0)
end = endBase;
else
end = start + nbasesInView - 1;
if(end > seqLength)
end = seqLength;
if(feature_display != null && nbasesInView < feature_display.getMaxVisibleBases())
nbasesInView = feature_display.getMaxVisibleBases();
boolean changeToStackView = false;
MemoryMXBean memory = ManagementFactory.getMemoryMXBean();
coverageView.init(this, pixPerBase, start, end);
if(isCoverage)
coveragePanel.init(this, pixPerBase, start, end);
if(isSNPplot)
snpPanel.init(this, pixPerBase, start, end);
synchronized (this)
try
{
float heapFractionUsedBefore = (float) ((float) memory.getHeapMemoryUsage().getUsed() /
(float) memory.getHeapMemoryUsage().getMax());
if(readsInView == null)
readsInView = new Vector<BamViewRecord>();
else
readsInView.clear();
final CountDownLatch latch = new CountDownLatch(bamList.size()-hideBamList.size());
//long ms = System.currentTimeMillis();
for(short i=0; i<bamList.size(); i++)
{
if(!hideBamList.contains(i))
bamReadTaskExecutor.execute(
new BamReadTask(start, end, i, pixPerBase, latch));
try
{
latch.await();
}
catch (InterruptedException e) {} // TODO
//System.out.println("===== NO. THREADS="+
// ((java.util.concurrent.ThreadPoolExecutor)bamReadTaskExecutor).getPoolSize()+" TIME="+(System.currentTimeMillis()-ms));
float heapFractionUsedAfter = (float) ((float) memory.getHeapMemoryUsage().getUsed() /
(float) memory.getHeapMemoryUsage().getMax());
// System.out.println("Heap Max : "+memory.getHeapMemoryUsage().getMax());
// System.out.println("Heap Used : "+memory.getHeapMemoryUsage().getUsed());
// System.out.println("Heap memory used "+heapFractionUsedAfter);
if ((heapFractionUsedAfter - heapFractionUsedBefore) > 0.06
&& !isStackView() && heapFractionUsedAfter > 0.8)
changeToStackView = true;
}
if((!isStackView() && !isStrandStackView()) || isBaseAlignmentView(pixPerBase))
{
Collections.sort(readsInView, new SAMRecordComparator());
}
else if( (isStackView() || isStrandStackView()) &&
bamList.size() > 1)
{
// merge multiple BAM files
Collections.sort(readsInView, new SAMRecordPositionComparator(BamView.this));
}
catch (OutOfMemoryError ome)
JOptionPane.showMessageDialog(this, "Out of Memory");
readsInView.clear();
return;
catch(net.sf.samtools.util.RuntimeIOException re)
{
JOptionPane.showMessageDialog(this, re.getMessage());
}
drawCoverage(g2,start, end, pixPerBase);
drawStackView(g2, seqLength, pixPerBase, start, end);
drawPairedStackView(g2, seqLength, pixPerBase, start, end);
else
drawLineView(g2, seqLength, pixPerBase, start, end);
if(isCoverage)
coveragePanel.repaint();
if(isSNPplot)
snpPanel.repaint();
if(changeToStackView)
{
"Note :: Changed to the stack view to save memory.\n"+
"Currently this is using "+
(memory.getHeapMemoryUsage().getUsed()/1000000.f)+" Mb "+
"and the maximum\nmemory limit is "+
(memory.getHeapMemoryUsage().getMax()/1000000.f)+" Mb.",
return (float)mainPanel.getWidth() / (float)nbasesInView;
{
if(feature_display == null)
return seqLength+nbasesInView/3;
/**
* Draw the zoomed-in base view.
* @param g2
* @param seqLength
* @param pixPerBase
* @param start
* @param end
*/
private void drawBaseAlignment(Graphics2D g2,
int seqLength,
float pixPerBase,
final int start,
tjc
committed
int ypos = 0;
end = start + ( mainPanel.getWidth() * ALIGNMENT_PIX_PER_BASE );
if(seqEnd > bases.getLength())
seqEnd = bases.getLength();
if(refSeqStart < 1)
refSeqStart = 1;
refSeq =
bases.getSubSequence(new Range(refSeqStart, seqEnd), Bases.FORWARD).toUpperCase();
ruler.refSeq = refSeq;
}
catch (OutOfRangeException e)
{
e.printStackTrace();
}
}
ruler.repaint();
drawSelectionRange(g2, ALIGNMENT_PIX_PER_BASE, start, end, Color.PINK);
g2.setStroke(new BasicStroke (2.f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND));
Rectangle r = jspView.getViewport().getViewRect();
int nreads = readsInView.size();
BamViewRecord thisRead = readsInView.get(i);
if (ypos < r.getMaxY() || ypos > r.getMinY())
drawSequence(g2, thisRead, ypos, refSeq, refSeqStart);
drawn[i] = true;
int thisEnd = thisRead.sam.getAlignmentEnd();
thisEnd = thisRead.sam.getAlignmentStart() + thisRead.sam.getReadLength();
BamViewRecord nextRead = readsInView.get(j);
int nextStart = nextRead.sam.getAlignmentStart();
if (nextStart > thisEnd + 1)
{
if (ypos < r.getMaxY() || ypos > r.getMinY())
drawSequence(g2, nextRead, ypos, refSeq, refSeqStart);
drawn[j] = true;
thisEnd = nextRead.sam.getAlignmentEnd();
thisEnd = nextStart + nextRead.sam.getReadLength();
}
else if (ypos > r.getMaxY() || ypos < r.getMinY())
break;
catch (ArrayIndexOutOfBoundsException ae)
{
System.err.println(readsInView.size()+" "+nreads);
ae.printStackTrace();
}
Dimension d = getPreferredSize();
d.setSize(getPreferredSize().getWidth(), ypos);
setPreferredSize(d);
/**
* Draw the query sequence
* @param g2
* @param read
* @param pixPerBase
* @param ypos
*/
private void drawSequence(Graphics2D g2, BamViewRecord bamViewRecord,
int ypos, String refSeq, int refSeqStart)
SAMRecord samRecord = bamViewRecord.sam;
if (!samRecord.getReadPairedFlag() || // read is not paired in sequencing
samRecord.getMateUnmappedFlag() ) // mate is unmapped ) // mate is unmapped
final Color col = g2.getColor();
int len = 0;
int refPos = 0;
String readSeq = samRecord.getReadString();
int offset = getSequenceOffset(samRecord.getReferenceName());
byte[] phredQuality = null;
if(baseQualityColour.isSelected())
phredQuality = samRecord.getBaseQualities();
Hashtable<Integer, String> insertions = null;
List<AlignmentBlock> blocks = samRecord.getAlignmentBlocks();
for(int i=0; i<blocks.size(); i++)
AlignmentBlock block = blocks.get(i);
int blockStart = block.getReadStart();
for(int j=0; j<block.getLength(); j++)
int readPos = blockStart-1+j;
xpos = block.getReferenceStart() - 1 + j + offset;
refPos = xpos - refSeqStart + 1;
setColourByBaseQuality(g2, phredQuality[readPos]);
if(isSNPs && refSeq != null && refPos > 0 && refPos < refSeq.length())
if(readSeq.charAt(readPos) != refSeq.charAt(refPos))
g2.setColor(Color.red);
else
g2.setColor(col);
}
g2.drawString(readSeq.substring(readPos, readPos+1),
refPos*ALIGNMENT_PIX_PER_BASE, ypos);
if(isSNPs)
g2.setColor(col);
// look for insertions
if(markInsertions.isSelected() && i < blocks.size()-1)
{
int blockEnd = blockStart+block.getLength();
int nextBlockStart = blocks.get(i+1).getReadStart();
int insertSize = nextBlockStart - blockEnd;
if(insertSize > 0)
{
if(insertions == null)
insertions = new Hashtable<Integer, String>();
tjc
committed
(refPos+refSeqStart+1)+" "+
readSeq.substring(blockEnd-1, nextBlockStart-1));
g2.drawLine(xscreen, ypos, xscreen, ypos-BASE_HEIGHT);
// mark on reference sequence as well
if(bases != null)
g2.drawLine(xscreen, 11, xscreen, 11-BASE_HEIGHT);
g2.setColor(col);
}
}
// highlight
if(highlightSAMRecord != null &&
highlightSAMRecord.sam.getReadName().equals(samRecord.getReadName()))
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
{
refPos = block.getReferenceStart() + offset - refSeqStart;
int xstart = refPos*ALIGNMENT_PIX_PER_BASE;
int width = block.getLength()*ALIGNMENT_PIX_PER_BASE;
Color col1 = g2.getColor();
g2.setColor(Color.red);
g2.drawRect(xstart, ypos-BASE_HEIGHT, width, BASE_HEIGHT);
if(i < blocks.size()-1)
{
int nextStart =
(blocks.get(i+1).getReferenceStart() + offset - refSeqStart)*ALIGNMENT_PIX_PER_BASE;
g2.drawLine(xstart+width, ypos-(BASE_HEIGHT/2), nextStart, ypos-(BASE_HEIGHT/2));
}
g2.setColor(col1);
}
else if(i < blocks.size()-1)
{
refPos = block.getReferenceStart() + offset - refSeqStart;
int xstart = refPos*ALIGNMENT_PIX_PER_BASE;
int width = block.getLength()*ALIGNMENT_PIX_PER_BASE;
int nextStart =
(blocks.get(i+1).getReferenceStart() + offset - refSeqStart)*ALIGNMENT_PIX_PER_BASE;
g2.drawLine(xstart+width, ypos-(BASE_HEIGHT/2), nextStart, ypos-(BASE_HEIGHT/2));
}
if(lastMousePoint != null && blocks.size() > 0)
refPos = blocks.get(0).getReferenceStart()+offset-refSeqStart;
refPos = blocks.get(blocks.size()-1).getReferenceStart()+
blocks.get(blocks.size()-1).getLength()+offset-refSeqStart;
if(lastMousePoint.getY() > ypos-11 && lastMousePoint.getY() < ypos)
if(lastMousePoint.getX() > xstart &&
lastMousePoint.getX() < xend)
{
mouseOverSAMRecord = bamViewRecord;
if(insertions != null)
mouseOverInsertion = insertions.get((int)lastMousePoint.getX());
/**
* Colour bases on their mapping quality.
* @param g2
* @param baseQuality
*/
private void setColourByBaseQuality(Graphics2D g2, byte baseQuality)
{
if (baseQuality < 10)
g2.setColor(Color.blue);
else if (baseQuality < 20)
else if (baseQuality < 30)
else
g2.setColor(Color.black);
}
* Draw inferred size view.
* @param g2
* @param seqLength
* @param pixPerBase
* @param start
* @param end
*/
private void drawLineView(Graphics2D g2, int seqLength, float pixPerBase, int start, int end)
drawSelectionRange(g2, pixPerBase,start, end, Color.PINK);
new BasicStroke (1.3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);
if(isShowScale())
scaleHeight = 15;
else
scaleHeight = 0;
int baseAtStartOfView = getBaseAtStartOfView();
Rectangle r = jspView.getViewport().getViewRect();
BamViewRecord bamViewRecord = readsInView.get(i);
SAMRecord samRecord = bamViewRecord.sam;
BamViewRecord bamViewNextRecord = null;
if( !samRecord.getReadPairedFlag() || // read is not paired in sequencing
int ypos = getYPos(scaleHeight, samRecord.getReadString().length()); // (getHeight() - scaleHeight) - samRecord.getReadString().length();
if(ypos > r.getMaxY() || ypos < r.getMinY())
drawRead(g2, bamViewRecord, pixPerBase, ypos, baseAtStartOfView, snps);
int ypos = getYPos(scaleHeight, Math.abs(samRecord.getInferredInsertSize()));
if( (ypos > r.getMaxY() || ypos < r.getMinY()) && ypos > 0 )
bamViewNextRecord = readsInView.get(++i);
samNextRecord = bamViewNextRecord.sam;
if(samRecord.getReadName().equals(samNextRecord.getReadName()))
if(samRecord.getAlignmentEnd() < samNextRecord.getAlignmentStart() &&
(samNextRecord.getAlignmentStart()-samRecord.getAlignmentEnd())*pixPerBase > 2.f)
g2.setColor(Color.LIGHT_GRAY);
int offset1 = getSequenceOffset(samRecord.getReferenceName());
int end1 = samRecord.getAlignmentEnd()+offset1-baseAtStartOfView;
int offset2 = getSequenceOffset(samNextRecord.getReferenceName());
int start2 = samNextRecord.getAlignmentStart()+offset2-baseAtStartOfView;
drawTranslucentLine(g2,
(int)(end1*pixPerBase), (int)(start2*pixPerBase), ypos);
g2.setColor(getColourByCoverageColour(bamViewRecord));
else if( (samRecord.getReadNegativeStrandFlag() && // strand of the query (1 for reverse)
samNextRecord.getReadNegativeStrandFlag()) ||
(!samRecord.getReadNegativeStrandFlag() &&
!samNextRecord.getReadNegativeStrandFlag()))
drawRead(g2, bamViewRecord, pixPerBase, ypos, baseAtStartOfView, snps);
drawRead(g2, bamViewNextRecord, pixPerBase, ypos, baseAtStartOfView, getSNPs(samNextRecord));
drawLoneRead(g2, bamViewRecord, ypos, pixPerBase, baseAtStartOfView, scaleHeight, snps);
drawLoneRead(g2, bamViewRecord, ypos, pixPerBase, baseAtStartOfView, scaleHeight, snps);
private int getYPos(int scaleHeight, int size)
{
if(!logScale)
else
{
int logInfSize = (int)( Math.log(size) * 100);
tjc
committed
/**
* Draw the reads as lines in vertical stacks. The reads are colour
* coded as follows:
*
* blue - reads are unique and are paired with a mapped mate
* black - reads are unique and are not paired or have an unmapped mate
* green - reads are duplicates
tjc
committed
*
* @param g2
* @param seqLength
* @param pixPerBase
* @param start
* @param end
*/
private void drawStackView(Graphics2D g2,
final int seqLength,
final float pixPerBase,
final int start,
final int end)
drawSelectionRange(g2, pixPerBase,start, end, Color.PINK);
1.3f,
BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER);
if(isShowScale())
scaleHeight = 15;
else
scaleHeight = 0;
int ypos = (getHeight() - scaleHeight);
int ydiff = 2;
if(isOrientation)
ydiff= 4;
tjc
committed
int maxEnd = 0;
int lstStart = 0;
int lstEnd = 0;
SAMRecord samRecord = bamViewRecord.sam;
int offset = getSequenceOffset(samRecord.getReferenceName());
tjc
committed
int recordStart = samRecord.getAlignmentStart()+offset;
int recordEnd = samRecord.getAlignmentEnd()+offset;
lstStart != recordStart || lstEnd != recordEnd || snps != null)
tjc
committed
{
g2.setColor(getColourByCoverageColour(bamViewRecord));
else if (!samRecord.getReadPairedFlag() || // read is not paired in sequencing
samRecord.getMateUnmappedFlag() ) // mate is unmapped ) // mate is unmapped
tjc
committed
g2.setColor(Color.black);
else
g2.setColor(Color.blue);
if(maxEnd < recordStart || ypos < 0)
tjc
committed
{
ypos = (getHeight() - scaleHeight)-ydiff;
tjc
committed
maxEnd = recordEnd+2;
}
else
if(snps != null)
lstStart = -1;
else
{
lstStart = recordStart;
lstEnd = recordEnd;
}
if(ypos > r.getMaxY() || ypos < r.getMinY())
drawRead(g2, bamViewRecord, pixPerBase, ypos, baseAtStartOfView, snps);
/**
* Draw the reads as lines in vertical stacks. The reads are colour
* coded as follows:
*
* blue - reads are unique and are paired with a mapped mate
* black - reads are unique and are not paired or have an unmapped mate
* green - reads are duplicates
*
* @param g2
* @param seqLength
* @param pixPerBase
* @param start
* @param end
*/
private void drawStrandStackView(Graphics2D g2,
int seqLength,
float pixPerBase,
int start,
int end)
{
drawSelectionRange(g2, pixPerBase,start, end, Color.PINK);
1.3f,
BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER);
drawScale(g2, start, end, pixPerBase, ((getHeight()+scaleHeight)/2));
int ymid = (getHeight()/ 2);
int ydiff = 2;
if(isOrientation)
ydiff= 4;
drawStrand(g2, false, scaleHeight, ymid-(scaleHeight/2), -ydiff, pixPerBase, stroke);
drawStrand(g2, true, scaleHeight, ymid+(scaleHeight/2), ydiff, pixPerBase, stroke);
}
private void drawStrand(Graphics2D g2,
boolean isStrandNegative,
int scaleHeight,
int ymid,
int ystep,
float pixPerBase,
Stroke stroke)
{
int hgt = getHeight();
int ypos = (hgt - scaleHeight);
int maxEnd = 0;
int lstStart = 0;
int lstEnd = 0;
int baseAtStartOfView = getBaseAtStartOfView();
Rectangle r = jspView.getViewport().getViewRect();
SAMRecord samRecord = bamViewRecord.sam;
if( samRecord.getReadNegativeStrandFlag() == isStrandNegative )
{
final int offset = getSequenceOffset(samRecord.getReferenceName());
final int recordStart = samRecord.getAlignmentStart()+offset;
final int recordEnd = samRecord.getAlignmentEnd()+offset;
if(colourByCoverageColour.isSelected() ||
lstStart != recordStart || lstEnd != recordEnd || snps != null)
g2.setColor(getColourByCoverageColour(bamViewRecord));
else if (!samRecord.getReadPairedFlag() || // read is not paired in sequencing
samRecord.getMateUnmappedFlag() ) // mate is unmapped
g2.setColor(Color.black);
else
g2.setColor(Color.blue);
if(maxEnd < recordStart || ypos < 0 || ypos > hgt)
{
ypos = ymid + ystep;
maxEnd = recordEnd+2;
}
else
ypos = ypos + ystep;
}
else
if(snps != null)
lstStart = -1;
else
{
lstStart = recordStart;
lstEnd = recordEnd;
}
if(ypos > r.getMaxY() || ypos < r.getMinY())
drawRead(g2, bamViewRecord, pixPerBase, ypos, baseAtStartOfView, snps);
* Draw paired reads as lines in a vertical stacks.
* @param g2
* @param seqLength
* @param pixPerBase
* @param start
* @param end
*/
private void drawPairedStackView(Graphics2D g2,
final int seqLength,
final float pixPerBase,
final int start,
final int end)
drawSelectionRange(g2, pixPerBase,start, end, Color.PINK);
if(isShowScale())
final Vector<PairedRead> pairedReads = new Vector<PairedRead>();
for(int i=0; i<readsInView.size(); i++)
{
BamViewRecord bamViewRecord = readsInView.get(i);
SAMRecord samRecord = bamViewRecord.sam;
if( !samRecord.getReadPairedFlag() || // read is not paired in sequencing
samRecord.getMateUnmappedFlag() ) // mate is unmapped
continue;
BamViewRecord bamViewNextRecord = null;
if(i < readsInView.size()-1)
{
bamViewNextRecord = readsInView.get(++i);
SAMRecord samNextRecord = bamViewNextRecord.sam;
final PairedRead pr = new PairedRead();
if(samRecord.getReadName().equals(samNextRecord.getReadName()) &&
isFromSameBamFile(bamViewRecord, bamViewNextRecord, bamList))
{
if(samRecord.getAlignmentStart() < samNextRecord.getAlignmentStart())
{
pr.sam1 = bamViewRecord;
pr.sam2 = bamViewNextRecord;
}
else
{
pr.sam2 = bamViewRecord;
pr.sam1 = bamViewNextRecord;
}
}
else
{
--i;
pr.sam1 = bamViewRecord;
pr.sam2 = null;
}
pairedReads.add(pr);
}
}
Collections.sort(pairedReads, new PairedReadComparator());
Stroke originalStroke = new BasicStroke (1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);
Stroke stroke =
new BasicStroke (1.3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);
if(isShowScale())
scaleHeight = 15;
else
scaleHeight = 0;
int ydiff = 3;
if(isOrientation)
ydiff= 5;
int ypos = getHeight() - scaleHeight - ydiff;
int lastEnd = 0;
int baseAtStartOfView = getBaseAtStartOfView();
Rectangle r = jspView.getViewport().getViewRect();
if(pr.sam1.sam.getAlignmentStart() > lastEnd)
ypos = getHeight() - scaleHeight - ydiff;
if(pr.sam2 != null)
lastEnd = pr.sam2.sam.getAlignmentEnd();
lastEnd = pr.sam1.sam.getAlignmentEnd();
if(ypos > r.getMaxY() || ypos < r.getMinY())
g2.setStroke(originalStroke);
if(highlightSAMRecord != null &&
highlightSAMRecord.sam.getReadName().equals(pr.sam1.sam.getReadName()))
g2.setColor(Color.black);
else
g2.setColor(Color.gray);
if(pr.sam2 != null)
{
if(!readsOverlap(pr.sam1.sam, pr.sam2.sam))
int offset1 = getSequenceOffset(pr.sam1.sam.getReferenceName());
int offset2 = getSequenceOffset(pr.sam2.sam.getReferenceName());
drawTranslucentJointedLine(g2,
(int)((pr.sam1.sam.getAlignmentEnd()+offset1-getBaseAtStartOfView())*pixPerBase),
(int)((pr.sam2.sam.getAlignmentStart()+offset2-getBaseAtStartOfView())*pixPerBase), ypos);
else if(!pr.sam1.sam.getMateUnmappedFlag() &&
pr.sam1.sam.getProperPairFlag() &&
pr.sam1.sam.getMateReferenceName().equals(pr.sam1.sam.getReferenceName()))
if(pr.sam1.sam.getAlignmentStart() > pr.sam1.sam.getMateAlignmentStart())
prStart = pr.sam1.sam.getMateAlignmentStart();
prEnd = pr.sam1.sam.getAlignmentStart();
prStart = pr.sam1.sam.getAlignmentEnd();
prEnd = pr.sam1.sam.getMateAlignmentStart();
int offset = getSequenceOffset(pr.sam1.sam.getReferenceName());
drawTranslucentJointedLine(g2,
(int)( (prStart+offset-getBaseAtStartOfView())*pixPerBase),
(int)( (prEnd +offset-getBaseAtStartOfView())*pixPerBase), ypos);
if(colourByCoverageColour.isSelected())
g2.setColor(getColourByCoverageColour(pr.sam1));
else if( pr.sam2 != null &&
!( pr.sam1.sam.getReadNegativeStrandFlag() ^ pr.sam2.sam.getReadNegativeStrandFlag() ) )
g2.setColor(Color.red);
else
g2.setColor(Color.blue);
drawRead(g2, pr.sam1, pixPerBase, ypos, baseAtStartOfView, getSNPs(pr.sam1.sam));
if(pr.sam2 != null)
drawRead(g2, pr.sam2, pixPerBase, ypos, baseAtStartOfView, getSNPs(pr.sam2.sam));
/**
* Check if two records are from the same BAM file
* @param sam1
* @param sam2
* @param bamList
* @return
*/
private boolean isFromSameBamFile(final BamViewRecord sam1,
final BamViewRecord sam2,
final List<String> bamList)
{
if(bamList == null || bamList.size()<2)
return true;
final short o1 = sam1.bamIndex;
final short o2 = sam2.bamIndex;
if(o1 != -1 && o2 != -1)
if( o1 != o2 )
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
return false;
return true;
}
/**
* Check if two records overlap
* @param s1
* @param s2
* @return true id the two reads overlap
*/
private boolean readsOverlap(final SAMRecord s1,
final SAMRecord s2)
{
if( (s2.getAlignmentStart() >= s1.getAlignmentStart() &&
s2.getAlignmentStart() <= s1.getAlignmentEnd()) ||
(s2.getAlignmentEnd() >= s1.getAlignmentStart() &&
s2.getAlignmentEnd() <= s1.getAlignmentEnd()) )
return true;
if( (s1.getAlignmentStart() >= s2.getAlignmentStart() &&
s1.getAlignmentStart() <= s2.getAlignmentEnd()) ||
(s1.getAlignmentEnd() >= s2.getAlignmentStart() &&
s1.getAlignmentEnd() <= s2.getAlignmentEnd()) )
return true;
return false;
}
/**
* Draw the read coverage.
* @param g2
* @param start
* @param end
* @param pixPerBase
*/
private void drawCoverage(Graphics2D g2, int start, int end, float pixPerBase)
{
int scaleHeight = 0;
if(isShowScale())
{
drawScale(g2, start, end, pixPerBase, getHeight());
scaleHeight = 15;
}
int hgt = jspView.getVisibleRect().height-scaleHeight;
if(!cbCoverageStrandView.isSelected() && !cbCoverageHeatMap.isSelected())
try
{
int y = getHeight()-6-( (hgt* MAX_COVERAGE)/(coverageView.max/coverageView.windowSize) );
g2.setColor(Color.YELLOW);
// draw the threshold for the coverage max read cut-off
g2.fillRect(0, y, getWidth(), 8);
}
catch(Exception e){}
g2.translate(0, getJspView().getViewport().getViewPosition().y);
coverageView.drawSelectionRange(g2, pixPerBase, start, end, getHeight(), Color.PINK);
coverageView.draw(g2, getWidth(), hgt);
coverageView.drawMax(g2);
}
/**
* Draw a read that apparently has a read mate that is not in view.
* @param g2
* @param thisRead
* @param ypos
* @param pixPerBase
* @param originalStroke
* @param stroke
*/
private void drawLoneRead(Graphics2D g2, BamViewRecord bamViewRecord, int ypos,
float pixPerBase, int baseAtStartOfView, int scaleHeight, List<Integer> snps)
SAMRecord samRecord = bamViewRecord.sam;
boolean offTheTop = false;
int offset = getSequenceOffset(samRecord.getReferenceName());
int thisStart = samRecord.getAlignmentStart()+offset;
int thisEnd = thisStart + samRecord.getReadString().length() -1;
if(ypos <= 0)
{
offTheTop = true;
ypos = samRecord.getReadString().length();
}
{
offTheTop = true;
ypos = getHeight() - scaleHeight - 5;
}
Math.abs(samRecord.getMateAlignmentStart()-samRecord.getAlignmentEnd())*pixPerBase > 2.f)
{
g2.setColor(Color.LIGHT_GRAY);
if(samRecord.getAlignmentEnd() < samRecord.getMateAlignmentStart())
{
(int)((samRecord.getMateAlignmentStart()-getBaseAtStartOfView()+offset)*pixPerBase);
drawTranslucentLine(g2,
(int)((thisEnd-getBaseAtStartOfView())*pixPerBase), nextStart, ypos);
int nextStart =
(int)((samRecord.getMateAlignmentStart()-getBaseAtStartOfView()+offset)*pixPerBase);
drawTranslucentLine(g2,
(int)((thisStart-getBaseAtStartOfView())*pixPerBase), nextStart, ypos);
g2.setColor(getColourByCoverageColour(bamViewRecord));
tjc
committed
else if(samRecord.getReadNegativeStrandFlag() &&
samRecord.getMateNegativeStrandFlag()) // strand of the query (1 for reverse)
g2.setColor(Color.red);
else
g2.setColor(Color.blue);
drawRead(g2, bamViewRecord, pixPerBase, ypos, baseAtStartOfView, snps);
/*if (isSNPs)
showSNPsOnReads(g2, samRecord, pixPerBase, ypos, offset);*/
private void drawScale(Graphics2D g2, int start, int end, float pixPerBase, int ypos)
g2.drawLine( 0, ypos-14,
(int)((end - getBaseAtStartOfView())*pixPerBase), ypos-14);
private void drawTicks(Graphics2D g2, int start, int end, float pixPerBase, int division, int ypos)
int markStart = (Math.round(start/division)*division);
if(markStart < 1)
markStart = 1;
g2.drawString(Integer.toString(m), x, ypos-1);
g2.drawLine((int)x, ypos-14,(int)x, ypos-11);
/**
* Draw a y-scale for inferred size (isize) of reads.
* @param g2
* @param xScaleHeight
*/
private void drawYScale(Graphics2D g2, int xScaleHeight)
int maxY = getPreferredSize().height-xScaleHeight;
if(logScale)
{
int start = 10;
int count = 0;
int ypos = getYPos(xScaleHeight, start);
while(ypos > 0 && count < 15 && start > 1)
{
g2.drawLine(0, ypos, 2, ypos);
g2.drawString(Integer.toString(start), 3, ypos);
start = start*5;
ypos = getYPos(xScaleHeight, start);
count++;
}
return;
}
for(int i=100; i<maxY; i+=100)
{
int ypos = getHeight()-i-xScaleHeight;
g2.drawLine(0, ypos, 2, ypos);
g2.drawString(Integer.toString(i), 3, ypos);
/**
* Draw a given read.
* @param g2
* @param thisRead
* @param pixPerBase
* @param ypos
* @param snps
final BamViewRecord bamViewRecord,
final int baseAtStartOfView,
SAMRecord thisRead = bamViewRecord.sam;
int offset = getSequenceOffset(thisRead.getReferenceName());
int thisStart = thisRead.getAlignmentStart()+offset-baseAtStartOfView;
int thisEnd = thisRead.getAlignmentEnd()+offset-baseAtStartOfView;
if(highlightSAMRecord != null &&
highlightSAMRecord.sam.getReadName().equals(thisRead.getReadName()))
Stroke originalStroke = g2.getStroke();
Stroke stroke =
new BasicStroke (3.f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);
Color c = g2.getColor();
g2.setColor(Color.black);
g2.drawLine((int)( thisStart * pixPerBase), ypos,
(int)( thisEnd * pixPerBase), ypos);
g2.setColor(c);
if(thisRead.getCigar().getCigarElements().size() == 1)
g2.drawLine((int)( thisStart * pixPerBase), ypos,
(int)( thisEnd * pixPerBase), ypos);
else
{
List<AlignmentBlock> blocks = thisRead.getAlignmentBlocks();
Color c = g2.getColor();
int lastEnd = 0;
for(int i=0; i<blocks.size(); i++)
{
AlignmentBlock block = blocks.get(i);
int blockStart = block.getReferenceStart()+offset-baseAtStartOfView;
int blockEnd = blockStart + block.getLength() - 1;
g2.drawLine((int)( blockStart * pixPerBase), ypos,
(int)( blockEnd * pixPerBase), ypos);
if(i > 0 && blockStart != lastEnd)
{
g2.setColor(Color.gray);
g2.drawLine((int)( blockStart * pixPerBase), ypos,
(int)( lastEnd * pixPerBase), ypos);
g2.setColor(c);
}
lastEnd = blockEnd;
}
}
if(isOrientation)
drawArrow(g2, thisRead, thisStart, thisEnd, pixPerBase, ypos);
// test if the mouse is over this read
if(lastMousePoint != null)
{
if(lastMousePoint.getY()+2 > ypos && lastMousePoint.getY()-2 < ypos)
if(lastMousePoint.getX() > thisStart * pixPerBase &&
lastMousePoint.getX() < thisEnd * pixPerBase)
{
mouseOverSAMRecord = bamViewRecord;
if (isSNPs && snps != null)
showSNPsOnReads(snps, g2, pixPerBase, ypos);
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
/**
* Draw arrow on the read to indicate orientation.
* @param g2
* @param thisRead
* @param thisStart
* @param thisEnd
* @param pixPerBase
* @param ypos
*/
private void drawArrow(Graphics2D g2,
SAMRecord thisRead,
int thisStart,
int thisEnd,
float pixPerBase,
int ypos)
{
if(thisRead.getReadNegativeStrandFlag())
{
int apos = ypos + 2;
g2.drawLine((int)( (thisStart+5) * pixPerBase), apos,
(int)( thisStart * pixPerBase), ypos);
}
else
{
int apos = ypos - 2;
g2.drawLine((int)( (thisEnd-5) * pixPerBase), apos,
(int)( thisEnd * pixPerBase), ypos);
}
}
/**
* Highlight a selected range
* @param g2
* @param pixPerBase
* @param start
* @param end
*/
private void drawSelectionRange(Graphics2D g2, float pixPerBase, int start, int end, Color c)
{
if(getSelection() != null)
{
Range selectedRange = getSelection().getSelectionRange();
if(selectedRange != null)
{
int rangeStart = selectedRange.getStart();
int rangeEnd = selectedRange.getEnd();
if(end < rangeStart || start > rangeEnd)
return;
int x = (int) (pixPerBase*(rangeStart-getBaseAtStartOfView()));
int width = (int) (pixPerBase*(rangeEnd-rangeStart+1));
g2.setColor(c);
g2.fillRect(x, 0, width, getHeight());
}
}
}
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
/**
* Draw a translucent line
* @param g2
* @param start
* @param end
* @param ypos
*/
private void drawTranslucentLine(Graphics2D g2, int start, int end, int ypos)
{
Composite origComposite = g2.getComposite();
g2.setComposite(translucent);
g2.drawLine(start, ypos, end, ypos);
g2.setComposite(origComposite);
}
/**
* Draw a translucent line
* @param g2
* @param start
* @param end
* @param ypos
*/
private void drawTranslucentJointedLine(Graphics2D g2, int start, int end, int ypos)
{
Composite origComposite = g2.getComposite();
g2.setComposite(translucent);
int mid = (int) ((end-start)/2.f)+start;
//g2.drawLine(start, ypos, end, ypos);
g2.drawLine(start, ypos, mid, ypos-5);
g2.drawLine(mid, ypos-5, end, ypos);
g2.setComposite(origComposite);
}
* @param snps
private void showSNPsOnReads(final List<Integer> snps,
final Graphics2D g2,
float pixPerBase, int ypos)
g2.setColor(Color.red);
for(int pos: snps)
g2.drawLine((int) (pos * pixPerBase), ypos + 2,
(int) (pos * pixPerBase), ypos - 2);
}
/**
* Get the SNP positions
* @param samRecord
*/
private List<Integer> getSNPs(final SAMRecord samRecord)
{
if(!isSNPs) // return null if not displaying SNPs
return null;
int rbeg = samRecord.getAlignmentStart();
int rend = samRecord.getAlignmentEnd();
int offset = getSequenceOffset(samRecord.getReferenceName());
ArrayList<Integer> snps = null;
// use alignment blocks of the contiguous alignment of
// subsets of read bases to a reference sequence
final char[] refSeq = bases.getSubSequenceC(
new Range(rbeg+offset, rend+offset), Bases.FORWARD);
final byte[] readSeq = samRecord.getReadBases();
offset = offset - getBaseAtStartOfView();
final List<AlignmentBlock> blocks = samRecord.getAlignmentBlocks();
int readStart = block.getReadStart();
int refStart = block.getReferenceStart();
int len = block.getLength();
for(int j=0; j<len; j++)
int readPos = readStart-1+j;
int refPos = refStart+j;
if (Character.toUpperCase(refSeq[refPos-rbeg]) != readSeq[readPos])
if(snps == null)
snps = new ArrayList<Integer>();
snps.add(refPos+offset);
System.err.println(samRecord.getReadName()+" "+e.getMessage());
return snps;
/**
* Add the alignment view to the supplied <code>JPanel</code> in
* a <code>JScrollPane</code>.
* @param mainPanel panel to add the alignment to
* @param autohide automatically hide the top panel containing the buttons
setDisplay(1, nbasesInView, null);
mainPanel.setLayout(new BorderLayout());
if(topPanel instanceof JPanel)
mainPanel.add(topPanel, BorderLayout.NORTH);
mainPanel.add(jspView, BorderLayout.CENTER);
JPanel bottomPanel = new JPanel(new BorderLayout());
coveragePanel = new CoveragePanel(this);
bottomPanel.add(coveragePanel, BorderLayout.CENTER);
//
snpPanel = new SnpPanel(this, bases);
bottomPanel.add(snpPanel, BorderLayout.NORTH);
if(feature_display == null)
{
scrollBar = new JScrollBar(JScrollBar.HORIZONTAL, 1, nbasesInView, 1,
getMaxBasesInPanel(getSequenceLength()));
scrollBar.setUnitIncrement(nbasesInView/20);
scrollBar.addAdjustmentListener(new AdjustmentListener()
{
public void adjustmentValueChanged(AdjustmentEvent e)
{
repaint();
if(isSNPplot)
snpPanel.repaint();
if(isCoverage)
coveragePanel.repaint();
}
});
bottomPanel.add(scrollBar, BorderLayout.SOUTH);
}
else
{
{
int seqLen = seqLengths.get((String) combo.getSelectedItem());
int artemisSeqLen = feature_display.getSequenceLength();
if(seqLen != artemisSeqLen)
{
int newIndex = -1;
for(int i=0; i<seqNames.size(); i++)
{
if(seqLengths.get(seqNames.get(i)) == artemisSeqLen)
{
// this looks like the correct sequence
combo.setSelectedIndex(i);
newIndex = i;
}
}
if(!Options.isBlackBeltMode())
{
String label[] = {
"The length of the sequence loaded does not match the length of",
"the default reference sequence in the BAM ("+seqNames.get(0)+").",
(newIndex == -1 ? "" : "The length does match the reference "+
};
new NonModalDialog(frame, label);
}
}
}
}
mainPanel.add(bottomPanel, BorderLayout.SOUTH);
coveragePanel.setPreferredSize(new Dimension(900, 100));
coveragePanel.setVisible(false);
snpPanel.setPreferredSize(new Dimension(900, 100));
snpPanel.setVisible(false);
jspView.getVerticalScrollBar().setValue(
jspView.getVerticalScrollBar().getMaximum());
private void addToViewMenu(final short thisBamIndex)
final File f = new File(bamList.get(thisBamIndex));
final JCheckBoxMenuItem cbBam = new JCheckBoxMenuItem(
f.getName(),
getImageIcon(getColourByCoverageColour(thisBamIndex)),
true);
bamFilesMenu.add(cbBam);
cbBam.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
if(cbBam.isSelected())
laststart = -1;
repaint();
}
});
}
/**
* Refresh the colour of the icons used to identify the
* BAM files.
*/
protected void refreshColourOfBamMenu()
{
final Component cs[] = bamFilesMenu.getMenuComponents();
for(Component c : cs)
{
if(c instanceof JCheckBoxMenuItem)
{
final JCheckBoxMenuItem cbBam = (JCheckBoxMenuItem) c;
final Color col = getColorByJCheckBoxMenuItem(cbBam);
if(col != null)
cbBam.setIcon(getImageIcon(col));
protected Color getColorByJCheckBoxMenuItem(JCheckBoxMenuItem cbBam)
{
final String bam = cbBam.getText();
for(short i=0; i<bamList.size(); i++)
{
final File f = new File(bamList.get(i));
if(f.getName().equals(bam))
return getColourByCoverageColour(i);
}
return null;
}
/**
* Create an icon of a box using the given colour.
* @param c
* @return
*/
{
BufferedImage image = (BufferedImage)this.createImage(10, 10);
Graphics2D g2 = image.createGraphics();
g2.setColor(c);
g2.fillRect(0, 0, 10, 10);
return new ImageIcon(image);
}
final JMenuItem addBam = new JMenuItem("Add BAM ...");
menu.add(addBam);
addBam.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
FileSelectionDialog bamFileSelection = new FileSelectionDialog(
null, false, "BamView", "BAM");
List<String> bamFiles = bamFileSelection.getFiles(BAM_SUFFIX);
short count = (short) bamList.size();
bamList.addAll(bamFileSelection.getFiles(BAM_SUFFIX));
for(short i=0; i<bamFiles.size(); i++)
addToViewMenu((short) (i+count));
repaint();
}
});
bamFilesMenu.setFont(addBam.getFont());
final JMenuItem groupBams = new JMenuItem("Group BAMs ...");
final GroupBamFrame groupsFrame = new GroupBamFrame(this, bamFilesMenu);
groupBams.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent arg0)
{
groupsFrame.updateAndDisplay();
}
});
bamFilesMenu.add(groupBams);
bamFilesMenu.addSeparator();
menu.add(bamFilesMenu);
final JMenu analyse = new JMenu("Analyse");
menu.add(analyse);
final JMenuItem readCount = new JMenuItem("Read count of selected features ...");
if(feature_display == null)
readCount.setEnabled(false);
readCount.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
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);
Box yBox = Box.createVerticalBox();
yBox.add(overlap);
yBox.add(spliced);
final ReadCountDialog opts = new ReadCountDialog(new JFrame(),
"Read Count Options", feature_display, yBox);
if(opts.getStatus() == -1)
return;
//JOptionPane.showMessageDialog(null, yBox, "Read Count Option", JOptionPane.INFORMATION_MESSAGE);
new MappedReads(features, (String)combo.getSelectedItem(), samFileReaderHash, bamList,
seqNames, offsetLengths, concatSequences, seqLengths,
samRecordFlagPredicate, samRecordMapQPredicate,
!overlap.isSelected(), spliced.isSelected());
}
});
final JMenuItem rpkm = new JMenuItem("RPKM value of selected features ...");
analyse.add(rpkm);
if(feature_display == null)
rpkm.setEnabled(false);
rpkm.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
final 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);
JCheckBox allRefSeqs = new JCheckBox("Use reads mapped to all reference sequences", false);
Box yBox = Box.createVerticalBox();
yBox.add(overlap);
yBox.add(spliced);
if(seqLengths.size() > 1)
yBox.add(allRefSeqs);
final ReadCountDialog opts = new ReadCountDialog(new JFrame(),
"RPKM Options", feature_display, yBox);
if(opts.getStatus() == -1)
return;
int seqlen = 0;
if(feature_display != null)
seqlen = feature_display.getSequenceLength();
else if(bases != null)
seqlen = bases.getLength();
new MappedReads(features, (String)combo.getSelectedItem(),
samFileReaderHash, bamList, seqNames, offsetLengths, concatSequences,
seqLengths, seqlen, samRecordFlagPredicate, samRecordMapQPredicate,
!overlap.isSelected(), spliced.isSelected(), allRefSeqs.isSelected());
final JMenuItem createFeatures = new JMenuItem("Create features from coverage peaks ...");
analyse.add(createFeatures);
if(feature_display == null)
createFeatures.setEnabled(false);
createFeatures.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if(feature_display == null)
return;
new CreateFeatures(groupsFrame);
for(short i=0; i<bamList.size(); i++)
addToViewMenu(i);
menu.add(new JSeparator());
cbStackView.setFont(viewMenu.getFont());
cbIsizeStackView.setFont(viewMenu.getFont());
cbPairedStackView.setFont(viewMenu.getFont());
cbStrandStackView.setFont(viewMenu.getFont());
cbCoverageView.setFont(viewMenu.getFont());
cbCoverageStrandView.setFont(viewMenu.getFont());
baseQualityColour.setFont(viewMenu.getFont());
colourByCoverageColour.setFont(viewMenu.getFont());
markInsertions.setFont(viewMenu.getFont());
cbIsizeStackView.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
laststart = -1;
logMenuItem.setEnabled(isIsizeStackView());
getJspView().setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
viewMenu.add(cbIsizeStackView);
cbStackView.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
laststart = -1;
if(cbStackView.isSelected())
logMenuItem.setEnabled(false);
getJspView().setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
cbPairedStackView.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
laststart = -1;
if(cbPairedStackView.isSelected())
logMenuItem.setEnabled(false);
getJspView().setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
repaint();
}
});
viewMenu.add(cbPairedStackView);
cbStrandStackView.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
laststart = -1;
if(cbStrandStackView.isSelected())
logMenuItem.setEnabled(false);
getJspView().setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
viewMenu.add(cbStrandStackView);
cbCoverageView.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
laststart = -1;
if(cbCoverageView.isSelected())
{
logMenuItem.setEnabled(true);
coverageView.setPlotHeatMap(false);
coverageView.setPlotByStrand(false);
setViewportBtm();
getJspView().setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
repaint();
}
});
viewMenu.add(cbCoverageView);
cbCoverageStrandView.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
laststart = -1;
if(cbCoverageStrandView.isSelected())
{
logMenuItem.setEnabled(true);
coverageView.setPlotHeatMap(false);
coverageView.setPlotByStrand(true);
setViewportBtm();
getJspView().setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
repaint();
}
});
viewMenu.add(cbCoverageStrandView);
cbCoverageHeatMap.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
laststart = -1;
if(cbCoverageHeatMap.isSelected())
{
logMenuItem.setEnabled(true);
coverageView.setPlotHeatMap(true);
setViewportBtm();
getJspView().setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
}
repaint();
}
});
viewMenu.add(cbCoverageHeatMap);
final JCheckBoxMenuItem checkBoxSNPs = new JCheckBoxMenuItem("SNP marks");
//
JMenu colourMenu = new JMenu("Colour By");
colourMenu.add(colourByCoverageColour);
baseQualityColour.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if(baseQualityColour.isSelected())
{
checkBoxSNPs.setSelected(false);
isSNPs = false;
}
repaint();
}
});
colourMenu.add(baseQualityColour);
menu.add(colourMenu);
//
JCheckBoxMenuItem checkBoxOrientation = new JCheckBoxMenuItem("Orientation");
checkBoxOrientation.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
isOrientation = !isOrientation;
repaint();
}
});
showMenu.add(checkBoxOrientation);
JCheckBoxMenuItem checkBoxSingle = new JCheckBoxMenuItem("Single Reads");
checkBoxSingle.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
repaint();
isSingle = !isSingle;
}
});
showMenu.add(checkBoxSingle);
checkBoxSNPs.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if (isSNPs && bases == null)
{
JOptionPane.showMessageDialog(null,
"No reference sequence supplied to identify SNPs.", "SNPs",
JOptionPane.INFORMATION_MESSAGE);
}
isSNPs = !isSNPs;
if(isSNPs)
baseQualityColour.setSelected(false);
repaint();
}
});
showMenu.add(checkBoxSNPs);
markInsertions.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
repaint();
}
});
showMenu.add(markInsertions);
JCheckBoxMenuItem checkBoxCoverage = new JCheckBoxMenuItem("Coverage");
checkBoxCoverage.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
isCoverage = !isCoverage;
coveragePanel.setVisible(isCoverage);
if( isCoverage &&
!cbCoverageView.isSelected() &&
!cbCoverageStrandView.isSelected() &&
!cbCoverageHeatMap.isSelected())
graphMenu.add(checkBoxCoverage);
JCheckBoxMenuItem checkBoxSNP = new JCheckBoxMenuItem("SNP");
checkBoxSNP.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
isSNPplot = !isSNPplot;
snpPanel.setVisible(isSNPplot);
repaint();
}
});
graphMenu.add(checkBoxSNP);
menu.add(graphMenu);
final JCheckBoxMenuItem checkBoxSync =
new JCheckBoxMenuItem("Asynchronous", asynchronous);
checkBoxSync.addActionListener(new ActionListener()
public void actionPerformed(ActionEvent e)
{
asynchronous = checkBoxSync.isSelected();
}
});
JMenu maxHeightMenu = new JMenu("BamView Height");
final String hgts[] =
{"500", "800", "1000", "1500", "2500", "5000", "50000"};
ButtonGroup bgroup = new ButtonGroup();
for(int i=0; i<hgts.length; i++)
{
final String hgt = hgts[i];
final JCheckBoxMenuItem maxHeightMenuItem = new JCheckBoxMenuItem(hgt);
bgroup.add(maxHeightMenuItem);
maxHeightMenuItem.setSelected(hgts[i].equals(Integer.toString(maxHeight)));
maxHeightMenu.add(maxHeightMenuItem);
maxHeightMenuItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if(maxHeightMenuItem.isSelected())
maxHeight = Integer.parseInt(hgt);
int start = getBaseAtStartOfView();
setDisplay(start, nbasesInView+start, null);
}
});
}
logMenuItem.setEnabled(isIsizeStackView());
logMenuItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
logScale = logMenuItem.isSelected();
repaint();
}
});
JMenuItem filter = new JMenuItem("Filter Reads ...");
menu.add(filter);
filter.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if(filterFrame == null)
filterFrame = new SAMRecordFilter(BamView.this);
else
filterFrame.setVisible(true);
}
});
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
JMenuItem maxReadCoverage = new JMenuItem("Read Coverage Threshold ...");
menu.add(maxReadCoverage);
maxReadCoverage.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
final TextFieldInt maxRead = new TextFieldInt();
maxRead.setValue(MAX_COVERAGE);
int status = JOptionPane.showConfirmDialog(null, maxRead,
"Read Coverage Threshold", JOptionPane.OK_CANCEL_OPTION);
if(status == JOptionPane.OK_OPTION &&
maxRead.getValue() != MAX_COVERAGE)
{
MAX_COVERAGE = maxRead.getValue();
if(MAX_COVERAGE < 1)
MAX_COVERAGE = Integer.MAX_VALUE;
laststart = -1;
repaint();
}
}
});
JMenuItem readList = new JMenuItem("List Reads ...");
menu.add(readList);
readList.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
final JMenuItem bamSplitter = new JMenuItem("Clone window");
bamSplitter.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
BamView bamView = new BamView(new Vector<String>(bamList),
null, nbasesInView, entry_edit,
feature_display, bases, (JPanel) mainPanel.getParent(), null);
bamView.getJspView().getVerticalScrollBar().setValue(
bamView.getJspView().getVerticalScrollBar().getMaximum());
getJspView().getVerticalScrollBar().setValue(
bamView.getJspView().getVerticalScrollBar().getMaximum());
int start = getBaseAtStartOfView();
setDisplay(start, nbasesInView+start, null);
if(feature_display != null)
{
feature_display.addDisplayAdjustmentListener(bamView);
feature_display.getSelection().addSelectionChangeListener(bamView);
}
}
});
menu.add(new JSeparator());
menu.add(bamSplitter);
//
JMenu coverageMenu = new JMenu("Coverage Options");
coverageView.init(this, 0.f, 0, 0);
coverageView.createMenus(coverageMenu);
viewMenu.add(new JSeparator());
viewMenu.add(coverageMenu);
private JComponent bamTopPanel(final JFrame frame)
{
final JComponent topPanel;
{
topPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
if(feature_display != null)
this.selection = feature_display.getSelection();
}
else
{
topPanel = new JMenuBar();
frame.setJMenuBar((JMenuBar)topPanel);
JMenu fileMenu = new JMenu("File");
topPanel.add(fileMenu);
JMenuItem readBam = new JMenuItem("Open new BamView ...");
fileMenu.add(readBam);
readBam.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
BamView.main(s);
}
});
JMenuItem close = new JMenuItem("Close");
fileMenu.add(close);
close.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
BamView.this.setVisible(false);
Component comp = BamView.this;
while( !(comp instanceof JFrame) )
comp = comp.getParent();
((JFrame)comp).dispose();
}
});
JMenuItem exit = new JMenuItem("Exit");
fileMenu.add(new JSeparator());
fileMenu.add(exit);
exit.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
int status = JOptionPane.showConfirmDialog(BamView.this,
"Exit BamView?", "Exit",
JOptionPane.OK_CANCEL_OPTION);
if(status != JOptionPane.OK_OPTION)
return;
System.exit(0);
}
});
addKeyListener(new KeyAdapter()
{
public void keyPressed(final KeyEvent event)
{
switch (event.getKeyCode())
{
case KeyEvent.VK_UP:
setZoomLevel((int) (BamView.this.nbasesInView * 1.1));
break;
case KeyEvent.VK_DOWN:
if (showBaseAlignment)
break;
setZoomLevel((int) (BamView.this.nbasesInView * .9));
break;
default:
break;
}
}
});
}
if(seqNames.size() > 1)
{
int len = 0;
for(int i=0; i<seqNames.size(); i++)
len += seqLengths.get(seqNames.get(i));
if(feature_display != null &&
len == feature_display.getSequenceLength())
concatSequences = true;
else if(bases != null &&
len == bases.getLength() )
concatSequences = true;
}
// auto hide top panel
final JCheckBox buttonAutoHide = new JCheckBox("Hide", (frame == null));
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
buttonAutoHide.setToolTipText("Auto-Hide");
final MouseMotionListener mouseMotionListener = new MouseMotionListener()
{
public void mouseDragged(MouseEvent event)
{
handleCanvasMouseDrag(event);
}
public void mouseMoved(MouseEvent e)
{
lastMousePoint = e.getPoint();
int thisHgt = HEIGHT;
if (thisHgt < 5)
thisHgt = 15;
int y = (int) (e.getY() - jspView.getViewport().getViewRect().getY());
if (y < thisHgt)
{
topPanel.setVisible(true);
}
else
{
if (buttonAutoHide.isSelected())
topPanel.setVisible(false);
}
mainPanel.repaint();
mainPanel.revalidate();
}
};
addMouseMotionListener(mouseMotionListener);
combo = new SequenceComboBox(seqNames){
private static final long serialVersionUID = 1L;
public void update(IndexReferenceEvent event)
{
laststart = -1;
if(feature_display != null)
setZoomLevel(feature_display.getMaxVisibleBases());
else
setZoomLevel(BamView.this.nbasesInView);
}
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
topPanel.add(combo);
if(feature_display == null)
{
final JTextField baseText = new JTextField(8);
JButton goTo = new JButton("GoTo:");
goTo.setToolTipText("Go to base position");
goTo.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try
{
int basePosition = Integer.parseInt(baseText.getText());
scrollBar.setValue(basePosition);
}
catch (NumberFormatException nfe)
{
JOptionPane.showMessageDialog(BamView.this,
"Expecting a base number!", "Number Format",
JOptionPane.WARNING_MESSAGE);
}
}
});
topPanel.add(goTo);
topPanel.add(baseText);
JButton zoomIn = new JButton("-");
zoomIn.setToolTipText("Zoom out (up arrow)");
Insets ins = new Insets(1,1,1,1);
zoomIn.setMargin(ins);
zoomIn.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
setZoomLevel((int) (BamView.this.nbasesInView * 1.1));
}
});
topPanel.add(zoomIn);
JButton zoomOut = new JButton("+");
zoomOut.setToolTipText("Zoom in (down arrow)");
zoomOut.setMargin(ins);
zoomOut.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if (showBaseAlignment)
return;
setZoomLevel((int) (BamView.this.nbasesInView * .9));
}
});
topPanel.add(zoomOut);
}
topPanel.add(buttonAutoHide);
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
if(feature_display != null)
{
JButton close = new JButton("Close");
topPanel.add(close);
close.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
final JPanel containerPanel = (JPanel) mainPanel.getParent();
feature_display.removeDisplayAdjustmentListener(BamView.this);
feature_display.getSelection().removeSelectionChangeListener(BamView.this);
containerPanel.remove(mainPanel);
if(containerPanel.getComponentCount() > 0)
containerPanel.revalidate();
else
{
if(entry_edit != null)
entry_edit.setNGDivider();
else
containerPanel.setVisible(false);
}
}
});
}
public void setVisible(boolean visible)
{
super.setVisible(visible);
mainPanel.setVisible(visible);
private void setViewportMidPoint()
{
Point p = jspView.getViewport().getLocation();
p.y = (getHeight() - jspView.getViewport().getViewRect().height)/2;
jspView.getViewport().setViewPosition(p);
}
private void setViewportBtm()
{
jspView.getVerticalScrollBar().setValue(
jspView.getVerticalScrollBar().getMaximum());
}
if(feature_display != null)
return feature_display.getForwardBaseAtLeftEdge();
else
return scrollBar.getValue();
}
/**
* Set the panel size based on the number of bases visible
* and repaint.
* @param nbasesInView
*/
if(isBaseAlignmentView(pixPerBase))
this.nbasesInView = (int)(mainPanel.getWidth()/pixPerBase);
if(ruler == null)
ruler = new Ruler();
jspView.setColumnHeaderView(ruler);
showBaseAlignment = true;
markInsertions.setEnabled(true);
if(isCoverageView(pixPerBase) && nbasesInView >= MAX_BASES)
{
cbLastSelected = getSelectedCheckBoxMenuItem();
cbCoverageView.setSelected(true);
coverageView.setPlotByStrand(false);
else if(isCoverageView(pixPerBase) && nbasesInView < MAX_BASES && cbLastSelected != null)
{
cbLastSelected.setSelected(true);
cbLastSelected = null;
}
else
setViewportMidPoint();
markInsertions.setEnabled(false);
{
scrollBar.setValues(startValue, nbasesInView, 1,
getMaxBasesInPanel(getSequenceLength()));
scrollBar.setUnitIncrement(nbasesInView/20);
scrollBar.setBlockIncrement(nbasesInView);
}
* Set the start and end base positions to display.
* @param start
* @param end
* @param event
public void setDisplay(int start,
int end,
DisplayAdjustmentEvent event)
this.startBase = start;
this.endBase = end;
else
{
if(feature_display == null)
pixPerBase = 1000.f/(float)(end-start+1);
else
pixPerBase = feature_display.getWidth()/(float)(end-start+1);
}
if(event == null)
{
this.startBase = -1;
this.endBase = -1;
}
/**
* Return an Artemis entry from a file
* @param entryFileName
* @param entryGroup
* @return
* @throws NoSequenceException
*/
private Entry getEntry(final String entryFileName, final EntryGroup entryGroup)
throws NoSequenceException
{
final Document entry_document = DocumentFactory.makeDocument(entryFileName);
final EntryInformation artemis_entry_information =
Options.getArtemisEntryInformation();
//System.out.println(entryFileName);
final uk.ac.sanger.artemis.io.Entry new_embl_entry =
EntryFileDialog.getEntryFromFile(null, entry_document,
artemis_entry_information,
false);
if(new_embl_entry == null) // the read failed
return null;
Entry entry = null;
try
{
if(entryGroup.getSequenceEntry() != null)
bases = entryGroup.getSequenceEntry().getBases();
else
entry = new Entry(bases,new_embl_entry);
entryGroup.add(entry);
}
catch(OutOfRangeException e)
{
new MessageDialog(null, "read failed: one of the features in " +
entryFileName + " has an out of range " +
"location: " + e.getMessage());
}
return entry;
}
private boolean isShowScale()
{
return (feature_display == null ? true : false);
}
public JScrollPane getJspView()
{
return jspView;
}
/**
* Handle a mouse drag event on the drawing canvas.
**/
if(event.getButton() == MouseEvent.BUTTON3 || bases == null)
tjc
committed
highlightSAMRecord = null;
if(event.getClickCount() > 1)
{
getSelection().clear();
repaint();
return;
}
highlightRange(event,
MouseEvent.BUTTON1_DOWN_MASK & MouseEvent.BUTTON2_DOWN_MASK);
}
/**
*
* @param event
* @param onmask
*/
protected void highlightRange(MouseEvent event, int onmask)
int start = (int) ( ( (event.getPoint().getX())/pixPerBase) + getBaseAtStartOfView() );
if(start < 1)
start = 1;
if(start > seqLength)
start = seqLength;
if (dragStart < 0 && (event.getModifiersEx() & onmask) == onmask)
dragStart = start;
else if((event.getModifiersEx() & onmask) != onmask)
dragStart = -1;
if(dragStart < 0)
drag_range = new MarkerRange (bases.getForwardStrand(), start, start);
else
drag_range = new MarkerRange (bases.getForwardStrand(), dragStart, start);
getSelection().setMarkerRange(drag_range);
repaint();
/**
* Get the colour for the given read given to it by the coverage plot.
* @param samRecord
* @return
*/
private Color getColourByCoverageColour(BamViewRecord samRecord)
short fileIndex = 0;
fileIndex = samRecord.bamIndex;
return getColourByCoverageColour(fileIndex);
}
private Color getColourByCoverageColour(final short fileIndex)
{
LineAttributes lines[] = CoveragePanel.getLineAttributes(bamList.size());
return lines[fileIndex].getLineColour();
}
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
protected int getMaxBases()
{
return MAX_BASES;
}
protected void setMaxBases(int max)
{
MAX_BASES = max;
}
private boolean isStackView()
{
return cbStackView.isSelected();
}
private boolean isPairedStackView()
{
return cbPairedStackView.isSelected();
}
private boolean isStrandStackView()
{
return cbStrandStackView.isSelected();
}
private boolean isCoverageView(float pixPerBase)
{
if(isBaseAlignmentView(pixPerBase))
return false;
return cbCoverageView.isSelected() || cbCoverageStrandView.isSelected() || cbCoverageHeatMap.isSelected();
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
}
private boolean isIsizeStackView()
{
return cbIsizeStackView.isSelected();
}
private boolean isBaseAlignmentView(float pixPerBase)
{
if(pixPerBase*1.08f >= ALIGNMENT_PIX_PER_BASE)
return true;
return false;
}
private JCheckBoxMenuItem getSelectedCheckBoxMenuItem()
{
if(isStackView())
return cbStackView;
if(isPairedStackView())
return cbPairedStackView;
if(isStrandStackView())
return cbStrandStackView;
if(isIsizeStackView())
return cbIsizeStackView;
if(cbCoverageView.isSelected())
return cbCoverageView;
if(cbCoverageHeatMap.isSelected())
return cbCoverageHeatMap;
protected List<BamViewRecord> getReadsInView()
protected int getBasesInView()
{
return nbasesInView;
}
protected void setHighlightSAMRecord(BamViewRecord highlightSAMRecord)
{
this.highlightSAMRecord = highlightSAMRecord;
}
protected BamViewRecord getHighlightSAMRecord()
protected FeatureDisplay getFeatureDisplay()
{
return feature_display;
}
/**
* @return the combo
*/
public SequenceComboBox getCombo()
{
return combo;
}
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
private String getVersion()
{
final ClassLoader cl = this.getClass().getClassLoader();
try
{
String line;
InputStream in = cl.getResourceAsStream("etc/versions");
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
while((line = reader.readLine()) != null)
{
if(line.startsWith("BamView"))
return line.substring( "BamView".length() ).trim();
}
reader.close();
in.close();
}
catch (Exception ex)
{
}
return null;
}
public void displayAdjustmentValueChanged(final DisplayAdjustmentEvent event)
if(event.getType() == DisplayAdjustmentEvent.REV_COMP_EVENT &&
event.isRevCompDisplay())
JOptionPane.showMessageDialog(this,
"Flipping the display is not supported by BamView.", "Warning",
JOptionPane.WARNING_MESSAGE);
if(!asynchronous)
{
// if not asynchronous
displayAdjustmentWork(event);
return;
}
public Object construct()
{
try
{
Thread.sleep(500);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
if(event.getStart() != ((FeatureDisplay)event.getSource()).getForwardBaseAtLeftEdge())
{
waitingFrame.showWaiting("waiting...", mainPanel);
waitingFrame.setVisible(false);
return null;
}
};
worker.start();
/**
* Carry out the display agjustment event action.
* @param event
*/
private void displayAdjustmentWork(final DisplayAdjustmentEvent event)
{
if(event.getType() == DisplayAdjustmentEvent.SCALE_ADJUST_EVENT)
{
laststart = -1;
BamView.this.startBase = event.getStart();
BamView.this.endBase = event.getEnd();
int width = feature_display.getMaxVisibleBases();
setZoomLevel(width);
repaint();
}
else
{
setDisplay(event.getStart(),
event.getStart()+feature_display.getMaxVisibleBases(), event);
repaint();
}
}
public void selectionChanged(SelectionChangeEvent event)
{
repaint();
protected int start;
protected int end;
protected String refSeq;
setPreferredSize(new Dimension(mainPanel.getWidth(), 26));
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
drawBaseScale(g2, start, end, 12);
}
private void drawBaseScale(Graphics2D g2, int start, int end, int ypos)
{
int startMark = (((int)(start/10))*10)+1;
if(end > getSequenceLength())
end = getSequenceLength();
for(int i=startMark; i<end; i+=20)
for(int i=startMark; i<end; i+=10)
{
int xpos = (i-start)*ALIGNMENT_PIX_PER_BASE;
xpos+=(ALIGNMENT_PIX_PER_BASE/2);
g2.drawLine(xpos, ypos+1, xpos, ypos+5);
}
if(refSeq != null)
{
ypos+=15;
g2.setColor(LIGHT_GREY);
g2.fillRect(0, ypos-11, getWidth(), 11);
g2.translate(0, 16);
drawSelectionRange(g2, ALIGNMENT_PIX_PER_BASE, start, end, Color.yellow);
g2.translate(0, -16);
g2.setColor(Color.black);
g2.drawString(refSeq, 0, ypos-2);
}
/**
* Popup menu listener
*/
class PopupListener extends MouseAdapter
{
JMenuItem gotoMateMenuItem;
tjc
committed
JMenuItem showDetails;
public void mouseClicked(MouseEvent e)
{
if(e.isPopupTrigger() ||
e.getButton() == MouseEvent.BUTTON3)
return;
BamView.this.requestFocus();
if(e.getClickCount() > 1)
getSelection().clear();
else if(e.getButton() == MouseEvent.BUTTON1)
highlightSAMRecord = mouseOverSAMRecord;
else
highlightRange(e, MouseEvent.BUTTON2_DOWN_MASK);
repaint();
}
public void mousePressed(MouseEvent e)
{
maybeShowPopup(e);
}
public void mouseReleased(MouseEvent e)
{
maybeShowPopup(e);
}
private void maybeShowPopup(MouseEvent e)
{
if(e.isPopupTrigger())
if(gotoMateMenuItem != null)
popup.remove(gotoMateMenuItem);
tjc
committed
if(showDetails != null)
popup.remove(showDetails);
if( mouseOverSAMRecord != null &&
mouseOverSAMRecord.sam.getReadPairedFlag() &&
!mouseOverSAMRecord.sam.getMateUnmappedFlag() )
{
final BamViewRecord thisSAMRecord = mouseOverSAMRecord;
gotoMateMenuItem = new JMenuItem("Go to mate of : "+
thisSAMRecord.sam.getReadName());
gotoMateMenuItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
String name = thisSAMRecord.sam.getMateReferenceName();
if(name.equals("="))
name = thisSAMRecord.sam.getReferenceName();
int offset = getSequenceOffset(name);
if(feature_display != null)
feature_display.makeBaseVisible(
thisSAMRecord.sam.getMateAlignmentStart()+offset);
else
scrollBar.setValue(
thisSAMRecord.sam.getMateAlignmentStart()+offset-
(nbasesInView/2));
highlightSAMRecord = thisSAMRecord;
}
});
popup.add(gotoMateMenuItem);
tjc
committed
}
if( mouseOverSAMRecord != null)
{
final BamViewRecord thisSAMRecord = mouseOverSAMRecord;
tjc
committed
showDetails = new JMenuItem("Show details of : "+
thisSAMRecord.sam.getReadName());
tjc
committed
showDetails.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
openFileViewer(thisSAMRecord.sam, getMate(thisSAMRecord), bamList);
tjc
committed
});
popup.add(showDetails);
}
popup.show(e.getComponent(),
e.getX(), e.getY());
protected static void openFileViewer(SAMRecord readRecord, SAMRecord mateRecord, List<String> bamList)
{
FileViewer viewDetail = new FileViewer(readRecord.getReadName(), true, false, false);
appendToDetailView(readRecord, mateRecord, viewDetail, bamList);
private static void appendToDetailView(final SAMRecord thisSAMRecord,
final SAMRecord thisSAMRecordMate,
final FileViewer viewDetail,
final List<String> bamList)
tjc
committed
{
if(bamList.size() > 1 && thisSAMRecord.getAttribute("FL") != null)
{
int bamIndex = (Integer)thisSAMRecord.getAttribute("FL");
if(bamIndex < bamList.size())
viewDetail.appendString("File "+bamList.get(bamIndex)+"\n\n", Level.INFO);
}
tjc
committed
viewDetail.appendString("Read Name "+thisSAMRecord.getReadName()+"\n", Level.INFO);
viewDetail.appendString("Coordinates "+thisSAMRecord.getAlignmentStart()+".."+
thisSAMRecord.getAlignmentEnd()+"\n", Level.DEBUG);
viewDetail.appendString("Length "+thisSAMRecord.getReadLength()+"\n", Level.DEBUG);
viewDetail.appendString("Reference Name "+thisSAMRecord.getReferenceName()+"\n", Level.DEBUG);
viewDetail.appendString("Inferred Size "+thisSAMRecord.getInferredInsertSize()+"\n", Level.DEBUG);
viewDetail.appendString("Mapping Quality "+thisSAMRecord.getMappingQuality()+"\n", Level.DEBUG);
viewDetail.appendString("Cigar String "+thisSAMRecord.getCigarString()+"\n", Level.DEBUG);
viewDetail.appendString("Strand "+
(thisSAMRecord.getReadNegativeStrandFlag() ? "-\n\n" : "+\n\n"), Level.DEBUG);
if(thisSAMRecord.getReadPairedFlag() && !thisSAMRecord.getMateUnmappedFlag())
{
if(thisSAMRecordMate != null)
{
viewDetail.appendString("Mate Coordinates "+thisSAMRecordMate.getAlignmentStart()+".."+
thisSAMRecordMate.getAlignmentEnd()+"\n", Level.DEBUG);
viewDetail.appendString("Mate Length "+thisSAMRecordMate.getReadLength()+"\n", Level.DEBUG);
viewDetail.appendString("Mate Reference Name "+thisSAMRecordMate.getReferenceName()+"\n", Level.DEBUG);
viewDetail.appendString("Mate Inferred Size "+thisSAMRecordMate.getInferredInsertSize()+"\n", Level.DEBUG);
viewDetail.appendString("Mate Mapping Quality "+thisSAMRecordMate.getMappingQuality()+"\n", Level.DEBUG);
viewDetail.appendString("Mate Cigar String "+thisSAMRecordMate.getCigarString()+"\n", Level.DEBUG);
}
else
{
viewDetail.appendString("Mate Start Coordinate "+thisSAMRecord.getMateAlignmentStart()+"\n", Level.DEBUG);
viewDetail.appendString("Mate Reference Name "+thisSAMRecord.getMateReferenceName()+"\n", Level.DEBUG);
}
viewDetail.appendString("Mate Strand "+
(thisSAMRecord.getMateNegativeStrandFlag() ? "-" : "+"), Level.DEBUG);
tjc
committed
}
else
{
viewDetail.appendString("Mate Unmapped ", Level.DEBUG);
tjc
committed
}
viewDetail.appendString("\n\nFlags:", Level.INFO);
viewDetail.appendString("\nDuplicate Read "+
(thisSAMRecord.getDuplicateReadFlag() ? "yes" : "no"), Level.DEBUG);
viewDetail.appendString("\nRead Paired "+
(thisSAMRecord.getReadPairedFlag() ? "yes" : "no"), Level.DEBUG);
if(thisSAMRecord.getReadPairedFlag())
{
viewDetail.appendString("\nFirst of Pair "+
tjc
committed
(thisSAMRecord.getFirstOfPairFlag() ? "yes" : "no"), Level.DEBUG);
tjc
committed
(thisSAMRecord.getMateUnmappedFlag() ? "yes" : "no"), Level.DEBUG);
tjc
committed
(thisSAMRecord.getProperPairFlag() ? "yes" : "no"), Level.DEBUG);
tjc
committed
viewDetail.appendString("\nRead Fails Vendor\nQuality Check "+
(thisSAMRecord.getReadFailsVendorQualityCheckFlag() ? "yes" : "no"), Level.DEBUG);
viewDetail.appendString("\nRead Unmapped "+
(thisSAMRecord.getReadUnmappedFlag() ? "yes" : "no"), Level.DEBUG);
if(thisSAMRecord.getReadPairedFlag())
viewDetail.appendString("\nSecond Of Pair "+
tjc
committed
(thisSAMRecord.getSecondOfPairFlag() ? "yes" : "no"), Level.DEBUG);
viewDetail.appendString("\n\nRead Bases:\n", Level.INFO);
// wrap the read bases
String seq = new String(thisSAMRecord.getReadBases());
int MAX_SEQ_LINE_LENGTH = 100;
for(int i=0; i<=seq.length(); i+=MAX_SEQ_LINE_LENGTH)
{
int iend = i+MAX_SEQ_LINE_LENGTH;
if(iend > seq.length())
iend = seq.length();
viewDetail.appendString(seq.substring(i, iend)+"\n", Level.DEBUG);
}
tjc
committed
}
/**
* Query for the mate of a read
* @param mate
* @return
*/
protected SAMRecord getMate(BamViewRecord thisSAMRecord)
if(!thisSAMRecord.sam.getReadPairedFlag() || // read is not paired in sequencing
thisSAMRecord.sam.getMateUnmappedFlag())
SAMRecord mate = null;
try
{
short fileIndex = 0;
if(bamList.size()>1 && thisSAMRecord.bamIndex > 0)
fileIndex = thisSAMRecord.bamIndex;
String bam = bamList.get(fileIndex);
final SAMFileReader inputSam = getSAMFileReader(bam);
mate = inputSam.queryMate(thisSAMRecord.sam);
}
catch (Exception e)
{
e.printStackTrace();
}
return mate;
}
protected SAMRecordPredicate getSamRecordFlagPredicate()
{
return samRecordFlagPredicate;
}
protected void setSamRecordFlagPredicate(
{
laststart = -1;
lastend = -1;
this.samRecordFlagPredicate = samRecordFlagPredicate;
}
tjc
committed
protected SAMRecordMapQPredicate getSamRecordMapQPredicate()
{
return samRecordMapQPredicate;
}
protected void setSamRecordMapQPredicate(
SAMRecordMapQPredicate samRecordMapQPredicate)
{
laststart = -1;
lastend = -1;
this.samRecordMapQPredicate = samRecordMapQPredicate;
}
/**
* @return the concatSequences
*/
protected boolean isConcatSequences()
{
return concatSequences;
}
class PairedRead
{
BamViewRecord sam1;
BamViewRecord sam2;
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
}
class CreateFeatures
{
CreateFeatures(final GroupBamFrame groupsFrame)
{
final TextFieldInt threshold = new TextFieldInt();
final TextFieldInt minSize = new TextFieldInt();
final TextFieldInt minBams = new TextFieldInt();
threshold.setValue(6);
minSize.setValue(6);
minBams.setValue( (groupsFrame.getNumberOfGroups() == 1 ?
bamList.size() : groupsFrame.getMaximumBamsInGroup()) );
final JPanel gridPanel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.WEST;
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 0;
gridPanel.add(new JLabel("Minimum number of reads:"), c);
c.gridy++;
gridPanel.add(threshold, c);
c.gridy++;
gridPanel.add(new JSeparator(), c);
c.gridy++;
gridPanel.add(new JLabel("Minimum number of BAMs for reads to be present in:"), c);
c.gridy++;
gridPanel.add(minBams, c);
JRadioButton useAllBams = new JRadioButton("out of all BAMs", (groupsFrame.getNumberOfGroups() == 1));
JRadioButton useGroup = new JRadioButton("within a group", (groupsFrame.getNumberOfGroups() != 1));
if(groupsFrame.getNumberOfGroups() == 1)
useGroup.setEnabled(false);
final ButtonGroup group = new ButtonGroup();
group.add(useAllBams);
group.add(useGroup);
final Box xBox = Box.createHorizontalBox();
xBox.add(useAllBams);
xBox.add(useGroup);
xBox.add(Box.createHorizontalGlue());
c.gridy++;
gridPanel.add(xBox, c);
c.gridy++;
gridPanel.add(new JSeparator(), c);
c.gridy++;
gridPanel.add(new JLabel("Minimum feature size:"), c);
c.gridy++;
gridPanel.add(minSize, c);
final JCheckBox cbOpposite = new JCheckBox("Assume reads on opposite strand", false);
cbOpposite.setToolTipText("for cDNA experiments when the reads are on the opposite strand");
c.gridy++;
gridPanel.add(cbOpposite, c);
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
int status =
JOptionPane.showConfirmDialog(feature_display, gridPanel,
"Options", JOptionPane.OK_CANCEL_OPTION);
if(status == JOptionPane.CANCEL_OPTION)
return;
if(!useGroup.isSelected() && minBams.getValue() > bamList.size())
{
status =
JOptionPane.showConfirmDialog(feature_display,
"The minimum number of BAMs setting can not be\n"+
"greater than the total number of BAM files.\n"+
"Set this to the number of BAMs (i.e. "+bamList.size()+").",
"Options", JOptionPane.OK_CANCEL_OPTION);
if(status == JOptionPane.CANCEL_OPTION)
return;
minBams.setValue(bamList.size());
}
else if(useGroup.isSelected() && minBams.getValue() > groupsFrame.getMaximumBamsInGroup())
{
status =
JOptionPane.showConfirmDialog(feature_display,
"Minimum number of BAMs setting can not be greater than\n"+
"the total number of BAM files found in any of the groups.\n"+
"Set this to the greatest number of BAM files in any\n"+
"group (i.e. "+groupsFrame.getMaximumBamsInGroup()+").",
"Options", JOptionPane.OK_CANCEL_OPTION);
if(status == JOptionPane.CANCEL_OPTION)
return;
minBams.setValue(groupsFrame.getMaximumBamsInGroup());
}
new MappedReads((String)combo.getSelectedItem(),BamView.this, samFileReaderHash,
seqNames, offsetLengths, concatSequences, seqLengths,
(useGroup.isSelected() ? groupsFrame : null), threshold.getValue(),
minSize.getValue(), minBams.getValue(), cbOpposite.isSelected(), true);
}
}
if(args.length == 0 && BamFrame.isMac())
{
try
{
Thread.sleep(1000);
}
catch (InterruptedException e1) {}
if(args.length == 0 || args[0].equals("NEW-BAMVIEW"))
System.setProperty("default_directory", System.getProperty("user.dir"));
FileSelectionDialog fileSelection = new FileSelectionDialog(
null, true, "BamView", "BAM");
reference = fileSelection.getReferenceFile();
if(reference == null || reference.equals(""))
reference = null;
if(args.length > 0 && args[0].equals("NEW-BAMVIEW"))
return;
System.err.println("No files found.");
else if(!args[0].startsWith("-"))
{
for(int i=0; i< args.length; i++)
bam.add(args[i]);
}
String chr = null;
String vw = null;
boolean orientation = false;
boolean covPlot = false;
boolean snpPlot = false;
int base = 0;
{
while(i < args.length-1 && !args[++i].startsWith("-"))
{
String filename = args[i];
if(FileSelectionDialog.isListOfFiles(filename))
bam.addAll(FileSelectionDialog.getListOfFiles(filename));
else
bam.add(filename);
}
nbasesInView = Integer.parseInt(args[++i]);
else if(args[i].equals("-s"))
System.setProperty("samtoolDir", args[++i]);
else if(args[i].equals("-c"))
chr = args[++i].trim();
else if(args[i].equals("-b"))
base = Integer.parseInt(args[++i].trim());
else if(args[i].equals("-v"))
vw = args[++i].trim();
else if(args[i].equals("-o"))
orientation = true;
else if(args[i].equals("-pc"))
covPlot = true;
else if(args[i].equals("-ps"))
snpPlot = true;
else if(args[i].startsWith("-h"))
{
System.out.println("-h\t show help");
System.out.println("-a\t BAM/SAM file to display");
System.out.println("-r\t reference file (optional)");
System.out.println("-n\t number of bases to display in the view (optional)");
System.out.println("-c\t chromosome name (optional)");
System.out.println("-v\t view (optional - IS (inferred size), S (stack, default), PS (paired stack), ST (strand), C (coverage))");
System.out.println("-b\t base position (optional)");
System.out.println("-o\t show orientation (optional)");
System.out.println("-pc\t plot coverage (optional)");
System.out.println("-ps\t plot SNP (optional and only with -r)");
final BamView view = new BamView(bam, reference, nbasesInView, null, null,
(JPanel)frame.getContentPane(), frame);
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
if(chr != null)
view.combo.setSelectedItem(chr);
if(vw != null)
{
if(vw.equalsIgnoreCase("IS"))
view.cbIsizeStackView.setSelected(true);
if(vw.equalsIgnoreCase("PS"))
view.cbPairedStackView.setSelected(true);
if(vw.equalsIgnoreCase("ST"))
view.cbStrandStackView.setSelected(true);
if(vw.equalsIgnoreCase("C"))
view.cbCoverageView.setSelected(true);
}
if(base > 0)
view.scrollBar.setValue(base);
if(orientation)
view.isOrientation = true;
if(covPlot)
{
view.isCoverage = true;
view.coveragePanel.setVisible(true);
}
if(snpPlot)
{
view.isSNPplot = true;
view.snpPanel.setVisible(true);
}
// translucent
//frame.getRootPane().putClientProperty("Window.alpha", new Float(0.9f));
/*frame.addWindowFocusListener(new WindowFocusListener()
{
public void windowGainedFocus(WindowEvent e)
{
view.requestFocus();
}
public void windowLostFocus(WindowEvent e){}
view.jspView.getVerticalScrollBar().setValue(
view.jspView.getVerticalScrollBar().getMaximum());