changeset 17:fb9dc2ee2fd4 draft

planemo upload for repository https://github.com/galaxyproject/tools-iuc/tree/master/tools/edger commit 76bd257ee51e9d7b912f570fb9ced1084ef44212
author iuc
date Wed, 15 Oct 2025 10:24:16 +0000
parents ae2aad0a6d50
children fd9902d118e5
files edger.R edger.xml test-data/factorinfo-extended.txt test-data/matrix-extended.txt
diffstat 4 files changed, 269 insertions(+), 106 deletions(-) [+]
line wrap: on
line diff
--- a/edger.R	Wed Sep 04 15:50:01 2024 +0000
+++ b/edger.R	Wed Oct 15 10:24:16 2025 +0000
@@ -330,6 +330,8 @@
 }
 contrast_data <- sanitise_equation(contrast_data)
 contrast_data <- gsub(" ", ".", contrast_data, fixed = TRUE)
+# Convert colons to dots to match design matrix column name processing
+contrast_data <- gsub(":", ".", contrast_data, fixed = TRUE)
 
 bcv_pdf <- make_out("bcvplot.pdf")
 bcv_png <- make_out("bcvplot.png")
@@ -431,6 +433,9 @@
     colnames(design) <- gsub(factor_list[i], "", colnames(design), fixed = TRUE)
 }
 
+# Ensure column names are syntactically valid
+colnames(design) <- make.names(colnames(design))
+
 # Calculating normalising factor, estimating dispersion
 data <- calcNormFactors(data, method = opt$normOpt)
 
--- a/edger.xml	Wed Sep 04 15:50:01 2024 +0000
+++ b/edger.xml	Wed Oct 15 10:24:16 2025 +0000
@@ -4,7 +4,7 @@
     </description>
     <macros>
         <token name="@TOOL_VERSION@">3.36.0</token>
-        <token name="@VERSION_SUFFIX@">5</token>
+        <token name="@VERSION_SUFFIX@">6</token>
     </macros>
     <edam_topics>
         <edam_topic>topic_3308</edam_topic>
@@ -212,7 +212,7 @@
                 <repeat name="rep_contrast" title="Contrast" min="1" default="1">
                     <param name="contrast" type="text" label="Contrast of Interest" help="Names of two groups to compare separated by a hyphen e.g. Mut-WT. If the order is Mut-WT the fold changes in the results will be up/down in Mut relative to WT. If you have more than one contrast enter each separately using the Insert Contrast button below. For differences between contrasts use e.g. (MT.t1-MT.t0)-(WT.t1-WT.t0). For more info, see Chapter 8 in the limma User's guide: https://www.bioconductor.org/packages/release/bioc/vignettes/limma/inst/doc/usersguide.pdf or https://bioconductor.org/packages/release/bioc/vignettes/edgeR/inst/doc/edgeRUsersGuide.pdf page 36 for nested comparisons.">
                         <validator type="empty_field"/>
-                        <validator type="regex" message="Please only use letters, numbers, parentheses or underscores">^[\w\-()]+$</validator>
+                        <validator type="regex" message="Please only use letters, numbers, parentheses, colon or underscores">^[\w\-():]+$</validator>
                     </param>
                 </repeat>
             </when>
@@ -295,20 +295,21 @@
     <tests>
         <!-- Ensure report is output -->
         <test expect_num_outputs="2">
-            <param name="format" value="matrix"/>
-            <param name="counts" value="matrix.txt"/>
-            <repeat name="rep_factor">
+            <param name="input|format" value="matrix"/>
+            <param name="input|counts" value="matrix.txt"/>
+            <param name="input|fact|ffile" value="no"/>
+            <repeat name="input|fact|rep_factor">
                 <param name="factorName" value="Genotype"/>
                 <param name="groupNames" value="Mut,Mut,Mut,WT,WT,WT"/>
             </repeat>
-            <param name="contrastOpt" value="manual"/>
-            <repeat name="rep_contrast">
+            <param name="contrasts|contrastOpt" value="manual"/>
+            <repeat name="contrasts|rep_contrast">
                 <param name="contrast" value="Mut-WT"/>
             </repeat>
-            <repeat name="rep_contrast">
+            <repeat name="contrasts|rep_contrast">
                 <param name="contrast" value="WT-Mut"/>
             </repeat>
