aberrant-expression 0.1.0__py3-none-any.whl

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.
Files changed (54) hide show
  1. aberrant_expression-0.1.0.dist-info/METADATA +451 -0
  2. aberrant_expression-0.1.0.dist-info/RECORD +54 -0
  3. aberrant_expression-0.1.0.dist-info/WHEEL +5 -0
  4. aberrant_expression-0.1.0.dist-info/licenses/LICENSE +48 -0
  5. aberrant_expression-0.1.0.dist-info/top_level.txt +1 -0
  6. abexp/__init__.py +12 -0
  7. abexp/absplice/__init__.py +21 -0
  8. abexp/absplice/dataloader.py +153 -0
  9. abexp/absplice/model.py +75 -0
  10. abexp/absplice/precomputed/AbSplice_DNA.onnx +0 -0
  11. abexp/absplice/precomputed/GENE_MAP.tsv.gz +0 -0
  12. abexp/absplice/result.py +307 -0
  13. abexp/absplice/splicemap.py +105 -0
  14. abexp/absplice/utils.py +76 -0
  15. abexp/absplice2/__init__.py +17 -0
  16. abexp/absplice2/dna.py +273 -0
  17. abexp/enformer/__init__.py +0 -0
  18. abexp/enformer/constants.py +6 -0
  19. abexp/enformer/dataloader/__init__.py +1 -0
  20. abexp/enformer/dataloader/dataloader.py +214 -0
  21. abexp/enformer/dataloader/tss_dataloader.py +266 -0
  22. abexp/enformer/enformer.py +551 -0
  23. abexp/enformer/logger.py +13 -0
  24. abexp/enformer/utils.py +78 -0
  25. abexp/mmsplice/__init__.py +21 -0
  26. abexp/mmsplice/batching.py +51 -0
  27. abexp/mmsplice/dataloader.py +432 -0
  28. abexp/mmsplice/layers.py +107 -0
  29. abexp/mmsplice/model.py +104 -0
  30. abexp/mmsplice/models/Acceptor.h5 +0 -0
  31. abexp/mmsplice/models/Donor.h5 +0 -0
  32. abexp/mmsplice/models/Exon.h5 +0 -0
  33. abexp/mmsplice/models/Intron3.h5 +0 -0
  34. abexp/mmsplice/models/Intron5.h5 +0 -0
  35. abexp/mmsplice/utils.py +140 -0
  36. abexp/pangolin/__init__.py +23 -0
  37. abexp/pangolin/annotation.py +42 -0
  38. abexp/pangolin/model.py +165 -0
  39. abexp/pangolin/pangolin.py +262 -0
  40. abexp/pangolin/weights.py +95 -0
  41. abexp/spliceai_rocksdb/__init__.py +11 -0
  42. abexp/spliceai_rocksdb/spliceai.py +194 -0
  43. abexp/utils/__init__.py +0 -0
  44. abexp/utils/common.py +16 -0
  45. abexp/utils/gff3.py +51 -0
  46. abexp/utils/models/__init__.py +1 -0
  47. abexp/utils/models/wrappers.py +104 -0
  48. abexp/utils/polars_functions/__init__.py +13 -0
  49. abexp/utils/polars_functions/featureset.py +188 -0
  50. abexp/utils/polars_functions/reshape.py +116 -0
  51. abexp/utils/polars_functions/write.py +10 -0
  52. abexp/utils/spark_functions/__init__.py +14 -0
  53. abexp/utils/spark_functions/featureset.py +178 -0
  54. abexp/utils/spark_functions/reshape.py +248 -0
