MetaPont 0.1.2__tar.gz → 0.1.4__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.
- {metapont-0.1.2/src/MetaPont.egg-info → metapont-0.1.4}/PKG-INFO +53 -17
- {metapont-0.1.2 → metapont-0.1.4}/README.md +52 -16
- {metapont-0.1.2 → metapont-0.1.4}/pyproject.toml +1 -1
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont/__init__.py +1 -1
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont/analysis.py +15 -7
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont/cli.py +75 -12
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont/compat.py +1 -1
- metapont-0.1.4/src/MetaPont/pipeline.py +868 -0
- {metapont-0.1.2 → metapont-0.1.4/src/MetaPont.egg-info}/PKG-INFO +53 -17
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont.egg-info/SOURCES.txt +2 -1
- metapont-0.1.4/tests/test_pipeline_v014.py +313 -0
- metapont-0.1.2/src/MetaPont/pipeline.py +0 -601
- {metapont-0.1.2 → metapont-0.1.4}/LICENSE +0 -0
- {metapont-0.1.2 → metapont-0.1.4}/setup.cfg +0 -0
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont/constants.py +0 -0
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont/layout.py +0 -0
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont/old/Contig_Coverage_Summary.py +0 -0
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont/old/Extract_By_Function.py +0 -0
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont/old/Extract_By_Taxa.py +0 -0
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont/old/Extract_Function_By_Taxa.py +0 -0
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont/old/Extract_Reads_By_Function.py +0 -0
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont/old/Function_By_Taxa.py +0 -0
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont/old/MetaPont_Combine.py +0 -0
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont/old/Report_Contig_Lineage.py +0 -0
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont/old/__init__.py +0 -0
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont/old/constants.py +0 -0
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont/parsers.py +0 -0
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont.egg-info/dependency_links.txt +0 -0
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont.egg-info/entry_points.txt +0 -0
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont.egg-info/requires.txt +0 -0
- {metapont-0.1.2 → metapont-0.1.4}/src/MetaPont.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: MetaPont
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: Integrated analysis of metagenomic assembly, readmapping, Kraken2 and eggNOG-mapper outputs.
|
|
5
5
|
Author-email: Nicholas Dimonaco <nicholas@dimonaco.co.uk>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -20,7 +20,7 @@ Provides-Extra: test
|
|
|
20
20
|
Requires-Dist: pytest>=7.0; extra == "test"
|
|
21
21
|
Dynamic: license-file
|
|
22
22
|
|
|
23
|
-
# MetaPont v0.1.
|
|
23
|
+
# MetaPont v0.1.4
|
|
24
24
|
|
|
25
25
|
MetaPont integrates existing metagenomic workflow outputs into per-sample and
|
|
26
26
|
cross-sample tables for contigs, taxonomy, readmapping support, and eggNOG-mapper
|
|
@@ -79,10 +79,20 @@ sample directory for the relevant files. The main inputs are:
|
|
|
79
79
|
| Contig FASTA | Contig inventory and lengths when a readmapping contig summary is absent |
|
|
80
80
|
|
|
81
81
|
Inputs are discovered independently, so incomplete samples can still be
|
|
82
|
-
included. Missing or
|
|
83
|
-
rerun missing upstream analyses.
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
included. Missing or empty core inputs are reported as warnings; MetaPont does not
|
|
83
|
+
rerun missing upstream analyses. The inventory checks the files MetaPont
|
|
84
|
+
actually consumes: contigs, Pyrodigal GFF/protein FASTA, eggNOG annotation TSV,
|
|
85
|
+
Kraken2 per-contig output/report, and readmapping contig/CDS summaries. Optional
|
|
86
|
+
sidecars (for example BAM/index, eggNOG XLSX, MPA report, Pyrodigal NT/QC files)
|
|
87
|
+
do not make an otherwise usable MetaPont input set incomplete.
|
|
88
|
+
|
|
89
|
+
MetaPont deliberately does not use modification-time comparisons to decide
|
|
90
|
+
whether outputs are stale. Scratch-retention commands such as `touch` can
|
|
91
|
+
update timestamps without changing file contents, so timestamp ordering is not
|
|
92
|
+
a reliable freshness test. The inventory reports presence/completeness, not
|
|
93
|
+
whether an upstream tool was rerun against the latest source assembly. Kraken2
|
|
94
|
+
assignments shorter than the selected minimum contig length are omitted from
|
|
95
|
+
taxonomy attribution by default. This filter does not rerun Kraken2.
|
|
86
96
|
|
|
87
97
|
## Commands
|
|
88
98
|
|
|
@@ -103,9 +113,10 @@ Useful options:
|
|
|
103
113
|
| Option | Default | Description |
|
|
104
114
|
| --- | --- | --- |
|
|
105
115
|
| `--force` | Off | Regenerate outputs even when the input signature matches a cached run. |
|
|
106
|
-
| `--no-heal-flags` | Off | Do not recreate missing upstream success flags when
|
|
116
|
+
| `--no-heal-flags` | Off | Do not recreate missing upstream success flags when the required non-empty core outputs are present. |
|
|
107
117
|
| `--min-contig-length N` | `2500` | Minimum Kraken2-assigned contig length retained for taxonomy attribution; use `0` to disable the filter. |
|
|
108
|
-
| `--taxon-function-abundance` | Off | Build the expanded taxon-by-function table. This
|
|
118
|
+
| `--taxon-function-abundance` | Off | Build the expanded taxon-by-function table using a disk-backed SQLite aggregation. This adds disk I/O and temporary disk usage. |
|
|
119
|
+
| `--signature-mode` | `sampled` | Cache input detection. `sampled` hashes seven evenly spaced 128 KiB blocks from each input and is insensitive to `touch`; `full` hashes every byte and is slower but provides whole-file SHA256 verification. |
|
|
109
120
|
| `--plots` | Off | Write optional quick-look PNG plots. Requires the `plots` installation extra. |
|
|
110
121
|
|
|
111
122
|
`metapont combine` is an alias for `metapont run`. The `metapont-combine`
|
|
@@ -117,9 +128,13 @@ command is also available for compatibility with the earlier combine command.
|
|
|
117
128
|
metapont inventory --root-dir /path/to/workflow-output --prefix E
|
|
118
129
|
```
|
|
119
130
|
|
|
120
|
-
The inventory reports discovered inputs,
|
|
121
|
-
warnings for each sample. Add `--heal-flags` to recreate a missing
|
|
122
|
-
only when
|
|
131
|
+
The inventory reports discovered inputs, core output availability, success
|
|
132
|
+
flags, and warnings for each sample. Add `--heal-flags` to recreate a missing
|
|
133
|
+
stage flag only when the full expected product set for that upstream stage is
|
|
134
|
+
present (including its QC/sidecar outputs where applicable). This is stricter
|
|
135
|
+
than MetaPont's integration-input check, so it does not mark an upstream stage
|
|
136
|
+
complete merely because MetaPont can consume a subset of its outputs. Timestamp
|
|
137
|
+
freshness is intentionally not inferred.
|
|
123
138
|
|
|
124
139
|
### Summarise readmapping coverage
|
|
125
140
|
|
|
@@ -140,7 +155,7 @@ Find taxa supporting a functional ID:
|
|
|
140
155
|
|
|
141
156
|
```bash
|
|
142
157
|
metapont query-function \
|
|
143
|
-
--root-dir /path/to/
|
|
158
|
+
--root-dir /path/to/MetaPont_Results \
|
|
144
159
|
--function-id GO:0016597 \
|
|
145
160
|
--category GO \
|
|
146
161
|
--rank Genus \
|
|
@@ -157,7 +172,7 @@ Find the most supported features associated with a taxon:
|
|
|
157
172
|
|
|
158
173
|
```bash
|
|
159
174
|
metapont query-taxon \
|
|
160
|
-
--root-dir /path/to/
|
|
175
|
+
--root-dir /path/to/MetaPont_Results \
|
|
161
176
|
--taxon Bacillus \
|
|
162
177
|
--category GO \
|
|
163
178
|
--rank Genus \
|
|
@@ -170,6 +185,20 @@ full lineage. `--category` is required for this query. Both query commands
|
|
|
170
185
|
accept an explicit `--gene-table` path; plain TSV and gzip-compressed TSV files
|
|
171
186
|
are supported.
|
|
172
187
|
|
|
188
|
+
Build the expanded taxon-by-function table **after** a normal MetaPont run,
|
|
189
|
+
without re-parsing the original eggNOG files or rerunning the integrated
|
|
190
|
+
analysis:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
metapont taxon-function-abundance \
|
|
194
|
+
--root-dir /path/to/workflow-output
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Alternatively, provide `--gene-table` to use an existing
|
|
198
|
+
`gene_annotations.tsv.gz`. This post-processing command uses a temporary
|
|
199
|
+
SQLite database to keep aggregation memory bounded. The output is written to
|
|
200
|
+
`MetaPont_Results/functional/taxon_function_abundance.tsv` by default.
|
|
201
|
+
|
|
173
202
|
## Results
|
|
174
203
|
|
|
175
204
|
The default output tree is:
|
|
@@ -182,7 +211,7 @@ MetaPont_Results/
|
|
|
182
211
|
├── functional/
|
|
183
212
|
│ ├── functional_abundance.tsv
|
|
184
213
|
│ ├── matrices/
|
|
185
|
-
│ └── taxon_function_abundance.tsv
|
|
214
|
+
│ └── taxon_function_abundance.tsv # optional; only when requested
|
|
186
215
|
├── inventory/
|
|
187
216
|
│ └── sample_inventory.tsv
|
|
188
217
|
├── metadata/
|
|
@@ -212,9 +241,16 @@ Supported functional categories include `COG`, `eggNOG_OG`, `GO`, `EC`,
|
|
|
212
241
|
is not a count of unique reads across genes. A read can support multiple genes
|
|
213
242
|
or annotations, so functional support values are not mutually exclusive.
|
|
214
243
|
Taxonomic relative abundance uses total mapped-read support as its denominator.
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
244
|
+
The new `Percent_Mapped_Reads_on_Classified_Contigs` field in the sample summary
|
|
245
|
+
shows how much of that denominator lies on Kraken-classified contigs.
|
|
246
|
+
|
|
247
|
+
Samples with missing or empty core workflow inputs are retained where
|
|
248
|
+
possible and listed in `summary/pipeline_warnings.tsv`. The sample summary also
|
|
249
|
+
reports genes processed versus genes with at least one functional feature, and
|
|
250
|
+
readmapping support on Kraken-classified, unclassified, length-filtered and
|
|
251
|
+
Kraken-unassigned contigs. `Genes_Annotated` remains for compatibility and is
|
|
252
|
+
equivalent to `Genes_Processed`; use `Genes_With_Function` when you specifically
|
|
253
|
+
mean genes with a parsed functional feature. A clean run writes
|
|
218
254
|
`MetaPont_analysis.success`; a run with warnings writes
|
|
219
255
|
`completed_with_warnings.flag`.
|
|
220
256
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# MetaPont v0.1.
|
|
1
|
+
# MetaPont v0.1.4
|
|
2
2
|
|
|
3
3
|
MetaPont integrates existing metagenomic workflow outputs into per-sample and
|
|
4
4
|
cross-sample tables for contigs, taxonomy, readmapping support, and eggNOG-mapper
|
|
@@ -57,10 +57,20 @@ sample directory for the relevant files. The main inputs are:
|
|
|
57
57
|
| Contig FASTA | Contig inventory and lengths when a readmapping contig summary is absent |
|
|
58
58
|
|
|
59
59
|
Inputs are discovered independently, so incomplete samples can still be
|
|
60
|
-
included. Missing or
|
|
61
|
-
rerun missing upstream analyses.
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
included. Missing or empty core inputs are reported as warnings; MetaPont does not
|
|
61
|
+
rerun missing upstream analyses. The inventory checks the files MetaPont
|
|
62
|
+
actually consumes: contigs, Pyrodigal GFF/protein FASTA, eggNOG annotation TSV,
|
|
63
|
+
Kraken2 per-contig output/report, and readmapping contig/CDS summaries. Optional
|
|
64
|
+
sidecars (for example BAM/index, eggNOG XLSX, MPA report, Pyrodigal NT/QC files)
|
|
65
|
+
do not make an otherwise usable MetaPont input set incomplete.
|
|
66
|
+
|
|
67
|
+
MetaPont deliberately does not use modification-time comparisons to decide
|
|
68
|
+
whether outputs are stale. Scratch-retention commands such as `touch` can
|
|
69
|
+
update timestamps without changing file contents, so timestamp ordering is not
|
|
70
|
+
a reliable freshness test. The inventory reports presence/completeness, not
|
|
71
|
+
whether an upstream tool was rerun against the latest source assembly. Kraken2
|
|
72
|
+
assignments shorter than the selected minimum contig length are omitted from
|
|
73
|
+
taxonomy attribution by default. This filter does not rerun Kraken2.
|
|
64
74
|
|
|
65
75
|
## Commands
|
|
66
76
|
|
|
@@ -81,9 +91,10 @@ Useful options:
|
|
|
81
91
|
| Option | Default | Description |
|
|
82
92
|
| --- | --- | --- |
|
|
83
93
|
| `--force` | Off | Regenerate outputs even when the input signature matches a cached run. |
|
|
84
|
-
| `--no-heal-flags` | Off | Do not recreate missing upstream success flags when
|
|
94
|
+
| `--no-heal-flags` | Off | Do not recreate missing upstream success flags when the required non-empty core outputs are present. |
|
|
85
95
|
| `--min-contig-length N` | `2500` | Minimum Kraken2-assigned contig length retained for taxonomy attribution; use `0` to disable the filter. |
|
|
86
|
-
| `--taxon-function-abundance` | Off | Build the expanded taxon-by-function table. This
|
|
96
|
+
| `--taxon-function-abundance` | Off | Build the expanded taxon-by-function table using a disk-backed SQLite aggregation. This adds disk I/O and temporary disk usage. |
|
|
97
|
+
| `--signature-mode` | `sampled` | Cache input detection. `sampled` hashes seven evenly spaced 128 KiB blocks from each input and is insensitive to `touch`; `full` hashes every byte and is slower but provides whole-file SHA256 verification. |
|
|
87
98
|
| `--plots` | Off | Write optional quick-look PNG plots. Requires the `plots` installation extra. |
|
|
88
99
|
|
|
89
100
|
`metapont combine` is an alias for `metapont run`. The `metapont-combine`
|
|
@@ -95,9 +106,13 @@ command is also available for compatibility with the earlier combine command.
|
|
|
95
106
|
metapont inventory --root-dir /path/to/workflow-output --prefix E
|
|
96
107
|
```
|
|
97
108
|
|
|
98
|
-
The inventory reports discovered inputs,
|
|
99
|
-
warnings for each sample. Add `--heal-flags` to recreate a missing
|
|
100
|
-
only when
|
|
109
|
+
The inventory reports discovered inputs, core output availability, success
|
|
110
|
+
flags, and warnings for each sample. Add `--heal-flags` to recreate a missing
|
|
111
|
+
stage flag only when the full expected product set for that upstream stage is
|
|
112
|
+
present (including its QC/sidecar outputs where applicable). This is stricter
|
|
113
|
+
than MetaPont's integration-input check, so it does not mark an upstream stage
|
|
114
|
+
complete merely because MetaPont can consume a subset of its outputs. Timestamp
|
|
115
|
+
freshness is intentionally not inferred.
|
|
101
116
|
|
|
102
117
|
### Summarise readmapping coverage
|
|
103
118
|
|
|
@@ -118,7 +133,7 @@ Find taxa supporting a functional ID:
|
|
|
118
133
|
|
|
119
134
|
```bash
|
|
120
135
|
metapont query-function \
|
|
121
|
-
--root-dir /path/to/
|
|
136
|
+
--root-dir /path/to/MetaPont_Results \
|
|
122
137
|
--function-id GO:0016597 \
|
|
123
138
|
--category GO \
|
|
124
139
|
--rank Genus \
|
|
@@ -135,7 +150,7 @@ Find the most supported features associated with a taxon:
|
|
|
135
150
|
|
|
136
151
|
```bash
|
|
137
152
|
metapont query-taxon \
|
|
138
|
-
--root-dir /path/to/
|
|
153
|
+
--root-dir /path/to/MetaPont_Results \
|
|
139
154
|
--taxon Bacillus \
|
|
140
155
|
--category GO \
|
|
141
156
|
--rank Genus \
|
|
@@ -148,6 +163,20 @@ full lineage. `--category` is required for this query. Both query commands
|
|
|
148
163
|
accept an explicit `--gene-table` path; plain TSV and gzip-compressed TSV files
|
|
149
164
|
are supported.
|
|
150
165
|
|
|
166
|
+
Build the expanded taxon-by-function table **after** a normal MetaPont run,
|
|
167
|
+
without re-parsing the original eggNOG files or rerunning the integrated
|
|
168
|
+
analysis:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
metapont taxon-function-abundance \
|
|
172
|
+
--root-dir /path/to/workflow-output
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Alternatively, provide `--gene-table` to use an existing
|
|
176
|
+
`gene_annotations.tsv.gz`. This post-processing command uses a temporary
|
|
177
|
+
SQLite database to keep aggregation memory bounded. The output is written to
|
|
178
|
+
`MetaPont_Results/functional/taxon_function_abundance.tsv` by default.
|
|
179
|
+
|
|
151
180
|
## Results
|
|
152
181
|
|
|
153
182
|
The default output tree is:
|
|
@@ -160,7 +189,7 @@ MetaPont_Results/
|
|
|
160
189
|
├── functional/
|
|
161
190
|
│ ├── functional_abundance.tsv
|
|
162
191
|
│ ├── matrices/
|
|
163
|
-
│ └── taxon_function_abundance.tsv
|
|
192
|
+
│ └── taxon_function_abundance.tsv # optional; only when requested
|
|
164
193
|
├── inventory/
|
|
165
194
|
│ └── sample_inventory.tsv
|
|
166
195
|
├── metadata/
|
|
@@ -190,9 +219,16 @@ Supported functional categories include `COG`, `eggNOG_OG`, `GO`, `EC`,
|
|
|
190
219
|
is not a count of unique reads across genes. A read can support multiple genes
|
|
191
220
|
or annotations, so functional support values are not mutually exclusive.
|
|
192
221
|
Taxonomic relative abundance uses total mapped-read support as its denominator.
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
222
|
+
The new `Percent_Mapped_Reads_on_Classified_Contigs` field in the sample summary
|
|
223
|
+
shows how much of that denominator lies on Kraken-classified contigs.
|
|
224
|
+
|
|
225
|
+
Samples with missing or empty core workflow inputs are retained where
|
|
226
|
+
possible and listed in `summary/pipeline_warnings.tsv`. The sample summary also
|
|
227
|
+
reports genes processed versus genes with at least one functional feature, and
|
|
228
|
+
readmapping support on Kraken-classified, unclassified, length-filtered and
|
|
229
|
+
Kraken-unassigned contigs. `Genes_Annotated` remains for compatibility and is
|
|
230
|
+
equivalent to `Genes_Processed`; use `Genes_With_Function` when you specifically
|
|
231
|
+
mean genes with a parsed functional feature. A clean run writes
|
|
196
232
|
`MetaPont_analysis.success`; a run with warnings writes
|
|
197
233
|
`completed_with_warnings.flag`.
|
|
198
234
|
|
|
@@ -11,7 +11,7 @@ from typing import Any
|
|
|
11
11
|
|
|
12
12
|
from .constants import FEATURE_COLUMNS
|
|
13
13
|
from .layout import discover_samples
|
|
14
|
-
from .parsers import open_text, parse_contig_summary
|
|
14
|
+
from .parsers import open_text, parse_contig_summary, split_features
|
|
15
15
|
from .pipeline import write_tsv
|
|
16
16
|
|
|
17
17
|
|
|
@@ -25,12 +25,15 @@ def _read_gene_table(path: str | Path):
|
|
|
25
25
|
def coverage_summary(root_dir: str | Path, prefixes: str, output: str | Path | None = None,
|
|
26
26
|
read_length: int | None = None) -> tuple[Path, int]:
|
|
27
27
|
root = Path(root_dir).expanduser().resolve()
|
|
28
|
+
if read_length is not None and read_length <= 0:
|
|
29
|
+
raise ValueError("read_length must be a positive integer.")
|
|
28
30
|
out = Path(output).expanduser().resolve() if output else root / "MetaPont_Results" / "summary" / "contig_coverage_summary.tsv"
|
|
29
31
|
samples = discover_samples(root, prefixes)
|
|
30
32
|
rows: list[dict[str, Any]] = []
|
|
31
33
|
for sample in samples:
|
|
32
|
-
if sample.contig_summary is None:
|
|
33
|
-
rows.append({"Sample": sample.name, "Status": "
|
|
34
|
+
if sample.contig_summary is None or not sample.contig_summary.is_file() or sample.contig_summary.stat().st_size == 0:
|
|
35
|
+
rows.append({"Sample": sample.name, "Status": "missing_or_empty_contig_summary",
|
|
36
|
+
"Contig_Summary": str(sample.contig_summary or "")})
|
|
34
37
|
continue
|
|
35
38
|
n_contigs = total_mapped = total_reported = 0
|
|
36
39
|
mapped_counts: list[int] = []
|
|
@@ -88,8 +91,9 @@ def coverage_summary(root_dir: str | Path, prefixes: str, output: str | Path | N
|
|
|
88
91
|
return out, len(rows)
|
|
89
92
|
|
|
90
93
|
|
|
91
|
-
def _feature_values(cell: str) -> list[str]:
|
|
92
|
-
|
|
94
|
+
def _feature_values(cell: str, category: str) -> list[str]:
|
|
95
|
+
"""Use the same feature parsing rules as the main annotation pipeline."""
|
|
96
|
+
return split_features(cell, category)
|
|
93
97
|
|
|
94
98
|
|
|
95
99
|
def query_function(gene_table: str | Path, function_id: str, output: str | Path,
|
|
@@ -98,6 +102,8 @@ def query_function(gene_table: str | Path, function_id: str, output: str | Path,
|
|
|
98
102
|
path = Path(gene_table)
|
|
99
103
|
if not path.is_file():
|
|
100
104
|
raise FileNotFoundError(f"Gene annotation table not found: {path}")
|
|
105
|
+
if top_n is not None and top_n < 1:
|
|
106
|
+
raise ValueError("top_n must be a positive integer.")
|
|
101
107
|
cat_norm = category.upper().replace("-", "_") if category else None
|
|
102
108
|
cat_aliases = {k.upper(): k for k in FEATURE_COLUMNS}
|
|
103
109
|
if cat_norm and cat_norm not in cat_aliases:
|
|
@@ -110,7 +116,7 @@ def query_function(gene_table: str | Path, function_id: str, output: str | Path,
|
|
|
110
116
|
denominator: dict[str, int] = defaultdict(int)
|
|
111
117
|
categories = [chosen_cat] if chosen_cat else list(FEATURE_COLUMNS)
|
|
112
118
|
for row in _read_gene_table(path):
|
|
113
|
-
found = any(function_id in _feature_values(row.get(cat, "")) for cat in categories)
|
|
119
|
+
found = any(function_id in _feature_values(row.get(cat, ""), cat) for cat in categories)
|
|
114
120
|
if not found:
|
|
115
121
|
continue
|
|
116
122
|
sample = row.get("Sample", "")
|
|
@@ -151,6 +157,8 @@ def query_taxon(gene_table: str | Path, taxon_query: str, output: str | Path,
|
|
|
151
157
|
path = Path(gene_table)
|
|
152
158
|
if not path.is_file():
|
|
153
159
|
raise FileNotFoundError(f"Gene annotation table not found: {path}")
|
|
160
|
+
if top_n < 1:
|
|
161
|
+
raise ValueError("top_n must be a positive integer.")
|
|
154
162
|
category_key = category.upper().replace("-", "_")
|
|
155
163
|
aliases = {key.upper(): key for key in FEATURE_COLUMNS}
|
|
156
164
|
if category_key not in aliases:
|
|
@@ -167,7 +175,7 @@ def query_taxon(gene_table: str | Path, taxon_query: str, output: str | Path,
|
|
|
167
175
|
continue
|
|
168
176
|
sample = row.get("Sample", "")
|
|
169
177
|
support = int(float(row.get("Gene_Read_Support", 0) or 0))
|
|
170
|
-
for feature in _feature_values(row.get(category_name, "")):
|
|
178
|
+
for feature in _feature_values(row.get(category_name, ""), category_name):
|
|
171
179
|
counts[(sample, value, lineage, feature)][0] += 1
|
|
172
180
|
counts[(sample, value, lineage, feature)][1] += support
|
|
173
181
|
per_sample: dict[str, list[dict[str, Any]]] = defaultdict(list)
|
|
@@ -10,7 +10,7 @@ from pathlib import Path
|
|
|
10
10
|
from . import MetaPont_Version, __version__
|
|
11
11
|
from .analysis import coverage_summary, query_function, query_taxon
|
|
12
12
|
from .layout import discover_samples
|
|
13
|
-
from .pipeline import OUTPUT_DIRNAME, run_analysis, write_inventory
|
|
13
|
+
from .pipeline import OUTPUT_DIRNAME, build_taxon_function_abundance, run_analysis, write_inventory
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
def _add_root_prefix(parser: argparse.ArgumentParser) -> None:
|
|
@@ -22,11 +22,19 @@ def _add_root_prefix(parser: argparse.ArgumentParser) -> None:
|
|
|
22
22
|
help=f"Results directory (default: ROOT/{OUTPUT_DIRNAME}).")
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
def
|
|
25
|
+
def _output_root(root_dir: str | None, output_dir: str | None) -> Path:
|
|
26
|
+
if output_dir:
|
|
27
|
+
return Path(output_dir).expanduser().resolve()
|
|
28
|
+
if not root_dir:
|
|
29
|
+
raise ValueError("Provide --root-dir, --output-dir or --gene-table.")
|
|
30
|
+
root = Path(root_dir).expanduser().resolve()
|
|
31
|
+
return root if root.name == OUTPUT_DIRNAME else root / OUTPUT_DIRNAME
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _gene_table(root_dir: str | None, output_dir: str | None, supplied: str | None) -> Path:
|
|
26
35
|
if supplied:
|
|
27
36
|
return Path(supplied).expanduser().resolve()
|
|
28
|
-
|
|
29
|
-
return output_root / "combined" / "gene_annotations.tsv.gz"
|
|
37
|
+
return _output_root(root_dir, output_dir) / "combined" / "gene_annotations.tsv.gz"
|
|
30
38
|
|
|
31
39
|
|
|
32
40
|
def _create_plots(output_root: Path) -> list[str]:
|
|
@@ -91,20 +99,24 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
91
99
|
run_p = sub.add_parser("run", aliases=["combine"], help="Build the integrated sample inventory, contig table and abundance summaries.")
|
|
92
100
|
_add_root_prefix(run_p)
|
|
93
101
|
run_p.add_argument("--force", action="store_true", help="Regenerate outputs even when the recorded input signature is unchanged.")
|
|
94
|
-
run_p.add_argument("--no-heal-flags", action="store_true", help="Do not recreate missing
|
|
102
|
+
run_p.add_argument("--no-heal-flags", action="store_true", help="Do not recreate missing upstream flags, even when the full expected stage output set is present.")
|
|
95
103
|
run_p.add_argument("--min-contig-length", type=int, default=2500, help="Minimum contig length to retain an existing Kraken2 assignment; classifications are not rerun.")
|
|
96
104
|
run_p.add_argument("--plots", action="store_true", help="Generate optional quick-look PNG plots (requires matplotlib).")
|
|
105
|
+
run_p.add_argument(
|
|
106
|
+
"--signature-mode", choices=("sampled", "full"), default="sampled",
|
|
107
|
+
help="Input change detection: sampled hashes seven evenly spaced blocks (touch-safe, default), or full SHA256 of every input byte (slower).",
|
|
108
|
+
)
|
|
97
109
|
run_p.add_argument(
|
|
98
110
|
"--taxon-function-abundance",
|
|
99
111
|
action="store_true",
|
|
100
112
|
help=(
|
|
101
|
-
"Generate the expanded taxon-function abundance table. "
|
|
102
|
-
"
|
|
113
|
+
"Generate the expanded taxon-function abundance table using a disk-backed aggregation. "
|
|
114
|
+
"This requires additional disk I/O and temporary space."
|
|
103
115
|
),
|
|
104
116
|
)
|
|
105
117
|
inv_p = sub.add_parser("inventory", help="Audit per-sample inputs, pipeline outputs and success flags.")
|
|
106
118
|
_add_root_prefix(inv_p)
|
|
107
|
-
inv_p.add_argument("--heal-flags", action="store_true", help="Recreate missing flags only when the
|
|
119
|
+
inv_p.add_argument("--heal-flags", action="store_true", help="Recreate missing upstream flags only when the full expected stage output set is present; timestamps are not used.")
|
|
108
120
|
|
|
109
121
|
cov_p = sub.add_parser("coverage", help="Summarise per-contig readmapping statistics by sample.")
|
|
110
122
|
_add_root_prefix(cov_p)
|
|
@@ -114,8 +126,9 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
114
126
|
qf_p = sub.add_parser("query-function", help="Find taxa supporting a particular eggNOG functional ID.")
|
|
115
127
|
qf_p.add_argument("--root-dir", "-d", default=None,
|
|
116
128
|
help="Workflow root used to find the default gene table; not needed with --gene-table or --output-dir.")
|
|
129
|
+
qf_p.add_argument("--gene-table", default=None,
|
|
130
|
+
help="Gene annotation TSV/TSV.GZ; defaults to the integrated output table.")
|
|
117
131
|
qf_p.add_argument("--output-dir", default=None)
|
|
118
|
-
qf_p.add_argument("--gene-table", default=None, help="Gene annotation TSV/TSV.GZ; defaults to the integrated output table.")
|
|
119
132
|
qf_p.add_argument("--function-id", "-f", required=True, help="Exact function ID, e.g. GO:0016597 or EC:2.7.11.1.")
|
|
120
133
|
qf_p.add_argument("--category", "-c", default=None, help="Optional annotation category, e.g. GO, EC, KEGG_KO, PFAM.")
|
|
121
134
|
qf_p.add_argument("--rank", default="Genus", help="Taxonomic rank for attribution (default: Genus).")
|
|
@@ -123,15 +136,25 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
123
136
|
qf_p.add_argument("--output", "-o", required=True)
|
|
124
137
|
|
|
125
138
|
qt_p = sub.add_parser("query-taxon", help="Report the most supported functions for a taxon.")
|
|
126
|
-
qt_p.add_argument("--root-dir", "-d",
|
|
139
|
+
qt_p.add_argument("--root-dir", "-d", default=None)
|
|
140
|
+
qt_p.add_argument("--gene-table", default=None,
|
|
141
|
+
help="Gene annotation TSV/TSV.GZ; defaults to the integrated output table.")
|
|
127
142
|
qt_p.add_argument("--output-dir", default=None)
|
|
128
|
-
qt_p.add_argument("--gene-table", default=None)
|
|
129
143
|
qt_p.add_argument("--taxon", "-t", required=True, help="Taxon name or lineage token, e.g. Bacillus or g__Bacillus.")
|
|
130
144
|
qt_p.add_argument("--category", "-c", required=True, help="Annotation category, e.g. GO, EC, KEGG_KO.")
|
|
131
145
|
qt_p.add_argument("--rank", default="Genus")
|
|
132
146
|
qt_p.add_argument("--top", type=int, default=20)
|
|
133
147
|
qt_p.add_argument("--output", "-o", required=True)
|
|
134
148
|
|
|
149
|
+
tf_p = sub.add_parser(
|
|
150
|
+
"taxon-function-abundance", aliases=["taxon-function"],
|
|
151
|
+
help="Build the expanded taxon-by-function table from an existing gene annotation table without rerunning the main analysis.",
|
|
152
|
+
)
|
|
153
|
+
tf_p.add_argument("--root-dir", "-d", default=None, help="Workflow root or MetaPont_Results directory.")
|
|
154
|
+
tf_p.add_argument("--gene-table", default=None, help="Existing gene_annotations.tsv or .tsv.gz file.")
|
|
155
|
+
tf_p.add_argument("--output-dir", default=None, help="MetaPont results directory (default derived from --root-dir).")
|
|
156
|
+
tf_p.add_argument("--output", "-o", default=None, help="Output TSV path (default: OUTPUT_DIR/functional/taxon_function_abundance.tsv).")
|
|
157
|
+
|
|
135
158
|
args = parser.parse_args(argv)
|
|
136
159
|
try:
|
|
137
160
|
if args.command in {"run", "combine"}:
|
|
@@ -141,6 +164,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
141
164
|
heal_flags=not args.no_heal_flags,
|
|
142
165
|
force=args.force,
|
|
143
166
|
include_taxon_function_abundance=args.taxon_function_abundance,
|
|
167
|
+
signature_mode=args.signature_mode,
|
|
144
168
|
)
|
|
145
169
|
if args.plots:
|
|
146
170
|
output_root = Path(result["output_dir"])
|
|
@@ -160,19 +184,58 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
160
184
|
print(f"Healed {len(events)} flags.")
|
|
161
185
|
return 0
|
|
162
186
|
if args.command == "coverage":
|
|
163
|
-
|
|
187
|
+
supplied_root = Path(args.root_dir).expanduser().resolve()
|
|
188
|
+
samples_root = supplied_root.parent if supplied_root.name == OUTPUT_DIRNAME else supplied_root
|
|
189
|
+
default_output_root = (
|
|
190
|
+
Path(args.output_dir).expanduser().resolve() if args.output_dir
|
|
191
|
+
else supplied_root if supplied_root.name == OUTPUT_DIRNAME
|
|
192
|
+
else supplied_root / OUTPUT_DIRNAME
|
|
193
|
+
)
|
|
194
|
+
default_output = default_output_root / "summary" / "contig_coverage_summary.tsv"
|
|
195
|
+
out, count = coverage_summary(
|
|
196
|
+
samples_root, args.prefix, args.output or default_output, args.read_length,
|
|
197
|
+
)
|
|
164
198
|
print(f"Coverage summary written for {count} samples: {out}")
|
|
165
199
|
return 0
|
|
166
200
|
if args.command == "query-function":
|
|
201
|
+
if args.root_dir is None and args.gene_table is None and args.output_dir is None:
|
|
202
|
+
raise ValueError("Provide --root-dir, --output-dir or --gene-table.")
|
|
203
|
+
|
|
204
|
+
# A MetaPont_Results directory can be supplied directly as root-dir.
|
|
205
|
+
if args.root_dir and Path(args.root_dir).expanduser().resolve().name == OUTPUT_DIRNAME and not args.output_dir:
|
|
206
|
+
args.output_dir = args.root_dir
|
|
207
|
+
|
|
167
208
|
table = _gene_table(args.root_dir, args.output_dir, args.gene_table)
|
|
168
209
|
count = query_function(table, args.function_id, args.output, args.category, args.rank, args.top)
|
|
169
210
|
print(f"Wrote {count} contributing taxon rows to {args.output}")
|
|
170
211
|
return 0
|
|
212
|
+
|
|
171
213
|
if args.command == "query-taxon":
|
|
214
|
+
if args.root_dir is None and args.gene_table is None and args.output_dir is None:
|
|
215
|
+
raise ValueError("Provide --root-dir, --output-dir or --gene-table.")
|
|
216
|
+
|
|
217
|
+
# A MetaPont_Results directory can be supplied directly as root-dir.
|
|
218
|
+
if args.root_dir and Path(args.root_dir).expanduser().resolve().name == OUTPUT_DIRNAME and not args.output_dir:
|
|
219
|
+
args.output_dir = args.root_dir
|
|
220
|
+
|
|
172
221
|
table = _gene_table(args.root_dir, args.output_dir, args.gene_table)
|
|
173
222
|
count = query_taxon(table, args.taxon, args.output, args.category, args.top, args.rank)
|
|
223
|
+
|
|
174
224
|
print(f"Wrote {count} taxon-associated function rows to {args.output}")
|
|
175
225
|
return 0
|
|
226
|
+
if args.command in {"taxon-function-abundance", "taxon-function"}:
|
|
227
|
+
if args.gene_table is None and args.root_dir is None and args.output_dir is None:
|
|
228
|
+
raise ValueError("Provide --gene-table, --root-dir or --output-dir.")
|
|
229
|
+
table = _gene_table(args.root_dir, args.output_dir, args.gene_table)
|
|
230
|
+
if args.output:
|
|
231
|
+
output = Path(args.output).expanduser().resolve()
|
|
232
|
+
elif args.output_dir or args.root_dir:
|
|
233
|
+
output = _output_root(args.root_dir, args.output_dir) / "functional" / "taxon_function_abundance.tsv"
|
|
234
|
+
else:
|
|
235
|
+
output = table.parent.parent / "functional" / "taxon_function_abundance.tsv"
|
|
236
|
+
count = build_taxon_function_abundance(table, output)
|
|
237
|
+
print(f"Wrote {count} taxon/function rows to {output}")
|
|
238
|
+
return 0
|
|
176
239
|
except (FileNotFoundError, RuntimeError, ValueError, OSError) as error:
|
|
177
240
|
print(f"ERROR: {error}", file=sys.stderr)
|
|
178
241
|
return 2
|
|
@@ -186,7 +186,7 @@ def function_by_taxa_main() -> int:
|
|
|
186
186
|
root = args.root_dir or args.directory
|
|
187
187
|
if not root:
|
|
188
188
|
parser.error("provide the sample root as a positional argument or with -d")
|
|
189
|
-
result = run_analysis(root, args.prefix, args.output_dir, heal_flags=True, force=False)
|
|
189
|
+
result = run_analysis(root, args.prefix, args.output_dir, heal_flags=True, force=False, include_taxon_function_abundance=True)
|
|
190
190
|
print(f"Function-by-taxon results written to {result['output_dir']}/functional/taxon_function_abundance.tsv")
|
|
191
191
|
return 0
|
|
192
192
|
|