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 * Created on Oct 6, 2009 021 * Author: Andreas Prlic 022 * 023 */ 024 025package org.biojava.nbio.structure.align.gui.jmol; 026 027import org.biojava.nbio.structure.*; 028import org.biojava.nbio.structure.align.gui.JPrintPanel; 029import org.biojava.nbio.structure.domain.LocalProteinDomainParser; 030import org.biojava.nbio.structure.domain.pdp.Domain; 031import org.biojava.nbio.structure.domain.pdp.Segment; 032import org.biojava.nbio.structure.gui.util.color.ColorUtils; 033import org.biojava.nbio.structure.jama.Matrix; 034import org.biojava.nbio.structure.scop.ScopDatabase; 035import org.biojava.nbio.structure.scop.ScopDomain; 036import org.biojava.nbio.structure.scop.ScopInstallation; 037import org.jmol.adapter.smarter.SmarterJmolAdapter; 038import org.jmol.api.JmolAdapter; 039import org.jmol.api.JmolStatusListener; 040import org.jmol.api.JmolViewer; 041import org.jmol.util.LoggerInterface; 042import org.slf4j.Logger; 043import org.slf4j.LoggerFactory; 044 045import javax.swing.*; 046 047import java.awt.*; 048import java.awt.event.ActionEvent; 049import java.awt.event.ActionListener; 050import java.text.DecimalFormat; 051import java.util.List; 052 053 054public class JmolPanel 055extends JPrintPanel 056implements ActionListener 057{ 058 private static final Logger logger = LoggerFactory.getLogger(JmolPanel.class); 059 060 private static final long serialVersionUID = -3661941083797644242L; 061 062 private JmolViewer viewer; 063 private JmolAdapter adapter; 064 JmolStatusListener statusListener; 065 final Dimension currentSize = new Dimension(); 066 final Rectangle rectClip = new Rectangle(); 067 068 Structure structure; 069 070 public JmolPanel() { 071 super(); 072 statusListener = new MyJmolStatusListener(); 073 adapter = new SmarterJmolAdapter(); 074 JmolLoggerAdapter jmolLogger = new JmolLoggerAdapter(LoggerFactory.getLogger(org.jmol.api.JmolViewer.class)); 075 org.jmol.util.Logger.setLogger(jmolLogger); 076 org.jmol.util.Logger.setLogLevel( jmolLogger.getLogLevel() ); 077 viewer = JmolViewer.allocateViewer(this, 078 adapter, 079 null,null,null,null, 080 statusListener); 081 082 } 083 084 @Override 085 public void paint(Graphics g) { 086 087 getSize(currentSize); 088 g.getClipBounds(rectClip); 089 viewer.renderScreenImage(g, currentSize, rectClip); 090 } 091 092 public void evalString(String rasmolScript){ 093 094 viewer.evalString(rasmolScript); 095 096 } 097 098 public void openStringInline(String pdbFile){ 099 viewer.openStringInline(pdbFile); 100 101 } 102 public JmolViewer getViewer() { 103 return viewer; 104 } 105 106 public JmolAdapter getAdapter(){ 107 return adapter; 108 } 109 110 public JmolStatusListener getStatusListener(){ 111 return statusListener; 112 } 113 public void executeCmd(String rasmolScript) { 114 viewer.evalString(rasmolScript); 115 } 116 117 public void setStructure(Structure s) 118 { 119 this.structure = s; 120 String serialized = s.toMMCIF(); 121 viewer.openStringInline(serialized); 122 evalString("save STATE state_1"); 123 } 124 125 /** assign a custom color to the Jmol chains command. 126 * 127 */ 128 public void jmolColorByChain(){ 129 String script = 130 "function color_by_chain(objtype, color_list) {"+ String.format("%n") + 131 ""+ String.format("%n") + 132 " if (color_list) {"+ String.format("%n") + 133 " if (color_list.type == \"string\") {"+ String.format("%n") + 134 " color_list = color_list.split(\",\").trim();"+ String.format("%n") + 135 " }"+ String.format("%n") + 136 " } else {"+ String.format("%n") + 137 " color_list = [\"104BA9\",\"AA00A2\",\"C9F600\",\"FFA200\",\"284A7E\",\"7F207B\",\"9FB82E\",\"BF8B30\",\"052D6E\",\"6E0069\",\"83A000\",\"A66A00\",\"447BD4\",\"D435CD\",\"D8FA3F\",\"FFBA40\",\"6A93D4\",\"D460CF\",\"E1FA71\",\"FFCC73\"];"+ String.format("%n") + 138 " }"+ String.format("%n") + 139 140 " var cmd2 = \"\";"+ String.format("%n") + 141 142 " if (!objtype) {"+ String.format("%n") + 143 " var type_list = [ \"backbone\",\"cartoon\",\"dots\",\"halo\",\"label\",\"meshribbon\",\"polyhedra\",\"rocket\",\"star\",\"strand\",\"strut\",\"trace\"];"+ String.format("%n") + 144 " cmd2 = \"color \" + type_list.join(\" none; color \") + \" none;\";"+ String.format("%n") + 145 " objtype = \"atoms\";"+ String.format("%n") + 146 147 " }"+ String.format("%n") + 148 149 " var chain_list = script(\"show chain\").trim().lines;"+ String.format("%n") + 150 " var chain_count = chain_list.length;"+ String.format("%n") + 151 152 " var color_count = color_list.length;"+ String.format("%n") + 153 " var sel = {selected};"+ String.format("%n") + 154 " var cmds = \"\";"+ String.format("%n") + 155 156 157 " for (var chain_number=1; chain_number<=chain_count; chain_number++) {"+ String.format("%n") + 158 " // remember, Jmol arrays start with 1, but % can return 0"+ String.format("%n") + 159 " cmds += \"select sel and :\" + chain_list[chain_number] + \";color \" + objtype + \" [x\" + color_list[(chain_number-1) % color_count + 1] + \"];\" + cmd2;"+ String.format("%n") + 160 " }"+ String.format("%n") + 161 " script INLINE @{cmds + \"select sel\"}"+ String.format("%n") + 162 "}"; 163 164 executeCmd(script); 165 } 166 167 /** The user selected one of the Combo boxes... 168 * 169 * @param event an ActionEvent 170 */ 171 @Override 172 public void actionPerformed(ActionEvent event) { 173 174 Object mysource = event.getSource(); 175 176 if ( ! (mysource instanceof JComboBox )) { 177 super.actionPerformed(event); 178 return; 179 } 180 181 @SuppressWarnings("unchecked") 182 JComboBox<String> source = (JComboBox<String>) event.getSource(); 183 String value = source.getSelectedItem().toString(); 184 evalString("save selection; "); 185 186 String selectLigand = "select ligand;wireframe 0.16;spacefill 0.5; color cpk ;"; 187 188 if ( value.equals("Cartoon")){ 189 String script = "hide null; select all; spacefill off; wireframe off; backbone off;" + 190 " cartoon on; " + 191 " select ligand; wireframe 0.16;spacefill 0.5; color cpk; " + 192 " select *.FE; spacefill 0.7; color cpk ; " + 193 " select *.CU; spacefill 0.7; color cpk ; " + 194 " select *.ZN; spacefill 0.7; color cpk ; " + 195 " select all; "; 196 this.executeCmd(script); 197 } else if (value.equals("Backbone")){ 198 String script = "hide null; select all; spacefill off; wireframe off; backbone 0.4;" + 199 " cartoon off; " + 200 " select ligand; wireframe 0.16;spacefill 0.5; color cpk; " + 201 " select *.FE; spacefill 0.7; color cpk ; " + 202 " select *.CU; spacefill 0.7; color cpk ; " + 203 " select *.ZN; spacefill 0.7; color cpk ; " + 204 " select all; "; 205 this.executeCmd(script); 206 } else if (value.equals("CPK")){ 207 String script = "hide null; select all; spacefill off; wireframe off; backbone off;" + 208 " cartoon off; cpk on;" + 209 " select ligand; wireframe 0.16;spacefill 0.5; color cpk; " + 210 " select *.FE; spacefill 0.7; color cpk ; " + 211 " select *.CU; spacefill 0.7; color cpk ; " + 212 " select *.ZN; spacefill 0.7; color cpk ; " + 213 " select all; "; 214 this.executeCmd(script); 215 216 } else if (value.equals("Ligands")){ 217 this.executeCmd("restrict ligand; cartoon off; wireframe on; display selected;"); 218 } else if (value.equals("Ligands and Pocket")){ 219 this.executeCmd(" select within (6.0,ligand); cartoon off; wireframe on; backbone off; display selected; "); 220 } else if ( value.equals("Ball and Stick")){ 221 String script = "hide null; restrict not water; wireframe 0.2; spacefill 25%;" + 222 " cartoon off; backbone off; " + 223 " select ligand; wireframe 0.16; spacefill 0.5; color cpk; " + 224 " select *.FE; spacefill 0.7; color cpk ; " + 225 " select *.CU; spacefill 0.7; color cpk ; " + 226 " select *.ZN; spacefill 0.7; color cpk ; " + 227 " select all; "; 228 this.executeCmd(script); 229 } else if ( value.equals("By Chain")){ 230 jmolColorByChain(); 231 String script = "hide null; select all;set defaultColors Jmol; color_by_chain(\"cartoon\"); color_by_chain(\"\"); " + selectLigand + "; select all; "; 232 this.executeCmd(script); 233 } else if ( value.equals("Rainbow")) { 234 this.executeCmd("hide null; select all; set defaultColors Jmol; color group; color cartoon group; " + selectLigand + "; select all; " ); 235 } else if ( value.equals("Secondary Structure")){ 236 this.executeCmd("hide null; select all; set defaultColors Jmol; color structure; color cartoon structure;" + selectLigand + "; select all; " ); 237 238 } else if ( value.equals("By Element")){ 239 this.executeCmd("hide null; select all; set defaultColors Jmol; color cpk; color cartoon cpk; " + selectLigand + "; select all; "); 240 } else if ( value.equals("By Amino Acid")){ 241 this.executeCmd("hide null; select all; set defaultColors Jmol; color amino; color cartoon amino; " + selectLigand + "; select all; " ); 242 } else if ( value.equals("Hydrophobicity") ){ 243 this.executeCmd("hide null; set defaultColors Jmol; select hydrophobic; color red; color cartoon red; select not hydrophobic ; color blue ; color cartoon blue; "+ selectLigand+"; select all; "); 244 } else if ( value.equals("Suggest Domains")){ 245 colorByPDP(); 246 } else if ( value.equals("Show SCOP Domains")){ 247 colorBySCOP(); 248 } 249 evalString("restore selection; "); 250 } 251 252 private void colorBySCOP() { 253 254 if ( structure == null) 255 return; 256 257 String pdbId = structure.getPDBCode(); 258 if ( pdbId == null) 259 return; 260 ScopDatabase scop = new ScopInstallation(); 261 262 List<ScopDomain> domains = scop.getDomainsForPDB(pdbId); 263 if ( domains == null) { 264 System.err.println("No SCOP domains found for " + pdbId); 265 return; 266 } 267 int i = -1; 268 for ( ScopDomain domain : domains){ 269 i++; 270 if ( i >= ColorUtils.colorWheel.length) 271 i = 0; 272 Color c1 = ColorUtils.colorWheel[i]; 273 List<String>ranges = domain.getRanges(); 274 275 for (String range : ranges){ 276 logger.debug(range); 277 String[] spl = range.split(":"); 278 String script = " select "; 279 if ( spl.length > 1 ) 280 script += spl[1]+":"+spl[0] +"/1;"; 281 else 282 script += "*" + spl[0]+"/1;"; 283 script += " color [" + c1.getRed() + ","+c1.getGreen() + "," +c1.getBlue()+"];"; 284 script += " color cartoon [" + c1.getRed() + ","+c1.getGreen() + "," +c1.getBlue()+"] ;"; 285 logger.debug(script); 286 evalString(script); 287 288 } 289 } 290 291 292 } 293 294 private void colorByPDP() { 295 logger.debug("colorByPDP"); 296 if ( structure == null) 297 return; 298 299 try { 300 Atom[] ca = StructureTools.getRepresentativeAtomArray(structure); 301 List<Domain> domains = LocalProteinDomainParser.suggestDomains(ca); 302 int i = -1; 303 for ( Domain dom : domains){ 304 i++; 305 if ( i > ColorUtils.colorWheel.length) 306 i = 0; 307 //System.out.println("DOMAIN:" + i + " size:" + dom.size + " " + dom.score); 308 List<Segment> segments = dom.getSegments(); 309 Color c1 = ColorUtils.colorWheel[i]; 310 //float fraction = 0f; 311 for ( Segment s : segments){ 312 //System.out.println(" Segment: " + s); 313 //Color c1 = ColorUtils.rotateHue(c, fraction); 314 // fraction += 1.0/(float)segments.size(); 315 int start = s.getFrom(); 316 int end = s.getTo(); 317 Group startG = ca[start].getGroup(); 318 Group endG = ca[end].getGroup(); 319 logger.debug(" Segment: " +startG.getResidueNumber() +":" + startG.getChainId() + " - " + endG.getResidueNumber()+":"+endG.getChainId() + " " + s); 320 String j1 = startG.getResidueNumber()+""; 321 String j2 = endG.getResidueNumber()+":"+endG.getChainId(); 322 String script = " select " +j1 +"-" +j2 +"/1;"; 323 script += " color [" + c1.getRed() + ","+c1.getGreen() + "," +c1.getBlue()+"];"; 324 script += " color cartoon [" + c1.getRed() + ","+c1.getGreen() + "," +c1.getBlue()+"] ;"; 325 logger.debug(script); 326 evalString(script); 327 } 328 329 } 330 } catch (Exception e){ 331 e.printStackTrace(); 332 } 333 } 334 335 public void rotateJmol(Matrix jmolRotation) { 336 337 if ( jmolRotation != null) { 338 double[] zyz = Calc.getZYZEuler(jmolRotation); 339 DecimalFormat df = new DecimalFormat("0.##"); 340 341 String script = "reset; rotate z " 342 + df.format(zyz[0]) 343 + "; rotate y " 344 + df.format(zyz[1]) 345 +"; rotate z " 346 + df.format(zyz[2])+";"; 347 348 executeCmd(script); 349 350 } 351 } 352 353 /** Clean up this instance for garbage collection, to avoid memory leaks... 354 * 355 */ 356 public void destroy(){ 357 358 executeCmd("zap;"); 359 structure = null; 360 361 viewer = null; 362 adapter = null; 363 } 364 365 public static class JmolLoggerAdapter implements LoggerInterface { 366 private Logger slf; 367 public JmolLoggerAdapter(Logger slf) { 368 this.slf=slf; 369 } 370 public int getLogLevel() { 371 if( slf.isTraceEnabled() ) 372 return org.jmol.util.Logger.LEVEL_MAX; 373 if( slf.isDebugEnabled() ) 374 return org.jmol.util.Logger.LEVEL_DEBUG; 375 if( slf.isInfoEnabled() ) 376 return org.jmol.util.Logger.LEVEL_INFO; 377 if( slf.isWarnEnabled() ) 378 return org.jmol.util.Logger.LEVEL_WARN; 379 if( slf.isErrorEnabled() ) 380 return org.jmol.util.Logger.LEVEL_ERROR; 381 throw new IllegalStateException("Unknown SLF4J error level"); 382 } 383 @Override 384 public void debug(String txt) { 385 slf.debug(txt); 386 } 387 @Override 388 public void info(String txt) { 389 slf.info(txt); 390 } 391 @Override 392 public void warn(String txt) { 393 slf.warn(txt); 394 } 395 @Override 396 public void warnEx(String txt, Throwable e) { 397 slf.warn(txt,e); 398 } 399 @Override 400 public void error(String txt) { 401 slf.error(txt); 402 } 403 @Override 404 public void errorEx(String txt, Throwable e) { 405 slf.error(txt,e); 406 } 407 @Override 408 public void fatal(String txt) { 409 slf.error(txt); 410 } 411 @Override 412 public void fatalEx(String txt, Throwable e) { 413 slf.error(txt,e); 414 } 415 } 416}