Skip to content

Convert: write SCope looms (regulons, embeddings, clusterings, MetaData) #61

Closed

Description

@Claptar

Part of #20. Follows #27, which reads SCope looms.

adata convert now reads a SCope loom into:

  • obsm["RegulonsAUC"] and varm["Regulons"], dataframes with a column per regulon (any other compound attribute, such as VSN's ClusterMarkers_<i>, the same way);
  • obsm["X_<name>"] per embedding, and a categorical obs column per clustering;
  • uns["scope"]: the decoded MetaData, the regulon thresholds, and each embedding's and clustering's SCope id, name and where it went.

Writing a loom still writes a plain one: the dataframes are left out with a warning, and nothing SCope shows is written in its form. Results edited as AnnData cannot go back to SCope.

Plan

AnnData SCope loom
a dataframe in obsm / varm a compound col_attrs / row_attrs, a field per column
obsm["X_*"], n x 2 Embeddings_X and Embeddings_Y, a field per id; the default (id -1) also as Embedding (_X, _Y)
categorical obs columns Clusterings, a field of cluster ids per clustering; ClusterID for the first
uns["scope"] MetaData, base64 of zlib-compressed JSON, rebuilt so its ids match the fields: embeddings, clusterings with their clusters, regulon thresholds

Ids and names come from uns["scope"]["embeddings"] and ["clusterings"] when the AnnData came from a SCope loom, so a round trip keeps them; otherwise they are given in order, the first embedding (or one a flag names) as the default.

Open questions:

  • HDF5 must fit a compound type in one object header message (64 KB): a 1,000-field compound of TF<i>_(+) names was refused, 600 fields fitted. pySCENIC's own export has the same limit. Refuse past it, or split?
  • Flags: opt in with --scope, or whenever uns["scope"] is there? --default-embedding? Which obs columns are clusterings?

Checks

  • The pySCENIC tutorial's loompy recipe reads back what was written, as test_external_readers.py does for import.
  • SCope loom → h5ad → SCope loom keeps every attribute and MetaData.
  • The file opens in SCope.

Activity

  1. added a commit that references this issue on Oct 22, 2026
  2. Claptar commented on Oct 22, 2026

    @Claptar
    ContributorAuthor

    Released in 0.15.0 (#70, with concat support in #69).

    adata convert x.h5ad -o x.loom --scope writes a loom SCope reads:

    • obsm/varm dataframes (RegulonsAUC, Regulons, ClusterMarkers_<id>[_<metric>]) as compound attributes;
    • two-column obsm arrays as Embeddings_X/_Y (and the default as Embedding; pick it with --default-embedding);
    • the clusterings a SCope import recorded, plus --clusterings a,b, as Clusterings and ClusterID;
    • MetaData (plain JSON) with embeddings, clusterings, metrics, annotations and regulon thresholds. Ids and names recorded on import are kept, so a SCope loom round-trips through h5ad.

    To fit SCope's reader: regulon names lose their spaces, clusterings and clusters are numbered 0..n-1 (marker fields renumbered with them), and markers are written only with their ClusterMarkers_<id> table and metrics. Anything HDF5 or SCope cannot take is refused or left out with a warning before writing.

    Checked on the public pySCENIC pbmc3k loom (Zenodo 10944066): loom → h5ad → --scope loom gives back the same AUC, regulons, embeddings, clusterings and thresholds through the pySCENIC tutorial's loompy recipe. SCope's own server is not installable from PyPI, so it was checked against its reading rules rather than run — a report from opening one in the viewer is welcome.

    concat now stacks obsm dataframes (following --join) and merges varm under --merge, as anndata.concat does.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions