ClockCytePy
A Python port of ClockCyteR.spatial — spatiotemporal and network analysis of circadian rhythms in organotypic suprachiasmatic nucleus (SCN) slices.
Nothing here is new science. ClockCytePy reproduces the published R analysis (Ferrari et al. 2026, Advanced Science, doi 10.1002/advs.75427) in Python, validated number-for-number against the toy dataset that ships with the original package.
It ports two trees: the public ClockCyteR.spatial v0.1.0, and Marco Ferrari's
unpublished continuation of it. Neither is a superset of the other, so the port is a
merge — see
docs/port-plan/private-fork-inventory.md.
Because that merge includes work that exists nowhere public, it is published with
Marco's agreement and with him as co-author.
Scope
In scope — everything either tree of ClockCyteR.spatial does, starting from per-region intensity tables:
- outlier removal, LOESS smoothing, polynomial detrending
- FFT-NLLS rhythm fitting (period, phase, amplitude, RAE, AUC) per region
- spatial maps and local coherence of every fitted parameter
- correlation networks, Leiden clustering, node and cluster metrics
- circular statistics, group comparisons, batch orchestration and reports
- the whole-SCN Z-profile trace plot, and cross-slice aggregation, both from the unpublished fork
Out of scope — deliberately. Cell segmentation, tracking, drift correction, damping estimates, rhythmicity significance testing, anatomical core/shell priors and hierarchical statistics all live in Auto-Organotypic, upstream or downstream of this package. ClockCytePy is not the place to extend the method; it is the place to reproduce it.
Boundary
images ──► Auto-Organotypic ──► per-region CSVs ──► ClockCytePy ──► per-cell tables
(upstream: registration, (the ClockCyteR (this package) (downstream:
outline, traces) _results format) Auto-Organotypic)
ClockCytePy imports nothing from Auto-Organotypic, and Auto-Organotypic imports nothing from ClockCytePy. They meet at a file format, never at a function call.
Install
pip install ClockCytePy # analysis only
pip install "ClockCytePy[plots]" # + the 34 figure types
pip install "ClockCytePy[plots,repro]" # + each figure carries the table it was drawn from
From a checkout, pip install -e . with the same extras. The import name is
clockcytepy.
Needs Python 3.10+. No R at runtime, ever — R appears exactly once, by hand, to bake the validation fixtures.
The repro extra pulls in ReproFig, which draws nothing: it
wraps the save, embedding the plotted CSV, the source-file hashes and the
package version inside the image so a figure can be audited later. Everything
below works without it, and the image is identical either way.
Use
from clockcytepy import (
Params, Channel, index_files, analyze_project, ranges_calculation, generate_plots,
)
params = Params(
channels={
"Ch1": Channel(enabled=False, label="red_channel", grid_file="Ch1_1_grid_vals.csv"),
"Ch2": Channel(enabled=True, label="Syn-Axon-GCaMP6s", grid_file="Ch2_2_grid_vals.csv"),
"Ch3": Channel(enabled=False, label="Brightfield", grid_file="Ch3_3_grid_vals.csv"),
},
coherence=True, normalize_phase=True, time_res=0.5,
intervals={"interval1": (0, 72)}, time_window=True, pixel_fct=2.82,
base_dir=base_dir,
)
files = index_files(params.base_dir)
results = analyze_project(files, params)
params.plotting.ranges = ranges_calculation(params, results)
generate_plots(results, params)
Anyone holding the R script should recognise that line for line. Output
filenames and folder layout match the R package's, so a ClockCytePy _results
folder and a ClockCyteR one are interchangeable.
Status
Stages 01-10 complete. 355 tests pass — 150 parity tests against the frozen R fixtures, 81 for the renderers and standalone helpers, 46 for paths the reference run never reaches, and 78 independence checks.
Every quantity the R package reports is reproduced bit-exactly, with one
exception — the offset column, which differs on one cell in 1199 and which
nothing downstream reads. Full evidence in
docs/parity-report.md.
| I/O, preprocessing, rhythm fitting | exact; cell membership identical |
| coherence, circular statistics | exact |
| correlation network | edge list identical, in order; node metrics exact |
| clustering | cannot be exact — R is not reproducible against itself. See below |
| orchestration, summaries, plot ranges | exact |
| plot data layer (8a) | exact, including the fork's Z-profile path |
| plot renderers (8b) | 30 of 34 types draw — the other four are dead branches in R. 249 of 249 files R writes are reproduced, name for name, across all three configurations; same data, ranges and colours, not pixels |
| standalone helpers | all eight ported, including network_plot's six styles |
| cross-slice aggregation (10) | done, validated to a lower standard by design |
The finding worth knowing. cluster_leiden is stochastic and the R package
sets no seed, so cluster assignments are not reproducible — two runs of the
published code on the identical graph agree on as little as 52% of cells on the
smallest slice. ClockCytePy samples the same distribution (it reproduces R's
stored partition exactly on all three slices) and exposes a seed argument so a
Python run can be made repeatable. It does not change the default, because that
would change behaviour.
Four plot types build nothing — in the R source, and therefore here.
period_variance, phase_variance and two_phases_rayleigh are empty
switch branches that report success and then hand the saver R's base plot
function; overlap_hetmap is disabled with if (FALSE). None is in a
default list. They are reproduced as skips, with the reason recorded, rather
than invented.
Seeing the figures
docs/figures/r-vs-python-figure-parity
— a 28-frame review stack, ClockCyteR left and ClockCytePy right, one frame per
plot type on slice L_1. preview.png is the first frame.
For Marco
docs/handoff-for-marco.md — the seeding decision, two questions the code could not settle, the attribution gate, and a full list of what was found and deliberately not fixed.
Plan and its corrections: docs/port-plan/00_overview.md, docs/port-plan/CORRECTIONS.md.
Release files for ClockCytePy 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| clockcytepy-0.1.0.tar.gz | 76.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| clockcytepy-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 160.7 kB
Release files / clockcytepy-0.1.0.tar.gz
| Download URL | clockcytepy-0.1.0.tar.gz |
|---|---|
| Size | 76.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c5081c3ed073aec59ccc0a1795a1e9a737eb14fa413391c68310dc836fd36d22
|
|
BLAKE2b-256 checksum How to use checksums |
7fca79349e70f6938b25df8ada63f78e9fce1bcdbf1c5c58d7ec7513647feb01
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|
Release files / clockcytepy-0.1.0-py3-none-any.whl
| Download URL | clockcytepy-0.1.0-py3-none-any.whl |
|---|---|
| Size | 84.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8ce9a349ff934b4fd3627b956c769320ba526f67838b51e915b144c0f6a49207
|
|
BLAKE2b-256 checksum How to use checksums |
8b41b9575867e164a02aecfe2cc0156d5cae2a9dbb873c59bddf95bf2fefa3e8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|