RefgenDetector 3.0.5__tar.gz → 3.0.7__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.
- {refgendetector-3.0.5/src/RefgenDetector.egg-info → refgendetector-3.0.7}/PKG-INFO +92 -7
- {refgendetector-3.0.5 → refgendetector-3.0.7}/README.md +91 -6
- {refgendetector-3.0.5 → refgendetector-3.0.7}/setup.py +1 -1
- {refgendetector-3.0.5 → refgendetector-3.0.7/src/RefgenDetector.egg-info}/PKG-INFO +92 -7
- {refgendetector-3.0.5 → refgendetector-3.0.7}/src/RefgenDetector.egg-info/SOURCES.txt +5 -1
- {refgendetector-3.0.5 → refgendetector-3.0.7}/src/refgenDetector/aligment_files.py +24 -21
- {refgendetector-3.0.5 → refgendetector-3.0.7}/src/refgenDetector/download_reference.py +1 -0
- refgendetector-3.0.7/src/refgenDetector/msgpacks/__init__.py +0 -0
- refgendetector-3.0.7/src/refgenDetector/msgpacks/create-plots.py +243 -0
- refgendetector-3.0.7/src/refgenDetector/msgpacks/create-plots2.py +220 -0
- refgendetector-3.0.7/src/refgenDetector/msgpacks/open_file.py +15 -0
- {refgendetector-3.0.5 → refgendetector-3.0.7}/src/refgenDetector/refgenDetector_main.py +1 -1
- {refgendetector-3.0.5 → refgendetector-3.0.7}/src/refgenDetector/variant_files.py +9 -4
- {refgendetector-3.0.5 → refgendetector-3.0.7}/LICENSE +0 -0
- {refgendetector-3.0.5 → refgendetector-3.0.7}/setup.cfg +0 -0
- {refgendetector-3.0.5 → refgendetector-3.0.7}/src/RefgenDetector.egg-info/dependency_links.txt +0 -0
- {refgendetector-3.0.5 → refgendetector-3.0.7}/src/RefgenDetector.egg-info/entry_points.txt +0 -0
- {refgendetector-3.0.5 → refgendetector-3.0.7}/src/RefgenDetector.egg-info/requires.txt +0 -0
- {refgendetector-3.0.5 → refgendetector-3.0.7}/src/RefgenDetector.egg-info/top_level.txt +0 -0
- {refgendetector-3.0.5 → refgendetector-3.0.7}/src/refgenDetector/__init__.py +0 -0
- {refgendetector-3.0.5 → refgendetector-3.0.7}/src/refgenDetector/chromosomes_dict.py +0 -0
- {refgendetector-3.0.5 → refgendetector-3.0.7}/src/refgenDetector/exceptions/NoFileException.py +0 -0
- {refgendetector-3.0.5 → refgendetector-3.0.7}/src/refgenDetector/exceptions/__init__.py +0 -0
- {refgendetector-3.0.5/src/refgenDetector/msgpacks → refgendetector-3.0.7/src/refgenDetector/github_msgpacks}/__init__.py +0 -0
- {refgendetector-3.0.5 → refgendetector-3.0.7}/src/refgenDetector/ref_manager.py +0 -0
- {refgendetector-3.0.5 → refgendetector-3.0.7}/src/refgenDetector/reference_genome_dictionaries.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: RefgenDetector
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.7
|
|
4
4
|
Author: Mireia Marin i Ginestar
|
|
5
5
|
Author-email: <mireia.marin@crg.eu>
|
|
6
6
|
Keywords: python
|
|
@@ -180,7 +180,9 @@ To infer the reference genome from a VCF the tool will read the VCF file in chun
|
|
|
180
180
|
|
|
181
181
|
The msgpack files were created comparing the nucleotides in each position for hg18, GRCh37, GRCh38 and T2T. Each file contains a list of the positions where each reference had a different nucleotide (distinguishing positions).
|
|
182
182
|
|
|
183
|
-
By getting the number of matches between these distinguishing positions and the `REF` present in the VCF we infer the reference genome version used to call the variants.
|
|
183
|
+
By getting the number of matches between these distinguishing positions and the `REF` present in the VCF we infer the reference genome version used to call the variants.
|
|
184
|
+
|
|
185
|
+
**Bear in mind** that the input VCF must be sorted to improve runtime performance.
|
|
184
186
|
|
|
185
187
|
## Requirements
|
|
186
188
|
|
|
@@ -197,15 +199,16 @@ Depending on how you want to install the package:
|
|
|
197
199
|
|
|
198
200
|
1. Clone this repository
|
|
199
201
|
|
|
200
|
-
|
|
202
|
+
```git clone https://github.com/EGA-archive/refgenDetector.git
|
|
201
203
|
cd refgenDetector
|
|
202
|
-
pip install -e .
|
|
204
|
+
pip install -e .
|
|
205
|
+
```
|
|
203
206
|
|
|
204
|
-
|
|
207
|
+
2. ``$ python3 refgenDetector_main.py -h ``
|
|
205
208
|
|
|
206
|
-
|
|
209
|
+
3. Download the `msgpack` files for the inference with VCFs: [Download the msgpack reference](https://crgcnag-my.sharepoint.com/:u:/g/personal/mimarin_crg_es/IQDa5CICZDAoRZmbfhBG3ZPEAWdVnNqvefFJB_r5Hc8aM70?e=kID7zn)
|
|
207
210
|
|
|
208
|
-
|
|
211
|
+
4. Move the `msgpack` to the correct path:
|
|
209
212
|
|
|
210
213
|
```
|
|
211
214
|
mv msgpacks.zip /refgenDetector/src/refgenDetector/
|
|
@@ -216,9 +219,91 @@ unzip /refgenDetector/src/refgenDetector/msgpacks.zip
|
|
|
216
219
|
|
|
217
220
|
``$ pip install refgenDetector``
|
|
218
221
|
|
|
222
|
+
The reference files for the VCF inference will be automatically downloaded after the first execution of refgenDetector
|
|
223
|
+
|
|
224
|
+
### With Docker
|
|
225
|
+
|
|
226
|
+
refgenDetector can be run using Docker, allowing it to work on Linux, Windows, and macOS without installing Python or other dependencies locally.
|
|
227
|
+
|
|
228
|
+
#### 1. Requirements
|
|
229
|
+
|
|
230
|
+
- [Docker](https://www.docker.com/) with Docker Compose installed
|
|
231
|
+
- The refgenDetector repository cloned locally
|
|
232
|
+
|
|
233
|
+
#### 2. Build and start the container
|
|
234
|
+
|
|
235
|
+
From the root directory of the repository, run:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
docker compose up -d --build
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
This builds the Docker image and starts the container in the background.
|
|
242
|
+
|
|
243
|
+
For subsequent starts, use:
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
docker compose up -d
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
#### 3. Add input files
|
|
250
|
+
|
|
251
|
+
Place the files you want to analyse in the `data/` directory of the repository.
|
|
252
|
+
|
|
253
|
+
This folder is automatically mounted inside the container, so files can be added or removed without rebuilding it.
|
|
254
|
+
|
|
255
|
+
#### 4. Run refgenDetector
|
|
256
|
+
|
|
257
|
+
Execute refgenDetector using:
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
docker compose exec refgendetector refgenDetector -t VCF -f sample.vcf.gz
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Replace `sample.vcf.gz` with your input filename.
|
|
264
|
+
|
|
265
|
+
Supported input types include:
|
|
266
|
+
|
|
267
|
+
- `VCF` — VCF files
|
|
268
|
+
- `BAM/CRAM` — BAM or CRAM files
|
|
269
|
+
- `Header` — extracted BAM/CRAM headers
|
|
270
|
+
|
|
271
|
+
For example, to analyse a BAM file:
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
docker compose exec refgendetector refgenDetector -t BAM/CRAM -f sample.bam
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
To display the available options:
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
docker compose exec refgendetector refgenDetector -h
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**Note:** On the first execution requiring reference databases, refgenDetector automatically downloads them. These files are stored in a persistent Docker volume and reused in subsequent executions, including after rebuilding the container.
|
|
284
|
+
|
|
285
|
+
#### 5. Stop the container
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
docker compose down
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
This stops and removes the container while preserving the downloaded reference databases.
|
|
292
|
+
|
|
293
|
+
To start it again:
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
docker compose up -d
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**Important:** Avoid using `docker compose down -v`, as this will also remove the persistent volume containing the reference databases.
|
|
300
|
+
|
|
219
301
|
|
|
220
302
|
## Usage
|
|
221
303
|
|
|
304
|
+
|
|
305
|
+
**Bear in mind that the VCF must be sorted for optimal execution.**
|
|
306
|
+
|
|
222
307
|
You can get the help menu by running:
|
|
223
308
|
|
|
224
309
|
```
|
|
@@ -154,7 +154,9 @@ To infer the reference genome from a VCF the tool will read the VCF file in chun
|
|
|
154
154
|
|
|
155
155
|
The msgpack files were created comparing the nucleotides in each position for hg18, GRCh37, GRCh38 and T2T. Each file contains a list of the positions where each reference had a different nucleotide (distinguishing positions).
|
|
156
156
|
|
|
157
|
-
By getting the number of matches between these distinguishing positions and the `REF` present in the VCF we infer the reference genome version used to call the variants.
|
|
157
|
+
By getting the number of matches between these distinguishing positions and the `REF` present in the VCF we infer the reference genome version used to call the variants.
|
|
158
|
+
|
|
159
|
+
**Bear in mind** that the input VCF must be sorted to improve runtime performance.
|
|
158
160
|
|
|
159
161
|
## Requirements
|
|
160
162
|
|
|
@@ -171,15 +173,16 @@ Depending on how you want to install the package:
|
|
|
171
173
|
|
|
172
174
|
1. Clone this repository
|
|
173
175
|
|
|
174
|
-
|
|
176
|
+
```git clone https://github.com/EGA-archive/refgenDetector.git
|
|
175
177
|
cd refgenDetector
|
|
176
|
-
pip install -e .
|
|
178
|
+
pip install -e .
|
|
179
|
+
```
|
|
177
180
|
|
|
178
|
-
|
|
181
|
+
2. ``$ python3 refgenDetector_main.py -h ``
|
|
179
182
|
|
|
180
|
-
|
|
183
|
+
3. Download the `msgpack` files for the inference with VCFs: [Download the msgpack reference](https://crgcnag-my.sharepoint.com/:u:/g/personal/mimarin_crg_es/IQDa5CICZDAoRZmbfhBG3ZPEAWdVnNqvefFJB_r5Hc8aM70?e=kID7zn)
|
|
181
184
|
|
|
182
|
-
|
|
185
|
+
4. Move the `msgpack` to the correct path:
|
|
183
186
|
|
|
184
187
|
```
|
|
185
188
|
mv msgpacks.zip /refgenDetector/src/refgenDetector/
|
|
@@ -190,9 +193,91 @@ unzip /refgenDetector/src/refgenDetector/msgpacks.zip
|
|
|
190
193
|
|
|
191
194
|
``$ pip install refgenDetector``
|
|
192
195
|
|
|
196
|
+
The reference files for the VCF inference will be automatically downloaded after the first execution of refgenDetector
|
|
197
|
+
|
|
198
|
+
### With Docker
|
|
199
|
+
|
|
200
|
+
refgenDetector can be run using Docker, allowing it to work on Linux, Windows, and macOS without installing Python or other dependencies locally.
|
|
201
|
+
|
|
202
|
+
#### 1. Requirements
|
|
203
|
+
|
|
204
|
+
- [Docker](https://www.docker.com/) with Docker Compose installed
|
|
205
|
+
- The refgenDetector repository cloned locally
|
|
206
|
+
|
|
207
|
+
#### 2. Build and start the container
|
|
208
|
+
|
|
209
|
+
From the root directory of the repository, run:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
docker compose up -d --build
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
This builds the Docker image and starts the container in the background.
|
|
216
|
+
|
|
217
|
+
For subsequent starts, use:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
docker compose up -d
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
#### 3. Add input files
|
|
224
|
+
|
|
225
|
+
Place the files you want to analyse in the `data/` directory of the repository.
|
|
226
|
+
|
|
227
|
+
This folder is automatically mounted inside the container, so files can be added or removed without rebuilding it.
|
|
228
|
+
|
|
229
|
+
#### 4. Run refgenDetector
|
|
230
|
+
|
|
231
|
+
Execute refgenDetector using:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
docker compose exec refgendetector refgenDetector -t VCF -f sample.vcf.gz
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Replace `sample.vcf.gz` with your input filename.
|
|
238
|
+
|
|
239
|
+
Supported input types include:
|
|
240
|
+
|
|
241
|
+
- `VCF` — VCF files
|
|
242
|
+
- `BAM/CRAM` — BAM or CRAM files
|
|
243
|
+
- `Header` — extracted BAM/CRAM headers
|
|
244
|
+
|
|
245
|
+
For example, to analyse a BAM file:
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
docker compose exec refgendetector refgenDetector -t BAM/CRAM -f sample.bam
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
To display the available options:
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
docker compose exec refgendetector refgenDetector -h
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
**Note:** On the first execution requiring reference databases, refgenDetector automatically downloads them. These files are stored in a persistent Docker volume and reused in subsequent executions, including after rebuilding the container.
|
|
258
|
+
|
|
259
|
+
#### 5. Stop the container
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
docker compose down
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
This stops and removes the container while preserving the downloaded reference databases.
|
|
266
|
+
|
|
267
|
+
To start it again:
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
docker compose up -d
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
**Important:** Avoid using `docker compose down -v`, as this will also remove the persistent volume containing the reference databases.
|
|
274
|
+
|
|
193
275
|
|
|
194
276
|
## Usage
|
|
195
277
|
|
|
278
|
+
|
|
279
|
+
**Bear in mind that the VCF must be sorted for optimal execution.**
|
|
280
|
+
|
|
196
281
|
You can get the help menu by running:
|
|
197
282
|
|
|
198
283
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: RefgenDetector
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.7
|
|
4
4
|
Author: Mireia Marin i Ginestar
|
|
5
5
|
Author-email: <mireia.marin@crg.eu>
|
|
6
6
|
Keywords: python
|
|
@@ -180,7 +180,9 @@ To infer the reference genome from a VCF the tool will read the VCF file in chun
|
|
|
180
180
|
|
|
181
181
|
The msgpack files were created comparing the nucleotides in each position for hg18, GRCh37, GRCh38 and T2T. Each file contains a list of the positions where each reference had a different nucleotide (distinguishing positions).
|
|
182
182
|
|
|
183
|
-
By getting the number of matches between these distinguishing positions and the `REF` present in the VCF we infer the reference genome version used to call the variants.
|
|
183
|
+
By getting the number of matches between these distinguishing positions and the `REF` present in the VCF we infer the reference genome version used to call the variants.
|
|
184
|
+
|
|
185
|
+
**Bear in mind** that the input VCF must be sorted to improve runtime performance.
|
|
184
186
|
|
|
185
187
|
## Requirements
|
|
186
188
|
|
|
@@ -197,15 +199,16 @@ Depending on how you want to install the package:
|
|
|
197
199
|
|
|
198
200
|
1. Clone this repository
|
|
199
201
|
|
|
200
|
-
|
|
202
|
+
```git clone https://github.com/EGA-archive/refgenDetector.git
|
|
201
203
|
cd refgenDetector
|
|
202
|
-
pip install -e .
|
|
204
|
+
pip install -e .
|
|
205
|
+
```
|
|
203
206
|
|
|
204
|
-
|
|
207
|
+
2. ``$ python3 refgenDetector_main.py -h ``
|
|
205
208
|
|
|
206
|
-
|
|
209
|
+
3. Download the `msgpack` files for the inference with VCFs: [Download the msgpack reference](https://crgcnag-my.sharepoint.com/:u:/g/personal/mimarin_crg_es/IQDa5CICZDAoRZmbfhBG3ZPEAWdVnNqvefFJB_r5Hc8aM70?e=kID7zn)
|
|
207
210
|
|
|
208
|
-
|
|
211
|
+
4. Move the `msgpack` to the correct path:
|
|
209
212
|
|
|
210
213
|
```
|
|
211
214
|
mv msgpacks.zip /refgenDetector/src/refgenDetector/
|
|
@@ -216,9 +219,91 @@ unzip /refgenDetector/src/refgenDetector/msgpacks.zip
|
|
|
216
219
|
|
|
217
220
|
``$ pip install refgenDetector``
|
|
218
221
|
|
|
222
|
+
The reference files for the VCF inference will be automatically downloaded after the first execution of refgenDetector
|
|
223
|
+
|
|
224
|
+
### With Docker
|
|
225
|
+
|
|
226
|
+
refgenDetector can be run using Docker, allowing it to work on Linux, Windows, and macOS without installing Python or other dependencies locally.
|
|
227
|
+
|
|
228
|
+
#### 1. Requirements
|
|
229
|
+
|
|
230
|
+
- [Docker](https://www.docker.com/) with Docker Compose installed
|
|
231
|
+
- The refgenDetector repository cloned locally
|
|
232
|
+
|
|
233
|
+
#### 2. Build and start the container
|
|
234
|
+
|
|
235
|
+
From the root directory of the repository, run:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
docker compose up -d --build
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
This builds the Docker image and starts the container in the background.
|
|
242
|
+
|
|
243
|
+
For subsequent starts, use:
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
docker compose up -d
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
#### 3. Add input files
|
|
250
|
+
|
|
251
|
+
Place the files you want to analyse in the `data/` directory of the repository.
|
|
252
|
+
|
|
253
|
+
This folder is automatically mounted inside the container, so files can be added or removed without rebuilding it.
|
|
254
|
+
|
|
255
|
+
#### 4. Run refgenDetector
|
|
256
|
+
|
|
257
|
+
Execute refgenDetector using:
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
docker compose exec refgendetector refgenDetector -t VCF -f sample.vcf.gz
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Replace `sample.vcf.gz` with your input filename.
|
|
264
|
+
|
|
265
|
+
Supported input types include:
|
|
266
|
+
|
|
267
|
+
- `VCF` — VCF files
|
|
268
|
+
- `BAM/CRAM` — BAM or CRAM files
|
|
269
|
+
- `Header` — extracted BAM/CRAM headers
|
|
270
|
+
|
|
271
|
+
For example, to analyse a BAM file:
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
docker compose exec refgendetector refgenDetector -t BAM/CRAM -f sample.bam
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
To display the available options:
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
docker compose exec refgendetector refgenDetector -h
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**Note:** On the first execution requiring reference databases, refgenDetector automatically downloads them. These files are stored in a persistent Docker volume and reused in subsequent executions, including after rebuilding the container.
|
|
284
|
+
|
|
285
|
+
#### 5. Stop the container
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
docker compose down
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
This stops and removes the container while preserving the downloaded reference databases.
|
|
292
|
+
|
|
293
|
+
To start it again:
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
docker compose up -d
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**Important:** Avoid using `docker compose down -v`, as this will also remove the persistent volume containing the reference databases.
|
|
300
|
+
|
|
219
301
|
|
|
220
302
|
## Usage
|
|
221
303
|
|
|
304
|
+
|
|
305
|
+
**Bear in mind that the VCF must be sorted for optimal execution.**
|
|
306
|
+
|
|
222
307
|
You can get the help menu by running:
|
|
223
308
|
|
|
224
309
|
```
|
|
@@ -17,4 +17,8 @@ src/refgenDetector/refgenDetector_main.py
|
|
|
17
17
|
src/refgenDetector/variant_files.py
|
|
18
18
|
src/refgenDetector/exceptions/NoFileException.py
|
|
19
19
|
src/refgenDetector/exceptions/__init__.py
|
|
20
|
-
src/refgenDetector/
|
|
20
|
+
src/refgenDetector/github_msgpacks/__init__.py
|
|
21
|
+
src/refgenDetector/msgpacks/__init__.py
|
|
22
|
+
src/refgenDetector/msgpacks/create-plots.py
|
|
23
|
+
src/refgenDetector/msgpacks/create-plots2.py
|
|
24
|
+
src/refgenDetector/msgpacks/open_file.py
|
|
@@ -250,33 +250,36 @@ def get_info_txt(header_txt, md5, assembly):
|
|
|
250
250
|
|
|
251
251
|
def process_data_txt(target_file, md5, assembly):
|
|
252
252
|
"""
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
Args:
|
|
257
|
-
target_file (str): path to the file
|
|
258
|
-
|
|
259
|
-
Returns:
|
|
260
|
-
header_txt (io.TextIOWrapper): text object
|
|
253
|
+
Read a BAM/CRAM header from a plain-text or gzip-compressed file.
|
|
254
|
+
Supports UTF-8 and ISO-8859-1 encodings.
|
|
261
255
|
"""
|
|
262
256
|
try:
|
|
263
|
-
if os.path.isfile(target_file):
|
|
264
|
-
with open(target_file, "r") as header_txt:
|
|
265
|
-
get_info_txt(header_txt, md5, assembly)
|
|
266
|
-
else:
|
|
257
|
+
if not os.path.isfile(target_file):
|
|
267
258
|
raise NoFileException()
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
259
|
+
|
|
260
|
+
# Detect gzip from its magic bytes
|
|
261
|
+
with open(target_file, "rb") as f:
|
|
262
|
+
is_gzip = f.read(2) == b"\x1f\x8b"
|
|
263
|
+
|
|
264
|
+
opener = gzip.open if is_gzip else open
|
|
265
|
+
|
|
272
266
|
try:
|
|
273
|
-
with
|
|
267
|
+
with opener(target_file, "rt", encoding="utf-8") as header_txt:
|
|
274
268
|
get_info_txt(header_txt, md5, assembly)
|
|
275
|
-
except
|
|
276
|
-
with
|
|
269
|
+
except UnicodeDecodeError:
|
|
270
|
+
with opener(target_file, "rt", encoding="iso-8859-1") as header_txt:
|
|
277
271
|
get_info_txt(header_txt, md5, assembly)
|
|
272
|
+
|
|
278
273
|
except NoFileException:
|
|
279
|
-
console.print(
|
|
280
|
-
|
|
274
|
+
console.print(
|
|
275
|
+
f"[bold]File:[/bold] {target_file}\n"
|
|
276
|
+
"[bold red]Error:[/bold red] File not found."
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
except (OSError, EOFError) as e:
|
|
280
|
+
console.print(
|
|
281
|
+
f"[bold red]Error reading file:[/bold red] {e}"
|
|
282
|
+
)
|
|
283
|
+
|
|
281
284
|
except Exception as e:
|
|
282
285
|
print("Unexpected error:\n", e)
|
|
File without changes
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"""
|
|
2
|
+
count_and_plot.py
|
|
3
|
+
-----------------
|
|
4
|
+
Reads all msgpack files (one per assembly × chromosome) and produces:
|
|
5
|
+
1. A stacked bar chart – positions per chromosome, coloured by assembly
|
|
6
|
+
2. A donut / bar summary – total positions per assembly
|
|
7
|
+
3. A heatmap – positions (chromosome × assembly)
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
python count_and_plot.py --dir /path/to/msgpack/folder --out /path/to/output/dir
|
|
11
|
+
|
|
12
|
+
Defaults to the current directory for both --dir and --out.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import argparse
|
|
16
|
+
import os
|
|
17
|
+
import re
|
|
18
|
+
import collections
|
|
19
|
+
import msgpack
|
|
20
|
+
import matplotlib
|
|
21
|
+
matplotlib.use("Agg")
|
|
22
|
+
import matplotlib.pyplot as plt
|
|
23
|
+
import matplotlib.ticker as mticker
|
|
24
|
+
import numpy as np
|
|
25
|
+
|
|
26
|
+
# ── helpers ──────────────────────────────────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
ASSEMBLIES = ["hg18", "GRCh37", "GRCh38", "T2T"]
|
|
29
|
+
|
|
30
|
+
# Natural sort order for chromosomes: 1-22, X, Y
|
|
31
|
+
def _chr_sort_key(c):
|
|
32
|
+
c = c.replace("chr", "")
|
|
33
|
+
if c == "X": return (23, 0)
|
|
34
|
+
if c == "Y": return (24, 0)
|
|
35
|
+
try: return (int(c), 0)
|
|
36
|
+
except: return (99, 0)
|
|
37
|
+
|
|
38
|
+
ASSEMBLY_COLORS = {
|
|
39
|
+
"hg18": "#4C72B0",
|
|
40
|
+
"GRCh37": "#DD8452",
|
|
41
|
+
"GRCh38": "#55A868",
|
|
42
|
+
"T2T": "#C44E52",
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
def load_counts(msgpack_dir: str) -> dict:
|
|
46
|
+
"""
|
|
47
|
+
Returns counts[assembly][chrom] = int (number of distinguishing positions).
|
|
48
|
+
"""
|
|
49
|
+
counts = {asm: {} for asm in ASSEMBLIES}
|
|
50
|
+
pattern = re.compile(r"^(hg18|GRCh37|GRCh38|T2T)-(chr[0-9XY]+)\.msgpack$")
|
|
51
|
+
|
|
52
|
+
for fname in sorted(os.listdir(msgpack_dir)):
|
|
53
|
+
m = pattern.match(fname)
|
|
54
|
+
if not m:
|
|
55
|
+
continue
|
|
56
|
+
assembly, chrom = m.group(1), m.group(2)
|
|
57
|
+
fpath = os.path.join(msgpack_dir, fname)
|
|
58
|
+
with open(fpath, "rb") as fh:
|
|
59
|
+
data = msgpack.unpack(fh, raw=False, strict_map_key=False)
|
|
60
|
+
counts[assembly][chrom] = len(data)
|
|
61
|
+
|
|
62
|
+
return counts
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# ── plot 1 : stacked bar per chromosome ──────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
def plot_stacked_bar(counts, out_path):
|
|
68
|
+
# collect all chromosomes present
|
|
69
|
+
all_chroms = sorted(
|
|
70
|
+
{c for asm in counts.values() for c in asm.keys()},
|
|
71
|
+
key=_chr_sort_key
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
x = np.arange(len(all_chroms))
|
|
75
|
+
width = 0.55
|
|
76
|
+
|
|
77
|
+
fig, ax = plt.subplots(figsize=(14, 5))
|
|
78
|
+
bottoms = np.zeros(len(all_chroms))
|
|
79
|
+
|
|
80
|
+
for asm in ASSEMBLIES:
|
|
81
|
+
vals = np.array([counts[asm].get(c, 0) for c in all_chroms])
|
|
82
|
+
ax.bar(x, vals, width, bottom=bottoms,
|
|
83
|
+
label=asm, color=ASSEMBLY_COLORS[asm], alpha=0.88)
|
|
84
|
+
bottoms += vals
|
|
85
|
+
|
|
86
|
+
ax.set_xticks(x)
|
|
87
|
+
ax.set_xticklabels(all_chroms, rotation=45, ha="right", fontsize=9)
|
|
88
|
+
ax.yaxis.set_major_formatter(mticker.FuncFormatter(lambda v, _: f"{int(v):,}"))
|
|
89
|
+
ax.set_ylabel("Distinguishing positions", fontsize=11)
|
|
90
|
+
ax.set_title("Distinguishing positions per chromosome\n(stacked by assembly)", fontsize=13)
|
|
91
|
+
ax.legend(title="Assembly", framealpha=0.9)
|
|
92
|
+
ax.spines[["top", "right"]].set_visible(False)
|
|
93
|
+
fig.tight_layout()
|
|
94
|
+
fig.savefig(out_path, dpi=150)
|
|
95
|
+
plt.close(fig)
|
|
96
|
+
print(f" Saved: {out_path}")
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# ── plot 2 : total per assembly (horizontal bar) ──────────────────────────────
|
|
100
|
+
|
|
101
|
+
def plot_totals(counts, out_path):
|
|
102
|
+
totals = {asm: sum(counts[asm].values()) for asm in ASSEMBLIES}
|
|
103
|
+
asms = list(totals.keys())
|
|
104
|
+
vals = [totals[a] for a in asms]
|
|
105
|
+
colors = [ASSEMBLY_COLORS[a] for a in asms]
|
|
106
|
+
|
|
107
|
+
fig, ax = plt.subplots(figsize=(7, 3.5))
|
|
108
|
+
bars = ax.barh(asms, vals, color=colors, height=0.5, alpha=0.9)
|
|
109
|
+
ax.bar_label(bars, labels=[f"{v:,}" for v in vals],
|
|
110
|
+
padding=6, fontsize=10)
|
|
111
|
+
ax.xaxis.set_major_formatter(mticker.FuncFormatter(lambda v, _: f"{int(v):,}"))
|
|
112
|
+
ax.set_xlabel("Total distinguishing positions", fontsize=11)
|
|
113
|
+
ax.set_title("Total distinguishing positions per assembly", fontsize=13)
|
|
114
|
+
ax.spines[["top", "right"]].set_visible(False)
|
|
115
|
+
max_val = max(vals) if vals else 1
|
|
116
|
+
ax.set_xlim(0, max_val * 1.15)
|
|
117
|
+
fig.tight_layout()
|
|
118
|
+
fig.savefig(out_path, dpi=150)
|
|
119
|
+
plt.close(fig)
|
|
120
|
+
print(f" Saved: {out_path}")
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
# ── plot 3 : heatmap (chromosome × assembly) ─────────────────────────────────
|
|
124
|
+
|
|
125
|
+
def plot_heatmap(counts, out_path):
|
|
126
|
+
all_chroms = sorted(
|
|
127
|
+
{c for asm in counts.values() for c in asm.keys()},
|
|
128
|
+
key=_chr_sort_key
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
matrix = np.array(
|
|
132
|
+
[[counts[asm].get(c, 0) for asm in ASSEMBLIES] for c in all_chroms],
|
|
133
|
+
dtype=float
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
fig, ax = plt.subplots(figsize=(6, 9))
|
|
137
|
+
im = ax.imshow(matrix, aspect="auto", cmap="YlOrRd")
|
|
138
|
+
|
|
139
|
+
ax.set_xticks(range(len(ASSEMBLIES)))
|
|
140
|
+
ax.set_xticklabels(ASSEMBLIES, fontsize=10)
|
|
141
|
+
ax.set_yticks(range(len(all_chroms)))
|
|
142
|
+
ax.set_yticklabels(all_chroms, fontsize=8)
|
|
143
|
+
ax.set_title("Distinguishing positions\n(chromosome × assembly)", fontsize=12)
|
|
144
|
+
|
|
145
|
+
cb = fig.colorbar(im, ax=ax, shrink=0.6, pad=0.02)
|
|
146
|
+
cb.set_label("# positions", fontsize=9)
|
|
147
|
+
cb.formatter = mticker.FuncFormatter(lambda v, _: f"{int(v):,}")
|
|
148
|
+
cb.update_ticks()
|
|
149
|
+
|
|
150
|
+
# annotate cells if the matrix is not too large
|
|
151
|
+
if matrix.size <= 200:
|
|
152
|
+
for i in range(len(all_chroms)):
|
|
153
|
+
for j in range(len(ASSEMBLIES)):
|
|
154
|
+
v = int(matrix[i, j])
|
|
155
|
+
ax.text(j, i, f"{v:,}", ha="center", va="center",
|
|
156
|
+
fontsize=6.5, color="black" if v < matrix.max() * 0.7 else "white")
|
|
157
|
+
|
|
158
|
+
fig.tight_layout()
|
|
159
|
+
fig.savefig(out_path, dpi=150)
|
|
160
|
+
plt.close(fig)
|
|
161
|
+
print(f" Saved: {out_path}")
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
# ── plot 4 : grouped bar (per-chrom, side-by-side assemblies) ─────────────────
|
|
165
|
+
|
|
166
|
+
def plot_grouped_bar(counts, out_path):
|
|
167
|
+
all_chroms = sorted(
|
|
168
|
+
{c for asm in counts.values() for c in asm.keys()},
|
|
169
|
+
key=_chr_sort_key
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
n_chr = len(all_chroms)
|
|
173
|
+
n_asm = len(ASSEMBLIES)
|
|
174
|
+
group_w = 0.8
|
|
175
|
+
bar_w = group_w / n_asm
|
|
176
|
+
x = np.arange(n_chr)
|
|
177
|
+
|
|
178
|
+
fig, ax = plt.subplots(figsize=(16, 5))
|
|
179
|
+
for i, asm in enumerate(ASSEMBLIES):
|
|
180
|
+
offsets = x - group_w / 2 + bar_w * (i + 0.5)
|
|
181
|
+
vals = [counts[asm].get(c, 0) for c in all_chroms]
|
|
182
|
+
ax.bar(offsets, vals, width=bar_w * 0.92,
|
|
183
|
+
label=asm, color=ASSEMBLY_COLORS[asm], alpha=0.88)
|
|
184
|
+
|
|
185
|
+
ax.set_xticks(x)
|
|
186
|
+
ax.set_xticklabels(all_chroms, rotation=45, ha="right", fontsize=9)
|
|
187
|
+
ax.yaxis.set_major_formatter(mticker.FuncFormatter(lambda v, _: f"{int(v):,}"))
|
|
188
|
+
ax.set_ylabel("Distinguishing positions", fontsize=11)
|
|
189
|
+
ax.set_title("Distinguishing positions per chromosome per assembly", fontsize=13)
|
|
190
|
+
ax.legend(title="Assembly", framealpha=0.9)
|
|
191
|
+
ax.spines[["top", "right"]].set_visible(False)
|
|
192
|
+
fig.tight_layout()
|
|
193
|
+
fig.savefig(out_path, dpi=150)
|
|
194
|
+
plt.close(fig)
|
|
195
|
+
print(f" Saved: {out_path}")
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
# ── main ──────────────────────────────────────────────────────────────────────
|
|
199
|
+
|
|
200
|
+
def main():
|
|
201
|
+
parser = argparse.ArgumentParser(description=__doc__,
|
|
202
|
+
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
203
|
+
parser.add_argument("--dir", default=".", help="Folder containing the msgpack files")
|
|
204
|
+
parser.add_argument("--out", default=".", help="Output folder for PNG plots")
|
|
205
|
+
args = parser.parse_args()
|
|
206
|
+
|
|
207
|
+
os.makedirs(args.out, exist_ok=True)
|
|
208
|
+
|
|
209
|
+
print(f"Loading msgpack files from: {os.path.abspath(args.dir)}")
|
|
210
|
+
counts = load_counts(args.dir)
|
|
211
|
+
|
|
212
|
+
# Print a summary table
|
|
213
|
+
all_chroms = sorted(
|
|
214
|
+
{c for asm in counts.values() for c in asm.keys()},
|
|
215
|
+
key=_chr_sort_key
|
|
216
|
+
)
|
|
217
|
+
print(f"\n{'Chrom':<10}", end="")
|
|
218
|
+
for asm in ASSEMBLIES:
|
|
219
|
+
print(f"{asm:>12}", end="")
|
|
220
|
+
print()
|
|
221
|
+
print("-" * (10 + 12 * len(ASSEMBLIES)))
|
|
222
|
+
for chrom in all_chroms:
|
|
223
|
+
print(f"{chrom:<10}", end="")
|
|
224
|
+
for asm in ASSEMBLIES:
|
|
225
|
+
print(f"{counts[asm].get(chrom, 0):>12,}", end="")
|
|
226
|
+
print()
|
|
227
|
+
print("-" * (10 + 12 * len(ASSEMBLIES)))
|
|
228
|
+
print(f"{'TOTAL':<10}", end="")
|
|
229
|
+
for asm in ASSEMBLIES:
|
|
230
|
+
print(f"{sum(counts[asm].values()):>12,}", end="")
|
|
231
|
+
print("\n")
|
|
232
|
+
|
|
233
|
+
print("Generating plots...")
|
|
234
|
+
plot_stacked_bar(counts, os.path.join(args.out, "01_stacked_bar_per_chrom.png"))
|
|
235
|
+
plot_totals (counts, os.path.join(args.out, "02_total_per_assembly.png"))
|
|
236
|
+
plot_heatmap (counts, os.path.join(args.out, "03_heatmap_chrom_x_assembly.png"))
|
|
237
|
+
plot_grouped_bar(counts, os.path.join(args.out, "04_grouped_bar_per_chrom.png"))
|
|
238
|
+
|
|
239
|
+
print("\nDone.")
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
if __name__ == "__main__":
|
|
243
|
+
main()
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
count_and_plot.py
|
|
5
|
+
-----------------
|
|
6
|
+
Reads msgpack files named as:
|
|
7
|
+
|
|
8
|
+
hg18-chr1.msgpack
|
|
9
|
+
GRCh37-chr1.msgpack
|
|
10
|
+
GRCh38-chr1.msgpack
|
|
11
|
+
T2T-chr1.msgpack
|
|
12
|
+
|
|
13
|
+
and creates one plot showing the number of distinguishing variants per
|
|
14
|
+
chromosome. Because all assemblies are expected to contain the same number
|
|
15
|
+
of variants, only one bar is shown per chromosome.
|
|
16
|
+
|
|
17
|
+
Usage:
|
|
18
|
+
python count_and_plot.py \
|
|
19
|
+
--dir /path/to/msgpack/folder \
|
|
20
|
+
--out /path/to/output/dir
|
|
21
|
+
|
|
22
|
+
Defaults to the current directory for both --dir and --out.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import argparse
|
|
26
|
+
import os
|
|
27
|
+
import re
|
|
28
|
+
|
|
29
|
+
import msgpack
|
|
30
|
+
import matplotlib
|
|
31
|
+
|
|
32
|
+
matplotlib.use("Agg")
|
|
33
|
+
|
|
34
|
+
import matplotlib.pyplot as plt
|
|
35
|
+
import matplotlib.ticker as mticker
|
|
36
|
+
import numpy as np
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
ASSEMBLIES = ["hg18", "GRCh37", "GRCh38", "T2T"]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def chromosome_sort_key(chromosome):
|
|
43
|
+
"""Natural chromosome order: chr1-chr22, chrX, chrY."""
|
|
44
|
+
chromosome = chromosome.removeprefix("chr")
|
|
45
|
+
|
|
46
|
+
if chromosome == "X":
|
|
47
|
+
return 23
|
|
48
|
+
if chromosome == "Y":
|
|
49
|
+
return 24
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
return int(chromosome)
|
|
53
|
+
except ValueError:
|
|
54
|
+
return 99
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def load_counts(msgpack_dir):
|
|
58
|
+
"""
|
|
59
|
+
Return:
|
|
60
|
+
|
|
61
|
+
counts[chromosome][assembly] = number of variants
|
|
62
|
+
"""
|
|
63
|
+
counts = {}
|
|
64
|
+
|
|
65
|
+
pattern = re.compile(
|
|
66
|
+
r"^(hg18|GRCh37|GRCh38|T2T)-(chr[0-9XY]+)\.msgpack$"
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
for filename in sorted(os.listdir(msgpack_dir)):
|
|
70
|
+
match = pattern.match(filename)
|
|
71
|
+
|
|
72
|
+
if not match:
|
|
73
|
+
continue
|
|
74
|
+
|
|
75
|
+
assembly, chromosome = match.groups()
|
|
76
|
+
file_path = os.path.join(msgpack_dir, filename)
|
|
77
|
+
|
|
78
|
+
with open(file_path, "rb") as file_handle:
|
|
79
|
+
data = msgpack.unpack(
|
|
80
|
+
file_handle,
|
|
81
|
+
raw=False,
|
|
82
|
+
strict_map_key=False,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
counts.setdefault(chromosome, {})
|
|
86
|
+
counts[chromosome][assembly] = len(data)
|
|
87
|
+
|
|
88
|
+
if not counts:
|
|
89
|
+
raise RuntimeError(
|
|
90
|
+
f"No matching msgpack files found in: {msgpack_dir}"
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
return counts
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def get_chromosome_counts(counts):
|
|
97
|
+
"""
|
|
98
|
+
Return one count per chromosome.
|
|
99
|
+
|
|
100
|
+
All available assemblies must have the same count for a chromosome.
|
|
101
|
+
"""
|
|
102
|
+
chromosome_counts = {}
|
|
103
|
+
|
|
104
|
+
for chromosome, assembly_counts in counts.items():
|
|
105
|
+
unique_counts = set(assembly_counts.values())
|
|
106
|
+
|
|
107
|
+
if len(unique_counts) != 1:
|
|
108
|
+
details = ", ".join(
|
|
109
|
+
f"{assembly}={count:,}"
|
|
110
|
+
for assembly, count in sorted(assembly_counts.items())
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
raise ValueError(
|
|
114
|
+
f"Assemblies have different counts for {chromosome}: "
|
|
115
|
+
f"{details}"
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
chromosome_counts[chromosome] = next(iter(unique_counts))
|
|
119
|
+
|
|
120
|
+
return chromosome_counts
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def plot_variants_per_chromosome(chromosome_counts, output_path):
|
|
124
|
+
chromosomes = sorted(
|
|
125
|
+
chromosome_counts,
|
|
126
|
+
key=chromosome_sort_key,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
values = [chromosome_counts[chromosome] for chromosome in chromosomes]
|
|
130
|
+
x_positions = np.arange(len(chromosomes))
|
|
131
|
+
|
|
132
|
+
figure, axis = plt.subplots(figsize=(14, 5))
|
|
133
|
+
|
|
134
|
+
axis.bar(
|
|
135
|
+
x_positions,
|
|
136
|
+
values,
|
|
137
|
+
width=0.7,
|
|
138
|
+
alpha=0.9,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
axis.set_xticks(x_positions)
|
|
142
|
+
axis.set_xticklabels(
|
|
143
|
+
chromosomes,
|
|
144
|
+
rotation=45,
|
|
145
|
+
ha="right",
|
|
146
|
+
fontsize=9,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
axis.yaxis.set_major_formatter(
|
|
150
|
+
mticker.FuncFormatter(lambda value, _: f"{int(value):,}")
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
axis.set_xlabel("Chromosome", fontsize=11)
|
|
154
|
+
axis.set_ylabel("Number of distinguishing variants", fontsize=11)
|
|
155
|
+
axis.set_title(
|
|
156
|
+
"Number of distinguishing variants per chromosome",
|
|
157
|
+
fontsize=13,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
axis.spines[["top", "right"]].set_visible(False)
|
|
161
|
+
|
|
162
|
+
figure.tight_layout()
|
|
163
|
+
figure.savefig(output_path, dpi=150)
|
|
164
|
+
plt.close(figure)
|
|
165
|
+
|
|
166
|
+
print(f"Saved: {output_path}")
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def main():
|
|
170
|
+
parser = argparse.ArgumentParser(
|
|
171
|
+
description=__doc__,
|
|
172
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
parser.add_argument(
|
|
176
|
+
"--dir",
|
|
177
|
+
default=".",
|
|
178
|
+
help="Folder containing the msgpack files",
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
parser.add_argument(
|
|
182
|
+
"--out",
|
|
183
|
+
default=".",
|
|
184
|
+
help="Output folder for the PNG plot",
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
args = parser.parse_args()
|
|
188
|
+
|
|
189
|
+
os.makedirs(args.out, exist_ok=True)
|
|
190
|
+
|
|
191
|
+
print(f"Loading msgpack files from: {os.path.abspath(args.dir)}")
|
|
192
|
+
|
|
193
|
+
counts = load_counts(args.dir)
|
|
194
|
+
chromosome_counts = get_chromosome_counts(counts)
|
|
195
|
+
|
|
196
|
+
print(f"\n{'Chromosome':<12}{'Variants':>15}")
|
|
197
|
+
print("-" * 27)
|
|
198
|
+
|
|
199
|
+
for chromosome in sorted(
|
|
200
|
+
chromosome_counts,
|
|
201
|
+
key=chromosome_sort_key,
|
|
202
|
+
):
|
|
203
|
+
print(
|
|
204
|
+
f"{chromosome:<12}"
|
|
205
|
+
f"{chromosome_counts[chromosome]:>15,}"
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
output_path = os.path.join(
|
|
209
|
+
args.out,
|
|
210
|
+
"variants_per_chromosome.png",
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
plot_variants_per_chromosome(
|
|
214
|
+
chromosome_counts,
|
|
215
|
+
output_path,
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
if __name__ == "__main__":
|
|
220
|
+
main()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import msgpack
|
|
2
|
+
|
|
3
|
+
path = "/home/mireia/GitHub/refgenDetector/src/refgenDetector/msgpacks/GRCh37-chr1.msgpack"
|
|
4
|
+
|
|
5
|
+
with open(path, "rb") as f:
|
|
6
|
+
unpacker = msgpack.Unpacker(
|
|
7
|
+
f,
|
|
8
|
+
raw=False,
|
|
9
|
+
strict_map_key=False # <-- THIS fixes your error
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
for i, obj in enumerate(unpacker):
|
|
13
|
+
print(obj)
|
|
14
|
+
if i == 10:
|
|
15
|
+
break
|
|
@@ -24,6 +24,7 @@ MSGPACK_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "msgpacks
|
|
|
24
24
|
final_results = []
|
|
25
25
|
console = Console(highlight=False)
|
|
26
26
|
_msgpack_cache = {}
|
|
27
|
+
_current_chr = None
|
|
27
28
|
|
|
28
29
|
def gather_and_sum(lists):
|
|
29
30
|
"""
|
|
@@ -54,13 +55,18 @@ def get_matches(snps_dict, chr_):
|
|
|
54
55
|
A list with the number of matches for each version, which is used to infer the reference genome version.
|
|
55
56
|
"""
|
|
56
57
|
|
|
57
|
-
global _msgpack_cache
|
|
58
|
+
global _msgpack_cache, _current_chr
|
|
58
59
|
start = time.time()
|
|
59
60
|
|
|
60
61
|
genome_versions = ["hg18", "GRCh37", "GRCh38", "T2T"]
|
|
61
62
|
matches = []
|
|
62
63
|
|
|
63
|
-
#
|
|
64
|
+
# If we've moved on to a different chromosome, drop the previous
|
|
65
|
+
# chromosome's msgpacks before loading the new ones.
|
|
66
|
+
if chr_ != _current_chr:
|
|
67
|
+
_msgpack_cache.clear()
|
|
68
|
+
_current_chr = chr_
|
|
69
|
+
|
|
64
70
|
positions = np.array(list(snps_dict.keys()), dtype=np.int64)
|
|
65
71
|
nucleotides = np.array(list(snps_dict.values()))
|
|
66
72
|
|
|
@@ -76,16 +82,15 @@ def get_matches(snps_dict, chr_):
|
|
|
76
82
|
|
|
77
83
|
ref_dict = _msgpack_cache[cache_key]
|
|
78
84
|
|
|
79
|
-
# Vectorized: look up all positions at once, compare arrays
|
|
80
85
|
ref_nucs = np.array([ref_dict.get(p, None) for p in positions])
|
|
81
86
|
match_count = int(np.sum(ref_nucs == nucleotides))
|
|
82
87
|
|
|
83
88
|
matches.append([version_name, match_count])
|
|
84
89
|
|
|
85
|
-
#console.print("Getting matches. Took:", time.time() - start, "s")
|
|
86
90
|
return matches
|
|
87
91
|
|
|
88
92
|
|
|
93
|
+
|
|
89
94
|
def trimming_indels(content, ref):
|
|
90
95
|
"""
|
|
91
96
|
If a row is longer than one position it is deleted, deleting this way any indels
|
|
File without changes
|
|
File without changes
|
{refgendetector-3.0.5 → refgendetector-3.0.7}/src/RefgenDetector.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{refgendetector-3.0.5 → refgendetector-3.0.7}/src/refgenDetector/exceptions/NoFileException.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{refgendetector-3.0.5 → refgendetector-3.0.7}/src/refgenDetector/reference_genome_dictionaries.py
RENAMED
|
File without changes
|