diff --git a/sirius_cli/src/main/java/de/unijena/bioinf/projectspace/Instance.java b/sirius_cli/src/main/java/de/unijena/bioinf/projectspace/Instance.java index 187168ffdd..0621bc8b0a 100644 --- a/sirius_cli/src/main/java/de/unijena/bioinf/projectspace/Instance.java +++ b/sirius_cli/src/main/java/de/unijena/bioinf/projectspace/Instance.java @@ -142,11 +142,23 @@ public final synchronized Optional loadTopFormulaResult(List getTop(List> sScoreds, Class... components) { - if (sScoreds.isEmpty()) return Optional.empty(); - else { - FormulaResult candidate = sScoreds.get(0).getCandidate(); - return loadFormulaResult(candidate.getId(), components); - } + if (sScoreds.isEmpty()) + return Optional.empty(); + + FormulaResult candidate = sScoreds.get(0).getCandidate(); + return loadFormulaResult(candidate.getId(), components); + } + + + @SafeVarargs + public final synchronized List> loadTopKFormulaResults(int k, List> rankingScoreTypes, Class... components) { + return getTopK(k, loadFormulaResults(rankingScoreTypes), components); + } + + @SafeVarargs + private List> getTopK(int k, List> sScoreds, Class... components) { + return sScoreds.stream().limit(k).peek(ss -> loadFormulaResult(ss.getCandidate().getId(), components) + .ifPresent(r -> ss.getCandidate().setAnnotationsFrom(r))).toList(); } @SafeVarargs diff --git a/sirius_gui/src/main/java/de/unijena/bioinf/ms/gui/dialogs/CompoundFilterOptionsDialog.java b/sirius_gui/src/main/java/de/unijena/bioinf/ms/gui/dialogs/CompoundFilterOptionsDialog.java index baa3c8a27c..1a2073a339 100644 --- a/sirius_gui/src/main/java/de/unijena/bioinf/ms/gui/dialogs/CompoundFilterOptionsDialog.java +++ b/sirius_gui/src/main/java/de/unijena/bioinf/ms/gui/dialogs/CompoundFilterOptionsDialog.java @@ -52,7 +52,7 @@ public class CompoundFilterOptionsDialog extends JDialog implements ActionListen final SearchTextField searchField; final JTextField searchFieldDialogCopy; - final JSpinner minMzSpinner, maxMzSpinner, minRtSpinner, maxRtSpinner, minConfidenceSpinner, maxConfidenceSpinner; + final JSpinner minMzSpinner, maxMzSpinner, minRtSpinner, maxRtSpinner, minConfidenceSpinner, maxConfidenceSpinner, candidateSpinner; public final JCheckboxListPanel adductOptions; JButton discard, apply, reset; JCheckBox invertFilter; @@ -200,9 +200,15 @@ public CompoundFilterOptionsDialog(MainFrame owner, SearchTextField searchField, { searchDBList = new JCheckboxListPanel<>(new DBSelectionList(), "Hit in structure DB"); smallParameters.add(searchDBList); + searchDBList.remove(searchDBList.buttons); searchDBList.checkBoxList.uncheckAll(); - if (filterModel.isDbFilterEnabled()) //null check - searchDBList.checkBoxList.checkAll(filterModel.getDbFilter()); + candidateSpinner = makeSpinner(1, 1, 100, 1); + smallParameters.addNamed("Candidates to check: ", candidateSpinner); + + if (filterModel.isDbFilterEnabled()) { //null check + searchDBList.checkBoxList.checkAll(filterModel.getDbFilter().getDbs()); + candidateSpinner.setValue(filterModel.getDbFilter().getNumOfCandidates()); + } } smallParameters.add(new JXTitledSeparator("Filter options")); @@ -300,7 +306,8 @@ private void applyToModel(@NotNull CompoundFilterModel filterModel) { ) ); - filterModel.setDbFilter(searchDBList.checkBoxList.getCheckedItems()); + filterModel.setDbFilter(new CompoundFilterModel.DbFilter(searchDBList.checkBoxList.getCheckedItems(), + ((SpinnerNumberModel) candidateSpinner.getModel()).getNumber().intValue())); saveTextFilter(); } @@ -371,6 +378,7 @@ private void resetSpinnerValues() { maxRtSpinner.setValue(filterModel.getMaxRt()); minConfidenceSpinner.setValue(filterModel.getMinConfidence()); maxConfidenceSpinner.setValue(filterModel.getMaxConfidence()); + candidateSpinner.setValue(1); } public double getMinMz() { diff --git a/sirius_gui/src/main/java/de/unijena/bioinf/ms/gui/utils/CompoundFilterMatcher.java b/sirius_gui/src/main/java/de/unijena/bioinf/ms/gui/utils/CompoundFilterMatcher.java index 7cf470275f..f832f24816 100644 --- a/sirius_gui/src/main/java/de/unijena/bioinf/ms/gui/utils/CompoundFilterMatcher.java +++ b/sirius_gui/src/main/java/de/unijena/bioinf/ms/gui/utils/CompoundFilterMatcher.java @@ -20,6 +20,7 @@ import ca.odell.glazedlists.matchers.Matcher; import de.unijena.bioinf.ChemistryBase.algorithm.scoring.SScored; +import de.unijena.bioinf.ChemistryBase.algorithm.scoring.Scored; import de.unijena.bioinf.ChemistryBase.chem.FormulaConstraints; import de.unijena.bioinf.ChemistryBase.chem.PrecursorIonType; import de.unijena.bioinf.ChemistryBase.chem.RetentionTime; @@ -27,6 +28,7 @@ import de.unijena.bioinf.ChemistryBase.ms.lcms.LCMSPeakInformation; import de.unijena.bioinf.GibbsSampling.ZodiacScore; import de.unijena.bioinf.chemdb.ChemDBs; +import de.unijena.bioinf.chemdb.CompoundCandidate; import de.unijena.bioinf.elgordo.LipidSpecies; import de.unijena.bioinf.fingerid.blast.FBCandidates; import de.unijena.bioinf.fingerid.blast.TopCSIScore; @@ -38,6 +40,7 @@ import de.unijena.bioinf.sirius.scores.SiriusScore; import org.jetbrains.annotations.NotNull; +import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.Set; @@ -121,18 +124,37 @@ private boolean matchesLipidFilter(InstanceBean item, CompoundFilterModel filter } private boolean matchesDBFilter(InstanceBean item, CompoundFilterModel filterModel) { - long requestFilter = filterModel.getDbFilterBits(); + final int k; + final long requestFilter; + if (filterModel.isDbFilterEnabled()) { + k = filterModel.getDbFilter().getNumOfCandidates(); + requestFilter = filterModel.getDbFilter().getDbFilterBits(); + } else { + k = 1; + requestFilter = 0; + } - FBCandidates candidates = item.loadTopFormulaResult(List.of(TopCSIScore.class), FBCandidates.class) - .flatMap(i -> i.getAnnotation(FBCandidates.class)).orElse(null); + final List> candidates; + switch (k) { + case 0 -> { + return false; + } + case 1 -> candidates = item.loadTopFormulaResult(List.of(TopCSIScore.class), FBCandidates.class) + .flatMap(i -> i.getAnnotation(FBCandidates.class).map(FBCandidates::getResults)) + .map(s -> s.stream().limit(k).toList()).orElse(null); + default -> candidates = item.loadTopKFormulaResults(k, List.of(TopCSIScore.class), FBCandidates.class) + .stream().filter(i -> i.getCandidate().hasAnnotation(FBCandidates.class)) + .flatMap(i -> i.getCandidate().getAnnotation(FBCandidates.class) + .map(FBCandidates::getResults).stream().flatMap(Collection::stream)).limit(k).toList(); + } - if (candidates == null) + if (candidates == null || candidates.isEmpty()) return false; if (requestFilter == 0) return true; - return candidates.getResults().stream().map(SScored::getCandidate).anyMatch(c -> ChemDBs.inFilter(c.getBitset(), requestFilter)); + return candidates.stream().map(SScored::getCandidate).anyMatch(c -> ChemDBs.inFilter(c.getBitset(), requestFilter)); } private boolean matchesElementFilter(InstanceBean item, CompoundFilterModel filterModel) { diff --git a/sirius_gui/src/main/java/de/unijena/bioinf/ms/gui/utils/CompoundFilterModel.java b/sirius_gui/src/main/java/de/unijena/bioinf/ms/gui/utils/CompoundFilterModel.java index f6e938208b..0884483936 100644 --- a/sirius_gui/src/main/java/de/unijena/bioinf/ms/gui/utils/CompoundFilterModel.java +++ b/sirius_gui/src/main/java/de/unijena/bioinf/ms/gui/utils/CompoundFilterModel.java @@ -58,8 +58,7 @@ public class CompoundFilterModel implements SiriusPCS { private ElementFilter elementFilter = ElementFilter.disabled(); @Nullable - private List dbFilter; - + private DbFilter dbFilter; /* min/max possible values @@ -131,24 +130,17 @@ public void setLipidFilter(LipidFilter value) { pcs.firePropertyChange("setLipidFilter", oldValue, value); } - public void setDbFilter(@Nullable List dbFilter) { + public void setDbFilter(@Nullable DbFilter dbFilter) { this.dbFilter = dbFilter; } @Nullable - public List getDbFilter() { + public DbFilter getDbFilter() { return dbFilter; } - public long getDbFilterBits() { - if (dbFilter == null || dbFilter.isEmpty()) - return 0; - return dbFilter.stream(). - mapToLong(CustomDataSources.Source::flag).reduce((a, b) -> a | b).orElse(0); - } - public boolean isDbFilterEnabled() { - return dbFilter != null && !dbFilter.isEmpty(); + return dbFilter != null && !dbFilter.dbs.isEmpty(); } public boolean isElementFilterEnabled() { @@ -343,6 +335,35 @@ public enum LipidFilter { KEEP_ALL_COMPOUNDS, ANY_LIPID_CLASS_DETECTED, NO_LIPID_CLASS_DETECTED } + public static class DbFilter { + final List dbs; + final int numOfCandidates; + + public DbFilter(List dbs) { + this(dbs, 5); + + } + public DbFilter(List dbFilter, int numOfCandidates) { + this.dbs = dbFilter; + this.numOfCandidates = numOfCandidates; + } + + public long getDbFilterBits() { + if (dbs == null || dbs.isEmpty()) + return 0; + return dbs.stream(). + mapToLong(CustomDataSources.Source::flag).reduce((a, b) -> a | b).orElse(0); + } + + public int getNumOfCandidates() { + return numOfCandidates; + } + + public List getDbs() { + return dbs; + } + } + public static class ElementFilter { @NotNull final FormulaConstraints constraints;