Skip to content

Using Python CLI ​

For local processing or automation, use the ProtSpace Python package. It turns embeddings, sequences or a UniProt query into a .parquetbundle you can drag onto the explore page.

Installation ​

bash
pip install protspace

Optional extras

ExtraInstallNeeded for
localpip install "protspace[local]"on-device embedding (--backend local) instead of the Biocentral API
similaritypip install "protspace[similarity]"MMseqs2 sequence-similarity projections (-s/--similarity)
frontendpip install "protspace[frontend]"the local Dash viewer (protspace serve)

Upgrading an existing install: -s/--similarity used to work out of the box because MMseqs2 shipped in the base install. It now lives in the similarity extra, so add pip install "protspace[similarity]" if you use that flag. Nothing else changes: the base install got smaller, and on macOS and Linux the extra installs from a prebuilt wheel rather than compiling from source.

Commands ​

CommandPurpose
protspace prepareFull pipeline: embed → project → annotate → (stats) → bundle
protspace embedFASTA → per-model HDF5 embeddings
protspace projectEmbeddings → 2D/3D projections
protspace annotateFetch UniProt / InterPro / taxonomy annotations
protspace statsScore projection quality (cluster validity + faithfulness)
protspace bundleMerge projections + annotations → .parquetbundle
protspace transferFill missing annotations from nearest neighbours (EAT)
protspace styleSet colors, shapes and legend order on a bundle
protspace convertUpgrade a v1/v2 bundle to the current v3 format
protspace serveRun a local viewer

Run protspace <command> -h for the built-in help of any command.

Most users only need prepare.

Quick Start ​

From a UniProt Query ​

bash
protspace prepare -q "(ft_domain:kinase) AND (reviewed:true)" -e prot_t5 -m pca2,umap2 -o output

From Local Embeddings ​

bash
protspace prepare -i embeddings.h5 -m pca2,umap2 -o output

From a FASTA File ​

bash
protspace prepare -i sequences.fasta -e prot_t5 -m pca2,umap2 -o output

protspace prepare ​

Runs the whole pipeline in one step. Requires at least one of -i/--input or -q/--query. Comma-separated arguments (-e, -m, -a) must not contain spaces.

bash
# From HDF5 embeddings
protspace prepare -i embeddings.h5 -m pca2,umap2 -o output

# From FASTA, auto-embed with two models
protspace prepare -i sequences.fasta -e prot_t5,esm2_650m -m pca2,umap2 -o output

# With sequence similarity (MMseqs2)
protspace prepare -i emb.h5 -f seq.fasta -s -m pca2,mds2 -o output

# External HDF5 without a model_name attribute, use colon syntax
protspace prepare -i external.h5:prot_t5 -m pca2 -o output

# Compare UMAP parameters in a single run
protspace prepare -i emb.h5 -m "umap2:n_neighbors=15" -m "umap2:n_neighbors=50" -m pca2 -o output

Input ​

FlagDescriptionDefault
-i, --inputHDF5/FASTA file(s). Repeat for multi-embedding. Name override: -i f.h5:name.-
-q, --queryUniProt query (alternative to -i).-
-f, --fastaFASTA for -s/--similarity when the input is HDF5.-

Embedding ​

FlagDescriptionDefault
-e, --embedderpLM model(s), comma-separated. See Embedder models.prot_t5
-b, --backendEmbedding engine: biocentral (remote API) or local (on-device GPU/CPU).biocentral
--batch-sizeSequences per batch. Backend default when unset: 1000 (Biocentral call) or 8 (local GPU).-
--max-lengthSkip sequences longer than this (--backend local only). Skipped sequences are named in the run summary.2000

-e requires FASTA input or -q/--query; it is rejected with HDF5-only input. When a FASTA is given without -e, prot_t5 is used.

Projection ​

FlagDescriptionDefault
-m, --methodsDR methods, comma-separated or repeated. See Projection methods.pca2
-s, --similarityAlso compute a sequence-similarity projection via MMseqs2. Needs protspace[similarity].off
--metricDistance metric: euclidean, cosine, manhattan.euclidean
--random-stateRandom seed.42
--n-neighborsUMAP/PaCMAP/LocalMAP neighbors (≥ 2). Larger = more global structure.25
--min-distUMAP minimum distance (0.0–0.99).0.1
--perplexityt-SNE perplexity (≥ 5). Should be below n_samples / 3.30.0
--learning-ratet-SNE learning rate (≥ 1).200.0
--mn-ratioPaCMAP/LocalMAP mid-near ratio (0.0–1.0).0.5
--fp-ratioPaCMAP/LocalMAP further ratio.2.0
--n-initMDS initializations.4
--max-iterMDS maximum iterations.300
--epsMDS convergence tolerance.0.001