@@ -0,0 +1,451 @@
1
+ Metadata-Version: 2.4
2
+ Name: aberrant-expression
3
+ Version: 0.1.0
4
+ Summary: Utilities, Enformer, MMSplice, AbSplice-DNA, SpliceAI-RocksDB, Pangolin and AbSplice2-DNA for the AbExp pipeline
5
+ Author: Jun Cheng, Muhammed Hasan Çelik, Nils Wagner
6
+ Author-email: Florian Hölzlwimmer <git.ich@frhoelzlwimmer.de>, George Tsitsiridis <gtsitsiridis@gmail.com>
7
+ Maintainer-email: Florian Hölzlwimmer <git.ich@frhoelzlwimmer.de>
8
+ License-Expression: MIT
9
+ Project-URL: Homepage, https://github.com/gagneurlab/AbExp
10
+ Project-URL: Source, https://github.com/gagneurlab/AbExp/tree/main/packages/aberrant_expression
11
+ Project-URL: Issues, https://github.com/gagneurlab/AbExp/issues
12
+ Keywords: aberrant expression,variant effect prediction,splicing,mmsplice,absplice,spliceai,pangolin,enformer,deep learning,computational biology,bioinformatics,genomics
13
+ Requires-Python: >=3.12
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Provides-Extra: models
17
+ Requires-Dist: aberrant-expression[numpy]; extra == "models"
18
+ Requires-Dist: scikit-learn>=1.4.1.post1; extra == "models"
19
+ Provides-Extra: polars
20
+ Requires-Dist: polars>=1.44; extra == "polars"
21
+ Provides-Extra: spark
22
+ Requires-Dist: pyspark>=3.4; extra == "spark"
23
+ Requires-Dist: pandas; extra == "spark"
24
+ Provides-Extra: gff3
25
+ Requires-Dist: aberrant-expression[polars]; extra == "gff3"
26
+ Requires-Dist: polars-bio>=0.36.0; extra == "gff3"
27
+ Provides-Extra: splicing
28
+ Requires-Dist: aberrant-expression[kipoiseq2,numpy,polars,tensorflow,tqdm]; extra == "splicing"
29
+ Requires-Dist: onnxruntime; extra == "splicing"
30
+ Provides-Extra: rocksdb
31
+ Requires-Dist: aberrant-expression[splicing]; extra == "rocksdb"
32
+ Requires-Dist: python-rocksdb>=0.7; extra == "rocksdb"
33
+ Provides-Extra: enformer
34
+ Requires-Dist: aberrant-expression[gff3,kipoiseq2,models,tensorflow,tqdm]; extra == "enformer"
35
+ Requires-Dist: kagglehub; extra == "enformer"
36
+ Requires-Dist: pyarrow; extra == "enformer"
37
+ Requires-Dist: xarray>=2024.5.0; extra == "enformer"
38
+ Requires-Dist: zarr>=2.15.0; extra == "enformer"
39
+ Requires-Dist: pyyaml; extra == "enformer"
40
+ Provides-Extra: pangolin
41
+ Requires-Dist: aberrant-expression[gff3,kipoiseq2,numpy]; extra == "pangolin"
42
+ Requires-Dist: torch>=2.4; extra == "pangolin"
43
+ Provides-Extra: absplice2
44
+ Requires-Dist: aberrant-expression[polars]; extra == "absplice2"
45
+ Provides-Extra: all
46
+ Requires-Dist: aberrant-expression[absplice2,enformer,gff3,models,pangolin,polars,spark,splicing]; extra == "all"
47
+ Provides-Extra: numpy
48
+ Requires-Dist: numpy>=1.26.4; extra == "numpy"
49
+ Provides-Extra: kipoiseq2
50
+ Requires-Dist: kipoiseq2[ranges]<0.2,>=0.1; extra == "kipoiseq2"
51
+ Provides-Extra: tensorflow
52
+ Requires-Dist: tensorflow>=2.14.0; extra == "tensorflow"
53
+ Provides-Extra: tqdm
54
+ Requires-Dist: tqdm; extra == "tqdm"
55
+ Dynamic: license-file
56
+
57
+ # aberrant-expression
58
+
59
+ tl;dr: The Python packages of the [AbExp](https://github.com/gagneurlab/AbExp) pipeline, in one distribution. pip
60
+ installs it as `aberrant-expression`, and Python imports it as `abexp`. The base has no dependencies and covers
61
+ `abexp.utils.common`; each extra adds the dependencies of other subpackages.
62
+
63
+ | import | contents | extra |
64
+ | ------------------------ | ----------------------------------------------------------------------------------------- | ---------- |
65
+ | `abexp.utils` | functions on polars and Spark DataFrames, a GFF3 reader, and the scikit-learn model wrappers of AbExp | `polars`, `spark`, `gff3`, `models` |
66
+ | `abexp.enformer` | variant effect prediction of promoter variants with Enformer | `enformer` |
67
+ | `abexp.mmsplice` | MMSplice and the junction VCF dataloaders | `splicing` |
68
+ | `abexp.absplice` | AbSplice-DNA from MMSplice with SpliceMaps and from SpliceAI | `splicing` |
69
+ | `abexp.spliceai_rocksdb` | SpliceAI scores from SpliceAI-RocksDB | `rocksdb` |
70
+ | `abexp.pangolin` | Pangolin's splice scores per variant and gene, with the published weights of Pangolin | `pangolin` |
71
+ | `abexp.absplice2` | AbSplice2-DNA from Pangolin and from MMSplice with SpliceMaps | `absplice2` |
72
+
73
+ `abexp.utils` and `abexp.enformer` were the distributions abexp-utils (`abexp_utils`) and kipoi-enformer
74
+ (`kipoi_enformer`). `abexp.mmsplice`, `abexp.absplice` and `abexp.spliceai_rocksdb` were the distribution
75
+ abexp-splicing. The modules keep their paths below the new top level, e.g. `kipoi_enformer.enformer` is now
76
+ `abexp.enformer.enformer`.
77
+
78
+ The name `abexp` on PyPI belongs to an unrelated library, which also installs into `site-packages/abexp`. So the two
79
+ cannot share an environment.
80
+
81
+ ## Installation
82
+
83
+ Install a release from the AbExp repository with pip. Choose the extras you need:
84
+
85
+ <!-- x-release-please-start-version -->
86
+ ```bash
87
+ pip install "aberrant-expression[polars] @ git+https://github.com/gagneurlab/AbExp.git@aberrant-expression-v0.1.0#subdirectory=packages/aberrant_expression"
88
+ ```
89
+ <!-- x-release-please-end -->
90
+
91
+ | extra | for |
92
+ | ---------- | ------------------------------------------------------------------------- |
93
+ | `models` | `abexp.utils.models` |
94
+ | `polars` | `abexp.utils.polars_functions` |
95
+ | `spark` | `abexp.utils.spark_functions`. The Spark functions need a Java runtime; pyspark 4 requires Java 17 or newer. |
96
+ | `gff3` | `abexp.utils.gff3` |
97
+ | `splicing` | `abexp.mmsplice` and `abexp.absplice` |
98
+ | `rocksdb` | `abexp.spliceai_rocksdb`, with `splicing` |
99
+ | `pangolin` | `abexp.pangolin`. conda-forge has PyTorch as `pytorch-cpu` and `pytorch-gpu`. |
100
+ | `absplice2` | `abexp.absplice2` |
101
+ | `enformer` | `abexp.enformer`. For GPU support on Linux, also install `tensorflow[and-cuda]`. |
102
+ | `all` | all extras but `rocksdb` |
103
+ | `numpy`, `kipoiseq2`, `tensorflow`, `tqdm` | one requirement each, which several extras share |
104
+
105
+ The extra `rocksdb` installs python-rocksdb, which pip builds only with the RocksDB library installed; conda-forge
106
+ has a build of it. SpliceAI predictions of the variants that are not in SpliceAI-RocksDB also need SpliceAI.
107
+ Install it separately. The AbExp pipeline uses the SpliceAI fork [hoeze/SpliceAI](https://github.com/hoeze/SpliceAI),
108
+ which also predicts multi-nucleotide variants:
109
+
110
+ ```bash
111
+ pip install "spliceai @ git+https://github.com/hoeze/SpliceAI.git@e3470ae185d1418fe40cf35e8c4e33431cbc5df2"
112
+ ```
113
+
114
+ For development, use the uv workspace of a checkout of AbExp. In the root of the checkout, this installs the
115
+ package in editable mode, with all extras but `rocksdb` and with the dependency group `test` for the tests:
116
+
117
+ ```bash
118
+ uv sync --extra all --group test
119
+ ```
120
+
121
+ Add `--extra rocksdb` if you work on `abexp.spliceai_rocksdb`.
122
+ [packages/README.md](https://github.com/gagneurlab/AbExp/blob/main/packages/README.md) in the AbExp repository
123
+ describes the workspace and the tests.
124
+
125
+ ## abexp.utils
126
+
127
+ `abexp.utils.polars_functions` and `abexp.utils.spark_functions` reshape polars and Spark DataFrames and join the
128
+ feature sets of AbExp. `abexp.utils.models` holds the scikit-learn model wrappers of the AbExp models, and needs the
129
+ extra `models`. `abexp.utils.gff3` reads GFF3 files with polars-bio for `abexp.enformer` and `abexp.pangolin`, and
130
+ needs the extra `gff3`. With `par_y_suffix=True`, it adds the suffix `_PAR_Y` to `gene_id` and `transcript_id` of the
131
+ chrY PAR copies, as `abexp.enformer` does.
132
+
133
+ ## abexp.enformer
134
+
135
+ ### Enformer model
136
+
137
+ `Enformer()` loads the Enformer model from Kaggle Models with kagglehub, under the handle
138
+ `deepmind/enformer/tensorFlow2/enformer/1`. These are the same files that TF Hub served at
139
+ `https://tfhub.dev/deepmind/enformer/1`. On first use, kagglehub downloads the model, about 1 GB, and caches it in
140
+ `~/.cache/kagglehub`. Set `KAGGLEHUB_CACHE` to use another directory. Once the model is cached, kagglehub loads it
141
+ without contacting Kaggle. kipoi-enformer 0.0.1 downloaded the model with tensorflow-hub instead and cached it in
142
+ `TFHUB_CACHE_DIR`.
143
+
144
+ ### Genome annotation
145
+
146
+ The dataloaders and `EnformerVeff` take the genome annotation as `genome_annotation`: the path to a GFF3 file, such
147
+ as a GENCODE annotation, or a polars or pandas DataFrame with pyranges-style columns, see
148
+ `abexp.enformer.utils.genome_annotation_to_polars`. kipoi-enformer 0.0.1 read a GTF file instead, and the parameter
149
+ was `gtf`.
150
+
151
+ ### Tissue mapper
152
+
153
+ `EnformerTissueMapper` maps the Enformer CAGE tracks to an expression score per GTEx tissue, with one linear model per
154
+ tissue. `train` fits a scikit-learn pipeline of a `StandardScaler` and a linear model for each tissue. The model must
155
+ be linear, e.g. from `sklearn.linear_model`; other models raise a `TypeError`. `train` writes the parameters of the
156
+ pipelines to a parquet file with one row per tissue: `tissue`, the `mean` and `scale` of the `StandardScaler`, and
157
+ the `coef` and `intercept` of the linear model. The features are the tracks in the order of the tracks yaml file.
158
+ `predict` computes the scores from this file with numpy and gives the same scores as the pipelines with scikit-learn
159
+ 1.5 to 1.7.
160
+
161
+ ### Usage
162
+
163
+ The example reads the chr22 sequence and genome annotation in `example/` of the AbExp repository and the test
164
+ data of this package. Run it in the root of a checkout of AbExp, after you have fetched the test data, see
165
+ [Tests](#tests).
166
+
167
+ ```python
168
+ from abexp.enformer.dataloader import RefTSSDataloader, VCFTSSDataloader
169
+ from abexp.enformer.enformer import Enformer, EnformerAggregator, EnformerTissueMapper, EnformerVeff
170
+ from pathlib import Path
171
+ from sklearn import linear_model
172
+
173
+ fasta_file = 'example/chr22_hg19.fa'
174
+ genome_annotation = 'example/chr22.gencode.v40lift37.annotation.gff3.gz'
175
+ data_dir = Path('packages/aberrant_expression/tests/enformer/data')
176
+
177
+ # define output dirs
178
+ output_dir = Path('output')
179
+ (output_dir / 'raw/ref.parquet/chrom=chr22').mkdir(exist_ok=True, parents=True)
180
+ (output_dir / 'raw/alt.parquet').mkdir(exist_ok=True, parents=True)
181
+ (output_dir / 'aggregated/ref.parquet/chrom=chr22').mkdir(exist_ok=True, parents=True)
182
+ (output_dir / 'aggregated/alt.parquet').mkdir(exist_ok=True, parents=True)
183
+ (output_dir / 'tissue/ref.parquet/chrom=chr22').mkdir(exist_ok=True, parents=True)
184
+ (output_dir / 'tissue/alt.parquet').mkdir(exist_ok=True, parents=True)
185
+
186
+ # define enformer objects
187
+ enformer = Enformer()
188
+ enformer_aggregator = EnformerAggregator()
189
+ enformer_tissue_mapper = EnformerTissueMapper(
190
+ tracks_path=data_dir / 'human_cage_nonuniversal_enformer_tracks.yaml')
191
+ enformer_veff = EnformerVeff(genome_annotation=genome_annotation)
192
+
193
+ # Reference sequences
194
+ # define reference dataloader
195
+ ref_dl = RefTSSDataloader(fasta_file=fasta_file, genome_annotation=genome_annotation, chromosome='chr22',
196
+ canonical_only=False, protein_coding_only=True)
197
+ # run enformer on reference genome
198
+ enformer.predict(ref_dl, batch_size=2, filepath=output_dir / 'raw/ref.parquet/chrom=chr22/data.parquet',
199
+ num_output_bins=11)
200
+ # aggregate reference enformer scores
201
+ enformer_aggregator.aggregate(output_dir / 'raw/ref.parquet/chrom=chr22/data.parquet',
202
+ output_dir / 'aggregated/ref.parquet/chrom=chr22/data.parquet')
203
+ # train tissue mapper using reference genome
204
+ enformer_tissue_mapper.train([output_dir / 'aggregated/ref.parquet/chrom=chr22/data.parquet'],
205
+ output_path=output_dir / 'tissue_mapper.parquet',
206
+ expression_path=data_dir / 'transcripts_tpms.zarr',
207
+ model=linear_model.ElasticNetCV(cv=2))
208
+ # map reference to tissues
209
+ enformer_tissue_mapper.predict(output_dir / 'aggregated/ref.parquet/chrom=chr22/data.parquet',
210
+ output_dir / 'tissue/ref.parquet/chrom=chr22/data.parquet')
211
+
212
+ # Alternative sequences
213
+ # define alternative dataloader
214
+ alt_dl = VCFTSSDataloader(fasta_file=fasta_file, genome_annotation=genome_annotation,
215
+ vcf_file=data_dir / 'chr22_var.vcf.gz', variant_upstream_tss=50,
216
+ variant_downstream_tss=200, canonical_only=False, protein_coding_only=True)
217
+ # run enformer on alternative genome
218
+ enformer.predict(alt_dl, batch_size=2, filepath=output_dir / 'raw/alt.parquet/chr22_var.vcf.gz.parquet',
219
+ num_output_bins=11)
220
+ # aggregate alternative enformer scores
221
+ enformer_aggregator.aggregate(output_dir / 'raw/alt.parquet/chr22_var.vcf.gz.parquet',
222
+ output_dir / 'aggregated/alt.parquet/chr22_var.vcf.gz.parquet')
223
+ # map alternative to tissues
224
+ enformer_tissue_mapper.predict(output_dir / 'aggregated/alt.parquet/chr22_var.vcf.gz.parquet',
225
+ output_dir / 'tissue/alt.parquet/chr22_var.vcf.gz.parquet')
226
+
227
+ # Variant effect prediction
228
+ enformer_veff.run(ref_paths=[output_dir / 'tissue/ref.parquet/chrom=chr22/data.parquet'],
229
+ alt_path=output_dir / 'tissue/alt.parquet/chr22_var.vcf.gz.parquet',
230
+ output_path=output_dir / 'veff.parquet', aggregation_mode='canonical')
231
+ ```
232
+
233
+ ### Known issues
234
+
235
+ `EnformerAggregator` averages the bins around the TSS bin of each shift. As the TSS, it takes the middle of the bins
236
+ that `Enformer.predict` saved. That is right for an even `num_output_bins`, such as all 896. With 21 output bins, the
237
+ workflow default, Enformer saves the bins 438 to 458. Their middle lies 64 bp downstream of the TSS. So shift +43
238
+ averages the bins 447 to 449, although the TSS lies in bin 447. With 896 output bins, it averages 446 to 448. Shifts
239
+ 0 and -43 average 447 to 449 in both cases.
240
+
241
+ The training pipeline [gtsitsiridis/kipoi_veff_analysis](https://github.com/gtsitsiridis/kipoi_veff_analysis)
242
+ trained the published tissue mapper (`elasticnet_cage_gtexv8`) on 21 output bins, so the tissue mapper learned this
243
+ behavior. The reference scores that the workflow downloads come from the same pipeline. So the code keeps the
244
+ behavior. A fix would replace `pred_seq_length // 2` with `pred.shape[2] // 2 * bin_size` in
245
+ `EnformerAggregator._aggregate_batch`. It needs a retrained tissue mapper and recomputed reference scores. The offset
246
+ came in with the crop to 21 output bins, in commit e2bbf5ec (2024-05-16) of the training pipeline.
247
+
248
+ ## abexp.mmsplice, abexp.absplice and abexp.spliceai_rocksdb
249
+
250
+ The parts of MMSplice, AbSplice and SpliceAI-RocksDB that the AbExp pipeline runs, on kipoiseq2. kipoi, kipoiseq 0.7,
251
+ cyvcf2 and pyranges are no longer needed. The outputs match the upstream packages, except for the row order,
252
+ rounding in the last digits and the choice among tied junctions, see
253
+ [Differences](#differences-from-the-upstream-packages).
254
+
255
+ | import | ported from | what AbExp uses |
256
+ | ------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
257
+ | `abexp.mmsplice` | [mmsplice](https://github.com/gagneurlab/MMSplice_MTSplice) 2.4.0 (31513da) | `MMSplice` and the junction VCF dataloaders |
258
+ | `abexp.absplice` | [absplice](https://github.com/gagneurlab/absplice) daad7b6, [splicemap](https://github.com/gagneurlab/splicemap) cf922eb | `SpliceOutlierDataloader`, `SpliceOutlier`, `SplicingOutlierResult`, `read_spliceai_vcf` |
259
+ | `abexp.spliceai_rocksdb` | [spliceai_rocksdb](https://github.com/gagneurlab/spliceai_rocksdb) 3c40d6e | `SpliceAI` |
260
+
261
+ ### Usage
262
+
263
+ The example runs AbSplice-DNA on the test data of this package. Run it in the root of a checkout of AbExp.
264
+
265
+ ```python
266
+ import polars as pl
267
+ from abexp.absplice import SpliceOutlier, SpliceOutlierDataloader, SplicingOutlierResult
268
+
269
+ data_dir = 'packages/aberrant_expression/tests/splicing/data'
270
+
271
+ # MMSplice with SpliceMaps: delta PSI per variant, junction and tissue
272
+ dl = SpliceOutlierDataloader(
273
+ 'example/chr22_hg38.fa', f'{data_dir}/clinvar_chr22.vcf',
274
+ splicemap5=[f'{data_dir}/Whole_Blood_splicemap_psi5.csv.gz'],
275
+ splicemap3=[f'{data_dir}/Whole_Blood_splicemap_psi3.csv.gz'],
276
+ )
277
+ SpliceOutlier().predict_save(dl, 'mmsplice_splicemap.csv')
278
+
279
+ # AbSplice-DNA per variant, gene and tissue, from MMSplice and SpliceAI
280
+ result = SplicingOutlierResult(
281
+ df_mmsplice=pl.read_csv('mmsplice_splicemap.csv'),
282
+ df_spliceai=pl.read_csv(f'{data_dir}/expected/spliceai_vcf.csv'),
283
+ )
284
+ df = result.predict_absplice_dna()
285
+ ```
286
+
287
+ `abexp.spliceai_rocksdb.SpliceAI(fasta, annotation='grch38', db_path={'22': <path>}).predict_save(vcf, csv)`
288
+ looks up the SpliceAI scores in SpliceAI-RocksDB and runs SpliceAI for the variants that are not in it.
289
+ `abexp.absplice.read_spliceai_vcf` reads a VCF file that the SpliceAI command line tool annotated.
290
+
291
+ ### Differences from the upstream packages
292
+
293
+ - kipoiseq2 yields the variant-junction pairs in the order of the VCF file, and kipoiseq 0.7 in the order of
294
+ pyranges. So the rows of the MMSplice table come in another order.
295
+ - MMSplice therefore predicts batches with other samples. TensorFlow rounds them differently, so `delta_logit_psi`
296
+ can differ in the last digits.
297
+ - A variant can have the same delta PSI at several junctions of a gene. absplice daad7b6 picked any one of them,
298
+ and the row order and the numpy version decided which one. abexp.absplice picks the first in the order of
299
+ junction, event_type, splice_site and the other columns. So the reported junction can differ from absplice, and
300
+ with its `median_n` also `splice_site_is_expressed` and `AbSplice_DNA`.
301
+ - `read_spliceai_vcf` names the column `acceptor_loss_position`, not `acceptor_loss_positiin`.
302
+ - `read_spliceai_vcf` gives each ALT allele only the SpliceAI entries of that allele. absplice gave it the entries
303
+ of all ALT alleles of its record. The workflow splits multi-allelic records before SpliceAI, so its tables do
304
+ not change.
305
+ - abexp.mmsplice, abexp.absplice and abexp.spliceai_rocksdb use polars and numpy instead of pandas. The tables in
306
+ and out are polars DataFrames. `predict_absplice_dna` returns variant, gene_id and tissue as columns, sorted by
307
+ them, and not as an index.
308
+ - The CSV files of `predict_save` format floats as polars does, e.g. `6.4e-6` instead of `6.4e-06`. The values do
309
+ not change.
310
+ - A VCF file without variants yields no samples. mmsplice compared the contigs of the VCF header with the FASTA
311
+ file, and abexp.mmsplice compares the chromosomes of the variants.
312
+ - If no variant lies on a chromosome of the junctions, e.g. in a VCF file with only chrM variants, abexp.mmsplice
313
+ logs a warning and yields no samples. mmsplice raised a ValueError if no contig of the VCF header had junctions.
314
+ - Only the parts that AbExp uses are kept. Not included: MTSplice, the VEP plugin, the dataloaders of GTF exons
315
+ and exon tables, the VCF writers, the variant filters of absplice, AbSplice-RNA, the CADD-Splice and
316
+ sample-based features, and the SpliceMap count tables. `predict_absplice_dna` reads only ONNX models.
317
+
318
+ ## abexp.pangolin
319
+
320
+ Pangolin's splice scores of variants (Zeng and Li, Genome Biology 2022, [Pangolin](https://github.com/tkzeng/Pangolin)),
321
+ on kipoiseq2 and PyTorch. Per variant and gene, it gives the largest gain and loss of splice site usage within
322
+ `distance` bases, like `pangolin -d 50 -m True`. The network and the data path are our own code; only the weights
323
+ come from Pangolin. The network uses unpadded convolutions, which give the same outputs with about a third less
324
+ computation, and it scores ref and alt sequences of equal length in batches.
325
+
326
+ The weights are not part of this package. They are GPL-3, as the Pangolin repository. `download_models` downloads
327
+ the 12 files of `abexp.pangolin.MODEL_FILES` (35 MB) from `pangolin/models` of the Pangolin repository at the
328
+ pinned commit `PANGOLIN_COMMIT` (5cf94b8), and checks their SHA-256 sums. It keeps the files that exist with the right
329
+ sum. `download_model(file, models_dir)` does the same for one file. `PangolinModels.from_dir` checks the SHA-256
330
+ sums too, and stops with a ValueError on files of another commit.
331
+
332
+ ```python
333
+ from abexp.pangolin import Pangolin, PangolinModels, download_models, read_gff3_genes
334
+
335
+ download_models('pangolin_models')
336
+ genes = read_gff3_genes('gencode.v42.annotation.gff3.gz', transcript_tags=['Ensembl_canonical'])
337
+ pangolin = Pangolin('genome.fa', genes, PangolinModels.from_dir('pangolin_models'), distance=50, mask=True)
338
+ pangolin.predict_df('variants.vcf').write_parquet('pangolin.parquet')
339
+ ```
340
+
341
+ ### Differences from upstream Pangolin
342
+
343
+ The scores match Pangolin (fork neverov-am/Pangolin 232cba0) up to the last float32 digits, except here:
344
+
345
+ - Every ALT allele of a record is scored. Pangolin scores only the first one.
346
+ - A gene counts if the ref allele overlaps it. Pangolin misses a gene that starts at the variant position, and a gene
347
+ that a deletion reaches only after its first base.
348
+ - Beyond the chromosome ends, the sequence is N. Pangolin skips variants within 5050 bases of the chromosome start,
349
+ and stops with an error for most variants within 5050 bases of its end.
350
+ - The ref check ignores the case of the FASTA file, and the sequence is upper case. Pangolin skips a variant whose
351
+ FASTA ref is in lower case.
352
+ - Variants with letters other than A, C, G, T and N in ref or alt are skipped. Pangolin stops with an error on them.
353
+ kipoiseq2 drops ALT alleles with N; Pangolin scores them with N as 0.
354
+ - The output is a polars DataFrame with unrounded float32 scores, not a VCF file with scores rounded to 2 decimals.
355
+ - The genes and splice sites come from a GENCODE GFF3 file, not from a gffutils database. An exon belongs to the
356
+ gene with its `gene_id` on its chromosome.
357
+ - With `mask`, each gene is masked on its own, as in the fork. tkzeng/Pangolin 5cf94b8 masks the loss and gain
358
+ arrays of a strand in place. So there, each gene starts from the arrays that the genes before it on the same
359
+ strand have masked (`pangolin/pangolin.py`, lines 133 to 153). The fork copies the arrays for each gene (lines 144
360
+ and 145 of 232cba0).
361
+
362
+ ## abexp.absplice2
363
+
364
+ AbSplice2-DNA per variant, gene and GTEx tissue, from Pangolin, MMSplice with SpliceMaps, and the SpliceMaps. The
365
+ code is our own, in polars, for the steps of the [AbSplice2](https://github.com/gagneurlab/absplice2) example
366
+ workflow after MMSplice and Pangolin, at commit a30120f. `absplice2_dna` matches Pangolin's gain and loss sites
367
+ with the SpliceMap sites within 2 bp, joins them with MMSplice, scores each row with the model, and keeps the row
368
+ with the largest score per variant, gene and tissue.
369
+
370
+ The AbSplice2 model is not part of this package. It is an ExplainableBoostingClassifier of interpret 0.2.7, which
371
+ the caller loads and passes as a function:
372
+
373
+ ```python
374
+ import pickle
375
+
376
+ import polars as pl
377
+ from abexp.absplice2 import absplice2_dna, read_mmsplice_splicemap
378
+
379
+ with open('AbSplice_2_DNA.pkl', 'rb') as fd:
380
+ model = pickle.load(fd)
381
+ df = absplice2_dna(
382
+ pangolin=pl.read_parquet('pangolin.parquet'), # the output of abexp.pangolin
383
+ splicemap5=['Whole_Blood_splicemap_psi5.csv.gz'],
384
+ splicemap3=['Whole_Blood_splicemap_psi3.csv.gz'],
385
+ mmsplice_splicemap=read_mmsplice_splicemap('mmsplice_splicemap.csv'),
386
+ predict=lambda features: model.predict_proba(features.to_pandas())[:, 1],
387
+ )
388
+ ```
389
+
390
+ The output matches the AbSplice2 scripts, except here:
391
+
392
+ - The variant is split into `chrom`, `start` (0-based), `end`, `ref` and `alt`, and `gene_id` is named `gene`.
393
+ - Pangolin's scores are rounded to 2 decimals in float64, Pangolin rounds them in float32. The two differ by 0.01
394
+ only for scores within float32 precision of a rounding boundary.
395
+ - Of the rows with the same largest score, AbSplice2 keeps any one. `absplice2_dna` keeps the first in the order
396
+ of the output columns, so its MMSplice columns can differ from AbSplice2.
397
+
398
+ ## Tests
399
+
400
+ The tests are in one directory per area, and each area needs the extras of its subpackages:
401
+
402
+ | directory | extras | reads |
403
+ | ---------------- | ----------------- | --------------------------------------------------------------------------------------- |
404
+ | `tests/utils` | `polars`, `spark`, `gff3` | nothing; the Spark tests need a Java runtime |
405
+ | `tests/enformer` | `enformer` | the files in `tests/enformer/data/` and the hg19 chr22 sequence `example/chr22_hg19.fa` |
406
+ | `tests/splicing` | `splicing` | the files in `tests/splicing/data/` and the hg38 chr22 sequence `example/chr22_hg38.fa` |
407
+ | `tests/pangolin` | `pangolin` | the files in `tests/pangolin/data/` and the published weights of Pangolin (35 MB) |
408
+ | `tests/absplice2` | `absplice2` | nothing |
409
+
410
+ The example sequences are in the AbExp repository, outside of the package. Pytest skips a test if one of its files
411
+ is missing, e.g. in an sdist.
412
+
413
+ git-lfs stores the files in `tests/enformer/data/`. `.lfsconfig` excludes them from the default fetch, so that pip
414
+ installs from a git URL do not download them. With git-lfs installed, fetch them in a checkout of AbExp and run the
415
+ tests:
416
+
417
+ ```bash
418
+ git lfs pull --include="packages/aberrant_expression/tests/enformer/data/**" --exclude=""
419
+ cd packages/aberrant_expression
420
+ pytest tests/utils
421
+ pytest tests/enformer
422
+ pytest tests/splicing
423
+ pytest tests/pangolin
424
+ pytest tests/absplice2
425
+ ```
426
+
427
+ The tests run across all cores by default, through pytest-xdist. Pass `-n0` to run them in one process, which a
428
+ debugger needs and which restores per-test output order. The tests of one xdist group run on one worker, one after
429
+ the other: the Spark tests, and the tests that run Enformer, which share their outputs. With `-n0`, the enformer
430
+ tests need about 3 GB of memory.
431
+
432
+ The pangolin tests run small networks with fixed random weights on a synthetic genome, and the published weights of
433
+ Pangolin on an excerpt of GRCh38 chr22 in `tests/pangolin/data/`. They download the published weights once into the
434
+ pytest cache, or into the folder in `ABEXP_PANGOLIN_MODELS_DIR` if set. Without network access, the download fails,
435
+ and so do the tests with the published weights. Their expected rows come from upstream Pangolin, see
436
+ `tests/pangolin/make_expected.py` and `tests/pangolin/make_expected_published.py`.
437
+
438
+ The absplice2 tests run `absplice2_dna` with a stand-in for the AbSplice2 model on the made-up inputs of
439
+ `tests/absplice2/constellations.py`, one constellation per test. Their expected rows come from the AbSplice2 scripts
440
+ with the same stand-in, see `tests/absplice2/make_expected.py`.
441
+
442
+ The expected outputs in `tests/splicing/data/expected/` come from the upstream packages, see
443
+ `tests/splicing/make_expected.py`. The SpliceAI-RocksDB tests also need the extra `rocksdb` and the hg38 chr22
444
+ database (2.6 GB). Set `ABEXP_SPLICEAI_ROCKSDB_HG38_CHR22` to the path of `spliceAI_hg38_chr22.db`, otherwise pytest
445
+ skips them. The test of the SpliceAI predictions also needs SpliceAI.
446
+
447
+ ## License
448
+
449
+ The code is under the MIT license, see [LICENSE](LICENSE). It lists the copyright notices of the upstream
450
+ projects of `abexp.mmsplice`, `abexp.absplice` and `abexp.spliceai_rocksdb`. `abexp.pangolin` loads the weights of Pangolin, which are
451
+ GPL-3 and not part of the package, see [abexp.pangolin](#abexppangolin).
@@ -0,0 +1,54 @@
1
+ aberrant_expression-0.1.0.dist-info/licenses/LICENSE,sha256=XmvHaJv1laxadywUzvJ8Ps2KPqq1kRGLkpXeUCbauSY,2289
2
+ abexp/__init__.py,sha256=cn7rm5EgKcB9Rgt_p0lfBtxg_Ak5W_-FaiJx3OJA4wo,420
3
+ abexp/absplice/__init__.py,sha256=lFozxEs0nGqGP_1Ebpp0U0AFECjmrU86q2N1GKRamEI,835
4
+ abexp/absplice/dataloader.py,sha256=TNkd_V3qJvxKLAs5hoU8B0dT5EhnsgLIey2lleEedmg,6697
5
+ abexp/absplice/model.py,sha256=WVrXumBkFWtPtImQV38Oqz2ubtZ12h-rmzVnjLLR2UY,3168
6
+ abexp/absplice/result.py,sha256=2GiLYU9ekmYcJ27qxWd9pZOZVR6U9-0YBqnq50dXEKQ,11413
7
+ abexp/absplice/splicemap.py,sha256=IVj429F7xmSNMAg-G8RNg2nUdU5zJ4TidubHINvx4DI,4639
8
+ abexp/absplice/utils.py,sha256=57ksqW4pkeX9SeZfQvb6Qav4arGorcgWkKwY4aJ5xqI,3922
9
+ abexp/absplice/precomputed/AbSplice_DNA.onnx,sha256=KHKMIVKSCEs5VvBcahTPFMpFPkWt5jEkkGcA2FqlopE,34886
10
+ abexp/absplice/precomputed/GENE_MAP.tsv.gz,sha256=5N2CJLqxZ9tztRfNjZcVVcNHuc7tONtUXGApsr4GvNU,1299476
11
+ abexp/absplice2/__init__.py,sha256=225dUYNBasZy0E4xpAGTkjhmYUyDH8ycMh7Z-_t1bKc,790
12
+ abexp/absplice2/dna.py,sha256=z39-sT47EzOlBWbbYXf45HJz6OxrxRAydiPrOOVQ6CU,11268
13
+ abexp/enformer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ abexp/enformer/constants.py,sha256=ZoKxJTDeJnfSWurTO3rEnFfc4xevIVEwUMSR3IeKDSE,80
15
+ abexp/enformer/enformer.py,sha256=TtC4cg88C5X8AOarMFTx9rT6OpSVtfr6GqozDTq15lY,29369
16
+ abexp/enformer/logger.py,sha256=zS65cDCVD82AMwFXCcDaRrn3v_Oi_IfoyUEJ4_sNmqE,341
17
+ abexp/enformer/utils.py,sha256=ozi6LVVX1TjgcHDbezI1Yiul-TXQzyv0nG400qTiW2o,3518
18
+ abexp/enformer/dataloader/__init__.py,sha256=PnDbH7RVdxj72jYFQCelfExC16DqvvwKS_MRhRYRT3Y,77
19
+ abexp/enformer/dataloader/dataloader.py,sha256=-b37FL8XWO2CSKI26yg8x1gJwanMzzEXCc7YJ3SgSm4,9542
20
+ abexp/enformer/dataloader/tss_dataloader.py,sha256=Q8iSSEuUTkvDBpVroOvQY3_2FoZpPYQ9o4ZbbBov7ao,14016
21
+ abexp/mmsplice/__init__.py,sha256=wSwL3U3fHnPL2kCiBFPrl_CF1cx7XpdPWBQjAT7zdmk,813
22
+ abexp/mmsplice/batching.py,sha256=aQqnZC3HMUBCiSLztq7bQSB-bAyRBrhcBTWUonqmFY8,1882
23
+ abexp/mmsplice/dataloader.py,sha256=yPbdDstfO2_6Uxbt-5Ra2idC8mFYeCVSiZMZa4o3nvg,17559
24
+ abexp/mmsplice/layers.py,sha256=sir1FZJKOWpdA2qZYKQOBcgwcEt90Bn2UtyM2yvEkM8,3764
25
+ abexp/mmsplice/model.py,sha256=Ct_CLGx1rr9c-LAe1v-0yK1wYvkHERKf3VNzCQLOKQc,4113
26
+ abexp/mmsplice/utils.py,sha256=rCyEY0o86NZZxtqaO_Lp3P2C7B8VoPWYwqXDrxb7waU,4117
27
+ abexp/mmsplice/models/Acceptor.h5,sha256=5pbCnq2FsWepEC3CQCDYwHKiMiNr5udbuuRRXvtGqkQ,104208
28
+ abexp/mmsplice/models/Donor.h5,sha256=0eF7n9dGLkktLFIK9TnZPgklJ7oZ2DXNhgLzdpEv9cY,268760
29
+ abexp/mmsplice/models/Exon.h5,sha256=rqfwr_ReFOgcbHm6wNrUiHIYgsRfs59sZuQYKl0DPJQ,45248
30
+ abexp/mmsplice/models/Intron3.h5,sha256=9SoRAEKXUsCZKlVWJaTNGbfP1thfzPwoiwdvUdcpk2M,70484
31
+ abexp/mmsplice/models/Intron5.h5,sha256=hHOIab0qHQeqapocZQ14uok6lzy1nXkJo8p27-JCZfY,70436
32
+ abexp/pangolin/__init__.py,sha256=d9jcn5sf3ZUKqvAQaKnGvCdGpbEhM51fTMyGzs2c5Ec,927
33
+ abexp/pangolin/annotation.py,sha256=3eZ5ztbGFOsftlAxPseKwbiWqKhJ-DOssjM7gSihOsw,1829
34
+ abexp/pangolin/model.py,sha256=yfjlK3fO1eIDgqf7Kc2Y2On6RSgyTvjpFeFv4mjnpto,7276
35
+ abexp/pangolin/pangolin.py,sha256=3QpnTR2Qn31VBeANCHG4yCVzxs0FCkuOPBL7Rjxpz_o,12568
36
+ abexp/pangolin/weights.py,sha256=lydmN4EcI3t_NlsZbS5fwwt7hiQiMc_d9c3O1aVbmek,4400
37
+ abexp/spliceai_rocksdb/__init__.py,sha256=vTHrjIjRuDNinTf83A61ykiJJnv4_h8h9MxeQaqgLAY,488
38
+ abexp/spliceai_rocksdb/spliceai.py,sha256=nZLQP7N7TNbqaIZ7X_DmWi115ST_HAQMfuKPMnq63B4,7210
39
+ abexp/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
+ abexp/utils/common.py,sha256=BWmkmHJroxgFoJZH4KVuKduVcnE6kJBJxAD9U-WFsZ4,329
41
+ abexp/utils/gff3.py,sha256=ZyYvCkFOn_DbE9BwE8eYd_Lg1ITF0N_sp1fWgorSSH0,2620
42
+ abexp/utils/models/__init__.py,sha256=76knxqc1HG3cwIBwYrfOCKPp21vbH0ttPuzTfaLUt8U,24
43
+ abexp/utils/models/wrappers.py,sha256=yygRTq0awx7Ek5rdydqUqfOVe9wz9mKjEVEIzTxuZiY,2995
44
+ abexp/utils/polars_functions/__init__.py,sha256=FR7nSK3IQ0EpEoGUrqWf9BBZr1xNz0rQA8JOfFWp39c,195
45
+ abexp/utils/polars_functions/featureset.py,sha256=WWummjbIfoyYCdHDmfRyfI8vPQygTtdBUoEgrLQktPI,6773
46
+ abexp/utils/polars_functions/reshape.py,sha256=sYnPzBoGUBXPVNjl5eUKT3euuynVqRB5vbgx5QTwXAY,3751
47
+ abexp/utils/polars_functions/write.py,sha256=JOJH6gXbyCZvBPUMKhd17y_5UYeanYnPqySbEDfUgX4,318
48
+ abexp/utils/spark_functions/__init__.py,sha256=mTxiQhjGcMgJ0TIQIEw8FkQNBc7j6m21x5OHBPoc00M,237
49
+ abexp/utils/spark_functions/featureset.py,sha256=ebw4vPI5AwmnjvjePsYYSiwXGizxYmYwi4dbGUWfc8Y,6244
50
+ abexp/utils/spark_functions/reshape.py,sha256=jmIr9SBJELAtDttan1x7wn4orI77y-7m73QAWZ50aMs,8986
51
+ aberrant_expression-0.1.0.dist-info/METADATA,sha256=r7ALVCnAgYumdVUKGOLOboDfc7hAQTcvflklOs4j1WE,27968
52
+ aberrant_expression-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
53
+ aberrant_expression-0.1.0.dist-info/top_level.txt,sha256=GqPPKL5yuol-h8hZOtfHhQYvBrpfdK4jd5pa9NfcMdY,6
54
+ aberrant_expression-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,48 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023-2026 Gagneur lab
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ -------------------------------------------------------------------------------
24
+
25
+ This package contains code and model files ported from the following projects.
26
+ They are under the MIT License with the terms above.
27
+
28
+ mmsplice 2.4.0, https://github.com/gagneurlab/MMSplice_MTSplice, commit 31513da:
29
+ src/abexp/mmsplice, including the model files in src/abexp/mmsplice/models
30
+ Copyright (c) 2018, Jun Cheng
31
+
32
+ kipoi-utils 0.7.7, https://github.com/kipoi/kipoi-utils:
33
+ src/abexp/mmsplice/batching.py
34
+ Copyright (c) 2019 Kipoi team
35
+
36
+ absplice, https://github.com/gagneurlab/absplice, commit daad7b6:
37
+ src/abexp/absplice, including the AbSplice-DNA model src/abexp/absplice/precomputed/AbSplice_DNA.onnx
38
+ and the gene table src/abexp/absplice/precomputed/GENE_MAP.tsv.gz
39
+ Copyright (c) 2023 Muhammed Hasan Çelik and Nils Wagner
40
+
41
+ splicemap, https://github.com/gagneurlab/splicemap, commit cf922eb:
42
+ src/abexp/absplice/splicemap.py
43
+ Copyright (c) 2023 Muhammed Hasan Çelik and Nils Wagner
44
+
45
+ spliceai_rocksdb, https://github.com/gagneurlab/spliceai_rocksdb, commit 3c40d6e:
46
+ src/abexp/spliceai_rocksdb
47
+ The repository has no license file; its setup.py declares license="MIT license" and the author
48
+ M. Hasan Çelik.
@@ -0,0 +1 @@
1
+ abexp
abexp/__init__.py ADDED
@@ -0,0 +1,12 @@
1
+ """The Python packages of the AbExp pipeline.
2
+
3
+ This module imports none of the subpackages, so that importing one subpackage does not import the dependencies of
4
+ the others.
5
+ """
6
+ from importlib.metadata import PackageNotFoundError, version
7
+
8
+ try:
9
+ __version__ = version('aberrant-expression')
10
+ except PackageNotFoundError:
11
+ # not installed, e.g. imported from a checkout through PYTHONPATH
12
+ __version__ = 'unknown'
@@ -0,0 +1,21 @@
1
+ """AbSplice-DNA: MMSplice with SpliceMaps, SpliceAI and the AbSplice-DNA model.
2
+
3
+ Ported from absplice (https://github.com/gagneurlab/absplice, commit daad7b6) and splicemap
4
+ (https://github.com/gagneurlab/splicemap, commit cf922eb), on kipoiseq2 instead of kipoiseq, kipoi and pyranges.
5
+ MIT License, Copyright (c) 2023 Muhammed Hasan Çelik and Nils Wagner; see LICENSE.
6
+ """
7
+ from abexp.absplice.dataloader import SpliceOutlierDataloader
8
+ from abexp.absplice.model import SpliceOutlier
9
+ from abexp.absplice.result import SplicingOutlierResult, GENE_MAP, ABSPLICE_DNA
10
+ from abexp.absplice.splicemap import SpliceMap
11
+ from abexp.absplice.utils import read_spliceai_vcf
12
+
13
+ __all__ = [
14
+ 'SpliceOutlierDataloader',
15
+ 'SpliceOutlier',
16
+ 'SplicingOutlierResult',
17
+ 'SpliceMap',
18
+ 'read_spliceai_vcf',
19
+ 'GENE_MAP',
20
+ 'ABSPLICE_DNA',
21
+ ]