pypi cellucid 0.9.1
cellucid 0.9.1

latest release: 0.9.2
3 hours ago

Version 0.9.1 is the PyPI submission release.

Added

  • Scanpy's own X_umap is served as written: when no X_umap_1d/X_umap_2d/X_umap_3d
    key exists, a bare X_umap of 1, 2, or 3 columns is read at the dimension its column
    count states, without renaming or writing to the caller's object. A dimensional key
    still decides its own dimension and still takes precedence; any other width is refused
    with its shape named. The same rule governs add_transition_drift_to_obsm and the
    browser's h5ad and Zarr readers, so one file opens the same way everywhere.
  • A long build reports its phases. The direct-AnnData server runs five reported steps, the
    adapter reports obs classification, embedding resolution and which key resolved it,
    vector-field discovery and the graph read, and the manifest and centroid pass is a step
    of its own instead of silence after a success line. AnnDataAdapter takes quiet.
  • GET /_cellucid/protocol answers with the wire capabilities the installed package
    accepts, so a web build can ask instead of assuming.
  • A notebook learns when a command it sent was refused, rather than reading None as
    success.
  • Release-contract validation for package, citation, documentation, and downstream recipe
    metadata; installed wheel and sdist gates on Linux, macOS, and Windows before
    publication; reproducible sdist normalization.
  • Antialiasing is a live setting, applied on the next frame instead of at context
    creation, and defaults from the cell count until the checkbox is touched.
  • A dataset opens at a point size derived from its cell count; the slider now
    reaches 0.050 and every stored session keeps the size it recorded.
  • The volumetric smoke render mode is marked alpha in the viewer.

Changed

  • Web app: the synthetic benchmark generator's custom point-count ceiling is
    raised from 50,000,000 to 250,000,000. The previous value was a declared product
    limit chosen well below the hardware's; the new one is the hardware's, sitting
    just inside the MAX_TEXTURE_SIZE² bound on the renderer's interaction-state
    texture (268,435,456 on a context reporting 16,384). A request that the machine
    cannot allocate now fails as an allocation error rather than being refused in
    advance, because the limit that actually binds is the machine's memory — 16 bytes
    per point, so 4 GB of source arrays at the new ceiling — and the control cannot
    know what that is. The point-count input, both validators and the worker boundary
    all read the one constant, so they cannot drift apart.
  • The neighbor graph and the vector-field overlay are read only when asked for:
    serve_connectivity=True / --connectivity and serve_vector_fields=True /
    --vector-fields on the direct-AnnData path. Each is otherwise never touched,
    and a dataset serving neither publishes exactly what an object holding neither
    publishes. Both are read and validated in full before the socket binds, because
    the manifests the viewer fetches first declare what they contain — and on a
    large object that is the longest part of startup, for a capability most sessions
    never turn on. A 50-neighbor graph over 18 million cells is roughly 900 million
    stored neighbors. A graph asked for and absent is reported; vector fields asked
    for and undeclared serve none, which is ordinary; vector_field_default is
    refused unless the fields it selects among are served. The startup report names
    each state separately. prepare() is unchanged in Python and R — both already
    took connectivities= and vector_fields= as data — and now announces all
    three optional capabilities alike when they are not requested.
  • Connectivity validation is measurably cheaper: degrees are counted with np.bincount
    rather than the unbuffered np.add.at (about twenty times faster on that step), one
    coordinate expansion feeds every check, and a graph already in compressed form is
    compared against its own transpose instead of being rebuilt first. Measured on a
    9M-stored-neighbor graph: 1.2x faster end to end and 36% lower peak memory. A graph
    above 50,000,000 stored neighbors logs what it is about to cost.
  • The tested Python range is 3.11 through 3.14, and direct AnnData operation targets
    AnnData 0.12, Zarr 3, and numcodecs 0.16.
  • PyPI publication uses GitHub OIDC trusted publishing and accepts only a pushed tag
    matching package version metadata exactly.
  • Export format: every scientific payload is named by its integer index or a fixed
    neutral name, so no filename carries an observation key, a gene name, or a field id.
  • The notebook viewers, the session applier, the data server, and the export writer are
    packages rather than single files. Every public name is imported from where it was, and
    the servers no longer import numpy at startup.
  • Adaptive level of detail is bounded by a point budget rather than a fixed ratio.
    A cloud already inside the budget is never reduced, and one above it stops at the
    budget instead of falling to a 44x reduction on any pull-back: at 18.1M cells that
    is 2.4M points rather than 412,000.
  • Served gene columns are cached under a byte budget rather than a count of a
    hundred columns, which on an 18.1M-cell object was 7.3 GB of resident memory.

