1 package jalview.gui.structurechooser;
3 import java.util.Locale;
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.BitSet;
8 import java.util.Collection;
9 import java.util.Collections;
10 import java.util.Comparator;
11 import java.util.List;
13 import jalview.datamodel.SequenceI;
14 import jalview.fts.api.FTSData;
15 import jalview.fts.core.FTSRestRequest;
17 public class TDBResultAnalyser
21 * model categories - update as needed. warnings output if unknown types
24 * Order denotes 'trust'
26 private static List<String> EXP_CATEGORIES = Arrays
28 { "EXPERIMENTALLY DETERMINED", "DEEP-LEARNING", "TEMPLATE-BASED",
29 "AB-INITIO", "CONFORMATIONAL ENSEMBLE" });
31 private SequenceI seq;
33 private Collection<FTSData> collectedResults;
35 private FTSRestRequest lastTdbRequest;
43 private int idx_mqual;
45 private int idx_resol;
50 private String filter = null;
53 * limit to particular source
55 private String sourceFilter = null;
57 private int idx_mprov;
59 public TDBResultAnalyser(SequenceI seq,
60 Collection<FTSData> collectedResults,
61 FTSRestRequest lastTdbRequest, String fieldToFilterBy,
65 this.collectedResults = collectedResults;
66 this.lastTdbRequest = lastTdbRequest;
67 this.filter = fieldToFilterBy;
68 this.sourceFilter = string;
69 idx_ups = lastTdbRequest.getFieldIndex("Uniprot Start");
70 idx_upe = lastTdbRequest.getFieldIndex("Uniprot End");
71 idx_mcat = lastTdbRequest.getFieldIndex("Model Category");
72 idx_mprov = lastTdbRequest.getFieldIndex("Provider");
73 idx_mqual = lastTdbRequest.getFieldIndex("Confidence");
74 idx_resol = lastTdbRequest.getFieldIndex("Resolution");
78 * maintain and resolve categories to 'trust order' TODO: change the trust
79 * scheme to something comprehensible.
82 * @return 0 for null cat, less than zero for others
84 public final int scoreCategory(String cat)
90 String upper_cat = cat.toUpperCase(Locale.ROOT);
91 int idx = EXP_CATEGORIES.indexOf(upper_cat);
94 System.out.println("Unknown category: '" + cat + "'");
95 EXP_CATEGORIES.add(upper_cat);
96 idx = EXP_CATEGORIES.size() - 1;
98 return -EXP_CATEGORIES.size() - idx;
102 * sorts records discovered by 3D beacons and excludes any that don't
103 * intersect with the sequence's start/end rage
107 public List<FTSData> getFilteredResponse()
109 List<FTSData> filteredResponse = new ArrayList<FTSData>();
111 // ignore anything outside the sequence region
112 for (FTSData row : collectedResults)
114 int up_s = (Integer) row.getSummaryData()[idx_ups];
115 int up_e = (Integer) row.getSummaryData()[idx_upe];
116 String provider = (String) row.getSummaryData()[idx_mprov];
117 String mcat = (String) row.getSummaryData()[idx_mcat];
118 // this makes sure all new categories are in the score array.
119 int scorecat = scoreCategory(mcat);
120 if (sourceFilter == null || sourceFilter.equals(provider))
122 if (seq == row.getSummaryData()[0] && up_e > seq.getStart()
123 && up_s < seq.getEnd())
125 filteredResponse.add(row);
129 // sort according to decreasing length,
131 Collections.sort(filteredResponse, new Comparator<FTSData>()
134 public int compare(FTSData o1, FTSData o2)
136 Object[] o1data = o1.getSummaryData();
137 Object[] o2data = o2.getSummaryData();
138 int o1_s = (Integer) o1data[idx_ups];
139 int o1_e = (Integer) o1data[idx_upe];
140 int o1_cat = scoreCategory((String) o1data[idx_mcat]);
141 String o1_prov = ((String) o1data[idx_mprov])
142 .toUpperCase(Locale.ROOT);
143 int o2_s = (Integer) o2data[idx_ups];
144 int o2_e = (Integer) o2data[idx_upe];
145 int o2_cat = scoreCategory((String) o2data[idx_mcat]);
146 String o2_prov = ((String) o2data[idx_mprov])
147 .toUpperCase(Locale.ROOT);
149 if (o1_cat == o2_cat)
153 int o1_xtent = o1_e - o1_s;
154 int o2_xtent = o2_e - o2_s;
155 if (o1_xtent == o2_xtent)
157 if (o1_cat == scoreCategory(EXP_CATEGORIES.get(0)))
159 if (o1_prov.equals(o2_prov))
161 if ("PDBE".equals(o1_prov))
163 if (eitherNull(idx_resol, o1data, o2data))
165 return nonNullFirst(idx_resol, o1data, o2data);
167 // experimental structures, so rank on quality
168 double o1_res = (Double) o1data[idx_resol];
169 double o2_res = (Double) o2data[idx_resol];
170 return (o2_res < o1_res) ? 1
171 : (o2_res == o1_res) ? 0 : -1;
175 return 0; // no change in order
180 // PDBe always ranked above all other experimentally
181 // determined categories
182 return "PDBE".equals(o1_prov) ? -1
183 : "PDBE".equals(o2_prov) ? 1 : 0;
188 if (eitherNull(idx_mqual, o1data, o2data))
190 return nonNullFirst(idx_mqual, o1data, o2data);
192 // models, so rank on qmean - b
193 double o1_mq = (Double) o1data[idx_mqual];
194 double o2_mq = (Double) o2data[idx_mqual];
195 return (o2_mq < o1_mq) ? 1 : (o2_mq == o1_mq) ? 0 : -1;
200 return o1_xtent - o2_xtent;
210 return o2_cat - o1_cat;
214 private int nonNullFirst(int idx_resol, Object[] o1data,
217 return o1data[idx_resol] == o2data[idx_resol] ? 0
218 : o1data[idx_resol] != null ? -1 : 1;
221 private boolean eitherNull(int idx_resol, Object[] o1data,
224 return (o1data[idx_resol] == null || o2data[idx_resol] == null);
228 public boolean equals(Object obj)
230 return super.equals(obj);
233 return filteredResponse;
237 * return list of structures to be marked as selected for this sequence
238 * according to given criteria
240 * @param filteredStructures
241 * - sorted, filtered structures from getFilteredResponse
244 public List<FTSData> selectStructures(List<FTSData> filteredStructures)
246 List<FTSData> selected = new ArrayList<FTSData>();
247 BitSet cover = new BitSet();
248 cover.set(seq.getStart(), seq.getEnd());
249 // walk down the list of structures, selecting some to add to selected
250 // TODO: could do simple DP - double loop to select largest number of
251 // structures covering largest number of sites
252 for (FTSData structure : filteredStructures)
254 Object[] odata = structure.getSummaryData();
255 int o1_s = (Integer) odata[idx_ups];
256 int o1_e = (Integer) odata[idx_upe];
257 int o1_cat = scoreCategory((String) odata[idx_mcat]);
258 BitSet scover = new BitSet();
259 // measure intersection
260 scover.set(o1_s, o1_e);
262 if (scover.cardinality() > 4)
264 selected.add(structure);
265 // clear the range covered by this structure
266 cover.andNot(scover);
269 if (selected.size() == 0)
273 // final step is to sort on length - this might help the superposition
275 Collections.sort(selected, new Comparator<FTSData>()
278 public int compare(FTSData o1, FTSData o2)
280 Object[] o1data = o1.getSummaryData();
281 Object[] o2data = o2.getSummaryData();
282 int o1_xt = ((Integer) o1data[idx_upe])
283 - ((Integer) o1data[idx_ups]);
284 int o1_cat = scoreCategory((String) o1data[idx_mcat]);
285 int o2_xt = ((Integer) o2data[idx_upe] - (Integer) o2data[idx_ups]);
286 int o2_cat = scoreCategory((String) o2data[idx_mcat]);
287 return o2_xt - o1_xt;
291 ThreeDBStructureChooserQuerySource.FILTER_FIRST_BEST_COVERAGE))
293 return selected.subList(0, 1);