Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: CI

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- uses: astral-sh/setup-uv@v5
with:
enable-cache: true

- run: uv sync --extra test
- run: uv run pytest
- run: uv build
35 changes: 35 additions & 0 deletions .github/workflows/publish-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Publish (TestPyPI)

on:
push:
tags:
- "v*-test"
workflow_dispatch:

jobs:
publish:
runs-on: ubuntu-latest
environment: testpypi
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v5

- uses: astral-sh/setup-uv@v5

- name: Show package metadata
run: |
python3 - <<'PY'
import tomllib
from pathlib import Path
project = tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8"))["project"]
assert project["name"] == "polyplot", project["name"]
print("package:", project["name"])
print("version:", project["version"])
PY

- run: uv sync --extra test
- run: uv run pytest
- run: uv build
- run: uv publish --publish-url https://test.pypi.org/legacy/
41 changes: 41 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Publish (PyPI)

on:
push:
tags:
- "v0.1"
workflow_dispatch:
inputs:
confirm_publish:
description: "Type 'publish' to upload to PyPI"
required: true
type: string

jobs:
publish:
if: ${{ inputs.confirm_publish == 'publish' }}
runs-on: ubuntu-latest
environment: pypi
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v5

- uses: astral-sh/setup-uv@v5

- name: Show package metadata
run: |
python3 - <<'PY'
import tomllib
from pathlib import Path
project = tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8"))["project"]
assert project["name"] == "polyplot", project["name"]
print("package:", project["name"])
print("version:", project["version"])
PY

- run: uv sync --extra test
- run: uv run pytest
- run: uv build
- run: uv publish
21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ From the repository root:
uv sync
```

Optional extras:

```bash
# test dependencies
uv sync --extra test

# docs tooling
uv sync --extra docs

# local development group (pytest + zensical)
uv sync --group dev
```

## Quick start (marimo)

```bash
Expand All @@ -39,12 +52,12 @@ po.plot(gdf) # meshifies from cache if needed; wireframe / opacity / BG in the
- **`meshify`**: preprocess a GeoDataFrame (`cell_id`, `ZIndex`, `geometry`), write `tiles/` and `tiles.json` under `.polyplot/<content hash>/` by default (override with `out_dir=...`). Use `smooth=False` for no Taubin smoothing, `use_cache=False` to force a rebuild.
- **`plot`**: calls `meshify` when needed, starts or reuses a local tile server, and returns a marimo `anywidget` viewer. Wireframe, opacity, and background are adjusted in the widget toolbar, not via Python.

## Full demo
## Full demo (development notebook)

The longer example is `notebook.py` (a marimo app):
The longer example is `dev/full_demo.py` (a marimo app for development/benchmarking):

```bash
uv run marimo edit notebook.py
uv run marimo edit dev/full_demo.py
```

