From 94b0e0573d8d7d71971088662f3621d6edaabe28 Mon Sep 17 00:00:00 2001 From: jsture Date: Wed, 10 Jun 2026 12:19:38 +0200 Subject: [PATCH 1/6] Bump GitHub Actions and pre-commit hooks - actions/checkout v4 -> v6, upload-artifact v4 -> v7, download-artifact v4 -> v8, astral-sh/setup-uv v5 -> v8 (Node 20 runners are deprecated, forced to Node 24 from 2026-06-16) - ruff pre-commit hook v0.15.15 -> v0.15.16 Co-Authored-By: Claude Fable 5 --- .github/workflows/ci.yml | 14 +++++++------- .github/workflows/docs.yml | 4 ++-- .github/workflows/release.yml | 8 ++++---- .pre-commit-config.yaml | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c4a6ec83..cebadc2f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,10 +17,10 @@ jobs: name: Lint & type-check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v8 with: enable-cache: true @@ -41,10 +41,10 @@ jobs: name: Build docs runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v8 with: enable-cache: true @@ -62,10 +62,10 @@ jobs: matrix: python-version: ["3.13"] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v8 with: enable-cache: true @@ -86,7 +86,7 @@ jobs: - name: Upload coverage if: matrix.python-version == '3.12' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: coverage-xml path: coverage.xml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 71ee8389..13e143d5 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -16,10 +16,10 @@ jobs: deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v8 with: enable-cache: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 981fa4c7..7ea59568 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,10 +19,10 @@ jobs: name: Build distributions runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v8 - name: Build sdist + wheel run: uv build @@ -31,7 +31,7 @@ jobs: run: uvx twine check dist/* - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: dist path: dist/* @@ -44,7 +44,7 @@ jobs: permissions: id-token: write # OIDC for Trusted Publishing steps: - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist path: dist diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a1c7a3da..5017bf04 100755 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,7 +16,7 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.15.15 + rev: v0.15.16 hooks: # Run the linter. - id: ruff From 8618bd3e1362032287bb0c70d2bfa76bbbe188f8 Mon Sep 17 00:00:00 2001 From: jsture Date: Wed, 10 Jun 2026 12:19:56 +0200 Subject: [PATCH 2/6] Refresh stale release metadata - README: add PyPI version badge; update the changelog blurb from the pre-fork 0.2.0 notes to the 0.3.0 release and link CHANGELOG.md - CITATION.cff: version 0.1.0 -> 0.3.0, add date-released; replace the schema-invalid `article-number` key with `number` (file now validates against CFF 1.2) - docs: single-source the changelog page by snippet-including the root CHANGELOG.md (via pymdownx.snippets) instead of maintaining a drifted copy Co-Authored-By: Claude Fable 5 --- CITATION.cff | 5 +++-- README.md | 12 +++++++++--- docs/changelog.md | 14 +------------- mkdocs.yml | 2 ++ 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index 073a62b0..14093b48 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -4,7 +4,8 @@ message: >- fork and also cite the original TopOMetry work listed under references. type: software title: topometry-nosc -version: 0.1.0 +version: 0.3.0 +date-released: 2026-06-10 authors: - family-names: Madsen given-names: Jakob @@ -34,6 +35,6 @@ references: journal: eLife year: 2024 volume: 13 - article-number: RP100361 + number: RP100361 doi: 10.7554/eLife.100361.2 url: "https://doi.org/10.7554/eLife.100361.2" diff --git a/README.md b/README.md index 79182a1c..380f476d 100755 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +[![PyPI](https://img.shields.io/pypi/v/topometry-nosc)](https://pypi.org/project/topometry-nosc/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/HauserGroup/topometryNoSC/blob/master/notebooks/example.ipynb) [![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv) @@ -161,9 +162,14 @@ Example `TopOGraph` fit: ## Changelog -**0.2.0** — Core-only release -- Removed single-cell / scanpy / AnnData wrappers (now a standalone geometry toolkit) -- Core API unchanged: `TopOGraph`, spectral scaffolds, graph operators, layouts, metrics, plotting +**0.3.0** — First PyPI release +- Published to PyPI as [`topometry-nosc`](https://pypi.org/project/topometry-nosc/) +- Simplified internals delegate to scikit-learn/SciPy/umap-learn where possible; + slimmer runtime dependencies (ANN backends and extra layouts are opt-in extras) +- Standalone building blocks (`kNN`, `Kernel`, `cknn_graph`, `EigenDecomposition`, + `LE`, `Projector`) usable and tested outside the `TopOGraph` orchestrator + +See [CHANGELOG.md](CHANGELOG.md) for the full history. #### Citation diff --git a/docs/changelog.md b/docs/changelog.md index 3bf68e65..786b75d5 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,13 +1 @@ -# Changelog - -## Unreleased - -- Documentation migrated to MkDocs Material. -- Added API reference through mkdocstrings. -- Added provenance and citation documentation. - -## v2.0.0 — Core-only release - -- Removed single-cell / scanpy / AnnData wrappers (now a standalone geometry toolkit). -- Core API unchanged: `TopOGraph`, spectral scaffolds, graph operators, layouts, - metrics, plotting. +--8<-- "CHANGELOG.md" diff --git a/mkdocs.yml b/mkdocs.yml index 6d1495dd..7bfd3f7f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -93,6 +93,8 @@ markdown_extensions: permalink: true - tables - pymdownx.superfences + - pymdownx.snippets: + check_paths: true - pymdownx.highlight - pymdownx.inlinehilite - pymdownx.arithmatex: From 20fc488c668cd38f3e17d23574de147b722e74a3 Mon Sep 17 00:00:00 2001 From: jsture Date: Thu, 11 Jun 2026 09:11:08 +0200 Subject: [PATCH 3/6] Address audit findings on layout simplification - Projector spectral initialization now uses LE() directly (normalized Laplacian, drop_first) instead of EigenDecomposition's default DM method, matching LayoutBuildMixin.spectral_layout; random fallback is float32 for consistency - eigen.py: use the _eigsh_tol helper instead of a broad type ignore on the eigsh tol argument - correct stale checkpointing comments/docstrings in Projector and fuzzy_embedding: optimization is delegated to umap-learn, so only initial (epoch 0) and final snapshots are captured, not per-epoch Verified: umap-learn is a core dependency and both optimize_layout_euclidean/_generic accept move_other in the pinned version (>=0.5.8, installed 0.5.9+). Co-Authored-By: Claude Fable 5 --- src/topo/layouts/map.py | 7 ++++--- src/topo/layouts/projector.py | 26 ++++++++++++++++---------- src/topo/spectral/eigen.py | 2 +- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/topo/layouts/map.py b/src/topo/layouts/map.py index b11909d7..67a0fd76 100755 --- a/src/topo/layouts/map.py +++ b/src/topo/layouts/map.py @@ -141,11 +141,12 @@ def fuzzy_embedding( euclidean_output : bool, default=True Whether to use the faster code specialised for euclidean output metrics save_every : int or None, optional - If provided and >0, store the embedding every `save_every` epochs into + If provided and >0, store the final embedding into `aux_data["checkpoints"]` as a list of dicts: [{"epoch": e, "embedding": Y_e}, ...] - WARNING: storing many snapshots can be memory intensive. Consider - passing `save_callback` to stream snapshots to disk. + Per-epoch checkpointing is not implemented since layout optimization + is delegated to `umap-learn`; at most the initial (epoch 0) and final + snapshots are captured. save_limit : int or None, optional Maximum number of snapshots to keep in-memory in `aux_data`. If exceeded, the earliest snapshots are discarded (FIFO). diff --git a/src/topo/layouts/projector.py b/src/topo/layouts/projector.py index 05767c11..ffa793e9 100755 --- a/src/topo/layouts/projector.py +++ b/src/topo/layouts/projector.py @@ -23,7 +23,7 @@ from topo.base.ann import kNN from topo.layouts.isomap import Isomap from topo.layouts.map import fuzzy_embedding -from topo.spectral.eigen import EigenDecomposition +from topo.spectral import LE from topo.tpgraph.kernels import Kernel from topo.utils._utils import get_landmark_indices @@ -73,10 +73,11 @@ class Projector(BaseEstimator, TransformerMixin): projection_method : str, default='Isomap' Which projection method to use. `UMAP` delegates to `umap-learn`; `MAP` - is TopoMetry's local checkpoint-aware graph-layout optimizer. Current options are: + is TopoMetry's graph-layout optimizer (optional initial/final snapshot + capture). Current options are: * 'Isomap' - one of the first manifold learning methods * ['t-SNE'](https://github.com/DmitryUlyanov/Multicore-TSNE) - a classic manifold learning method - * 'MAP' - local checkpoint-aware graph-layout optimization + * 'MAP' - graph-layout optimization with initial/final snapshot capture * ['UMAP'](https://umap-learn.readthedocs.io/en/latest/index.html) - upstream `umap-learn` estimator * ['PaCMAP'](http://jmlr.org/papers/v22/20-1061.html) (Pairwise-controlled Manifold Approximation and Projection) - for balanced visualizations * ['TriMAP'](https://github.com/eamid/trimap) - dimensionality reduction using triplets @@ -125,11 +126,11 @@ def __init__( keep_estimator=False, random_state=None, verbose=False, - # ---- NEW: checkpointing passthrough to MAP ---- - save_every=None, # int or None: store Y every `save_every` epochs + # ---- checkpointing passthrough to MAP ---- + save_every=None, # int or None: store final MAP embedding in aux checkpoints save_limit=None, # cap snapshots kept in memory save_callback=None, # callable(epoch:int, Y:np.ndarray) -> None - include_init_snapshot=True, # store epoch=0 (post-init) snapshot + include_init_snapshot=True, # store epoch=0 snapshot before SGD ): self.n_components = n_components self.metric = metric @@ -317,9 +318,14 @@ def fit(self, X: np.ndarray | csr_matrix | Kernel, **kwargs: Any) -> "Projector" if self.init == "spectral": try: self.init_Y_ = np.asarray( - EigenDecomposition( - n_components=self.n_components - ).fit_transform(K) + LE( + K, + n_eigs=int(self.n_components), + laplacian_type="normalized", + drop_first=True, + return_evals=False, + ), + dtype=np.float32, ) except Exception: warnings.warn( @@ -327,7 +333,7 @@ def fit(self, X: np.ndarray | csr_matrix | Kernel, **kwargs: Any) -> "Projector" ) self.init_Y_ = self.random_state.randn( _n_rows(K, "projection graph"), self.n_components - ) + ).astype(np.float32) else: self.init_Y_ = self.random_state.randn( _n_rows(K, "projection graph"), self.n_components diff --git a/src/topo/spectral/eigen.py b/src/topo/spectral/eigen.py index a5c5d0c3..0354a88d 100755 --- a/src/topo/spectral/eigen.py +++ b/src/topo/spectral/eigen.py @@ -164,7 +164,7 @@ def eigendecompose( G_csr, k=k, which="LM" if largest else "SM", - tol=float(eigen_tol), # type: ignore + tol=_eigsh_tol(eigen_tol), ) except ArpackError as exc: raise RuntimeError( From 684f7026e3959289574cab1cac38fa7218c507df Mon Sep 17 00:00:00 2001 From: jsture Date: Mon, 29 Jun 2026 10:36:57 +0100 Subject: [PATCH 4/6] removed mkdocs --- mkdocs.yml | 101 ----------------------------------------------------- 1 file changed, 101 deletions(-) delete mode 100644 mkdocs.yml diff --git a/mkdocs.yml b/mkdocs.yml deleted file mode 100644 index 7bfd3f7f..00000000 --- a/mkdocs.yml +++ /dev/null @@ -1,101 +0,0 @@ -site_name: topometry-nosc -site_description: "An independently maintained, heavily modified fork of TopOMetry." -site_url: https://HauserGroup.github.io/topometryNoSC/ -repo_url: https://github.com/HauserGroup/topometryNoSC -repo_name: HauserGroup/topometryNoSC - -watch: - - docs - - src/topo - -theme: - name: material - logo: assets/topometry_logo.png - favicon: assets/topometry_logo.png - icon: - repo: fontawesome/brands/github - font: - text: Nunito - code: JetBrains Mono - palette: - - media: "(prefers-color-scheme: light)" - scheme: default - primary: pink - accent: teal - toggle: - icon: material/weather-night - name: Switch to dark mode - - media: "(prefers-color-scheme: dark)" - scheme: slate - primary: pink - accent: teal - toggle: - icon: material/weather-sunny - name: Switch to light mode - features: - - navigation.tabs - - navigation.sections - - navigation.top - - navigation.indexes - - navigation.footer - - content.code.copy - - content.code.annotate - - search.suggest - - search.highlight - -extra_css: - - stylesheets/extra.css - -extra_javascript: - - javascripts/mathjax.js - - https://unpkg.com/mathjax@3/es5/tex-mml-chtml.js - -plugins: - - search - - social - - mkdocstrings: - handlers: - python: - paths: [src] - options: - docstring_style: numpy - show_source: false - separate_signature: true - show_signature_annotations: true - members_order: source - merge_init_into_class: true - -nav: - - Home: index.md - - Installation: installation.md - - Quickstart: quickstart.md - - 'Practical FAQ: Manifold Learning & Dimensionality Reduction': faq.md - - Tutorials: - - 'Step by step: Manifold Learning Pipeline': tutorials/step-by-step.md - - Plotting: tutorials/plotting.md - - Data provenance: tutorials/data-provenance.md - - 'Concepts: Graphs & Spectral Scaffolds': concepts.md - - 'Math Details: LBO, Diffusion Maps, & CkNN': math_details.md - - 'Background: CkNN, Diffusion Maps, & Manifold Learning': background.md - - API Reference: - - Overview: api/index.md - - 'Main workflow: TopOGraph': api/topograph.md - - Advanced estimators: api/advanced.md - - Evaluation metrics: api/metrics.md - - Plotting: api/plotting.md - - Developer reference: api/internal.md - - Citation: citation.md - - Changelog: changelog.md - -markdown_extensions: - - admonition - - toc: - permalink: true - - tables - - pymdownx.superfences - - pymdownx.snippets: - check_paths: true - - pymdownx.highlight - - pymdownx.inlinehilite - - pymdownx.arithmatex: - generic: true From 7ca4c768adc41ebbec3101e151fd5e2f0a8425aa Mon Sep 17 00:00:00 2001 From: jsture Date: Mon, 29 Jun 2026 10:39:24 +0100 Subject: [PATCH 5/6] fixed setup-uv version 8 to 8.2.0 --- .github/workflows/ci.yml | 6 +++--- .github/workflows/docs.yml | 2 +- .github/workflows/release.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cebadc2f..1c47ec7f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/checkout@v6 - name: Install uv - uses: astral-sh/setup-uv@v8 + uses: astral-sh/setup-uv@v8.2.0 with: enable-cache: true @@ -44,7 +44,7 @@ jobs: - uses: actions/checkout@v6 - name: Install uv - uses: astral-sh/setup-uv@v8 + uses: astral-sh/setup-uv@v8.2.0 with: enable-cache: true @@ -65,7 +65,7 @@ jobs: - uses: actions/checkout@v6 - name: Install uv - uses: astral-sh/setup-uv@v8 + uses: astral-sh/setup-uv@v8.2.0 with: enable-cache: true diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 13e143d5..6c852a9e 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -19,7 +19,7 @@ jobs: - uses: actions/checkout@v6 - name: Install uv - uses: astral-sh/setup-uv@v8 + uses: astral-sh/setup-uv@v8.2.0 with: enable-cache: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7ea59568..d78b950f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@v6 - name: Install uv - uses: astral-sh/setup-uv@v8 + uses: astral-sh/setup-uv@v8.2.0 - name: Build sdist + wheel run: uv build From edbb958fe2972f83ae4af1c12d8ff2fcb2cccc71 Mon Sep 17 00:00:00 2001 From: jsture Date: Mon, 29 Jun 2026 10:41:13 +0100 Subject: [PATCH 6/6] docs to zensical workflow --- .github/workflows/docs.yml | 39 +++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 6c852a9e..72e104fd 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -1,30 +1,35 @@ -name: Deploy docs +name: Docs on: push: - branches: [master] + branches: [main] workflow_dispatch: +# Deploy via the GitHub Pages "GitHub Actions" source (set it in repo +# Settings -> Pages). Zensical has no `gh-deploy`; we build and upload the +# site as a Pages artifact instead. permissions: - contents: write - -concurrency: - group: docs-${{ github.ref }} - cancel-in-progress: true + contents: read + pages: write + id-token: write jobs: deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - - name: Install uv - uses: astral-sh/setup-uv@v8.2.0 + - uses: actions/configure-pages@v6 + - uses: actions/checkout@v7 + - uses: astral-sh/setup-uv@v8.2.0 with: + python-version: "3.13" enable-cache: true - - - name: Sync (docs group) - run: uv sync --group docs - - - name: Deploy to GitHub Pages - run: uv run mkdocs gh-deploy --force + - run: uv sync --dev + - run: uv run zensical build + - uses: actions/upload-pages-artifact@v6 + with: + path: site + - uses: actions/deploy-pages@v6 + id: deployment