PythiaLabelGenerator 1.0.0__tar.gz → 1.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pythialabelgenerator-1.2.0/.gitattributes +1 -0
- pythialabelgenerator-1.2.0/.github/workflows/publish-pypi.yml +63 -0
- pythialabelgenerator-1.2.0/.github/workflows/test-label-generator.yml +89 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/.gitignore +3 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/.pre-commit-config.yaml +2 -2
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/PKG-INFO +71 -24
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/README.md +65 -18
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/labelgenerator/iqtree.py +1 -2
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/labelgenerator/label.py +6 -5
- pythialabelgenerator-1.2.0/labelgenerator/logger.py +49 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/labelgenerator/main.py +48 -19
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/labelgenerator/raxmlng.py +9 -3
- pythialabelgenerator-1.2.0/pixi.toml +55 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/pyproject.toml +12 -31
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/conftest.py +14 -3
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/test_label.py +27 -11
- pythialabelgenerator-1.2.0/tests/test_main.py +138 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/test_raxmlng.py +38 -4
- pythialabelgenerator-1.0.0/.github/actions/setup-iqtree/action.yml +0 -22
- pythialabelgenerator-1.0.0/.github/actions/setup-raxmlng/action.yml +0 -20
- pythialabelgenerator-1.0.0/.github/actions/test-label-cli/action.yml +0 -12
- pythialabelgenerator-1.0.0/.github/workflows/test-label-generator.yml +0 -72
- pythialabelgenerator-1.0.0/etc/environment.yml +0 -9
- pythialabelgenerator-1.0.0/labelgenerator/logger.py +0 -32
- pythialabelgenerator-1.0.0/tests/test_config.py +0 -2
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/LICENSE +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/__init__.py +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/examples/example.phy +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/labelgenerator/__init__.py +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/labelgenerator/iqtree_parser.py +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/setup.py +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/__init__.py +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/AA.phy +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/DNA.phy +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/MORPH.phy +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/logs/AA.iqtree.iqtree +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/logs/AA.iqtree.log +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/logs/DNA.iqtree.iqtree +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/logs/DNA.iqtree.log +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/logs/DNA.raxml.log +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/logs/MORPH.iqtree.iqtree +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/logs/MORPH.iqtree.log +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/logs/test.raxml.bestModel +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/logs/test.raxml.bestTree +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/logs/test.raxml.log +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/logs/test.raxml.mlTrees +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/logs/test.raxml.rba +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/logs/test.raxml.startTree +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/logs/test.rfdist.raxml.log +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/logs/test.rfdist.raxml.rfDistances +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/mltrees/AA.raxml.bestModel +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/mltrees/AA.raxml.bestTree +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/mltrees/AA.raxml.log +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/mltrees/AA.raxml.mlTrees +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/mltrees/AA.raxml.rba +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/mltrees/AA.raxml.startTree +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/mltrees/DNA.raxml.bestModel +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/mltrees/DNA.raxml.bestTree +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/mltrees/DNA.raxml.bestTreeCollapsed +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/mltrees/DNA.raxml.log +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/mltrees/DNA.raxml.mlTrees +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/mltrees/DNA.raxml.rba +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/mltrees/DNA.raxml.startTree +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/mltrees/MORPH.raxml.bestModel +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/mltrees/MORPH.raxml.bestTree +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/mltrees/MORPH.raxml.bestTreeCollapsed +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/mltrees/MORPH.raxml.log +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/mltrees/MORPH.raxml.mlTrees +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/mltrees/MORPH.raxml.rba +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/data/mltrees/MORPH.raxml.startTree +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/test_iqtree.py +0 -0
- {pythialabelgenerator-1.0.0 → pythialabelgenerator-1.2.0}/tests/test_iqtree_parser.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pixi.lock linguist-generated=true
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
concurrency:
|
|
11
|
+
group: pypi-${{ github.event.release.tag_name }}
|
|
12
|
+
cancel-in-progress: false
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
validate-release:
|
|
16
|
+
name: Validate release version
|
|
17
|
+
if: github.event_name == 'release' && github.event.action == 'published' && !github.event.release.draft && !github.event.release.prerelease
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- name: Check out released commit
|
|
21
|
+
uses: actions/checkout@v7
|
|
22
|
+
- name: Set up Python
|
|
23
|
+
uses: actions/setup-python@v7
|
|
24
|
+
with:
|
|
25
|
+
python-version: '3.14'
|
|
26
|
+
- name: Check tag matches package version
|
|
27
|
+
env:
|
|
28
|
+
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
|
29
|
+
run: |
|
|
30
|
+
python - <<'PY'
|
|
31
|
+
import os
|
|
32
|
+
import pathlib
|
|
33
|
+
import tomllib
|
|
34
|
+
|
|
35
|
+
version = tomllib.loads(pathlib.Path("pyproject.toml").read_text())["project"]["version"]
|
|
36
|
+
tag = os.environ["RELEASE_TAG"]
|
|
37
|
+
if tag != version:
|
|
38
|
+
raise SystemExit(f"Release tag {tag!r} must match package version {version!r}")
|
|
39
|
+
print(f"Validated release {version}")
|
|
40
|
+
PY
|
|
41
|
+
|
|
42
|
+
test-and-build:
|
|
43
|
+
name: Test and build release
|
|
44
|
+
needs: validate-release
|
|
45
|
+
uses: ./.github/workflows/test-label-generator.yml
|
|
46
|
+
|
|
47
|
+
publish:
|
|
48
|
+
name: Upload distributions to PyPI
|
|
49
|
+
needs: test-and-build
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
environment:
|
|
52
|
+
name: pypi
|
|
53
|
+
url: https://pypi.org/project/PythiaLabelGenerator/
|
|
54
|
+
permissions:
|
|
55
|
+
id-token: write
|
|
56
|
+
steps:
|
|
57
|
+
- name: Download tested distributions
|
|
58
|
+
uses: actions/download-artifact@v8
|
|
59
|
+
with:
|
|
60
|
+
name: python-distributions
|
|
61
|
+
path: dist/
|
|
62
|
+
- name: Publish distributions
|
|
63
|
+
uses: pypa/gh-action-pypi-publish@v1.14.2
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
name: Build and test LabelGenerator
|
|
2
|
+
run-name: Build and test the LabelGenerator Python library
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
pull_request:
|
|
6
|
+
push:
|
|
7
|
+
branches:
|
|
8
|
+
- main
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
workflow_call:
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
pixi-tests:
|
|
17
|
+
name: Pixi tests (${{ matrix.os }}, ${{ matrix.environment }})
|
|
18
|
+
runs-on: ${{ matrix.os }}
|
|
19
|
+
strategy:
|
|
20
|
+
fail-fast: false
|
|
21
|
+
matrix:
|
|
22
|
+
os: [ubuntu-latest, macos-latest]
|
|
23
|
+
environment: [py311, py314, legacy-raxml]
|
|
24
|
+
steps:
|
|
25
|
+
- name: Check out repository code
|
|
26
|
+
uses: actions/checkout@v7
|
|
27
|
+
- name: Set up Pixi
|
|
28
|
+
uses: prefix-dev/setup-pixi@v0.10.2
|
|
29
|
+
with:
|
|
30
|
+
pixi-version: v0.77.0
|
|
31
|
+
environments: ${{ matrix.environment }}
|
|
32
|
+
frozen: true
|
|
33
|
+
cache: true
|
|
34
|
+
cache-write: ${{ github.event_name == 'push' && github.ref_name == 'main' }}
|
|
35
|
+
- name: Check the lock file
|
|
36
|
+
run: pixi lock --check
|
|
37
|
+
- name: Check RAxML-NG and IQ-TREE
|
|
38
|
+
run: pixi run --frozen --environment ${{ matrix.environment }} binary-smoke
|
|
39
|
+
- name: Run the test suite
|
|
40
|
+
run: pixi run --frozen --environment ${{ matrix.environment }} test
|
|
41
|
+
- name: Check the CLI
|
|
42
|
+
run: pixi run --frozen --environment ${{ matrix.environment }} cli-smoke
|
|
43
|
+
|
|
44
|
+
package-smoke:
|
|
45
|
+
name: Python package smoke test (${{ matrix.os }})
|
|
46
|
+
runs-on: ${{ matrix.os }}
|
|
47
|
+
strategy:
|
|
48
|
+
fail-fast: false
|
|
49
|
+
matrix:
|
|
50
|
+
os: [ubuntu-latest, macos-latest]
|
|
51
|
+
steps:
|
|
52
|
+
- name: Check out repository code
|
|
53
|
+
uses: actions/checkout@v7
|
|
54
|
+
- name: Set up Pixi
|
|
55
|
+
uses: prefix-dev/setup-pixi@v0.10.2
|
|
56
|
+
with:
|
|
57
|
+
pixi-version: v0.77.0
|
|
58
|
+
environments: build
|
|
59
|
+
frozen: true
|
|
60
|
+
cache: true
|
|
61
|
+
- name: Check the lock file
|
|
62
|
+
run: pixi lock --check
|
|
63
|
+
- name: Build and verify distributions
|
|
64
|
+
run: pixi run --frozen package-smoke
|
|
65
|
+
- name: Check distribution filenames
|
|
66
|
+
run: |
|
|
67
|
+
pixi run --frozen --environment build python - <<'PY'
|
|
68
|
+
import pathlib
|
|
69
|
+
import tomllib
|
|
70
|
+
|
|
71
|
+
version = tomllib.loads(pathlib.Path("pyproject.toml").read_text())["project"]["version"]
|
|
72
|
+
expected = {
|
|
73
|
+
f"pythialabelgenerator-{version}-py3-none-any.whl",
|
|
74
|
+
f"pythialabelgenerator-{version}.tar.gz",
|
|
75
|
+
}
|
|
76
|
+
actual = {path.name for path in pathlib.Path("dist").iterdir()}
|
|
77
|
+
if actual != expected:
|
|
78
|
+
raise SystemExit(f"Expected distributions {sorted(expected)}, found {sorted(actual)}")
|
|
79
|
+
PY
|
|
80
|
+
- name: Upload tested distributions
|
|
81
|
+
if: matrix.os == 'ubuntu-latest'
|
|
82
|
+
uses: actions/upload-artifact@v7
|
|
83
|
+
with:
|
|
84
|
+
name: python-distributions
|
|
85
|
+
path: |
|
|
86
|
+
dist/*.whl
|
|
87
|
+
dist/*.tar.gz
|
|
88
|
+
if-no-files-found: error
|
|
89
|
+
overwrite: true
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
repos:
|
|
2
2
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
3
|
-
rev:
|
|
3
|
+
rev: v6.0.0
|
|
4
4
|
hooks:
|
|
5
5
|
- id: check-yaml
|
|
6
6
|
- id: end-of-file-fixer
|
|
7
7
|
- id: trailing-whitespace
|
|
8
8
|
- id: detect-private-key
|
|
9
9
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
10
|
-
rev: v0.
|
|
10
|
+
rev: v0.16.6
|
|
11
11
|
hooks:
|
|
12
12
|
# Run the linter.
|
|
13
13
|
- id: ruff
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: PythiaLabelGenerator
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Command line tool to generate the ground-truth phylogenetic difficulty of MSAs
|
|
5
5
|
Project-URL: Homepage, https://github.com/tschuelia/PythiaLabelGenerator
|
|
6
6
|
Author-email: Julia Haag <info@juliaschmid.com>
|
|
7
7
|
License-Expression: GPL-3.0-or-later
|
|
8
8
|
License-File: LICENSE
|
|
9
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
11
9
|
Classifier: Programming Language :: Python :: 3.11
|
|
12
10
|
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
-
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
|
+
Requires-Python: <3.15,>=3.11
|
|
14
14
|
Requires-Dist: loguru
|
|
15
|
-
Requires-Dist: pythiaphylopredictor>=2.
|
|
15
|
+
Requires-Dist: pythiaphylopredictor>=2.1.0
|
|
16
16
|
Requires-Dist: regex
|
|
17
17
|
Provides-Extra: test
|
|
18
18
|
Requires-Dist: pytest; extra == 'test'
|
|
19
19
|
Description-Content-Type: text/markdown
|
|
20
20
|
|
|
21
|
-
# Pythia Difficulty Label Generator
|
|
21
|
+
# Pythia Difficulty Label Generator (PyDLG)
|
|
22
22
|
|
|
23
23
|

|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
PyDLG generates the ground-truth phylogenetic difficulty label for an MSA and
|
|
26
26
|
corresponds to the prediction target of our difficulty prediction tool [Pythia](https://github.com/tschuelia/PyPythia).
|
|
27
27
|
|
|
28
28
|
> [!CAUTION]
|
|
@@ -59,6 +59,18 @@ Per default, the difficulty is based on $`N_{\text{all}}=100`$ ML trees.
|
|
|
59
59
|
Note that this number can be adjusted by the user, however, the difficulty will only be an approximation if the number
|
|
60
60
|
of trees is changed.
|
|
61
61
|
|
|
62
|
+
## RAxML-NG 2 Compatibility
|
|
63
|
+
|
|
64
|
+
When using RAxML-NG 2, PyDLG automatically passes the following flags to preserve the label-generation procedure
|
|
65
|
+
used in our publications:
|
|
66
|
+
|
|
67
|
+
- `--adaptive off` disables adaptive search and its early-stopping rule. This ensures that tree searches are not
|
|
68
|
+
cut short based on estimated difficulty and that label computation follows our published difficulty definition.
|
|
69
|
+
- `--extra brlen-start-fixed` restores the initial branch-length behavior of RAxML-NG 1.2, so labels are computed
|
|
70
|
+
using the same initialization as in our publications.
|
|
71
|
+
|
|
72
|
+
These flags are applied automatically; no additional `label` arguments are required.
|
|
73
|
+
|
|
62
74
|
## Prediction of Phylogenetic Difficulty
|
|
63
75
|
|
|
64
76
|
As stated above, computing the ground-truth difficulty for an MSA is very time-consuming and requires a lot of
|
|
@@ -70,7 +82,7 @@ comprising [SARS-CoV-2 sequences](https://doi.org/10.1093/molbev/msaa314) (appro
|
|
|
70
82
|
12 hours on a large compute cluster. Using Pythia instead, we can predict the same MSA to be very difficult in about 2.5
|
|
71
83
|
minutes on a standard MacBook.
|
|
72
84
|
|
|
73
|
-
Only use
|
|
85
|
+
Only use PyDLG if you need the ground-truth difficulty for a specific MSA and you are sure that Pythia is unable to
|
|
74
86
|
predict the difficulty accurately.
|
|
75
87
|
The only case where we observed Pythia to fail is for language MSAs, so if you are working with DNA, Protein, or
|
|
76
88
|
biological morphological data, Pythia should work just fine 😉
|
|
@@ -79,16 +91,20 @@ biological morphological data, Pythia should work just fine 😉
|
|
|
79
91
|
|
|
80
92
|
#### Requirements
|
|
81
93
|
|
|
82
|
-
To use
|
|
94
|
+
To use PyDLG, you need to install
|
|
83
95
|
|
|
84
96
|
- RAxML-NG: See [the RAxML-NG GitHub repository](https://github.com/amkozlov/raxml-ng) for installation instructions.
|
|
85
|
-
|
|
97
|
+
PyDLG supports both RAxML-NG 1.x and 2.x.
|
|
86
98
|
- IQ-TREE: See [the IQ-TREE website](http://www.iqtree.org) for installation instructions. Please install IQ-TREE
|
|
87
99
|
version 2 or higher.
|
|
88
100
|
|
|
89
101
|
#### Install via conda (recommended)
|
|
90
102
|
|
|
91
|
-
|
|
103
|
+
You can install the package using conda:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
conda install pythialabelgenerator -c conda-forge
|
|
107
|
+
```
|
|
92
108
|
|
|
93
109
|
#### Install using pip
|
|
94
110
|
|
|
@@ -98,9 +114,41 @@ You can install the package using pip:
|
|
|
98
114
|
pip install pythialabelgenerator
|
|
99
115
|
```
|
|
100
116
|
|
|
117
|
+
This installs the Python package but not RAxML-NG or IQ-TREE. Install both programs separately as described in
|
|
118
|
+
[Requirements](#requirements).
|
|
119
|
+
|
|
120
|
+
#### Develop using Pixi
|
|
121
|
+
|
|
122
|
+
Pixi is the supported way to create a development environment containing the Python package and both phylogenetic
|
|
123
|
+
binaries:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
git clone https://github.com/tschuelia/PythiaLabelGenerator.git
|
|
127
|
+
cd PythiaLabelGenerator
|
|
128
|
+
pixi install --frozen
|
|
129
|
+
pixi run binary-smoke
|
|
130
|
+
pixi run cli-smoke
|
|
131
|
+
pixi run test
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Unlike released-package installations, these project-local Pixi environments install the tested binaries from
|
|
135
|
+
Bioconda. The default environment contains RAxML-NG 2.0.2 and IQ-TREE 2.4.0, while `legacy-raxml` contains RAxML-NG
|
|
136
|
+
1.2.2. PyPythia 2.1.0 or newer is installed from conda-forge.
|
|
137
|
+
|
|
138
|
+
The default environment uses Python 3.14 and RAxML-NG 2.0.2. Use `pixi run --environment py311 ...` or
|
|
139
|
+
`pixi run --environment py314 ...` to reproduce the minimum and maximum Python versions tested in CI, or
|
|
140
|
+
`pixi run --environment legacy-raxml ...` to test with RAxML-NG 1.2.2. PyDLG supports Python 3.11 through Python 3.14.
|
|
141
|
+
|
|
142
|
+
Install the pre-commit hooks once and run all checks on demand using the dedicated environment:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
pixi run --environment pre-commit pre-commit-install
|
|
146
|
+
pixi run --environment pre-commit pre-commit-run
|
|
147
|
+
```
|
|
148
|
+
|
|
101
149
|
## Usage
|
|
102
150
|
|
|
103
|
-
|
|
151
|
+
PyDLG is primarily a command line tool. You can call it using the `label` command, for instance, to
|
|
104
152
|
compute the difficulty for the example MSA provided in the `examples` directory run
|
|
105
153
|
|
|
106
154
|
```bash
|
|
@@ -112,9 +160,9 @@ to the console.
|
|
|
112
160
|
The output will look something like this:
|
|
113
161
|
|
|
114
162
|
```text
|
|
115
|
-
|
|
163
|
+
PyDLG version 1.2.0 released by The Exelixis Lab
|
|
116
164
|
Developed by: Julia Haag
|
|
117
|
-
Latest version: https://github.com/tschuelia/
|
|
165
|
+
Latest version: https://github.com/tschuelia/PythiaLabelGenerator
|
|
118
166
|
Questions/problems/suggestions? Please open an issue on GitHub.
|
|
119
167
|
|
|
120
168
|
LabelGenerator was called at 06-Mar-2025 15:15:03 as follows:
|
|
@@ -142,14 +190,14 @@ Depending on your system setup, you might need to pass a RAxML-NG and IQ-TREE bi
|
|
|
142
190
|
You can do this using the `-r` and `-i` options, respectively. This is required in case `raxml-ng` and/or `iqtree2` are
|
|
143
191
|
not in your `$PATH`.
|
|
144
192
|
|
|
145
|
-
Note that this `
|
|
193
|
+
Note that this `example.phy` MSA is not the same exemplary MSA as we provide in the PyPythia repository, so please don't compare this ground-truth label to the exemplary prediction in PyPythia 😉
|
|
146
194
|
|
|
147
195
|
For a full list of command line options, run `label -h`:
|
|
148
196
|
|
|
149
197
|
```text
|
|
150
|
-
|
|
198
|
+
PyDLG version 1.2.0 released by The Exelixis Lab
|
|
151
199
|
Developed by: Julia Haag
|
|
152
|
-
Latest version: https://github.com/tschuelia/
|
|
200
|
+
Latest version: https://github.com/tschuelia/PythiaLabelGenerator
|
|
153
201
|
Questions/problems/suggestions? Please open an issue on GitHub.
|
|
154
202
|
|
|
155
203
|
usage: label [-h] -m MSA -r RAXMLNG -i IQTREE [-t THREADS] [-s SEED] [-p PREFIX] [--model MODEL] [--ntrees NTREES] [--redo] [-V]
|
|
@@ -183,19 +231,19 @@ difficulties, as the difficulty is based on the average pairwise RF distance bet
|
|
|
183
231
|
|
|
184
232
|
### Result Files
|
|
185
233
|
|
|
186
|
-
Running
|
|
234
|
+
Running PyDLG will result in the following files:
|
|
187
235
|
|
|
188
236
|
- `{prefix}.raxml.*`: RAxML-NG log and result files.
|
|
189
237
|
- `{prefix}.iqtree.*`: IQ-TREE log and result files.
|
|
190
238
|
- `{prefix}.labelGen.log`: Log file containing the output of the label generator. This is the same output as printed to
|
|
191
239
|
the terminal.
|
|
240
|
+
- `{prefix}.csv`: The computed ground-truth difficulty and all features required for Pythia for the given MSA.
|
|
192
241
|
|
|
193
242
|
You can set the prefix of these files using the `-p` option. By default, the prefix is the name of the MSA file.
|
|
194
243
|
Note that RAxML-NG and IQ-TREE refuse to overwrite existing files. If you want to redo the computations, you can use the
|
|
195
244
|
`--redo` option.
|
|
196
245
|
Please also specify the `--redo` option if you want to change the number of trees to infer using the `--ntrees` option
|
|
197
|
-
for the same prefix. Otherwise,
|
|
198
|
-
the label generator will exit with an error message.
|
|
246
|
+
for the same prefix. Otherwise, PyDLG will exit with an error message.
|
|
199
247
|
|
|
200
248
|
### Input Data
|
|
201
249
|
|
|
@@ -209,7 +257,6 @@ you can do so using the `--model` option.
|
|
|
209
257
|
|
|
210
258
|
|
|
211
259
|
## Citation
|
|
212
|
-
|
|
213
|
-
brief description of this new labelling tool. Please cite this pre-print if you use this tool in your research.
|
|
260
|
+
Please cite the following preprint if you use this tool in your research.
|
|
214
261
|
|
|
215
|
-
|
|
262
|
+
Haag, J. & Stamatakis, A. (2025). **Pythia 2.0: New Data, New Prediction Model, New Features.** *BioRxiv*. [https://doi.org/10.1101/2025.03.25.645182](https://doi.org/10.1101/2025.03.25.645182)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# Pythia Difficulty Label Generator
|
|
1
|
+
# Pythia Difficulty Label Generator (PyDLG)
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
PyDLG generates the ground-truth phylogenetic difficulty label for an MSA and
|
|
6
6
|
corresponds to the prediction target of our difficulty prediction tool [Pythia](https://github.com/tschuelia/PyPythia).
|
|
7
7
|
|
|
8
8
|
> [!CAUTION]
|
|
@@ -39,6 +39,18 @@ Per default, the difficulty is based on $`N_{\text{all}}=100`$ ML trees.
|
|
|
39
39
|
Note that this number can be adjusted by the user, however, the difficulty will only be an approximation if the number
|
|
40
40
|
of trees is changed.
|
|
41
41
|
|
|
42
|
+
## RAxML-NG 2 Compatibility
|
|
43
|
+
|
|
44
|
+
When using RAxML-NG 2, PyDLG automatically passes the following flags to preserve the label-generation procedure
|
|
45
|
+
used in our publications:
|
|
46
|
+
|
|
47
|
+
- `--adaptive off` disables adaptive search and its early-stopping rule. This ensures that tree searches are not
|
|
48
|
+
cut short based on estimated difficulty and that label computation follows our published difficulty definition.
|
|
49
|
+
- `--extra brlen-start-fixed` restores the initial branch-length behavior of RAxML-NG 1.2, so labels are computed
|
|
50
|
+
using the same initialization as in our publications.
|
|
51
|
+
|
|
52
|
+
These flags are applied automatically; no additional `label` arguments are required.
|
|
53
|
+
|
|
42
54
|
## Prediction of Phylogenetic Difficulty
|
|
43
55
|
|
|
44
56
|
As stated above, computing the ground-truth difficulty for an MSA is very time-consuming and requires a lot of
|
|
@@ -50,7 +62,7 @@ comprising [SARS-CoV-2 sequences](https://doi.org/10.1093/molbev/msaa314) (appro
|
|
|
50
62
|
12 hours on a large compute cluster. Using Pythia instead, we can predict the same MSA to be very difficult in about 2.5
|
|
51
63
|
minutes on a standard MacBook.
|
|
52
64
|
|
|
53
|
-
Only use
|
|
65
|
+
Only use PyDLG if you need the ground-truth difficulty for a specific MSA and you are sure that Pythia is unable to
|
|
54
66
|
predict the difficulty accurately.
|
|
55
67
|
The only case where we observed Pythia to fail is for language MSAs, so if you are working with DNA, Protein, or
|
|
56
68
|
biological morphological data, Pythia should work just fine 😉
|
|
@@ -59,16 +71,20 @@ biological morphological data, Pythia should work just fine 😉
|
|
|
59
71
|
|
|
60
72
|
#### Requirements
|
|
61
73
|
|
|
62
|
-
To use
|
|
74
|
+
To use PyDLG, you need to install
|
|
63
75
|
|
|
64
76
|
- RAxML-NG: See [the RAxML-NG GitHub repository](https://github.com/amkozlov/raxml-ng) for installation instructions.
|
|
65
|
-
|
|
77
|
+
PyDLG supports both RAxML-NG 1.x and 2.x.
|
|
66
78
|
- IQ-TREE: See [the IQ-TREE website](http://www.iqtree.org) for installation instructions. Please install IQ-TREE
|
|
67
79
|
version 2 or higher.
|
|
68
80
|
|
|
69
81
|
#### Install via conda (recommended)
|
|
70
82
|
|
|
71
|
-
|
|
83
|
+
You can install the package using conda:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
conda install pythialabelgenerator -c conda-forge
|
|
87
|
+
```
|
|
72
88
|
|
|
73
89
|
#### Install using pip
|
|
74
90
|
|
|
@@ -78,9 +94,41 @@ You can install the package using pip:
|
|
|
78
94
|
pip install pythialabelgenerator
|
|
79
95
|
```
|
|
80
96
|
|
|
97
|
+
This installs the Python package but not RAxML-NG or IQ-TREE. Install both programs separately as described in
|
|
98
|
+
[Requirements](#requirements).
|
|
99
|
+
|
|
100
|
+
#### Develop using Pixi
|
|
101
|
+
|
|
102
|
+
Pixi is the supported way to create a development environment containing the Python package and both phylogenetic
|
|
103
|
+
binaries:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
git clone https://github.com/tschuelia/PythiaLabelGenerator.git
|
|
107
|
+
cd PythiaLabelGenerator
|
|
108
|
+
pixi install --frozen
|
|
109
|
+
pixi run binary-smoke
|
|
110
|
+
pixi run cli-smoke
|
|
111
|
+
pixi run test
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Unlike released-package installations, these project-local Pixi environments install the tested binaries from
|
|
115
|
+
Bioconda. The default environment contains RAxML-NG 2.0.2 and IQ-TREE 2.4.0, while `legacy-raxml` contains RAxML-NG
|
|
116
|
+
1.2.2. PyPythia 2.1.0 or newer is installed from conda-forge.
|
|
117
|
+
|
|
118
|
+
The default environment uses Python 3.14 and RAxML-NG 2.0.2. Use `pixi run --environment py311 ...` or
|
|
119
|
+
`pixi run --environment py314 ...` to reproduce the minimum and maximum Python versions tested in CI, or
|
|
120
|
+
`pixi run --environment legacy-raxml ...` to test with RAxML-NG 1.2.2. PyDLG supports Python 3.11 through Python 3.14.
|
|
121
|
+
|
|
122
|
+
Install the pre-commit hooks once and run all checks on demand using the dedicated environment:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
pixi run --environment pre-commit pre-commit-install
|
|
126
|
+
pixi run --environment pre-commit pre-commit-run
|
|
127
|
+
```
|
|
128
|
+
|
|
81
129
|
## Usage
|
|
82
130
|
|
|
83
|
-
|
|
131
|
+
PyDLG is primarily a command line tool. You can call it using the `label` command, for instance, to
|
|
84
132
|
compute the difficulty for the example MSA provided in the `examples` directory run
|
|
85
133
|
|
|
86
134
|
```bash
|
|
@@ -92,9 +140,9 @@ to the console.
|
|
|
92
140
|
The output will look something like this:
|
|
93
141
|
|
|
94
142
|
```text
|
|
95
|
-
|
|
143
|
+
PyDLG version 1.2.0 released by The Exelixis Lab
|
|
96
144
|
Developed by: Julia Haag
|
|
97
|
-
Latest version: https://github.com/tschuelia/
|
|
145
|
+
Latest version: https://github.com/tschuelia/PythiaLabelGenerator
|
|
98
146
|
Questions/problems/suggestions? Please open an issue on GitHub.
|
|
99
147
|
|
|
100
148
|
LabelGenerator was called at 06-Mar-2025 15:15:03 as follows:
|
|
@@ -122,14 +170,14 @@ Depending on your system setup, you might need to pass a RAxML-NG and IQ-TREE bi
|
|
|
122
170
|
You can do this using the `-r` and `-i` options, respectively. This is required in case `raxml-ng` and/or `iqtree2` are
|
|
123
171
|
not in your `$PATH`.
|
|
124
172
|
|
|
125
|
-
Note that this `
|
|
173
|
+
Note that this `example.phy` MSA is not the same exemplary MSA as we provide in the PyPythia repository, so please don't compare this ground-truth label to the exemplary prediction in PyPythia 😉
|
|
126
174
|
|
|
127
175
|
For a full list of command line options, run `label -h`:
|
|
128
176
|
|
|
129
177
|
```text
|
|
130
|
-
|
|
178
|
+
PyDLG version 1.2.0 released by The Exelixis Lab
|
|
131
179
|
Developed by: Julia Haag
|
|
132
|
-
Latest version: https://github.com/tschuelia/
|
|
180
|
+
Latest version: https://github.com/tschuelia/PythiaLabelGenerator
|
|
133
181
|
Questions/problems/suggestions? Please open an issue on GitHub.
|
|
134
182
|
|
|
135
183
|
usage: label [-h] -m MSA -r RAXMLNG -i IQTREE [-t THREADS] [-s SEED] [-p PREFIX] [--model MODEL] [--ntrees NTREES] [--redo] [-V]
|
|
@@ -163,19 +211,19 @@ difficulties, as the difficulty is based on the average pairwise RF distance bet
|
|
|
163
211
|
|
|
164
212
|
### Result Files
|
|
165
213
|
|
|
166
|
-
Running
|
|
214
|
+
Running PyDLG will result in the following files:
|
|
167
215
|
|
|
168
216
|
- `{prefix}.raxml.*`: RAxML-NG log and result files.
|
|
169
217
|
- `{prefix}.iqtree.*`: IQ-TREE log and result files.
|
|
170
218
|
- `{prefix}.labelGen.log`: Log file containing the output of the label generator. This is the same output as printed to
|
|
171
219
|
the terminal.
|
|
220
|
+
- `{prefix}.csv`: The computed ground-truth difficulty and all features required for Pythia for the given MSA.
|
|
172
221
|
|
|
173
222
|
You can set the prefix of these files using the `-p` option. By default, the prefix is the name of the MSA file.
|
|
174
223
|
Note that RAxML-NG and IQ-TREE refuse to overwrite existing files. If you want to redo the computations, you can use the
|
|
175
224
|
`--redo` option.
|
|
176
225
|
Please also specify the `--redo` option if you want to change the number of trees to infer using the `--ntrees` option
|
|
177
|
-
for the same prefix. Otherwise,
|
|
178
|
-
the label generator will exit with an error message.
|
|
226
|
+
for the same prefix. Otherwise, PyDLG will exit with an error message.
|
|
179
227
|
|
|
180
228
|
### Input Data
|
|
181
229
|
|
|
@@ -189,7 +237,6 @@ you can do so using the `--model` option.
|
|
|
189
237
|
|
|
190
238
|
|
|
191
239
|
## Citation
|
|
192
|
-
|
|
193
|
-
brief description of this new labelling tool. Please cite this pre-print if you use this tool in your research.
|
|
240
|
+
Please cite the following preprint if you use this tool in your research.
|
|
194
241
|
|
|
195
|
-
|
|
242
|
+
Haag, J. & Stamatakis, A. (2025). **Pythia 2.0: New Data, New Prediction Model, New Features.** *BioRxiv*. [https://doi.org/10.1101/2025.03.25.645182](https://doi.org/10.1101/2025.03.25.645182)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import pathlib
|
|
2
2
|
import subprocess
|
|
3
|
-
from typing import Optional
|
|
4
3
|
|
|
5
4
|
from pypythia.custom_types import DataType
|
|
6
5
|
|
|
@@ -49,7 +48,7 @@ def run_statstests(
|
|
|
49
48
|
model: str,
|
|
50
49
|
prefix: pathlib.Path,
|
|
51
50
|
seed: int = 0,
|
|
52
|
-
threads:
|
|
51
|
+
threads: int | None = None,
|
|
53
52
|
is_morph: bool = False,
|
|
54
53
|
redo: bool = False,
|
|
55
54
|
) -> None:
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import pathlib
|
|
2
|
-
from typing import Optional
|
|
3
2
|
|
|
4
|
-
from pypythia.msa import
|
|
3
|
+
from pypythia.msa import MSA, DataType
|
|
5
4
|
|
|
6
5
|
from labelgenerator.iqtree import (
|
|
7
6
|
filter_plausible_trees,
|
|
@@ -100,14 +99,15 @@ def get_label(
|
|
|
100
99
|
|
|
101
100
|
|
|
102
101
|
def compute_label(
|
|
102
|
+
msa_obj: MSA,
|
|
103
103
|
msa_file: pathlib.Path,
|
|
104
104
|
raxmlng: pathlib.Path,
|
|
105
105
|
iqtree: pathlib.Path,
|
|
106
106
|
prefix: pathlib.Path,
|
|
107
|
-
model:
|
|
107
|
+
model: str | None = None,
|
|
108
108
|
n_trees: int = 100,
|
|
109
109
|
seed: int = 0,
|
|
110
|
-
threads:
|
|
110
|
+
threads: int | None = None,
|
|
111
111
|
redo: bool = False,
|
|
112
112
|
log_info: bool = True,
|
|
113
113
|
) -> float:
|
|
@@ -117,6 +117,7 @@ def compute_label(
|
|
|
117
117
|
|
|
118
118
|
|
|
119
119
|
Args:
|
|
120
|
+
msa_obj (MSA): MSA object containing the input data.
|
|
120
121
|
msa_file (pathlib.Path): Path to the MSA file to compute the label for. Can be either in FASTA or PHYLIP format.
|
|
121
122
|
raxmlng (pathlib.Path): Path to the RAxML-NG executable.
|
|
122
123
|
iqtree (pathlib.Path): Path to the IQ-TREE executable.
|
|
@@ -134,7 +135,6 @@ def compute_label(
|
|
|
134
135
|
float: The ground truth difficulty label for the given MSA.
|
|
135
136
|
|
|
136
137
|
"""
|
|
137
|
-
msa_obj = parse_msa(msa_file)
|
|
138
138
|
model = model or msa_obj.get_raxmlng_model()
|
|
139
139
|
|
|
140
140
|
# 1. Infer 100 ML trees for the given MSA using RAxML-NG
|
|
@@ -182,6 +182,7 @@ def compute_label(
|
|
|
182
182
|
seed=seed,
|
|
183
183
|
threads=threads,
|
|
184
184
|
redo=redo,
|
|
185
|
+
is_morph=msa_obj.data_type == DataType.MORPH,
|
|
185
186
|
)
|
|
186
187
|
|
|
187
188
|
# 4. Filter the plausible trees
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import textwrap
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
import loguru
|
|
6
|
+
|
|
7
|
+
from labelgenerator import __version__
|
|
8
|
+
|
|
9
|
+
SCRIPT_START = time.perf_counter()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
logger = loguru.logger
|
|
13
|
+
logger.remove()
|
|
14
|
+
logger.add(sys.stderr, format="{message}")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_header():
|
|
18
|
+
return textwrap.dedent(
|
|
19
|
+
f"PyDLG version {__version__} released by The Exelixis Lab\n"
|
|
20
|
+
f"Developed by: Julia Haag\n"
|
|
21
|
+
f"Latest version: https://github.com/tschuelia/PythiaLabelGenerator\n"
|
|
22
|
+
f"Questions/problems/suggestions? Please open an issue on GitHub.\n",
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def log_runtime_information(message, log_runtime=True):
|
|
27
|
+
if log_runtime:
|
|
28
|
+
seconds = time.perf_counter() - SCRIPT_START
|
|
29
|
+
fmt_time = time.strftime("%H:%M:%S", time.gmtime(seconds))
|
|
30
|
+
time_string = f"[{fmt_time}] "
|
|
31
|
+
else:
|
|
32
|
+
time_string = ""
|
|
33
|
+
logger.info(f"{time_string}{message}")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def log_runtime(total_runtime: int, runtime_name: str):
|
|
37
|
+
hours, remainder = divmod(total_runtime, 3600)
|
|
38
|
+
minutes, seconds = divmod(remainder, 60)
|
|
39
|
+
|
|
40
|
+
if hours > 0:
|
|
41
|
+
logger.info(
|
|
42
|
+
f"{runtime_name}: {int(hours):02d}:{int(minutes):02d}:{seconds:02d} hours ({round(total_runtime)} seconds)."
|
|
43
|
+
)
|
|
44
|
+
elif minutes > 0:
|
|
45
|
+
logger.info(
|
|
46
|
+
f"{runtime_name}: {int(minutes):02d}:{int(seconds):02d} minutes ({round(total_runtime)} seconds)."
|
|
47
|
+
)
|
|
48
|
+
else:
|
|
49
|
+
logger.info(f"{runtime_name}: {seconds:.2f} seconds.")
|