else if (evt.getSource() == seqColour)
{
setEnabled(seqColour);
- jmb.colourBySequence(ap);
+ jmb.updateStructureColours(ap);
}
else if (!allChainsSelected)
{
public void updateColours(Object source)
{
AlignmentPanel panel = (AlignmentPanel) source;
- jmb.colourBySequence(panel);
+ jmb.updateStructureColours(panel);
}
public void updateTitleAndMenus()
return;
}
setChainMenuItems(jmb.getChainNames());
- jmb.colourBySequence(ap);
+ jmb.updateStructureColours(ap);
setTitle(jmb.getViewerTitle());
}
public void updateColours(Object source)
{
AlignmentPanel ap = (AlignmentPanel) source;
- colourBySequence(ap);
+ updateStructureColours(ap);
}
@Override
import jalview.datamodel.HiddenColumns;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SequenceI;
+import jalview.ext.rbvi.chimera.AtomSpecModel;
import jalview.gui.IProgressIndicator;
import jalview.io.DataSourceType;
import jalview.io.StructureFile;
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;
import jalview.util.MessageManager;
}
Thread colourby = null;
+
/**
* Sends a set of colour commands to the structure viewer
*
- * @param colourBySequenceCommands
+ * @param commands
*/
@Override
- protected void colourBySequence(
- final StructureMappingcommandSet[] colourBySequenceCommands)
+ protected void colourBySequence(final String[] commands)
{
if (colourby != null)
{
@Override
public void run()
{
- for (StructureMappingcommandSet cpdbbyseq : colourBySequenceCommands)
+ for (String cmd : commands)
{
- for (String cbyseq : cpdbbyseq.commands)
- {
- executeWhenReady(cbyseq);
- }
+ executeWhenReady(cmd);
}
}
});
* @return
*/
@Override
- protected StructureMappingcommandSet[] getColourBySequenceCommands(
+ protected String[] getColourBySequenceCommands(
String[] files, AlignmentViewPanel viewPanel)
{
- return JmolCommands.getColourBySequenceCommand(getSsm(), files,
- this, viewPanel);
+ Map<Object, AtomSpecModel> map = buildColoursMap(viewPanel);
+
+ return JmolCommands.getColourBySequenceCommand(map);
}
/**
@Override
public void showStructures(AlignViewportI av, boolean refocus)
{
- // TODO show Jmol structure optionally restricted to visible alignment
- // and/or selected chains
+ StringBuilder cmd = new StringBuilder(128);
+
+ if (isShowAlignmentOnly())
+ {
+ cmd.append("hide *;");
+
+ AtomSpecModel model = getShownResidues(av);
+ String atomSpec = JmolCommands.getAtomSpec(model);
+
+ cmd.append("display ").append(atomSpec);
+ }
+ else
+ {
+ cmd.append("display *");
+ }
+ cmd.append("; cartoon");
+ if (refocus)
+ {
+ cmd.append("; zoom 100");
+ }
+ evalStateCommand(cmd.toString());
+ }
+
+ /**
+ * Answers a Jmol syntax style structure model specification. Model number 0, 1,
+ * 2... is formatted as "1.1", "2.1", "3.1" etc.
+ */
+ @Override
+ public String getModelSpec(int model)
+ {
+ return String.valueOf(model + 1) + ".1";
}
}
import jalview.datamodel.AlignmentI;
import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SequenceI;
+import jalview.ext.rbvi.chimera.AtomSpecModel;
import jalview.renderer.seqfeatures.FeatureColourFinder;
import jalview.structure.StructureMapping;
import jalview.structure.StructureMappingcommandSet;
import java.awt.Color;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
* Routines for generating Jmol commands for Jalview/Jmol binding another
public class JmolCommands
{
+ private static final String COMMA = ",";
+
/**
* Jmol utility which constructs the commands to colour chains by the given
* alignment
String newSelcom = (mapping[m].getChain() != " "
? ":" + mapping[m].getChain()
: "") + "/" + (pdbfnum + 1) + ".1" + ";color["
- + col.getRed() + "," + col.getGreen() + ","
+ + col.getRed() + COMMA + col.getGreen() + COMMA
+ col.getBlue() + "]";
if (command.length() > newSelcom.length() && command
.substring(command.length() - newSelcom.length())
return sb;
}
+ /**
+ * Answers a Jmol 'color' command to colour residues as described by the given
+ * map of {@code <Color, AtomSpecModel>}
+ *
+ * @param map
+ * @return
+ */
+ public static String[] getColourBySequenceCommand(
+ Map<Object, AtomSpecModel> map)
+ {
+ String[] cmds = new String[map.keySet().size()];
+
+ int i = 0;
+ for (Object o : map.keySet())
+ {
+ StringBuilder cmd = new StringBuilder(128);
+ Color c = (Color) o;
+ String atomSpec = getAtomSpec(map.get(o));
+ cmd.append("select ").append(atomSpec).append(";color[")
+ .append(c.getRed()).append(COMMA).append(c.getGreen())
+ .append(COMMA).append(c.getBlue()).append("];");
+ cmds[i] = cmd.toString();
+ i++;
+ }
+
+ return cmds;
+ }
+
+ /**
+ * Builds a Jmol syntax selection expression from the given model, for example
+ *
+ * <pre>
+ * 61-64,70:A/1.1,12-25,41-44:B/1.1,12:A/2.1
+ * for model 1, chain A, residues 61-64 and 70, chain B residues 12-25 and 41-44, model 2 chain A residue 12
+ * </pre>
+ *
+ * @param atomSpecModel
+ * @return
+ */
+ public static String getAtomSpec(AtomSpecModel atomSpecModel)
+ {
+ StringBuilder sb = new StringBuilder(64);
+ for (int model : atomSpecModel.getModels())
+ {
+ for (String chain : atomSpecModel.getChains(model))
+ {
+ if (sb.length() > 0)
+ {
+ sb.append(COMMA);
+ }
+ boolean firstRange = true;
+ for (int[] range : atomSpecModel.getRanges(model, chain))
+ {
+ if (!firstRange)
+ {
+ sb.append(COMMA);
+ }
+ firstRange = false;
+ sb.append(range[0]);
+ if (range[1] != range[0])
+ {
+ sb.append("-").append(range[1]);
+ }
+ }
+ sb.append(":").append(chain).append("/")
+ .append(String.valueOf(model + 1))
+ .append(".1");
+ }
+ }
+
+ return sb.toString();
+ }
+
}
/**
* Constructs Chimera commands to colour residues as per the Jalview alignment
*
- * @param files
- * @param viewPanel
+ * @param colourMap
* @param binding
* @return
*/
- public static StructureMappingcommandSet[] getColourBySequenceCommand(
- String[] files, AlignmentViewPanel viewPanel,
+ public static String[] getColourBySequenceCommand(
+ Map<Object, AtomSpecModel> colourMap,
AAStructureBindingModel binding)
{
- StructureSelectionManager ssm = binding.getSsm();
- SequenceRenderer sr = binding.getSequenceRenderer(viewPanel);
- SequenceI[][] sequence = binding.getSequence();
- boolean hideHiddenRegions = binding.isShowAlignmentOnly()
- && binding.isHideHiddenRegions();
-
- Map<Object, AtomSpecModel> colourMap = buildColoursMap(ssm, files,
- sequence, sr, hideHiddenRegions, viewPanel);
-
List<String> colourCommands = buildColourCommands(colourMap, binding);
- StructureMappingcommandSet cs = new StructureMappingcommandSet(
- ChimeraCommands.class, null,
- colourCommands.toArray(new String[colourCommands.size()]));
-
- return new StructureMappingcommandSet[] { cs };
+ return colourCommands.toArray(new String[colourCommands.size()]);
}
/**
{
if (startPos != -1)
{
- addColourRange(colourMap, lastColour, pdbfnum, startPos,
+ addMapRange(colourMap, lastColour, pdbfnum, startPos,
lastPos, lastChain);
}
startPos = pos;
// final colour range
if (lastColour != null)
{
- addColourRange(colourMap, lastColour, pdbfnum, startPos,
+ addMapRange(colourMap, lastColour, pdbfnum, startPos,
lastPos, lastChain);
}
// break;
}
/**
- * Helper method to add one contiguous colour range to the colour map.
+ * Helper method to add one contiguous range to the map, for a given value key
+ * (e.g. colour or feature type), structure model number, and chain
*
* @param map
* @param key
* @param endPos
* @param chain
*/
- protected static void addColourRange(Map<Object, AtomSpecModel> map,
+ public static void addMapRange(Map<Object, AtomSpecModel> map,
Object key, int model, int startPos, int endPos, String chain)
{
/*
}
for (int[] range : mappedRanges)
{
- addColourRange(featureValues, value, modelNumber, range[0],
+ addMapRange(featureValues, value, modelNumber, range[0],
range[1], mapping.getChain());
}
}
/**
* Sends a set of colour commands to the structure viewer
*
- * @param colourBySequenceCommands
+ * @param commands
*/
@Override
- protected void colourBySequence(
- StructureMappingcommandSet[] colourBySequenceCommands)
+ protected void colourBySequence(String[] commands)
{
- for (StructureMappingcommandSet cpdbbyseq : colourBySequenceCommands)
+ for (String command : commands)
{
- for (String command : cpdbbyseq.commands)
- {
- sendAsynchronousCommand(command, COLOURING_CHIMERA);
- }
+ sendAsynchronousCommand(command, COLOURING_CHIMERA);
}
}
/**
+ * Computes and returns a set of commands to colour residues in Chimera the same
+ * as mapped residues in the alignment
+ *
* @param files
* @param viewPanel
* @return
*/
@Override
- protected StructureMappingcommandSet[] getColourBySequenceCommands(
+ protected String[] getColourBySequenceCommands(
String[] files, AlignmentViewPanel viewPanel)
{
- return ChimeraCommands.getColourBySequenceCommand(files, viewPanel,
- this);
+ Map<Object, AtomSpecModel> colourMap = buildColoursMap(viewPanel);
+
+ return ChimeraCommands.getColourBySequenceCommand(colourMap, this);
}
/**
// Set the colour using the current view for the associated alignframe
for (AlignmentViewPanel avp : _colourwith)
{
- binding.colourBySequence(avp);
+ binding.updateStructureColours(avp);
}
seqColoursApplied = true;
}
import jalview.api.AlignViewportI;
import jalview.api.AlignmentViewPanel;
+import jalview.api.FeatureRenderer;
import jalview.api.SequenceRenderer;
import jalview.api.StructureSelectionManagerProvider;
import jalview.api.structures.JalviewStructureDisplayI;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SequenceI;
import jalview.ext.rbvi.chimera.AtomSpecModel;
+import jalview.ext.rbvi.chimera.ChimeraCommands;
import jalview.io.DataSourceType;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
import jalview.schemes.ColourSchemeI;
import jalview.structure.AtomSpec;
import jalview.structure.StructureListener;
import jalview.structure.StructureMapping;
-import jalview.structure.StructureMappingcommandSet;
import jalview.structure.StructureSelectionManager;
import jalview.util.Comparison;
import jalview.util.MessageManager;
import java.util.BitSet;
import java.util.Collections;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
/**
*
public abstract void setBackgroundColour(Color col);
- protected abstract StructureMappingcommandSet[] getColourBySequenceCommands(
+ protected abstract String[] getColourBySequenceCommands(
String[] files, AlignmentViewPanel avp);
/**
AlignmentViewPanel alignment);
protected abstract void colourBySequence(
- StructureMappingcommandSet[] colourBySequenceCommands);
+ String[] colourBySequenceCommands);
public abstract void colourByChain();
* colours on either change of alignment colours, or change to the visible
* region of the alignment.
*/
- public void colourBySequence(AlignmentViewPanel alignmentv)
+ public void updateStructureColours(AlignmentViewPanel alignmentv)
{
if (!isLoadingFinished())
{
}
String[] files = getStructureFiles();
- StructureMappingcommandSet[] colourBySequenceCommands = getColourBySequenceCommands(
+ String[] colourBySequenceCommands = getColourBySequenceCommands(
files, alignmentv);
colourBySequence(colourBySequenceCommands);
}
}
if (!isLoadingFromArchive())
{
- colourBySequence(ap);
+ updateStructureColours(ap);
}
}
{
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(
+ 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,
+ pdbfnum, startPos,
+ lastPos, lastChain);
+ }
+ startPos = pos;
+ }
+ lastColour = colour;
+ lastPos = pos;
+ lastChain = chain;
+ }
+ // final colour range
+ if (lastColour != null)
+ {
+ ChimeraCommands.addMapRange(colourMap, lastColour, pdbfnum,
+ startPos, lastPos, lastChain);
+ }
+ // break;
+ }
+ }
+ }
+ }
+ return colourMap;
+ }
}
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;
}
@Override
- protected StructureMappingcommandSet[] getColourBySequenceCommands(
- String[] files, AlignmentViewPanel avp)
+ protected String[] getColourBySequenceCommands(String[] files,
+ AlignmentViewPanel avp)
{
return null;
}
}
@Override
- protected void colourBySequence(
- StructureMappingcommandSet[] colourBySequenceCommands)
+ protected void colourBySequence(String[] colourBySequenceCommands)
{
}
{
Map<Object, AtomSpecModel> map = new LinkedHashMap<>();
- ChimeraCommands.addColourRange(map, Color.blue, 0, 2, 5, "A");
- ChimeraCommands.addColourRange(map, Color.blue, 0, 7, 7, "B");
- ChimeraCommands.addColourRange(map, Color.blue, 0, 9, 23, "A");
- ChimeraCommands.addColourRange(map, Color.blue, 1, 1, 1, "A");
- ChimeraCommands.addColourRange(map, Color.blue, 1, 4, 7, "B");
- ChimeraCommands.addColourRange(map, Color.yellow, 1, 8, 8, "A");
- ChimeraCommands.addColourRange(map, Color.yellow, 1, 3, 5, "A");
- ChimeraCommands.addColourRange(map, Color.red, 0, 3, 5, "A");
- ChimeraCommands.addColourRange(map, Color.red, 0, 6, 9, "A");
+ 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");
// 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.addColourRange(featureValues, "X", 0, 8, 20, "A");
+ ChimeraCommands.addMapRange(featureValues, "X", 0, 8, 20, "A");
List<String> commands = ChimeraCommands
.buildSetAttributeCommands(featuresMap, mockBinding);
assertEquals(commands.get(0), "setattr r jv_chain 'X' #0:8-20.A");
// add same feature value, overlapping range
- ChimeraCommands.addColourRange(featureValues, "X", 0, 3, 9, "A");
+ ChimeraCommands.addMapRange(featureValues, "X", 0, 3, 9, "A");
// same feature value, contiguous range
- ChimeraCommands.addColourRange(featureValues, "X", 0, 21, 25, "A");
+ ChimeraCommands.addMapRange(featureValues, "X", 0, 21, 25, "A");
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.addColourRange(featureValues, "X", 0, 21, 25, "B");
+ ChimeraCommands.addMapRange(featureValues, "X", 0, 21, 25, "B");
// same feature value and chain, different model
- ChimeraCommands.addColourRange(featureValues, "X", 1, 26, 30, "A");
+ ChimeraCommands.addMapRange(featureValues, "X", 1, 26, 30, "A");
commands = ChimeraCommands.buildSetAttributeCommands(featuresMap,
mockBinding);
assertEquals(1, commands.size());
"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");
+ ChimeraCommands.addMapRange(featureValues, "Y", 0, 40, 50, "A");
commands = ChimeraCommands.buildSetAttributeCommands(featuresMap,
mockBinding);
assertEquals(2, commands.size());
featuresMap.clear();
featureValues.clear();
featuresMap.put("side-chain binding!", featureValues);
- ChimeraCommands.addColourRange(featureValues,
+ ChimeraCommands.addMapRange(featureValues,
"<html>metal <a href=\"http:a.b.c/x\"> 'ion!", 0, 7, 15,
"A");
// feature names are sanitised to change non-alphanumeric to underscore
PA.setValue(mockBinding, "ssm", ssm);
PA.setValue(mockBinding, "sequence", seqs);
- StructureMappingcommandSet[] commands = ChimeraCommands
+ String[] commands = ChimeraCommands
.getColourBySequenceCommand(files, af.alignPanel, 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
import jalview.io.FileFormats;
import jalview.schemes.ColourSchemeI;
import jalview.structure.AtomSpec;
-import jalview.structure.StructureMappingcommandSet;
import jalview.structure.StructureSelectionManager;
import jalview.structures.models.AAStructureBindingModel.SuperposeData;
}
@Override
- protected StructureMappingcommandSet[] getColourBySequenceCommands(
- String[] files, AlignmentViewPanel avp)
+ protected String[] getColourBySequenceCommands(String[] files,
+ AlignmentViewPanel avp)
{
// TODO Auto-generated method stub
return null;
}
@Override
- protected void colourBySequence(
- StructureMappingcommandSet[] colourBySequenceCommands)
+ protected void colourBySequence(String[] colourBySequenceCommands)
{
// TODO Auto-generated method stub
}
@Override
- protected StructureMappingcommandSet[] getColourBySequenceCommands(
+ protected String[] getColourBySequenceCommands(
String[] files, AlignmentViewPanel avp)
{
return null;
}
@Override
- protected void colourBySequence(
- StructureMappingcommandSet[] colourBySequenceCommands)
+ protected void colourBySequence(String[] colourBySequenceCommands)
{
}