From 924ca548deba12f63a04b0c0ffe496f91a765447 Mon Sep 17 00:00:00 2001 From: alexeid Date: Wed, 19 Aug 2026 13:29:22 +1200 Subject: [PATCH 1/4] Register TreeCredibleLevel and DissonanceCalculator as package apps Both were listed as BEASTInterface service providers but had no entry, so applauncher could not find them. --- version.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/version.xml b/version.xml index aa63cfb..06ca773 100644 --- a/version.xml +++ b/version.xml @@ -23,5 +23,7 @@ + + From c35b0dbe470246364c7678211ed21a708c6cc51f Mon Sep 17 00:00:00 2001 From: alexeid Date: Wed, 19 Aug 2026 13:29:22 +1200 Subject: [PATCH 2/4] Document Dissonance tool and fix Usage section headings Group all applauncher tools under one heading at the same nesting level, add a section for DissonanceCalculator, and correct the TreeCredibleLevel parameters: ccdType defaults to CCD0, numsamples to 100000, plus the required out parameter and the quiet flag. --- README.md | 50 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index ad558d2..f19194c 100644 --- a/README.md +++ b/README.md @@ -80,12 +80,12 @@ where `/path/to` the path to where BEAST is installed. For Windows, use For CCD1 based point estimates select `MAP (CCD1)` from the drop down box in the GUI, or use `CCD1` instead of `CCD0` for the command line version. -### Phylogenetic Entropy, Rogue & Skeleton Analysis +### AppLauncher Tools -The CCD package has three tools (small apps) to compute the phylogenetic entropy of a tree set, compute rogues scores for each clade, and conduct a skeleton analysis -that can each be executed with BEAST's AppLauncher. +The CCD package comes with a set of tools (small apps) that can each be executed with BEAST's AppLauncher. Note that the given trees *need to be binary* and are assumed to be rooted; they are typically given by a NEXUS `.tree` file, but a list of Newick strings also works. -For more information on the concepts see the [paper](https://www.biorxiv.org/content/10.1101/2024.09.25.615070v1) +When a tool finishes, it prints the reference(s) to cite for the method it implements; this is written to stderr, so it does not interfere with results written to stdout. +For more information on the concepts behind the entropy, rogue and skeleton tools see the [paper](https://www.biorxiv.org/content/10.1101/2024.09.25.615070v1) and for further information and example data see the [research paper repository](https://github.com/CompEvol/CCD-Research/tree/main/skeletonsAndRogues). @@ -101,6 +101,22 @@ It has three parameters: - `ccdType`: either `CCD0`, `CCD1`, or `CCD2` (default: `CCD0`) +#### Dissonance + +The tool `DissonanceCalculator` computes the phylogenetic entropy (via CCD0) of one or more tree sets and, with the `dissonance` flag, also reports a dissonance value for each of them. +The dissonance is computed by splitting a tree set into its first and second half and subtracting the mean entropy of the two halves from the entropy of the whole set. +It is thus a diagnostic *within* a single tree set and not a comparison *between* the given tree files. +``` +/path/to/applauncher DissonanceCalculator -trees /path/to/treeInputFile.trees -burnin 10 -dissonance true +``` +The app has the following parameters: +- `trees`: trees file to analyse; can be given more than once to process several tree sets in one run +- `burnin`: percentage of trees to be used as burn-in (integer, default: `10%`) +- `dissonance`: `true` to also compute the dissonance of each tree set (default: `false`) +- `summarise`: `true` to print the mean and standard deviation of the entropies across all given tree sets (default: `false`) +- `quiet`: `true` to only output the entropy (and dissonance) values and nothing else (default: `false`) + + #### Rogue Analysis A rogue analysis computes a **rogue score** for each clade, including each taxon, based on a given posterior sample of *binary* trees and some parameters and prints it to a csv file. @@ -147,17 +163,25 @@ If you further specify an output file, then the given tree set will be reduced/f - `out`: reduced tree output file; the given tree set will not be filtered if not specified - `exclude`: file name of text file containing taxa to exclude from filtering - can be comma, tab or newline delimited -### Credible Level Evaluation +#### Credible Level Evaluation -The credible level of a tree within a credible CCD or a probability-based credible set (on a CCD) can be computed with the following tool. +The **credible level** of a tree is the probability mass of the smallest credible set containing it, +that is, the smallest α for which the tree lies in an α credible set. +The tool `TreeCredibleLevel` computes it, together with the probability of the tree, from a CCD estimated from a posterior tree sample. ``` -/path/to/applauncher TreeCredibleLevel -trees /path/to/treeInputFile.trees -tree /path/to/treeInputFile.tree(s) -burnin 10 -out path/to/outputTreeFile +/path/to/applauncher TreeCredibleLevel -trees /path/to/treeInputFile.trees -tree /path/to/testTreeFile.tree -burnin 10 -out path/to/outputFile ``` The app has the following parameters: -- `trees`: trees file to construct CCD with and analyse (required) +- `trees`: trees file to construct the CCD with (required) +- `tree`: tree file containing the tree for which the probability and credible level are computed (required); only the first tree is used +- `out`: output file (required); the probability of the tree is written to the first line and its credible level to the second - `burnin`: percentage of trees to be used as burn-in (integer, default: `10%`) -- `ccdType`: either `CCD0` or `CCD1` or `CCD2` (default: `CCD1`) -- `tree`: tree for which the credible level is computed -- `method`: whether to use probability-based method (`probability`, default) or a credible CCD (`credibleCCD`) -For the probability-based method the following two parameters can be set: -- `numsamples`: the number of trees sampled from the CCD to compute the credible level thresholds (default: `10000`) +- `ccdType`: either `CCD0`, `CCD1`, or `CCD2` (default: `CCD0`) +- `method`: whether to use the probability-based method (`probability`, default) or a credible CCD (`credibleCCD`) +- `quiet`: `true` to only output the credible level and nothing else (default: `false`) + +For the probability-based method one further parameter can be set: +- `numsamples`: the number of trees sampled from the CCD to compute the credible level thresholds (default: `100000`) + +Both methods are described in the [credible sets paper](https://doi.org/10.1093/molbev/msag141): +Klawitter J, Drummond AJ (2026), *Bayesian credible sets for phylogenetic tree topologies with applications to coverage analysis and cross-model comparison*, Molecular Biology and Evolution 43(7), msag141. From 04e36838b5338b3cac7dd59cf1b2014332260f33 Mon Sep 17 00:00:00 2001 From: alexeid Date: Wed, 19 Aug 2026 13:29:22 +1200 Subject: [PATCH 3/4] Print citations when applauncher tools finish Add CCDToolUtil.printCitations and @Citation annotations to the six applauncher tools. Output goes to stderr so it does not interfere with results written to stdout, and respects the quiet/verbose flags. Also corrects DissonanceCalculator's app title, which read "Entropy Calculator". --- src/main/java/ccd/tools/CCDSampler.java | 6 ++++ src/main/java/ccd/tools/CCDToolUtil.java | 29 +++++++++++++++++++ .../java/ccd/tools/DissonanceCalculator.java | 9 ++++-- .../java/ccd/tools/EntropyCalculator.java | 8 +++++ src/main/java/ccd/tools/RogueAnalysis.java | 6 ++++ src/main/java/ccd/tools/SkeletonAnalysis.java | 6 ++++ .../java/ccd/tools/TreeCredibleLevel.java | 5 ++++ 7 files changed, 67 insertions(+), 2 deletions(-) diff --git a/src/main/java/ccd/tools/CCDSampler.java b/src/main/java/ccd/tools/CCDSampler.java index 63c2570..4fea2fc 100644 --- a/src/main/java/ccd/tools/CCDSampler.java +++ b/src/main/java/ccd/tools/CCDSampler.java @@ -1,5 +1,6 @@ package ccd.tools; +import beast.base.core.Citation; import beast.base.core.Description; import beast.base.core.Input; import beast.base.core.Log; @@ -19,6 +20,9 @@ import ccd.model.HeightSettingStrategy; import ccd.model.KRegCCD; +@Citation(value = "Berling and Klawitter et al. (2025). PLOS Computational Biology.\n" + + "Accurate Bayesian phylogenetic point estimation using a tree distribution parameterized by clade probabilities.", + DOI = "https://doi.org/10.1371/journal.pcbi.1012789") @Description("Allows to sample from a CCD{0,1} based on a input set of trees") public class CCDSampler extends Runnable { final public Input treeInput = new Input<>("trees", "trees file to construct CCD with and analyse", Input.Validate.REQUIRED); @@ -67,6 +71,8 @@ public void run() throws Exception { bufferedOutputWriter.newLine(); } } + + CCDToolUtil.printCitations(this); } public static void main(String[] args) throws Exception { diff --git a/src/main/java/ccd/tools/CCDToolUtil.java b/src/main/java/ccd/tools/CCDToolUtil.java index ab6ec19..5b74db6 100644 --- a/src/main/java/ccd/tools/CCDToolUtil.java +++ b/src/main/java/ccd/tools/CCDToolUtil.java @@ -1,5 +1,7 @@ package ccd.tools; +import beast.base.core.Citable; +import beast.base.core.Citation; import beast.base.core.Input; import beast.base.core.Log; import beastfx.app.treeannotator.TreeAnnotator; @@ -14,6 +16,7 @@ import ccd.model.RegCCD; import java.io.IOException; +import java.util.List; /** * Static methods provided for tools {@link beastfx.app.tools.Application} in the CCD package @@ -110,4 +113,30 @@ public static AbstractCCD getCCDTypeByName(TreeAnnotator.MemoryFriendlyTreeSet t } return ccd; } + + /** + * Print the {@link Citation}s of the given tool, if it has any, in the style used by + * TreeAnnotator. Output goes to {@link Log#warning} (stderr) so that it does not interfere + * with results written to stdout. + * + * @param tool the tool whose citations are printed + */ + public static void printCitations(Citable tool) { + List citations = tool.getCitationList(); + if (citations.isEmpty()) { + return; + } + + StringBuilder buf = new StringBuilder(); + buf.append("\n======================================================\n"); + buf.append("Please cite the following when using these results:\n"); + for (Citation citation : citations) { + buf.append("\n").append(citation.value()).append("\n"); + if (!citation.DOI().isEmpty()) { + buf.append(citation.DOI()).append("\n"); + } + } + buf.append("======================================================"); + Log.warning(buf.toString()); + } } diff --git a/src/main/java/ccd/tools/DissonanceCalculator.java b/src/main/java/ccd/tools/DissonanceCalculator.java index 4ec3b72..8b479df 100644 --- a/src/main/java/ccd/tools/DissonanceCalculator.java +++ b/src/main/java/ccd/tools/DissonanceCalculator.java @@ -1,5 +1,6 @@ package ccd.tools; +import beast.base.core.Citation; import beast.base.core.Description; import beast.base.core.Input; import beast.base.core.Log; @@ -13,6 +14,9 @@ import java.util.ArrayList; import java.util.List; +@Citation(value = "Klawitter, Bouckaert and Drummond (2024). bioRxiv.\n" + + "Skeletons in the forest: using entropy-based rogue detection on Bayesian phylogenetic tree distributions.", + DOI = "https://doi.org/10.1101/2024.09.25.615070") @Description("Calculates the phylogenetic entropies of the posterior tree distribution (estimated via CCD0s) of given tree sets") public class DissonanceCalculator extends beast.base.inference.Runnable { final public Input> treeInput = new Input<>("trees", "trees to include in dissonance calculation", new ArrayList<>()); @@ -32,7 +36,7 @@ public void run() throws Exception { long start = System.currentTimeMillis(); if (!quiet) { - Log.info("# Starting Entropy Calculator"); + Log.info("# Starting Dissonance Calculator"); } List entropies = new ArrayList<>(); @@ -115,11 +119,12 @@ public void run() throws Exception { long end = System.currentTimeMillis(); if (!quiet) { Log.info("Done in " + (end - start) / 1000.0 + " seconds"); + CCDToolUtil.printCitations(this); } } public static void main(String[] args) throws Exception { - new Application(new DissonanceCalculator(), "Entropy Calculator", args); + new Application(new DissonanceCalculator(), "Dissonance Calculator", args); } } diff --git a/src/main/java/ccd/tools/EntropyCalculator.java b/src/main/java/ccd/tools/EntropyCalculator.java index 532cb7a..bfd11a1 100644 --- a/src/main/java/ccd/tools/EntropyCalculator.java +++ b/src/main/java/ccd/tools/EntropyCalculator.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; +import beast.base.core.Citation; import beast.base.core.Description; import beast.base.core.Input; import beast.base.core.Log; @@ -14,6 +15,9 @@ import ccd.model.AbstractCCD; import ccd.model.CCDType; +@Citation(value = "Klawitter, Bouckaert and Drummond (2024). bioRxiv.\n" + + "Skeletons in the forest: using entropy-based rogue detection on Bayesian phylogenetic tree distributions.", + DOI = "https://doi.org/10.1101/2024.09.25.615070") @Description("Calculates the phylogenetic entropy of the posterior tree distribution") public class EntropyCalculator extends beast.base.inference.Runnable { // input @@ -64,6 +68,10 @@ public void run() throws Exception { } k++; } + + if (verboseInput.get()) { + CCDToolUtil.printCitations(this); + } } public static void main(String[] args) throws Exception { diff --git a/src/main/java/ccd/tools/RogueAnalysis.java b/src/main/java/ccd/tools/RogueAnalysis.java index 867e5cc..aa23bb0 100644 --- a/src/main/java/ccd/tools/RogueAnalysis.java +++ b/src/main/java/ccd/tools/RogueAnalysis.java @@ -1,5 +1,6 @@ package ccd.tools; +import beast.base.core.Citation; import beast.base.core.Description; import beast.base.core.Input; import beast.base.core.Input.Validate; @@ -23,6 +24,9 @@ import java.util.Arrays; import java.util.Map; +@Citation(value = "Klawitter, Bouckaert and Drummond (2024). bioRxiv.\n" + + "Skeletons in the forest: using entropy-based rogue detection on Bayesian phylogenetic tree distributions.", + DOI = "https://doi.org/10.1101/2024.09.25.615070") @Description("Analyse the clades in a CCD for given trees based on their clade rogue score (based on entropy)") public class RogueAnalysis extends Runnable { @@ -141,6 +145,8 @@ public void run() throws Exception { createNexusTreeFile(infoOutputFileName, tree); Log.warning("Done"); + + CCDToolUtil.printCitations(this); } private boolean cladeConditionSatisfied(Clade clade, int maxCladeSize, double minProbability) { diff --git a/src/main/java/ccd/tools/SkeletonAnalysis.java b/src/main/java/ccd/tools/SkeletonAnalysis.java index 8fad9d0..bb56c8d 100644 --- a/src/main/java/ccd/tools/SkeletonAnalysis.java +++ b/src/main/java/ccd/tools/SkeletonAnalysis.java @@ -1,6 +1,7 @@ package ccd.tools; +import beast.base.core.Citation; import beast.base.core.Description; import beast.base.core.Input; import beast.base.core.Input.Validate; @@ -30,6 +31,9 @@ import static ccd.algorithms.RogueDetection.TerminationStrategy.*; +@Citation(value = "Klawitter, Bouckaert and Drummond (2024). bioRxiv.\n" + + "Skeletons in the forest: using entropy-based rogue detection on Bayesian phylogenetic tree distributions.", + DOI = "https://doi.org/10.1101/2024.09.25.615070") @Description("Analyses the skeleton of a CCD for given trees based on the total rogue scores (based on entropy)") public class SkeletonAnalysis extends Runnable { // input @@ -145,6 +149,8 @@ public void run() throws Exception { RogueDetection.annotateRoguePlacements(ccd, lastCCD, rogues, tree); System.out.println("The resulting annotated tree is: "); System.out.println(tree.getRoot().toNewick()); + + CCDToolUtil.printCitations(this); } /* Extracted code that filters source treeset. */ diff --git a/src/main/java/ccd/tools/TreeCredibleLevel.java b/src/main/java/ccd/tools/TreeCredibleLevel.java index d9aad0a..8487f5f 100644 --- a/src/main/java/ccd/tools/TreeCredibleLevel.java +++ b/src/main/java/ccd/tools/TreeCredibleLevel.java @@ -1,5 +1,6 @@ package ccd.tools; +import beast.base.core.Citation; import beast.base.core.Description; import beast.base.core.Input; import beast.base.core.Log; @@ -21,6 +22,9 @@ import static ccd.algorithms.credibleSets.ProbabilityBasedCredibleSetComputer.DEFAULT_NUM_SAMPLES; +@Citation(value = "Klawitter and Drummond (2026). Molecular Biology and Evolution 43(7), msag141.\n" + + "Bayesian credible sets for phylogenetic tree topologies with applications to coverage analysis and cross-model comparison.", + DOI = "https://doi.org/10.1093/molbev/msag141") @Description("Compute probability and credible level of given tree in CCD of given tree set") public class TreeCredibleLevel extends beast.base.inference.Runnable { // input @@ -99,6 +103,7 @@ public void run() throws Exception { if (!quiet) { Log.info("Done."); + CCDToolUtil.printCitations(this); } } From d247b6e219006aa725926b768618face5303b3db Mon Sep 17 00:00:00 2001 From: alexeid Date: Wed, 19 Aug 2026 13:29:22 +1200 Subject: [PATCH 4/4] Use beast 2.8.0-beta8 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 20924e6..8ca9b90 100644 --- a/pom.xml +++ b/pom.xml @@ -41,7 +41,7 @@ UTF-8 25 - 2.8.0-beta7 + 2.8.0-beta8 25.0.2 beast.base beast.base.minimal.BeastMain