-            <param name="normalisationOption" value="TMM"/>
+            <param name="adv|normalisationOption" value="TMM"/>
             <output_collection name="outTables" count="2">
                 <element name="edgeR_Mut-WT" ftype="tabular">
                     <assert_contents>
@@ -334,17 +335,18 @@
         </test>
         <!-- Complex contrasts constructions -->
         <test expect_num_outputs="2">
-            <param name="format" value="matrix"/>
-            <param name="counts" value="matrix-complex.txt"/>
-            <repeat name="rep_factor">
+            <param name="input|format" value="matrix"/>
+            <param name="input|counts" value="matrix-complex.txt"/>
+            <param name="input|fact|ffile" value="no"/>
+            <repeat name="input|fact|rep_factor">
                 <param name="factorName" value="Genotype"/>
                 <param name="groupNames" value="MutA,MutA,MutA,MutB,MutB,MutB,WTA,WTA,WTA,WTB,WTB,WTB"/>
             </repeat>
-            <param name="contrastOpt" value="manual"/>
-            <repeat name="rep_contrast">
+            <param name="contrasts|contrastOpt" value="manual"/>
+            <repeat name="contrasts|rep_contrast">
                 <param name="contrast" value="(MutA-MutB)-(WTA-WTB)"/>
             </repeat>
-            <param name="normalisationOption" value="TMM"/>
+            <param name="adv|normalisationOption" value="TMM"/>
             <output_collection name="outTables" count="1">
                 <element name="edgeR_(MutA-MutB)-(WTA-WTB)" ftype="tabular">
                     <assert_contents>
@@ -364,19 +366,20 @@
         </test>
         <!-- Ensure annotation file input works -->
         <test expect_num_outputs="2">
-            <param name="format" value="matrix"/>
-            <param name="annoOpt" value="yes"/>
-            <param name="geneanno" value="anno.txt"/>
-            <param name="counts" value="matrix.txt"/>
-            <repeat name="rep_factor">
+            <param name="input|format" value="matrix"/>
+            <param name="anno|annoOpt" value="yes"/>
+            <param name="anno|geneanno" value="anno.txt"/>
+            <param name="input|counts" value="matrix.txt"/>
+            <param name="input|fact|ffile" value="no"/>
+            <repeat name="input|fact|rep_factor">
                 <param name="factorName" value="Genotype"/>
                 <param name="groupNames" value="Mut,Mut,Mut,WT,WT,WT"/>
             </repeat>
-            <param name="contrastOpt" value="manual"/>
-            <repeat name="rep_contrast">
+            <param name="contrasts|contrastOpt" value="manual"/>
+            <repeat name="contrasts|rep_contrast">
                 <param name="contrast" value="Mut-WT"/>
             </repeat>
-            <param name="normalisationOption" value="TMM"/>
+            <param name="adv|normalisationOption" value="TMM"/>
             <output_collection name="outTables" count="1">
                 <element name="edgeR_Mut-WT" ftype="tabular">
                     <assert_contents>
@@ -388,19 +391,20 @@
         </test>
         <!-- Ensure RScript and RData file can be output -->
         <test expect_num_outputs="3">
-            <param name="format" value="matrix"/>
-            <param name="rscript" value="True"/>
-            <param name="rdaOption" value="true"/>
-            <param name="counts" value="matrix.txt"/>
-            <repeat name="rep_factor">
+            <param name="input|format" value="matrix"/>
+            <param name="out|rscript" value="True"/>
+            <param name="out|rdaOption" value="true"/>
+            <param name="input|counts" value="matrix.txt"/>
+            <param name="input|fact|ffile" value="no"/>
+            <repeat name="input|fact|rep_factor">
                 <param name="factorName" value="Genotype"/>
                 <param name="groupNames" value="Mut,Mut,Mut,WT,WT,WT"/>
             </repeat>
-            <param name="contrastOpt" value="manual"/>
-            <repeat name="rep_contrast">
+            <param name="contrasts|contrastOpt" value="manual"/>
+            <repeat name="contrasts|rep_contrast">
                 <param name="contrast" value="Mut-WT"/>
             </repeat>
-            <param name="normalisationOption" value="TMM"/>
+            <param name="adv|normalisationOption" value="TMM"/>
             <output name="outReport">
                 <assert_contents>
                     <has_text text="RData"/>
@@ -414,21 +418,22 @@
         </test>
         <!-- Ensure secondary factors work -->
         <test expect_num_outputs="2">
