public abstract jalview.api.FeatureRenderer getFeatureRenderer(
AlignmentViewPanel alignment);
+
+ /**
+ * Sets the flag for whether only mapped visible residues in the alignment
+ * should be visible in the structure viewer
+ *
+ * @param b
+ */
+ public void setShowAlignmentOnly(boolean b)
+ {
+ showAlignmentOnly = b;
+ }
+
+ /**
+ * Answers true if only residues mapped to the alignment should be shown in the
+ * structure viewer, else false
+ *
+ * @return
+ */
+ public boolean isShowAlignmentOnly()
+ {
+ return showAlignmentOnly;
+ }
+
+ /**
+ * Sets the flag for hiding regions of structure which are hidden in the
+ * alignment (only applies when the structure viewer is restricted to the
+ * alignment only)
+ *
+ * @param b
+ */
+ public void setHideHiddenRegions(boolean b)
+ {
+ hideHiddenRegions = b;
+ }
+
+ /**
+ * Answers true if regions hidden in the alignment should also be hidden in the
+ * structure viewer, else false (only applies when the structure viewer is
+ * restricted to the alignment only)
+ *
+ * @return
+ */
+ public boolean isHideHiddenRegions()
+ {
+ return hideHiddenRegions;
+ }
+
+ /**
+ * Shows the structures in the viewer, without changing their colouring. This is
+ * to support toggling of whether the whole structure is shown, or only residues
+ * mapped to visible regions of the alignment.
+ *
+ * @param alignViewportI
+ * @param refocus
+ * if true, refit the display to the viewer
+ */
+ public void showStructures(AlignViewportI alignViewportI, boolean refocus)
+ {
+ // override with implementation
+ }
+
+ @Override
+ public void updateColours(Object source)
+ {
+ AlignmentViewPanel ap = (AlignmentViewPanel) source;
+ // ignore events from panels not used to colour this view
+ if (!getViewer().isUsedforcolourby(ap))
+ {
+ return;
+ }
+ if (!isLoadingFromArchive())
+ {
+ updateStructureColours(ap);
+ }
+ }
+
+ /**
+ * Sets the list of chains to display (as "pdbid:chain"), where an empty list
+ * means show all
+ *
+ * @param chains
+ */
+ public void setChainsToShow(List<String> chains)
+ {
+ chainsToShow = chains;
+ }
+
+ /**
+ * Answers true if the specified structure and chain are selected to be shown in
+ * the viewer, else false
+ *
+ * @param pdbId
+ * @param chainId
+ * @return
+ */
+ protected boolean isShowChain(String pdbId, String chainId)
+ {
+ if (chainsToShow.isEmpty())
+ {
+ return true;
+ }
+ 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);
+ }
+
+ /**
+ * Build a data structure which records contiguous subsequences for each colour.
+ * From this we can easily generate the Chimera command for colour by sequence.
+ *
+ * <pre>
+ * Color
+ * Model number
+ * Chain
+ * list of start/end ranges
+ * </pre>
+ *
+ * Ordering is by order of addition (for colours and positions), natural
+ * ordering (for models and chains)
+ *
+ * @param viewPanel
+ * @return
+ */
- protected Map<Object, AtomSpecModel> buildColoursMap(
++ public Map<Object, AtomSpecModel> buildColoursMap(
+ AlignmentViewPanel viewPanel)
+ {
+ FeatureRenderer fr = viewPanel.getFeatureRenderer();
+ FeatureColourFinder finder = new FeatureColourFinder(fr);
+ AlignViewportI viewport = viewPanel.getAlignViewport();
+ HiddenColumns cs = viewport.getAlignment().getHiddenColumns();
+ AlignmentI al = viewport.getAlignment();
+ SequenceRenderer sr = getSequenceRenderer(viewPanel);
+ String[] files = getStructureFiles();
+
+ Map<Object, AtomSpecModel> colourMap = new LinkedHashMap<>();
+ Color lastColour = null;
+
+ for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
+ {
+ StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
+
+ if (mapping == null || mapping.length < 1)
+ {
+ continue;
+ }
+
+ int startPos = -1, lastPos = -1;
+ String lastChain = "";
+ for (int s = 0; s < sequence[pdbfnum].length; s++)
+ {
+ for (int sp, m = 0; m < mapping.length; m++)
+ {
+ final SequenceI seq = sequence[pdbfnum][s];
+ if (mapping[m].getSequence() == seq
+ && (sp = al.findIndex(seq)) > -1)
+ {
+ SequenceI asp = al.getSequenceAt(sp);
+ for (int r = 0; r < asp.getLength(); r++)
+ {
+ // no mapping to gaps in sequence
+ if (Comparison.isGap(asp.getCharAt(r)))
+ {
+ continue;
+ }
+ int pos = mapping[m].getPDBResNum(asp.findPosition(r));
+
+ if (pos < 1 || pos == lastPos)
+ {
+ continue;
+ }
+
+ Color colour = sr.getResidueColour(seq, r, finder);
+
+ /*
+ * hidden regions are shown gray or, optionally, ignored
+ */
+ if (!cs.isVisible(r))
+ {
+ if (hideHiddenRegions)
+ {
+ continue;
+ }
+ else
+ {
+ colour = Color.GRAY;
+ }
+ }
+
+ final String chain = mapping[m].getChain();
+
+ /*
+ * Just keep incrementing the end position for this colour range
+ * _unless_ colour, PDB model or chain has changed, or there is a
+ * gap in the mapped residue sequence
+ */
+ final boolean newColour = !colour.equals(lastColour);
+ final boolean nonContig = lastPos + 1 != pos;
+ final boolean newChain = !chain.equals(lastChain);
+ if (newColour || nonContig || newChain)
+ {
+ if (startPos != -1)
+ {
- ChimeraCommands.addMapRange(colourMap, lastColour,
++ ChimeraCommands.addAtomSpecRange(colourMap, lastColour,
+ pdbfnum, startPos,
+ lastPos, lastChain);
+ }
+ startPos = pos;
+ }
+ lastColour = colour;
+ lastPos = pos;
+ lastChain = chain;
+ }
+ // final colour range
+ if (lastColour != null)
+ {
- ChimeraCommands.addMapRange(colourMap, lastColour, pdbfnum,
++ ChimeraCommands.addAtomSpecRange(colourMap, lastColour,
++ pdbfnum,
+ startPos, lastPos, lastChain);
+ }
+ // break;
+ }
+ }
+ }
+ }
+ return colourMap;
+ }
}
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
+import junit.extensions.PA;
+
public class ChimeraCommandsTest
{
-
+ private SequenceRenderer sr;
++
++ private String[] files;
+
+ 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 String[] getColourBySequenceCommands(String[] files,
+ AlignmentViewPanel avp)
+ {
+ return null;
+ }
+
+ @Override
+ public jalview.api.SequenceRenderer getSequenceRenderer(
+ AlignmentViewPanel alignment)
+ {
+ return sr;
+ }
+
+ @Override
+ protected void colourBySequence(String[] colourBySequenceCommands)
+ {
+ }
+
+ @Override
+ public void colourByChain()
+ {
+ }
+
+ @Override
+ public void colourByCharge()
+ {
+ }
+
+ @Override
+ public FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment)
+ {
+ return null;
+ }
+
+ @Override
+ public String[] getStructureFiles()
+ {
- return null;
++ return files;
+ }
+
+ @Override
+ public String getModelSpec(int model)
+ {
+ return "#" + String.valueOf(model);
+ }
+ };
@BeforeClass(alwaysRun = true)
public void setUpJvOptionPane()
@Test(groups = { "Functional" })
public void testBuildColourCommands()
{
--
- Map<Object, AtomSpecModel> map = new LinkedHashMap<Object, AtomSpecModel>();
+ Map<Object, AtomSpecModel> map = new LinkedHashMap<>();
- ChimeraCommands.addMapRange(map, Color.blue, 0, 2, 5, "A");
- ChimeraCommands.addMapRange(map, Color.blue, 0, 7, 7, "B");
- ChimeraCommands.addMapRange(map, Color.blue, 0, 9, 23, "A");
- ChimeraCommands.addMapRange(map, Color.blue, 1, 1, 1, "A");
- ChimeraCommands.addMapRange(map, Color.blue, 1, 4, 7, "B");
- ChimeraCommands.addMapRange(map, Color.yellow, 1, 8, 8, "A");
- ChimeraCommands.addMapRange(map, Color.yellow, 1, 3, 5, "A");
- ChimeraCommands.addMapRange(map, Color.red, 0, 3, 5, "A");
- ChimeraCommands.addMapRange(map, Color.red, 0, 6, 9, "A");
+ ChimeraCommands.addAtomSpecRange(map, Color.blue, 0, 2, 5, "A");
+ ChimeraCommands.addAtomSpecRange(map, Color.blue, 0, 7, 7, "B");
+ ChimeraCommands.addAtomSpecRange(map, Color.blue, 0, 9, 23, "A");
+ ChimeraCommands.addAtomSpecRange(map, Color.blue, 1, 1, 1, "A");
+ ChimeraCommands.addAtomSpecRange(map, Color.blue, 1, 4, 7, "B");
+ ChimeraCommands.addAtomSpecRange(map, Color.yellow, 1, 8, 8, "A");
+ ChimeraCommands.addAtomSpecRange(map, Color.yellow, 1, 3, 5, "A");
+ ChimeraCommands.addAtomSpecRange(map, Color.red, 0, 3, 5, "A");
+ ChimeraCommands.addAtomSpecRange(map, Color.red, 0, 6, 9, "A");
// 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
* start with just one feature/value...
*/
featuresMap.put("chain", featureValues);
- ChimeraCommands.addMapRange(featureValues, "X", 0, 8, 20, "A");
+ ChimeraCommands.addAtomSpecRange(featureValues, "X", 0, 8, 20, "A");
List<String> commands = ChimeraCommands
- .buildSetAttributeCommands(featuresMap);
+ .buildSetAttributeCommands(featuresMap, mockBinding);
assertEquals(1, commands.size());
/*
assertEquals(commands.get(0), "setattr r jv_chain 'X' #0:8-20.A");
// add same feature value, overlapping range
- ChimeraCommands.addMapRange(featureValues, "X", 0, 3, 9, "A");
+ ChimeraCommands.addAtomSpecRange(featureValues, "X", 0, 3, 9, "A");
// same feature value, contiguous range
- ChimeraCommands.addMapRange(featureValues, "X", 0, 21, 25, "A");
+ ChimeraCommands.addAtomSpecRange(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");
// same feature value and model, different chain
- ChimeraCommands.addMapRange(featureValues, "X", 0, 21, 25, "B");
+ ChimeraCommands.addAtomSpecRange(featureValues, "X", 0, 21, 25, "B");
// same feature value and chain, different model
- ChimeraCommands.addMapRange(featureValues, "X", 1, 26, 30, "A");
+ ChimeraCommands.addAtomSpecRange(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.addMapRange(featureValues, "Y", 0, 40, 50, "A");
+ ChimeraCommands.addAtomSpecRange(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:
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" };
++ files = new String[] { "seq1.pdb", "seq2.pdb" };
StructureSelectionManager ssm = new StructureSelectionManager();
/*
"B", map, null);
ssm.addStructureMapping(sm2);
- StructureMappingcommandSet[] commands = ChimeraCommands
- .getColourBySequenceCommand(ssm, files, seqs, sr, af.alignPanel);
+ /*
+ * put data into the mock binding object
+ */
+ PA.setValue(mockBinding, "ssm", ssm);
+ PA.setValue(mockBinding, "sequence", seqs);
+
++ Map<Object, AtomSpecModel> colourMap = mockBinding
++ .buildColoursMap(af.alignPanel);
+ String[] commands = ChimeraCommands
- .getColourBySequenceCommand(files, af.alignPanel, mockBinding);
++ .getColourBySequenceCommand(colourMap, mockBinding);
assertEquals(1, commands.length);
- assertEquals(1, commands[0].commands.length);
- String theCommand = commands[0].commands[0];
+ String theCommand = commands[0];
// M colour is #82827d (see strand.html help page)
assertTrue(theCommand.contains("color #82827d #0:21.A|#1:21.B"));
// H colour is #60609f