@@ -42,15 +42,56 @@ def configure(self) -> None:
4242 t = st .tabs (["**Identification**" , "**Rescoring**" , "**Filtering**" , "**Quantification**" , "**Group Selection**" ])
4343
4444 with t [0 ]:
45- st .info ("""
45+ # Checkbox for decoy generation
46+ # reactive=True ensures the parent configure() fragment re-runs when checkbox changes,
47+ # so conditional UI (DecoyDatabase settings) updates immediately
48+ self .ui .input_widget (
49+ key = "generate-decoys" ,
50+ default = True ,
51+ name = "Generate Decoy Database" ,
52+ widget_type = "checkbox" ,
53+ help = "Generate reversed decoy sequences for FDR calculation. Disable if your FASTA already contains decoys." ,
54+ reactive = True ,
55+ )
56+
57+ # Reload params to get current checkbox value after it was saved
58+ self .params = self .parameter_manager .get_parameters_from_json ()
59+
60+ # Show DecoyDatabase settings if generating decoys
61+ if self .params .get ("generate-decoys" , True ):
62+ st .info ("""
63+ **Decoy Database Settings:**
64+ * **decoy_string**: Prefix/suffix for decoy protein accessions
65+ * **method**: Method for generating decoys (reverse, shuffle)
66+ """ )
67+ self .ui .input_TOPP (
68+ "DecoyDatabase" ,
69+ custom_defaults = {
70+ "decoy_string" : "rev_" ,
71+ "decoy_string_position" : "prefix" ,
72+ "method" : "reverse" ,
73+ },
74+ include_parameters = ["decoy_string" , "decoy_string_position" , "method" ],
75+ )
76+
77+ comet_info = """
4678 **Identification (Comet):**
4779 * **enzyme**: The enzyme used for peptide digestion.
4880 * **missed_cleavages**: Number of possible cleavage sites missed by the enzyme. It has no effect if enzyme is unspecific cleavage.
4981 * **fixed_modifications**: Fixed modifications, specified using Unimod (www.unimod.org) terms, e.g. 'Carbamidomethyl (C)' or 'Oxidation (M)'
5082 * **variable_modifications**: Variable modifications, specified using Unimod (www.unimod.org) terms, e.g. 'Carbamidomethyl (C)' or 'Oxidation (M)'
51- * **PeptideIndexing:decoy_string**: String that was appended (or prefixed - see 'decoy_string_position' flag below) to the accessions
83+ """
84+ if not self .params .get ("generate-decoys" , True ):
85+ comet_info += """* **PeptideIndexing:decoy_string**: String that was appended (or prefixed - see 'decoy_string_position' flag below) to the accessions
5286 in the protein database to indicate decoy proteins.
53- """ )
87+ """
88+ st .info (comet_info )
89+
90+ comet_include = ["enzyme" , "missed_cleavages" , "fixed_modifications" , "variable_modifications" ]
91+ if not self .params .get ("generate-decoys" , True ):
92+ # Only show decoy_string when not generating decoys
93+ comet_include .append ("PeptideIndexing:decoy_string" )
94+
5495 self .ui .input_TOPP (
5596 "CometAdapter" ,
5697 custom_defaults = {
@@ -72,17 +113,19 @@ def configure(self) -> None:
72113 "PeptideIndexing:unmatched_action" : "warn" ,
73114 "PeptideIndexing:decoy_string" : "rev_"
74115 },
75- include_parameters = [ "enzyme" , "missed_cleavages" , "fixed_modifications" , "variable_modifications" , "PeptideIndexing:decoy_string" ] ,
116+ include_parameters = comet_include ,
76117 )
77118
78119 with t [1 ]:
79120 st .info ("""
80121 **Rescoring (Percolator):**
81- * **decoy_pattern**: Define the text pattern to identify the decoy proteins and/or PSMs, set this up if the label that identifies the decoys in the database is not the default (Only valid if option -protein_level_fdrs is active).
82122 * **post_processing_tdc**: Use target-decoy competition to assign q-values and PEPs.
83123 * **score_type**: Type of the peptide main score
84124 * **subset_max_train**: Only train an SVM on a subset of <x> PSMs, and use the resulting score vector to evaluate the other PSMs. Recommended when analyzing huge numbers (>1 million) of PSMs. When set to 0, all PSMs are used for training as normal.
85125 """ )
126+ # decoy_pattern is always derived from upstream, never shown
127+ percolator_include = ["post_processing_tdc" , "score_type" , "subset_max_train" ]
128+
86129 self .ui .input_TOPP (
87130 "PercolatorAdapter" ,
88131 custom_defaults = {
@@ -92,7 +135,7 @@ def configure(self) -> None:
92135 "score_type" : "pep" ,
93136 "post_processing_tdc" : "true" ,
94137 },
95- include_parameters = [ "decoy_pattern" , "post_processing_tdc" , "score_type" , "subset_max_train" ] ,
138+ include_parameters = percolator_include ,
96139 )
97140
98141 with t [2 ]:
@@ -224,19 +267,25 @@ def execution(self) -> None:
224267 return
225268
226269 fasta_path = Path (fasta_file )
227- # decoy_fasta = fasta_path.with_suffix(".decoy.fasta")
228-
229- # if not decoy_fasta.exists():
230- # st.info("Generating decoy FASTA database...")
231- # self.executor.run_topp(
232- # "DecoyDatabase",
233- # {
234- # "in": [str(fasta_path)],
235- # "out": [str(decoy_fasta)],
236- # },
237- # )
238-
239- # st.success(f"Using decoy FASTA: {decoy_fasta.name}")
270+
271+ if self .params .get ("generate-decoys" , True ):
272+ decoy_fasta = fasta_path .with_suffix (".decoy.fasta" )
273+ # Get decoy_string from DecoyDatabase params
274+ decoy_string = self .params .get ("DecoyDatabase" , {}).get ("decoy_string" , "rev_" )
275+
276+ if not decoy_fasta .exists ():
277+ st .info ("Generating decoy FASTA database..." )
278+ self .executor .run_topp (
279+ "DecoyDatabase" ,
280+ {"in" : [str (fasta_path )], "out" : [str (decoy_fasta )]},
281+ )
282+ st .success (f"Using decoy FASTA: { decoy_fasta .name } " )
283+ database_fasta = decoy_fasta
284+ else :
285+ # Get decoy_string from CometAdapter params
286+ decoy_string = self .params .get ("CometAdapter" , {}).get ("PeptideIndexing:decoy_string" , "rev_" )
287+ st .info (f"Using original FASTA: { fasta_path .name } " )
288+ database_fasta = fasta_path
240289
241290 # ================================
242291 # 1️⃣ Directory setup
@@ -274,16 +323,18 @@ def execution(self) -> None:
274323
275324 # --- CometAdapter ---
276325 with st .spinner (f"CometAdapter ({ stem } )" ):
326+ comet_extra_params = {"database" : str (database_fasta )}
327+ if self .params .get ("generate-decoys" , True ):
328+ # Propagate decoy_string from DecoyDatabase
329+ comet_extra_params ["PeptideIndexing:decoy_string" ] = decoy_string
330+
277331 self .executor .run_topp (
278332 "CometAdapter" ,
279333 {
280334 "in" : in_mzML ,
281335 "out" : comet_results ,
282336 },
283- {
284- # "database": str(decoy_fasta),
285- "database" : str (fasta_path ),
286- },
337+ comet_extra_params ,
287338 )
288339
289340 # if not Path(comet_results).exists():
@@ -298,6 +349,7 @@ def execution(self) -> None:
298349 "in" : comet_results ,
299350 "out" : percolator_results ,
300351 },
352+ {"decoy_pattern" : decoy_string }, # Always propagated from upstream
301353 )
302354
303355 # if not Path(percolator_results[i]).exists():
@@ -355,8 +407,7 @@ def execution(self) -> None:
355407 "out_msstats" : [quant_msstats ],
356408 },
357409 {
358- # "fasta": str(decoy_fasta),
359- "fasta" : str (fasta_path ),
410+ "fasta" : str (database_fasta ),
360411 "psmFDR" : 0.5 ,
361412 "proteinFDR" : 0.5 ,
362413 "threads" : 12 ,
0 commit comments