package jalview.ws.phyre2; import jalview.datamodel.AlignmentI; import jalview.datamodel.SequenceI; import jalview.fts.core.DecimalFormatTableCellRenderer; import jalview.io.DataSourceType; import jalview.io.FileFormat; import jalview.io.FormatAdapter; import jalview.io.StructureFile; import jalview.schemes.ResidueProperties; import jalview.structure.StructureMapping; import jalview.structure.StructureMappingClient; import jalview.structures.models.MappingOutputModel; import jalview.util.Comparison; import jalview.util.Format; import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import javax.swing.JTable; import javax.swing.table.DefaultTableModel; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; public class Phyre2Client extends StructureMappingClient { private final static String NEWLINE = System.lineSeparator(); public static final int UNASSIGNED = -1; private final static String PATH_SEPARATOR = File.separator; public Phyre2Client(StructureFile structureFile) { this.structureFile = structureFile; } @Override public StructureMapping getStructureMapping(SequenceI seq, String pdbFile, String chain) { final StringBuilder mappingDetails = new StringBuilder(128); PrintStream ps = new PrintStream(System.out) { @Override public void print(String x) { mappingDetails.append(x); } @Override public void println() { mappingDetails.append(NEWLINE); } }; HashMap mapping = getPhyre2FastaMapping(seq, ps); String mappingOutput = mappingDetails.toString(); StructureMapping phyre2ModelMapping = new StructureMapping(seq, pdbFile, structureFile.getId(), chain, mapping, mappingOutput); return phyre2ModelMapping; } public HashMap getPhyre2FastaMapping(SequenceI inputSeq, java.io.PrintStream os) { HashMap mapping = new HashMap(); AlignmentI seq2Phyre2ModelFastaMapping = null; try { seq2Phyre2ModelFastaMapping = new FormatAdapter().readFile( getFastaMappingFile(), DataSourceType.FILE, FileFormat.Fasta); } catch (IOException e1) { e1.printStackTrace(); } SequenceI[] seqs = seq2Phyre2ModelFastaMapping.getSequencesArray(); SequenceI tSequenceRes = seqs[0]; SequenceI tStructureRes = seqs[1]; // Essential to resolve fastaAlignment to input sequence and model sequence // coordinates tSequenceRes.setStart(inputSeq.getStart()); tSequenceRes.setEnd(inputSeq.getEnd()); tStructureRes.setStart(structureFile.getSeqsAsArray()[0].getStart()); tStructureRes.setEnd(structureFile.getSeqsAsArray()[0].getEnd()); try { int sequenceResLenght = tSequenceRes.getLength(); int structureResLenght = tStructureRes.getLength(); if (sequenceResLenght == structureResLenght) { int prevStructResNum = -1; int alignmentLenght = sequenceResLenght + tSequenceRes.getStart(); for (int x = 0; x < alignmentLenght; x++) { int alignSeqResidueIndex = tSequenceRes.findIndex(x); int structResNum = tStructureRes .findPosition(alignSeqResidueIndex); int sequenceResNum = tSequenceRes .findPosition(alignSeqResidueIndex - 1); boolean sameResNum = (structResNum == prevStructResNum); // System.out.println(sequenceResNum + " : " // + (sameResNum ? -1 : prevStructResNum)); mapping.put(sequenceResNum, new int[] { sameResNum ? -1 : prevStructResNum, -1 }); prevStructResNum = structResNum; } } } catch (Exception e) { e.printStackTrace(); } try { populateAtomPositions(" ", mapping); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (StructureMappingException e) { e.printStackTrace(); } if (os != null) { MappingOutputModel mop = new MappingOutputModel(); mop.setSeqStart(tSequenceRes.getStart()); mop.setSeqEnd(tSequenceRes.getEnd()); mop.setSeqName(tSequenceRes.getName()); mop.setSeqResidue(tSequenceRes.getSequenceAsString()); mop.setStrStart(tStructureRes.getStart()); mop.setStrEnd(tStructureRes.getEnd()); mop.setStrName(tStructureRes.getName()); mop.setStrResidue(tStructureRes.getSequenceAsString()); mop.setType("pep"); try { os.print(getMappingOutput(mop).toString()); } catch (Exception e) { e.printStackTrace(); } os.println(); } return mapping; } private String getFastaMappingFile() { File phyre2ModelFile = new File(structureFile.getDataName()); String phyre2ModelResultDir = phyre2ModelFile.getParent(); String modelId = structureFile.getId().substring(0, structureFile.getId().lastIndexOf(".pdb")); return phyre2ModelResultDir + PATH_SEPARATOR + modelId + ".fasta"; } @Override public StringBuffer getMappingOutput(MappingOutputModel mp) throws StructureMappingException { String seqRes = mp.getSeqResidue(); String seqName = mp.getSeqName(); int sStart = mp.getSeqStart(); int sEnd = mp.getSeqEnd(); String strRes = mp.getStrResidue(); String strName = mp.getStrName(); int pdbStart = mp.getStrStart(); int pdbEnd = mp.getStrEnd(); String type = mp.getType(); int maxid = (seqName.length() >= strName.length()) ? seqName.length() : strName.length(); int len = 72 - maxid - 1; int nochunks = ((seqRes.length()) / len) + ((seqRes.length()) % len > 0 ? 1 : 0); // output mappings StringBuffer output = new StringBuffer(); output.append(NEWLINE); output.append("Sequence \u27f7 Structure mapping details").append( NEWLINE); output.append("Method: Phyre2 Alignment"); output.append(NEWLINE).append(NEWLINE); output.append(new Format("%" + maxid + "s").form(seqName)); output.append(" : "); output.append(String.valueOf(sStart)); output.append(" - "); output.append(String.valueOf(sEnd)); output.append(" Maps to "); output.append(NEWLINE); output.append(new Format("%" + maxid + "s").form(strName)); output.append(" : "); output.append(String.valueOf(pdbStart)); output.append(" - "); output.append(String.valueOf(pdbEnd)); output.append(NEWLINE).append(NEWLINE); int matchedSeqCount = 0; for (int j = 0; j < nochunks; j++) { // Print the first aligned sequence output.append(new Format("%" + (maxid) + "s").form(seqName)).append( " "); for (int i = 0; i < len; i++) { if ((i + (j * len)) < seqRes.length()) { output.append(seqRes.charAt(i + (j * len))); } } output.append(NEWLINE); output.append(new Format("%" + (maxid) + "s").form(" ")).append(" "); // Print out the matching chars for (int i = 0; i < len; i++) { try { if ((i + (j * len)) < seqRes.length()) { boolean sameChar = Comparison.isSameResidue( seqRes.charAt(i + (j * len)), strRes.charAt(i + (j * len)), false); if (sameChar && !jalview.util.Comparison.isGap(seqRes.charAt(i + (j * len)))) { matchedSeqCount++; output.append("|"); } else if (type.equals("pep")) { if (ResidueProperties.getPAM250(seqRes.charAt(i + (j * len)), strRes.charAt(i + (j * len))) > 0) { output.append("."); } else { output.append(" "); } } else { output.append(" "); } } } catch (IndexOutOfBoundsException e) { continue; } } // Now print the second aligned sequence output = output.append(NEWLINE); output = output.append(new Format("%" + (maxid) + "s").form(strName)) .append(" "); for (int i = 0; i < len; i++) { if ((i + (j * len)) < strRes.length()) { output.append(strRes.charAt(i + (j * len))); } } output.append(NEWLINE).append(NEWLINE); } float pid = (float) matchedSeqCount / seqRes.length() * 100; // if (pid < SiftsSettings.getFailSafePIDThreshold()) // { // throw new Exception(">>> Low PID detected for Phyre2 mapping..."); // } output.append("Length of alignment = " + seqRes.length()).append( NEWLINE); output.append(new Format("Percentage ID = %2.2f").form(pid)); return output; } public static List parsePhyre2ResultSummaryTable( String html) { List phyre2Results = new ArrayList(); try { File in = new File(html); Document doc = Jsoup.parse(in, null); // Document doc = Jsoup.connect(html).get(); Elements tableElements = doc.select("table.midshade"); for (Element table : tableElements) { System.out.println(); Elements tableRowElements = table.select(":not(thead) tr"); for (int i = 0; i < tableRowElements.size(); i++) { Element row = tableRowElements.get(i); Elements rowItems = row.select("td"); if (rowItems.size() > 11) { // for (int j = 0; j < rowItems.size(); j++) // { // System.out.println(">>> r:" + j + " = " // + rowItems.get(j).text()); // } String c = rowItems.get(6).select("input").attr("onmouseover"); String alignedRange = c.substring(c.indexOf("Residues ") + 9, c.indexOf(" of your sequence aligned ")); String coverage = c.substring(c.lastIndexOf(" (") + 2, c.lastIndexOf(" coverage). Click to view detailed")); // System.out.println("coverage" + coverage); try { Phyre2SummaryPojo psp = new Phyre2SummaryPojo(); String sn = rowItems.get(0).text(); psp.setSerialNo(Integer.valueOf(sn)); psp.setTemplateId(rowItems.get(1).text()); psp.setCoverage(coverage); psp.setAlignedRange(alignedRange); psp.setConfidence(Double.valueOf(rowItems.get(8).text())); psp.setPid(Integer.valueOf(rowItems.get(9).text())); psp.setTemplateSummary(rowItems.get(10).text()); // System.out.println("row >>>> " + psp.toString()); // System.out.println(); phyre2Results.add(psp); } catch (NumberFormatException e) { e.printStackTrace(); } catch (IndexOutOfBoundsException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } } } return phyre2Results; } catch (Exception e) { e.printStackTrace(); return null; } } public static DefaultTableModel getTableModel( List phyreResults) { if (phyreResults == null) { return null; } DefaultTableModel tableModel = new DefaultTableModel() { @Override public boolean isCellEditable(int row, int column) { return false; } @Override public Class getColumnClass(int columnIndex) { switch (columnIndex) { case 0: return Integer.class; case 1: return String.class; case 2: return String.class; case 3: return String.class; case 4: return Double.class; case 5: return Integer.class; case 6: return String.class; default: return String.class; } } }; tableModel.addColumn("#"); tableModel.addColumn("Template"); tableModel.addColumn("Aligned Range"); tableModel.addColumn("Coverage"); tableModel.addColumn("Confidence"); tableModel.addColumn("%.i.d"); tableModel.addColumn("Template Information"); for (Phyre2SummaryPojo res : phyreResults) { tableModel.addRow(new Object[] { res.getSerialNo(), res.getTemplateId(), res.getAlignedRange(), res.getCoverage(), res.getConfidence(), res.getPid(), res.getTemplateSummary() }); } return tableModel; } public static void configurePhyreResultTable(JTable phyreResultTable) { DecimalFormatTableCellRenderer idCellRender = new DecimalFormatTableCellRenderer( true, 0); DecimalFormatTableCellRenderer pidCellRender = new DecimalFormatTableCellRenderer( true, 1); DecimalFormatTableCellRenderer confidenceCellRender = new DecimalFormatTableCellRenderer( true, 1); phyreResultTable.getColumn("#").setMinWidth(20); phyreResultTable.getColumn("#").setPreferredWidth(30); phyreResultTable.getColumn("#").setMaxWidth(40); phyreResultTable.getColumn("#").setCellRenderer(idCellRender); phyreResultTable.getColumn("Template").setMinWidth(60); phyreResultTable.getColumn("Template").setPreferredWidth(60); phyreResultTable.getColumn("Template").setMaxWidth(90); phyreResultTable.getColumn("Aligned Range").setMinWidth(80); phyreResultTable.getColumn("Aligned Range").setPreferredWidth(80); phyreResultTable.getColumn("Aligned Range").setMaxWidth(120); phyreResultTable.getColumn("Coverage").setMinWidth(60); phyreResultTable.getColumn("Coverage").setPreferredWidth(60); phyreResultTable.getColumn("Coverage").setMaxWidth(90); phyreResultTable.getColumn("Confidence").setMinWidth(60); phyreResultTable.getColumn("Confidence").setPreferredWidth(60); phyreResultTable.getColumn("Confidence").setMaxWidth(90); phyreResultTable.getColumn("Confidence").setCellRenderer( confidenceCellRender); phyreResultTable.getColumn("%.i.d").setMinWidth(45); phyreResultTable.getColumn("%.i.d").setPreferredWidth(450); phyreResultTable.getColumn("%.i.d").setMaxWidth(65); phyreResultTable.getColumn("%.i.d").setCellRenderer(pidCellRender); phyreResultTable.getColumn("Template Information").setMinWidth(400); phyreResultTable.getColumn("Template Information").setPreferredWidth( 600); phyreResultTable.getColumn("Template Information").setMaxWidth(1500); } }