X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fjalview%2Fext%2Frbvi%2Fchimera%2FChimeraCommands.java;h=bfec5b274ae824ceb7cedeaaf60417453737e8af;hb=970992fea3af6d3495bf4bc795e81295e885df4d;hp=3caaac3532367e30f3f2d11003cbdb23c9560437;hpb=0d1529f5a1f02b9cb959f0fe0d3e7f468723b83a;p=jalview.git diff --git a/src/jalview/ext/rbvi/chimera/ChimeraCommands.java b/src/jalview/ext/rbvi/chimera/ChimeraCommands.java index 3caaac3..bfec5b2 100644 --- a/src/jalview/ext/rbvi/chimera/ChimeraCommands.java +++ b/src/jalview/ext/rbvi/chimera/ChimeraCommands.java @@ -23,19 +23,17 @@ package jalview.ext.rbvi.chimera; import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; import jalview.api.FeatureRenderer; -import jalview.api.SequenceRenderer; import jalview.datamodel.AlignmentI; -import jalview.datamodel.HiddenColumns; import jalview.datamodel.MappedFeatures; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import jalview.gui.Desktop; -import jalview.renderer.seqfeatures.FeatureColourFinder; import jalview.structure.StructureMapping; import jalview.structure.StructureMappingcommandSet; import jalview.structure.StructureSelectionManager; +import jalview.structures.models.AAStructureBindingModel; import jalview.util.ColorUtils; -import jalview.util.Comparison; +import jalview.util.StructureCommands; import java.awt.Color; import java.util.ArrayList; @@ -50,37 +48,30 @@ import java.util.Map; * @author JimP * */ -public class ChimeraCommands +public class ChimeraCommands extends StructureCommands { - 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 colourMap + * @param binding * @return */ - public static StructureMappingcommandSet[] getColourBySequenceCommand( - StructureSelectionManager ssm, String[] files, - SequenceI[][] sequence, SequenceRenderer sr, - AlignmentViewPanel viewPanel) + public static String[] getColourBySequenceCommand( + Map colourMap, + AAStructureBindingModel binding) { - Map colourMap = buildColoursMap(ssm, files, - sequence, sr, viewPanel); + List colourCommands = buildColourCommands(colourMap, binding); - List colourCommands = buildColourCommands(colourMap); - - StructureMappingcommandSet cs = new StructureMappingcommandSet( - ChimeraCommands.class, null, - colourCommands.toArray(new String[colourCommands.size()])); - - return new StructureMappingcommandSet[] { cs }; + return colourCommands.toArray(new String[colourCommands.size()]); } /** @@ -96,10 +87,12 @@ public class ChimeraCommands * * * @param colourMap + * @param binding * @return */ protected static List buildColourCommands( - Map colourMap) + Map colourMap, + AAStructureBindingModel binding) { /* * This version concatenates all commands into a single String (semi-colon @@ -108,231 +101,44 @@ public class ChimeraCommands */ List commands = new ArrayList<>(); StringBuilder sb = new StringBuilder(256); - boolean firstColour = true; + sb.append(COLOR_GRAY_HEX); + for (Object key : colourMap.keySet()) { Color colour = (Color) key; String colourCode = ColorUtils.toTkCode(colour); - if (!firstColour) - { - sb.append("; "); - } + sb.append("; "); sb.append("color ").append(colourCode).append(" "); - firstColour = false; 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>> 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> 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.
-   * Color
-   *     Model number
-   *         Chain
-   *             list of start/end ranges
-   * Ordering is by order of addition (for colours and positions), natural ordering (for models and chains)
-   * 
- */ - protected static Map buildColoursMap( - StructureSelectionManager ssm, String[] files, - SequenceI[][] sequence, SequenceRenderer sr, - AlignmentViewPanel viewPanel) - { - FeatureRenderer fr = viewPanel.getFeatureRenderer(); - FeatureColourFinder finder = new FeatureColourFinder(fr); - AlignViewportI viewport = viewPanel.getAlignViewport(); - HiddenColumns cs = viewport.getAlignment().getHiddenColumns(); - AlignmentI al = viewport.getAlignment(); - Map 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); - - /* - * darker colour for hidden regions - */ - if (!cs.isVisible(r)) - { - 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) - { - addAtomSpecRange(colourMap, lastColour, pdbfnum, startPos, - lastPos, lastChain); - } - startPos = pos; - } - lastColour = colour; - lastPos = pos; - lastChain = chain; - } - // final colour range - if (lastColour != null) - { - addAtomSpecRange(colourMap, lastColour, pdbfnum, startPos, - lastPos, lastChain); - } - // break; - } - } - } - } - return colourMap; - } - - /** - * Helper method to add one contiguous range to the AtomSpec model for the given - * value (creating the model if necessary). As used by Jalview, {@code value} is - *
    - *
  • a colour, when building a 'colour structure by sequence' command
  • - *
  • a feature value, when building a 'set Chimera attributes from features' - * command
  • - *
- * - * @param map - * @param value - * @param model - * @param startPos - * @param endPos - * @param chain - */ - protected static void addAtomSpecRange(Map map, - Object value, int model, int startPos, int endPos, String chain) - { - /* - * Get/initialize map of data for the colour - */ - AtomSpecModel atomSpec = map.get(value); - if (atomSpec == null) - { - atomSpec = new AtomSpecModel(); - map.put(value, atomSpec); - } - - atomSpec.addRange(model, startPos, endPos, chain); - } - - /** * 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> featureMap = buildFeaturesMap( ssm, files, seqs, viewPanel); - List commands = buildSetAttributeCommands(featureMap); + List commands = buildSetAttributeCommands(featureMap, binding); StructureMappingcommandSet cs = new StructureMappingcommandSet( ChimeraCommands.class, null, @@ -579,10 +385,12 @@ public class ChimeraCommands * * * @param featureMap + * @param binding * @return */ protected static List buildSetAttributeCommands( - Map> featureMap) + Map> featureMap, + AAStructureBindingModel binding) { List commands = new ArrayList<>(); for (String featureType : featureMap.keySet()) @@ -608,7 +416,7 @@ public class ChimeraCommands 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()); } } @@ -652,4 +460,56 @@ public class ChimeraCommands 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; + sb.append(binding.getModelSpec(model)).append(":"); + + boolean firstPositionForModel = true; + + for (String chain : atomSpec.getChains(model)) + { + chain = " ".equals(chain) ? chain : chain.trim(); + + List rangeList = atomSpec.getRanges(model, chain); + + String chainToken = " ".equals(chain) ? "." : "." + chain; + appendResidueRange(sb, rangeList, chainToken, + firstPositionForModel); + firstPositionForModel = false; + } + } + return sb.toString(); + } + + /** + * Chimera atomspec requires chain to be specified for each start-end residue + * range, otherwise it will apply to all chains + * + * @param sb + * @param chain + */ + protected static void appendChainToRange(StringBuilder sb, String chain) + { + sb.append("."); + if (!" ".equals(chain)) + { + sb.append(chain); + } + } + }