package jalview.gui.structurechooser; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import jalview.datamodel.SequenceI; import jalview.fts.api.FTSData; import jalview.fts.core.FTSRestRequest; public class TDBResultAnalyser { /** * model categories - update as needed. warnings output if unknown types * encountered. * * Order denotes 'trust' */ private static List EXP_CATEGORIES = Arrays .asList(new String[] { "EXPERIMENTALLY DETERMINED", "DEEP-LEARNING", "TEMPLATE-BASED" }); private SequenceI seq; private Collection collectedResults; private FTSRestRequest lastTdbRequest; private int idx_ups; private int idx_upe; private int idx_mcat; private int idx_mqual; private int idx_resol; public TDBResultAnalyser(SequenceI seq, Collection collectedResults, FTSRestRequest lastTdbRequest) { this.seq = seq; this.collectedResults = collectedResults; this.lastTdbRequest = lastTdbRequest; idx_ups = lastTdbRequest.getFieldIndex("Uniprot Start"); idx_upe = lastTdbRequest.getFieldIndex("Uniprot End"); idx_mcat = lastTdbRequest.getFieldIndex("Model Category"); idx_mqual = lastTdbRequest.getFieldIndex("Confidence"); idx_resol = lastTdbRequest.getFieldIndex("Resolution"); } private final int scoreCategory(String cat) { // TODO: make quicker int idx = EXP_CATEGORIES.indexOf(cat.toUpperCase()); if (idx == -1) { System.out.println("Unknown category: '" + cat + "'"); } return -EXP_CATEGORIES.size() - idx; } /** * sorts records discovered by 3D beacons and excludes any that don't * intersect with the sequence's start/end rage * * @return */ public List getFilteredResponse() { List filteredResponse = new ArrayList(); // ignore anything outside the sequence region for (FTSData row : collectedResults) { int up_s = (Integer) row.getSummaryData()[idx_ups]; int up_e = (Integer) row.getSummaryData()[idx_upe]; if (seq == row.getSummaryData()[0] && up_e > seq.getStart() && up_s < seq.getEnd()) { filteredResponse.add(row); } } // sort according to decreasing length, // increasing start Collections.sort(filteredResponse, new Comparator() { @Override public int compare(FTSData o1, FTSData o2) { Object[] o1data = o1.getSummaryData(); Object[] o2data = o2.getSummaryData(); int o1_s = (Integer) o1data[idx_ups]; int o1_e = (Integer) o1data[idx_upe]; int o1_cat = scoreCategory((String) o1data[idx_mcat]); int o2_s = (Integer) o2data[idx_ups]; int o2_e = (Integer) o2data[idx_upe]; int o2_cat = scoreCategory((String) o2data[idx_mcat]); if (o1_cat == o2_cat) { if (o1_s == o2_s) { int o1_xtent = o1_e - o1_s; int o2_xtent = o2_e - o2_s; if (o1_xtent == o2_xtent) { if (o1_cat == scoreCategory(EXP_CATEGORIES.get(0))) { // experimental structures, so rank on quality double o1_res = (Double) o1data[idx_resol]; double o2_res = (Double) o2data[idx_resol]; return (o2_res < o1_res) ? 1 : (o2_res == o1_res) ? 0 : -1; } else { // models, so rank on qmean float o1_mq = (Float) o1data[idx_mqual]; float o2_mq = (Float) o2data[idx_mqual]; return (o2_mq < o1_mq) ? 1 : (o2_mq == o1_mq) ? 0 : -1; } } else { return o1_xtent - o2_xtent; } } else { return o1_s - o2_s; } } else { return o2_cat - o1_cat; } } @Override public boolean equals(Object obj) { return super.equals(obj); } }); return filteredResponse; } /** * return list of structures to be marked as selected for this sequence according to given criteria * @param filteredStructures - sorted, filtered structures from getFilteredResponse * */ public List selectStructures(List filteredStructures) { List selected = new ArrayList(); BitSet cover = new BitSet(); cover.set(seq.getStart(),seq.getEnd()); // walk down the list of structures, selecting some to add to selected for (FTSData structure:filteredStructures) { Object[] odata=structure.getSummaryData(); int o1_s = (Integer) odata[idx_ups]; int o1_e = (Integer) odata[idx_upe]; int o1_cat = scoreCategory((String) odata[idx_mcat]); BitSet scover = new BitSet(); // measure intersection scover.set(o1_s,o1_e); scover.and(cover); if (scover.cardinality()>4) { selected.add(structure); // clear the range covered by this structure cover.andNot(scover); } } // final step is to sort on length - this might help the superposition process Collections.sort(selected,new Comparator() { @Override public int compare(FTSData o1, FTSData o2) { Object[] o1data = o1.getSummaryData(); Object[] o2data = o2.getSummaryData(); int o1_xt = ((Integer) o1data[idx_upe]) - ((Integer) o1data[idx_ups]); int o1_cat = scoreCategory((String) o1data[idx_mcat]); int o2_xt = ((Integer) o2data[idx_upe]-(Integer) o2data[idx_ups]); int o2_cat = scoreCategory((String) o2data[idx_mcat]); return o2_xt-o1_xt; } }); return selected; } }