Annotations ​

FlagDescriptionDefault
-a, --annotationsAnnotation groups, individual names, or a CSV/TSV path. Repeatable.default
--scores / --no-scoresInclude annotation confidence scores.on

Output ​

FlagDescriptionDefault
-o, --outputOutput directory..
--bundled / --no-bundledBundle into a single .parquetbundle.bundled
--stats / --no-statsCompute projection quality statistics. See Projection statistics.off
--cluster-selectionWith --stats, how to choose the cluster count K: elbow, silhouette, or both.elbow
--stats-annotationWith --stats, which annotation column(s) to score: auto or a comma-separated list.auto
--refetchRecompute stages (comma-separated): query, embed, similarity, projections, uniprot, taxonomy, interpro, ted, biocentral. Shorthands: all, annotations.off
--keep-tmp / --no-keep-tmpCache intermediates in {output}/tmp/ for resumability.on
--dump-cachePrint cached annotations and exit.off
--no-logSkip writing run.log to the output directory.off
-v, --verboseVerbosity: -v = INFO, -vv = DEBUG.-

Each run appends its command, version, settings and timing to run.log in the output directory. The uniprot_release: line under ## Annotations names the UniProtKB release the annotations came from (for example 2026_03), whether they were fetched in that run or read from the annotation cache. It lists every release when cached and newly fetched values differ, says unknown for values from a cache written before releases were recorded, and says none when no UniProt data was used: the annotations came only from a CSV file, or no identifier is a UniProt accession.

Projection Methods ​

Methods require a dimension suffix: 2 for 2D, 3 for 3D.

Dimension Suffix Required

Specify pca2 or pca3, not pca alone.

Method2D3DDescription
PCApca2pca3Principal Component Analysis
UMAPumap2umap3Uniform Manifold Approximation
t-SNEtsne2tsne3t-distributed Stochastic Neighbor Emb.
PaCMAPpacmap2pacmap3Pairwise Controlled Manifold Approx.
MDSmds2mds3Multidimensional Scaling
LocalMAPlocalmap2localmap3Local-first alternative to PaCMAP

TIP

The web app renders 2D projections, prefer *2 methods. 3D projections are viewable with protspace serve.

Inline parameter overrides ​

-m accepts per-method overrides as semicolon-separated key=value pairs. The same keys exist as global flags; an inline override only affects that one method.

bash
-m "umap2:n_neighbors=50;min_dist=0.1" -m "tsne2:perplexity=50"
KeyAbbrevTypeUsed by
n_neighborsnintUMAP, PaCMAP, LocalMAP
min_distdfloatUMAP
perplexitypfloatt-SNE
learning_ratelrfloatt-SNE
mn_ratiomnfloatPaCMAP, LocalMAP
fp_ratiofpfloatPaCMAP, LocalMAP
metricmstrAll (euclidean, cosine, manhattan)
random_statersintAll
n_initniintMDS
max_itermiintMDS
epsefloatMDS

Projection naming ​

Projections are prefixed with their embedding source: ESM2-650M — PCA 2, ProtT5 — UMAP 2, MMseqs2 — MDS 2.

When the same method and dimension count appears more than once in a run with different inline overrides, the differing parameters are appended in parentheses using the abbreviations above. So

bash
protspace prepare -i emb.h5 \
  -m "umap2:n_neighbors=15" \
  -m "umap2:n_neighbors=50;min_dist=0.05" \
  -m pca2 \
  -o output

produces ProtT5 — PCA 2, ProtT5 — UMAP 2 (n=15) and ProtT5 — UMAP 2 (d=0.05, n=50). A plain umap2 with no overrides keeps the unsuffixed name.

Embedder Models ​

When the input is a FASTA file or a UniProt query, -e selects the protein language model used to embed the sequences.

bash
protspace prepare -i sequences.fasta -e prot_t5 -m pca2,umap2 -o output

Available shortcuts: prot_t5, prost_t5, esm2_8m, esm2_35m, esm2_150m, esm2_650m, esm2_3b, ankh_base, ankh_large, ankh3_large, esmc_300m, esmc_600m

