From db005f38bdad89aef8e22750682edf2eecccc0e0 Mon Sep 17 00:00:00 2001 From: Jim Procter Date: Wed, 8 Sep 2021 13:33:20 +0100 Subject: [PATCH] JAL-3829 allow client-side selection of structures for a sequence by passing in discovered structures --- src/jalview/gui/StructureChooser.java | 2 +- .../PDBStructureChooserQuerySource.java | 2 +- .../StructureChooserQuerySource.java | 3 +- .../ThreeDBStructureChooserQuerySource.java | 111 ++++++++++++++++++-- .../StructureChooserQuerySourceTest.java | 6 ++ 5 files changed, 113 insertions(+), 11 deletions(-) diff --git a/src/jalview/gui/StructureChooser.java b/src/jalview/gui/StructureChooser.java index a83adcb..55d0ba1 100644 --- a/src/jalview/gui/StructureChooser.java +++ b/src/jalview/gui/StructureChooser.java @@ -352,7 +352,7 @@ public class StructureChooser extends GStructureChooser FTSRestResponse resultList; try { - resultList = data.selectFirstRankedQuery(seq, wantedFields, + resultList = data.selectFirstRankedQuery(seq, discoveredStructuresSet,wantedFields, fieldToFilterBy, !chk_invertFilter.isSelected()); } catch (Exception e) diff --git a/src/jalview/gui/structurechooser/PDBStructureChooserQuerySource.java b/src/jalview/gui/structurechooser/PDBStructureChooserQuerySource.java index 75e7fc0..1c43bea 100644 --- a/src/jalview/gui/structurechooser/PDBStructureChooserQuerySource.java +++ b/src/jalview/gui/structurechooser/PDBStructureChooserQuerySource.java @@ -272,7 +272,7 @@ public class PDBStructureChooserQuerySource * @return * @throws Exception */ - public FTSRestResponse selectFirstRankedQuery(SequenceI seq, + public FTSRestResponse selectFirstRankedQuery(SequenceI seq, Collection collectedResults, Collection wantedFields, String fieldToFilterBy, boolean b) throws Exception { diff --git a/src/jalview/gui/structurechooser/StructureChooserQuerySource.java b/src/jalview/gui/structurechooser/StructureChooserQuerySource.java index 96b67e4..6a1c64f 100644 --- a/src/jalview/gui/structurechooser/StructureChooserQuerySource.java +++ b/src/jalview/gui/structurechooser/StructureChooserQuerySource.java @@ -167,6 +167,7 @@ public abstract class StructureChooserQuerySource * * @param seq * - seq to generate a query for + * @param discoveredStructuresSet - existing set of entries - allows client side selection * @param wantedFields * - fields to retrieve * @param selectedFilterOpt @@ -177,7 +178,7 @@ public abstract class StructureChooserQuerySource * @throws Exception */ public abstract FTSRestResponse selectFirstRankedQuery(SequenceI seq, - Collection wantedFields, String fieldToFilterBy, + Collection discoveredStructuresSet, Collection wantedFields, String fieldToFilterBy, boolean b) throws Exception; /** diff --git a/src/jalview/gui/structurechooser/ThreeDBStructureChooserQuerySource.java b/src/jalview/gui/structurechooser/ThreeDBStructureChooserQuerySource.java index b3242de..1c04d3a 100644 --- a/src/jalview/gui/structurechooser/ThreeDBStructureChooserQuerySource.java +++ b/src/jalview/gui/structurechooser/ThreeDBStructureChooserQuerySource.java @@ -1,7 +1,10 @@ package jalview.gui.structurechooser; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; @@ -198,6 +201,16 @@ public class ThreeDBStructureChooserQuerySource } /** + * 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" }); + + /** * FTSRestClient specific query builder to pick top ranked entry from a * fetchStructuresMetaData query * @@ -213,22 +226,104 @@ public class ThreeDBStructureChooserQuerySource * @throws Exception */ public FTSRestResponse selectFirstRankedQuery(SequenceI seq, + Collection collectedResults, Collection wantedFields, String fieldToFilterBy, boolean b) throws Exception { - FTSRestResponse resultList; - FTSRestRequest pdbRequest = getTDBeaconsRequest(seq, wantedFields); - if (pdbRequest == null) + List filteredResponse = new ArrayList(); + final int idx_ups = lastTdbRequest.getFieldIndex("Uniprot Start"); + final int idx_upe = lastTdbRequest.getFieldIndex("Uniprot End"); + final int idx_mcat = lastTdbRequest.getFieldIndex("Model Category"); + final int idx_mqual = lastTdbRequest.getFieldIndex("Qmean"); + final int idx_resol = lastTdbRequest.getFieldIndex("Resolution"); + + // ignore anything outside the sequence region + for (FTSData row : collectedResults) { - return null; + 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); + } } - pdbRequest.setResponseSize(1); - resultList = tdbRestClient.executeRequest(pdbRequest); + // sort according to decreasing length, + // increasing start + Collections.sort(filteredResponse, new Comparator() + { + + 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; + } - // TODO: client side filtering - sort results and pick top one (or N) + @Override + public int compare(FTSData o1, FTSData o2) + { + int o1_s = (Integer) o1.getSummaryData()[idx_ups]; + int o1_e = (Integer) o1.getSummaryData()[idx_upe]; + int o1_cat = scoreCategory((String) o1.getSummaryData()[idx_mcat]); + int o2_s = (Integer) o2.getSummaryData()[idx_ups]; + int o2_e = (Integer) o2.getSummaryData()[idx_upe]; + int o2_cat = scoreCategory((String) o2.getSummaryData()[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) o1.getSummaryData()[idx_resol]; + double o2_res = (Double) o2.getSummaryData()[idx_resol]; + return (o2_res < o1_res) ? 1 : (o2_res == o1_res) ? 0 : -1; + } + else + { + // models, so rank on qmean + float o1_mq = (Float) o1.getSummaryData()[idx_mqual]; + float o2_mq = (Float) o2.getSummaryData()[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; + } + } - lastTdbRequest = pdbRequest; + @Override + public boolean equals(Object obj) + { + return super.equals(obj); + } + }); + FTSRestResponse resultList = new FTSRestResponse(); + resultList.setNumberOfItemsFound(filteredResponse.size()); + resultList.setSearchSummary(filteredResponse); return resultList; } diff --git a/test/jalview/gui/structurechooser/StructureChooserQuerySourceTest.java b/test/jalview/gui/structurechooser/StructureChooserQuerySourceTest.java index f492ce6..acedfed 100644 --- a/test/jalview/gui/structurechooser/StructureChooserQuerySourceTest.java +++ b/test/jalview/gui/structurechooser/StructureChooserQuerySourceTest.java @@ -24,6 +24,7 @@ package jalview.gui.structurechooser; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; +import java.util.Collection; import java.util.Vector; import org.junit.Assert; @@ -38,6 +39,7 @@ import jalview.datamodel.DBRefSource; import jalview.datamodel.PDBEntry; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceI; +import jalview.fts.api.FTSData; import jalview.fts.core.FTSRestRequest; import jalview.fts.core.FTSRestResponse; import jalview.fts.service.pdb.PDBFTSRestClient; @@ -260,6 +262,9 @@ public class StructureChooserQuerySourceTest try { upResponse = tdbquery.fetchStructuresMetaData(upSeq, tdbquery.getDocFieldPrefs().getStructureSummaryFields(), null, false); + // test ranking without additional PDBe data + FTSRestResponse firstRanked = tdbquery.selectFirstRankedQuery(upSeq, upResponse.getSearchSummary(), tdbquery.getDocFieldPrefs().getStructureSummaryFields(), "", false); + assertTrue(firstRanked.getNumberOfItemsFound()==upResponse.getNumberOfItemsFound()); // NB Could have race condition here String pdb_Query = tdbquery.buildPDBFTSQueryFor(upResponse); assertTrue(pdb_Query.trim().length()>0); @@ -268,6 +273,7 @@ public class StructureChooserQuerySourceTest FTSRestResponse joinedResp = tdbquery.joinResponses(upResponse, pdbResponse); assertEquals(upResponse.getNumberOfItemsFound(),joinedResp.getNumberOfItemsFound()); + } catch (Exception x) { x.printStackTrace(); -- 1.7.10.2