*/
package jalview.ext.rbvi.chimera;
-import jalview.util.IntRangeComparator;
-
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
- * A class to model a Chimera atomspec pattern, for example
- *
- * <pre>
- * #0:15.A,28.A,54.A,63.A,70-72.A,83-84.A,97-98.A|#1:2.A,6.A,11.A,13-14.A,70.A,82.A,96-97.A
- * </pre>
- *
- * where
- * <ul>
- * <li>#0 is a model number</li>
- * <li>15 or 70-72 is a residue number, or range of residue numbers</li>
- * <li>.A is a chain identifier</li>
- * <li>residue ranges are separated by comma</li>
- * <li>atomspecs for distinct models are separated by | (or)</li>
- * </ul>
- *
- * <pre>
- * @see http://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/frameatom_spec.html
- * </pre>
+ * A class to model a Chimera or Jmol residue set, as
+ * {@code Map<modelNumber, Map<chainId, List<residueRange>>>}. This can then be
+ * traversed to generate the required display command in Chimera or Jmol syntax.
*/
public class AtomSpecModel
{
*/
public AtomSpecModel()
{
- atomSpec = new TreeMap<Integer, Map<String, List<int[]>>>();
+ atomSpec = new TreeMap<>();
+ }
+
+ public Map<Integer, Map<String, List<int[]>>> getMap()
+ {
+ return atomSpec;
}
/**
Map<String, List<int[]>> modelData = atomSpec.get(model);
if (modelData == null)
{
- atomSpec.put(model, modelData = new TreeMap<String, List<int[]>>());
+ atomSpec.put(model, modelData = new TreeMap<>());
}
/*
List<int[]> chainData = modelData.get(chain);
if (chainData == null)
{
- chainData = new ArrayList<int[]>();
+ chainData = new ArrayList<>();
modelData.put(chain, chainData);
}
}
/**
- * Returns the range(s) formatted as a Chimera atomspec
+ * Answers an iterable set of the structure models in this model
*
* @return
*/
- public String getAtomSpec()
+ public Iterable<Integer> getModels()
{
- StringBuilder sb = new StringBuilder(128);
- boolean firstModel = true;
- for (Integer model : atomSpec.keySet())
- {
- if (!firstModel)
- {
- sb.append("|");
- }
- firstModel = false;
- sb.append("#").append(model).append(":");
-
- boolean firstPositionForModel = true;
- final Map<String, List<int[]>> modelData = atomSpec.get(model);
-
- for (String chain : modelData.keySet())
- {
- chain = " ".equals(chain) ? chain : chain.trim();
-
- List<int[]> rangeList = modelData.get(chain);
-
- /*
- * sort ranges into ascending start position order
- */
- Collections.sort(rangeList, IntRangeComparator.ASCENDING);
-
- int start = rangeList.isEmpty() ? 0 : rangeList.get(0)[0];
- int end = rangeList.isEmpty() ? 0 : rangeList.get(0)[1];
-
- Iterator<int[]> iterator = rangeList.iterator();
- while (iterator.hasNext())
- {
- int[] range = iterator.next();
- if (range[0] <= end + 1)
- {
- /*
- * range overlaps or is contiguous with the last one
- * - so just extend the end position, and carry on
- * (unless this is the last in the list)
- */
- end = Math.max(end, range[1]);
- }
- else
- {
- /*
- * we have a break so append the last range
- */
- appendRange(sb, start, end, chain, firstPositionForModel);
- firstPositionForModel = false;
- start = range[0];
- end = range[1];
- }
- }
-
- /*
- * and append the last range
- */
- if (!rangeList.isEmpty())
- {
- appendRange(sb, start, end, chain, firstPositionForModel);
- firstPositionForModel = false;
- }
- }
- }
- return sb.toString();
+ return atomSpec.keySet();
}
/**
- * @param sb
- * @param start
- * @param end
- * @param chain
- * @param firstPositionForModel
+ * Answers an iterable set of the chains in this model for the given structure
+ * model, or an empty set if none
+ *
+ * @param model
+ * @return
*/
- protected void appendRange(StringBuilder sb, int start, int end,
- String chain, boolean firstPositionForModel)
+ public Iterable<String> getChains(Integer model)
{
- if (!firstPositionForModel)
- {
- sb.append(",");
- }
- if (end == start)
+ if (atomSpec.containsKey(model))
{
- sb.append(start);
- }
- else
- {
- sb.append(start).append("-").append(end);
+ return atomSpec.get(model).keySet();
}
+ return Collections.emptySet();
+ }
- sb.append(".");
- if (!" ".equals(chain)) {
- sb.append(chain);
+ public List<int[]> getRanges(Integer model, String chain)
+ {
+ Map<String, List<int[]>> modelData = atomSpec.get(model);
+ if (modelData != null)
+ {
+ List<int[]> chainData = modelData.get(chain);
+ if (chainData != null)
+ {
+ return chainData;
+ }
}
+ return Collections.EMPTY_LIST;
}
}
import jalview.structures.models.AAStructureBindingModel;
import jalview.util.ColorUtils;
import jalview.util.Comparison;
+import jalview.util.IntRangeComparator;
import java.awt.Color;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
{
public static final String NAMESPACE_PREFIX = "jv_";
+ /*
+ * colour for residues shown in structure but hidden in alignment
+ */
private static final String COLOR_GRAY_HEX = "color "
+ ColorUtils.toTkCode(Color.GRAY);
/**
* Constructs Chimera commands to colour residues as per the Jalview alignment
*
- * @param ssm
* @param files
- * @param sequence
- * @param sr
- * @param fr
* @param viewPanel
+ * @param binding
* @return
*/
public static StructureMappingcommandSet[] getColourBySequenceCommand(
- StructureSelectionManager ssm, String[] files,
- AAStructureBindingModel binding, AlignmentViewPanel viewPanel)
+ String[] files, AlignmentViewPanel viewPanel,
+ AAStructureBindingModel binding)
{
+ StructureSelectionManager ssm = binding.getSsm();
SequenceRenderer sr = binding.getSequenceRenderer(viewPanel);
SequenceI[][] sequence = binding.getSequence();
boolean hideHiddenRegions = binding.isShowAlignmentOnly()
&& binding.isHideHiddenRegions();
- return getColourBySequenceCommand(ssm, files, sequence, sr,
- hideHiddenRegions, viewPanel);
- }
-
- static StructureMappingcommandSet[] getColourBySequenceCommand(
- StructureSelectionManager ssm, String[] files,
- SequenceI[][] sequence, SequenceRenderer sr,
- boolean hideHiddenRegions, AlignmentViewPanel viewPanel)
- {
Map<Object, AtomSpecModel> colourMap = buildColoursMap(ssm, files,
sequence, sr, hideHiddenRegions, viewPanel);
- List<String> colourCommands = buildColourCommands(colourMap);
+ List<String> colourCommands = buildColourCommands(colourMap, binding);
StructureMappingcommandSet cs = new StructureMappingcommandSet(
ChimeraCommands.class, null,
* </pre>
*
* @param colourMap
+ * @param binding
* @return
*/
protected static List<String> buildColourCommands(
- Map<Object, AtomSpecModel> colourMap)
+ Map<Object, AtomSpecModel> colourMap,
+ AAStructureBindingModel binding)
{
/*
* This version concatenates all commands into a single String (semi-colon
sb.append("; ");
sb.append("color ").append(colourCode).append(" ");
final AtomSpecModel colourData = colourMap.get(colour);
- sb.append(colourData.getAtomSpec());
+ sb.append(getAtomSpec(colourData, binding));
}
commands.add(sb.toString());
return commands;
}
/**
- * Traverses a map of { modelNumber, {chain, {list of from-to ranges} } } and
- * builds a Chimera format atom spec
- *
- * @param modelAndChainRanges
- */
- protected static String getAtomSpec(
- Map<Integer, Map<String, List<int[]>>> modelAndChainRanges)
- {
- StringBuilder sb = new StringBuilder(128);
- boolean firstModelForColour = true;
- for (Integer model : modelAndChainRanges.keySet())
- {
- boolean firstPositionForModel = true;
- if (!firstModelForColour)
- {
- sb.append("|");
- }
- firstModelForColour = false;
- sb.append("#").append(model).append(":");
-
- final Map<String, List<int[]>> modelData = modelAndChainRanges
- .get(model);
- for (String chain : modelData.keySet())
- {
- boolean hasChain = !"".equals(chain.trim());
- for (int[] range : modelData.get(chain))
- {
- if (!firstPositionForModel)
- {
- sb.append(",");
- }
- if (range[0] == range[1])
- {
- sb.append(range[0]);
- }
- else
- {
- sb.append(range[0]).append("-").append(range[1]);
- }
- if (hasChain)
- {
- sb.append(".").append(chain);
- }
- firstPositionForModel = false;
- }
- }
- }
- return sb.toString();
- }
-
- /**
* Build a data structure which records contiguous subsequences for each colour.
* From this we can easily generate the Chimera command for colour by sequence.
*
/**
* Constructs and returns Chimera commands to set attributes on residues
- * corresponding to features in Jalview. Attribute names are the Jalview
- * feature type, with a "jv_" prefix.
+ * corresponding to features in Jalview. Attribute names are the Jalview feature
+ * type, with a "jv_" prefix.
*
* @param ssm
* @param files
* @param seqs
* @param viewPanel
+ * @param binding
* @return
*/
public static StructureMappingcommandSet getSetAttributeCommandsForFeatures(
- StructureSelectionManager ssm, String[] files, SequenceI[][] seqs,
- AlignmentViewPanel viewPanel)
+ AlignmentViewPanel viewPanel, AAStructureBindingModel binding)
{
+ StructureSelectionManager ssm = binding.getSsm();
+ String[] files = binding.getStructureFiles();
+ SequenceI[][] seqs = binding.getSequence();
+
Map<String, Map<Object, AtomSpecModel>> featureMap = buildFeaturesMap(
ssm, files, seqs, viewPanel);
- List<String> commands = buildSetAttributeCommands(featureMap);
+ List<String> commands = buildSetAttributeCommands(featureMap, binding);
StructureMappingcommandSet cs = new StructureMappingcommandSet(
ChimeraCommands.class, null,
* </pre>
*
* @param featureMap
+ * @param binding
* @return
*/
protected static List<String> buildSetAttributeCommands(
- Map<String, Map<Object, AtomSpecModel>> featureMap)
+ Map<String, Map<Object, AtomSpecModel>> featureMap,
+ AAStructureBindingModel binding)
{
List<String> commands = new ArrayList<>();
for (String featureType : featureMap.keySet())
featureValue = featureValue.replaceAll("\\'", "'");
sb.append("setattr r ").append(attributeName).append(" '")
.append(featureValue).append("' ");
- sb.append(values.get(value).getAtomSpec());
+ sb.append(getAtomSpec(values.get(value), binding));
commands.add(sb.toString());
}
}
return attName;
}
+ /**
+ * Returns the range(s) formatted as a Chimera atomspec
+ *
+ * @return
+ */
+ public static String getAtomSpec(AtomSpecModel atomSpec,
+ AAStructureBindingModel binding)
+ {
+ StringBuilder sb = new StringBuilder(128);
+ boolean firstModel = true;
+ for (Integer model : atomSpec.getModels())
+ {
+ if (!firstModel)
+ {
+ sb.append("|");
+ }
+ firstModel = false;
+ // todo use JalviewChimeraBinding.getModelSpec(model)
+ // which means this cannot be static
+ sb.append(binding.getModelSpec(model)).append(":");
+
+ boolean firstPositionForModel = true;
+
+ for (String chain : atomSpec.getChains(model))
+ {
+ chain = " ".equals(chain) ? chain : chain.trim();
+
+ List<int[]> rangeList = atomSpec.getRanges(model, chain);
+
+ /*
+ * sort ranges into ascending start position order
+ */
+ Collections.sort(rangeList, IntRangeComparator.ASCENDING);
+
+ int start = rangeList.isEmpty() ? 0 : rangeList.get(0)[0];
+ int end = rangeList.isEmpty() ? 0 : rangeList.get(0)[1];
+
+ Iterator<int[]> iterator = rangeList.iterator();
+ while (iterator.hasNext())
+ {
+ int[] range = iterator.next();
+ if (range[0] <= end + 1)
+ {
+ /*
+ * range overlaps or is contiguous with the last one
+ * - so just extend the end position, and carry on
+ * (unless this is the last in the list)
+ */
+ end = Math.max(end, range[1]);
+ }
+ else
+ {
+ /*
+ * we have a break so append the last range
+ */
+ appendRange(sb, start, end, chain, firstPositionForModel);
+ firstPositionForModel = false;
+ start = range[0];
+ end = range[1];
+ }
+ }
+
+ /*
+ * and append the last range
+ */
+ if (!rangeList.isEmpty())
+ {
+ appendRange(sb, start, end, chain, firstPositionForModel);
+ firstPositionForModel = false;
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * A helper method that appends one start-end range to a Chimera atomspec
+ *
+ * @param sb
+ * @param start
+ * @param end
+ * @param chain
+ * @param firstPositionForModel
+ */
+ static void appendRange(StringBuilder sb, int start, int end,
+ String chain, boolean firstPositionForModel)
+ {
+ if (!firstPositionForModel)
+ {
+ sb.append(",");
+ }
+ if (end == start)
+ {
+ sb.append(start);
+ }
+ else
+ {
+ sb.append(start).append("-").append(end);
+ }
+
+ sb.append(".");
+ if (!" ".equals(chain))
+ {
+ sb.append(chain);
+ }
+ }
+
}
import jalview.schemes.ColourSchemeI;
import jalview.schemes.ResidueProperties;
import jalview.structure.AtomSpec;
-import jalview.structure.StructureMapping;
import jalview.structure.StructureMappingcommandSet;
import jalview.structure.StructureSelectionManager;
import jalview.structures.models.AAStructureBindingModel;
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;
* @see
* https://www.cgl.ucsf.edu/chimera/docs/UsersGuide/midas/match.html
*/
- command.append("match ").append(getModelSpec(pdbfnum)).append(":");
+ command.append("match ").append(getModelSpec(pdbfnum))
+ .append(":");
command.append(selcom[pdbfnum]);
command.append("@").append(
structures[pdbfnum].isRna ? PHOSPHORUS : ALPHACARBON);
* @param pdbfnum
* @return
*/
- protected String getModelSpec(int pdbfnum)
+ @Override
+ public String getModelSpec(int pdbfnum)
{
if (pdbfnum < 0 || pdbfnum >= getPdbCount())
{
*/
List<ChimeraModel> maps = chimeraMaps.get(getStructureFiles()[pdbfnum]);
boolean hasSubModels = maps != null && maps.size() > 1;
- return "#" + String.valueOf(pdbfnum) + (hasSubModels ? ".1" : "");
+ String spec = "#" + String.valueOf(pdbfnum);
+ return hasSubModels ? spec + ".1" : spec;
}
/**
protected StructureMappingcommandSet[] getColourBySequenceCommands(
String[] files, AlignmentViewPanel viewPanel)
{
- return ChimeraCommands.getColourBySequenceCommand(getSsm(), files,
- this, viewPanel);
+ return ChimeraCommands.getColourBySequenceCommand(files, viewPanel,
+ this);
}
/**
}
StructureMappingcommandSet commandSet = ChimeraCommands
- .getSetAttributeCommandsForFeatures(getSsm(), files,
- getSequence(), avp);
+ .getSetAttributeCommandsForFeatures(avp, this);
String[] commands = commandSet.commands;
if (commands.length > 10)
{
{
StringBuilder cmd = new StringBuilder(128);
cmd.append("~display; ~ribbon;");
- String atomSpec = getMappedResidues(av);
+
+ AtomSpecModel model = getShownResidues(av);
+ String atomSpec = ChimeraCommands.getAtomSpec(model, this);
+
cmd.append("ribbon ").append(atomSpec);
if (!isShowAlignmentOnly())
{
}
sendChimeraCommand(cmd.toString(), false);
}
-
- /**
- * Builds a Chimera atomSpec of residues mapped from sequences, of the format
- * (#model:residues.chain)
- *
- * <pre>
- * #0:2-94.A | #1:1-93.C | #2:1-93.A
- * </pre>
- *
- * Only residues visible in the alignment are included, that is, hidden columns
- * and sequences are excluded.
- *
- * @param av
- * @return
- */
- private String getMappedResidues(AlignViewportI av)
- {
- AlignmentI alignment = av.getAlignment();
- final int width = alignment.getWidth();
-
- String[] files = getStructureFiles();
-
- StringBuilder atomSpec = new StringBuilder(256);
-
- for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
- {
- StructureMapping[] mappings = getSsm().getMapping(files[pdbfnum]);
-
- /*
- * Find the first mapped sequence (if any) for this PDB entry which is in
- * the alignment
- */
- final int seqCountForPdbFile = getSequence()[pdbfnum].length;
- for (int s = 0; s < seqCountForPdbFile; s++)
- {
- for (StructureMapping mapping : mappings)
- {
- final SequenceI theSequence = getSequence()[pdbfnum][s];
- if (mapping.getSequence() == theSequence
- && alignment.findIndex(theSequence) > -1)
- {
- String chainCd = mapping.getChain();
- if (!isShowChain(mapping.getPdbId(), chainCd))
- {
- continue;
- }
- Iterator<int[]> visible;
- if (isShowAlignmentOnly() && isHideHiddenRegions())
- {
- visible = alignment.getHiddenColumns()
- .getVisContigsIterator(0, width, true);
- }
- else
- {
- visible = Collections.singletonList(new int[] { 0, width })
- .iterator();
- }
- while (visible.hasNext())
- {
- int[] visibleRegion = visible.next();
- int seqStartPos = theSequence.findPosition(visibleRegion[0]);
- int seqEndPos = theSequence.findPosition(visibleRegion[1]);
- List<int[]> residueRanges = mapping
- .getPDBResNumRanges(seqStartPos, seqEndPos);
- if (!residueRanges.isEmpty())
- {
- if (atomSpec.length() > 0)
- {
- atomSpec.append("| ");
- }
- atomSpec.append(getModelSpec(pdbfnum)).append(":");
- boolean first = true;
- for (int[] range : residueRanges)
- {
- if (!first)
- {
- atomSpec.append(",");
- }
- first = false;
- atomSpec.append(range[0]).append("-").append(range[1]);
- atomSpec.append(".").append(chainCd);
- }
- }
- }
- }
- }
- }
- }
-
- return atomSpec.toString();
- }
}
import jalview.datamodel.HiddenColumns;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SequenceI;
+import jalview.ext.rbvi.chimera.AtomSpecModel;
import jalview.io.DataSourceType;
import jalview.schemes.ColourSchemeI;
import jalview.structure.AtomSpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
+import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
/**
}
return chainsToShow.contains(pdbId + ":" + chainId);
}
+
+ @Override
+ public abstract String[] getStructureFiles();
+
+ /**
+ * Builds a model of residues mapped from sequences to show on structure, taking
+ * into account user choices of
+ * <ul>
+ * <li>which chains are shown</li>
+ * <li>whether all structure is shown, or only that mapped to the alignment</li>
+ * <li>whether hidden regions of the alignment are hidden (excluded) or grayed
+ * out (included)</li>
+ * </ul>
+ *
+ * @param av
+ * @return
+ */
+ protected AtomSpecModel getShownResidues(AlignViewportI av)
+ {
+ AlignmentI alignment = av.getAlignment();
+ final int width = alignment.getWidth();
+
+ String[] files = getStructureFiles();
+
+ AtomSpecModel model = new AtomSpecModel();
+
+ for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
+ {
+ StructureMapping[] mappings = getSsm().getMapping(files[pdbfnum]);
+
+ /*
+ * Find the first mapped sequence (if any) for this PDB entry which is in
+ * the alignment
+ */
+ final int seqCountForPdbFile = getSequence()[pdbfnum].length;
+ for (int s = 0; s < seqCountForPdbFile; s++)
+ {
+ for (StructureMapping mapping : mappings)
+ {
+ final SequenceI theSequence = getSequence()[pdbfnum][s];
+ if (mapping.getSequence() == theSequence
+ && alignment.findIndex(theSequence) > -1)
+ {
+ String chainCd = mapping.getChain();
+ if (!isShowChain(mapping.getPdbId(), chainCd))
+ {
+ continue;
+ }
+ Iterator<int[]> visible;
+ if (isShowAlignmentOnly() && isHideHiddenRegions())
+ {
+ visible = alignment.getHiddenColumns()
+ .getVisContigsIterator(0, width, true);
+ }
+ else
+ {
+ visible = Collections.singletonList(new int[] { 0, width })
+ .iterator();
+ }
+ while (visible.hasNext())
+ {
+ int[] visibleRegion = visible.next();
+ int seqStartPos = theSequence.findPosition(visibleRegion[0]);
+ int seqEndPos = theSequence.findPosition(visibleRegion[1]);
+ List<int[]> residueRanges = mapping
+ .getPDBResNumRanges(seqStartPos, seqEndPos);
+ if (!residueRanges.isEmpty())
+ {
+ for (int[] range : residueRanges)
+ {
+ model.addRange(pdbfnum, range[0], range[1], chainCd);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return model;
+ }
+
+ /**
+ * Answers a default structure model specification which is simply the string
+ * form of the model number. Override if needed to specify submodels.
+ *
+ * @param model
+ * @return
+ */
+ public String getModelSpec(int model)
+ {
+ return String.valueOf(model);
+ }
}
+++ /dev/null
-package jalview.ext.rbvi.chimera;
-
-import static org.testng.Assert.assertEquals;
-
-import org.testng.annotations.Test;
-
-public class AtomSpecModelTest
-{
- @Test(groups = "Functional")
- public void testGetAtomSpec()
- {
- AtomSpecModel model = new AtomSpecModel();
- assertEquals(model.getAtomSpec(), "");
- model.addRange(1, 2, 4, "A");
- assertEquals(model.getAtomSpec(), "#1:2-4.A");
- model.addRange(1, 8, 8, "A");
- assertEquals(model.getAtomSpec(), "#1:2-4.A,8.A");
- model.addRange(1, 5, 7, "B");
- assertEquals(model.getAtomSpec(), "#1:2-4.A,8.A,5-7.B");
- model.addRange(1, 3, 5, "A");
- assertEquals(model.getAtomSpec(), "#1:2-5.A,8.A,5-7.B");
- model.addRange(0, 1, 4, "B");
- assertEquals(model.getAtomSpec(), "#0:1-4.B|#1:2-5.A,8.A,5-7.B");
- model.addRange(0, 5, 9, "C");
- assertEquals(model.getAtomSpec(), "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-7.B");
- model.addRange(1, 8, 10, "B");
- assertEquals(model.getAtomSpec(), "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-10.B");
- model.addRange(1, 8, 9, "B");
- assertEquals(model.getAtomSpec(), "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-10.B");
- model.addRange(0, 3, 10, "C"); // subsumes 5-9
- assertEquals(model.getAtomSpec(), "#0:1-4.B,3-10.C|#1:2-5.A,8.A,5-10.B");
- model.addRange(5, 25, 35, " "); // empty chain code - e.g. from homology
- // modelling
- assertEquals(model.getAtomSpec(),
- "#0:1-4.B,3-10.C|#1:2-5.A,8.A,5-10.B|#5:25-35.");
-
- }
-
-}
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
+import jalview.api.AlignmentViewPanel;
+import jalview.api.FeatureRenderer;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceI;
import jalview.gui.AlignFrame;
import jalview.gui.JvOptionPane;
import jalview.gui.SequenceRenderer;
+import jalview.schemes.ColourSchemeI;
import jalview.schemes.JalviewColourScheme;
+import jalview.structure.AtomSpec;
import jalview.structure.StructureMapping;
import jalview.structure.StructureMappingcommandSet;
import jalview.structure.StructureSelectionManager;
+import jalview.structures.models.AAStructureBindingModel;
import java.awt.Color;
import java.util.HashMap;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
+import junit.extensions.PA;
+
public class ChimeraCommandsTest
{
+ private SequenceRenderer sr;
+
+ private AAStructureBindingModel mockBinding = new AAStructureBindingModel(
+ null, null)
+ {
+ @Override
+ public void releaseReferences(Object svl)
+ {
+ }
+
+ @Override
+ public void highlightAtoms(List<AtomSpec> atoms)
+ {
+ }
+
+ @Override
+ public List<String> getChainNames()
+ {
+ return null;
+ }
+
+ @Override
+ public void setJalviewColourScheme(ColourSchemeI cs)
+ {
+ }
+
+ @Override
+ public String superposeStructures(AlignmentI[] alignments,
+ int[] structureIndices, HiddenColumns[] hiddenCols)
+ {
+ return null;
+ }
+
+ @Override
+ public void setBackgroundColour(Color col)
+ {
+ }
+
+ @Override
+ protected StructureMappingcommandSet[] getColourBySequenceCommands(
+ String[] files, AlignmentViewPanel avp)
+ {
+ return null;
+ }
+
+ @Override
+ public jalview.api.SequenceRenderer getSequenceRenderer(
+ AlignmentViewPanel alignment)
+ {
+ return sr;
+ }
+
+ @Override
+ protected void colourBySequence(
+ StructureMappingcommandSet[] colourBySequenceCommands)
+ {
+ }
+
+ @Override
+ public void colourByChain()
+ {
+ }
+
+ @Override
+ public void colourByCharge()
+ {
+ }
+
+ @Override
+ public FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment)
+ {
+ return null;
+ }
+
+ @Override
+ public String[] getStructureFiles()
+ {
+ return null;
+ }
+
+ @Override
+ public String getModelSpec(int model)
+ {
+ return "#" + String.valueOf(model);
+ }
+ };
+
@BeforeClass(alwaysRun = true)
public void setUpJvOptionPane()
{
// Colours should appear in the Chimera command in the order in which
// they were added; within colour, by model, by chain, ranges in start order
// all prefixed with #808080 to colour hidden regions (if shown) gray
- String command = ChimeraCommands.buildColourCommands(map).get(0);
+ String command = ChimeraCommands.buildColourCommands(map, mockBinding)
+ .get(0);
assertEquals(
command,
"color #808080; color #0000ff #0:2-5.A,9-23.A,7.B|#1:1.A,4-7.B; color #ffff00 #1:3-5.A,8.A; color #ff0000 #0:3-9.A");
ChimeraCommands.addColourRange(featureValues, "X", 0, 8, 20, "A");
List<String> commands = ChimeraCommands
- .buildSetAttributeCommands(featuresMap);
+ .buildSetAttributeCommands(featuresMap, mockBinding);
assertEquals(1, commands.size());
/*
ChimeraCommands.addColourRange(featureValues, "X", 0, 3, 9, "A");
// same feature value, contiguous range
ChimeraCommands.addColourRange(featureValues, "X", 0, 21, 25, "A");
- commands = ChimeraCommands.buildSetAttributeCommands(featuresMap);
+ commands = ChimeraCommands.buildSetAttributeCommands(featuresMap,
+ mockBinding);
assertEquals(1, commands.size());
assertEquals(commands.get(0), "setattr r jv_chain 'X' #0:3-25.A");
ChimeraCommands.addColourRange(featureValues, "X", 0, 21, 25, "B");
// same feature value and chain, different model
ChimeraCommands.addColourRange(featureValues, "X", 1, 26, 30, "A");
- commands = ChimeraCommands.buildSetAttributeCommands(featuresMap);
+ commands = ChimeraCommands.buildSetAttributeCommands(featuresMap,
+ mockBinding);
assertEquals(1, commands.size());
assertEquals(commands.get(0),
"setattr r jv_chain 'X' #0:3-25.A,21-25.B|#1:26-30.A");
// same feature, different value
ChimeraCommands.addColourRange(featureValues, "Y", 0, 40, 50, "A");
- commands = ChimeraCommands.buildSetAttributeCommands(featuresMap);
+ commands = ChimeraCommands.buildSetAttributeCommands(featuresMap,
+ mockBinding);
assertEquals(2, commands.size());
// commands are ordered by feature type but not by value
// so use contains to test for the expected command:
"A");
// feature names are sanitised to change non-alphanumeric to underscore
// feature values are sanitised to encode single quote characters
- commands = ChimeraCommands.buildSetAttributeCommands(featuresMap);
+ commands = ChimeraCommands.buildSetAttributeCommands(featuresMap,
+ mockBinding);
assertTrue(commands
.contains("setattr r jv_side_chain_binding_ '<html>metal <a href=\"http:a.b.c/x\"> 'ion!' #0:7-15.A"));
}
cs.addElement(4);
af.getViewport().setColumnSelection(cs);
af.hideSelColumns_actionPerformed(null);
- SequenceRenderer sr = new SequenceRenderer(af.getViewport());
+ sr = new SequenceRenderer(af.getViewport());
SequenceI[][] seqs = new SequenceI[][] { { seq1 }, { seq2 } };
String[] files = new String[] { "seq1.pdb", "seq2.pdb" };
StructureSelectionManager ssm = new StructureSelectionManager();
"B", map, null);
ssm.addStructureMapping(sm2);
+ /*
+ * put data into the mock binding object
+ */
+ PA.setValue(mockBinding, "ssm", ssm);
+ PA.setValue(mockBinding, "sequence", seqs);
+
StructureMappingcommandSet[] commands = ChimeraCommands
- .getColourBySequenceCommand(ssm, files, seqs, sr, false,
- af.alignPanel);
+ .getColourBySequenceCommand(files, af.alignPanel, mockBinding);
assertEquals(1, commands.length);
assertEquals(1, commands[0].commands.length);
String theCommand = commands[0].commands[0];
// S and G are both coloured #4949b6
assertTrue(theCommand.contains("color #4949b6 #0:26-30.A|#1:26-30.B"));
}
+
+ @Test(groups = "Functional")
+ public void testGetAtomSpec()
+ {
+ AtomSpecModel model = new AtomSpecModel();
+ assertEquals(ChimeraCommands.getAtomSpec(model, mockBinding), "");
+ model.addRange(1, 2, 4, "A");
+ assertEquals(ChimeraCommands.getAtomSpec(model, mockBinding),
+ "#1:2-4.A");
+ model.addRange(1, 8, 8, "A");
+ assertEquals(ChimeraCommands.getAtomSpec(model, mockBinding),
+ "#1:2-4.A,8.A");
+ model.addRange(1, 5, 7, "B");
+ assertEquals(ChimeraCommands.getAtomSpec(model, mockBinding),
+ "#1:2-4.A,8.A,5-7.B");
+ model.addRange(1, 3, 5, "A");
+ assertEquals(ChimeraCommands.getAtomSpec(model, mockBinding),
+ "#1:2-5.A,8.A,5-7.B");
+ model.addRange(0, 1, 4, "B");
+ assertEquals(ChimeraCommands.getAtomSpec(model, mockBinding),
+ "#0:1-4.B|#1:2-5.A,8.A,5-7.B");
+ model.addRange(0, 5, 9, "C");
+ assertEquals(ChimeraCommands.getAtomSpec(model, mockBinding),
+ "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-7.B");
+ model.addRange(1, 8, 10, "B");
+ assertEquals(ChimeraCommands.getAtomSpec(model, mockBinding),
+ "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-10.B");
+ model.addRange(1, 8, 9, "B");
+ assertEquals(ChimeraCommands.getAtomSpec(model, mockBinding),
+ "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-10.B");
+ model.addRange(0, 3, 10, "C"); // subsumes 5-9
+ assertEquals(ChimeraCommands.getAtomSpec(model, mockBinding),
+ "#0:1-4.B,3-10.C|#1:2-5.A,8.A,5-10.B");
+ model.addRange(5, 25, 35, " "); // empty chain code - e.g. from homology
+ // modelling
+ assertEquals(ChimeraCommands.getAtomSpec(model, mockBinding),
+ "#0:1-4.B,3-10.C|#1:2-5.A,8.A,5-10.B|#5:25-35.");
+
+ }
}