Licensing

ankh_base, ankh_large and ankh3_large are CC-BY-NC-SA-4.0. All other models are permissively licensed, including the ESM-C models: esmc_300m and esmc_600m were relicensed under MIT in May 2026, retroactively, when ESM-C moved to the Chan Zuckerberg Biohub.

Local backend ​

--backend local computes embeddings on a local GPU/CPU via HuggingFace transformers instead of the remote Biocentral API, useful when the API is unavailable or when you are working offline. It needs the extra: pip install "protspace[local]".

bash
protspace prepare -i sequences.fasta -e prot_t5 --backend local -m pca2 -o output

Annotations ​

Specify annotation sources with -a. The flag is repeatable and each value may be a group name, an individual annotation name, or a path to a CSV/TSV file.

bash
# Use a predefined group
-a default        # EC, keyword, length, protein_families, reviewed
-a all            # Everything from all sources

# Pick individual sources
-a uniprot -a interpro -a taxonomy -a ted -a biocentral

# Or pick individual annotation names
-a protein_families,reviewed,pfam,genus,species

# Or provide a CSV/TSV file
-a annotations.csv
GroupSource annotations
defaultEC, keyword, length, protein_families, reviewed
uniprotGene name, EC, GO terms, subcellular location, length, and more
interproPfam, CATH, SMART, CDD, Panther, Superfamily, and more
taxonomyKingdom, phylum, class, order, family, genus, species
tedAlphaFold TED domain annotations
biocentralPredicted membrane, signal peptide, transmembrane, subcellular location
allAll of the above

See the Annotation Reference for what each individual column contains.

gene_name, protein_name and uniprot_kb_id are always included, they are fetched regardless of what you pass to -a.

Input requirements ​

Annotation sources differ in what they need to identify a protein:

RequirementSourcesWorks with -f FASTA?
UniProt accessionUniProt, taxonomy, TEDNo, accession needed
Protein sequenceInterPro, Biocentral, Pfam clansYes, provide -f

If your H5 keys are not valid UniProt accessions (for example NCBI|... or custom IDs), the accession-dependent annotations come back empty. Sequence-dependent annotations still work if you pass the original FASTA with -f. A UniProt batch that fails outright leaves its proteins' UniProt annotations empty too, and the run warns how many batches and proteins are affected.

Custom CSV annotations ​

csv
identifier,taxonomy,family,function
P12345,Bacteria,Kinase,ATP binding
P67890,Archaea,Phosphatase,Hydrolase
Q54321,Eukaryota,Kinase,Transferase

The identifier column must match the protein IDs in your embeddings file.

On column name collisions, CSV values take precedence over the fetched ones. With --keep-tmp, only API-fetched annotations are cached, the CSV is always re-read fresh.

Combining Multiple Inputs ​

When several -i inputs are given, the behaviour depends on whether they share an embedding name:

  • Same embedding name → proteins are unioned. Use this to combine datasets (for example two species both embedded with ProtT5).
  • Different embedding names → proteins are intersected. Use this to compare embeddings on the same proteins.
bash
# Union: combine two species into one visualization
protspace prepare -i human.h5:prot_t5 -i drosophila.h5:prot_t5 -m umap2 -o output

# Intersection: compare embeddings on shared proteins
protspace prepare -i prot_t5.h5 -i esm2_650m.h5 -m pca2 -o output

Duplicate proteins across same-name inputs are deduplicated when their embeddings match within tolerance; conflicting embeddings for the same protein ID raise an error.

Model Name Resolution (-i file.h5:name) ​

HDF5 files need a model name for projection labels. It is resolved in this order:

  1. Colon syntax, -i file.h5:prot_t5 (highest priority)
  2. HDF5 attribute, model_name in the root attributes, set automatically by protspace embed/prepare
  3. Error, the command exits with a copy-pasteable fix

Use the colon syntax for HDF5 files created outside ProtSpace (bio_embeddings, custom scripts, Colab). Files produced by protspace embed/prepare already carry the attribute.

bash
# External files, need colon syntax
protspace prepare -i my_embeddings.h5:prot_t5 -m pca2 -o output

# ProtSpace-generated files, just work
protspace prepare -i embeddings/prot_t5.h5 -m pca2 -o output

Check whether a file has the attribute:

