001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021package org.biojava.nbio.structure.align.gui.aligpanel; 022 023import org.biojava.nbio.structure.Atom; 024import org.biojava.nbio.structure.StructureException; 025import org.biojava.nbio.structure.align.gui.DisplayAFP; 026import org.biojava.nbio.structure.align.gui.JPrintPanel; 027import org.biojava.nbio.structure.align.gui.MenuCreator; 028import org.biojava.nbio.structure.align.gui.StructureAlignmentDisplay; 029import org.biojava.nbio.structure.align.gui.jmol.AbstractAlignmentJmol; 030import org.biojava.nbio.structure.align.gui.jmol.JmolTools; 031import org.biojava.nbio.structure.align.gui.jmol.StructureAlignmentJmol; 032import org.biojava.nbio.structure.align.model.AFPChain; 033import org.biojava.nbio.structure.align.model.AfpChainWriter; 034import org.biojava.nbio.structure.align.util.AFPAlignmentDisplay; 035import org.biojava.nbio.structure.align.util.AtomCache; 036import org.biojava.nbio.structure.align.util.UserConfiguration; 037import org.biojava.nbio.structure.align.webstart.WebStartMain; 038import org.biojava.nbio.structure.align.xml.AFPChainXMLParser; 039import org.biojava.nbio.structure.gui.events.AlignmentPositionListener; 040import org.biojava.nbio.structure.gui.util.AlignedPosition; 041import org.biojava.nbio.structure.gui.util.color.ColorUtils; 042 043import java.awt.*; 044import java.awt.event.ActionEvent; 045import java.awt.event.WindowEvent; 046import java.awt.event.WindowListener; 047import java.io.BufferedReader; 048import java.io.FileReader; 049import java.util.BitSet; 050import java.util.List; 051 052 053/** A JPanel that can display an AFPChain in a nice way and interact with Jmol. 054 * 055 * @author Andreas Prlic 056 * 057 */ 058public class AligPanel extends JPrintPanel implements AlignmentPositionListener, WindowListener{ 059 060 /** 061 * 062 */ 063 private static final long serialVersionUID = -6892229111166263764L; 064 065 private AFPChain afpChain; 066 private AFPChainCoordManager coordManager ; 067 private Font seqFont; 068 private Font eqFont; 069 private AbstractAlignmentJmol jmol; 070 private AligPanelMouseMotionListener mouseMoLi; 071 072 private BitSet selection; 073 074 private boolean selectionLocked; 075 private Atom[] ca1; 076 private Atom[] ca2; 077 078 private boolean colorBySimilarity; 079 080 private boolean colorByAlignmentBlock; 081 082 private static final Color COLOR_EQUAL = Color.decode("#6A93D4"); 083 private static final Color COLOR_SIMILAR = Color.decode("#D460CF"); 084 085 086 public static void main(String[] args){ 087 088 String file = "/Users/ap3/tmp/4hhb.ce"; 089 090 try { 091 BufferedReader in = new BufferedReader(new FileReader(file)); 092 StringBuffer xml = new StringBuffer(); 093 String str; 094 while ((str = in.readLine()) != null) { 095 xml.append(str); 096 } 097 in.close(); 098 099 AFPChain[] afps = AFPChainXMLParser.parseMultiXML(xml.toString()); 100 AFPChain afpChain = afps[0]; 101 102 UserConfiguration config = WebStartMain.getWebStartConfig(); 103 AtomCache cache = new AtomCache(config.getPdbFilePath(),config.getCacheFilePath()); 104 105 Atom[] ca1 = cache.getAtoms(afpChain.getName1()); 106 Atom[] ca2 = cache.getAtoms(afpChain.getName2()); 107 108 AFPChainXMLParser.rebuildAFPChain(afpChain, ca1, ca2); 109 110 111 //StructureAlignment algorithm = StructureAlignmentFactory.getAlgorithm(afpChain.getAlgorithmName()); 112 StructureAlignmentJmol jmol= StructureAlignmentDisplay.display(afpChain, ca1, ca2); 113 114 DisplayAFP.showAlignmentPanel(afpChain, ca1, ca2, jmol); 115 116 117 118 119 } catch (Exception e){ 120 e.printStackTrace(); 121 } 122 } 123 124 125 public AligPanel(){ 126 super(); 127 this.setBackground(Color.white); 128 coordManager = new AFPChainCoordManager(); 129 seqFont = new Font("SansSerif",Font.PLAIN,12); 130 eqFont = new Font("SansSerif",Font.BOLD,12); 131 132 mouseMoLi = new AligPanelMouseMotionListener(this); 133 this.addMouseMotionListener(mouseMoLi); 134 this.addMouseListener(mouseMoLi); 135 mouseMoLi.addAligPosListener(this); 136 137 selection = new BitSet(); 138 colorBySimilarity = false; 139 colorByAlignmentBlock = false; 140 } 141 142 143 144 public AFPChainCoordManager getCoordManager() { 145 return coordManager; 146 } 147 148 149 public void addAlignmentPositionListener(AlignmentPositionListener li){ 150 mouseMoLi.addAligPosListener(li); 151 } 152 153 public void destroy(){ 154 155 setAFPChain(null); 156 mouseMoLi.destroy(); 157 jmol = null; 158 ca1 = null; 159 ca2 = null; 160 selection = null; 161 } 162 163 public AFPChain getAFPChain(){ 164 return afpChain; 165 } 166 167 public void setAFPChain(AFPChain afpChain) { 168 169 this.afpChain = afpChain; 170 coordManager.setAFPChain(afpChain); 171 if ( afpChain != null) { 172 selection = new BitSet (afpChain.getAlnLength()); 173 if ( afpChain.getBlockNum() > 1) { 174 colorByAlignmentBlock = true; 175 } 176 } 177 178 } 179 180 181@Override 182public void paintComponent(Graphics g){ 183 184 super.paintComponent(g); 185 186 Graphics2D g2D = (Graphics2D) g; 187 188 189 g2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, 190 RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 191 192 g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 193 RenderingHints.VALUE_ANTIALIAS_ON); 194 195 196 // only draw within the ranges of the Clip 197 //Rectangle drawHere = g2D.getClipBounds(); 198 199 200 //int startpos = coordManager.getSeqPos(0,drawHere.x); 201 //int endpos = coordManager.getSeqPos(0,drawHere.x+drawHere.width-2); 202 203 204 char[] seq1 = afpChain.getAlnseq1(); 205 char[] seq2 = afpChain.getAlnseq2(); 206 char[] symb = afpChain.getAlnsymb(); 207 208 int startpos = 0; 209 int endpos = afpChain.getAlnLength(); 210 211 String summary = afpChain.toString(); 212 g2D.drawString(summary, 20, coordManager.getSummaryPos()); 213 214 Color significantCol = Color.red; 215 if ( afpChain.isSignificantResult()) 216 significantCol = Color.green; 217 218 g2D.setPaint(significantCol); 219 // draw a darker backgroun 220 Rectangle sig = new Rectangle(10,10,10,10); 221 g2D.fill(sig); 222 boolean isFATCAT = false; 223 if ( afpChain.getAlgorithmName().startsWith("jFatCat")){ 224 isFATCAT = true; 225 } 226 for ( int i = startpos ; ((i <= endpos) && ( i < afpChain.getAlnLength())) ;i++){ 227 228 // TODO: 229 // color amino acids by hydrophobicity 230 char c1 = seq1[i]; 231 char c2 = seq2[i]; 232 boolean isGapped = false; 233 g2D.setFont(seqFont); 234 235 List<Integer> alignedPos = null; 236 if ( colorByAlignmentBlock){ 237 alignedPos = DisplayAFP.getEQRAlignmentPos(afpChain); 238 } 239 if ( isFATCAT){ 240 char s = symb[i]; 241 if ( s != ' ') { 242 isGapped = false; 243 g2D.setFont(eqFont); 244 } 245 else 246 isGapped = true; 247 } else { 248 char s = symb[i]; 249 if ( c1 != '-' && c2 != '-' && s!= ' '){ 250 // no gap 251 g2D.setFont(eqFont); 252 } else { 253 isGapped = true; 254 255 } 256 } 257 258 Point p1 = coordManager.getPanelPos(0,i); 259 int xpos1 = p1.x; 260 int ypos1 = p1.y; 261 Point p2 = coordManager.getPanelPos(1, i); 262 int xpos2 = p2.x; 263 int ypos2 = p2.y; 264 int blockNum = afpChain.getBlockNum(); 265 if (! isGapped) { 266 Color bg = Color.white; 267 Color bg2 = Color.white; 268 Color end1 = ColorUtils.rotateHue(ColorUtils.orange, (1.0f / 24.0f) * blockNum ); 269 Color end2 = ColorUtils.rotateHue(ColorUtils.cyan, (1.0f / 24.0f) * (blockNum +1)) ; 270 271 if ( colorByAlignmentBlock) { 272 273 if (! alignedPos.contains(i)){ 274 275 // unaligned! 276 bg = Color.white; 277 bg2 = Color.white; 278 } else { 279 280 int colorPos = 0; 281 if (isFATCAT) { 282 int block = 0; 283 char s = symb[i]; 284 try { 285 block = Integer.parseInt(String.valueOf(s)) - 1; 286 bg = ColorUtils.getIntermediate(ColorUtils.orange, end1, blockNum, block); 287 bg2 = ColorUtils.getIntermediate(ColorUtils.cyan, end2, blockNum, block); 288 //bg = ColorUtils.rotateHue(ColorUtils.orange, (1.0f / 24.0f) * block ); 289 //bg2 = ColorUtils.rotateHue(ColorUtils.cyan, (1.0f / 16.0f) * block ); 290 } catch (Exception e){} 291 292 if ( colorPos > ColorUtils.colorWheel.length){ 293 colorPos = ColorUtils.colorWheel.length % colorPos ; 294 } 295 } else { 296 colorPos = AFPAlignmentDisplay.getBlockNrForAlignPos(afpChain, i); 297 bg = ColorUtils.getIntermediate(ColorUtils.orange, end1, blockNum, colorPos); 298 bg2 = ColorUtils.getIntermediate(ColorUtils.cyan, end2, blockNum, colorPos); 299 //bg = ColorUtils.rotateHue(ColorUtils.orange, (1.0f / 24.0f) * colorPos ); 300 //bg2 = ColorUtils.rotateHue(ColorUtils.cyan, (1.0f / 16.0f) * colorPos); 301 } 302 303 } 304 } else { 305 306 bg = Color.LIGHT_GRAY; 307 bg2 = Color.LIGHT_GRAY; 308 } 309 310 // draw a darker background 311 g2D.setPaint(bg); 312 Rectangle rec = new Rectangle(p1.x-1,p1.y-11, (p2.x-p1.x)+12, (p2.y-p1.y)+1); 313 g2D.fill(rec); 314 g2D.setPaint(bg2); 315 Rectangle rec2 = new Rectangle(p1.x-1,p1.y+4, (p2.x-p1.x)+12, (p2.y-p1.y)-3); 316 g2D.fill(rec2); 317 318 //g2D.setPaint(Color.black); 319 //g2D.draw(rec); 320 } 321 if ( colorBySimilarity){ 322 if ( c1 == c2){ 323 Color bg = COLOR_EQUAL; 324 g2D.setPaint(bg); 325 Rectangle rec = new Rectangle(p1.x-1,p1.y-11, (p2.x-p1.x)+12, (p2.y-p1.y)+12); 326 g2D.fill(rec); 327 } else if (AFPAlignmentDisplay.aaScore(c1, c2) > 0) { 328 Color bg = COLOR_SIMILAR; 329 g2D.setPaint(bg); 330 Rectangle rec = new Rectangle(p1.x-1,p1.y-11, (p2.x-p1.x)+12, (p2.y-p1.y)+12); 331 g2D.fill(rec); 332 } 333 } 334 335 //if ( selectionStart != null && selectionEnd != null){ 336 // if ( i >= selectionStart.getPos1() && i <= selectionEnd.getPos1()) { 337 338 if ( isSelected(i)){ 339 // draw selection 340 Color bg = Color.YELLOW; 341 g2D.setPaint(bg); 342 // draw a darker backgroun 343 Rectangle rec = new Rectangle(p1.x-1,p1.y-11, (p2.x-p1.x)+12, (p2.y-p1.y)+12); 344 g2D.fill(rec); 345 // } 346 } 347 348 // draw the AA sequence 349 g2D.setColor(Color.black); 350 g2D.drawString(String.valueOf(c1), xpos1, ypos1); 351 g2D.drawString(String.valueOf(c2), xpos2, ypos2); 352 353 354 355 356 //System.out.println(seq1[i] + " " + xpos1 + " " + ypos1 + " " + seq2[i] + xpos2 + " " + ypos2); 357 } 358 359 int nrLines = (afpChain.getAlnLength() -1) / AFPChainCoordManager.DEFAULT_LINE_LENGTH; 360 361 362 for ( int i = 0 ; i <= nrLines ; i++){ 363 364 try { 365 // draw legend at i 366 Point p1 = coordManager.getLegendPosition(i,0); 367 Point p2 = coordManager.getLegendPosition(i,1); 368 369 370 int aligPos = i * AFPChainCoordManager.DEFAULT_LINE_LENGTH ; 371 Atom a1 = DisplayAFP.getAtomForAligPos(afpChain, 0,aligPos, ca1,false); 372 Atom a2 = DisplayAFP.getAtomForAligPos(afpChain, 1,aligPos, ca2,false); 373 String label1 = JmolTools.getPdbInfo(a1,false); 374 String label2 = JmolTools.getPdbInfo(a2,false); 375 g2D.drawString(label1, p1.x,p1.y); 376 g2D.drawString(label2, p2.x,p2.y); 377 378 Point p3 = coordManager.getEndLegendPosition(i,0); 379 Point p4 = coordManager.getEndLegendPosition(i,1); 380 381 aligPos = i * AFPChainCoordManager.DEFAULT_LINE_LENGTH + AFPChainCoordManager.DEFAULT_LINE_LENGTH -1 ; 382 if ( aligPos > afpChain.getAlnLength()) 383 aligPos = afpChain.getAlnLength() - 1; 384 Atom a3 = DisplayAFP.getAtomForAligPos(afpChain, 0,aligPos, ca1,true); 385 Atom a4 = DisplayAFP.getAtomForAligPos(afpChain, 1,aligPos, ca2,true); 386 387 String label3 = JmolTools.getPdbInfo(a3,false); 388 String label4 = JmolTools.getPdbInfo(a4,false); 389 390 g2D.drawString(label3, p3.x,p3.y); 391 g2D.drawString(label4, p4.x,p4.y); 392 393 394 } catch (StructureException e){ 395 e.printStackTrace(); 396 } 397 } 398 399 400 } 401 402 403 404 405 private boolean isSelected(int alignmentPosition) { 406 407 return selection.get(alignmentPosition); 408 409 } 410 411 412 @Override 413public void mouseOverPosition(AlignedPosition p) { 414 //System.out.println("AligPanel: mouse over position " + p.getPos1() ); 415 416 if ( ! selectionLocked) 417 selection.clear(); 418 selection.set(p.getPos1()); 419 420 updateJmolDisplay(); 421 422 this.repaint(); 423 424 } 425 426 private void updateJmolDisplay() { 427 428 if ( jmol == null) 429 return; 430 431 int size = afpChain.getAlnLength(); 432 433 StringBuffer cmd = new StringBuffer("select "); 434 435 int nrSelected = 0; 436 try { 437 438 for (int i = 0 ; i< size ; i++){ 439 if ( selection.get(i)){ 440 441 Atom a1 = DisplayAFP.getAtomForAligPos(afpChain, 0,i, ca1, false); 442 Atom a2 = DisplayAFP.getAtomForAligPos(afpChain, 1,i, ca2, false); 443 444 String select1 = ""; 445 446 if ( a1 != null ) 447 select1 = JmolTools.getPdbInfo(a1); 448 String select2 = "" ; 449 if ( a2 != null) 450 select2 = JmolTools.getPdbInfo(a2); 451 452 // nothing to display 453 if ( select1.equals("") && select2.equals("")) 454 continue; 455 456 if ( nrSelected > 0) 457 cmd.append(", "); 458 459 cmd.append(select1); 460 cmd.append("/1, "); 461 cmd.append(select2); 462 cmd.append("/2"); 463 nrSelected++; 464 } 465 } 466 467 468 } catch (StructureException e){ 469 e.printStackTrace(); 470 } 471 if ( nrSelected == 0) 472 cmd.append(" none;"); 473 else 474 cmd.append("; set display selected;"); 475 476 jmol.evalString(cmd.toString()); 477 478 479 } 480 481 482 @Override 483public void positionSelected(AlignedPosition p) { 484 mouseOverPosition(p); 485 486 } 487 488 @Override 489public void rangeSelected(AlignedPosition start, AlignedPosition end) { 490 //System.out.println("AligPanel: range selected " + start.getPos1() + " - " + end.getPos1() + " selectionLockedL " + selectionLocked); 491 if ( ! selectionLocked ) 492 selection.clear(); 493 selection.set(start.getPos1(), end.getPos1()+1); 494 updateJmolDisplay(); 495 this.repaint(); 496 497 } 498 499 @Override 500public void selectionLocked() { 501 selectionLocked = true; 502 503 } 504 505 @Override 506public void selectionUnlocked() { 507 selectionLocked = false; 508 selection.clear(); 509 this.repaint(); 510 511 } 512 513 514 @Override 515public void toggleSelection(AlignedPosition p) { 516 selection.flip(p.getPos1()); 517 //System.out.println("AligPanel: toggle selection " + p.getPos1() + " " + selection.get(p.getPos1())); 518 updateJmolDisplay(); 519 this.repaint(); 520 521 } 522 523 524 525 public void setAlignmentJmol(AbstractAlignmentJmol jmol) { 526 this.jmol = jmol; 527 528 } 529 530 531 @Override 532public void windowActivated(WindowEvent e) { 533 534 // TODO Auto-generated method stub 535 536 } 537 538 539 @Override 540public void windowClosed(WindowEvent e) { 541 // TODO Auto-generated method stub 542 543 } 544 545 546 @Override 547public void windowClosing(WindowEvent e) { 548 destroy(); 549 550 } 551 552 553 @Override 554public void windowDeactivated(WindowEvent e) { 555 // TODO Auto-generated method stub 556 557 } 558 559 560 @Override 561public void windowDeiconified(WindowEvent e) { 562 // TODO Auto-generated method stub 563 564 } 565 566 567 @Override 568public void windowIconified(WindowEvent e) { 569 // TODO Auto-generated method stub 570 571 } 572 573 574 @Override 575public void windowOpened(WindowEvent e) { 576 // TODO Auto-generated method stub 577 578 } 579 580 @Override 581public void actionPerformed(ActionEvent e) { 582 String cmd = e.getActionCommand(); 583 // print is handled by superclass 584 if ( cmd.equals(MenuCreator.PRINT)) { 585 super.actionPerformed(e); 586 } else if (cmd.equals(MenuCreator.TEXT_ONLY)){ 587 String result = AfpChainWriter.toWebSiteDisplay(afpChain, ca1, ca2); 588 DisplayAFP.showAlignmentImage(afpChain, result); 589 } else if ( cmd.equals(MenuCreator.PAIRS_ONLY)) { 590 String result = AfpChainWriter.toAlignedPairs(afpChain, ca1, ca2) ; 591 DisplayAFP.showAlignmentImage(afpChain, result); 592 } else if (cmd.equals(MenuCreator.FATCAT_TEXT)){ 593 String result = afpChain.toFatcat(ca1, ca2); 594 result += AFPChain.newline; 595 result += afpChain.toRotMat(); 596 DisplayAFP.showAlignmentImage(afpChain, result); 597 } else if ( cmd.equals(MenuCreator.SELECT_EQR)){ 598 selectEQR(); 599 } else if ( cmd.equals(MenuCreator.SIMILARITY_COLOR)){ 600 colorBySimilarity(true); 601 } else if ( cmd.equals(MenuCreator.EQR_COLOR)){ 602 colorBySimilarity(false); 603 } else if ( cmd.equals(MenuCreator.FATCAT_BLOCK)){ 604 colorByAlignmentBlock(); 605 } 606 else { 607 System.err.println("Unknown command:" + cmd); 608 } 609 610 } 611 612 613 private void colorByAlignmentBlock() { 614 colorByAlignmentBlock = true; 615 colorBySimilarity = false; 616 this.repaint(); 617 618 } 619 620 621 private void colorBySimilarity(boolean flag) { 622 this.colorBySimilarity = flag; 623 colorByAlignmentBlock = false; 624 this.repaint(); 625 } 626 627 628 private void selectEQR() { 629 630 selection.clear(); 631 632 List<Integer> pos1 = DisplayAFP.getEQRAlignmentPos(afpChain); 633 634 for (int pos : pos1){ 635 selection.flip(pos); 636 } 637 mouseMoLi.triggerSelectionLocked(true); 638 updateJmolDisplay(); 639 this.repaint(); 640 641 } 642 643 public Atom[] getCa1() { 644 return ca1; 645 } 646 647 648 public void setCa1(Atom[] ca1) { 649 this.ca1 = ca1; 650 } 651 652 653 public Atom[] getCa2() { 654 return ca2; 655 } 656 657 658 public void setCa2(Atom[] ca2) { 659 this.ca2 = ca2; 660 } 661 662 663}