Fixed

  • cellucid serve --help no longer fails with UnicodeEncodeError on a Windows console
    using a single-byte code page such as CP1252. argparse wrote help, usage, version and
    error text straight to the stream, bypassing the escaping every other console line
    already gets; the CLI's parsers now route that text through the same writer, so any
    character the console cannot show is printed as a backslash escape instead of
    aborting the command. The serve help text itself is now plain ASCII.
  • A bind address is no longer printed as a URL. --host 0.0.0.0 used to print
    http://0.0.0.0:<port> and try to open it; the banner now prints the loopback origin,
    which is what a browser on the serving machine and the near end of an SSH tunnel both
    use, plus the machine's own name for clients elsewhere. An IPv6 literal bind is
    bracketed as a URL requires.
  • An import failure names the condition it is: a distribution absent from the environment
    (pip install), one present but too old to hold the name asked of it
    (pip install --upgrade), or a standard-library module the running interpreter cannot
    provide -- reported with that interpreter's version, its executable, and the supported
    range, because no package supplies it.
  • cellucid serve answers an operator mistake with one actionable line instead of a
    traceback, and keeps the traceback for genuine defects.
  • Both writers refuse the same numeric input everywhere it can enter. Float32
    underflow (a nonzero value below 2^-149 becoming 0.0) is now refused for vector
    fields here, and for quantized fields, embeddings, and latent_space in the R
    writer, where normalization hid the caller's magnitude from the write-time check.
  • A label the browser cannot draw, including an unpaired surrogate, is refused by name.
  • prepare() reconciles the export root, so it cannot publish coordinates the viewer is
    never told to fetch, and every manifest is checked as written bytes rather than only as
    an in-memory payload.
  • Every published payload is little-endian whatever the host is.
  • prepare() and the web cache both refuse a directory nobody set aside for them,
    including the working directory, the home directory, and paths reached through a link.
  • A constant continuous field -- a gene at one level in every cell, or a column a subset
    flattened -- has an encoding instead of failing the export.
  • debug_connection() reports the dataset probes for a published sample state.
  • Publishing a sample's starting view restates its identity. A view is captured
    against a locally served copy of the generation, and the catalog serves the
    same bytes under its own id, so a capture published as-is was refused on every
    open and the sample showed none of its view. The publish step now renames the
    capture -- only after re-deriving the generation's counts and cell-order digest
    from what it ships -- and repoints the catalog digest itself, so the artifact
    and its advertisement cannot part company.
  • A refusal that names two identical cell and gene counts as proof of a
    different dataset now names the two dataset identities instead.
  • prepare() no longer rejects an export because of a gene it was never asked to export.
  • A payload that is not entirely finite is refused with counts -- how many NaN,
    infinite, or outside float32, and the first positions -- instead of a bare 500.
    The server answers 422 with that diagnosis as JSON; the exporter and the R writer
    raise the same report, and the viewer shows it.
  • An official sample's published view applies over plain HTTP. Its integrity check used
    crypto.subtle, which is secure-context only, so a LAN bind opened the dataset
    uncoloured; the digest is computed the same way with or without WebCrypto.
  • Auto level of detail follows the camera at every dataset size. Its floor was an
    absolute point budget, unsatisfiable below two million points, so on most datasets
    Auto answered full detail at every distance and did nothing; the floor is now the
    smaller of that budget and an 8x reduction cap.
  • Level of detail no longer draws square patches. Sorting on a bit-reversed Morton
    code made each level a set of whole lattice cells; sorting on the plain code and
    bit-reversing the rank takes the same fraction from every neighbourhood. At 44x
    reduction: density error 138% to 5%, empty populated regions 42% to none.
  • The velocity overlay's Sync with LOD read the level scale backwards, running at
    full particle count on the coarsest level and disposing itself at full detail.

Security

  • Jupyter events, session uploads, web asset inventories, and server artifacts use
    authenticated schemas, bounded payloads, and path confinement.
  • Both servers validate the Host header ahead of routing, file reads, and event
    delivery. A non-loopback bind is an explicit request for network exposure and has no
    authentication of any kind: every user who can reach the port reads the dataset.

Documentation

  • The Python, R, and web guides are organized around the current executable contracts,
    with real browser screenshots for primary workflows.
  • Serving from an HPC cluster is documented end to end, including why a compute node
    commonly refuses SSH, the login-node port forward that works instead, why that requires
    --host 0.0.0.0, and why the browser address stays 127.0.0.1.
  • Corrected embedding guidance: an all-identical embedding has no finite normalization
    range and is rejected.
  • Added a complete standard scVelo recipe for vector fields.

Don't miss a new cellucid release

NewReleases is sending notifications on new releases.