bash
python -c "import h5py; print(dict(h5py.File('file.h5','r').attrs))"

Intermediate Caching ​

With --keep-tmp (the default), intermediate results are cached in {output}/tmp/ and reused on subsequent runs:

Cached itemFileReuse behavior
FASTA sequencesqueries/{query hash}.fastaSkip the download for that query
Embeddings{embedder}.h5Skip proteins already embedded from the same residues
Annotationsall_annotations.parquetFetch missing or stale columns, and missing proteins
Similarity matrixsimilarity_matrix.npySkip MMseqs2 recomputation
DR projectionsproj_{name}_{method}{dims}_{hash}.npzSkip dimensionality reduction

The annotation cache always stores scores; --no-scores strips them from the output afterwards.

The annotation cache is read per column and per protein: a source is queried only for the proteins whose values the cache cannot supply, and a cache covering more proteins than the current run keeps those extra rows. It is also written after each source finishes, not only at the end of the run, so a crash or failure in a late source (TED can run for hours) does not cost the sources that already finished. An embedding HDF5 records the backend and model that wrote it, and a run that points at another producer's file stops rather than mixing two embedding spaces.

If a source could not be fully retrieved, its columns are left out of the cache: a partly empty column is indistinguishable from one where those proteins genuinely have no entry, so caching it would make every later run reuse the gaps instead of refetching. Sources that did complete are still cached, so one flaky API does not cost an expensive UniProt fetch or a long TED pass. Values the cache already held for the failed source are kept as they were, and the cache is left untouched only when nothing else completed. Either way the run still returns everything it did retrieve, and the next run fetches the rest. Transient HTTP failures are retried with backoff first, so this is reserved for a source that is genuinely unavailable. Use --refetch annotations to rewrite the cache regardless — that is the repair path for a cache already holding empty values. See Fetching & Caching for the full picture.

Legacy annotation caches are migrated when they are read:

  • A cache that spelled an unassigned TED domain unclassified is rewritten in place to TED's -, so no refetch is needed.
  • A cache written before xref_pdb told "no PDB structure" apart from "no UniProt entry" cannot be corrected in place. A run that surfaces the column re-fetches the whole UniProt source once and warns which columns it is refreshing; cached columns from other sources are reused. A run that does not request xref_pdb drops it from the cache instead, so a later run that asks for it still migrates.
  • A cache written before protein_families kept family names whole, or before InterPro columns reached every protein sharing a sequence, is refreshed the same way: a run that requests protein_families re-fetches UniProt once, a run that requests an InterPro column re-fetches InterPro once, and a run that requests neither drops those columns. At Swiss-Prot scale this one-time refresh takes hours. An older ProtSpace (4.13 or earlier) corrupts the new multi-family values if it resumes from such a cache, so after a downgrade delete the cache or run once with --refetch uniprot.
  • A cache written before root became the top of the lineage, or before a negative predicted_transmembrane prediction was spelled non-transmembrane instead of none, is refreshed the same way: a run that requests root re-fetches the taxonomy once, a run that requests predicted_transmembrane re-fetches Biocentral once, and a run that requests neither drops those columns.

A refresh re-fetches every column of that source the cache holds, not only the requested ones, so the cache keeps them all; the run still returns only what it asked for.

Projection caches are keyed by embedding name, method, dimensions and every parameter, so changing any parameter creates a new entry. Use --refetch all to bypass all caches, or --refetch <stages> selectively (for example --refetch ted,biocentral).

Annotation name caches ​

Separate from {output}/tmp/, the reference name lookups used to make annotation IDs human-readable are cached under your home directory and shared across all runs:

CacheLocationMax agePurpose
CATH names~/.cache/protspace/cath/30 daysCATH hierarchy names, used by cath and TED domains
InterPro names~/.cache/protspace/interpro/7 daysEntry names for superfamily and panther
EC names~/.cache/protspace/enzyme/7 daysEnzyme descriptions from ExPASy
Pfam clans~/.cache/protspace/pfam_clans/30 daysPfam family → clan mapping

These are refreshed automatically once they expire; delete a directory to force a re-download. The default annotation group only needs the UniProt REST API plus ExPASy for EC names.

protspace embed ​

FASTA → one HDF5 file per model, with model_name written to the H5 root attributes.

bash
# Remote Biocentral API (default)
protspace embed -i sequences.fasta -e prot_t5 -e esm2_3b -o embeddings/

