/*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2b1)
- * Copyright (C) 2014 The Jalview Authors
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
*
* This file is part of Jalview.
*
*/
package jalview.ext.jmol;
-import jalview.api.AlignmentViewPanel;
-import jalview.api.FeatureRenderer;
-import jalview.api.SequenceRenderer;
-import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
-import jalview.datamodel.PDBEntry;
-import jalview.datamodel.SequenceI;
-import jalview.io.AppletFormatAdapter;
-import jalview.schemes.ColourSchemeI;
-import jalview.schemes.ResidueProperties;
-import jalview.structure.StructureMapping;
-import jalview.structure.StructureMappingcommandSet;
-import jalview.structure.StructureSelectionManager;
-import jalview.structures.models.AAStructureBindingModel;
-import jalview.util.MessageManager;
-
import java.awt.Color;
import java.awt.Container;
import java.awt.event.ComponentEvent;
import java.io.File;
import java.net.URL;
import java.security.AccessControlException;
-import java.util.Enumeration;
import java.util.Hashtable;
+import java.util.List;
import java.util.Map;
import java.util.Vector;
import org.jmol.constant.EnumCallback;
import org.jmol.popup.JmolPopup;
+import jalview.api.AlignmentViewPanel;
+import jalview.api.FeatureRenderer;
+import jalview.api.SequenceRenderer;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceI;
+import jalview.io.AppletFormatAdapter;
+import jalview.schemes.ColourSchemeI;
+import jalview.schemes.ResidueProperties;
+import jalview.structure.AtomSpec;
+import jalview.structure.StructureMappingcommandSet;
+import jalview.structure.StructureSelectionManager;
+import jalview.structures.models.AAStructureBindingModel;
+
public abstract class JalviewJmolBinding extends AAStructureBindingModel
implements JmolStatusListener, JmolSelectionListener,
ComponentListener
{ hiddenCols });
}
+ /**
+ * Construct and send a command to align structures against a reference
+ * structure, based on one or more sequence alignments
+ *
+ * @param _alignment
+ * an array of alignments to process
+ * @param _refStructure
+ * an array of corresponding reference structures (index into pdb
+ * file array); if a negative value is passed, the first PDB file
+ * mapped to an alignment sequence is used as the reference for
+ * superposition
+ * @param _hiddenCols
+ * an array of corresponding hidden columns for each alignment
+ */
public void superposeStructures(AlignmentI[] _alignment,
int[] _refStructure, ColumnSelection[] _hiddenCols)
{
- assert (_alignment.length == _refStructure.length && _alignment.length != _hiddenCols.length);
-
String[] files = getPdbFile();
- // check to see if we are still waiting for Jmol files
- long starttime = System.currentTimeMillis();
- boolean waiting = true;
- do
- {
- waiting = false;
- for (String file : files)
- {
- try
- {
- // HACK - in Jalview 2.8 this call may not be threadsafe so we catch
- // every possible exception
- StructureMapping[] sm = getSsm().getMapping(file);
- if (sm == null || sm.length == 0)
- {
- waiting = true;
- }
- } catch (Exception x)
- {
- waiting = true;
- } catch (Error q)
- {
- waiting = true;
- }
- }
- // we wait around for a reasonable time before we give up
- } while (waiting
- && System.currentTimeMillis() < (10000 + 1000 * files.length + starttime));
- if (waiting)
+
+ if (!waitForFileLoad(files))
{
- System.err
- .println("RUNTIME PROBLEM: Jmol seems to be taking a long time to process all the structures.");
return;
}
- StringBuffer selectioncom = new StringBuffer();
+
+ StringBuilder selectioncom = new StringBuilder(256);
// In principle - nSeconds specifies the speed of animation for each
// superposition - but is seems to behave weirdly, so we don't specify it.
String nSeconds = " ";
+ refStructure);
refStructure = -1;
}
- if (refStructure < -1)
- {
- refStructure = -1;
- }
- StringBuffer command = new StringBuffer();
+ /*
+ * 'matched' array will hold 'true' for visible alignment columns where
+ * all sequences have a residue with a mapping to the PDB structure
+ */
boolean matched[] = new boolean[alignment.getWidth()];
for (int m = 0; m < matched.length; m++)
{
-
matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;
}
- int commonrpositions[][] = new int[files.length][alignment.getWidth()];
- String isel[] = new String[files.length];
- // reference structure - all others are superposed in it
- String[] targetC = new String[files.length];
- String[] chainNames = new String[files.length];
- for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
+ SuperposeData[] structures = new SuperposeData[files.length];
+ for (int f = 0; f < files.length; f++)
{
- StructureMapping[] mapping = getSsm().getMapping(files[pdbfnum]);
- // RACE CONDITION - getMapping only returns Jmol loaded filenames once
- // Jmol callback has completed.
- if (mapping == null || mapping.length < 1)
- {
- throw new Error(MessageManager.getString("error.implementation_error_jmol_getting_data"));
- }
- int lastPos = -1;
- final int sequenceCountForPdbFile = getSequence()[pdbfnum].length;
- for (int s = 0; s < sequenceCountForPdbFile; s++)
- {
- for (int sp, m = 0; m < mapping.length; m++)
- {
- if (mapping[m].getSequence() == getSequence()[pdbfnum][s]
- && (sp = alignment.findIndex(getSequence()[pdbfnum][s])) > -1)
- {
- if (refStructure == -1)
- {
- refStructure = pdbfnum;
- }
- SequenceI asp = alignment.getSequenceAt(sp);
- for (int r = 0; r < matched.length; r++)
- {
- if (!matched[r])
- {
- continue;
- }
- matched[r] = false; // assume this is not a good site
- if (r >= asp.getLength())
- {
- continue;
- }
-
- if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
- {
- // no mapping to gaps in sequence
- continue;
- }
- int t = asp.findPosition(r); // sequence position
- int apos = mapping[m].getAtomNum(t);
- int pos = mapping[m].getPDBResNum(t);
-
- if (pos < 1 || pos == lastPos)
- {
- // can't align unmapped sequence
- continue;
- }
- matched[r] = true; // this is a good ite
- lastPos = pos;
- // just record this residue position
- commonrpositions[pdbfnum][r] = pos;
- }
- // create model selection suffix
- isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";
- if (mapping[m].getChain() == null
- || mapping[m].getChain().trim().length() == 0)
- {
- targetC[pdbfnum] = "";
- }
- else
- {
- targetC[pdbfnum] = ":" + mapping[m].getChain();
- }
- chainNames[pdbfnum] = mapping[m].getPdbId()
- + targetC[pdbfnum];
- // move on to next pdb file
- s = getSequence()[pdbfnum].length;
- break;
- }
- }
- }
+ structures[f] = new SuperposeData(alignment.getWidth());
}
- // TODO: consider bailing if nmatched less than 4 because superposition
- // not
- // well defined.
- // TODO: refactor superposable position search (above) from jmol selection
- // construction (below)
+ /*
+ * Calculate the superposable alignment columns ('matched'), and the
+ * corresponding structure residue positions (structures.pdbResNo)
+ */
+ int candidateRefStructure = findSuperposableResidues(alignment,
+ matched, structures);
+ if (refStructure < 0)
+ {
+ /*
+ * If no reference structure was specified, pick the first one that has
+ * a mapping in the alignment
+ */
+ refStructure = candidateRefStructure;
+ }
String[] selcom = new String[files.length];
int nmatched = 0;
- // generate select statements to select regions to superimpose structures
+ for (boolean b : matched)
+ {
+ if (b)
+ {
+ nmatched++;
+ }
+ }
+ if (nmatched < 4)
+ {
+ // TODO: bail out here because superposition illdefined?
+ }
+
+ /*
+ * generate select statements to select regions to superimpose structures
+ */
{
for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
{
- String chainCd = targetC[pdbfnum];
+ String chainCd = ":" + structures[pdbfnum].chain;
int lpos = -1;
boolean run = false;
- StringBuffer molsel = new StringBuffer();
+ StringBuilder molsel = new StringBuilder();
molsel.append("{");
for (int r = 0; r < matched.length; r++)
{
if (matched[r])
{
- if (pdbfnum == 0)
- {
- nmatched++;
- }
- if (lpos != commonrpositions[pdbfnum][r] - 1)
+ int pdbResNo = structures[pdbfnum].pdbResNo[r];
+ if (lpos != pdbResNo - 1)
{
// discontinuity
if (lpos != -1)
{
molsel.append(lpos);
molsel.append(chainCd);
- // molsel.append("} {");
molsel.append("|");
}
+ run = false;
}
else
{
}
run = true;
}
- lpos = commonrpositions[pdbfnum][r];
- // molsel.append(lpos);
+ lpos = pdbResNo;
}
}
- // add final selection phrase
+ /*
+ * add final selection phrase
+ */
if (lpos != -1)
{
molsel.append(lpos);
}
}
}
+ StringBuilder command = new StringBuilder(256);
for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
{
if (pdbfnum == refStructure || selcom[pdbfnum] == null
}
command.append("echo ");
command.append("\"Superposing (");
- command.append(chainNames[pdbfnum]);
+ command.append(structures[pdbfnum].pdbId);
command.append(") against reference (");
- command.append(chainNames[refStructure]);
+ command.append(structures[refStructure].pdbId);
command.append(")\";\ncompare " + nSeconds);
command.append("{");
- command.append(1 + pdbfnum);
+ command.append(Integer.toString(1 + pdbfnum));
command.append(".1} {");
- command.append(1 + refStructure);
- command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
-
- // form the matched pair strings
- String sep = "";
- for (int s = 0; s < 2; s++)
- {
- command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
- }
+ command.append(Integer.toString(1 + refStructure));
+ // conformation=1 excludes alternate locations for CA (JAL-1757)
+ command.append(".1} SUBSET {(*.CA | *.P) and conformation=1} ATOMS ");
+
+ // for (int s = 0; s < 2; s++)
+ // {
+ // command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
+ // }
+ command.append(selcom[pdbfnum]);
+ command.append(selcom[refStructure]);
command.append(" ROTATE TRANSLATE;\n");
}
if (selectioncom.length() > 0)
evalStateCommand("select *; cartoons off; backbone; select ("
+ selectioncom.toString() + "); cartoons; ");
// selcom.append("; ribbons; ");
+ String cmdString = command.toString();
System.out
- .println("Superimpose command(s):\n" + command.toString());
+.println("Superimpose command(s):\n" + cmdString);
- evalStateCommand(command.toString());
+ evalStateCommand(cmdString);
}
}
if (selectioncom.length() > 0)
// ////////////////////////////////
// /StructureListener
+ @Override
public synchronized String[] getPdbFile()
{
if (viewer == null)
jmolpopup.show(x, y);
}
+ /**
+ * Highlight zero, one or more atoms on the structure
+ */
+ @Override
+ public void highlightAtoms(List<AtomSpec> atoms)
+ {
+ if (atoms != null)
+ {
+ for (AtomSpec atom : atoms)
+ {
+ highlightAtom(atom.getAtomIndex(), atom.getPdbResNum(),
+ atom.getChain(), atom.getPdbFile());
+ }
+ }
+ }
+
// jmol/ssm only
public void highlightAtom(int atomIndex, int pdbResNum, String chain,
String pdbfile)
return;
}
- String res;
- int index;
- Color col;
jmolHistory(false);
- // TODO: Switch between nucleotide or aa selection expressions
- Enumeration en = ResidueProperties.aa3Hash.keys();
- StringBuffer command = new StringBuffer("select *;color white;");
- while (en.hasMoreElements())
+ StringBuilder command = new StringBuilder(128);
+ command.append("select *;color white;");
+ List<String> residueSet = ResidueProperties.getResidues(isNucleotide(),
+ false);
+ for (String res : residueSet)
{
- res = en.nextElement().toString();
- index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();
- if (index > 20)
- {
- continue;
- }
-
- col = cs.findColour(ResidueProperties.aa[index].charAt(0));
-
+ Color col = cs.findColour(res.charAt(0));
command.append("select " + res + ";color[" + col.getRed() + ","
+ col.getGreen() + "," + col.getBlue() + "];");
}
jmolHistory(true);
}
- /**
- *
- * @param pdbfile
- * @return text report of alignment between pdbfile and any associated
- * alignment sequences
- */
- public String printMapping(String pdbfile)
- {
- return getSsm().printMapping(pdbfile);
- }
-
@Override
public void resizeInnerPanel(String data)
{