From 81316c6cc11e29c893d55e87ebd16d9ecd09c1f3 Mon Sep 17 00:00:00 2001 From: gmungoc Date: Wed, 3 Dec 2014 15:00:53 +0000 Subject: [PATCH] JAL-1609 wip on Chimera colour by sequence --- .../edu/ucsf/rbvi/strucviz2/ChimeraManager.java | 3 +- src/jalview/ext/rbvi/chimera/ChimeraCommands.java | 213 ++++++++++++++++---- src/jalview/schemes/Blosum62ColourScheme.java | 9 +- src/jalview/ws/HttpClientUtils.java | 9 +- 4 files changed, 193 insertions(+), 41 deletions(-) diff --git a/src/ext/edu/ucsf/rbvi/strucviz2/ChimeraManager.java b/src/ext/edu/ucsf/rbvi/strucviz2/ChimeraManager.java index f65f00b..a76c7e0 100644 --- a/src/ext/edu/ucsf/rbvi/strucviz2/ChimeraManager.java +++ b/src/ext/edu/ucsf/rbvi/strucviz2/ChimeraManager.java @@ -746,7 +746,8 @@ public class ChimeraManager */ public List sendChimeraCommand(String command, boolean reply) { - if (!isChimeraLaunched()) + if (!isChimeraLaunched() || command == null + || "".equals(command.trim())) { return null; } diff --git a/src/jalview/ext/rbvi/chimera/ChimeraCommands.java b/src/jalview/ext/rbvi/chimera/ChimeraCommands.java index 4ee74aa..3c47ed1 100644 --- a/src/jalview/ext/rbvi/chimera/ChimeraCommands.java +++ b/src/jalview/ext/rbvi/chimera/ChimeraCommands.java @@ -27,10 +27,15 @@ import jalview.datamodel.SequenceI; import jalview.structure.StructureMapping; import jalview.structure.StructureMappingcommandSet; import jalview.structure.StructureSelectionManager; +import jalview.util.Comparison; import java.awt.Color; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; /** @@ -54,15 +59,31 @@ public class ChimeraCommands SequenceI[][] sequence, SequenceRenderer sr, FeatureRenderer fr, AlignmentI alignment) { - - ArrayList cset = new ArrayList(); + String defAttrPath = null; + FileOutputStream fos = null; + try + { + File outFile = File.createTempFile("jalviewdefattr", ".xml"); + outFile.deleteOnExit(); + defAttrPath = outFile.getPath(); + fos = new FileOutputStream(outFile); + fos.write("attribute: jalviewclr\n".getBytes()); + } catch (IOException e1) + { + e1.printStackTrace(); + } + List cset = new ArrayList(); /* * Map of { colour, positionSpecs} */ Map colranges = new LinkedHashMap(); + StringBuilder setAttributes = new StringBuilder(256); + String lastColour = "none"; + Color lastCol = null; for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++) { + boolean startModel = true; StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]); if (mapping == null || mapping.length < 1) @@ -70,21 +91,21 @@ public class ChimeraCommands continue; } - int startPos = -1, lastPos = -1, startModel = -1, lastModel = -1; + int startPos = -1, lastPos = -1; String lastChain = ""; - Color lastCol = null; for (int s = 0; s < sequence[pdbfnum].length; s++) { for (int sp, m = 0; m < mapping.length; m++) { - if (mapping[m].getSequence() == sequence[pdbfnum][s] - && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1) + final SequenceI seq = sequence[pdbfnum][s]; + if (mapping[m].getSequence() == seq + && (sp = alignment.findIndex(seq)) > -1) { SequenceI asp = alignment.getSequenceAt(sp); for (int r = 0; r < asp.getLength(); r++) { // no mapping to gaps in sequence - if (jalview.util.Comparison.isGap(asp.getCharAt(r))) + if (Comparison.isGap(asp.getCharAt(r))) { continue; } @@ -95,51 +116,152 @@ public class ChimeraCommands continue; } - Color col = sr.getResidueBoxColour(sequence[pdbfnum][s], r); - - if (fr != null) + Color col = getResidueColour(seq, r, sr, fr); + /* + * 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 = !col.equals(lastCol); + final boolean nonContig = lastPos + 1 != pos; + final boolean newChain = !mapping[m].getChain().equals(lastChain); + if (newColour || nonContig || startModel || newChain) { - col = fr.findFeatureColour(col, sequence[pdbfnum][s], r); - } - if (lastCol != col || lastPos + 1 != pos - || pdbfnum != lastModel - || !mapping[m].getChain().equals(lastChain)) - { - if (lastCol != null) + if (/* lastCol != null */startPos != -1) { - addColourRange(colranges, lastCol,startModel,startPos,lastPos,lastChain); + addColourRange(colranges, lastCol, pdbfnum, startPos, + lastPos, lastChain, startModel); + startModel = false; } - lastCol = null; + // lastCol = null; startPos = pos; - startModel = pdbfnum; } lastCol = col; lastPos = pos; - lastModel = pdbfnum; + // lastModel = pdbfnum; lastChain = mapping[m].getChain(); } // final colour range if (lastCol != null) { - addColourRange(colranges, lastCol,startModel,startPos,lastPos,lastChain); + addColourRange(colranges, lastCol, pdbfnum, startPos, + lastPos, lastChain, false); } break; } } } - // Finally, add the command set ready to be returned. - StringBuilder coms = new StringBuilder(256); - for (String cr:colranges.keySet()) + } + try + { + lastColour = buildColourCommands(cset, colranges, + fos, setAttributes); + } catch (IOException e) { - coms.append("color #"+cr+" "+colranges.get(cr)+";"); + e.printStackTrace(); } - cset.add(new StructureMappingcommandSet(ChimeraCommands.class, - files[pdbfnum], new String[] { coms.toString() })); + + try + { + fos.close(); + } catch (IOException e) + { + e.printStackTrace(); + } + + /* + * Send a rangeColor command, preceded by either defattr or setattr, + * whichever we end up preferring! + * + * rangecolor requires a minimum of two attribute values to operate on + */ + StringBuilder rangeColor = new StringBuilder(256); + rangeColor.append("rangecolor jalviewclr"); + int colourId = 0; + for (String colour : colranges.keySet()) + { + colourId++; + rangeColor.append(" " + colourId + " " + colour); } + String rangeColorCommand = rangeColor.toString(); + if (rangeColorCommand.split(" ").length < 5) + { + rangeColorCommand += " max " + lastColour; + } + final String defAttrCommand = "defattr " + defAttrPath + + " raiseTool false"; + final String setAttrCommand = setAttributes.toString(); + final String attrCommand = false ? defAttrCommand : setAttrCommand; + cset.add(new StructureMappingcommandSet(ChimeraCommands.class, null, + new String[] + { attrCommand /* , rangeColorCommand */})); + return cset.toArray(new StructureMappingcommandSet[cset.size()]); } /** + * Get the residue colour at the given sequence position - as determined by + * the sequence group colour (if any), else the colour scheme, possibly + * overridden by a feature colour. + * + * @param seq + * @param position + * @param sr + * @param fr + * @return + */ + protected static Color getResidueColour(final SequenceI seq, + int position, SequenceRenderer sr, FeatureRenderer fr) + { + Color col = sr.getResidueBoxColour(seq, position); + + if (fr != null) + { + col = fr.findFeatureColour(col, seq, position); + } + return col; + } + + /** + * Helper method to build the colour commands for one PDBfile. + * + * @param cset + * the list of commands to be added to + * @param colranges + * the map of colours to residue positions already determined + * @param fos + * file to write 'defattr' commands to + * @param setAttributes + * @throws IOException + */ + protected static String buildColourCommands( + List cset, + Map colranges, + FileOutputStream fos, StringBuilder setAttributes) + throws IOException + { + int colourId = 0; + String lastColour = null; + for (String colour : colranges.keySet()) + { + lastColour = colour; + colourId++; + /* + * Using color command directly is slow for larger structures. + * setAttributes.append("color #" + colour + " " + colranges.get(colour)+ + * ";"); + */ + setAttributes.append("color " + colour + " " + colranges.get(colour) + + ";"); + final String atomSpec = new String(colranges.get(colour)); + // setAttributes.append("setattr r jalviewclr " + colourId + " " + // + atomSpec + ";"); + fos.write(("\t" + atomSpec + "\t" + colourId + "\n").getBytes()); + } + return lastColour; + } + + /** * Helper method to record a range of positions of the same colour. * * @param colranges @@ -148,12 +270,14 @@ public class ChimeraCommands * @param startPos * @param endPos * @param chain + * @param changeModel */ private static void addColourRange(Map colranges, - Color colour, int model, - int startPos, int endPos, String chain) + Color colour, int model, int startPos, int endPos, String chain, + boolean startModel) { - String colstring = ((colour.getRed()< 16) ? "0":"")+Integer.toHexString(colour.getRed()) + String colstring = "#" + ((colour.getRed() < 16) ? "0" : "") + + Integer.toHexString(colour.getRed()) + ((colour.getGreen()< 16) ? "0":"")+Integer.toHexString(colour.getGreen()) + ((colour.getBlue()< 16) ? "0":"")+Integer.toHexString(colour.getBlue()); StringBuilder currange = colranges.get(colstring); @@ -161,12 +285,31 @@ public class ChimeraCommands { colranges.put(colstring, currange = new StringBuilder(256)); } - if (currange.length() > 0) + /* + * Format as (e.g.) #0:1-3.A,5.A,7-10.A,...#1:1-4.B,..etc + */ + // if (currange.length() > 0) + // { + // currange.append("|"); + // } + // currange.append("#" + model + ":" + ((startPos==endPos) ? startPos : + // startPos + "-" + // + endPos) + "." + chain); + if (currange.length() == 0) + { + currange.append("#" + model + ":"); + } + else if (startModel) + { + currange.append(",#" + model + ":"); + } + else { - currange.append("|"); + currange.append(","); } - currange.append("#" + model + ":" + ((startPos==endPos) ? startPos : startPos + "-" - + endPos) + "." + chain); + final String rangeSpec = (startPos == endPos) ? Integer + .toString(startPos) : (startPos + "-" + endPos); + currange.append(rangeSpec + "." + chain); } } diff --git a/src/jalview/schemes/Blosum62ColourScheme.java b/src/jalview/schemes/Blosum62ColourScheme.java index 41f7781..70c7685 100755 --- a/src/jalview/schemes/Blosum62ColourScheme.java +++ b/src/jalview/schemes/Blosum62ColourScheme.java @@ -21,14 +21,13 @@ package jalview.schemes; import jalview.analysis.AAFrequency; - -import java.awt.Color; -import java.util.Map; - import jalview.datamodel.AnnotatedCollectionI; import jalview.datamodel.SequenceCollectionI; import jalview.datamodel.SequenceI; +import java.awt.Color; +import java.util.Map; + public class Blosum62ColourScheme extends ResidueColourScheme { public Blosum62ColourScheme() @@ -59,6 +58,7 @@ public class Blosum62ColourScheme extends ResidueColourScheme if (max.indexOf(res) > -1) { + // TODO use a constant here? currentColour = new Color(154, 154, 255); } else @@ -74,6 +74,7 @@ public class Blosum62ColourScheme extends ResidueColourScheme if (c > 0) { + // TODO use a constant here? currentColour = new Color(204, 204, 255); } else diff --git a/src/jalview/ws/HttpClientUtils.java b/src/jalview/ws/HttpClientUtils.java index 229fa4e..1bdf64f 100644 --- a/src/jalview/ws/HttpClientUtils.java +++ b/src/jalview/ws/HttpClientUtils.java @@ -29,6 +29,7 @@ import java.util.List; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; +import org.apache.http.HttpVersion; import org.apache.http.NameValuePair; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; @@ -40,6 +41,9 @@ import org.apache.http.entity.mime.content.FileBody; import org.apache.http.entity.mime.content.InputStreamBody; import org.apache.http.entity.mime.content.StringBody; import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.CoreProtocolPNames; +import org.apache.http.params.HttpParams; /** * Helpful procedures for working with services via HTTPClient @@ -64,7 +68,10 @@ public class HttpClientUtils List vals) throws ClientProtocolException, IOException { - HttpClient httpclient = new DefaultHttpClient(); + HttpParams params = new BasicHttpParams(); + params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, + HttpVersion.HTTP_1_1); + HttpClient httpclient = new DefaultHttpClient(params); HttpPost httppost = new HttpPost(postUrl); UrlEncodedFormEntity ue = new UrlEncodedFormEntity(vals, "UTF-8"); httppost.setEntity(ue); -- 1.7.10.2