# On-device GPU/CPU, works offline
protspace embed -i sequences.fasta -e prot_t5 -o embeddings/ --backend local

# Raise the local length cap for a dataset with long sequences
protspace embed -i sequences.fasta -e prot_t5 -o embeddings/ --backend local --max-length 4000

-i, -e and -o are required. --backend, --batch-size and --max-length behave as in prepare.

When embedding fails ​

An incomplete embedding exits non-zero, on either backend. A truncated .h5 projects, bundles and scores completely normally, so a run that embedded 90% of your proteins would otherwise hand you plausible numbers computed on a silently truncated dataset.

Two outcomes are distinguished:

  • Skipped — a sequence a documented capability limit puts out of reach: longer than --max-length, or exhausting GPU memory at batch size 1 (local backend only). These are named in the run summary and do not fail the run.
  • Failed — anything else missing from the .h5. The run exits 1 and the partial output is kept, so a rerun embeds only what is missing.

Multiple -e models are independent: one failing model no longer abandons the rest, and the command exits 1 once at the end naming every model that failed.

Identifiers containing / are rejected up front on both backends — HDF5 treats / as a group separator, so such an identifier can never become the dataset you asked for.

-f/--fasta coverage: when a FASTA is supplied alongside HDF5 input, the embeddings are checked against it. Proteins in the .h5 that the FASTA does not cover are reported, and with -s/--similarity they are an error: an uncovered protein leaves its self-similarity at 0, which suppresses the similarity-to-distance conversion for the whole matrix and inverts the MDS projection. A FASTA covering more than the embeddings is normal and is not reported. The same FASTA supplies the sequences carried into the bundle, and it applies to every HDF5 input — a directory of them as much as a single file. A -f path that does not exist is rejected outright rather than ignored.

No healthy Biocentral service became available ​

With the default biocentral backend, ProtSpace waits 30 seconds for the Biocentral server and then stops with ERROR: No healthy Biocentral service became available in time, followed by the reason:

  • The server did not answer (a connection error or a 503). Biocentral is down or unreachable. Retry later, or embed on your own hardware with --backend local.
  • The server runs a version this release does not support. The message names both versions and the range your installed client accepts, for example runs Biocentral v3.0.0, but the installed biocentral-api 2.0.0 only supports servers v2.0.0 up to (not including) v3.0.0. The Biocentral client and server change major version together, and a ProtSpace release works with one of them. Upgrade with pip install -U protspace, which needs Python 3.12 or newer.

Annotation fails softly: with -a biocentral, the Biocentral columns are left empty with the same message as a warning, and are not cached, so a later run asks again.

Python 3.14 and pip

The Biocentral client declares Python <3.14, and pip honours that: on 3.14 it cannot install the current client, so pip install protspace settles on an older ProtSpace release without failing. The client itself runs on 3.14. Install with uv pip install protspace, which ignores that upper bound, or use Python 3.12 or 3.13. Check what you got with pip show protspace.

protspace project ​

Run dimensionality reduction on existing HDF5 embeddings. Writes projections_metadata.parquet and projections_data.parquet to the output directory.

bash
protspace project -i embeddings/prot_t5.h5 -i embeddings/esm2_3b.h5 -m pca2,umap2 -o projections/

Accepts the same projection flags as prepare, plus -f/--fasta for -s/--similarity.

protspace annotate ​

Extract protein identifiers from an HDF5 or FASTA file and fetch their annotations.

bash
protspace annotate -i embeddings/prot_t5.h5 -a default -o annotations.parquet
FlagDescriptionDefault
-i, --inputHDF5 or FASTA file (required).-
-a, --annotationsAnnotation sources (repeatable).default
-o, --outputOutput parquet path.annotations.parquet
--scores / --no-scoresInclude annotation confidence scores.on
--cache-dirKeep the annotation cache in this directory (created if missing), so a rerun resumes.off
--refetchWith --cache-dir, fetch these sources again (comma-separated): uniprot, taxonomy, interpro, ted, biocentral. Shorthand: annotations.off

Without --cache-dir, annotate fetches every requested source and writes only its output file. With it, the command reads and writes all_annotations.parquet in that directory under the same rules as prepare's intermediate cache: each source is saved as soon as it finishes, and a rerun with the same arguments fetches only the sources and proteins the cache is missing. Pointing it at a prepare run's {output}/tmp/ reuses that run's annotations.