-            <param name="format" value="matrix"/>
-            <param name="counts" value="matrix.txt"/>
-            <repeat name="rep_factor">
+            <param name="input|format" value="matrix"/>
+            <param name="input|counts" value="matrix.txt"/>
+            <param name="input|fact|ffile" value="no"/>
+            <repeat name="input|fact|rep_factor">
                 <param name="factorName" value="Genotype"/>
                 <param name="groupNames" value="Mut,Mut,Mut,WT,WT,WT"/>
             </repeat>
-            <repeat name="rep_factor">
+            <repeat name="input|fact|rep_factor">
                 <param name="factorName" value="Batch"/>
                 <param name="groupNames" value="b1,b2,b3,b1,b2,b3"/>
             </repeat>
-            <param name="contrastOpt" value="manual"/>
-            <repeat name="rep_contrast">
+            <param name="contrasts|contrastOpt" value="manual"/>
+            <repeat name="contrasts|rep_contrast">
                 <param name="contrast" value="Mut-WT"/>
             </repeat>
-            <param name="normalisationOption" value="TMM"/>
+            <param name="adv|normalisationOption" value="TMM"/>
             <output_collection name="outTables" count="1">
                 <element name="edgeR_Mut-WT" ftype="tabular">
                     <assert_contents>
@@ -440,15 +445,15 @@
         </test>
         <!-- Ensure factors file with unordered samples works -->
         <test expect_num_outputs="2">
-            <param name="format" value="matrix"/>
-            <param name="ffile" value="yes"/>
-            <param name="finfo" value="factorinfo.txt"/>
-            <param name="counts" value="matrix.txt"/>
-            <param name="contrastOpt" value="manual"/>
-            <repeat name="rep_contrast">
+            <param name="input|format" value="matrix"/>
+            <param name="input|fact|ffile" value="yes"/>
+            <param name="input|fact|finfo" value="factorinfo.txt"/>
+            <param name="input|counts" value="matrix.txt"/>
+            <param name="contrasts|contrastOpt" value="manual"/>
+            <repeat name="contrasts|rep_contrast">
                 <param name="contrast" value="Mut-WT"/>
             </repeat>
-            <param name="normalisationOption" value="TMM"/>
+            <param name="adv|normalisationOption" value="TMM"/>
             <output_collection name="outTables" count="1">
                 <element name="edgeR_Mut-WT" ftype="tabular">
                     <assert_contents>
@@ -460,18 +465,19 @@
         </test>
         <!-- Ensure normalised counts file output works-->
         <test expect_num_outputs="2">
-            <param name="format" value="matrix"/>
-            <param name="normCounts" value="true"/>
-            <param name="counts" value="matrix.txt"/>
-            <repeat name="rep_factor">
+            <param name="input|format" value="matrix"/>
+            <param name="out|normCounts" value="true"/>
+            <param name="input|counts" value="matrix.txt"/>
+            <param name="input|fact|ffile" value="no"/>
+            <repeat name="input|fact|rep_factor">
                 <param name="factorName" value="Genotype"/>
                 <param name="groupNames" value="Mut,Mut,Mut,WT,WT,WT"/>
             </repeat>
-            <param name="contrastOpt" value="manual"/>
-            <repeat name="rep_contrast">
+            <param name="contrasts|contrastOpt" value="manual"/>
+            <repeat name="contrasts|rep_contrast">
                 <param name="contrast" value="Mut-WT"/>
             </repeat>
-            <param name="normalisationOption" value="TMM"/>
+            <param name="adv|normalisationOption" value="TMM"/>
             <output_collection name="outTables" count="2">
                 <element name="edgeR_Mut-WT" ftype="tabular">
                     <assert_contents>
@@ -489,18 +495,19 @@
         </test>
         <!-- Ensure likelihood ratio option works -->
         <test expect_num_outputs="2">
-            <param name="format" value="matrix"/>
-            <param name="counts" value="matrix.txt"/>
-            <repeat name="rep_factor">
+            <param name="input|format" value="matrix"/>
+            <param name="input|counts" value="matrix.txt"/>
+            <param name="input|fact|ffile" value="no"/>
+            <repeat name="input|fact|rep_factor">
                 <param name="factorName" value="Genotype"/>
                 <param name="groupNames" value="Mut,Mut,Mut,WT,WT,WT"/>
             </repeat>
