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,149 @@
|
|
|
1
|
+
"""Metadata tracking for AnnData operations."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any, Dict, Optional, Union
|
|
7
|
+
|
|
8
|
+
import anndata as ad
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class MetadataTracker:
|
|
12
|
+
"""
|
|
13
|
+
Track operations performed on AnnData objects.
|
|
14
|
+
|
|
15
|
+
Stores metadata in adata.uns['spatialcore_metadata'] and optionally
|
|
16
|
+
writes to a JSON file.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
adata
|
|
21
|
+
AnnData object to track.
|
|
22
|
+
json_path
|
|
23
|
+
Optional path to write metadata JSON file.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
adata: ad.AnnData,
|
|
29
|
+
json_path: Optional[Union[str, Path]] = None,
|
|
30
|
+
) -> None:
|
|
31
|
+
self.adata = adata
|
|
32
|
+
self.json_path = Path(json_path) if json_path else None
|
|
33
|
+
|
|
34
|
+
if "spatialcore_metadata" not in adata.uns:
|
|
35
|
+
adata.uns["spatialcore_metadata"] = {
|
|
36
|
+
"created": datetime.now().isoformat(),
|
|
37
|
+
"operations": [],
|
|
38
|
+
}
|
|
39
|
+
else:
|
|
40
|
+
# Ensure operations is a list (may be numpy array after h5ad reload)
|
|
41
|
+
meta = adata.uns["spatialcore_metadata"]
|
|
42
|
+
if "operations" not in meta:
|
|
43
|
+
meta["operations"] = []
|
|
44
|
+
elif not isinstance(meta["operations"], list):
|
|
45
|
+
meta["operations"] = list(meta["operations"])
|
|
46
|
+
|
|
47
|
+
def log_operation(
|
|
48
|
+
self,
|
|
49
|
+
function_name: str,
|
|
50
|
+
parameters: Dict[str, Any],
|
|
51
|
+
outputs: Optional[Dict[str, str]] = None,
|
|
52
|
+
) -> None:
|
|
53
|
+
"""
|
|
54
|
+
Log an operation to the metadata.
|
|
55
|
+
|
|
56
|
+
Parameters
|
|
57
|
+
----------
|
|
58
|
+
function_name
|
|
59
|
+
Name of the function that was called.
|
|
60
|
+
parameters
|
|
61
|
+
Dictionary of parameters passed to the function.
|
|
62
|
+
outputs
|
|
63
|
+
Dictionary describing where outputs were stored
|
|
64
|
+
(e.g., {'obs': 'cell_type', 'obsm': 'X_spatial_nmf'}).
|
|
65
|
+
"""
|
|
66
|
+
entry = {
|
|
67
|
+
"timestamp": datetime.now().isoformat(),
|
|
68
|
+
"function": function_name,
|
|
69
|
+
"parameters": _serialize_params(parameters),
|
|
70
|
+
}
|
|
71
|
+
if outputs:
|
|
72
|
+
entry["outputs"] = outputs
|
|
73
|
+
|
|
74
|
+
self.adata.uns["spatialcore_metadata"]["operations"].append(entry)
|
|
75
|
+
|
|
76
|
+
if self.json_path:
|
|
77
|
+
self._write_json()
|
|
78
|
+
|
|
79
|
+
def _write_json(self) -> None:
|
|
80
|
+
"""Write metadata to JSON file."""
|
|
81
|
+
with open(self.json_path, "w") as f:
|
|
82
|
+
json.dump(self.adata.uns["spatialcore_metadata"], f, indent=2)
|
|
83
|
+
|
|
84
|
+
def get_history(self) -> list:
|
|
85
|
+
"""Return list of all operations performed."""
|
|
86
|
+
return self.adata.uns["spatialcore_metadata"]["operations"]
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def update_metadata(
|
|
90
|
+
adata: ad.AnnData,
|
|
91
|
+
function_name: str,
|
|
92
|
+
parameters: Dict[str, Any],
|
|
93
|
+
outputs: Optional[Dict[str, str]] = None,
|
|
94
|
+
) -> None:
|
|
95
|
+
"""
|
|
96
|
+
Convenience function to update metadata without creating a tracker.
|
|
97
|
+
|
|
98
|
+
Parameters
|
|
99
|
+
----------
|
|
100
|
+
adata
|
|
101
|
+
AnnData object to update.
|
|
102
|
+
function_name
|
|
103
|
+
Name of the function that was called.
|
|
104
|
+
parameters
|
|
105
|
+
Dictionary of parameters passed to the function.
|
|
106
|
+
outputs
|
|
107
|
+
Dictionary describing where outputs were stored.
|
|
108
|
+
"""
|
|
109
|
+
tracker = MetadataTracker(adata)
|
|
110
|
+
tracker.log_operation(function_name, parameters, outputs)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def prepare_metadata_for_h5ad(adata: ad.AnnData) -> None:
|
|
114
|
+
"""
|
|
115
|
+
Convert metadata to h5ad-compatible format.
|
|
116
|
+
|
|
117
|
+
The operations list contains nested dicts that can't be serialized
|
|
118
|
+
directly to h5ad. This function converts it to a JSON string.
|
|
119
|
+
|
|
120
|
+
Parameters
|
|
121
|
+
----------
|
|
122
|
+
adata
|
|
123
|
+
AnnData object with spatialcore_metadata.
|
|
124
|
+
"""
|
|
125
|
+
if "spatialcore_metadata" in adata.uns:
|
|
126
|
+
meta = adata.uns["spatialcore_metadata"]
|
|
127
|
+
if "operations" in meta and isinstance(meta["operations"], list):
|
|
128
|
+
# Convert operations list to JSON string for h5ad compatibility
|
|
129
|
+
meta["operations_json"] = json.dumps(meta["operations"])
|
|
130
|
+
meta["operations"] = [] # Clear the list to avoid serialization issues
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _serialize_params(params: Dict[str, Any]) -> Dict[str, Any]:
|
|
134
|
+
"""Convert parameters to JSON-serializable format."""
|
|
135
|
+
serialized = {}
|
|
136
|
+
for key, value in params.items():
|
|
137
|
+
if isinstance(value, (str, int, float, bool, type(None))):
|
|
138
|
+
serialized[key] = value
|
|
139
|
+
elif isinstance(value, (list, tuple)):
|
|
140
|
+
serialized[key] = list(value)
|
|
141
|
+
elif isinstance(value, dict):
|
|
142
|
+
serialized[key] = _serialize_params(value)
|
|
143
|
+
elif isinstance(value, Path):
|
|
144
|
+
serialized[key] = str(value)
|
|
145
|
+
elif isinstance(value, ad.AnnData):
|
|
146
|
+
serialized[key] = f"<AnnData: {value.shape[0]} obs x {value.shape[1]} var>"
|
|
147
|
+
else:
|
|
148
|
+
serialized[key] = str(type(value).__name__)
|
|
149
|
+
return serialized
|