org.biojava.nbio.structure.gui.SequenceDisplay Maven / Gradle / Ivy
/*
* BioJava development code
*
* This code may be freely distributed and modified under the
* terms of the GNU Lesser General Public Licence. This should
* be distributed with the code. If you do not have a copy,
* see:
*
* http://www.gnu.org/copyleft/lesser.html
*
* Copyright for this code is held jointly by the individual
* authors. These should be listed in @author doc comments.
*
* For more information on the BioJava project and its aims,
* or to join the biojava-l mailing list, visit the home page
* at:
*
* http://www.biojava.org/
*
* created at May 26, 2008
*/
package org.biojava.nbio.structure.gui;
import org.biojava.nbio.structure.*;
import org.biojava.nbio.structure.align.StructurePairAligner;
import org.biojava.nbio.structure.align.pairwise.AlternativeAlignment;
import org.biojava.nbio.structure.gui.events.AlignmentPositionListener;
import org.biojava.nbio.structure.gui.util.AlignedPosition;
import org.biojava.nbio.structure.gui.util.SequenceMouseListener;
import org.biojava.nbio.structure.gui.util.SequenceScalePanel;
import org.biojava.nbio.structure.io.PDBFileReader;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
/** A sequence display that can show the results of a protein structure alignment.
*
* @author Andreas Prlic
* @since 1.7
*/
public class SequenceDisplay extends JPanel implements ChangeListener {
/**
*
*/
private static final long serialVersionUID = -1829252532712454236L;
Structure structure1;
Structure structure2;
AlternativeAlignment alig;
StructurePairAligner structurePairAligner;
SequenceScalePanel panel1;
SequenceScalePanel panel2;
JSlider residueSizeSlider;
JLabel percentageDisplay;
int[] idx1;
int[] idx2;
/** the maximum value that the scale can get
*
*/
public static final int MAX_SCALE = 10;
//private static final Logger logger = LoggerFactory.getLogger(SequenceDisplay.class);
List apos;
float scale;
SequenceMouseListener mouseListener1;
SequenceMouseListener mouseListener2;
JLabel label1;
JLabel label2;
public static void main(String[] args){
try {
PDBFileReader pdbr = new PDBFileReader();
//String pdb1 = "1crl";
//String pdb2 = "1ede";
String pdb1 = "1buz";
String pdb2 = "5pti";
// NO NEED TO DO CHANGE ANYTHING BELOW HERE...
StructurePairAligner sc = new StructurePairAligner();
// step1 : read molecules
System.out.println("aligning " + pdb1 + " vs. " + pdb2);
Structure s1 = pdbr.getStructureById(pdb1);
Structure s2 = pdbr.getStructureById(pdb2);
// step 2 : do the calculations
sc.align(s1,s2);
AlternativeAlignment[] aligs = sc.getAlignments();
SequenceDisplay displ = new SequenceDisplay(sc);
displ.setStructure1(s1);
displ.setStructure2(s2);
displ.setAlternativeAlignment(aligs[0]);
displ.updateDisplay();
JFrame frame = new JFrame("Sequences for AlternativeAlignment ["+0+"]");
frame.getContentPane().add(displ);
frame.pack();
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter(){
@Override
public void windowClosing(WindowEvent e){
JFrame f = (JFrame) e.getSource();
f.setVisible(false);
f.dispose();
}
});
} catch (Exception e){
e.printStackTrace();
}
}
public SequenceDisplay(StructurePairAligner structurePairAligner){
super();
structure1 = null;
structure2 = null;
alig = null;
this.structurePairAligner = structurePairAligner;
panel1 = new SequenceScalePanel(1);
panel2 = new SequenceScalePanel(2);
mouseListener1 = new SequenceMouseListener(this);
panel1.addMouseListener(mouseListener1);
panel1.addMouseMotionListener(mouseListener1);
mouseListener2 = new SequenceMouseListener(this);
panel2.addMouseListener(mouseListener2);
panel2.addMouseMotionListener(mouseListener2);
//SequenceMouseListener ml = new SequenceMouseListener(this);
//this.addMouseListener(ml);
//this.addMouseMotionListener(ml);
Box vBox = Box.createVerticalBox();
Box hBox1 = Box.createHorizontalBox();
Box hBox2 = Box.createHorizontalBox();
label1 = new JLabel();
hBox1.add(label1);
label2 = new JLabel();
hBox2.add(label2);
hBox1.add(panel1);
hBox2.add(panel2);
vBox.add(hBox1);
vBox.add(hBox2);
int RES_MIN = 1;
int RES_MAX = 100;
int RES_INIT = 100;
residueSizeSlider = new JSlider(JSlider.HORIZONTAL,
RES_MIN, RES_MAX, RES_INIT);
residueSizeSlider.setInverted(true);
//residueSizeSlider.setMajorTickSpacing(5);
//residueSizeSlider.setMinorTickSpacing(2);
residueSizeSlider.setPaintTicks(false);
residueSizeSlider.setPaintLabels(false);
residueSizeSlider.addChangeListener(this);
//residueSizeSlider.setPreferredSize(new Dimension(100,15));
percentageDisplay = new JLabel("100 %");
Box hBox = Box.createHorizontalBox();
hBox.setBackground(Color.white);
hBox.add(Box.createHorizontalGlue());
hBox.add(residueSizeSlider);
hBox.add(percentageDisplay);
hBox.add(Box.createHorizontalGlue());
//vBox.add(hBox);
JScrollPane scroll = new JScrollPane(vBox);
//scroll.setPreferredSize(new Dimension(500,160));
Box vBox2 = Box.createVerticalBox();
vBox2.add(scroll);
vBox2.add(hBox);
//vBox2.setPreferredSize(new Dimension(500,160));
//vBox2.setSize(new Dimension(500,160));
//vBox2.setMinimumSize(new Dimension(500,160));
//vBox2.setMaximumSize(new Dimension(500,160));
this.setPreferredSize(new Dimension(500,100));
this.add(vBox2);
this.setLayout(new BoxLayout(this,BoxLayout.Y_AXIS));
apos = new ArrayList();
}
public void clearListeners(){
mouseListener1.clearListeners();
mouseListener2.clearListeners();
}
public void addAlignmentPositionListener(AlignmentPositionListener li){
mouseListener1.addAlignmentPositionListener(li);
mouseListener2.addAlignmentPositionListener(li);
}
public StructurePairAligner getStructurePairAligner() {
return structurePairAligner;
}
public void setStructurePairAligner(StructurePairAligner structurePairAligner) {
this.structurePairAligner = structurePairAligner;
}
/** get the identical position in the alignment
*
* @return identical positions for structure1
*/
public int[] getIdx1() {
return idx1;
}
/** set the identical positions in the alignment
*
* @param idx identical positions for structure1
*/
private void setIdx1(int[] idx) {
this.idx1 = idx;
}
/** get the identical position in the alignment
*
* @return identical positions for structure2
*/
public int[] getIdx2() {
return idx2;
}
/** set the identical positions in the alignment
*
* @param idx identical positions for structure2
*/
private void setIdx2(int[] idx) {
this.idx2 = idx;
}
private void buildAligMap(){
apos.clear();
int gap = 0;
int gpos1 = 0;
int gpos2 = 0;
for (int pos = 0 ; pos < idx1.length ; pos ++){
int p1 = idx1[pos];
int p2 = idx2[pos];
int end = Math.max(p1,p2);
//System.out.println("p1: " + p1 + " p2: " + p2 );
// fill up gaps...
for (;gap " + end);
apos.add(m);
}
// add this aligned position
AlignedPosition m = new AlignedPosition();
m.setPos1(p1);
m.setPos2(p2);
m.setEquivalent(AlignedPosition.EQUIVALENT);
//System.out.println(m);
apos.add(m);
gpos1++;
gpos2++;
gap++;
}
//System.out.println(apos);
}
private void setAtoms(Structure s, SequenceScalePanel panel){
if ( structurePairAligner == null){
System.err.println("StructurePairAligner has not been set");
return;
}
Atom[] ca1 = structurePairAligner.getAlignmentAtoms(s);
Chain c = new ChainImpl();
c.setChainID("1");
for (Atom atom : ca1) {
Group g = atom.getGroup();
Chain parentChain = g.getChain();
c.addGroup(g);
// hack for Jmol?
g.setChain(parentChain);
}
panel.setChain(c);
}
//TODO: add a method to allow the display if the structure alignment
// has been called with setting the atoms directly
public void setStructure1(Structure structure){
this.structure1 = structure;
if ( structure != null) {
setAtoms(structure1,panel1);
label1.setText(structure.getPDBCode());
label1.repaint();
}
}
public void setStructure2(Structure structure){
this.structure2 = structure;
if ( structure != null){
setAtoms(structure2,panel2);
label2.setText(structure.getPDBCode());
label2.repaint();
}
}
public void setAlternativeAlignment(AlternativeAlignment alig){
this.alig = alig;
this.setIdx1(alig.getIdx1());
this.setIdx2(alig.getIdx2());
buildAligMap();
panel1.setAligMap(apos);
panel2.setAligMap(apos);
updateDisplay();
}
public List getAligMap(){
return apos;
}
@Override
public void stateChanged(ChangeEvent e) {
JSlider source = (JSlider)e.getSource();
//if (!source.getValueIsAdjusting()) {
int residueSize = source.getValue();
calcScale(residueSize);
updatePercentageDisplay();
this.repaint();
this.revalidate();
//this.updateUI();
//int width = getTotalWidth();
//int height = getTotalHeight();
//Dimension d = new Dimension(width,height);
//logger.info("setting preferred size" + width + " " + height);
//this.setPreferredSize(d);
//this.setSize(d);
// }
}
public void updateDisplay(){
int residueSize = residueSizeSlider.getValue();
calcScale(residueSize);
updatePercentageDisplay();
this.repaint();
this.revalidate();
}
private void updatePercentageDisplay(){
int perc = residueSizeSlider.getValue();
percentageDisplay.setText(perc+ " %");
}
private int getMaxSequenceLength(){
int l1 = panel1.getChain().getAtomGroups(GroupType.AMINOACID).size();
int l2 = panel2.getChain().getAtomGroups(GroupType.AMINOACID).size();
if ( l1 > l2)
return l1;
else return l2;
}
/** calculate the float that is used for display.
* 1 * scale = size of 1 amino acid (in pixel).
* maximum @see MAX_SCALE
* @param zoomFactor
* @return a float that is the display "scale" - an internal value required for paintin.
* user should only interact with the zoomfactor ...
*/
private float getScaleForZoom(int zoomFactor){
if ( zoomFactor > 100)
zoomFactor = 100;
if ( zoomFactor < 1)
zoomFactor = 1;
int DEFAULT_X_START
= SequenceScalePanel.DEFAULT_X_START;
int DEFAULT_X_RIGHT_BORDER = SequenceScalePanel.DEFAULT_X_RIGHT_BORDER;
int seqLength = getMaxSequenceLength();
// the maximum width depends on the size of the parent Component
int width=getWidth();
float s = width / (float) ( seqLength + DEFAULT_X_START + DEFAULT_X_RIGHT_BORDER );
//logger.info("scale for 100% " + s + " " + seqLength + " " + zoomFactor);
s = (100) * s / ( zoomFactor * 1.0f) ;
if ( s > MAX_SCALE)
s = MAX_SCALE;
//logger.info("but changed to " + s);
return s;
}
/** a value of 100 means that the whole sequence should be displayed in the current visible window
* a factor of 1 means that one amino acid shoud be drawn as big as possible
*
* @param zoomFactor - a value between 1 and 100
*
*
*/
public void calcScale(int zoomFactor){
float s = getScaleForZoom(zoomFactor);
scale = s;
//logger.info("calc scale zoom:"+zoomFactor+ " s: " + s);
panel1.setScale(s);
panel2.setScale(s);
panel1.repaint();
panel2.repaint();
//return scale;
}
public float getScale(){
return scale;
}
}