Skip to content

Commit d626f3d

Browse files
Merge pull request #93 from databio/umap
Releaase 0.13.0
2 parents 8240385 + 1d2f797 commit d626f3d

6 files changed

Lines changed: 76 additions & 7 deletions

File tree

bbconf/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.12.0"
1+
__version__ = "0.13.0"

bbconf/config_parser/bedbaseconfig.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import warnings
44
from pathlib import Path
55
from typing import List, Literal, Union
6+
import numpy as np
67

78
import boto3
89
import qdrant_client
@@ -18,6 +19,10 @@
1819
from geniml.search.query2vec import BED2Vec
1920
from pephubclient import PEPHubClient
2021
from zarr import Group as Z_GROUP
22+
from umap import UMAP
23+
24+
import joblib
25+
import io
2126

2227
from bbconf.config_parser.const import (
2328
S3_BEDSET_PATH_FOLDER,
@@ -67,6 +72,7 @@ def __init__(self, config: Union[Path, str], init_ml: bool = True):
6772
self._b2bsi = self._init_b2bsi_object()
6873
self._r2v = self._init_r2v_object()
6974
self._bivec = self._init_bivec_object()
75+
self._umap_model: Union[UMAP, None] = self._init_umap_model()
7076
else:
7177
_LOGGER.info(
7278
"Skipping initialization of ML models, init_ml parameter set to False."
@@ -75,6 +81,7 @@ def __init__(self, config: Union[Path, str], init_ml: bool = True):
7581
self._b2bsi = None
7682
self._r2v = None
7783
self._bivec = None
84+
self._umap_model: Union[UMAP, None] = None
7885

7986
self._phc = self._init_pephubclient()
8087
self._boto3_client = self._init_boto3_client()
@@ -414,6 +421,47 @@ def _init_r2v_object(self) -> Union[Region2VecExModel, None]:
414421
)
415422
return None
416423

424+
def _init_umap_model(self) -> Union[UMAP, None]:
425+
"""
426+
Load UMAP model from the specified path, or url
427+
"""
428+
429+
if not self.config.path.umap_model:
430+
_LOGGER.warning(
431+
"UMAP model path is not specified in the configuration, and won't be used."
432+
)
433+
return None
434+
435+
model_path = self.config.path.umap_model
436+
437+
if model_path.startswith(("http://", "https://")):
438+
import requests
439+
440+
try:
441+
response = requests.get(model_path)
442+
response.raise_for_status()
443+
buffer = io.BytesIO(response.content)
444+
umap_model = joblib.load(buffer)
445+
print(f"UMAP model loaded from URL: {model_path}")
446+
except requests.RequestException as e:
447+
_LOGGER.error(f"Error downloading UMAP model from URL: {e}")
448+
return None
449+
else:
450+
try:
451+
with open(model_path, "rb") as file:
452+
umap_model = joblib.load(file)
453+
print(f"UMAP model loaded from local path: {model_path}")
454+
except FileNotFoundError as e:
455+
_LOGGER.error(f"Error loading UMAP model from local path: {e}")
456+
return None
457+
458+
if not isinstance(umap_model, UMAP):
459+
_LOGGER.error(f"Loaded object is not a UMAP instance: {type(umap_model)}")
460+
return None
461+
# np.random.seed(42)
462+
umap_model.random_state = 42
463+
return umap_model
464+
417465
def upload_s3(self, file_path: str, s3_path: Union[Path, str]) -> None:
418466
"""
419467
Upload file to s3.

bbconf/config_parser/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ class ConfigPath(BaseModel):
6767
region2vec: str = DEFAULT_REGION2_VEC_MODEL
6868
# vec2vec: str = DEFAULT_VEC2VEC_MODEL
6969
text2vec: str = DEFAULT_TEXT2VEC_MODEL
70+
umap_model: Union[str, None] = None # Path or link to pre-trained UMAP model
7071

7172

7273
class AccessMethodsStruct(BaseModel):

bbconf/modules/bedfiles.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55

66
import numpy as np
77
from geniml.bbclient import BBClient
8-
from geniml.io import RegionSet
8+
9+
# from geniml.io import RegionSet
910
from geniml.search.backends import QdrantBackend
1011
from gtars.models import RegionSet as GRegionSet
1112
from pephubclient.exceptions import ResponseError
@@ -1155,7 +1156,7 @@ def delete_pephub_sample(self, identifier: str):
11551156
def upload_file_qdrant(
11561157
self,
11571158
bed_id: str,
1158-
bed_file: Union[str, RegionSet],
1159+
bed_file: Union[str, GRegionSet],
11591160
payload: dict = None,
11601161
) -> None:
11611162
"""
@@ -1183,7 +1184,7 @@ def upload_file_qdrant(
11831184
)
11841185
return None
11851186

1186-
def _embed_file(self, bed_file: Union[str, RegionSet]) -> np.ndarray:
1187+
def _embed_file(self, bed_file: Union[str, GRegionSet]) -> np.ndarray:
11871188
"""
11881189
Create embedding for bed file
11891190
@@ -1204,8 +1205,8 @@ def _embed_file(self, bed_file: Union[str, RegionSet]) -> np.ndarray:
12041205
try:
12051206
bed_region_set = GRegionSet(bed_file)
12061207
except RuntimeError as _:
1207-
bed_region_set = RegionSet(bed_file)
1208-
elif isinstance(bed_file, RegionSet) or isinstance(bed_file, GRegionSet):
1208+
bed_region_set = GRegionSet(bed_file)
1209+
elif isinstance(bed_file, GRegionSet) or isinstance(bed_file, GRegionSet):
12091210
bed_region_set = bed_file
12101211
else:
12111212
raise BedBaseConfError(
@@ -1215,6 +1216,20 @@ def _embed_file(self, bed_file: Union[str, RegionSet]) -> np.ndarray:
12151216
vec_dim = bed_embedding.shape[0]
12161217
return bed_embedding.reshape(1, vec_dim)
12171218

1219+
def _get_umap_file(self, bed_file: Union[str, GRegionSet]) -> np.ndarray:
1220+
"""
1221+
Create UMAP for bed file
1222+
1223+
:param bed_file: bed file path or region set
1224+
"""
1225+
1226+
if self._config._umap_model is None:
1227+
raise BedBaseConfError("UMAP model is not initialized.")
1228+
1229+
bed_embedding = self._embed_file(bed_file)
1230+
bed_umap = self._config._umap_model.transform(bed_embedding)
1231+
return bed_umap
1232+
12181233
def text_to_bed_search(
12191234
self,
12201235
query: str,
@@ -1270,7 +1285,7 @@ def text_to_bed_search(
12701285

12711286
def bed_to_bed_search(
12721287
self,
1273-
region_set: RegionSet,
1288+
region_set: GRegionSet,
12741289
limit: int = 10,
12751290
offset: int = 0,
12761291
) -> BedListSearchResult:

docs/changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) and [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) format.
44

5+
### [0.13.0] - 2025-11-24
6+
### Added:
7+
- Conversion of bedfile to umap from predefined model
8+
59
### [0.12.0] - 2025-09-11
610
### Added:
711
- New qdrant semantic search

requirements/requirements-all.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ pyyaml >= 6.0.1 # for s3fs because of the errors
1414
s3fs >= 2024.3.1
1515
pandas >= 2.0.0
1616
pybiocfilecache == 0.6.1
17+
umap-learn >= 0.5.8

0 commit comments

Comments
 (0)