-            <param name="contrastOpt" value="manual"/>
-            <repeat name="rep_contrast">
+            <param name="contrasts|contrastOpt" value="manual"/>
+            <repeat name="contrasts|rep_contrast">
                 <param name="contrast" value="Mut-WT"/>
             </repeat>
-            <param name="normalisationOption" value="TMM"/>
-            <param name="lrtOption" value="true"/>
+            <param name="adv|normalisationOption" value="TMM"/>
+            <param name="adv|lrtOption" value="true"/>
             <output name="outReport">
                 <assert_contents>
                     <has_text text="likelihood ratio"/>
@@ -510,8 +517,8 @@
         </test>
         <!-- Ensure multiple counts files input works -->
         <test expect_num_outputs="2">
-            <param name="format" value="files"/>
-            <repeat name="rep_factor">
+            <param name="input|format" value="files"/>
+            <repeat name="input|rep_factor">
                 <param name="factorName" value="Genotype"/>
                 <repeat name="rep_group">
                     <param name="groupName" value="WT"/>
@@ -522,7 +529,7 @@
                     <param name="countsFile" value="Mut1.counts,Mut2.counts,Mut3.counts"/>
                 </repeat>
             </repeat>
-            <repeat name="rep_factor">
+            <repeat name="input|rep_factor">
                 <param name="factorName" value="Batch"/>
                 <repeat name="rep_group">
                     <param name="groupName" value="b1"/>
@@ -537,16 +544,16 @@
                     <param name="countsFile" value="WT3.counts,Mut3.counts"/>
                 </repeat>
             </repeat>
-            <param name="annoOpt" value="yes"/>
-            <param name="geneanno" value="anno.txt"/>
-            <param name="contrastOpt" value="manual"/>
-            <repeat name="rep_contrast">
+            <param name="anno|annoOpt" value="yes"/>
+            <param name="anno|geneanno" value="anno.txt"/>
+            <param name="contrasts|contrastOpt" value="manual"/>
+            <repeat name="contrasts|rep_contrast">
                 <param name="contrast" value="Mut-WT"/>
             </repeat>
-            <repeat name="rep_contrast">
+            <repeat name="contrasts|rep_contrast">
                 <param name="contrast" value="WT-Mut"/>
             </repeat>
-            <param name="normCounts" value="true"/>
+            <param name="out|normCounts" value="true"/>
             <output_collection name="outTables" count="3">
                 <element name="edgeR_Mut-WT" ftype="tabular">
                     <assert_contents>
@@ -570,23 +577,24 @@
         </test>
         <!-- Ensure filtering on CPM in Mnimum Samples works -->
         <test expect_num_outputs="2">
-            <param name="format" value="matrix"/>
-            <param name="counts" value="matrix.txt"/>
-            <repeat name="rep_factor">
+            <param name="input|format" value="matrix"/>
+            <param name="input|counts" value="matrix.txt"/>
+            <param name="input|fact|ffile" value="no"/>
+            <repeat name="input|fact|rep_factor">
                 <param name="factorName" value="Genotype"/>
                 <param name="groupNames" value="Mut,Mut,Mut,WT,WT,WT"/>
             </repeat>
-            <param name="contrastOpt" value="manual"/>
-            <repeat name="rep_contrast">
+            <param name="contrasts|contrastOpt" value="manual"/>
+            <repeat name="contrasts|rep_contrast">
                 <param name="contrast" value="Mut-WT"/>
             </repeat>
-            <param name="normalisationOption" value="TMM"/>
-            <param name="filt_select" value="yes"/>
-            <param name="format_select" value="cpm"/>
+            <param name="adv|normalisationOption" value="TMM"/>
+            <param name="f|filt|filt_select" value="yes"/>
+            <param name="f|filt|cformat|format_select" value="cpm"/>
             <!-- real cpmReq values would be a lot lower
                  this is just for this tiny test dataset -->
-            <param name="cpmReq" value="1000"/>
-            <param name="cpmSampleReq" value="3"/>
+            <param name="f|filt|cformat|cpmReq" value="1000"/>
+            <param name="f|filt|cformat|cpmSampleReq" value="3"/>
             <output name="outReport">
                 <assert_contents>
                     <has_text text="CPM in at least"/>
@@ -606,22 +614,23 @@
         </test>
         <!-- Ensure filtering on Count in Minmum Samples works -->
         <test expect_num_outputs="2">
