Skip to content

Commit 16673c7

Browse files
committed
Add demo entrypoint
1 parent e49bf62 commit 16673c7

File tree

4 files changed

+145
-13
lines changed

4 files changed

+145
-13
lines changed

pyproject.toml

+8-3
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,17 @@ classifiers = [
1919
"Programming Language :: Python :: 3.10",
2020
"Programming Language :: Python :: 3.11",
2121
]
22-
requires-python = ">=3.8"
22+
requires-python = ">=3.8,<3.12"
2323
dependencies = [
2424
"anywidget>=0.2.3",
2525
"cev-metrics>=0.1.2",
2626
"ipywidgets>=8.0.0",
2727
"jinja2>=3.0.0",
2828
"jupyter-scatter>=0.14.0",
29-
"pandas>=1.0",
29+
"pandas>=1.0,<2.0",
30+
"numpy>=1.0,<2.0",
31+
"pyarrow",
32+
"pooch>=1.3.0",
3033
]
3134
dynamic = ["version"]
3235

@@ -36,7 +39,6 @@ dev = [
3639
"black[jupyter]",
3740
"jupyterlab",
3841
"pytest",
39-
"rich",
4042
"ruff",
4143
]
4244
notebooks = [
@@ -45,6 +47,9 @@ notebooks = [
4547
"matplotlib",
4648
]
4749

50+
[project.scripts]
51+
cev = "cev._cli:main"
52+
4853
[project.urls]
4954
homepage = "https://github.com/OzetteTech/comparative-embedding-visualization"
5055

src/cev/__init__.py

+1-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
from importlib.metadata import PackageNotFoundError, version
1+
from cev._version import __version__ # noqa
22

33
import cev.metrics as metrics # noqa
44
import cev.widgets as widgets # noqa
5-
6-
try:
7-
__version__ = version("cev")
8-
except PackageNotFoundError:
9-
__version__ = "uninstalled"

src/cev/_cli.py

+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import argparse
2+
import json
3+
import os
4+
import shutil
5+
import sys
6+
import textwrap
7+
import zipfile
8+
from pathlib import Path
9+
10+
import pooch
11+
12+
from cev._version import __version__
13+
14+
_DEV = True
15+
16+
17+
def download_data() -> tuple[Path, Path]:
18+
archive = pooch.retrieve(
19+
url="https://figshare.com/ndownloader/articles/23063615/versions/1",
20+
path=pooch.os_cache("cev"),
21+
fname="data.zip",
22+
known_hash=None,
23+
)
24+
archive = Path(archive)
25+
files = [
26+
"mair-2022-tissue-138-umap.pq",
27+
"mair-2022-tissue-138-ozette.pq",
28+
]
29+
with zipfile.ZipFile(archive, "r") as zip_ref:
30+
for file in files:
31+
zip_ref.extract(file, path=archive.parent)
32+
return (
33+
archive.parent / "mair-2022-tissue-138-umap.pq",
34+
archive.parent / "mair-2022-tissue-138-ozette.pq",
35+
)
36+
37+
38+
def write_notebook(output: Path):
39+
umap_path, ozette_path = download_data()
40+
source = textwrap.dedent(
41+
f"""
42+
import pandas as pd
43+
from cev.widgets import Embedding, EmbeddingComparisonWidget
44+
45+
umap_embedding = pd.read_parquet("{umap_path}").pipe(Embedding.from_ozette)
46+
ozette_embedding = pd.read_parquet("{ozette_path}").pipe(Embedding.from_ozette)
47+
48+
EmbeddingComparisonWidget(
49+
umap_embedding,
50+
ozette_embedding,
51+
titles=("Standard UMAP", "Annotation-Transformed UMAP"),
52+
metric="confusion",
53+
selection="synced",
54+
auto_zoom=True,
55+
row_height=320,
56+
)
57+
"""
58+
).strip()
59+
60+
nb = {
61+
"cells": [
62+
{
63+
"cell_type": "code",
64+
"execution_count": None,
65+
"metadata": {},
66+
"outputs": [],
67+
"source": source,
68+
}
69+
],
70+
"metadata": {
71+
"kernelspec": {
72+
"display_name": "Python 3",
73+
"language": "python",
74+
"name": "python3",
75+
}
76+
},
77+
"nbformat": 4,
78+
"nbformat_minor": 5,
79+
}
80+
with output.open("w") as f:
81+
json.dump(nb, f, indent=2)
82+
83+
84+
def check_uv_available():
85+
if shutil.which("uv") is None:
86+
print("Error: 'uv' command not found.", file=sys.stderr)
87+
print("Please install 'uv' to run `cev demo` entrypoint.", file=sys.stderr)
88+
print(
89+
"For more information, visit: https://github.com/astral-sh/uv",
90+
file=sys.stderr,
91+
)
92+
sys.exit(1)
93+
94+
95+
def run_notebook(notebook_path: Path):
96+
check_uv_available()
97+
command = [
98+
"uvx",
99+
"--python",
100+
"3.11",
101+
"--with",
102+
"." if _DEV else f"cev=={__version__}",
103+
"--with",
104+
"jupyterlab",
105+
"jupyter",
106+
"lab",
107+
str(notebook_path),
108+
]
109+
try:
110+
os.execvp(command[0], command)
111+
except OSError as e:
112+
print(f"Error executing {command[0]}: {e}", file=sys.stderr)
113+
sys.exit(1)
114+
115+
116+
def main():
117+
parser = argparse.ArgumentParser(prog="cev")
118+
subparsers = parser.add_subparsers(dest="command", help="Available commands")
119+
subparsers.add_parser("download", help="Download the demo notebook (and data)")
120+
subparsers.add_parser("demo", help="Run the demo notebook in JupyterLab")
121+
args = parser.parse_args()
122+
123+
notebook_path = Path("cev-demo.ipynb")
124+
if args.command == "download":
125+
write_notebook(notebook_path)
126+
elif args.command == "demo":
127+
write_notebook(notebook_path)
128+
run_notebook(notebook_path)
129+
else:
130+
parser.print_help()
131+
132+
133+
if __name__ == "__main__":
134+
main()

src/cev/_widget_utils.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -399,15 +399,13 @@ def robust_labels(labels: npt.ArrayLike, robust: npt.NDArray[np.bool_] | None =
399399

400400

401401
@typing.overload
402-
def create_colormaps(cats: typing.Iterable[str]) -> dict:
403-
...
402+
def create_colormaps(cats: typing.Iterable[str]) -> dict: ...
404403

405404

406405
@typing.overload
407406
def create_colormaps(
408407
cats: typing.Iterable[str], *other: typing.Iterable[str]
409-
) -> tuple[dict, ...]:
410-
...
408+
) -> tuple[dict, ...]: ...
411409

412410

413411
def create_colormaps(

0 commit comments

Comments
 (0)