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