malariagen_data 2.0.0__tar.gz → 2.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {malariagen_data-2.0.0 → malariagen_data-2.2.0}/PKG-INFO +2 -1
- {malariagen_data-2.0.0 → malariagen_data-2.2.0}/malariagen_data/ag3.py +518 -160
- {malariagen_data-2.0.0 → malariagen_data-2.2.0}/malariagen_data/util.py +32 -0
- {malariagen_data-2.0.0 → malariagen_data-2.2.0}/pyproject.toml +3 -2
- {malariagen_data-2.0.0 → malariagen_data-2.2.0}/setup.py +2 -1
- {malariagen_data-2.0.0 → malariagen_data-2.2.0}/LICENSE +0 -0
- {malariagen_data-2.0.0 → malariagen_data-2.2.0}/malariagen_data/__init__.py +0 -0
- {malariagen_data-2.0.0 → malariagen_data-2.2.0}/malariagen_data/amin1.py +0 -0
- {malariagen_data-2.0.0 → malariagen_data-2.2.0}/malariagen_data/pf7.py +0 -0
- {malariagen_data-2.0.0 → malariagen_data-2.2.0}/malariagen_data/pf7_config.json +0 -0
- {malariagen_data-2.0.0 → malariagen_data-2.2.0}/malariagen_data/veff.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: malariagen-data
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: A package for accessing MalariaGEN public data.
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Alistair Miles
|
|
@@ -12,6 +12,7 @@ Classifier: Programming Language :: Python :: 3.7
|
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.8
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.9
|
|
14
14
|
Requires-Dist: BioPython
|
|
15
|
+
Requires-Dist: bokeh
|
|
15
16
|
Requires-Dist: dask[array]
|
|
16
17
|
Requires-Dist: fsspec
|
|
17
18
|
Requires-Dist: gcsfs
|
|
@@ -4,15 +4,13 @@ from collections import Counter
|
|
|
4
4
|
|
|
5
5
|
import allel
|
|
6
6
|
import dask.array as da
|
|
7
|
-
import ipyleaflet
|
|
8
|
-
import ipywidgets
|
|
9
7
|
import numba
|
|
10
8
|
import numpy as np
|
|
11
9
|
import pandas as pd
|
|
12
|
-
import plotly.express as px
|
|
13
10
|
import xarray as xr
|
|
14
11
|
import zarr
|
|
15
|
-
|
|
12
|
+
|
|
13
|
+
import malariagen_data
|
|
16
14
|
|
|
17
15
|
from . import veff
|
|
18
16
|
from .util import (
|
|
@@ -145,15 +143,16 @@ class Ag3:
|
|
|
145
143
|
def __repr__(self):
|
|
146
144
|
return (
|
|
147
145
|
f"<MalariaGEN Ag3 data resource API>\n"
|
|
148
|
-
f"Storage URL
|
|
149
|
-
f"
|
|
150
|
-
f"Cohorts analysis
|
|
151
|
-
f"Species analysis
|
|
152
|
-
f"Site filters analysis
|
|
146
|
+
f"Storage URL : {self._url}\n"
|
|
147
|
+
f"Data releases available : {', '.join(self.releases)}\n"
|
|
148
|
+
f"Cohorts analysis : {DEFAULT_COHORTS_ANALYSIS}\n"
|
|
149
|
+
f"Species analysis : {DEFAULT_SPECIES_ANALYSIS}\n"
|
|
150
|
+
f"Site filters analysis : {DEFAULT_SITE_FILTERS_ANALYSIS}\n"
|
|
151
|
+
f"Software version : {malariagen_data.__version__}\n"
|
|
153
152
|
f"---\n"
|
|
154
153
|
f"Please note that data are subject to terms of use,\n"
|
|
155
154
|
f"for more information see https://www.malariagen.net/data\n"
|
|
156
|
-
f"or contact data@malariagen.net. For API documentation see: "
|
|
155
|
+
f"or contact data@malariagen.net. For API documentation see: \n"
|
|
157
156
|
f"https://malariagen.github.io/vector-data/ag3/api.html"
|
|
158
157
|
)
|
|
159
158
|
|
|
@@ -173,10 +172,11 @@ class Ag3:
|
|
|
173
172
|
</thead>
|
|
174
173
|
<tbody>
|
|
175
174
|
<tr><th style="text-align: left">Storage URL</th><td>{self._url}</td></tr>
|
|
176
|
-
<tr><th style="text-align: left">
|
|
175
|
+
<tr><th style="text-align: left">Data releases available</th><td>{', '.join(self.releases)}</td></tr>
|
|
177
176
|
<tr><th style="text-align: left">Cohorts analysis</th><td>{DEFAULT_COHORTS_ANALYSIS}</td></tr>
|
|
178
177
|
<tr><th style="text-align: left">Species analysis</th><td>{DEFAULT_SPECIES_ANALYSIS}</td></tr>
|
|
179
178
|
<tr><th style="text-align: left">Site filters analysis</th><td>{DEFAULT_SITE_FILTERS_ANALYSIS}</td></tr>
|
|
179
|
+
<tr><th style="text-align: left">Software version</th><td>{malariagen_data.__version__}</td></tr>
|
|
180
180
|
</tbody>
|
|
181
181
|
</table>
|
|
182
182
|
"""
|
|
@@ -1287,7 +1287,11 @@ class Ag3:
|
|
|
1287
1287
|
ann.get_effects(transcript=transcript, variants=df_snps)
|
|
1288
1288
|
|
|
1289
1289
|
# add label
|
|
1290
|
-
df_snps["label"] =
|
|
1290
|
+
df_snps["label"] = _pandas_apply(
|
|
1291
|
+
_make_snp_label_effect,
|
|
1292
|
+
df_snps,
|
|
1293
|
+
columns=["contig", "position", "ref_allele", "alt_allele", "aa_change"],
|
|
1294
|
+
)
|
|
1291
1295
|
|
|
1292
1296
|
# set index
|
|
1293
1297
|
df_snps.set_index(
|
|
@@ -1298,7 +1302,11 @@ class Ag3:
|
|
|
1298
1302
|
else:
|
|
1299
1303
|
|
|
1300
1304
|
# add label
|
|
1301
|
-
df_snps["label"] =
|
|
1305
|
+
df_snps["label"] = _pandas_apply(
|
|
1306
|
+
_make_snp_label,
|
|
1307
|
+
df_snps,
|
|
1308
|
+
columns=["contig", "position", "ref_allele", "alt_allele"],
|
|
1309
|
+
)
|
|
1302
1310
|
|
|
1303
1311
|
# set index
|
|
1304
1312
|
df_snps.set_index(
|
|
@@ -1709,7 +1717,7 @@ class Ag3:
|
|
|
1709
1717
|
|
|
1710
1718
|
Parameters
|
|
1711
1719
|
----------
|
|
1712
|
-
contig : str
|
|
1720
|
+
contig : str or list of str
|
|
1713
1721
|
Chromosome arm, e.g., "3R". Multiple values can be provided
|
|
1714
1722
|
as a list, in which case data will be concatenated, e.g., ["2R", "3R"].
|
|
1715
1723
|
sample_sets : str or list of str, optional
|
|
@@ -1884,7 +1892,7 @@ class Ag3:
|
|
|
1884
1892
|
|
|
1885
1893
|
Parameters
|
|
1886
1894
|
----------
|
|
1887
|
-
contig : str
|
|
1895
|
+
contig : str or list of str
|
|
1888
1896
|
Chromosome arm, e.g., "3R". Multiple values can be provided
|
|
1889
1897
|
as a list, in which case data will be concatenated, e.g., ["2R", "3R"].
|
|
1890
1898
|
sample_set : str
|
|
@@ -2037,7 +2045,7 @@ class Ag3:
|
|
|
2037
2045
|
|
|
2038
2046
|
Parameters
|
|
2039
2047
|
----------
|
|
2040
|
-
contig : str
|
|
2048
|
+
contig : str or list of str
|
|
2041
2049
|
Chromosome arm, e.g., "3R". Multiple values can be provided
|
|
2042
2050
|
as a list, in which case data will be concatenated, e.g., ["2R", "3R"].
|
|
2043
2051
|
sample_sets : str or list of str, optional
|
|
@@ -2088,8 +2096,9 @@ class Ag3:
|
|
|
2088
2096
|
|
|
2089
2097
|
Parameters
|
|
2090
2098
|
----------
|
|
2091
|
-
contig : str
|
|
2092
|
-
Chromosome arm, e.g., "3R".
|
|
2099
|
+
contig : str or list of str
|
|
2100
|
+
Chromosome arm, e.g., "3R". Multiple values can be provided
|
|
2101
|
+
as a list, in which case data will be concatenated, e.g., ["2R", "3R"].
|
|
2093
2102
|
sample_sets : str or list of str
|
|
2094
2103
|
Can be a sample set identifier (e.g., "AG1000G-AO") or a list of sample set
|
|
2095
2104
|
identifiers (e.g., ["AG1000G-BF-A", "AG1000G-BF-B"]) or a release identifier (e.g.,
|
|
@@ -2102,6 +2111,22 @@ class Ag3:
|
|
|
2102
2111
|
|
|
2103
2112
|
"""
|
|
2104
2113
|
|
|
2114
|
+
# handle multiple contigs
|
|
2115
|
+
if isinstance(contig, str):
|
|
2116
|
+
contig = [contig]
|
|
2117
|
+
|
|
2118
|
+
ds = xarray_concat(
|
|
2119
|
+
[self._gene_cnv(contig=c, sample_sets=sample_sets) for c in contig],
|
|
2120
|
+
dim="genes",
|
|
2121
|
+
)
|
|
2122
|
+
|
|
2123
|
+
return ds
|
|
2124
|
+
|
|
2125
|
+
def _gene_cnv(self, *, contig, sample_sets):
|
|
2126
|
+
|
|
2127
|
+
# sanity check
|
|
2128
|
+
assert isinstance(contig, str)
|
|
2129
|
+
|
|
2105
2130
|
# access HMM data
|
|
2106
2131
|
ds_hmm = self.cnv_hmm(contig=contig, sample_sets=sample_sets)
|
|
2107
2132
|
pos = ds_hmm["variant_position"].values
|
|
@@ -2111,6 +2136,7 @@ class Ag3:
|
|
|
2111
2136
|
# access genes
|
|
2112
2137
|
df_geneset = self.geneset()
|
|
2113
2138
|
df_genes = df_geneset.query(f"type == 'gene' and contig == '{contig}'")
|
|
2139
|
+
n_genes = len(df_genes)
|
|
2114
2140
|
|
|
2115
2141
|
# setup intermediates
|
|
2116
2142
|
windows = []
|
|
@@ -2143,14 +2169,16 @@ class Ag3:
|
|
|
2143
2169
|
ds_out = xr.Dataset(
|
|
2144
2170
|
coords={
|
|
2145
2171
|
"gene_id": (["genes"], df_genes["ID"].values),
|
|
2146
|
-
"gene_start": (["genes"], df_genes["start"].values),
|
|
2147
|
-
"gene_end": (["genes"], df_genes["end"].values),
|
|
2148
2172
|
"sample_id": (["samples"], ds_hmm["sample_id"].values),
|
|
2149
2173
|
},
|
|
2150
2174
|
data_vars={
|
|
2175
|
+
"gene_contig": (["genes"], np.array([contig] * n_genes, dtype=object)),
|
|
2176
|
+
"gene_start": (["genes"], df_genes["start"].values),
|
|
2177
|
+
"gene_end": (["genes"], df_genes["end"].values),
|
|
2151
2178
|
"gene_windows": (["genes"], windows),
|
|
2152
2179
|
"gene_name": (["genes"], df_genes["Name"].values),
|
|
2153
2180
|
"gene_strand": (["genes"], df_genes["strand"].values),
|
|
2181
|
+
"gene_description": (["genes"], df_genes["description"].values),
|
|
2154
2182
|
"CN_mode": (["genes", "samples"], modes),
|
|
2155
2183
|
"CN_mode_count": (["genes", "samples"], counts),
|
|
2156
2184
|
"sample_coverage_variance": (
|
|
@@ -2183,8 +2211,9 @@ class Ag3:
|
|
|
2183
2211
|
|
|
2184
2212
|
Parameters
|
|
2185
2213
|
----------
|
|
2186
|
-
contig : str
|
|
2187
|
-
Chromosome arm, e.g., "3R".
|
|
2214
|
+
contig : str or list of str
|
|
2215
|
+
Chromosome arm, e.g., "3R". Multiple values can be provided
|
|
2216
|
+
as a list, in which case data will be concatenated, e.g., ["2R", "3R"].
|
|
2188
2217
|
cohorts : str or dict
|
|
2189
2218
|
If a string, gives the name of a predefined cohort set, e.g., one of
|
|
2190
2219
|
{"admin1_month", "admin1_year", "admin2_month", "admin2_year"}.
|
|
@@ -2221,6 +2250,46 @@ class Ag3:
|
|
|
2221
2250
|
# check parameters
|
|
2222
2251
|
_check_param_min_cohort_size(min_cohort_size)
|
|
2223
2252
|
|
|
2253
|
+
if isinstance(contig, str):
|
|
2254
|
+
contig = [contig]
|
|
2255
|
+
|
|
2256
|
+
df = pd.concat(
|
|
2257
|
+
[
|
|
2258
|
+
self._gene_cnv_frequencies(
|
|
2259
|
+
contig=c,
|
|
2260
|
+
cohorts=cohorts,
|
|
2261
|
+
sample_query=sample_query,
|
|
2262
|
+
cohorts_analysis=cohorts_analysis,
|
|
2263
|
+
min_cohort_size=min_cohort_size,
|
|
2264
|
+
species_analysis=species_analysis,
|
|
2265
|
+
sample_sets=sample_sets,
|
|
2266
|
+
drop_invariant=drop_invariant,
|
|
2267
|
+
max_coverage_variance=max_coverage_variance,
|
|
2268
|
+
)
|
|
2269
|
+
for c in contig
|
|
2270
|
+
],
|
|
2271
|
+
axis=0,
|
|
2272
|
+
)
|
|
2273
|
+
|
|
2274
|
+
return df
|
|
2275
|
+
|
|
2276
|
+
def _gene_cnv_frequencies(
|
|
2277
|
+
self,
|
|
2278
|
+
*,
|
|
2279
|
+
contig,
|
|
2280
|
+
cohorts,
|
|
2281
|
+
sample_query,
|
|
2282
|
+
cohorts_analysis,
|
|
2283
|
+
min_cohort_size,
|
|
2284
|
+
species_analysis,
|
|
2285
|
+
sample_sets,
|
|
2286
|
+
drop_invariant,
|
|
2287
|
+
max_coverage_variance,
|
|
2288
|
+
):
|
|
2289
|
+
|
|
2290
|
+
# sanity check - this function is one contig at a time
|
|
2291
|
+
assert isinstance(contig, str)
|
|
2292
|
+
|
|
2224
2293
|
# load sample metadata
|
|
2225
2294
|
df_samples = self.sample_metadata(
|
|
2226
2295
|
sample_sets=sample_sets,
|
|
@@ -2245,9 +2314,6 @@ class Ag3:
|
|
|
2245
2314
|
else:
|
|
2246
2315
|
loc_samples = loc_pass_samples
|
|
2247
2316
|
|
|
2248
|
-
# get genes
|
|
2249
|
-
df_genes = self.geneset().query(f"type == 'gene' and contig == '{contig}'")
|
|
2250
|
-
|
|
2251
2317
|
# figure out expected copy number
|
|
2252
2318
|
if contig == "X":
|
|
2253
2319
|
is_male = (df_samples["sex_call"] == "M").values
|
|
@@ -2255,20 +2321,25 @@ class Ag3:
|
|
|
2255
2321
|
else:
|
|
2256
2322
|
expected_cn = 2
|
|
2257
2323
|
|
|
2258
|
-
# setup output dataframe
|
|
2259
|
-
n_genes =
|
|
2324
|
+
# setup output dataframe - two rows for each gene, one for amplification and one for deletion
|
|
2325
|
+
n_genes = ds_cnv.dims["genes"]
|
|
2326
|
+
df_genes = ds_cnv[
|
|
2327
|
+
[
|
|
2328
|
+
"gene_id",
|
|
2329
|
+
"gene_name",
|
|
2330
|
+
"gene_strand",
|
|
2331
|
+
"gene_description",
|
|
2332
|
+
"gene_contig",
|
|
2333
|
+
"gene_start",
|
|
2334
|
+
"gene_end",
|
|
2335
|
+
]
|
|
2336
|
+
].to_dataframe()
|
|
2260
2337
|
df = pd.concat([df_genes, df_genes], axis=0).reset_index(drop=True)
|
|
2261
|
-
|
|
2262
|
-
# drop columns we don't need
|
|
2263
|
-
df.drop(columns=["source", "type", "score", "phase", "Parent"], inplace=True)
|
|
2264
|
-
|
|
2265
|
-
# rename some columns
|
|
2266
2338
|
df.rename(
|
|
2267
2339
|
columns={
|
|
2268
|
-
"
|
|
2269
|
-
"
|
|
2270
|
-
"
|
|
2271
|
-
"description": "gene_description",
|
|
2340
|
+
"gene_contig": "contig",
|
|
2341
|
+
"gene_start": "start",
|
|
2342
|
+
"gene_end": "end",
|
|
2272
2343
|
},
|
|
2273
2344
|
inplace=True,
|
|
2274
2345
|
)
|
|
@@ -2329,9 +2400,12 @@ class Ag3:
|
|
|
2329
2400
|
df.reset_index(drop=True, inplace=True)
|
|
2330
2401
|
df = pd.concat([df, df_freqs, df_extras], axis=1)
|
|
2331
2402
|
df.sort_values(["contig", "start", "cnv_type"], inplace=True)
|
|
2403
|
+
df.reset_index(drop=True, inplace=True)
|
|
2332
2404
|
|
|
2333
2405
|
# add label
|
|
2334
|
-
df["label"] =
|
|
2406
|
+
df["label"] = _pandas_apply(
|
|
2407
|
+
_make_gene_cnv_label, df, columns=["gene_id", "gene_name", "cnv_type"]
|
|
2408
|
+
)
|
|
2335
2409
|
|
|
2336
2410
|
# deal with invariants
|
|
2337
2411
|
if drop_invariant:
|
|
@@ -2709,7 +2783,11 @@ class Ag3:
|
|
|
2709
2783
|
df_aaf["max_af"] = df_aaf[freq_cols].max(axis=1)
|
|
2710
2784
|
|
|
2711
2785
|
# add label
|
|
2712
|
-
df_aaf["label"] =
|
|
2786
|
+
df_aaf["label"] = _pandas_apply(
|
|
2787
|
+
_make_snp_label_aa,
|
|
2788
|
+
df_aaf,
|
|
2789
|
+
columns=["aa_change", "contig", "position", "ref_allele", "alt_allele"],
|
|
2790
|
+
)
|
|
2713
2791
|
|
|
2714
2792
|
# sort by genomic position
|
|
2715
2793
|
df_aaf = df_aaf.sort_values(["position", "aa_change"])
|
|
@@ -2743,20 +2821,23 @@ class Ag3:
|
|
|
2743
2821
|
title=True,
|
|
2744
2822
|
**kwargs,
|
|
2745
2823
|
):
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2824
|
+
"""Plot a heatmap from a pandas DataFrame of frequencies, e.g., output
|
|
2825
|
+
from `Ag3.snp_allele_frequencies()` or `Ag3.gene_cnv_frequencies()`.
|
|
2826
|
+
It's recommended to filter the input DataFrame to just rows of interest,
|
|
2827
|
+
i.e., fewer rows than `max_len`.
|
|
2750
2828
|
|
|
2751
2829
|
Parameters
|
|
2752
2830
|
----------
|
|
2753
2831
|
df : pandas DataFrame
|
|
2754
|
-
A DataFrame of frequencies, e.g., output from
|
|
2832
|
+
A DataFrame of frequencies, e.g., output from
|
|
2833
|
+
`snp_allele_frequencies()` or `gene_cnv_frequencies()`.
|
|
2755
2834
|
index : str or list of str
|
|
2756
|
-
One or more column headers that are present in the input dataframe.
|
|
2757
|
-
row labels. The column/s must
|
|
2835
|
+
One or more column headers that are present in the input dataframe.
|
|
2836
|
+
This becomes the heatmap y-axis row labels. The column/s must
|
|
2837
|
+
produce a unique index.
|
|
2758
2838
|
max_len : int, optional
|
|
2759
|
-
Displaying large styled dataframes may cause ipython notebooks to
|
|
2839
|
+
Displaying large styled dataframes may cause ipython notebooks to
|
|
2840
|
+
crash.
|
|
2760
2841
|
x_label : str, optional
|
|
2761
2842
|
This is the x-axis label that will be displayed on the heatmap.
|
|
2762
2843
|
y_label : str, optional
|
|
@@ -2781,6 +2862,8 @@ class Ag3:
|
|
|
2781
2862
|
|
|
2782
2863
|
"""
|
|
2783
2864
|
|
|
2865
|
+
import plotly.express as px
|
|
2866
|
+
|
|
2784
2867
|
# check len of input
|
|
2785
2868
|
if len(df) > max_len:
|
|
2786
2869
|
raise ValueError(f"Input DataFrame is longer than {max_len}")
|
|
@@ -2871,39 +2954,40 @@ class Ag3:
|
|
|
2871
2954
|
species_analysis=DEFAULT_SPECIES_ANALYSIS,
|
|
2872
2955
|
site_filters_analysis=DEFAULT_SITE_FILTERS_ANALYSIS,
|
|
2873
2956
|
):
|
|
2874
|
-
"""Group samples by taxon, area (space) and period (time), then compute
|
|
2875
|
-
and frequencies.
|
|
2957
|
+
"""Group samples by taxon, area (space) and period (time), then compute
|
|
2958
|
+
SNP allele counts and frequencies.
|
|
2876
2959
|
|
|
2877
2960
|
Parameters
|
|
2878
2961
|
----------
|
|
2879
2962
|
transcript : str
|
|
2880
2963
|
Gene transcript ID (AgamP4.12), e.g., "AGAP004707-RD".
|
|
2881
2964
|
area_by : str
|
|
2882
|
-
Column name in the sample metadata to use to group samples
|
|
2883
|
-
use "
|
|
2884
|
-
or use "
|
|
2965
|
+
Column name in the sample metadata to use to group samples
|
|
2966
|
+
spatially. E.g., use "admin1_iso" or "admin1_name" to group by level 1
|
|
2967
|
+
administrative divisions, or use "admin2_name" to group by level 2
|
|
2968
|
+
administrative divisions.
|
|
2885
2969
|
period_by : {"year", "quarter", "month"}
|
|
2886
2970
|
Length of time to group samples temporally.
|
|
2887
2971
|
sample_sets : str or list of str, optional
|
|
2888
|
-
Can be a sample set identifier (e.g., "AG1000G-AO") or a list of
|
|
2889
|
-
identifiers (e.g., ["AG1000G-BF-A", "AG1000G-BF-B"]) or a
|
|
2890
|
-
"3.0") or a list of release identifiers.
|
|
2972
|
+
Can be a sample set identifier (e.g., "AG1000G-AO") or a list of
|
|
2973
|
+
sample set identifiers (e.g., ["AG1000G-BF-A", "AG1000G-BF-B"]) or a
|
|
2974
|
+
release identifier (e.g., "3.0") or a list of release identifiers.
|
|
2891
2975
|
sample_query : str, optional
|
|
2892
|
-
A pandas query string which will be evaluated against the sample
|
|
2893
|
-
"taxon == 'coluzzii' and country == 'Burkina Faso'".
|
|
2976
|
+
A pandas query string which will be evaluated against the sample
|
|
2977
|
+
metadata e.g., "taxon == 'coluzzii' and country == 'Burkina Faso'".
|
|
2894
2978
|
min_cohort_size : int, optional
|
|
2895
2979
|
Minimum cohort size. Any cohorts below this size are omitted.
|
|
2896
2980
|
drop_invariant : bool, optional
|
|
2897
|
-
If True, variants with no alternate allele calls in any cohorts are
|
|
2898
|
-
the result.
|
|
2981
|
+
If True, variants with no alternate allele calls in any cohorts are
|
|
2982
|
+
dropped from the result.
|
|
2899
2983
|
variant_query : str, optional
|
|
2900
2984
|
site_mask : str, optional
|
|
2901
2985
|
Site filters mask to apply.
|
|
2902
2986
|
nobs_mode : {"called", "fixed"}
|
|
2903
|
-
Method for calculating the denominator when computing frequencies.
|
|
2904
|
-
then use the number of called alleles, i.e., number of
|
|
2905
|
-
genotype calls multiplied by 2. If "fixed"
|
|
2906
|
-
multiplied by 2.
|
|
2987
|
+
Method for calculating the denominator when computing frequencies.
|
|
2988
|
+
If "called" then use the number of called alleles, i.e., number of
|
|
2989
|
+
samples with non-missing genotype calls multiplied by 2. If "fixed"
|
|
2990
|
+
then use the number of samples multiplied by 2.
|
|
2907
2991
|
ci_method : {"normal", "agresti_coull", "beta", "wilson", "binom_test"}, optional
|
|
2908
2992
|
Method to use for computing confidence intervals, passed through to
|
|
2909
2993
|
`statsmodels.stats.proportion.proportion_confint`.
|
|
@@ -2918,11 +3002,11 @@ class Ag3:
|
|
|
2918
3002
|
-------
|
|
2919
3003
|
ds : xarray.Dataset
|
|
2920
3004
|
The resulting dataset contains data has dimensions "cohorts" and "variants".
|
|
2921
|
-
Variables prefixed with "
|
|
3005
|
+
Variables prefixed with "cohort" are 1-dimensional arrays with data about
|
|
2922
3006
|
the cohorts, such as the area, period, taxon and cohort size. Variables
|
|
2923
|
-
prefixed with "
|
|
3007
|
+
prefixed with "variant" are 1-dimensional arrays with data about the variants,
|
|
2924
3008
|
such as the contig, position, reference and alternate alleles. Variables prefixed
|
|
2925
|
-
with "
|
|
3009
|
+
with "event" are 2-dimensional arrays with the allele counts and frequency
|
|
2926
3010
|
calculations.
|
|
2927
3011
|
|
|
2928
3012
|
"""
|
|
@@ -2976,8 +3060,8 @@ class Ag3:
|
|
|
2976
3060
|
# bring genotypes into memory
|
|
2977
3061
|
gt = gt.compute()
|
|
2978
3062
|
|
|
2979
|
-
# convert genotypes to more convenient representation
|
|
2980
|
-
gac, gan = _genotypes_to_alt_allele_counts_melt(gt, max_allele=3)
|
|
3063
|
+
# # convert genotypes to more convenient representation
|
|
3064
|
+
# gac, gan = _genotypes_to_alt_allele_counts_melt(gt, max_allele=3)
|
|
2981
3065
|
|
|
2982
3066
|
# set up variant variables
|
|
2983
3067
|
contigs = ds_snps.attrs["contigs"]
|
|
@@ -3013,13 +3097,18 @@ class Ag3:
|
|
|
3013
3097
|
# compute cohort allele counts
|
|
3014
3098
|
# cohort_gac = np.take(gac, sample_indices, axis=1)
|
|
3015
3099
|
# np.sum(cohort_gac, axis=1, out=count[:, cohort_index])
|
|
3016
|
-
count[:, cohort_index] = _take_sum_cols(gac, sample_indices)
|
|
3100
|
+
# count[:, cohort_index] = _take_sum_cols(gac, sample_indices)
|
|
3101
|
+
cohort_ac, cohort_an = _cohort_alt_allele_counts_melt(
|
|
3102
|
+
gt, sample_indices, max_allele=3
|
|
3103
|
+
)
|
|
3104
|
+
count[:, cohort_index] = cohort_ac
|
|
3017
3105
|
|
|
3018
3106
|
# compute cohort allele numbers
|
|
3019
3107
|
if nobs_mode == "called":
|
|
3020
3108
|
# cohort_gan = np.take(gan, sample_indices, axis=1)
|
|
3021
3109
|
# np.sum(cohort_gan, axis=1, out=nobs[:, cohort_index])
|
|
3022
|
-
nobs[:, cohort_index] = _take_sum_cols(gan, sample_indices)
|
|
3110
|
+
# nobs[:, cohort_index] = _take_sum_cols(gan, sample_indices)
|
|
3111
|
+
nobs[:, cohort_index] = cohort_an
|
|
3023
3112
|
elif nobs_mode == "fixed":
|
|
3024
3113
|
nobs[:, cohort_index] = cohort.size * 2
|
|
3025
3114
|
else:
|
|
@@ -3053,7 +3142,7 @@ class Ag3:
|
|
|
3053
3142
|
# deal with SNP alleles not observed
|
|
3054
3143
|
if drop_invariant:
|
|
3055
3144
|
loc_variant = max_af > 0
|
|
3056
|
-
df_variants = df_variants.loc[loc_variant]
|
|
3145
|
+
df_variants = df_variants.loc[loc_variant].reset_index(drop=True)
|
|
3057
3146
|
count = np.compress(loc_variant, count, axis=0)
|
|
3058
3147
|
nobs = np.compress(loc_variant, nobs, axis=0)
|
|
3059
3148
|
frequency = np.compress(loc_variant, frequency, axis=0)
|
|
@@ -3065,7 +3154,11 @@ class Ag3:
|
|
|
3065
3154
|
ann.get_effects(transcript=transcript, variants=df_variants)
|
|
3066
3155
|
|
|
3067
3156
|
# add variant labels
|
|
3068
|
-
df_variants["label"] =
|
|
3157
|
+
df_variants["label"] = _pandas_apply(
|
|
3158
|
+
_make_snp_label_effect,
|
|
3159
|
+
df_variants,
|
|
3160
|
+
columns=["contig", "position", "ref_allele", "alt_allele", "aa_change"],
|
|
3161
|
+
)
|
|
3069
3162
|
|
|
3070
3163
|
# build the output dataset
|
|
3071
3164
|
ds_out = xr.Dataset()
|
|
@@ -3129,8 +3222,8 @@ class Ag3:
|
|
|
3129
3222
|
Gene transcript ID (AgamP4.12), e.g., "AGAP004707-RD".
|
|
3130
3223
|
area_by : str
|
|
3131
3224
|
Column name in the sample metadata to use to group samples spatially. E.g.,
|
|
3132
|
-
use "
|
|
3133
|
-
or use "
|
|
3225
|
+
use "admin1_iso" or "admin1_name" to group by level 1 administrative divisions,
|
|
3226
|
+
or use "admin2_name" to group by level 2 administrative divisions.
|
|
3134
3227
|
period_by : {"year", "quarter", "month"}
|
|
3135
3228
|
Length of time to group samples temporally.
|
|
3136
3229
|
sample_sets : str or list of str, optional
|
|
@@ -3164,11 +3257,11 @@ class Ag3:
|
|
|
3164
3257
|
-------
|
|
3165
3258
|
ds : xarray.Dataset
|
|
3166
3259
|
The resulting dataset contains data has dimensions "cohorts" and "variants".
|
|
3167
|
-
Variables prefixed with "
|
|
3260
|
+
Variables prefixed with "cohort" are 1-dimensional arrays with data about
|
|
3168
3261
|
the cohorts, such as the area, period, taxon and cohort size. Variables
|
|
3169
|
-
prefixed with "
|
|
3262
|
+
prefixed with "variant" are 1-dimensional arrays with data about the variants,
|
|
3170
3263
|
such as the contig, position, reference and alternate alleles. Variables prefixed
|
|
3171
|
-
with "
|
|
3264
|
+
with "event" are 2-dimensional arrays with the allele counts and frequency
|
|
3172
3265
|
calculations.
|
|
3173
3266
|
|
|
3174
3267
|
"""
|
|
@@ -3241,7 +3334,11 @@ class Ag3:
|
|
|
3241
3334
|
df_variants.columns = [c.split("variant_")[1] for c in df_variants.columns]
|
|
3242
3335
|
|
|
3243
3336
|
# assign new variant label
|
|
3244
|
-
label =
|
|
3337
|
+
label = _pandas_apply(
|
|
3338
|
+
_make_snp_label_aa,
|
|
3339
|
+
df_variants,
|
|
3340
|
+
columns=["aa_change", "contig", "position", "ref_allele", "alt_allele"],
|
|
3341
|
+
)
|
|
3245
3342
|
ds_aa_frq["variant_label"] = "variants", label
|
|
3246
3343
|
|
|
3247
3344
|
# apply variant query if given
|
|
@@ -3285,12 +3382,13 @@ class Ag3:
|
|
|
3285
3382
|
|
|
3286
3383
|
Parameters
|
|
3287
3384
|
----------
|
|
3288
|
-
contig : str
|
|
3289
|
-
Chromosome arm, e.g., "3R".
|
|
3385
|
+
contig : str or list of str
|
|
3386
|
+
Chromosome arm, e.g., "3R". Multiple values can be provided
|
|
3387
|
+
as a list, in which case data will be concatenated, e.g., ["2R", "3R"].
|
|
3290
3388
|
area_by : str
|
|
3291
3389
|
Column name in the sample metadata to use to group samples spatially. E.g.,
|
|
3292
|
-
use "
|
|
3293
|
-
or use "
|
|
3390
|
+
use "admin1_iso" or "admin1_name" to group by level 1 administrative divisions,
|
|
3391
|
+
or use "admin2_name" to group by level 2 administrative divisions.
|
|
3294
3392
|
period_by : {"year", "quarter", "month"}
|
|
3295
3393
|
Length of time to group samples temporally.
|
|
3296
3394
|
sample_sets : str or list of str, optional
|
|
@@ -3319,11 +3417,11 @@ class Ag3:
|
|
|
3319
3417
|
-------
|
|
3320
3418
|
ds : xarray.Dataset
|
|
3321
3419
|
The resulting dataset contains data has dimensions "cohorts" and "variants".
|
|
3322
|
-
Variables prefixed with "
|
|
3420
|
+
Variables prefixed with "cohort" are 1-dimensional arrays with data about
|
|
3323
3421
|
the cohorts, such as the area, period, taxon and cohort size. Variables
|
|
3324
|
-
prefixed with "
|
|
3422
|
+
prefixed with "variant" are 1-dimensional arrays with data about the variants,
|
|
3325
3423
|
such as the contig, position, reference and alternate alleles. Variables prefixed
|
|
3326
|
-
with "
|
|
3424
|
+
with "event" are 2-dimensional arrays with the allele counts and frequency
|
|
3327
3425
|
calculations.
|
|
3328
3426
|
|
|
3329
3427
|
"""
|
|
@@ -3331,6 +3429,52 @@ class Ag3:
|
|
|
3331
3429
|
# check parameters
|
|
3332
3430
|
_check_param_min_cohort_size(min_cohort_size)
|
|
3333
3431
|
|
|
3432
|
+
if isinstance(contig, str):
|
|
3433
|
+
contig = [contig]
|
|
3434
|
+
|
|
3435
|
+
ds = xarray_concat(
|
|
3436
|
+
[
|
|
3437
|
+
self._gene_cnv_frequencies_advanced(
|
|
3438
|
+
contig=c,
|
|
3439
|
+
area_by=area_by,
|
|
3440
|
+
period_by=period_by,
|
|
3441
|
+
sample_sets=sample_sets,
|
|
3442
|
+
sample_query=sample_query,
|
|
3443
|
+
min_cohort_size=min_cohort_size,
|
|
3444
|
+
variant_query=variant_query,
|
|
3445
|
+
drop_invariant=drop_invariant,
|
|
3446
|
+
max_coverage_variance=max_coverage_variance,
|
|
3447
|
+
ci_method=ci_method,
|
|
3448
|
+
cohorts_analysis=cohorts_analysis,
|
|
3449
|
+
species_analysis=species_analysis,
|
|
3450
|
+
)
|
|
3451
|
+
for c in contig
|
|
3452
|
+
],
|
|
3453
|
+
dim="variants",
|
|
3454
|
+
)
|
|
3455
|
+
|
|
3456
|
+
return ds
|
|
3457
|
+
|
|
3458
|
+
def _gene_cnv_frequencies_advanced(
|
|
3459
|
+
self,
|
|
3460
|
+
*,
|
|
3461
|
+
contig,
|
|
3462
|
+
area_by,
|
|
3463
|
+
period_by,
|
|
3464
|
+
sample_sets,
|
|
3465
|
+
sample_query,
|
|
3466
|
+
min_cohort_size,
|
|
3467
|
+
variant_query,
|
|
3468
|
+
drop_invariant,
|
|
3469
|
+
max_coverage_variance,
|
|
3470
|
+
ci_method,
|
|
3471
|
+
cohorts_analysis,
|
|
3472
|
+
species_analysis,
|
|
3473
|
+
):
|
|
3474
|
+
|
|
3475
|
+
# sanity check - here we deal with one contig only
|
|
3476
|
+
assert isinstance(contig, str)
|
|
3477
|
+
|
|
3334
3478
|
# load sample metadata
|
|
3335
3479
|
df_samples = self.sample_metadata(
|
|
3336
3480
|
sample_sets=sample_sets,
|
|
@@ -3439,7 +3583,11 @@ class Ag3:
|
|
|
3439
3583
|
)
|
|
3440
3584
|
|
|
3441
3585
|
# add variant label
|
|
3442
|
-
df_variants["label"] =
|
|
3586
|
+
df_variants["label"] = _pandas_apply(
|
|
3587
|
+
_make_gene_cnv_label,
|
|
3588
|
+
df_variants,
|
|
3589
|
+
columns=["gene_id", "gene_name", "cnv_type"],
|
|
3590
|
+
)
|
|
3443
3591
|
|
|
3444
3592
|
# build the output dataset
|
|
3445
3593
|
ds_out = xr.Dataset()
|
|
@@ -3461,7 +3609,7 @@ class Ag3:
|
|
|
3461
3609
|
if drop_invariant:
|
|
3462
3610
|
loc_variant = df_variants["max_af"].values > 0
|
|
3463
3611
|
ds_out = ds_out.isel(variants=loc_variant)
|
|
3464
|
-
df_variants = df_variants.loc[loc_variant]
|
|
3612
|
+
df_variants = df_variants.loc[loc_variant].reset_index(drop=True)
|
|
3465
3613
|
|
|
3466
3614
|
# apply variant query
|
|
3467
3615
|
if variant_query is not None:
|
|
@@ -3508,6 +3656,8 @@ class Ag3:
|
|
|
3508
3656
|
|
|
3509
3657
|
"""
|
|
3510
3658
|
|
|
3659
|
+
import plotly.express as px
|
|
3660
|
+
|
|
3511
3661
|
# handle title
|
|
3512
3662
|
if title is True:
|
|
3513
3663
|
title = ds.attrs.get("title", None)
|
|
@@ -3610,6 +3760,9 @@ class Ag3:
|
|
|
3610
3760
|
|
|
3611
3761
|
"""
|
|
3612
3762
|
|
|
3763
|
+
import ipyleaflet
|
|
3764
|
+
import ipywidgets
|
|
3765
|
+
|
|
3613
3766
|
# slice dataset to variant of interest
|
|
3614
3767
|
if isinstance(variant, int):
|
|
3615
3768
|
ds_variant = ds.isel(variants=variant)
|
|
@@ -3710,6 +3863,9 @@ class Ag3:
|
|
|
3710
3863
|
|
|
3711
3864
|
"""
|
|
3712
3865
|
|
|
3866
|
+
import ipyleaflet
|
|
3867
|
+
import ipywidgets
|
|
3868
|
+
|
|
3713
3869
|
# handle title
|
|
3714
3870
|
if title is True:
|
|
3715
3871
|
title = ds.attrs.get("title", None)
|
|
@@ -3744,6 +3900,248 @@ class Ag3:
|
|
|
3744
3900
|
|
|
3745
3901
|
return out
|
|
3746
3902
|
|
|
3903
|
+
def resolve_region(self, region):
|
|
3904
|
+
"""Convert a genome region into a standard data structure.
|
|
3905
|
+
|
|
3906
|
+
Parameters
|
|
3907
|
+
----------
|
|
3908
|
+
region: str
|
|
3909
|
+
Chromosome arm (e.g., "2L"), gene name (e.g., "AGAP007280") or genomic
|
|
3910
|
+
region defined with coordinates (e.g., "2L:44989425-44998059").
|
|
3911
|
+
|
|
3912
|
+
Returns
|
|
3913
|
+
-------
|
|
3914
|
+
out : Region
|
|
3915
|
+
A named tuple with attributes contig, start and end.
|
|
3916
|
+
|
|
3917
|
+
"""
|
|
3918
|
+
|
|
3919
|
+
return resolve_region(self, region)
|
|
3920
|
+
|
|
3921
|
+
def plot_genes(
|
|
3922
|
+
self,
|
|
3923
|
+
region,
|
|
3924
|
+
width=700,
|
|
3925
|
+
height=120,
|
|
3926
|
+
show=True,
|
|
3927
|
+
toolbar_location="above",
|
|
3928
|
+
x_range=None,
|
|
3929
|
+
title="Genes",
|
|
3930
|
+
):
|
|
3931
|
+
"""@@TODO"""
|
|
3932
|
+
|
|
3933
|
+
import bokeh.models as bkmod
|
|
3934
|
+
import bokeh.plotting as bkplt
|
|
3935
|
+
|
|
3936
|
+
# handle region parameter - this determines the genome region to plot
|
|
3937
|
+
region = self.resolve_region(region)
|
|
3938
|
+
contig = region.contig
|
|
3939
|
+
start = region.start
|
|
3940
|
+
end = region.end
|
|
3941
|
+
if start is None:
|
|
3942
|
+
start = 0
|
|
3943
|
+
if end is None:
|
|
3944
|
+
end = len(self.genome_sequence(contig))
|
|
3945
|
+
|
|
3946
|
+
# define x axis range
|
|
3947
|
+
if x_range is None:
|
|
3948
|
+
x_range = bkmod.Range1d(start, end, bounds="auto")
|
|
3949
|
+
|
|
3950
|
+
# select the genes overlapping the requested region
|
|
3951
|
+
df_geneset = self.geneset(attributes=["ID", "Name", "Parent", "description"])
|
|
3952
|
+
# df_geneset = df_geneset.set_index("ID")
|
|
3953
|
+
data = df_geneset.query(
|
|
3954
|
+
f"type == 'gene' and contig == '{contig}' and start < {end} and end > {start}"
|
|
3955
|
+
).copy()
|
|
3956
|
+
|
|
3957
|
+
# we're going to plot each gene as a rectangle, so add some additional
|
|
3958
|
+
# columns
|
|
3959
|
+
data["bottom"] = np.where(data["strand"] == "+", 1, 0)
|
|
3960
|
+
data["top"] = data["bottom"] + 0.8
|
|
3961
|
+
|
|
3962
|
+
# tidy up some columns for presentation
|
|
3963
|
+
data["Name"].fillna("", inplace=True)
|
|
3964
|
+
data["description"].fillna("", inplace=True)
|
|
3965
|
+
|
|
3966
|
+
# define tooltips for hover
|
|
3967
|
+
tooltips = [
|
|
3968
|
+
("ID", "@ID"),
|
|
3969
|
+
("Name", "@Name"),
|
|
3970
|
+
("Description", "@description"),
|
|
3971
|
+
("Location", "@contig:@start{,}-@end{,}"),
|
|
3972
|
+
]
|
|
3973
|
+
|
|
3974
|
+
# make a figure
|
|
3975
|
+
fig = bkplt.figure(
|
|
3976
|
+
title=title,
|
|
3977
|
+
plot_width=width,
|
|
3978
|
+
plot_height=height,
|
|
3979
|
+
tools="xpan,xzoom_in,xzoom_out,xwheel_zoom,reset,tap,hover",
|
|
3980
|
+
toolbar_location=toolbar_location,
|
|
3981
|
+
active_scroll="xwheel_zoom",
|
|
3982
|
+
active_drag="xpan",
|
|
3983
|
+
tooltips=tooltips,
|
|
3984
|
+
x_range=x_range,
|
|
3985
|
+
)
|
|
3986
|
+
fig.toolbar.logo = None
|
|
3987
|
+
|
|
3988
|
+
# add functionality to click through to vectorbase
|
|
3989
|
+
url = "https://vectorbase.org/vectorbase/app/record/gene/@ID"
|
|
3990
|
+
taptool = fig.select(type=bkmod.TapTool)
|
|
3991
|
+
taptool.callback = bkmod.OpenURL(url=url)
|
|
3992
|
+
|
|
3993
|
+
# now plot the genes as rectangles
|
|
3994
|
+
fig.quad(
|
|
3995
|
+
bottom="bottom",
|
|
3996
|
+
top="top",
|
|
3997
|
+
left="start",
|
|
3998
|
+
right="end",
|
|
3999
|
+
source=data,
|
|
4000
|
+
line_width=0.5,
|
|
4001
|
+
fill_alpha=0.5,
|
|
4002
|
+
)
|
|
4003
|
+
|
|
4004
|
+
# tidy up the plot
|
|
4005
|
+
fig.xaxis.axis_label = f"Contig {contig} position (bp)"
|
|
4006
|
+
fig.y_range = bkmod.Range1d(-0.4, 2.2)
|
|
4007
|
+
fig.ygrid.visible = False
|
|
4008
|
+
yticks = [0.4, 1.4]
|
|
4009
|
+
yticklabels = ["-", "+"]
|
|
4010
|
+
fig.yaxis.ticker = yticks
|
|
4011
|
+
fig.yaxis.major_label_overrides = {k: v for k, v in zip(yticks, yticklabels)}
|
|
4012
|
+
fig.xaxis[0].formatter = bkmod.NumeralTickFormatter(format="0,0")
|
|
4013
|
+
|
|
4014
|
+
if show:
|
|
4015
|
+
bkplt.show(fig)
|
|
4016
|
+
|
|
4017
|
+
return fig
|
|
4018
|
+
|
|
4019
|
+
def plot_transcript(
|
|
4020
|
+
self,
|
|
4021
|
+
transcript,
|
|
4022
|
+
width=700,
|
|
4023
|
+
height=120,
|
|
4024
|
+
show=True,
|
|
4025
|
+
x_range=None,
|
|
4026
|
+
toolbar_location="above",
|
|
4027
|
+
title=True,
|
|
4028
|
+
):
|
|
4029
|
+
|
|
4030
|
+
import bokeh.models as bkmod
|
|
4031
|
+
import bokeh.plotting as bkplt
|
|
4032
|
+
|
|
4033
|
+
# find the transcript annotation
|
|
4034
|
+
df_geneset = self.geneset().set_index("ID")
|
|
4035
|
+
parent = df_geneset.loc[transcript]
|
|
4036
|
+
|
|
4037
|
+
if title is True:
|
|
4038
|
+
title = f"{transcript} ({parent.strand})"
|
|
4039
|
+
|
|
4040
|
+
# define tooltips for hover
|
|
4041
|
+
tooltips = [
|
|
4042
|
+
("Type", "@type"),
|
|
4043
|
+
("Location", "@contig:@start{,}-@end{,}"),
|
|
4044
|
+
]
|
|
4045
|
+
|
|
4046
|
+
# make a figure
|
|
4047
|
+
fig = bkplt.figure(
|
|
4048
|
+
title=title,
|
|
4049
|
+
plot_width=width,
|
|
4050
|
+
plot_height=height,
|
|
4051
|
+
tools="xpan,xzoom_in,xzoom_out,xwheel_zoom,reset,hover",
|
|
4052
|
+
toolbar_location=toolbar_location,
|
|
4053
|
+
active_scroll="xwheel_zoom",
|
|
4054
|
+
active_drag="xpan",
|
|
4055
|
+
tooltips=tooltips,
|
|
4056
|
+
x_range=x_range,
|
|
4057
|
+
)
|
|
4058
|
+
fig.toolbar.logo = None
|
|
4059
|
+
|
|
4060
|
+
# find child components of the transcript
|
|
4061
|
+
data = df_geneset.set_index("Parent").loc[transcript].copy()
|
|
4062
|
+
data["bottom"] = -0.4
|
|
4063
|
+
data["top"] = 0.4
|
|
4064
|
+
|
|
4065
|
+
# plot exons
|
|
4066
|
+
exons = data.query("type == 'exon'")
|
|
4067
|
+
fig.quad(
|
|
4068
|
+
bottom="bottom",
|
|
4069
|
+
top="top",
|
|
4070
|
+
left="start",
|
|
4071
|
+
right="end",
|
|
4072
|
+
source=exons,
|
|
4073
|
+
fill_color=None,
|
|
4074
|
+
line_color="black",
|
|
4075
|
+
line_width=0.5,
|
|
4076
|
+
fill_alpha=0,
|
|
4077
|
+
)
|
|
4078
|
+
|
|
4079
|
+
# plot introns
|
|
4080
|
+
for intron_start, intron_end in zip(exons[:-1]["end"], exons[1:]["start"]):
|
|
4081
|
+
intron_midpoint = (intron_start + intron_end) / 2
|
|
4082
|
+
line_data = pd.DataFrame(
|
|
4083
|
+
{
|
|
4084
|
+
"x": [intron_start, intron_midpoint, intron_end],
|
|
4085
|
+
"y": [0, 0.1, 0],
|
|
4086
|
+
"type": "intron",
|
|
4087
|
+
"contig": parent.contig,
|
|
4088
|
+
"start": intron_start,
|
|
4089
|
+
"end": intron_end,
|
|
4090
|
+
}
|
|
4091
|
+
)
|
|
4092
|
+
fig.line(
|
|
4093
|
+
x="x",
|
|
4094
|
+
y="y",
|
|
4095
|
+
source=line_data,
|
|
4096
|
+
line_width=1,
|
|
4097
|
+
line_color="black",
|
|
4098
|
+
)
|
|
4099
|
+
|
|
4100
|
+
# plot UTRs
|
|
4101
|
+
fig.quad(
|
|
4102
|
+
bottom="bottom",
|
|
4103
|
+
top="top",
|
|
4104
|
+
left="start",
|
|
4105
|
+
right="end",
|
|
4106
|
+
source=data.query("type == 'five_prime_UTR'"),
|
|
4107
|
+
fill_color="green",
|
|
4108
|
+
line_width=0,
|
|
4109
|
+
fill_alpha=0.5,
|
|
4110
|
+
)
|
|
4111
|
+
fig.quad(
|
|
4112
|
+
bottom="bottom",
|
|
4113
|
+
top="top",
|
|
4114
|
+
left="start",
|
|
4115
|
+
right="end",
|
|
4116
|
+
source=data.query("type == 'three_prime_UTR'"),
|
|
4117
|
+
fill_color="red",
|
|
4118
|
+
line_width=0,
|
|
4119
|
+
fill_alpha=0.5,
|
|
4120
|
+
)
|
|
4121
|
+
|
|
4122
|
+
# plot CDSs
|
|
4123
|
+
fig.quad(
|
|
4124
|
+
bottom="bottom",
|
|
4125
|
+
top="top",
|
|
4126
|
+
left="start",
|
|
4127
|
+
right="end",
|
|
4128
|
+
source=data.query("type == 'CDS'"),
|
|
4129
|
+
fill_color="blue",
|
|
4130
|
+
line_width=0,
|
|
4131
|
+
fill_alpha=0.5,
|
|
4132
|
+
)
|
|
4133
|
+
|
|
4134
|
+
# tidy up the figure
|
|
4135
|
+
fig.yaxis.ticker = []
|
|
4136
|
+
fig.y_range = bkmod.Range1d(-0.6, 0.6)
|
|
4137
|
+
fig.xaxis.axis_label = f"Contig {parent.contig} position (bp)"
|
|
4138
|
+
fig.xaxis[0].formatter = bkmod.NumeralTickFormatter(format="0,0")
|
|
4139
|
+
|
|
4140
|
+
if show:
|
|
4141
|
+
bkplt.show(fig)
|
|
4142
|
+
|
|
4143
|
+
return fig
|
|
4144
|
+
|
|
3747
4145
|
|
|
3748
4146
|
@numba.njit("Tuple((int8, int64))(int8[:], int8)")
|
|
3749
4147
|
def _cn_mode_1d(a, vmax):
|
|
@@ -3818,109 +4216,59 @@ def _make_sample_period_year(row):
|
|
|
3818
4216
|
return pd.NaT
|
|
3819
4217
|
|
|
3820
4218
|
|
|
3821
|
-
# def _genotypes_to_alt_allele_counts_melt(gt, max_allele):
|
|
3822
|
-
# """Convert a genotype array to an array of alt allele counts, melted to
|
|
3823
|
-
# store one row per alt allele."""
|
|
3824
|
-
#
|
|
3825
|
-
# n_variants = gt.shape[0]
|
|
3826
|
-
# n_samples = gt.shape[1]
|
|
3827
|
-
#
|
|
3828
|
-
# # convert to genotype allele counts
|
|
3829
|
-
# gac = allel.GenotypeArray(gt).to_allele_counts(max_allele=max_allele)
|
|
3830
|
-
# assert gac.shape == (n_variants, n_samples, max_allele + 1)
|
|
3831
|
-
#
|
|
3832
|
-
# # sum total observations over alleles
|
|
3833
|
-
# gan = gac.sum(axis=2)
|
|
3834
|
-
#
|
|
3835
|
-
# # keep only alt allele counts
|
|
3836
|
-
# gac_alt = gac[:, :, 1:]
|
|
3837
|
-
# assert gac_alt.shape == (n_variants, n_samples, max_allele)
|
|
3838
|
-
#
|
|
3839
|
-
# # use some numpy tricks to melt alleles into rows
|
|
3840
|
-
# gac_alt_melt = gac_alt.swapaxes(2, 1).reshape(-1, n_samples)
|
|
3841
|
-
# assert gac_alt_melt.shape == (n_variants * max_allele, n_samples)
|
|
3842
|
-
# gan_melt = np.repeat(gan, max_allele, axis=0)
|
|
3843
|
-
# assert gan_melt.shape == (n_variants * max_allele, n_samples)
|
|
3844
|
-
#
|
|
3845
|
-
# return gac_alt_melt, gan_melt
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
4219
|
@numba.njit
|
|
3849
|
-
def
|
|
3850
|
-
"""Convert a genotype array to an array of alt allele counts, melted to
|
|
3851
|
-
store one row per alt allele."""
|
|
4220
|
+
def _cohort_alt_allele_counts_melt_kernel(gt, indices, max_allele):
|
|
3852
4221
|
|
|
3853
4222
|
n_variants = gt.shape[0]
|
|
3854
|
-
|
|
4223
|
+
n_indices = indices.shape[0]
|
|
3855
4224
|
ploidy = gt.shape[2]
|
|
3856
4225
|
|
|
3857
|
-
|
|
3858
|
-
|
|
4226
|
+
ac_alt_melt = np.zeros(n_variants * max_allele, dtype=np.int64)
|
|
4227
|
+
an = np.zeros(n_variants, dtype=np.int64)
|
|
3859
4228
|
|
|
3860
4229
|
for i in range(n_variants):
|
|
3861
4230
|
out_i_offset = (i * max_allele) - 1
|
|
3862
|
-
for j in range(
|
|
4231
|
+
for j in range(n_indices):
|
|
4232
|
+
ix = indices[j]
|
|
3863
4233
|
for k in range(ploidy):
|
|
3864
|
-
allele = gt[i,
|
|
4234
|
+
allele = gt[i, ix, k]
|
|
3865
4235
|
if allele > 0:
|
|
3866
4236
|
out_i = out_i_offset + allele
|
|
3867
|
-
|
|
3868
|
-
|
|
4237
|
+
ac_alt_melt[out_i] += 1
|
|
4238
|
+
an[i] += 1
|
|
3869
4239
|
elif allele == 0:
|
|
3870
|
-
|
|
4240
|
+
an[i] += 1
|
|
3871
4241
|
|
|
3872
|
-
return
|
|
4242
|
+
return ac_alt_melt, an
|
|
3873
4243
|
|
|
3874
4244
|
|
|
3875
|
-
def
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
return
|
|
4245
|
+
def _cohort_alt_allele_counts_melt(gt, indices, max_allele):
|
|
4246
|
+
ac_alt_melt, an = _cohort_alt_allele_counts_melt_kernel(gt, indices, max_allele)
|
|
4247
|
+
an_melt = np.repeat(an, max_allele, axis=0)
|
|
4248
|
+
return ac_alt_melt, an_melt
|
|
3879
4249
|
|
|
3880
4250
|
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
n_variants = a.shape[0]
|
|
3884
|
-
n_indices = indices.shape[0]
|
|
3885
|
-
out = np.zeros(n_variants, dtype=np.int64)
|
|
3886
|
-
for i in range(n_variants):
|
|
3887
|
-
v_sum = 0
|
|
3888
|
-
for j in range(n_indices):
|
|
3889
|
-
ix = indices[j]
|
|
3890
|
-
v = a[i, ix]
|
|
3891
|
-
v_sum += v
|
|
3892
|
-
out[i] = v_sum
|
|
3893
|
-
return out
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
def _make_snp_label(row):
|
|
3897
|
-
label = (
|
|
3898
|
-
f"{row['contig']}:{row['position']:,} {row['ref_allele']}>{row['alt_allele']}"
|
|
3899
|
-
)
|
|
3900
|
-
return label
|
|
4251
|
+
def _make_snp_label(contig, position, ref_allele, alt_allele):
|
|
4252
|
+
return f"{contig}:{position:,} {ref_allele}>{alt_allele}"
|
|
3901
4253
|
|
|
3902
4254
|
|
|
3903
|
-
def _make_snp_label_effect(
|
|
3904
|
-
label =
|
|
3905
|
-
f"{row['contig']}:{row['position']:,} {row['ref_allele']}>{row['alt_allele']}"
|
|
3906
|
-
)
|
|
3907
|
-
aa_change = row["aa_change"]
|
|
4255
|
+
def _make_snp_label_effect(contig, position, ref_allele, alt_allele, aa_change):
|
|
4256
|
+
label = f"{contig}:{position:,} {ref_allele}>{alt_allele}"
|
|
3908
4257
|
if isinstance(aa_change, str):
|
|
3909
4258
|
label += f" ({aa_change})"
|
|
3910
4259
|
return label
|
|
3911
4260
|
|
|
3912
4261
|
|
|
3913
|
-
def _make_snp_label_aa(
|
|
3914
|
-
label = f"{
|
|
4262
|
+
def _make_snp_label_aa(aa_change, contig, position, ref_allele, alt_allele):
|
|
4263
|
+
label = f"{aa_change} ({contig}:{position:,} {ref_allele}>{alt_allele})"
|
|
3915
4264
|
return label
|
|
3916
4265
|
|
|
3917
4266
|
|
|
3918
|
-
def _make_gene_cnv_label(
|
|
3919
|
-
label =
|
|
3920
|
-
gene_name = row["gene_name"]
|
|
4267
|
+
def _make_gene_cnv_label(gene_id, gene_name, cnv_type):
|
|
4268
|
+
label = gene_id
|
|
3921
4269
|
if isinstance(gene_name, str):
|
|
3922
4270
|
label += f" ({gene_name})"
|
|
3923
|
-
label += f" {
|
|
4271
|
+
label += f" {cnv_type}"
|
|
3924
4272
|
return label
|
|
3925
4273
|
|
|
3926
4274
|
|
|
@@ -3963,6 +4311,8 @@ def _map_snp_to_aa_change_frq_ds(ds):
|
|
|
3963
4311
|
|
|
3964
4312
|
|
|
3965
4313
|
def _add_frequency_ci(ds, ci_method):
|
|
4314
|
+
from statsmodels.stats.proportion import proportion_confint
|
|
4315
|
+
|
|
3966
4316
|
if ci_method is not None:
|
|
3967
4317
|
count = ds["event_count"].values
|
|
3968
4318
|
nobs = ds["event_nobs"].values
|
|
@@ -4047,3 +4397,11 @@ def _check_param_min_cohort_size(min_cohort_size):
|
|
|
4047
4397
|
raise ValueError(
|
|
4048
4398
|
f"Value of parameter min_cohort_size must be at least 1; found {min_cohort_size}."
|
|
4049
4399
|
)
|
|
4400
|
+
|
|
4401
|
+
|
|
4402
|
+
def _pandas_apply(f, df, columns):
|
|
4403
|
+
"""Optimised alternative to pandas apply."""
|
|
4404
|
+
df = df.reset_index(drop=True)
|
|
4405
|
+
iterator = zip(*[df[c].values for c in columns])
|
|
4406
|
+
ret = pd.Series((f(*vals) for vals in iterator))
|
|
4407
|
+
return ret
|
|
@@ -404,3 +404,35 @@ def xarray_concat(
|
|
|
404
404
|
join=join,
|
|
405
405
|
**kwargs,
|
|
406
406
|
)
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
def type_error(
|
|
410
|
+
name,
|
|
411
|
+
value,
|
|
412
|
+
expectation,
|
|
413
|
+
):
|
|
414
|
+
message = (
|
|
415
|
+
f"Bad type for parameter {name}; expected {expectation}, "
|
|
416
|
+
f"found {type(value)}"
|
|
417
|
+
)
|
|
418
|
+
raise TypeError(message)
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def value_error(
|
|
422
|
+
name,
|
|
423
|
+
value,
|
|
424
|
+
expectation,
|
|
425
|
+
):
|
|
426
|
+
message = (
|
|
427
|
+
f"Bad value for parameter {name}; expected {expectation}, " f"found {value!r}"
|
|
428
|
+
)
|
|
429
|
+
raise ValueError(message)
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
def check_type(
|
|
433
|
+
name,
|
|
434
|
+
value,
|
|
435
|
+
expectation,
|
|
436
|
+
):
|
|
437
|
+
if not isinstance(value, expectation):
|
|
438
|
+
type_error(name, value, expectation)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "malariagen_data"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.2.0"
|
|
4
4
|
description = "A package for accessing MalariaGEN public data."
|
|
5
|
-
authors = ["Alistair Miles <alistair.miles@sanger.ac.uk>", "Chris Clarkson <cc28@sanger.ac.uk>", "Kathryn Murie <km22@sanger.ac.uk>", "Nace Kranjc <n.kranjc@imperial.ac.uk>"]
|
|
5
|
+
authors = ["Alistair Miles <alistair.miles@sanger.ac.uk>", "Chris Clarkson <cc28@sanger.ac.uk>", "Kathryn Murie <km22@sanger.ac.uk>", "Nace Kranjc <n.kranjc@imperial.ac.uk>", "Kelly Bennett <kb25@sanger.ac.uk>"]
|
|
6
6
|
license = "MIT"
|
|
7
7
|
|
|
8
8
|
[tool.poetry.dependencies]
|
|
@@ -19,6 +19,7 @@ scikit-allel = "*"
|
|
|
19
19
|
xarray = "*"
|
|
20
20
|
numba = "*"
|
|
21
21
|
plotly = "*"
|
|
22
|
+
bokeh = "*"
|
|
22
23
|
statsmodels = "*"
|
|
23
24
|
ipyleaflet = "*"
|
|
24
25
|
ipywidgets = "*"
|
|
@@ -9,6 +9,7 @@ package_data = \
|
|
|
9
9
|
|
|
10
10
|
install_requires = \
|
|
11
11
|
['BioPython',
|
|
12
|
+
'bokeh',
|
|
12
13
|
'dask[array]',
|
|
13
14
|
'fsspec',
|
|
14
15
|
'gcsfs',
|
|
@@ -27,7 +28,7 @@ install_requires = \
|
|
|
27
28
|
|
|
28
29
|
setup_kwargs = {
|
|
29
30
|
'name': 'malariagen-data',
|
|
30
|
-
'version': '2.
|
|
31
|
+
'version': '2.2.0',
|
|
31
32
|
'description': 'A package for accessing MalariaGEN public data.',
|
|
32
33
|
'long_description': None,
|
|
33
34
|
'author': 'Alistair Miles',
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|