cellucid 0.0.1a0__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.
- cellucid-0.0.1a0/PKG-INFO +105 -0
- cellucid-0.0.1a0/README.md +77 -0
- cellucid-0.0.1a0/pyproject.toml +44 -0
- cellucid-0.0.1a0/setup.cfg +4 -0
- cellucid-0.0.1a0/src/cellucid/__init__.py +12 -0
- cellucid-0.0.1a0/src/cellucid/anndata_variations.py +149 -0
- cellucid-0.0.1a0/src/cellucid/prepare_data.py +960 -0
- cellucid-0.0.1a0/src/cellucid/repo_to_text.py +186 -0
- cellucid-0.0.1a0/src/cellucid.egg-info/PKG-INFO +105 -0
- cellucid-0.0.1a0/src/cellucid.egg-info/SOURCES.txt +11 -0
- cellucid-0.0.1a0/src/cellucid.egg-info/dependency_links.txt +1 -0
- cellucid-0.0.1a0/src/cellucid.egg-info/requires.txt +14 -0
- cellucid-0.0.1a0/src/cellucid.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cellucid
|
|
3
|
+
Version: 0.0.1a0
|
|
4
|
+
Summary: Utilities to export data for the 3D UMAP WebGL viewer.
|
|
5
|
+
Author: cellucid contributors
|
|
6
|
+
License: Proprietary
|
|
7
|
+
Project-URL: Repository, https://github.com/theislab/cellucid-data
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
10
|
+
Classifier: License :: Other/Proprietary License
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
Requires-Dist: numpy>=1.22
|
|
17
|
+
Requires-Dist: pandas>=1.5
|
|
18
|
+
Requires-Dist: scipy>=1.9
|
|
19
|
+
Requires-Dist: tqdm>=4.66
|
|
20
|
+
Provides-Extra: analysis
|
|
21
|
+
Requires-Dist: anndata>=0.10; extra == "analysis"
|
|
22
|
+
Requires-Dist: scanpy>=1.10; extra == "analysis"
|
|
23
|
+
Provides-Extra: docs
|
|
24
|
+
Requires-Dist: sphinx>=7.2; extra == "docs"
|
|
25
|
+
Requires-Dist: myst-parser>=2.0; extra == "docs"
|
|
26
|
+
Requires-Dist: sphinx-autodoc-typehints>=1.25; extra == "docs"
|
|
27
|
+
Requires-Dist: sphinx_rtd_theme>=1.3; extra == "docs"
|
|
28
|
+
|
|
29
|
+
<p>
|
|
30
|
+
<img src="cellucid-logo.svg" alt="Cellucid logo" width="320">
|
|
31
|
+
</p>
|
|
32
|
+
|
|
33
|
+
[](https://pypi.org/project/cellucid/)
|
|
34
|
+
[](https://pypi.org/project/cellucid/)
|
|
35
|
+
[](https://cellucid.readthedocs.io/en/latest/)
|
|
36
|
+
|
|
37
|
+
# cellucid (Python)
|
|
38
|
+
|
|
39
|
+
Python utilities for exporting AnnData/numpy payloads into the manifest + binary format consumed by the Cellucid WebGL viewer. Everything here is independent of the website; generate data wherever you like, then copy the resulting files into the viewer’s `assets/exports/` directory when you host the site.
|
|
40
|
+
|
|
41
|
+
## Layout (repo: theislab/cellucid-data)
|
|
42
|
+
- `src/cellucid/prepare_data.py`: `export_data_for_web` writes points/obs/var/connectivity binaries into an `exports/` directory (configurable).
|
|
43
|
+
- `src/cellucid/anndata_variations.py`: UMAP sweep helper for experimentation (uses Scanpy).
|
|
44
|
+
- `src/cellucid/repo_to_text.py`: utility to dump repository contents to a single text file.
|
|
45
|
+
- `notebooks/`: exploratory notebook that demonstrates exporting viewer assets.
|
|
46
|
+
- `data/`: example/raw inputs (h5ad, pickles) and experiment outputs live here; this folder stays untracked by default.
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
Requires Python 3.10+.
|
|
50
|
+
|
|
51
|
+
From the repo root:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install -e python
|
|
55
|
+
# or with optional extras
|
|
56
|
+
pip install -e python[analysis,docs]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The package name is `cellucid` and imports under `cellucid`.
|
|
60
|
+
|
|
61
|
+
## Usage
|
|
62
|
+
```python
|
|
63
|
+
import scanpy as sc
|
|
64
|
+
from cellucid.prepare_data import export_data_for_web
|
|
65
|
+
|
|
66
|
+
adata = sc.read_h5ad("path/to/adata.h5ad")
|
|
67
|
+
export_data_for_web(
|
|
68
|
+
X_umap=adata.obsm["X_umap"],
|
|
69
|
+
latent_space=adata.X,
|
|
70
|
+
obs=adata.obs,
|
|
71
|
+
var=adata.var,
|
|
72
|
+
gene_expression=adata.X,
|
|
73
|
+
connectivities=adata.obsp.get("connectivities"),
|
|
74
|
+
out_dir="exports", # default; change as needed
|
|
75
|
+
var_quantization=8,
|
|
76
|
+
obs_continuous_quantization=8,
|
|
77
|
+
compression=6,
|
|
78
|
+
)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The exporter defaults to `exports/` under your current working directory. After generation, copy or sync that folder into the website’s `assets/exports/` directory so the viewer can load the files.
|
|
82
|
+
|
|
83
|
+
To run the UMAP sweep helper:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
python -m cellucid.anndata_variations
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Ensure `python/data/raw` contains the expected h5ad/pickle files or override the module constants before calling. Paths in the notebook and sweep helper assume the `data/` directory inside this `python/` project; point them to your own locations as needed.
|
|
90
|
+
|
|
91
|
+
## Companion web viewer (theislab/cellucid)
|
|
92
|
+
The static viewer lives in a separate repository (`theislab/cellucid`). After running `export_data_for_web`, copy or sync the resulting `exports/` directory into that repo’s `assets/exports/` folder before hosting. The manifest/binary schema is shared; no build step is required on the web side.
|
|
93
|
+
|
|
94
|
+
## Documentation
|
|
95
|
+
- Build locally: `pip install -e python[docs] && sphinx-build -b html docs docs/_build/html`
|
|
96
|
+
- Read the Docs: `python/.readthedocs.yaml` targets `docs/conf.py` with the `docs` extra.
|
|
97
|
+
|
|
98
|
+
## Publishing
|
|
99
|
+
Install packaging tools if needed: `pip install build twine`
|
|
100
|
+
|
|
101
|
+
1. From `python/`, bump the version in `pyproject.toml`.
|
|
102
|
+
2. Build: `python -m build`
|
|
103
|
+
3. Upload to PyPI (or TestPyPI) with `twine upload dist/*`.
|
|
104
|
+
|
|
105
|
+
Update the `license`, `authors`, and `Repository` URL in `pyproject.toml` before publishing if needed.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
<p>
|
|
2
|
+
<img src="cellucid-logo.svg" alt="Cellucid logo" width="320">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
[](https://pypi.org/project/cellucid/)
|
|
6
|
+
[](https://pypi.org/project/cellucid/)
|
|
7
|
+
[](https://cellucid.readthedocs.io/en/latest/)
|
|
8
|
+
|
|
9
|
+
# cellucid (Python)
|
|
10
|
+
|
|
11
|
+
Python utilities for exporting AnnData/numpy payloads into the manifest + binary format consumed by the Cellucid WebGL viewer. Everything here is independent of the website; generate data wherever you like, then copy the resulting files into the viewer’s `assets/exports/` directory when you host the site.
|
|
12
|
+
|
|
13
|
+
## Layout (repo: theislab/cellucid-data)
|
|
14
|
+
- `src/cellucid/prepare_data.py`: `export_data_for_web` writes points/obs/var/connectivity binaries into an `exports/` directory (configurable).
|
|
15
|
+
- `src/cellucid/anndata_variations.py`: UMAP sweep helper for experimentation (uses Scanpy).
|
|
16
|
+
- `src/cellucid/repo_to_text.py`: utility to dump repository contents to a single text file.
|
|
17
|
+
- `notebooks/`: exploratory notebook that demonstrates exporting viewer assets.
|
|
18
|
+
- `data/`: example/raw inputs (h5ad, pickles) and experiment outputs live here; this folder stays untracked by default.
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
Requires Python 3.10+.
|
|
22
|
+
|
|
23
|
+
From the repo root:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install -e python
|
|
27
|
+
# or with optional extras
|
|
28
|
+
pip install -e python[analysis,docs]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The package name is `cellucid` and imports under `cellucid`.
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
```python
|
|
35
|
+
import scanpy as sc
|
|
36
|
+
from cellucid.prepare_data import export_data_for_web
|
|
37
|
+
|
|
38
|
+
adata = sc.read_h5ad("path/to/adata.h5ad")
|
|
39
|
+
export_data_for_web(
|
|
40
|
+
X_umap=adata.obsm["X_umap"],
|
|
41
|
+
latent_space=adata.X,
|
|
42
|
+
obs=adata.obs,
|
|
43
|
+
var=adata.var,
|
|
44
|
+
gene_expression=adata.X,
|
|
45
|
+
connectivities=adata.obsp.get("connectivities"),
|
|
46
|
+
out_dir="exports", # default; change as needed
|
|
47
|
+
var_quantization=8,
|
|
48
|
+
obs_continuous_quantization=8,
|
|
49
|
+
compression=6,
|
|
50
|
+
)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The exporter defaults to `exports/` under your current working directory. After generation, copy or sync that folder into the website’s `assets/exports/` directory so the viewer can load the files.
|
|
54
|
+
|
|
55
|
+
To run the UMAP sweep helper:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
python -m cellucid.anndata_variations
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Ensure `python/data/raw` contains the expected h5ad/pickle files or override the module constants before calling. Paths in the notebook and sweep helper assume the `data/` directory inside this `python/` project; point them to your own locations as needed.
|
|
62
|
+
|
|
63
|
+
## Companion web viewer (theislab/cellucid)
|
|
64
|
+
The static viewer lives in a separate repository (`theislab/cellucid`). After running `export_data_for_web`, copy or sync the resulting `exports/` directory into that repo’s `assets/exports/` folder before hosting. The manifest/binary schema is shared; no build step is required on the web side.
|
|
65
|
+
|
|
66
|
+
## Documentation
|
|
67
|
+
- Build locally: `pip install -e python[docs] && sphinx-build -b html docs docs/_build/html`
|
|
68
|
+
- Read the Docs: `python/.readthedocs.yaml` targets `docs/conf.py` with the `docs` extra.
|
|
69
|
+
|
|
70
|
+
## Publishing
|
|
71
|
+
Install packaging tools if needed: `pip install build twine`
|
|
72
|
+
|
|
73
|
+
1. From `python/`, bump the version in `pyproject.toml`.
|
|
74
|
+
2. Build: `python -m build`
|
|
75
|
+
3. Upload to PyPI (or TestPyPI) with `twine upload dist/*`.
|
|
76
|
+
|
|
77
|
+
Update the `license`, `authors`, and `Repository` URL in `pyproject.toml` before publishing if needed.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "cellucid"
|
|
7
|
+
version = "0.0.1a0"
|
|
8
|
+
description = "Utilities to export data for the 3D UMAP WebGL viewer."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "Proprietary" }
|
|
12
|
+
authors = [{ name = "cellucid contributors" }]
|
|
13
|
+
dependencies = [
|
|
14
|
+
"numpy>=1.22",
|
|
15
|
+
"pandas>=1.5",
|
|
16
|
+
"scipy>=1.9",
|
|
17
|
+
"tqdm>=4.66",
|
|
18
|
+
]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
22
|
+
"License :: Other/Proprietary License",
|
|
23
|
+
"Intended Audience :: Science/Research",
|
|
24
|
+
"Topic :: Scientific/Engineering :: Visualization",
|
|
25
|
+
"Topic :: Scientific/Engineering :: Bio-Informatics",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.optional-dependencies]
|
|
29
|
+
analysis = [
|
|
30
|
+
"anndata>=0.10",
|
|
31
|
+
"scanpy>=1.10",
|
|
32
|
+
]
|
|
33
|
+
docs = [
|
|
34
|
+
"sphinx>=7.2",
|
|
35
|
+
"myst-parser>=2.0",
|
|
36
|
+
"sphinx-autodoc-typehints>=1.25",
|
|
37
|
+
"sphinx_rtd_theme>=1.3",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.urls]
|
|
41
|
+
Repository = "https://github.com/theislab/cellucid-data"
|
|
42
|
+
|
|
43
|
+
[tool.setuptools.packages.find]
|
|
44
|
+
where = ["src"]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Utilities for exporting AnnData/array data for the 3D UMAP web viewer."""
|
|
2
|
+
|
|
3
|
+
from importlib import metadata as _metadata
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
__version__ = _metadata.version("cellucid")
|
|
7
|
+
except _metadata.PackageNotFoundError: # pragma: no cover - handled in dev installs
|
|
8
|
+
__version__ = "0.0.0"
|
|
9
|
+
|
|
10
|
+
from .prepare_data import export_data_for_web
|
|
11
|
+
|
|
12
|
+
__all__ = ["export_data_for_web", "__version__"]
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import gc
|
|
2
|
+
import pandas as pd
|
|
3
|
+
import itertools
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from tqdm import tqdm
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
import scanpy as sc
|
|
9
|
+
except ImportError as exc: # pragma: no cover - optional dependency
|
|
10
|
+
raise ImportError(
|
|
11
|
+
"scanpy is required for cellucid.anndata_variations; install with "
|
|
12
|
+
"`pip install cellucid[analysis]` or add scanpy to your environment."
|
|
13
|
+
) from exc
|
|
14
|
+
|
|
15
|
+
def _find_repo_root() -> Path:
|
|
16
|
+
"""Locate the python project root (contains pyproject.toml and data/)."""
|
|
17
|
+
for candidate in Path(__file__).resolve().parents:
|
|
18
|
+
if (candidate / "pyproject.toml").exists() and (candidate / "data").exists():
|
|
19
|
+
return candidate
|
|
20
|
+
return Path.cwd()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
REPO_ROOT = _find_repo_root()
|
|
24
|
+
RAW_DATA_DIR = REPO_ROOT / "data" / "raw"
|
|
25
|
+
EXPERIMENT_DIR = REPO_ROOT / "data" / "experiments"
|
|
26
|
+
|
|
27
|
+
INPUT_H5AD = RAW_DATA_DIR / "adata_latent_scvi-adata_unified_20250925_001_integration-supergpu02.scidom.de-bb886d36409e78a3.h5ad"
|
|
28
|
+
METADATA_PICKLE = RAW_DATA_DIR / "adata_obs_extracted.pickle"
|
|
29
|
+
OUTPUT_DIR = EXPERIMENT_DIR / "umap_parameter_sweep"
|
|
30
|
+
|
|
31
|
+
MIN_DISTS = [0.1, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50]
|
|
32
|
+
N_NEIGHBORS_LIST = [5, 10, 15, 30, 50, 90, 120]
|
|
33
|
+
RANDOM_SEED = 42
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _print_setup():
|
|
37
|
+
"""Log resolved paths so it's obvious what is being used."""
|
|
38
|
+
print("==== AnnData UMAP sweep setup ====")
|
|
39
|
+
print(f"Current working dir : {Path.cwd()}")
|
|
40
|
+
print(f"Repo root : {REPO_ROOT}")
|
|
41
|
+
print(f"Input h5ad : {INPUT_H5AD} (exists: {INPUT_H5AD.exists()})")
|
|
42
|
+
print(f"Metadata pickle : {METADATA_PICKLE} (exists: {METADATA_PICKLE.exists()})")
|
|
43
|
+
print(f"Output directory : {OUTPUT_DIR}")
|
|
44
|
+
print("==================================")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def validate_inputs() -> None:
|
|
48
|
+
"""Ensure required files and folders exist before heavy work."""
|
|
49
|
+
missing = [path for path in (INPUT_H5AD, METADATA_PICKLE) if not path.exists()]
|
|
50
|
+
if missing:
|
|
51
|
+
missing_list = "\n - ".join(str(path) for path in missing)
|
|
52
|
+
raise FileNotFoundError(f"Missing required input files:\n - {missing_list}")
|
|
53
|
+
|
|
54
|
+
EXPERIMENT_DIR.mkdir(parents=True, exist_ok=True)
|
|
55
|
+
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def load_and_preprocess_data():
|
|
60
|
+
validate_inputs()
|
|
61
|
+
print("Loading and preparing data (this happens only once)...")
|
|
62
|
+
adata = sc.read_h5ad(INPUT_H5AD)
|
|
63
|
+
adata_complete = pd.read_pickle(METADATA_PICKLE)
|
|
64
|
+
|
|
65
|
+
if "qc_fail" not in adata_complete.columns:
|
|
66
|
+
raise KeyError("Metadata pickle missing required column 'qc_fail'.")
|
|
67
|
+
|
|
68
|
+
missing_cells = set(adata.obs_names) - set(adata_complete.index)
|
|
69
|
+
if missing_cells:
|
|
70
|
+
raise ValueError(f"Metadata missing {len(missing_cells)} cells (e.g., {next(iter(missing_cells))}).")
|
|
71
|
+
|
|
72
|
+
adata_complete = adata_complete.loc[adata.obs_names]
|
|
73
|
+
qc_mask = ~adata_complete["qc_fail"].fillna(False)
|
|
74
|
+
|
|
75
|
+
# Apply QC filtering to both the matrix and obs
|
|
76
|
+
adata = adata[qc_mask].copy()
|
|
77
|
+
adata_complete = adata_complete.loc[qc_mask]
|
|
78
|
+
adata.obs = adata_complete
|
|
79
|
+
|
|
80
|
+
# Drop heavy derived fields to reduce per-run memory
|
|
81
|
+
for container in (adata.obsm, adata.obsp):
|
|
82
|
+
for key in list(container.keys()):
|
|
83
|
+
del container[key]
|
|
84
|
+
adata.uns.clear()
|
|
85
|
+
|
|
86
|
+
print(f"Data prepared. Final: {adata}")
|
|
87
|
+
print(f"Cells kept after QC : {adata.n_obs}")
|
|
88
|
+
print(f"Features : {adata.n_vars}")
|
|
89
|
+
return adata
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def run_parameter_sweep(_adata):
|
|
93
|
+
"""
|
|
94
|
+
Iterates through parameters, calculating UMAPs and saving results.
|
|
95
|
+
"""
|
|
96
|
+
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
|
97
|
+
param_combinations = list(itertools.product(N_NEIGHBORS_LIST, MIN_DISTS))
|
|
98
|
+
print(f"Starting sweep over {len(param_combinations)} combinations...")
|
|
99
|
+
print(f"Writing outputs to: {OUTPUT_DIR}")
|
|
100
|
+
|
|
101
|
+
existing_before = 0
|
|
102
|
+
for k, min_dist in param_combinations:
|
|
103
|
+
dist_str = f"{min_dist:.2f}".replace('.', '_')
|
|
104
|
+
filename = OUTPUT_DIR / f"adata|k__{k}|min_dist_{dist_str}.h5ad"
|
|
105
|
+
if filename.exists():
|
|
106
|
+
existing_before += 1
|
|
107
|
+
to_compute = len(param_combinations) - existing_before
|
|
108
|
+
print(f"Found {existing_before} outputs already present; {to_compute} will be computed.")
|
|
109
|
+
|
|
110
|
+
if to_compute == 0:
|
|
111
|
+
print("All combinations already exist. Nothing to do.")
|
|
112
|
+
return
|
|
113
|
+
|
|
114
|
+
skipped = 0
|
|
115
|
+
created = 0
|
|
116
|
+
|
|
117
|
+
for k, min_dist in tqdm(param_combinations, desc="Processing"):
|
|
118
|
+
dist_str = f"{min_dist:.2f}".replace('.', '_')
|
|
119
|
+
filename = OUTPUT_DIR / f"adata|k__{k}|min_dist_{dist_str}.h5ad"
|
|
120
|
+
if filename.exists():
|
|
121
|
+
skipped += 1
|
|
122
|
+
tqdm.write(f"Exists, skipping: {filename.name}")
|
|
123
|
+
continue
|
|
124
|
+
|
|
125
|
+
adata = _adata.copy()
|
|
126
|
+
try:
|
|
127
|
+
sc.pp.neighbors(adata, n_neighbors=k, random_state=RANDOM_SEED)
|
|
128
|
+
sc.tl.umap(
|
|
129
|
+
adata,
|
|
130
|
+
n_components=3,
|
|
131
|
+
min_dist=min_dist,
|
|
132
|
+
random_state=RANDOM_SEED,
|
|
133
|
+
)
|
|
134
|
+
adata.write_h5ad(filename)
|
|
135
|
+
created += 1
|
|
136
|
+
except Exception as e:
|
|
137
|
+
tqdm.write(f"Calculation error for {filename.name}: {e}")
|
|
138
|
+
gc.collect()
|
|
139
|
+
|
|
140
|
+
print(f"Finished sweep. Created {created}, skipped {skipped}, total {len(param_combinations)}.")
|
|
141
|
+
|
|
142
|
+
if __name__ == "__main__":
|
|
143
|
+
try:
|
|
144
|
+
_print_setup()
|
|
145
|
+
clean_adata = load_and_preprocess_data()
|
|
146
|
+
run_parameter_sweep(clean_adata)
|
|
147
|
+
print("Processing complete.")
|
|
148
|
+
except Exception as e:
|
|
149
|
+
print(f"An error occurred: {e}")
|