-            <param name="format" value="matrix"/>
-            <param name="counts" value="matrix.txt"/>
-            <repeat name="rep_factor">
+            <param name="input|format" value="matrix"/>
+            <param name="input|counts" value="matrix.txt"/>
+            <param name="input|fact|ffile" value="no"/>
+            <repeat name="input|fact|rep_factor">
                 <param name="factorName" value="Genotype"/>
                 <param name="groupNames" value="Mut,Mut,Mut,WT,WT,WT"/>
             </repeat>
-            <param name="contrastOpt" value="manual"/>
-            <repeat name="rep_contrast">
+            <param name="contrasts|contrastOpt" value="manual"/>
+            <repeat name="contrasts|rep_contrast">
                 <param name="contrast" value="Mut-WT"/>
             </repeat>
-            <param name="normalisationOption" value="TMM"/>
-            <param name="filt_select" value="yes"/>
-            <param name="format_select" value="counts"/>
-            <param name="cntReq" value="10"/>
-            <param name="count_select" value="sample"/>
-            <param name="cntSampleReq" value="3"/>
+            <param name="adv|normalisationOption" value="TMM"/>
+            <param name="f|filt|filt_select" value="yes"/>
+            <param name="f|filt|cformat|format_select" value="counts"/>
+            <param name="f|filt|cformat|cntReq" value="10"/>
+            <param name="f|filt|cformat|samples|count_select" value="sample"/>
+            <param name="f|filt|cformat|samples|cntSampleReq" value="3"/>
             <output name="outReport">
                 <assert_contents>
                     <has_text text="counts in at least"/>
@@ -641,23 +650,24 @@
         </test>
         <!-- Ensure filtering on Total Count works -->
         <test expect_num_outputs="2">
-            <param name="format" value="matrix"/>
-            <param name="counts" value="matrix.txt"/>
-            <repeat name="rep_factor">
+            <param name="input|format" value="matrix"/>
+            <param name="input|counts" value="matrix.txt"/>
+            <param name="input|fact|ffile" value="no"/>
+            <repeat name="input|fact|rep_factor">
                 <param name="factorName" value="Genotype"/>
                 <param name="groupNames" value="Mut,Mut,Mut,WT,WT,WT"/>
             </repeat>
-            <param name="contrastOpt" value="manual"/>
-            <repeat name="rep_contrast">
+            <param name="contrasts|contrastOpt" value="manual"/>
+            <repeat name="contrasts|rep_contrast">
                 <param name="contrast" value="Mut-WT"/>
             </repeat>
-            <param name="normalisationOption" value="TMM"/>
-            <param name="filt_select" value="yes"/>
-            <param name="format_select" value="counts"/>
+            <param name="adv|normalisationOption" value="TMM"/>
+            <param name="f|filt|filt_select" value="yes"/>
+            <param name="f|filt|cformat|format_select" value="counts"/>
             <!-- real cntReq values would be a lot lower
                  this is just for this tiny test dataset -->
-            <param name="cntReq" value="1000"/>
-            <param name="count_select" value="total"/>
+            <param name="f|filt|cformat|cntReq" value="1000"/>
+            <param name="f|filt|cformat|samples|count_select" value="total"/>
             <output name="outReport">
                 <assert_contents>
                     <has_text text="after summing counts for all samples"/>
@@ -677,20 +687,21 @@
         </test>
         <!-- Ensure formula and contrast file work -->
         <test expect_num_outputs="2">
-            <param name="format" value="matrix"/>
-            <param name="counts" value="matrix.txt"/>
-            <repeat name="rep_factor">
+            <param name="input|format" value="matrix"/>
+            <param name="input|counts" value="matrix.txt"/>
+            <param name="input|fact|ffile" value="no"/>
+            <repeat name="input|fact|rep_factor">
                 <param name="factorName" value="Genotype"/>
                 <param name="groupNames" value="Mut,Mut,Mut,WT,WT,WT"/>
             </repeat>
-            <repeat name="rep_factor">
+            <repeat name="input|fact|rep_factor">
                 <param name="factorName" value="Batch"/>
                 <param name="groupNames" value="b1,b2,b3,b1,b2,b3"/>
             </repeat>