bash
# Interrupted during TED? Run the same command again: UniProt and InterPro come from the cache.
protspace annotate -i sequences.fasta -a default,interpro,ted -o annotations.parquet \
  --cache-dir annotations_cache/

protspace stats ​

Score the quality of the projections in an existing project directory and write them as a statistics.parquet, the optional fifth part of a .parquetbundle.

Folding it in with bundle -s fills the bundle's statistics slot, and the web app reads that table: it draws separation-score strips in the legend, adds a By separation legend sort mode and fills the Separation section of the projection metadata panel. See Separation Scores for how the scores read in the app, and Data Format Reference for the bundle parts. The faithfulness metrics ride in the projection metadata (info_json.quality), so they show even in a bundle written without statistics.

bash
# Faithfulness only (no annotations needed)
protspace stats -i embeddings/prot_t5.h5 -p projections/ -o statistics.parquet

# Also score annotation-based validity and emit cluster legend styles
protspace stats -i embeddings/prot_t5.h5 -p projections/ -o statistics.parquet \
  -a annotations.parquet --settings-out cluster_styles.json

# Score only specific annotations
protspace stats -i embeddings/prot_t5.h5 -p projections/ -o statistics.parquet \
  -a annotations.parquet --stats-annotation major_group,ec_number
FlagDescriptionDefault
-i, --inputHDF5 embedding file(s), required. Repeatable; -i file.h5:name to override the name.-
-p, --projectionsDirectory with projections_metadata.parquet and projections_data.parquet, required.-
-o, --outputOutput statistics.parquet path, required.-
-a, --annotationsAnnotations parquet, enriched in place with per-protein cluster_* membership columns and scored for annotation-based validity plus ARI/NMI agreement.-
--settings-outWrite auto-generated cluster legend styles here (JSON) for bundle --settings. Requires -a.-
--cluster-selectionHow to choose the cluster count K: elbow, silhouette, or both.elbow
--stats-annotationWhich curated annotation column(s) to score: auto or a comma-separated list. Requires -a. The cluster_* membership columns are scored regardless of this.auto
--metricHigh-dimensional distance metric for faithfulness when the projection metadata omits one (PCA/MDS).euclidean
--seedRandom seed.42

Projection statistics ​

protspace stats and prepare --stats compute three families of metrics:

  • Annotation-based validity, silhouette, Davies–Bouldin and Calinski–Harabasz scored on an annotation's own category labels, computed once for the source embedding (the reference a projection is read against) and again for each projection. Rows land in statistics.parquet with space_kind ∈ {embedding, projection} and an annotation column. Silhouette and Davies–Bouldin are additionally emitted per category, on rows carrying a category value (aggregate rows leave it null); Calinski–Harabasz stays aggregate-only. A one-member category gets no per-category row and is excluded from the Davies–Bouldin and Calinski–Harabasz input, so an annotation with a few singleton categories still scores on the rest. Requires -a.
  • Auto-clustering and its agreement with annotations, KMeans labels the projection, with K chosen by the inertia elbow and/or maximum silhouette. Each selection becomes a per-protein membership column (cluster_elbow_<projection>, cluster_silhouette_<projection>) holding a bare cluster N label, the same shape as a curated categorical annotation. Each clustering is then scored on its own categories exactly as an annotation is, aggregate and per-category, filed under the membership column's name and tagged label_kind=kmeans_elbow|kmeans_silhouette, whether or not --stats-annotation named anything. Read those scores as descriptive rather than as a verdict: KMeans drew the boundaries being graded, and a silhouette-selected K was chosen by maximising the very number reported. Separately, each clustering's ARI/NMI agreement with every scored annotation is recorded as stat_family=cluster_agreement. --no-scores does not touch these columns, they carry no score to strip; bundles written by older versions, whose values were cluster N|0.41, still load because the app drops the suffix by column name.
  • Faithfulness, how well the projection preserves the embedding's structure: kNN-overlap, trustworthiness and continuity (local), plus random-triplet accuracy and Spearman distance correlation (global). These ride in each projection's info_json.quality, not in statistics.parquet.

Statistics are opt-in because the extra compute can be slow on large runs. A failure for one metric or projection is logged and skipped rather than failing the run, and above 5000 points the heavier metrics run on a deterministic, id-seeded subsample.

Cluster rows share the annotation column with curated ones, so filter on label_kind == 'annotation' to isolate the columns you named.

