spatialcore 0.1.9__py3-none-any.whl
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.
- spatialcore/__init__.py +122 -0
- spatialcore/annotation/__init__.py +253 -0
- spatialcore/annotation/acquisition.py +529 -0
- spatialcore/annotation/annotate.py +603 -0
- spatialcore/annotation/cellxgene.py +365 -0
- spatialcore/annotation/confidence.py +802 -0
- spatialcore/annotation/discovery.py +529 -0
- spatialcore/annotation/expression.py +363 -0
- spatialcore/annotation/loading.py +529 -0
- spatialcore/annotation/markers.py +297 -0
- spatialcore/annotation/ontology.py +1282 -0
- spatialcore/annotation/patterns.py +247 -0
- spatialcore/annotation/pipeline.py +620 -0
- spatialcore/annotation/synapse.py +380 -0
- spatialcore/annotation/training.py +1457 -0
- spatialcore/annotation/validation.py +422 -0
- spatialcore/core/__init__.py +34 -0
- spatialcore/core/cache.py +118 -0
- spatialcore/core/logging.py +135 -0
- spatialcore/core/metadata.py +149 -0
- spatialcore/core/utils.py +768 -0
- spatialcore/data/gene_mappings/ensembl_to_hugo_human.tsv +86372 -0
- spatialcore/data/markers/canonical_markers.json +83 -0
- spatialcore/data/ontology_mappings/ontology_index.json +63865 -0
- spatialcore/plotting/__init__.py +109 -0
- spatialcore/plotting/benchmark.py +477 -0
- spatialcore/plotting/celltype.py +329 -0
- spatialcore/plotting/confidence.py +413 -0
- spatialcore/plotting/spatial.py +505 -0
- spatialcore/plotting/utils.py +411 -0
- spatialcore/plotting/validation.py +1342 -0
- spatialcore-0.1.9.dist-info/METADATA +213 -0
- spatialcore-0.1.9.dist-info/RECORD +36 -0
- spatialcore-0.1.9.dist-info/WHEEL +5 -0
- spatialcore-0.1.9.dist-info/licenses/LICENSE +201 -0
- spatialcore-0.1.9.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Synapse data download utilities.
|
|
3
|
+
|
|
4
|
+
This module provides functions for downloading reference datasets from
|
|
5
|
+
Synapse (synapse.org), a platform commonly used for sharing biomedical
|
|
6
|
+
research data.
|
|
7
|
+
|
|
8
|
+
Authentication requires a Synapse account and auth token. Set the
|
|
9
|
+
SYNAPSE_AUTH_TOKEN environment variable or pass the token directly.
|
|
10
|
+
|
|
11
|
+
References:
|
|
12
|
+
- Synapse: https://www.synapse.org/
|
|
13
|
+
- synapseclient docs: https://python-docs.synapse.org/
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Dict, List, Optional, Any
|
|
19
|
+
|
|
20
|
+
from spatialcore.core.logging import get_logger
|
|
21
|
+
|
|
22
|
+
logger = get_logger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def authenticate_synapse(auth_token: Optional[str] = None) -> bool:
|
|
26
|
+
"""
|
|
27
|
+
Authenticate with Synapse.
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
auth_token : str, optional
|
|
32
|
+
Synapse authentication token. If None, uses SYNAPSE_AUTH_TOKEN
|
|
33
|
+
environment variable.
|
|
34
|
+
|
|
35
|
+
Returns
|
|
36
|
+
-------
|
|
37
|
+
bool
|
|
38
|
+
True if authentication successful.
|
|
39
|
+
|
|
40
|
+
Notes
|
|
41
|
+
-----
|
|
42
|
+
To get a Synapse auth token:
|
|
43
|
+
1. Create account at synapse.org
|
|
44
|
+
2. Go to Account Settings > Personal Access Tokens
|
|
45
|
+
3. Generate token with "Download" scope
|
|
46
|
+
4. Set SYNAPSE_AUTH_TOKEN environment variable
|
|
47
|
+
|
|
48
|
+
Examples
|
|
49
|
+
--------
|
|
50
|
+
>>> from spatialcore.annotation.synapse import authenticate_synapse
|
|
51
|
+
>>> # Using environment variable
|
|
52
|
+
>>> success = authenticate_synapse()
|
|
53
|
+
>>> # Using direct token
|
|
54
|
+
>>> success = authenticate_synapse("my_token")
|
|
55
|
+
"""
|
|
56
|
+
try:
|
|
57
|
+
import synapseclient
|
|
58
|
+
except ImportError:
|
|
59
|
+
raise ImportError(
|
|
60
|
+
"synapseclient is required for Synapse downloads. "
|
|
61
|
+
"Install with: pip install synapseclient"
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
token = auth_token or os.environ.get("SYNAPSE_AUTH_TOKEN")
|
|
65
|
+
|
|
66
|
+
if not token:
|
|
67
|
+
logger.warning(
|
|
68
|
+
"No Synapse auth token provided. "
|
|
69
|
+
"Set SYNAPSE_AUTH_TOKEN environment variable or pass auth_token."
|
|
70
|
+
)
|
|
71
|
+
return False
|
|
72
|
+
|
|
73
|
+
try:
|
|
74
|
+
syn = synapseclient.Synapse()
|
|
75
|
+
syn.login(authToken=token, silent=True)
|
|
76
|
+
logger.info("Successfully authenticated with Synapse")
|
|
77
|
+
return True
|
|
78
|
+
except Exception as e:
|
|
79
|
+
logger.error(f"Synapse authentication failed: {e}")
|
|
80
|
+
return False
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def download_synapse_reference(
|
|
84
|
+
synapse_id: str,
|
|
85
|
+
output_dir: Path,
|
|
86
|
+
auth_token: Optional[str] = None,
|
|
87
|
+
force: bool = False,
|
|
88
|
+
) -> Path:
|
|
89
|
+
"""
|
|
90
|
+
Download reference dataset from Synapse.
|
|
91
|
+
|
|
92
|
+
Parameters
|
|
93
|
+
----------
|
|
94
|
+
synapse_id : str
|
|
95
|
+
Synapse entity ID (e.g., "syn12345678").
|
|
96
|
+
output_dir : Path
|
|
97
|
+
Directory to save downloaded file.
|
|
98
|
+
auth_token : str, optional
|
|
99
|
+
Synapse authentication token. If None, uses SYNAPSE_AUTH_TOKEN
|
|
100
|
+
environment variable.
|
|
101
|
+
force : bool, default False
|
|
102
|
+
Force re-download even if file exists.
|
|
103
|
+
|
|
104
|
+
Returns
|
|
105
|
+
-------
|
|
106
|
+
Path
|
|
107
|
+
Path to downloaded file.
|
|
108
|
+
|
|
109
|
+
Raises
|
|
110
|
+
------
|
|
111
|
+
ImportError
|
|
112
|
+
If synapseclient is not installed.
|
|
113
|
+
ValueError
|
|
114
|
+
If authentication fails or entity not found.
|
|
115
|
+
|
|
116
|
+
Examples
|
|
117
|
+
--------
|
|
118
|
+
>>> from spatialcore.annotation.synapse import download_synapse_reference
|
|
119
|
+
>>> path = download_synapse_reference(
|
|
120
|
+
... "syn12345678",
|
|
121
|
+
... output_dir=Path("./data"),
|
|
122
|
+
... )
|
|
123
|
+
>>> print(f"Downloaded to: {path}")
|
|
124
|
+
"""
|
|
125
|
+
try:
|
|
126
|
+
import synapseclient
|
|
127
|
+
except ImportError:
|
|
128
|
+
raise ImportError(
|
|
129
|
+
"synapseclient is required for Synapse downloads. "
|
|
130
|
+
"Install with: pip install synapseclient"
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
output_dir = Path(output_dir)
|
|
134
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
135
|
+
|
|
136
|
+
# Get auth token
|
|
137
|
+
token = auth_token or os.environ.get("SYNAPSE_AUTH_TOKEN")
|
|
138
|
+
if not token:
|
|
139
|
+
raise ValueError(
|
|
140
|
+
"Synapse authentication required. "
|
|
141
|
+
"Set SYNAPSE_AUTH_TOKEN environment variable or pass auth_token."
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
# Initialize client
|
|
145
|
+
syn = synapseclient.Synapse()
|
|
146
|
+
try:
|
|
147
|
+
syn.login(authToken=token, silent=True)
|
|
148
|
+
except Exception as e:
|
|
149
|
+
raise ValueError(f"Synapse authentication failed: {e}")
|
|
150
|
+
|
|
151
|
+
# Get entity info
|
|
152
|
+
try:
|
|
153
|
+
entity = syn.get(synapse_id, downloadFile=False)
|
|
154
|
+
filename = entity.name
|
|
155
|
+
expected_path = output_dir / filename
|
|
156
|
+
except Exception as e:
|
|
157
|
+
raise ValueError(f"Failed to get Synapse entity '{synapse_id}': {e}")
|
|
158
|
+
|
|
159
|
+
# Check if already downloaded
|
|
160
|
+
if expected_path.exists() and not force:
|
|
161
|
+
logger.info(f"File already exists: {expected_path}")
|
|
162
|
+
return expected_path
|
|
163
|
+
|
|
164
|
+
# Download
|
|
165
|
+
logger.info(f"Downloading Synapse entity: {synapse_id}")
|
|
166
|
+
logger.info(f" Name: {filename}")
|
|
167
|
+
|
|
168
|
+
try:
|
|
169
|
+
entity = syn.get(synapse_id, downloadLocation=str(output_dir))
|
|
170
|
+
downloaded_path = Path(entity.path)
|
|
171
|
+
logger.info(f" Downloaded to: {downloaded_path}")
|
|
172
|
+
return downloaded_path
|
|
173
|
+
except Exception as e:
|
|
174
|
+
raise ValueError(f"Failed to download '{synapse_id}': {e}")
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def get_synapse_entity_info(
|
|
178
|
+
synapse_id: str,
|
|
179
|
+
auth_token: Optional[str] = None,
|
|
180
|
+
) -> Dict[str, Any]:
|
|
181
|
+
"""
|
|
182
|
+
Get metadata for a Synapse entity.
|
|
183
|
+
|
|
184
|
+
Parameters
|
|
185
|
+
----------
|
|
186
|
+
synapse_id : str
|
|
187
|
+
Synapse entity ID.
|
|
188
|
+
auth_token : str, optional
|
|
189
|
+
Synapse authentication token.
|
|
190
|
+
|
|
191
|
+
Returns
|
|
192
|
+
-------
|
|
193
|
+
Dict[str, Any]
|
|
194
|
+
Entity metadata including:
|
|
195
|
+
- name: File name
|
|
196
|
+
- id: Synapse ID
|
|
197
|
+
- content_type: MIME type
|
|
198
|
+
- size_mb: File size in MB
|
|
199
|
+
- md5: MD5 checksum
|
|
200
|
+
- created_on: Creation date
|
|
201
|
+
- modified_on: Last modified date
|
|
202
|
+
|
|
203
|
+
Examples
|
|
204
|
+
--------
|
|
205
|
+
>>> from spatialcore.annotation.synapse import get_synapse_entity_info
|
|
206
|
+
>>> info = get_synapse_entity_info("syn12345678")
|
|
207
|
+
>>> print(f"Size: {info['size_mb']:.1f} MB")
|
|
208
|
+
"""
|
|
209
|
+
try:
|
|
210
|
+
import synapseclient
|
|
211
|
+
except ImportError:
|
|
212
|
+
raise ImportError(
|
|
213
|
+
"synapseclient is required. "
|
|
214
|
+
"Install with: pip install synapseclient"
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
token = auth_token or os.environ.get("SYNAPSE_AUTH_TOKEN")
|
|
218
|
+
if not token:
|
|
219
|
+
raise ValueError("Synapse authentication required.")
|
|
220
|
+
|
|
221
|
+
syn = synapseclient.Synapse()
|
|
222
|
+
syn.login(authToken=token, silent=True)
|
|
223
|
+
|
|
224
|
+
entity = syn.get(synapse_id, downloadFile=False)
|
|
225
|
+
|
|
226
|
+
# Extract metadata
|
|
227
|
+
info = {
|
|
228
|
+
"name": entity.name,
|
|
229
|
+
"id": entity.id,
|
|
230
|
+
"content_type": getattr(entity, "contentType", "unknown"),
|
|
231
|
+
"created_on": getattr(entity, "createdOn", None),
|
|
232
|
+
"modified_on": getattr(entity, "modifiedOn", None),
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
# Get file-specific info
|
|
236
|
+
if hasattr(entity, "contentSize"):
|
|
237
|
+
info["size_mb"] = entity.contentSize / (1024 * 1024)
|
|
238
|
+
if hasattr(entity, "md5"):
|
|
239
|
+
info["md5"] = entity.md5
|
|
240
|
+
|
|
241
|
+
return info
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def list_synapse_folder(
|
|
245
|
+
folder_id: str,
|
|
246
|
+
auth_token: Optional[str] = None,
|
|
247
|
+
file_types: Optional[List[str]] = None,
|
|
248
|
+
) -> List[Dict[str, Any]]:
|
|
249
|
+
"""
|
|
250
|
+
List contents of a Synapse folder.
|
|
251
|
+
|
|
252
|
+
Parameters
|
|
253
|
+
----------
|
|
254
|
+
folder_id : str
|
|
255
|
+
Synapse folder ID.
|
|
256
|
+
auth_token : str, optional
|
|
257
|
+
Synapse authentication token.
|
|
258
|
+
file_types : List[str], optional
|
|
259
|
+
Filter by file extensions (e.g., [".h5ad", ".h5"]).
|
|
260
|
+
|
|
261
|
+
Returns
|
|
262
|
+
-------
|
|
263
|
+
List[Dict[str, Any]]
|
|
264
|
+
List of entity metadata dictionaries.
|
|
265
|
+
|
|
266
|
+
Examples
|
|
267
|
+
--------
|
|
268
|
+
>>> from spatialcore.annotation.synapse import list_synapse_folder
|
|
269
|
+
>>> files = list_synapse_folder("syn12345", file_types=[".h5ad"])
|
|
270
|
+
>>> for f in files:
|
|
271
|
+
... print(f"{f['name']}: {f['size_mb']:.1f} MB")
|
|
272
|
+
"""
|
|
273
|
+
try:
|
|
274
|
+
import synapseclient
|
|
275
|
+
except ImportError:
|
|
276
|
+
raise ImportError(
|
|
277
|
+
"synapseclient is required. "
|
|
278
|
+
"Install with: pip install synapseclient"
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
token = auth_token or os.environ.get("SYNAPSE_AUTH_TOKEN")
|
|
282
|
+
if not token:
|
|
283
|
+
raise ValueError("Synapse authentication required.")
|
|
284
|
+
|
|
285
|
+
syn = synapseclient.Synapse()
|
|
286
|
+
syn.login(authToken=token, silent=True)
|
|
287
|
+
|
|
288
|
+
# Get folder children
|
|
289
|
+
children = list(syn.getChildren(folder_id))
|
|
290
|
+
|
|
291
|
+
results = []
|
|
292
|
+
for child in children:
|
|
293
|
+
# Filter by type if specified
|
|
294
|
+
if file_types is not None:
|
|
295
|
+
name = child.get("name", "")
|
|
296
|
+
if not any(name.endswith(ext) for ext in file_types):
|
|
297
|
+
continue
|
|
298
|
+
|
|
299
|
+
info = {
|
|
300
|
+
"name": child.get("name"),
|
|
301
|
+
"id": child.get("id"),
|
|
302
|
+
"type": child.get("type"),
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
# Add size if available
|
|
306
|
+
if "dataFileHandleId" in child:
|
|
307
|
+
try:
|
|
308
|
+
entity = syn.get(child["id"], downloadFile=False)
|
|
309
|
+
if hasattr(entity, "contentSize"):
|
|
310
|
+
info["size_mb"] = entity.contentSize / (1024 * 1024)
|
|
311
|
+
except Exception:
|
|
312
|
+
pass
|
|
313
|
+
|
|
314
|
+
results.append(info)
|
|
315
|
+
|
|
316
|
+
return results
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def download_synapse_folder(
|
|
320
|
+
folder_id: str,
|
|
321
|
+
output_dir: Path,
|
|
322
|
+
auth_token: Optional[str] = None,
|
|
323
|
+
file_types: Optional[List[str]] = None,
|
|
324
|
+
force: bool = False,
|
|
325
|
+
) -> List[Path]:
|
|
326
|
+
"""
|
|
327
|
+
Download all files from a Synapse folder.
|
|
328
|
+
|
|
329
|
+
Parameters
|
|
330
|
+
----------
|
|
331
|
+
folder_id : str
|
|
332
|
+
Synapse folder ID.
|
|
333
|
+
output_dir : Path
|
|
334
|
+
Directory to save downloaded files.
|
|
335
|
+
auth_token : str, optional
|
|
336
|
+
Synapse authentication token.
|
|
337
|
+
file_types : List[str], optional
|
|
338
|
+
Only download files with these extensions.
|
|
339
|
+
force : bool, default False
|
|
340
|
+
Force re-download even if files exist.
|
|
341
|
+
|
|
342
|
+
Returns
|
|
343
|
+
-------
|
|
344
|
+
List[Path]
|
|
345
|
+
Paths to downloaded files.
|
|
346
|
+
|
|
347
|
+
Examples
|
|
348
|
+
--------
|
|
349
|
+
>>> from spatialcore.annotation.synapse import download_synapse_folder
|
|
350
|
+
>>> paths = download_synapse_folder(
|
|
351
|
+
... "syn12345",
|
|
352
|
+
... output_dir=Path("./data"),
|
|
353
|
+
... file_types=[".h5ad"],
|
|
354
|
+
... )
|
|
355
|
+
"""
|
|
356
|
+
# List folder contents
|
|
357
|
+
files = list_synapse_folder(folder_id, auth_token, file_types)
|
|
358
|
+
|
|
359
|
+
if not files:
|
|
360
|
+
logger.warning(f"No matching files found in folder {folder_id}")
|
|
361
|
+
return []
|
|
362
|
+
|
|
363
|
+
logger.info(f"Found {len(files)} files to download")
|
|
364
|
+
|
|
365
|
+
downloaded = []
|
|
366
|
+
for file_info in files:
|
|
367
|
+
if file_info.get("type") == "org.sagebionetworks.repo.model.FileEntity":
|
|
368
|
+
try:
|
|
369
|
+
path = download_synapse_reference(
|
|
370
|
+
file_info["id"],
|
|
371
|
+
output_dir,
|
|
372
|
+
auth_token,
|
|
373
|
+
force,
|
|
374
|
+
)
|
|
375
|
+
downloaded.append(path)
|
|
376
|
+
except Exception as e:
|
|
377
|
+
logger.warning(f"Failed to download {file_info['name']}: {e}")
|
|
378
|
+
|
|
379
|
+
logger.info(f"Downloaded {len(downloaded)} files")
|
|
380
|
+
return downloaded
|