From 4cb2a65dd173394e043f2f5886f814866efcb771 Mon Sep 17 00:00:00 2001 From: tjc <tjc@ee4ac58c-ac51-4696-9907-e4b3aa274f04> Date: Fri, 27 Aug 2010 08:19:40 +0000 Subject: [PATCH] changes for combining reference contigs in a vcf git-svn-id: svn+ssh://svn.internal.sanger.ac.uk/repos/svn/pathsoft/artemis/trunk@14676 ee4ac58c-ac51-4696-9907-e4b3aa274f04 --- .../artemis/components/variant/VCFview.java | 404 ++++++++++++------ 1 file changed, 282 insertions(+), 122 deletions(-) diff --git a/uk/ac/sanger/artemis/components/variant/VCFview.java b/uk/ac/sanger/artemis/components/variant/VCFview.java index 008e73e5a..bfce3e16c 100644 --- a/uk/ac/sanger/artemis/components/variant/VCFview.java +++ b/uk/ac/sanger/artemis/components/variant/VCFview.java @@ -45,12 +45,14 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; +import java.util.Hashtable; import java.util.List; import java.util.Vector; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.JButton; +import javax.swing.JCheckBox; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComboBox; import javax.swing.JComponent; @@ -74,6 +76,7 @@ import uk.ac.sanger.artemis.Entry; import uk.ac.sanger.artemis.EntryGroup; import uk.ac.sanger.artemis.Feature; import uk.ac.sanger.artemis.FeatureKeyPredicate; +import uk.ac.sanger.artemis.FeaturePredicate; import uk.ac.sanger.artemis.FeatureVector; import uk.ac.sanger.artemis.Options; import uk.ac.sanger.artemis.Selection; @@ -143,6 +146,10 @@ public class VCFview extends JPanel private boolean showNonOverlappings = true; private float MIN_QUALITY = -10; + Hashtable<String, Integer> offsetLengths = null; + private boolean concatSequences = false; + private Point lastMousePoint; + private Pattern multiAllelePattern = Pattern.compile("^[AGCT]+,[AGCT,]+$"); private static Pattern tabPattern = Pattern.compile("\t"); @@ -214,23 +221,10 @@ public class VCFview extends JPanel // // - final MouseMotionListener mouseMotionListener = new MouseMotionListener() - { - public void mouseDragged(MouseEvent event) - { - handleCanvasMouseDrag(event); - } - - public void mouseMoved(MouseEvent e) - { - findVariantAtPoint(e.getPoint()); - } - }; - addMouseMotionListener(mouseMotionListener); addMouseListener(new PopupListener()); // - createMenus(frame); + createMenus(frame, jspView); setDisplay(); if(feature_display == null) @@ -248,85 +242,90 @@ public class VCFview extends JPanel } } - private void createMenus(JFrame frame) + private void createMenus(JFrame frame, final JScrollPane jspView) { - JComponent topPanel; + final JComponent topPanel; if(feature_display != null) topPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0)); else { topPanel = new JMenuBar(); frame.setJMenuBar((JMenuBar)topPanel); - } + + JMenu fileMenu = new JMenu("File"); + topPanel.add(fileMenu); - JMenu fileMenu = new JMenu("File"); - topPanel.add(fileMenu); - - JMenuItem printImage = new JMenuItem("Save As Image Files (png/jpeg)..."); - printImage.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) + JMenuItem printImage = new JMenuItem("Save As Image Files (png/jpeg)..."); + printImage.addActionListener(new ActionListener() { - PrintVCFview part = new PrintVCFview(VCFview.this); - part.print(); - } - }); - fileMenu.add(printImage); - - JMenuItem printPS = new JMenuItem("Print..."); - printPS.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) + public void actionPerformed(ActionEvent e) + { + PrintVCFview part = new PrintVCFview(VCFview.this); + part.print(); + } + }); + fileMenu.add(printImage); + + JMenuItem printPS = new JMenuItem("Print..."); + printPS.addActionListener(new ActionListener() { - PrintVCFview part = new PrintVCFview(VCFview.this); - part.validate(); - part.doPrintActions(); - } - }); - fileMenu.add(printPS); - + public void actionPerformed(ActionEvent e) + { + PrintVCFview part = new PrintVCFview(VCFview.this); + part.validate(); + part.doPrintActions(); + } + }); + fileMenu.add(printPS); + - JMenuItem close = new JMenuItem("Close"); - fileMenu.add(close); - close.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) + JMenuItem close = new JMenuItem("Close"); + fileMenu.add(close); + close.addActionListener(new ActionListener() { - VCFview.this.setVisible(false); - Component comp = VCFview.this; - - while( !(comp instanceof JFrame) ) - comp = comp.getParent(); - ((JFrame)comp).dispose(); - } - }); - - JButton zoomIn = new JButton("-"); - Insets ins = new Insets(1,1,1,1); - zoomIn.setMargin(ins); - zoomIn.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) + public void actionPerformed(ActionEvent e) + { + VCFview.this.setVisible(false); + Component comp = VCFview.this; + + while( !(comp instanceof JFrame) ) + comp = comp.getParent(); + ((JFrame)comp).dispose(); + } + }); + + JButton zoomIn = new JButton("-"); + Insets ins = new Insets(1,1,1,1); + zoomIn.setMargin(ins); + zoomIn.addActionListener(new ActionListener() { - setZoomLevel((int) (VCFview.this.nbasesInView * 1.1)); - } - }); - topPanel.add(zoomIn); + public void actionPerformed(ActionEvent e) + { + setZoomLevel((int) (VCFview.this.nbasesInView * 1.1)); + } + }); + topPanel.add(zoomIn); - JButton zoomOut = new JButton("+"); - zoomOut.setMargin(ins); - zoomOut.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) + JButton zoomOut = new JButton("+"); + zoomOut.setMargin(ins); + zoomOut.addActionListener(new ActionListener() { - setZoomLevel((int) (VCFview.this.nbasesInView * .9)); - } - }); - topPanel.add(zoomOut); + public void actionPerformed(ActionEvent e) + { + setZoomLevel((int) (VCFview.this.nbasesInView * .9)); + } + }); + topPanel.add(zoomOut); + } final JComboBox combo = new JComboBox(tr[0].getmSeq()); + + if(tr[0].getmSeq().length > 1) + combo.addItem("Combine All"); + if(chr == null) this.chr = tr[0].getmSeq()[0]; + combo.setSelectedItem(this.chr); combo.setEditable(false); combo.setMaximumRowCount(20); @@ -335,11 +334,52 @@ public class VCFview extends JPanel { public void itemStateChanged(ItemEvent e) { - VCFview.this.chr = (String) combo.getSelectedItem(); + if(combo.getSelectedItem().equals("Combine All")) + concatSequences = true; + else + { + VCFview.this.chr = (String) combo.getSelectedItem(); + concatSequences = false; + } repaint(); } }); topPanel.add(combo); + if(topPanel instanceof JPanel) + vcfPanel.add(topPanel, BorderLayout.NORTH); + + // auto hide top panel + final JCheckBox buttonAutoHide = new JCheckBox("Hide", true); + buttonAutoHide.setToolTipText("Auto-Hide"); + topPanel.add(buttonAutoHide); + final MouseMotionListener mouseMotionListener = new MouseMotionListener() + { + public void mouseDragged(MouseEvent event) + { + handleCanvasMouseDrag(event); + } + + public void mouseMoved(MouseEvent e) + { + findVariantAtPoint(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); + } + + } + }; + addMouseMotionListener(mouseMotionListener); + // popup menu popup = new JPopupMenu(); @@ -561,44 +601,111 @@ public class VCFview extends JPanel return msg; } + + + /** + * For VCF 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(!concatSequences) + return 0; + + if(offsetLengths == null) + { + String[] contigs = tr[0].getmSeq(); + FeatureVector features = entryGroup.getAllFeatures(); + offsetLengths = new Hashtable<String, Integer>(contigs.length); + for(int i=0; i<contigs.length; i++) + { + FeatureContigPredicate predicate = new FeatureContigPredicate(contigs[i]); + for(int j=0; j<features.size(); j++) + { + if(predicate.testPredicate(features.elementAt(j))) + { + offsetLengths.put(contigs[i], features.elementAt(j).getFirstBase()-1); + break; + } + } + } + } + return offsetLengths.get(refName); + } + protected void paintComponent(Graphics g) { super.paintComponent(g); mouseOverVCFline = null; float pixPerBase = getPixPerBaseByWidth(); - String s; - int start = getBaseAtStartOfView(); int end = start+nbasesInView; - String region = chr+":"+start+"-"+end; drawSelectionRange((Graphics2D)g, pixPerBase, start, end); - + FeatureVector features = getCDSFeaturesInRange(start, end); - - // a region is specified; random access for (int i = 0; i < tr.length; i++) { - TabixReader.Iterator iter = tr[i].query(region); // get the iterator - if (iter == null) - return; - try - { - while ((s = iter.next()) != null) - drawVariantCall(g, s, start, i, pixPerBase, features); - } - catch (IOException e) + if(concatSequences) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + String[] contigs = tr[0].getmSeq(); + for(int j=0; j<contigs.length; j++) + { + int offset = getSequenceOffset(contigs[j]); + int nextOffset; + if(j<contigs.length-1) + nextOffset = getSequenceOffset(contigs[j+1]); + else + nextOffset = seqLength; + + if( (offset >= start && offset < end) || + (offset < start && start < nextOffset) ) + { + int thisStart = start - offset; + if(thisStart < 1) + thisStart = 1; + int thisEnd = end - offset; + + drawRegion(g, contigs[j]+":"+thisStart+"-"+thisEnd, i, start, pixPerBase, features); + } + } + + } + else + drawRegion(g, chr+":"+start+"-"+end, i, start, pixPerBase, features); } if(feature_display == null) drawScale((Graphics2D)g, start, end, pixPerBase, getHeight()); } + private void drawRegion(Graphics g, + String region, + int i, + int start, + float pixPerBase, + FeatureVector features) + { + String s; + TabixReader.Iterator iter = tr[i].query(region); // get the iterator + if (iter == null) + return; + try + { + while ((s = iter.next()) != null) + drawVariantCall(g, s, start, i, pixPerBase, features); + } + catch (IOException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + private FeatureVector getCDSFeaturesInRange(int start, int end) { try @@ -780,7 +887,8 @@ public class VCFview extends JPanel { //String parts[] = line.split("\\t"); String parts[] = tabPattern.split(line, 0); - int basePosition = Integer.parseInt(parts[1]); + + int basePosition = Integer.parseInt(parts[1]) + getSequenceOffset(parts[0]); if( !showVariant(parts[3], parts[4], features, basePosition, parts[5]) ) return; @@ -921,49 +1029,85 @@ public class VCFview extends JPanel return pos; } - private void findVariantAtPoint(Point lastMousePoint) + private void findVariantAtPoint(Point mousePoint) { float pixPerBase = getPixPerBaseByWidth(); - String s; int start = getBaseAtStartOfView(); int end = start+nbasesInView; - String region = chr+":"+start+"-"+end; FeatureVector features = getCDSFeaturesInRange(start, end); for (int i = 0; i < tr.length; i++) { - TabixReader.Iterator iter = tr[i].query(region); // get the iterator - if (iter == null) - return; - try + if(concatSequences) { - while ((s = iter.next()) != null) + String[] contigs = tr[0].getmSeq(); + for(int j=0; j<contigs.length; j++) { - String parts[] = tabPattern.split(s, 7); - int basePosition = Integer.parseInt(parts[1]); - - if( !showVariant(parts[3], parts[4], features, basePosition, parts[5]) ) - continue; + int offset = getSequenceOffset(contigs[j]); + int nextOffset; + if(j<contigs.length-1) + nextOffset = getSequenceOffset(contigs[j+1]); + else + nextOffset = seqLength; - int pos[] = getScreenPosition(basePosition, pixPerBase, start, i); - if(lastMousePoint != null && - lastMousePoint.getY() < pos[1] && - lastMousePoint.getY() > pos[1]-LINE_HEIGHT && - lastMousePoint.getX() > pos[0]-3 && - lastMousePoint.getX() < pos[0]+3) - { - mouseOverVCFline = s; - mouseOverIndex = i; - } + if( (offset >= start && offset < end) || + (offset < start && start < nextOffset) ) + { + int thisStart = start - offset; + if(thisStart < 1) + thisStart = 1; + int thisEnd = end - offset; + searchRegion(contigs[j]+":"+thisStart+"-"+thisEnd, i, mousePoint, features, start, pixPerBase); + } } - } - catch (IOException e) - { - e.printStackTrace(); - } + } + else + searchRegion(chr+":"+start+"-"+end, i, mousePoint, features, start, pixPerBase); } } + private void searchRegion(String region, int i, Point mousePoint, FeatureVector features, + int start, float pixPerBase) + { + TabixReader.Iterator iter = tr[i].query(region); // get the iterator + if (iter == null) + return; + try + { + String s; + while ((s = iter.next()) != null) + isMouseOver(mousePoint, s, features, i, start, pixPerBase); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + private void isMouseOver(Point mousePoint, + String s, + FeatureVector features, + int i, + int start, float pixPerBase) + { + String parts[] = tabPattern.split(s, 7); + int basePosition = Integer.parseInt(parts[1]) + getSequenceOffset(parts[0]); + + if( !showVariant(parts[3], parts[4], features, basePosition, parts[5]) ) + return; + + int pos[] = getScreenPosition(basePosition, pixPerBase, start, i); + if(mousePoint != null && + mousePoint.getY() < pos[1] && + mousePoint.getY() > pos[1]-LINE_HEIGHT && + mousePoint.getX() > pos[0]-3 && + mousePoint.getX() < pos[0]+3) + { + mouseOverVCFline = s; + mouseOverIndex = i; + } + } + private void drawScale(Graphics2D g2, int start, int end, float pixPerBase, int ypos) { g2.setColor(Color.black); @@ -1260,6 +1404,22 @@ public class VCFview extends JPanel repaint(); } + class FeatureContigPredicate implements FeaturePredicate + { + String contigName; + FeatureContigPredicate(String contigName) + { + this.contigName = contigName; + } + + public boolean testPredicate(Feature feature) + { + if(feature.getIDString().equals(contigName)) + return true; + return false; + } + } + public static void main(String args[]) { List<String> vcfFileList = new Vector<String>(); -- GitLab