malariagen_data 2.1.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.1.0 → malariagen_data-2.2.0}/PKG-INFO +2 -1
- {malariagen_data-2.1.0 → malariagen_data-2.2.0}/malariagen_data/ag3.py +331 -2
- {malariagen_data-2.1.0 → malariagen_data-2.2.0}/malariagen_data/util.py +32 -0
- {malariagen_data-2.1.0 → malariagen_data-2.2.0}/pyproject.toml +2 -1
- {malariagen_data-2.1.0 → malariagen_data-2.2.0}/setup.py +2 -1
- {malariagen_data-2.1.0 → malariagen_data-2.2.0}/LICENSE +0 -0
- {malariagen_data-2.1.0 → malariagen_data-2.2.0}/malariagen_data/__init__.py +0 -0
- {malariagen_data-2.1.0 → malariagen_data-2.2.0}/malariagen_data/amin1.py +0 -0
- {malariagen_data-2.1.0 → malariagen_data-2.2.0}/malariagen_data/pf7.py +0 -0
- {malariagen_data-2.1.0 → malariagen_data-2.2.0}/malariagen_data/pf7_config.json +0 -0
- {malariagen_data-2.1.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
|
|
@@ -2250,6 +2250,46 @@ class Ag3:
|
|
|
2250
2250
|
# check parameters
|
|
2251
2251
|
_check_param_min_cohort_size(min_cohort_size)
|
|
2252
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
|
+
|
|
2253
2293
|
# load sample metadata
|
|
2254
2294
|
df_samples = self.sample_metadata(
|
|
2255
2295
|
sample_sets=sample_sets,
|
|
@@ -3342,8 +3382,9 @@ class Ag3:
|
|
|
3342
3382
|
|
|
3343
3383
|
Parameters
|
|
3344
3384
|
----------
|
|
3345
|
-
contig : str
|
|
3346
|
-
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"].
|
|
3347
3388
|
area_by : str
|
|
3348
3389
|
Column name in the sample metadata to use to group samples spatially. E.g.,
|
|
3349
3390
|
use "admin1_iso" or "admin1_name" to group by level 1 administrative divisions,
|
|
@@ -3388,6 +3429,52 @@ class Ag3:
|
|
|
3388
3429
|
# check parameters
|
|
3389
3430
|
_check_param_min_cohort_size(min_cohort_size)
|
|
3390
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
|
+
|
|
3391
3478
|
# load sample metadata
|
|
3392
3479
|
df_samples = self.sample_metadata(
|
|
3393
3480
|
sample_sets=sample_sets,
|
|
@@ -3813,6 +3900,248 @@ class Ag3:
|
|
|
3813
3900
|
|
|
3814
3901
|
return out
|
|
3815
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
|
+
|
|
3816
4145
|
|
|
3817
4146
|
@numba.njit("Tuple((int8, int64))(int8[:], int8)")
|
|
3818
4147
|
def _cn_mode_1d(a, vmax):
|
|
@@ -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,6 +1,6 @@
|
|
|
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
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"
|
|
@@ -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
|