-            <param name="contrastOpt" value="file"/>
-            <param name="cinfo" value="contrasts_file.txt"/>
+            <param name="contrasts|contrastOpt" value="file"/>
+            <param name="contrasts|cinfo" value="contrasts_file.txt"/>
             <param name="formula" value="~ 0 + Genotype + Batch"/>
-            <param name="normalisationOption" value="TMM"/>
+            <param name="adv|normalisationOption" value="TMM"/>
             <output_collection name="outTables" count="3">
                 <element name="edgeR_Mut-WT" ftype="tabular">
                     <assert_contents>
@@ -710,6 +721,78 @@
                 </element>
             </output_collection>
         </test>
+        <!-- Test interaction contrasts with extended dataset (tests make.names fix for interaction terms) -->
+        <test expect_num_outputs="2">
+            <param name="input|format" value="matrix"/>
+            <param name="input|counts" value="matrix-extended.txt"/>
+            <param name="input|fact|ffile" value="yes"/>
+            <param name="input|fact|finfo" value="factorinfo-extended.txt"/>
+            <param name="formula" value="~ 0 + Genotype:Batch"/>
+            <param name="contrasts|contrastOpt" value="manual"/>
+            <repeat name="contrasts|rep_contrast">
+                <param name="contrast" value="Mut:b1-WT:b1"/>
+            </repeat>
+            <repeat name="contrasts|rep_contrast">
+                <param name="contrast" value="Mut:b2-Mut:b3"/>
+            </repeat>
+            <param name="adv|normalisationOption" value="TMM"/>
+            <output_collection name="outTables" count="2">
+                <element name="edgeR_Mut.b1-WT.b1" ftype="tabular">
+                    <assert_contents>
+                        <has_text_matching expression="GeneID.*logFC.*logCPM.*F.*PValue.*FDR"/>
+                        <has_text_matching expression="11304"/>
+                    </assert_contents>
+                </element>
+                <element name="edgeR_Mut.b2-Mut.b3" ftype="tabular">
+                    <assert_contents>
+                        <has_text_matching expression="GeneID.*logFC.*logCPM.*F.*PValue.*FDR"/>
+                        <has_text_matching expression="11304"/>
+                    </assert_contents>
+                </element>
+            </output_collection>
+            <output name="outReport">
+                <assert_contents>
+                    <has_text text="edgeR Analysis Output"/>
+                    <has_text text="quasi-likelihood"/>
+                </assert_contents>
+            </output>
+        </test>
+        <!-- Test full factorial interaction model (tests make.names fix with different interaction formula) -->
+        <test expect_num_outputs="2">
+            <param name="input|format" value="matrix"/>
+            <param name="input|counts" value="matrix-extended.txt"/>
+            <param name="input|fact|ffile" value="yes"/>
+            <param name="input|fact|finfo" value="factorinfo-extended.txt"/>
+            <param name="formula" value="~ Genotype * Batch"/>
+            <param name="contrasts|contrastOpt" value="manual"/>
+            <repeat name="contrasts|rep_contrast">
+                <param name="contrast" value="WT:b2"/>
+            </repeat>
+            <repeat name="contrasts|rep_contrast">
+                <param name="contrast" value="WT:b3-WT:b2"/>
+            </repeat>
+            <param name="adv|normalisationOption" value="TMM"/>
+            <output_collection name="outTables" count="2">
+                <element name="edgeR_WT.b2" ftype="tabular">
+                    <assert_contents>
+                        <has_text_matching expression="GeneID.*logFC.*logCPM.*F.*PValue.*FDR"/>
+                        <has_text_matching expression="11304"/>
+                    </assert_contents>
+                </element>
+                <element name="edgeR_WT.b3-WT.b2" ftype="tabular">
+                    <assert_contents>
+                        <has_text_matching expression="GeneID.*logFC.*logCPM.*F.*PValue.*FDR"/>
+                        <has_text_matching expression="11304"/>
+                    </assert_contents>
+                </element>
+            </output_collection>
+            <output name="outReport">
+                <assert_contents>
+                    <has_text text="edgeR Analysis Output"/>
+                    <has_text text="quasi-likelihood"/>
+                </assert_contents>
+            </output>
+        </test>
     </tests>
     <help><![CDATA[
 .. class:: infomark
@@ -811,6 +894,57 @@
 and one contrast per line on the first column (other columns are ignored). If using this option, make sure to
 remove any contrast section from the manual part, or the tool will fail.
 
+**Working with Interactions:**
+When you have multiple factors, you may want to test for interaction effects between them. 
+For example, with factors Genotype (Mut, WT) and Batch (b1, b2, b3), you might want to test 
+whether the effect of genotype differs between batches.
+
+*Interaction Formula:* To include interaction terms, use the Formula field with one of these patterns:
+
+- ``~ Genotype * Batch`` - Full factorial model (main effects + interactions)
+- ``~ Genotype + Batch + Genotype:Batch`` - Equivalent to above
+- ``~ 0 + Genotype:Batch`` - Cell-means model (each group combination separately)
+
+The cell-means model (``~ 0 + Genotype:Batch``) is often preferred for testing specific 
+group comparisons as it creates individual parameters for each combination (e.g., Mut.b1, WT.b1, etc.).
+
+*Interaction Contrasts:* When using interactions, contrast names will contain colons that get 
+converted to dots automatically. For example:
+
+**Cell-means model contrasts** (with ``~ 0 + Genotype:Batch``):
+- Input contrast: ``Mut:b1-WT:b1`` (compare Mut vs WT within batch b1)
+- Input contrast: ``Mut:b2-Mut:b3`` (compare batch b2 vs b3 within Mut genotype)  
+- Output file names: ``edgeR_Mut.b1-WT.b1.tsv``, ``edgeR_Mut.b2-Mut.b3.tsv``
+
+**Full factorial model contrasts** (with ``~ Genotype * Batch``):
+- Input contrast: ``WT:b2`` (interaction effect: WT×b2 vs baseline)
+- Input contrast: ``WT:b3-WT:b2`` (compare interaction effects: WT×b3 vs WT×b2)
+- Output file names: ``edgeR_WT.b2.tsv``, ``edgeR_WT.b3-WT.b2.tsv``
+
+*Using Contrasts Files with Interactions:* When using a contrasts file instead of manual entry, 
+the same interaction contrast syntax applies. Create a tab-separated file with a header and 
+one contrast per line:
+
+Example contrasts file for cell-means model::
+
+    Contrast
+    Mut:b1-WT:b1
+    Mut:b2-Mut:b3
+    WT:b1-WT:b2
+
+Example contrasts file for full factorial model::
+
+    Contrast
+    WT:b2
+    WT:b3-WT:b2
+    WT
+
+The colons in contrast names will be automatically converted to dots in output file names, 
+regardless of whether contrasts are entered manually or via file.
+
+Note: Ensure you have sufficient replicates for interaction models. With n factors each having 
+k levels, you need more than n×k samples to estimate interactions properly.
+
 **Filter Low Counts:**
 Genes with very low counts across all libraries provide little evidence for differential expression.
 In the biological point of view, a gene must be expressed at some minimal level before
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/factorinfo-extended.txt	Wed Oct 15 10:24:16 2025 +0000
@@ -0,0 +1,13 @@
+Samples	Genotype	Batch
+Mut1	Mut	b1
+Mut2	Mut	b2
+Mut3	Mut	b3
+Mut4	Mut	b1
+Mut5	Mut	b2
+Mut6	Mut	b3
+WT1	WT	b1
+WT2	WT	b2
+WT3	WT	b3
+WT4	WT	b1
+WT5	WT	b2
+WT6	WT	b3
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/matrix-extended.txt	Wed Oct 15 10:24:16 2025 +0000
@@ -0,0 +1,11 @@
+GeneID	Mut1	Mut2	Mut3	Mut4	Mut5	Mut6	WT1	WT2	WT3	WT4	WT5	WT6
+11287	1463	1441	1495	1520	1480	1510	1699	1528	1601	1650	1580	1620
+11298	1345	1291	1346	1380	1320	1360	1905	1744	1834	1880	1800	1860
+11302	5	6	5	7	6	5	6	8	7	8	7	6
+11303	1574	1519	1654	1600	1550	1620	2099	1974	2100	2050	2000	2080
+11304	361	397	346	380	360	370	356	312	337	340	320	330
+11305	1762	1942	2027	1800	1900	1950	2528	2438	2493	2500	2450	2480
+11306	842	789	856	820	800	830	945	901	932	920	910	940
+11307	523	498	547	510	520	530	678	634	663	660	650	670
+11308	1234	1187	1267	1220	1200	1240	1456	1389	1423	1440	1420	1430
+11309	678	645	692	670	660	680	789	751	776	780	770	790
\ No newline at end of file