JAL-2434 omit unmapped positions from mapping
[jalview.git] / src / jalview / ws / phyre2 / Phyre2Client.java
1 package jalview.ws.phyre2;
2
3 import jalview.datamodel.AlignmentI;
4 import jalview.datamodel.SequenceI;
5 import jalview.fts.core.DecimalFormatTableCellRenderer;
6 import jalview.io.AppletFormatAdapter;
7 import jalview.io.DataSourceType;
8 import jalview.io.FileFormat;
9 import jalview.io.FormatAdapter;
10 import jalview.io.StructureFile;
11 import jalview.schemes.ResidueProperties;
12 import jalview.structure.StructureMapping;
13 import jalview.structure.StructureMappingClient;
14 import jalview.structures.models.MappingOutputModel;
15 import jalview.util.Comparison;
16 import jalview.util.Format;
17
18 import java.io.BufferedReader;
19 import java.io.FileReader;
20 import java.io.IOException;
21 import java.io.PrintStream;
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.List;
25
26 import javax.swing.JTable;
27 import javax.swing.table.DefaultTableModel;
28
29 public class Phyre2Client extends StructureMappingClient
30 {
31   private final static String NEWLINE = System.lineSeparator();
32
33   private String fastaMappingFile;
34
35   public Phyre2Client(StructureFile structureFile)
36   {
37     this.structureFile = structureFile;
38   }
39
40   public StructureMapping getStructureMapping(SequenceI seq,
41           String pdbFile, String fMappingFile, String chain)
42   {
43     this.fastaMappingFile = fMappingFile;
44     return getStructureMapping(seq, pdbFile, chain);
45   }
46
47   @Override
48   public StructureMapping getStructureMapping(SequenceI seq,
49           String pdbFile, String chain)
50   {
51     final StringBuilder mappingDetails = new StringBuilder(128);
52     PrintStream ps = new PrintStream(System.out)
53     {
54       @Override
55       public void print(String x)
56       {
57         mappingDetails.append(x);
58       }
59
60       @Override
61       public void println()
62       {
63         mappingDetails.append(NEWLINE);
64       }
65     };
66     HashMap<Integer, int[]> mapping = getPhyre2FastaMapping(seq, ps);
67
68     String mappingOutput = mappingDetails.toString();
69     StructureMapping phyre2ModelMapping = new StructureMapping(seq,
70             pdbFile, structureFile.getId(), chain, mapping, mappingOutput);
71     return phyre2ModelMapping;
72   }
73
74   public HashMap<Integer, int[]> getPhyre2FastaMapping(SequenceI inputSeq,
75           java.io.PrintStream os)
76   {
77     HashMap<Integer, int[]> mapping = new HashMap<Integer, int[]>();
78     AlignmentI seq2Phyre2ModelFastaMapping = null;
79     try
80     {
81       String fastaFile = getFastaMappingFile();
82       DataSourceType protocol = AppletFormatAdapter
83               .checkProtocol(fastaFile);
84       seq2Phyre2ModelFastaMapping = new FormatAdapter().readFile(fastaFile,
85               protocol, FileFormat.Fasta);
86     } catch (IOException e1)
87     {
88       e1.printStackTrace();
89     }
90     SequenceI[] seqs = seq2Phyre2ModelFastaMapping.getSequencesArray();
91     SequenceI tSequenceRes = seqs[0];
92     SequenceI tStructureRes = seqs[1];
93
94     // Essential to resolve fastaAlignment to input sequence and model sequence
95     // coordinates
96     tSequenceRes.setStart(inputSeq.getStart());
97     tSequenceRes.setEnd(inputSeq.getEnd());
98
99     tStructureRes.setStart(structureFile.getSeqsAsArray()[0].getStart());
100     tStructureRes.setEnd(structureFile.getSeqsAsArray()[0].getEnd());
101     try
102     {
103       int sequenceResLength = tSequenceRes.getLength();
104       int structureResLength = tStructureRes.getLength();
105       if (sequenceResLength == structureResLength)
106       {
107         int prevStructResNum = -1;
108         int alignmentLength = sequenceResLength + tSequenceRes.getStart();
109         for (int x = 0; x < alignmentLength; x++)
110         {
111           int alignSeqResidueIndex = tSequenceRes.findIndex(x);
112           int structResNum = tStructureRes
113                   .findPosition(alignSeqResidueIndex);
114           int sequenceResNum = tSequenceRes
115                   .findPosition(alignSeqResidueIndex - 1);
116           if (structResNum != prevStructResNum)
117           {
118             // System.out.println(sequenceResNum + " : " + prevStructResNum);
119             mapping.put(sequenceResNum, new int[] { prevStructResNum,
120                 StructureMapping.UNASSIGNED });
121           }
122           prevStructResNum = structResNum;
123         }
124       }
125     } catch (Exception e)
126     {
127       e.printStackTrace();
128     }
129
130     /*
131      * now populate atom positions for structure residues (and remove
132      * residue if atom position cannot be found)
133      */
134     try
135     {
136       populateAtomPositions(" ", mapping);
137     } catch (IllegalArgumentException e)
138     {
139       e.printStackTrace();
140     } catch (StructureMappingException e)
141     {
142       e.printStackTrace();
143     }
144
145     if (os != null)
146     {
147       MappingOutputModel mop = new MappingOutputModel();
148       mop.setSeqStart(tSequenceRes.getStart());
149       mop.setSeqEnd(tSequenceRes.getEnd());
150       mop.setSeqName(tSequenceRes.getName());
151       mop.setSeqResidue(tSequenceRes.getSequenceAsString());
152
153       mop.setStrStart(tStructureRes.getStart());
154       mop.setStrEnd(tStructureRes.getEnd());
155       mop.setStrName(tStructureRes.getName());
156       mop.setStrResidue(tStructureRes.getSequenceAsString());
157
158       mop.setType("pep");
159       try
160       {
161         os.print(getMappingOutput(mop).toString());
162       } catch (Exception e)
163       {
164         e.printStackTrace();
165       }
166       os.println();
167     }
168     return mapping;
169   }
170
171   private String getFastaMappingFile()
172   {
173     return fastaMappingFile;
174   }
175
176   void setFastaMappingFile(String fastaMappingFile)
177   {
178     this.fastaMappingFile = fastaMappingFile;
179   }
180
181   @Override
182   public StringBuffer getMappingOutput(MappingOutputModel mp)
183           throws StructureMappingException
184   {
185     String seqRes = mp.getSeqResidue();
186     String seqName = mp.getSeqName();
187     int sStart = mp.getSeqStart();
188     int sEnd = mp.getSeqEnd();
189
190     String strRes = mp.getStrResidue();
191     String strName = mp.getStrName();
192     int pdbStart = mp.getStrStart();
193     int pdbEnd = mp.getStrEnd();
194
195     String type = mp.getType();
196
197     int maxid = (seqName.length() >= strName.length()) ? seqName.length()
198             : strName.length();
199     int len = 72 - maxid - 1;
200
201     int nochunks = ((seqRes.length()) / len)
202             + ((seqRes.length()) % len > 0 ? 1 : 0);
203     // output mappings
204     StringBuffer output = new StringBuffer();
205     output.append(NEWLINE);
206     output.append("Sequence \u27f7 Structure mapping details").append(
207             NEWLINE);
208     output.append("Method: Phyre2 Alignment");
209     output.append(NEWLINE).append(NEWLINE);
210
211     output.append(new Format("%" + maxid + "s").form(seqName));
212     output.append(" :  ");
213     output.append(String.valueOf(sStart));
214     output.append(" - ");
215     output.append(String.valueOf(sEnd));
216     output.append(" Maps to ");
217     output.append(NEWLINE);
218     output.append(new Format("%" + maxid + "s").form(strName));
219     output.append(" :  ");
220     output.append(String.valueOf(pdbStart));
221     output.append(" - ");
222     output.append(String.valueOf(pdbEnd));
223     output.append(NEWLINE).append(NEWLINE);
224
225     int matchedSeqCount = 0;
226     for (int j = 0; j < nochunks; j++)
227     {
228       // Print the first aligned sequence
229       output.append(new Format("%" + (maxid) + "s").form(seqName)).append(
230               " ");
231
232       for (int i = 0; i < len; i++)
233       {
234         if ((i + (j * len)) < seqRes.length())
235         {
236           output.append(seqRes.charAt(i + (j * len)));
237         }
238       }
239
240       output.append(NEWLINE);
241       output.append(new Format("%" + (maxid) + "s").form(" ")).append(" ");
242
243       // Print out the matching chars
244       for (int i = 0; i < len; i++)
245       {
246         try
247         {
248           if ((i + (j * len)) < seqRes.length())
249           {
250             boolean sameChar = Comparison.isSameResidue(
251                     seqRes.charAt(i + (j * len)),
252                     strRes.charAt(i + (j * len)), false);
253             if (sameChar
254                     && !jalview.util.Comparison.isGap(seqRes.charAt(i
255                             + (j * len))))
256             {
257               matchedSeqCount++;
258               output.append("|");
259             }
260             else if (type.equals("pep"))
261             {
262               if (ResidueProperties.getPAM250(seqRes.charAt(i + (j * len)),
263                       strRes.charAt(i + (j * len))) > 0)
264               {
265                 output.append(".");
266               }
267               else
268               {
269                 output.append(" ");
270               }
271             }
272             else
273             {
274               output.append(" ");
275             }
276           }
277         } catch (IndexOutOfBoundsException e)
278         {
279           continue;
280         }
281       }
282       // Now print the second aligned sequence
283       output = output.append(NEWLINE);
284       output = output.append(new Format("%" + (maxid) + "s").form(strName))
285               .append(" ");
286       for (int i = 0; i < len; i++)
287       {
288         if ((i + (j * len)) < strRes.length())
289         {
290           output.append(strRes.charAt(i + (j * len)));
291         }
292       }
293       output.append(NEWLINE).append(NEWLINE);
294     }
295     float pid = (float) matchedSeqCount / seqRes.length() * 100;
296     output.append("Length of alignment = " + seqRes.length()).append(
297             NEWLINE);
298     output.append(new Format("Percentage ID = %2.2f").form(pid));
299     return output;
300   }
301
302
303   public static List<Phyre2SummaryPojo> parsePhyreCrudeList(String crudeList)
304   {
305     List<Phyre2SummaryPojo> phyre2Results = new ArrayList<Phyre2SummaryPojo>();
306     try (BufferedReader br = new BufferedReader(new FileReader(crudeList)))
307     {
308       String line;
309       while ((line = br.readLine()) != null)
310       {
311         String[] lineData = line.split(" ");
312         Phyre2SummaryPojo psp = new Phyre2SummaryPojo();
313         psp.setSerialNo(Integer.valueOf(lineData[0]));
314         psp.setTemplateId(lineData[1]);
315         psp.setConfidence(100 * Double.valueOf(lineData[2]));
316         psp.setPid(Integer.valueOf(lineData[3]));
317         psp.setAlignedRange(lineData[4] + " - " + lineData[5]);
318         // psp.setCoverage(coverage);
319         // psp.setTemplateSummary(templateSummary);
320         phyre2Results.add(psp);
321       }
322     } catch (Exception e)
323     {
324       e.printStackTrace();
325     }
326     return phyre2Results;
327   }
328
329   public static DefaultTableModel getTableModel(
330           List<Phyre2SummaryPojo> phyreResults)
331   {
332     if (phyreResults == null)
333     {
334       return null;
335     }
336     DefaultTableModel tableModel = new DefaultTableModel()
337     {
338       @Override
339       public boolean isCellEditable(int row, int column)
340       {
341         return false;
342       }
343
344       @Override
345       public Class<?> getColumnClass(int columnIndex)
346       {
347         switch (columnIndex)
348         {
349         case 0:
350           return Integer.class;
351         case 1:
352           return String.class;
353         case 2:
354           return String.class;
355         case 3:
356           return String.class;
357         case 4:
358           return Double.class;
359         case 5:
360           return Integer.class;
361         case 6:
362           return String.class;
363         default:
364           return String.class;
365         }
366       }
367
368     };
369
370     tableModel.addColumn("#");
371     tableModel.addColumn("Template");
372     tableModel.addColumn("Aligned Range");
373     tableModel.addColumn("Coverage");
374     tableModel.addColumn("Confidence");
375     tableModel.addColumn("%.i.d");
376     tableModel.addColumn("Template Information");
377
378     for (Phyre2SummaryPojo res : phyreResults)
379     {
380       tableModel.addRow(new Object[] { res.getSerialNo(),
381           res.getTemplateId(), res.getAlignedRange(), res.getCoverage(),
382           res.getConfidence(), res.getPid(), res.getTemplateSummary() }); 
383     }
384     return tableModel;
385   }
386
387   public static void configurePhyreResultTable(JTable phyreResultTable)
388   {
389
390     DecimalFormatTableCellRenderer idCellRender = new DecimalFormatTableCellRenderer(
391             true, 0);
392     DecimalFormatTableCellRenderer pidCellRender = new DecimalFormatTableCellRenderer(
393             true, 1);
394     DecimalFormatTableCellRenderer confidenceCellRender = new DecimalFormatTableCellRenderer(
395             true, 1);
396
397     phyreResultTable.getColumn("#").setMinWidth(20);
398     phyreResultTable.getColumn("#").setPreferredWidth(30);
399     phyreResultTable.getColumn("#").setMaxWidth(40);
400     phyreResultTable.getColumn("#").setCellRenderer(idCellRender);
401
402     phyreResultTable.getColumn("Template").setMinWidth(60);
403     phyreResultTable.getColumn("Template").setPreferredWidth(90);
404     phyreResultTable.getColumn("Template").setMaxWidth(150);
405
406     phyreResultTable.getColumn("Aligned Range").setMinWidth(80);
407     phyreResultTable.getColumn("Aligned Range").setPreferredWidth(80);
408     phyreResultTable.getColumn("Aligned Range").setMaxWidth(120);
409
410     phyreResultTable.getColumn("Coverage").setMinWidth(60);
411     phyreResultTable.getColumn("Coverage").setPreferredWidth(60);
412     phyreResultTable.getColumn("Coverage").setMaxWidth(90);
413
414     phyreResultTable.getColumn("Confidence").setMinWidth(60);
415     phyreResultTable.getColumn("Confidence").setPreferredWidth(60);
416     phyreResultTable.getColumn("Confidence").setMaxWidth(90);
417     phyreResultTable.getColumn("Confidence").setCellRenderer(
418             confidenceCellRender);
419
420     phyreResultTable.getColumn("%.i.d").setMinWidth(45);
421     phyreResultTable.getColumn("%.i.d").setPreferredWidth(450);
422     phyreResultTable.getColumn("%.i.d").setMaxWidth(65);
423     phyreResultTable.getColumn("%.i.d").setCellRenderer(pidCellRender);
424
425     phyreResultTable.getColumn("Template Information").setMinWidth(400);
426     phyreResultTable.getColumn("Template Information").setPreferredWidth(
427             600);
428     phyreResultTable.getColumn("Template Information").setMaxWidth(1500);
429   }
430 }