2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3 * Copyright (C) 2014 The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.ext.rbvi.chimera;
23 import jalview.api.FeatureRenderer;
24 import jalview.api.SequenceRenderer;
25 import jalview.datamodel.AlignmentI;
26 import jalview.datamodel.SequenceI;
27 import jalview.structure.StructureMapping;
28 import jalview.structure.StructureMappingcommandSet;
29 import jalview.structure.StructureSelectionManager;
30 import jalview.util.Comparison;
32 import java.awt.Color;
34 import java.io.FileOutputStream;
35 import java.io.IOException;
36 import java.util.ArrayList;
37 import java.util.LinkedHashMap;
38 import java.util.List;
42 * Routines for generating Chimera commands for Jalview/Chimera binding
47 public class ChimeraCommands
51 * utility to construct the commands to colour chains by the given alignment
52 * for passing to Chimera
54 * @returns Object[] { Object[] { <model being coloured>,
57 public static StructureMappingcommandSet[] getColourBySequenceCommand(
58 StructureSelectionManager ssm, String[] files,
59 SequenceI[][] sequence, SequenceRenderer sr, FeatureRenderer fr,
62 String defAttrPath = null;
63 FileOutputStream fos = null;
66 File outFile = File.createTempFile("jalviewdefattr", ".xml");
67 outFile.deleteOnExit();
68 defAttrPath = outFile.getPath();
69 fos = new FileOutputStream(outFile);
70 fos.write("attribute: jalviewclr\n".getBytes());
71 } catch (IOException e1)
75 List<StructureMappingcommandSet> cset = new ArrayList<StructureMappingcommandSet>();
78 * Map of { colour, positionSpecs}
80 Map<String, StringBuilder> colranges = new LinkedHashMap<String, StringBuilder>();
81 StringBuilder setAttributes = new StringBuilder(256);
82 String lastColour = "none";
84 for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
86 boolean startModel = true;
87 StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
89 if (mapping == null || mapping.length < 1)
94 int startPos = -1, lastPos = -1;
95 String lastChain = "";
96 for (int s = 0; s < sequence[pdbfnum].length; s++)
98 for (int sp, m = 0; m < mapping.length; m++)
100 final SequenceI seq = sequence[pdbfnum][s];
101 if (mapping[m].getSequence() == seq
102 && (sp = alignment.findIndex(seq)) > -1)
104 SequenceI asp = alignment.getSequenceAt(sp);
105 for (int r = 0; r < asp.getLength(); r++)
107 // no mapping to gaps in sequence
108 if (Comparison.isGap(asp.getCharAt(r)))
112 int pos = mapping[m].getPDBResNum(asp.findPosition(r));
114 if (pos < 1 || pos == lastPos)
119 Color col = getResidueColour(seq, r, sr, fr);
121 * Just keep incrementing the end position for this colour range
122 * _unless_ colour, PDB model or chain has changed, or there is a
123 * gap in the mapped residue sequence
125 final boolean newColour = !col.equals(lastCol);
126 final boolean nonContig = lastPos + 1 != pos;
127 final boolean newChain = !mapping[m].getChain().equals(lastChain);
128 if (newColour || nonContig || startModel || newChain)
130 if (/* lastCol != null */startPos != -1)
132 addColourRange(colranges, lastCol, pdbfnum, startPos,
133 lastPos, lastChain, startModel);
141 // lastModel = pdbfnum;
142 lastChain = mapping[m].getChain();
144 // final colour range
147 addColourRange(colranges, lastCol, pdbfnum, startPos,
148 lastPos, lastChain, false);
157 lastColour = buildColourCommands(cset, colranges,
159 } catch (IOException e)
167 } catch (IOException e)
173 * Send a rangeColor command, preceded by either defattr or setattr,
174 * whichever we end up preferring!
176 * rangecolor requires a minimum of two attribute values to operate on
178 StringBuilder rangeColor = new StringBuilder(256);
179 rangeColor.append("rangecolor jalviewclr");
181 for (String colour : colranges.keySet())
184 rangeColor.append(" " + colourId + " " + colour);
186 String rangeColorCommand = rangeColor.toString();
187 if (rangeColorCommand.split(" ").length < 5)
189 rangeColorCommand += " max " + lastColour;
191 final String defAttrCommand = "defattr " + defAttrPath
192 + " raiseTool false";
193 final String setAttrCommand = setAttributes.toString();
194 final String attrCommand = false ? defAttrCommand : setAttrCommand;
195 cset.add(new StructureMappingcommandSet(ChimeraCommands.class, null,
197 { attrCommand /* , rangeColorCommand */}));
199 return cset.toArray(new StructureMappingcommandSet[cset.size()]);
203 * Get the residue colour at the given sequence position - as determined by
204 * the sequence group colour (if any), else the colour scheme, possibly
205 * overridden by a feature colour.
213 protected static Color getResidueColour(final SequenceI seq,
214 int position, SequenceRenderer sr, FeatureRenderer fr)
216 Color col = sr.getResidueBoxColour(seq, position);
220 col = fr.findFeatureColour(col, seq, position);
226 * Helper method to build the colour commands for one PDBfile.
229 * the list of commands to be added to
231 * the map of colours to residue positions already determined
233 * file to write 'defattr' commands to
234 * @param setAttributes
235 * @throws IOException
237 protected static String buildColourCommands(
238 List<StructureMappingcommandSet> cset,
239 Map<String, StringBuilder> colranges,
240 FileOutputStream fos, StringBuilder setAttributes)
244 String lastColour = null;
245 for (String colour : colranges.keySet())
250 * Using color command directly is slow for larger structures.
251 * setAttributes.append("color #" + colour + " " + colranges.get(colour)+
254 setAttributes.append("color " + colour + " " + colranges.get(colour)
256 final String atomSpec = new String(colranges.get(colour));
257 // setAttributes.append("setattr r jalviewclr " + colourId + " "
258 // + atomSpec + ";");
259 fos.write(("\t" + atomSpec + "\t" + colourId + "\n").getBytes());
265 * Helper method to record a range of positions of the same colour.
275 private static void addColourRange(Map<String, StringBuilder> colranges,
276 Color colour, int model, int startPos, int endPos, String chain,
279 String colstring = "#" + ((colour.getRed() < 16) ? "0" : "")
280 + Integer.toHexString(colour.getRed())
281 + ((colour.getGreen()< 16) ? "0":"")+Integer.toHexString(colour.getGreen())
282 + ((colour.getBlue()< 16) ? "0":"")+Integer.toHexString(colour.getBlue());
283 StringBuilder currange = colranges.get(colstring);
284 if (currange == null)
286 colranges.put(colstring, currange = new StringBuilder(256));
289 * Format as (e.g.) #0:1-3.A,5.A,7-10.A,...#1:1-4.B,..etc
291 // if (currange.length() > 0)
293 // currange.append("|");
295 // currange.append("#" + model + ":" + ((startPos==endPos) ? startPos :
297 // + endPos) + "." + chain);
298 if (currange.length() == 0)
300 currange.append("#" + model + ":");
304 currange.append(",#" + model + ":");
308 currange.append(",");
310 final String rangeSpec = (startPos == endPos) ? Integer
311 .toString(startPos) : (startPos + "-" + endPos);
312 currange.append(rangeSpec + "." + chain);