From 8c0955545a1a10062467e2d6dc7feb1e855655c0 Mon Sep 17 00:00:00 2001 From: gmungoc Date: Tue, 8 Nov 2016 14:55:21 +0000 Subject: [PATCH] JAL-2295 feature and colour commands refactored to use AtomSpecModel --- src/jalview/ext/rbvi/chimera/ChimeraCommands.java | 157 ++++++++++---------- .../ext/rbvi/chimera/ChimeraCommandsTest.java | 20 +-- 2 files changed, 92 insertions(+), 85 deletions(-) diff --git a/src/jalview/ext/rbvi/chimera/ChimeraCommands.java b/src/jalview/ext/rbvi/chimera/ChimeraCommands.java index 93262aa..d34ac25 100644 --- a/src/jalview/ext/rbvi/chimera/ChimeraCommands.java +++ b/src/jalview/ext/rbvi/chimera/ChimeraCommands.java @@ -33,7 +33,6 @@ import jalview.util.Comparison; import java.awt.Color; import java.util.ArrayList; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -59,7 +58,7 @@ public class ChimeraCommands SequenceI[][] sequence, SequenceRenderer sr, FeatureRenderer fr, AlignmentI alignment) { - Map colourMap = buildColoursMap( + Map colourMap = buildColoursMap( ssm, files, sequence, sr, fr, alignment); List colourCommands = buildColourCommands(colourMap); @@ -87,7 +86,7 @@ public class ChimeraCommands * @return */ protected static List buildColourCommands( - Map colourMap) + Map colourMap) { /* * This version concatenates all commands into a single String (semi-colon @@ -97,8 +96,9 @@ public class ChimeraCommands List commands = new ArrayList(); StringBuilder sb = new StringBuilder(256); boolean firstColour = true; - for (Color colour : colourMap.keySet()) + for (Object key : colourMap.keySet()) { + Color colour = (Color) key; String colourCode = ColorUtils.toTkCode(colour); if (!firstColour) { @@ -177,12 +177,12 @@ public class ChimeraCommands * Ordering is by order of addition (for colours and positions), natural ordering (for models and chains) * */ - protected static Map buildColoursMap( + protected static Map buildColoursMap( StructureSelectionManager ssm, String[] files, SequenceI[][] sequence, SequenceRenderer sr, FeatureRenderer fr, AlignmentI alignment) { - Map colourMap = new LinkedHashMap(); + Map colourMap = new LinkedHashMap(); Color lastColour = null; for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++) { @@ -233,7 +233,7 @@ public class ChimeraCommands { if (startPos != -1) { - addColourRange(colourMap, lastColour, pdbfnum, startPos, + addRange(colourMap, lastColour, pdbfnum, startPos, lastPos, lastChain); } startPos = pos; @@ -245,7 +245,7 @@ public class ChimeraCommands // final colour range if (lastColour != null) { - addColourRange(colourMap, lastColour, pdbfnum, startPos, + addRange(colourMap, lastColour, pdbfnum, startPos, lastPos, lastChain); } // break; @@ -259,34 +259,32 @@ public class ChimeraCommands /** * Helper method to add one contiguous colour range to the colour map. * - * @param colourMap - * @param colour + * @param map + * @param key * @param model * @param startPos * @param endPos * @param chain */ - protected static void addColourRange( -Map colourMap, - Color colour, int model, int startPos, int endPos, String chain) + protected static void addRange(Map map, + Object key, int model, int startPos, int endPos, String chain) { - // refactor for reuse as addRange /* * Get/initialize map of data for the colour */ - AtomSpecModel colourData = colourMap.get(colour); - if (colourData == null) + AtomSpecModel atomSpec = map.get(key); + if (atomSpec == null) { - colourData = new AtomSpecModel(); - colourMap.put(colour, colourData); + atomSpec = new AtomSpecModel(); + map.put(key, atomSpec); } - colourData.addRange(model, startPos, endPos, chain); + atomSpec.addRange(model, startPos, endPos, chain); } /** * Constructs and returns a set of Chimera commands to set attributes on - * residues corresponding to features in Jalview. + * residues corresponding to features in Jalview * * @param ssm * @param files @@ -299,23 +297,20 @@ Map colourMap, StructureSelectionManager ssm, String[] files, SequenceI[][] seqs, FeatureRenderer fr, AlignmentI alignment) { - Map>>> featureMap = buildFeaturesMap( + Map featureMap = buildFeaturesMap( ssm, files, seqs, fr, alignment); - List colourCommands = buildSetAttributeCommands(featureMap); + List commands = buildSetAttributeCommands(featureMap); StructureMappingcommandSet cs = new StructureMappingcommandSet( ChimeraCommands.class, null, - colourCommands.toArray(new String[colourCommands.size()])); + commands.toArray(new String[commands.size()])); return cs; } /** - *
-   * Helper method to build a map of 
-   * { featureType, {modelNumber, {chain, {list of from-to ranges} } } }
-   * 
+ * Helper method to build a map of { featureType, AtomSpecModel } * * @param ssm * @param files @@ -324,11 +319,11 @@ Map colourMap, * @param alignment * @return */ - protected static Map>>> buildFeaturesMap( + protected static Map buildFeaturesMap( StructureSelectionManager ssm, String[] files, SequenceI[][] seqs, FeatureRenderer fr, AlignmentI alignment) { - Map>>> theMap = new HashMap>>>(); + Map theMap = new LinkedHashMap(); List visibleFeatures = fr.getDisplayedFeatureTypes(); if (visibleFeatures.isEmpty()) @@ -336,9 +331,6 @@ Map colourMap, return theMap; } - /* - * traverse mappings to structures - */ for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++) { StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]); @@ -348,7 +340,6 @@ Map colourMap, continue; } - int lastPos = -1; for (int seqNo = 0; seqNo < seqs[pdbfnum].length; seqNo++) { for (int m = 0; m < mapping.length; m++) @@ -357,49 +348,70 @@ Map colourMap, int sp = alignment.findIndex(seq); if (mapping[m].getSequence() == seq && sp > -1) { - SequenceI asp = alignment.getSequenceAt(sp); - /* - * traverse each sequence for its mapped positions + * found a sequence with a mapping to a structure; + * now scan its features */ - for (int r = 0; r < asp.getLength(); r++) - { - // no mapping to gaps in sequence - if (Comparison.isGap(asp.getCharAt(r))) - { - continue; - } - int residuePos = asp.findPosition(r); - int pos = mapping[m].getPDBResNum(residuePos); - - if (pos < 1 || pos == lastPos) - { - continue; - } - final String chain = mapping[m].getChain(); + SequenceI asp = alignment.getSequenceAt(sp); - /* - * record any features at this position, with the model, chain - * and residue number they map to - */ - List features = fr.findFeaturesAtRes(asp, - residuePos); - for (SequenceFeature feature : features) - { - if (!visibleFeatures.contains(feature)) - { - continue; - } - } - } + scanSequenceFeatures(visibleFeatures, mapping[m], asp, theMap, + pdbfnum); } } } - } + } return theMap; } /** + * Inspect features on the sequence; for each feature that is visible, + * determine its mapped ranges in the structure (if any) according to the + * given mapping, and add them to the map + * + * @param visibleFeatures + * @param mapping + * @param seq + * @param theMap + * @param modelNumber + */ + protected static void scanSequenceFeatures(List visibleFeatures, + StructureMapping mapping, SequenceI seq, + Map theMap, int modelNumber) + { + SequenceFeature[] sfs = seq.getSequenceFeatures(); + if (sfs == null) + { + return; + } + + for (SequenceFeature sf : sfs) + { + String type = sf.getType(); + if (!visibleFeatures.contains(type)) + { + continue; + } + List mappedRanges = mapping.getPDBResNumRanges(sf.getBegin(), + sf.getEnd()); + + if (!mappedRanges.isEmpty()) + { + AtomSpecModel atomSpec = theMap.get(type); + if (atomSpec == null) + { + atomSpec = new AtomSpecModel(); + theMap.put(type, atomSpec); + } + for (int[] range : mappedRanges) + { + atomSpec.addRange(modelNumber, range[0], range[1], + mapping.getChain()); + } + } + } + } + + /** * Traverse the map of features/models/chains/positions to construct a list of * 'setattr' commands (one per feature type). The format of each command is * @@ -416,22 +428,17 @@ Map colourMap, * * @param featureMap * @return - * @see http - * ://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/frameatom_spec - * .html */ protected static List buildSetAttributeCommands( - Map>>> featureMap) + Map featureMap) { List commands = new ArrayList(); for (String featureType : featureMap.keySet()) { StringBuilder sb = new StringBuilder(128); - featureType = featureType.replace(" ", "_"); - sb.append("setattr r jv:").append(featureType).append(" \" \" "); - final Map>> featureData = featureMap - .get(featureType); - sb.append(getAtomSpec(featureData)); + String sanitised = featureType.replace(" ", "_").replace("-", "_"); + sb.append("setattr r jv_").append(sanitised).append(" \" \" "); + sb.append(featureMap.get(featureType).getAtomSpec()); commands.add(sb.toString()); } diff --git a/test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java b/test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java index 3c6f830..b534b4f 100644 --- a/test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java +++ b/test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java @@ -34,16 +34,16 @@ public class ChimeraCommandsTest public void testBuildColourCommands() { - Map 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"); + Map map = new LinkedHashMap(); + ChimeraCommands.addRange(map, Color.blue, 0, 2, 5, "A"); + ChimeraCommands.addRange(map, Color.blue, 0, 7, 7, "B"); + ChimeraCommands.addRange(map, Color.blue, 0, 9, 23, "A"); + ChimeraCommands.addRange(map, Color.blue, 1, 1, 1, "A"); + ChimeraCommands.addRange(map, Color.blue, 1, 4, 7, "B"); + ChimeraCommands.addRange(map, Color.yellow, 1, 8, 8, "A"); + ChimeraCommands.addRange(map, Color.yellow, 1, 3, 5, "A"); + ChimeraCommands.addRange(map, Color.red, 0, 3, 5, "A"); + ChimeraCommands.addRange(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 -- 1.7.10.2