protspace bundle ​

Merge projections and annotations into a single .parquetbundle, optionally folding in a statistics parquet as the fifth part and a settings JSON as the fourth.

bash
protspace bundle -p projections/ -a annotations.parquet -o output.parquetbundle

# With projection statistics and auto-generated cluster legend styles
protspace bundle -p projections/ -a annotations.parquet \
  -s statistics.parquet --settings cluster_styles.json -o output.parquetbundle
FlagDescriptionDefault
-p, --projectionsDirectory with the projection parquet files, required.-
-a, --annotationsAnnotations parquet file, required.-
-o, --outputOutput .parquetbundle path, required.-
-s, --statisticsProjection-statistics parquet → fifth bundle part.-
--settingsSettings JSON (for example cluster legend styles) → fourth part.-

Every bundle is written with six parts (format v3); -s fills the fifth, the statistics slot, and the web app renders that table, see Separation Scores.

The annotations parquet can be the output of protspace annotate, the annotation cache prepare keeps (tmp/all_annotations.parquet), or a table of your own. annotate and the cache hold percent-encoded v2 cells, stamped protspace_format_version = 2, and those pass through unchanged; a cache written before the cache carried that stamp is recognised as one and read the same way. Any other table without the stamp, for example one you built with pandas, is read as plain text (the legacy v1 cell grammar): a literal % stays a percent sign, and a ; inside parentheses, as in Membrane (single-pass; type I), stays part of one label. Separate several values in one cell with ; outside parentheses.

A bundle never carries the internal organism_id and sequence columns, which ProtSpace fetches only to look up taxonomy and sequence-based annotations. bundle drops them even when the annotations parquet has them (for example from annotate -a sequence, whose own parquet keeps them), and transfer, convert and style drop them from an older bundle that still carries them.

protspace transfer ​

Embedding Annotation Transfer (EAT): fill missing annotation values from the nearest annotated reference protein. For every query protein with no value in the requested column, the command finds the closest reference by distance in the original high-dimensional embedding space, not in the 2D/3D projection, and copies that label along with a reliability index in [0, 1].

The curated source column (COL) is left untouched; three new columns are written: COL__pred_value (string), COL__pred_confidence (float) and COL__pred_source (string, the reference protein the label came from, for provenance).

The filters are optional. With no --query-* and no --reference-* filter, transfer runs within the bundle: every protein missing a value in a --transfer column is a query, and every protein holding one is a reference. A value is missing exactly when the web app shows it as N/A (see Missing Values), so a cell spelled N/A or None is filled, never copied. Those two sets are complements of the same missing-value test, so a protein can never be its own source, and no marker column is needed to describe "the rows that are empty". Reach for the filters only to narrow that down, for example to label one species from another or to hold out a labelled subset as a benchmark. Passing only one side is fine too: the other side stays unrestricted rather than coming back empty.

A filter you do pass has to match something. An explicit rule that selects nobody fails with an error naming that side's flags, rather than writing the bundle back unchanged. That includes a query rule broad enough to swallow every protein the reference rule matched, since a protein matching both explicit rules counts as a query.

bash
# Fill every gap in the bundle from the bundle's own annotated proteins
protspace transfer \
  -b results.parquetbundle \
  -e embeddings.h5:prot_t5 \
  -t protein_category \
  -o results.parquetbundle

# Or narrow both sides: label the TRINITY_ assembly from curated neurotoxins only
protspace transfer \
  -b results.parquetbundle \
  -e embeddings.h5:prot_t5 \
  -t protein_category \
  -o results.parquetbundle \
  --query-id-prefix TRINITY_ \
  --reference-where 'protein_category~neurotoxin'
FlagDescriptionDefault
-b, --bundleInput .parquetbundle, required.-
-e, --embeddingsHDF5 embeddings; :name suffix for external files. Required.-
-t, --transferAnnotation column to transfer (repeatable), required.-
-o, --outputOutput .parquetbundle (may overwrite the input), required.-
--kNumber of nearest neighbours considered.1
--metricDistance metric: cosine or euclidean.cosine
--query-id-prefixOnly transfer to query IDs with this prefix (repeatable).any protein missing a value
--query-whereRestrict queries to rows where col contains substr (col~substr).any protein missing a value
--reference-id-prefixOnly use references whose ID has this prefix (repeatable).any protein that has a value
--reference-whereRestrict references the same way (col~substr).any protein that has a value

