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