## Sample data
Expand All @@ -63,4 +76,4 @@ The Python package lives in the `polyplot/` directory. Optional: install [gltfpa

[github.com/ckmah/polyplot](https://github.com/ckmah/polyplot)

To publish pre-rendered molab sessions, run from the repo root: `uvx marimo export session quickstart.py` (and similarly for `notebook.py` if desired).
To publish pre-rendered molab sessions, run from the repo root: `uvx marimo export session quickstart.py` (and similarly for `dev/full_demo.py` if desired).
2 changes: 1 addition & 1 deletion autoresearch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Experiment drivers and benchmarks for the meshify pipeline. This tree is **not**

| Path | Role |
|------|------|
| `scripts/meshify_benchmark_measure.py` | Runs `notebook.py`, prints seconds per cell |
| `scripts/meshify_benchmark_measure.py` | Runs `dev/full_demo.py`, prints seconds per cell |
| `scripts/run_experiments.py` | Main commit / measure / revert loop |
| `scripts/autoresearch_alg.py` | Fixed catalog of algorithmic experiments |
| `scripts/autoresearch_1k.py` | Structural grid over mesh knobs |
Expand Down
4 changes: 2 additions & 2 deletions autoresearch/scripts/meshify_benchmark_measure.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""Run ``notebook.py`` once and print meshify wall time **per cell** (seconds).
"""Run ``dev/full_demo.py`` once and print meshify wall time per cell.

Reads the last line matching ``^MESHIFY_PER_CELL_SECONDS=(.+)$`` from combined
stdout/stderr. Also writes the full capture to ``autoresearch/logs/run.log``.
Expand All @@ -26,7 +26,7 @@ def main() -> None:
log_dir = autoresearch_dir / "logs"
log_dir.mkdir(parents=True, exist_ok=True)
proc = subprocess.run(
["uv", "run", "python", str(repo_root / "notebook.py")],
["uv", "run", "python", str(repo_root / "dev" / "full_demo.py")],
cwd=repo_root,
capture_output=True,
text=True,
Expand Down
73 changes: 73 additions & 0 deletions dev/full_demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "marimo>=0.22",
# "geopandas>=1.0",
# "pyarrow",
# "polyplot @ git+https://github.com/ckmah/polyplot.git@ec17ca181279b30b4b2befddb15d5c15d118b3b0",
# ]
# ///

import marimo

__generated_with = "0.23.1"
app = marimo.App(width="full")


@app.cell
def _():
import os

import geopandas as gpd
import polyplot as po

parquet_url = os.getenv(
"POLYPLOT_PARQUET_URL",
"https://huggingface.co/datasets/ckmah/polyplot/resolve/92678be92f8e0b06fc2a32b53885c4fdf3419ee3/liver_crop.parquet",
)
return gpd, parquet_url, po


@app.cell
def _(gpd, parquet_url):
"""Load dataset from Hugging Face only (no fallbacks)."""
import pathlib
import tempfile
import urllib.parse
import urllib.request

scheme = urllib.parse.urlparse(parquet_url).scheme.lower()
if scheme in {"http", "https"}:
with urllib.request.urlopen(parquet_url, timeout=120) as response:
with tempfile.TemporaryDirectory() as temp_dir:
parquet_path = pathlib.Path(temp_dir) / "dataset.parquet"
parquet_path.write_bytes(response.read())
gdf = gpd.read_parquet(parquet_path)
else:
gdf = gpd.read_parquet(parquet_url)
return (gdf,)


@app.cell
def _(gdf, po):
import time

n_cells = int(gdf["cell_id"].nunique())
t0 = time.perf_counter()
po.meshify(gdf, use_cache=False)
elapsed = time.perf_counter() - t0
per_cell = elapsed / n_cells if n_cells else 0.0
print(f"MESHIFY_SECONDS={elapsed:.6f}", flush=True)
print(f"MESHIFY_PER_CELL_SECONDS={per_cell:.6f}", flush=True)
return


@app.cell
def _(gdf, po):
viewer = po.plot(gdf, on_demand=True, max_orbit_distance=2000)
viewer
return


if __name__ == "__main__":
app.run()
17 changes: 15 additions & 2 deletions docs/get-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,19 @@ cd polyplot
uv sync
```

Optional extras:

```bash
# run tests
uv sync --extra test

# docs tooling
uv sync --extra docs

# local development group (pytest + zensical)
uv sync --group dev
```

## Sample data

The repository includes a small **`sample_data/liver_crop_sample.parquet`** (about 50 cells in one spatial patch) for demos and CI. To build a new subset from a local full `liver_crop.parquet`, use:
Expand All @@ -35,10 +48,10 @@ A **“Open in molab”** badge in the [README](https://github.com/ckmah/polyplo

## Full demo

For a longer walkthrough, see `notebook.py`:
For a longer walkthrough, see `dev/full_demo.py`:

```bash
uv run marimo edit notebook.py
uv run marimo edit dev/full_demo.py
```

## Build this documentation site locally
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ icon: lucide/rocket

- [**Get started**](get-started.md) – install, sample data, and the quickstart notebook.
- [**User guide**](user-guide.md) – `meshify`, `plot`, and caching.
- [PyPI / source](https://github.com/ckmah/polyplot) – `uv sync` from the repository root; API docstrings in `polyplot/`.
- [PyPI / source](https://github.com/ckmah/polyplot) – `uv sync` from the repository root (`--extra test` / `--extra docs` as needed); API docstrings in `polyplot/`.

## At a glance

Expand Down
64 changes: 0 additions & 64 deletions notebook.py

This file was deleted.

1 change: 0 additions & 1 deletion polyplot/_preprocess.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from __future__ import annotations

import geopandas as gpd
import pandas as pd


def preprocess_gdf(
Expand Down
12 changes: 9 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,23 @@ dependencies = [
"shapely>=2.0",
"numpy>=1.26",
"mapbox-earcut>=1.0",
"matplotlib>=3.10.8",
"pygltflib>=1.15",
"numba>=0.65.0",
"trimesh>=4.11.5",
"scipy>=1.17.1",
]

[project.optional-dependencies]
test = [
"pytest>=8.4.0",
]
docs = [
"zensical>=0.0.36",
]

[dependency-groups]
dev = [
"pytest>=8.4.0",
"zensical>=0.0.36",
]

[tool.pytest.ini_options]
Expand All @@ -37,7 +43,7 @@ packages = ["polyplot"]

[tool.marimo.save]
# Required for stable `--watch`: otherwise autosave races with external editors
# (e.g. Cursor) and the browser can show stale code vs notebook.py on disk.
# (e.g. Cursor) and the browser can show stale code vs on-disk notebook files.
autosave = "off"

[tool.uv]
Expand Down
Loading
Loading