A bundle carrying these columns renders the transferred proteins as ringed markers with their own legend section, see Transferred Annotations (EAT).

The output is always a format v3 bundle. A v1 or v2 input is read the way protspace convert reads it, protein IDs included, so the transfer runs over the proteins the web app showed: a row with no ID, or an earlier row whose ID a later row repeats, is neither a query nor a reference. A legacy input that convert refuses is refused here too, with the same reason, and nothing is written.

Reliability index ​

The exact form of COL__pred_confidence depends on --metric and --k:

  • --metric cosine (default), --k 1: confidence = clamp(1 - cosine_distance, 0, 1), where the cosine distance lies in [0, 2]. Cosine is the default because this value is bounded and directly interpretable as a cosine similarity.
  • --metric euclidean, --k 1: confidence = 0.5 / (0.5 + distance) (1 at distance 0, 0.5 at distance 0.5, → 0 as distance grows). This is the published goPredSim transform, calibrated for ProtT5, so on embedding spaces with much larger raw distances treat it as a ranking rather than a calibrated probability.
  • --k > 1, the mean reliability: the per-neighbour similarity above summed over the k nearest neighbours carrying the chosen label, divided by min(k, number of references). Because of this normalization, confidences are not comparable across different --k values.

A non-finite distance maps to a confidence of 0, so an invalid neighbour never scores highly.

The method follows Littmann et al., Sci Rep 2021 (DOI 10.1038/s41598-020-80786-0) and Heinzinger et al., NAR Genom Bioinform 2022 (DOI 10.1093/nargab/lqac043).

protspace style ​

Set colors, shapes and legend order on an existing bundle. See Annotation Styling for the styles-JSON format.

bash
protspace style data.parquetbundle --generate-template > styles.json
protspace style input.parquetbundle output.parquetbundle --annotation-styles styles.json
protspace style data.parquetbundle --dump-settings
FlagDescription
--annotation-stylesStyles as an inline JSON string or a path to a JSON file.
--generate-templatePrint a pre-filled template (values in frequency order) and exit.
--dump-settingsPrint the stored settings and exit.

The output path is only required when you are writing styles, not for --dump-settings or --generate-template.

The output is always a format v3 bundle. A v3 input keeps its data parts byte for byte and only its settings change. A v1 or v2 input is upgraded on the way, exactly as protspace convert would write it, and style logs a warning saying so, because builds from before format v3 cannot open the result. A legacy input that convert refuses is refused here too, with the same reason, and nothing is written.

protspace convert ​

Rewrite a bundle written in format v1 or v2 as format v3. Reading v1/v2 bundles is deprecated: they still open, with a warning, until protspace 5.0.0 removes support for them.

bash
protspace convert old.parquetbundle new.parquetbundle
protspace convert old.parquetbundle --in-place
FlagDescription
--in-placeOverwrite the input with its v3 conversion.
-v, --verboseVerbosity: -v = INFO, -vv = DEBUG.

Give either an output path or --in-place; the input is never overwritten otherwise. Settings (legend colors, shapes, order) and projection statistics are kept as they are, and the file is written atomically, so a failed run leaves the destination unchanged. A bundle that is already v3 is reported as current and nothing is written. The internal organism_id and sequence columns an older bundle may carry are dropped, as from every bundle ProtSpace writes.

The converted bundle holds the proteins the web app showed for the old file. Older web builds were lenient about the protein ID column, and convert reads it the way they did, with a warning each time: without a protein_id or identifier column, the first column whose name contains id, uniprot or entry (else the first column) is the ID; a row with no ID is dropped; and when two rows share an ID, the later one is kept. A bundle whose projection metadata and projection rows name different projections, or that has two rows for one protein in one projection, is refused with a message saying so.

Without a Python install, load the bundle at protspace.app/explore and export it again: the web app always exports v3. That export leaves out any protein no projection places (an annotations row without coordinates), which convert keeps. See Legacy formats.

protspace serve ​

Run a local Dash viewer. Most users should explore bundles in the hosted viewer at protspace.app/explore: nothing to install, and drag & drop works. Use serve for offline viewing; it also renders 3D projections.

bash
protspace serve output.parquetbundle --port 8050 --pdb-zip structures.zip
FlagDescriptionDefault
--portPort to run the server on.8050
--pdb-zipZIP file containing PDB structures.-

See Also ​

Released under the MIT License.