Skip to content

Commit a3cb3e3

Browse files
authored
Merge branch 'master' into GH987-fix-sample-query-options-annotation-in-average-fst
2 parents d31589f + f6b172f commit a3cb3e3

3 files changed

Lines changed: 72 additions & 31 deletions

File tree

malariagen_data/anoph/genome_sequence.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717

1818
class AnophelesGenomeSequenceData(AnophelesBase):
19+
_cache_genome: Optional[zarr.hierarchy.Group]
20+
1921
def __init__(
2022
self, virtual_contigs: Optional[Mapping[str, Sequence[str]]] = None, **kwargs
2123
):
@@ -29,9 +31,6 @@ def __init__(
2931
virtual_contigs = dict()
3032
self._virtual_contigs = virtual_contigs
3133

32-
# Initialize cache attributes.
33-
self._cache_genome = None
34-
3534
@property
3635
def contigs(self) -> Tuple[str, ...]:
3736
"""Contigs in the reference genome."""
@@ -62,13 +61,9 @@ def _genome_ref_id(self) -> str:
6261
def _genome_ref_name(self) -> str:
6362
return self.config["GENOME_REF_NAME"]
6463

65-
@_check_types
66-
@doc(
67-
summary="Open the reference genome zarr.",
68-
returns="Zarr hierarchy containing the reference genome sequence.",
69-
)
7064
def open_genome(self) -> zarr.hierarchy.Group:
71-
if self._cache_genome is None:
65+
"""Open the reference genome zarr."""
66+
if not hasattr(self, "_cache_genome") or self._cache_genome is None:
7267
path = f"{self._base_path}/{self._genome_zarr_path}"
7368
store = _init_zarr_store(fs=self._fs, path=path)
7469
self._cache_genome = zarr.open_consolidated(store=store)

malariagen_data/anoph/map_params.py

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Parameters for functions plotting maps using ipyleaflet."""
22

3+
import warnings
34
from typing import Dict, Tuple, Union
45

56
import ipyleaflet # type: ignore
@@ -17,22 +18,70 @@
1718

1819
zoom_default: zoom = 3
1920

20-
basemap_abbrevs = {
21-
"mapnik": ipyleaflet.basemaps.OpenStreetMap.Mapnik,
22-
"natgeoworldmap": ipyleaflet.basemaps.Esri.NatGeoWorldMap,
23-
"opentopomap": ipyleaflet.basemaps.OpenTopoMap,
24-
"positron": ipyleaflet.basemaps.CartoDB.Positron,
25-
"satellite": ipyleaflet.basemaps.Gaode.Satellite,
26-
"worldimagery": ipyleaflet.basemaps.Esri.WorldImagery,
27-
"worldstreetmap": ipyleaflet.basemaps.Esri.WorldStreetMap,
28-
"worldtopomap": ipyleaflet.basemaps.Esri.WorldTopoMap,
21+
# Candidate basemap abbreviations — loaded lazily to avoid import failures
22+
# if a provider has been decommissioned upstream.
23+
_basemap_abbrev_candidates = {
24+
"mapnik": lambda: ipyleaflet.basemaps.OpenStreetMap.Mapnik,
25+
"natgeoworldmap": lambda: ipyleaflet.basemaps.Esri.NatGeoWorldMap,
26+
"opentopomap": lambda: ipyleaflet.basemaps.OpenTopoMap,
27+
"positron": lambda: ipyleaflet.basemaps.CartoDB.Positron,
28+
"satellite": lambda: ipyleaflet.basemaps.Gaode.Satellite,
29+
"worldimagery": lambda: ipyleaflet.basemaps.Esri.WorldImagery,
30+
"worldstreetmap": lambda: ipyleaflet.basemaps.Esri.WorldStreetMap,
31+
"worldtopomap": lambda: ipyleaflet.basemaps.Esri.WorldTopoMap,
2932
}
3033

34+
_basemap_abbrevs: dict | None = None
35+
36+
37+
def get_basemap_abbrevs() -> dict:
38+
"""Return available basemap abbreviations, skipping any unavailable providers."""
39+
global _basemap_abbrevs
40+
if _basemap_abbrevs is None:
41+
_basemap_abbrevs = {}
42+
for key, provider_fn in _basemap_abbrev_candidates.items():
43+
try:
44+
_basemap_abbrevs[key] = provider_fn()
45+
except Exception:
46+
warnings.warn(
47+
f"Basemap provider {key!r} is not available and will be skipped.",
48+
stacklevel=2,
49+
)
50+
return _basemap_abbrevs
51+
52+
53+
# Keep basemap_abbrevs as a property-like alias for backwards compatibility.
54+
# Code that does `map_params.basemap_abbrevs` will call get_basemap_abbrevs().
55+
class _BasemapAbbrevProxy:
56+
def __getattr__(self, item):
57+
return getattr(get_basemap_abbrevs(), item)
58+
59+
def __iter__(self):
60+
return iter(get_basemap_abbrevs())
61+
62+
def __getitem__(self, item):
63+
return get_basemap_abbrevs()[item]
64+
65+
def __contains__(self, item):
66+
return item in get_basemap_abbrevs()
67+
68+
def keys(self):
69+
return get_basemap_abbrevs().keys()
70+
71+
def values(self):
72+
return get_basemap_abbrevs().values()
73+
74+
def items(self):
75+
return get_basemap_abbrevs().items()
76+
77+
78+
basemap_abbrevs = _BasemapAbbrevProxy()
79+
3180
basemap: TypeAlias = Annotated[
3281
Union[str, Dict, ipyleaflet.TileLayer, xyzservices.lib.TileProvider],
3382
f"""
3483
Basemap from ipyleaflet or other TileLayer provider. Strings are abbreviations mapped to corresponding
35-
basemaps, available values are {list(basemap_abbrevs.keys())}.
84+
basemaps, available values are {list(_basemap_abbrev_candidates.keys())}.
3685
""",
3786
]
3887

malariagen_data/anoph/snp_frq.py

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from functools import cached_property
12
from typing import Optional, Dict, Union, Callable, List
23
import warnings
34

@@ -40,9 +41,6 @@ def __init__(
4041
# to the superclass constructor.
4142
super().__init__(**kwargs)
4243

43-
# Set up cache variables.
44-
self._cache_annotator = None
45-
4644
def _snp_df_melt(self, *, ds_snp: xr.Dataset) -> pd.DataFrame:
4745
"""Set up a dataframe with SNP site and filter data,
4846
melting each alternate allele into a separate row."""
@@ -81,13 +79,12 @@ def _snp_df_melt(self, *, ds_snp: xr.Dataset) -> pd.DataFrame:
8179

8280
return df_snps
8381

82+
@cached_property
8483
def _snp_effect_annotator(self):
8584
"""Set up variant effect annotator."""
86-
if self._cache_annotator is None:
87-
self._cache_annotator = veff.Annotator(
88-
genome=self.open_genome(), genome_features=self.genome_features()
89-
)
90-
return self._cache_annotator
85+
return veff.Annotator(
86+
genome=self.open_genome(), genome_features=self.genome_features()
87+
)
9188

9289
@_check_types
9390
@doc(
@@ -112,7 +109,7 @@ def snp_effects(
112109
df_snps = self._snp_df_melt(ds_snp=ds_snp)
113110

114111
# Setup variant effect annotator.
115-
ann = self._snp_effect_annotator()
112+
ann = self._snp_effect_annotator
116113

117114
# Add effects to the dataframe.
118115
ann.get_effects(transcript=transcript, variants=df_snps)
@@ -249,7 +246,7 @@ def snp_allele_frequencies(
249246

250247
if effects:
251248
# Add effect annotations.
252-
ann = self._snp_effect_annotator()
249+
ann = self._snp_effect_annotator
253250
ann.get_effects(
254251
transcript=transcript, variants=df_snps, progress=self._progress
255252
)
@@ -586,7 +583,7 @@ def snp_allele_frequencies_advanced(
586583
frequency = np.compress(loc_variant, frequency, axis=0)
587584

588585
# Set up variant effect annotator.
589-
ann = self._snp_effect_annotator()
586+
ann = self._snp_effect_annotator
590587

591588
# Add effects to the dataframe.
592589
ann.get_effects(
@@ -832,7 +829,7 @@ def snp_genotype_allele_counts(
832829
df_snps = pd.concat([df_snps, df_counts], axis=1)
833830

834831
# Add effect annotations.
835-
ann = self._snp_effect_annotator()
832+
ann = self._snp_effect_annotator
836833
ann.get_effects(
837834
transcript=transcript, variants=df_snps, progress=self._progress
838835
)

0 commit comments

Comments
 (0)