public void stopListening()
{
- sendChimeraCommand("listen stop models ; listen stop selection ", false);
+ // TODO send this command when viewer connection is closed in Jalview
+ String command = isChimeraX
+ ? "info notify stop models jalview; info notify stop selection jalview"
+ : "listen stop models ; listen stop selection ";
+ sendChimeraCommand(command, false);
}
/**
*/
public void startListening(String uri)
{
- sendChimeraCommand("listen start models url " + uri
- + ";listen start select prefix SelectionChanged url " + uri,
- false);
+ String command = isChimeraX
+ ? ("info notify start models prefix ModelChanged jalview url "
+ + uri
+ + "; info notify start selection jalview prefix SelectionChanged url "
+ + uri)
+ : ("listen start models url " + uri
+ + ";listen start select prefix SelectionChanged url "
+ + uri);
+ sendChimeraCommand(command, false);
}
/**
public List<String> getSelectedResidueSpecs()
{
List<String> selectedResidues = new ArrayList<>();
- List<String> chimeraReply = sendChimeraCommand(
- "list selection level residue", true);
+
+ /*
+ * skip for now if ChimeraX - times out
+ */
+ if (isChimeraX)
+ {
+ return selectedResidues;
+ }
+
+ // in fact 'listinfo' (undocumented) works in ChimeraX
+ String command = (isChimeraX ? "info" : "list")
+ + " selection level residue";
+ List<String> chimeraReply = sendChimeraCommand(command, true);
if (chimeraReply != null)
{
/*
- * expect 0, 1 or more lines of the format
+ * expect 0, 1 or more lines of the format either
+ * Chimera:
* residue id #0:43.A type GLY
- * where we are only interested in the atomspec #0.43.A
+ * ChimeraX:
+ * residue id /A:89 name THR index 88
+ * We are only interested in the atomspec (third token of the reply)
*/
for (String inputLine : chimeraReply)
{
String[] inputLineParts = inputLine.split("\\s+");
- if (inputLineParts.length == 5)
+ if (inputLineParts.length >= 5)
{
selectedResidues.add(inputLineParts[2]);
}
public List<String> getAttrList()
{
List<String> attributes = new ArrayList<>();
- final List<String> reply = sendChimeraCommand("list resattr", true);
+ String command = (isChimeraX ? "info " : "list") + "resattr";
+ final List<String> reply = sendChimeraCommand(command, true);
if (reply != null)
{
for (String inputLine : reply)
{
// dumpRequest(request);
String message = request.getParameter(CHIMERA_NOTIFICATION);
- if (SELECTION_CHANGED.equals(message))
+ if (message == null)
{
- this.chimeraBinding.highlightChimeraSelection();
+ message = request.getParameter("chimerax_notification");
}
- else if (message != null && message.startsWith(MODEL_CHANGED))
+ if (message != null)
{
- processModelChanged(message.substring(MODEL_CHANGED.length()));
- }
- else
- {
- System.err.println("Unexpected chimeraNotification: " + message);
+ if (message.startsWith("SelectionChanged"))
+ {
+ this.chimeraBinding.highlightChimeraSelection();
+ }
+ else if (message.startsWith(MODEL_CHANGED))
+ {
+ System.err.println(message);
+ processModelChanged(message.substring(MODEL_CHANGED.length()));
+ }
+ else
+ {
+ System.err.println("Unexpected chimeraNotification: " + message);
+ }
}
}
import java.util.BitSet;
import java.util.Collections;
import java.util.Hashtable;
+import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public void colourByCharge()
{
colourBySequence = false;
- String command = "color white;color red ::ASP;color red ::GLU;color blue ::LYS;color blue ::ARG;color yellow ::CYS";
+ String command = viewer.isChimeraX()
+ ? "color white;color :ASP,GLU red;color :LYS,ARG blue;color :CYS yellow"
+ : "color white;color red ::ASP;color red ::GLU;color blue ::LYS;color blue ::ARG;color yellow ::CYS";
sendAsynchronousCommand(command, COLOURING_CHIMERA);
}
refreshPdbEntries();
StringBuilder selectioncom = new StringBuilder(256);
+ boolean chimeraX = viewer.isChimeraX();
for (int a = 0; a < _alignment.length; a++)
{
int refStructure = _refStructure[a];
String[] selcom = new String[files.length];
for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
{
+ final int modelNo = pdbfnum + (chimeraX ? 1 : 0);
+ // todo correct resolution to model number
String chainCd = "." + structures[pdbfnum].chain;
int lpos = -1;
boolean run = false;
StringBuilder molsel = new StringBuilder();
+ if (chimeraX)
+ {
+ molsel.append("/" + structures[pdbfnum].chain + ":");
+ }
int nextColumnMatch = matched.nextSetBit(0);
while (nextColumnMatch != -1)
if (lpos != -1)
{
molsel.append(String.valueOf(lpos));
- molsel.append(chainCd);
+ if (!chimeraX)
+ {
+ molsel.append(chainCd);
+ }
molsel.append(",");
}
run = false;
if (lpos != -1)
{
molsel.append(String.valueOf(lpos));
- molsel.append(chainCd);
+ if (!chimeraX)
+ {
+ molsel.append(chainCd);
+ }
}
if (molsel.length() > 1)
{
selcom[pdbfnum] = molsel.toString();
- selectioncom.append("#").append(String.valueOf(pdbfnum))
- .append(":");
+ selectioncom.append("#").append(String.valueOf(modelNo));
+ if (!chimeraX)
+ {
+ selectioncom.append(":");
+ }
selectioncom.append(selcom[pdbfnum]);
- selectioncom.append(" ");
+ // selectioncom.append(" ");
if (pdbfnum < files.length - 1)
{
- selectioncom.append("| ");
+ selectioncom.append("|");
}
}
else
StringBuilder command = new StringBuilder(256);
for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
{
+ final int modelNo = pdbfnum + (chimeraX ? 1 : 0);
if (pdbfnum == refStructure || selcom[pdbfnum] == null
|| selcom[refStructure] == null)
{
* @see
* https://www.cgl.ucsf.edu/chimera/docs/UsersGuide/midas/match.html
*/
- command.append("match ").append(getModelSpec(pdbfnum)).append(":");
+ command.append(chimeraX ? "align " : "match ");
+ command.append(getModelSpec(modelNo));
+ if (!chimeraX)
+ {
+ command.append(":");
+ }
command.append(selcom[pdbfnum]);
command.append("@").append(
structures[pdbfnum].isRna ? PHOSPHORUS : ALPHACARBON);
- // JAL-1757 exclude alternate CA locations
- command.append(NO_ALTLOCS);
- command.append(" ").append(getModelSpec(refStructure)).append(":");
+ // JAL-1757 exclude alternate CA locations - ChimeraX syntax tbd
+ if (!chimeraX)
+ {
+ command.append(NO_ALTLOCS);
+ }
+ command.append(chimeraX ? " toAtoms " : " ")
+ .append(getModelSpec(refStructure + (chimeraX ? 1 : 0)));
+ if (!chimeraX)
+ {
+ command.append(":");
+ }
command.append(selcom[refStructure]);
command.append("@").append(
structures[refStructure].isRna ? PHOSPHORUS : ALPHACARBON);
- command.append(NO_ALTLOCS);
+ if (!chimeraX)
+ {
+ command.append(NO_ALTLOCS);
+ }
}
if (selectioncom.length() > 0)
{
System.out.println(
"Superimpose command(s):\n" + command.toString());
}
- allComs.append("~display all; chain @CA|P; ribbon ")
- .append(selectioncom.toString())
- .append(";" + command.toString());
+ // allComs.append("~display all; ");
+ // if (chimeraX)
+ // {
+ // allComs.append("show ").append(selectioncom.toString())
+ // .append(" pbonds");
+ // }
+ // else
+ // {
+ // allComs.append("chain @CA|P; ribbon ");
+ // allComs.append(selectioncom.toString());
+ // }
+ if (allComs.length() > 0) {
+ allComs.append(";");
+ }
+ allComs.append(command.toString());
}
}
{
System.out.println("Select regions:\n" + selectioncom.toString());
}
- allComs.append("; ~display all; chain @CA|P; ribbon ")
- .append(selectioncom.toString()).append("; focus");
+ allComs.append(";~display all; ");
+ if (chimeraX)
+ {
+ allComs.append("show @CA|P pbonds; show ")
+ .append(selectioncom.toString()).append(" ribbons; view");
+ }
+ else
+ {
+ allComs.append("chain @CA|P; ribbon ; focus");
+ allComs.append(selectioncom.toString());
+ }
+ // allComs.append("; ~display all; chain @CA|P; ribbon ")
+ // .append(selectioncom.toString()).append("; focus");
List<String> chimeraReplies = sendChimeraCommand(allComs.toString(),
true);
for (String reply : chimeraReplies)
{
if (pdbfnum < 0 || pdbfnum >= getPdbCount())
{
- return "";
+ return "#" + pdbfnum; // temp hack for ChimeraX
}
/*
protected List<AtomSpec> convertStructureResiduesToAlignment(
List<String> structureSelection)
{
+ boolean chimeraX = viewer.isChimeraX();
List<AtomSpec> atomSpecs = new ArrayList<>();
for (String atomSpec : structureSelection)
{
try
{
- AtomSpec spec = AtomSpec.fromChimeraAtomspec(atomSpec);
+ AtomSpec spec = AtomSpec.fromChimeraAtomspec(atomSpec, chimeraX);
String pdbfilename = getPdbFileForModel(spec.getModelNumber());
spec.setPdbFile(pdbfilename);
atomSpecs.add(spec);
return;
}
- // Chimera expects RBG values in the range 0-1
- final double normalise = 255D;
viewerCommandHistory(false);
StringBuilder command = new StringBuilder(128);
List<String> residueSet = ResidueProperties.getResidues(isNucleotide(),
false);
+
+ /*
+ * concatenate colour commands, one per residue symbol
+ * Chimera format: color 0.000000,0.372549,0.627451 ::VAL
+ * ChimeraX format: color :VAL rgb(73,73,182)
+ */
+ boolean chimeraX = viewer.isChimeraX();
for (String resName : residueSet)
{
char res = resName.length() == 3
? ResidueProperties.getSingleCharacterCode(resName)
: resName.charAt(0);
Color col = cs.findColour(res, 0, null, null, 0f);
- command.append("color " + col.getRed() / normalise + ","
- + col.getGreen() / normalise + "," + col.getBlue() / normalise
- + " ::" + resName + ";");
+ command.append("color ");
+ String colorSpec = getRgbDescriptor(col, chimeraX);
+ if (chimeraX)
+ {
+ command.append(":").append(resName).append(" ").append(colorSpec);
+ }
+ else
+ {
+ command.append(colorSpec).append(" ::").append(resName);
+ }
+ command.append(";");
}
sendAsynchronousCommand(command.toString(), COLOURING_CHIMERA);
public void setBackgroundColour(Color col)
{
viewerCommandHistory(false);
- double normalise = 255D;
- final String command = "background solid " + col.getRed() / normalise
- + "," + col.getGreen() / normalise + ","
- + col.getBlue() / normalise + ";";
+ String command = "set bgColor "
+ + getRgbDescriptor(col, viewer.isChimeraX());
viewer.sendChimeraCommand(command, false);
viewerCommandHistory(true);
}
/**
+ * Answers the Chimera/X format for RGB values of the given colour.
+ *
+ * <pre>
+ * Chimera: r,g,b with values scaled [0=1]
+ * ChimeraX: rgb(r,g,b) with values scaled 0-255
+ * </pre>
+ *
+ * @param col
+ * @param chimeraX
+ * @return
+ */
+ private static String getRgbDescriptor(Color col, boolean chimeraX)
+ {
+ if (chimeraX)
+ {
+ return String.format("rgb(%d,%d,%d)", col.getRed(), col.getGreen(),
+ col.getBlue());
+ }
+ else
+ {
+ double scale = 255D;
+ return String.format("%f,%f,%f", col.getRed() / scale,
+ col.getGreen() / scale, col.getBlue() / scale);
+ }
+ }
+
+ /**
* Ask Chimera to save its session to the given file. Returns true if
* successful, else false.
*
*/
public void focusView()
{
- sendChimeraCommand("focus", false);
+ sendChimeraCommand(viewer.isChimeraX() ? "view" : "focus", false);
}
/**
{
boolean featureAdded = false;
String featureGroup = getViewerFeatureGroup();
+ boolean chimeraX = viewer.isChimeraX();
for (String residue : residues)
{
try
{
- spec = AtomSpec.fromChimeraAtomspec(atomSpec);
+ spec = AtomSpec.fromChimeraAtomspec(atomSpec, chimeraX);
} catch (IllegalArgumentException e)
{
System.err.println("Problem parsing atomspec " + atomSpec);
}
return -1;
}
+
+ /**
+ * Answers a (possibly empty) list of attribute names in Chimera[X], excluding
+ * any which were added from Jalview
+ *
+ * @return
+ */
+ public List<String> getChimeraAttributes()
+ {
+ List<String> atts = viewer.getAttrList();
+ Iterator<String> it = atts.iterator();
+ while (it.hasNext())
+ {
+ if (it.next().startsWith(ChimeraCommands.NAMESPACE_PREFIX))
+ {
+ /*
+ * attribute added from Jalview - exclude it
+ */
+ it.remove();
+ }
+ }
+ return atts;
+ }
}
import jalview.datamodel.AlignmentI;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SequenceI;
-import jalview.ext.rbvi.chimera.ChimeraCommands;
import jalview.ext.rbvi.chimera.JalviewChimeraBinding;
import jalview.gui.StructureViewer.ViewerType;
import jalview.io.DataSourceType;
*/
protected void buildAttributesMenu(JMenu attributesMenu)
{
- List<String> atts = jmb.sendChimeraCommand("list resattr", true);
- if (atts == null)
- {
- return;
- }
+ List<String> atts = jmb.getChimeraAttributes();
attributesMenu.removeAll();
Collections.sort(atts);
- for (String att : atts)
+ for (String attName : atts)
{
- final String attName = att.split(" ")[1];
-
- /*
- * ignore 'jv_*' attributes, as these are Jalview features that have
- * been transferred to residue attributes in Chimera!
- */
- if (!attName.startsWith(ChimeraCommands.NAMESPACE_PREFIX))
+ JMenuItem menuItem = new JMenuItem(attName);
+ menuItem.addActionListener(new ActionListener()
{
- JMenuItem menuItem = new JMenuItem(attName);
- menuItem.addActionListener(new ActionListener()
+ @Override
+ public void actionPerformed(ActionEvent e)
{
- @Override
- public void actionPerformed(ActionEvent e)
- {
- getChimeraAttributes(attName);
- }
- });
- attributesMenu.add(menuItem);
- }
+ getChimeraAttributes(attName);
+ }
+ });
+ attributesMenu.add(menuItem);
}
}
* Parses a Chimera atomspec e.g. #1:12.A to construct an AtomSpec model (with
* null pdb file name)
*
+ * <pre>
+ * Chimera format:
+ * #1.2:12-20.A model 1, submodel 2, chain A, atoms 12-20
+ * ChimeraX format:
+ * #1.2/A:12-20
+ * </pre>
+ *
* @param spec
+ * @param chimeraX
* @return
* @throw IllegalArgumentException if the spec cannot be parsed, or represents
* more than one residue
+ * @see https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/frameatom_spec.html
+ * @see http://rbvi.ucsf.edu/chimerax/docs/user/commands/atomspec.html
*/
- public static AtomSpec fromChimeraAtomspec(String spec)
+ public static AtomSpec fromChimeraAtomspec(String spec, boolean chimeraX)
{
- int colonPos = spec.indexOf(":");
- if (colonPos == -1)
+ int modelSeparatorPos = spec.indexOf(chimeraX ? "/" : ":");
+ if (modelSeparatorPos == -1)
{
throw new IllegalArgumentException(spec);
}
int hashPos = spec.indexOf("#");
- if (hashPos == -1 && colonPos != 0)
+ if (hashPos == -1 && modelSeparatorPos != 0)
{
// # is missing but something precedes : - reject
throw new IllegalArgumentException(spec);
}
- String modelSubmodel = spec.substring(hashPos + 1, colonPos);
- int dotPos = modelSubmodel.indexOf(".");
+ String modelSubmodel = spec.substring(hashPos + 1, modelSeparatorPos);
int modelId = 0;
try
{
- modelId = Integer.valueOf(dotPos == -1 ? modelSubmodel
- : modelSubmodel.substring(0, dotPos));
+ int subModelPos = modelSubmodel.indexOf(".");
+ modelId = Integer.valueOf(
+ subModelPos > 0 ? modelSubmodel.substring(0, subModelPos)
+ : modelSubmodel);
} catch (NumberFormatException e)
{
// ignore, default to model 0
}
- String residueChain = spec.substring(colonPos + 1);
- dotPos = residueChain.indexOf(".");
+ /*
+ * now process what follows the model, either
+ * Chimera: atoms.chain
+ * ChimeraX: chain:atoms
+ */
+ String atomsAndChain = spec.substring(modelSeparatorPos + 1);
+ String[] tokens = atomsAndChain.split(chimeraX ? "\\:" : "\\.");
+ String atoms = tokens.length == 1 ? atomsAndChain
+ : (chimeraX ? tokens[1] : tokens[0]);
int resNum = 0;
try
{
- resNum = Integer.parseInt(dotPos == -1 ? residueChain
- : residueChain.substring(0, dotPos));
+ resNum = Integer.parseInt(atoms);
} catch (NumberFormatException e)
{
// could be a range e.g. #1:4-7.B
throw new IllegalArgumentException(spec);
}
- String chainId = dotPos == -1 ? "" : residueChain.substring(dotPos + 1);
+ String chainId = tokens.length == 1 ? ""
+ : (chimeraX ? tokens[0] : tokens[1]);
return new AtomSpec(modelId, chainId, resNum, 0);
}
public class AtomSpecTest
{
@Test
- public void testFromChimeraAtomSpec()
+ public void testFromChimeraAtomSpec_chimera()
{
- AtomSpec as = AtomSpec.fromChimeraAtomspec("#1:12.B");
+ AtomSpec as = AtomSpec.fromChimeraAtomspec("#1:12.B", false);
assertEquals(as.getModelNumber(), 1);
assertEquals(as.getPdbResNum(), 12);
assertEquals(as.getChain(), "B");
assertNull(as.getPdbFile());
// no model - default to zero
- as = AtomSpec.fromChimeraAtomspec(":13.C");
+ as = AtomSpec.fromChimeraAtomspec(":13.C", false);
assertEquals(as.getModelNumber(), 0);
assertEquals(as.getPdbResNum(), 13);
assertEquals(as.getChain(), "C");
assertNull(as.getPdbFile());
// model.submodel
- as = AtomSpec.fromChimeraAtomspec("#3.2:15");
+ as = AtomSpec.fromChimeraAtomspec("#3.2:15", false);
assertEquals(as.getModelNumber(), 3);
assertEquals(as.getPdbResNum(), 15);
assertEquals(as.getChain(), "");
String spec = "3:12.B";
try
{
- as = AtomSpec.fromChimeraAtomspec(spec);
+ as = AtomSpec.fromChimeraAtomspec(spec, false);
fail("Expected exception for " + spec);
} catch (IllegalArgumentException e)
{
spec = "#3:12-14.B";
try
{
- as = AtomSpec.fromChimeraAtomspec(spec);
+ as = AtomSpec.fromChimeraAtomspec(spec, false);
fail("Expected exception for " + spec);
} catch (IllegalArgumentException e)
{
spec = "";
try
{
- as = AtomSpec.fromChimeraAtomspec(spec);
+ as = AtomSpec.fromChimeraAtomspec(spec, false);
fail("Expected exception for " + spec);
} catch (IllegalArgumentException e)
{
spec = null;
try
{
- as = AtomSpec.fromChimeraAtomspec(spec);
+ as = AtomSpec.fromChimeraAtomspec(spec, false);
+ fail("Expected exception for " + spec);
+ } catch (NullPointerException e)
+ {
+ // ok
+ }
+ }
+
+ @Test
+ public void testFromChimeraAtomSpec_chimeraX()
+ {
+ AtomSpec as = AtomSpec.fromChimeraAtomspec("#1/B:12", true);
+ assertEquals(as.getModelNumber(), 1);
+ assertEquals(as.getPdbResNum(), 12);
+ assertEquals(as.getChain(), "B");
+ assertNull(as.getPdbFile());
+
+ // no model - default to zero
+ as = AtomSpec.fromChimeraAtomspec("/C:13", true);
+ assertEquals(as.getModelNumber(), 0);
+ assertEquals(as.getPdbResNum(), 13);
+ assertEquals(as.getChain(), "C");
+ assertNull(as.getPdbFile());
+
+ // model.submodel
+ as = AtomSpec.fromChimeraAtomspec("#3.2/:15", true);
+ assertEquals(as.getModelNumber(), 3);
+ assertEquals(as.getPdbResNum(), 15);
+ assertEquals(as.getChain(), "");
+ assertNull(as.getPdbFile());
+
+ String spec = "3:12.B";
+ try
+ {
+ as = AtomSpec.fromChimeraAtomspec(spec, true);
+ fail("Expected exception for " + spec);
+ } catch (IllegalArgumentException e)
+ {
+ // ok
+ }
+
+ spec = "#3:12-14.B";
+ try
+ {
+ as = AtomSpec.fromChimeraAtomspec(spec, true);
+ fail("Expected exception for " + spec);
+ } catch (IllegalArgumentException e)
+ {
+ // ok
+ }
+
+ spec = "";
+ try
+ {
+ as = AtomSpec.fromChimeraAtomspec(spec, true);
+ fail("Expected exception for " + spec);
+ } catch (IllegalArgumentException e)
+ {
+ // ok
+ }
+
+ spec = null;
+ try
+ {
+ as = AtomSpec.fromChimeraAtomspec(spec, true);
fail("Expected exception for " + spec);
} catch (NullPointerException e)
{