volumizer discovers and annotates occluded volumes in proteins including:
cavities: Volumes within a protein that do not make any contacts with bulk solvent. Useful for e.g. carrying cargo.pockets: Volumes on the protein surface that make a single contact with bulk solvent. Useful for e.g. ligand binding or catalysis.pores: Volumes connecting two bulk solvent surfaces. Useful for e.g. filtering solutes.
The core classifier also identifies hubs (volumes connecting more than two
bulk-solvent surfaces), but CLI-written annotation outputs omit hubs by default.
Pass --include-hubs to restore hub emission in CLI JSON/CIF outputs.
Here is shown an example pore identified and annotated (red) in PDB 4JPN (green).

The same pore volume annotated (red) shown as a slice through the protein (grey).

The dataframe output shows volume/dimensinos of each occluded volume in the structure
| id | type | volume | x | y | z | |
|---|---|---|---|---|---|---|
| 0 | 0 | pore | 38286.0 | 108.221 | 38.574 | 36.310 |
| 1 | 0 | 189.0 | 8.214 | 5.628 | 0.000 | |
| 2 | 1 | 162.0 | 6.635 | 3.843 | 2.840 | |
| 3 | 2 | 162.0 | 7.298 | 4.002 | 2.557 | |
| 4 | 3 | 162.0 | 10.757 | 2.701 | 0.000 | |
| 5 | 4 | 135.0 | 6.000 | 6.000 | 0.000 |
Install from PyPI:
pip install volumizerThis installs the portable Python wheel and CLI (volumizer). Optional local C helpers and the optional Rust native extension are not bundled in the default wheel.
On a fresh Linux machine, the shortest repository-local setup is:
- Install
uv, Node.js + npm, and optionallybuild-essentialif you want the local C helpers. - Run:
bash scripts/bootstrap_linux.sh- Verify the CLI:
uv run --python 3.11 volumizer --version- Build and serve the local gallery from a run summary:
./gallery /path/to/run.summary.jsonThe bootstrap script installs the Python dependencies, compiles the optional local C helpers when cc is available, installs the npm packages, and downloads the Playwright Chromium build needed for thumbnail rendering. Use --no-gallery to skip the Node/Playwright setup or --with-native to also build the optional Rust backend.
biotite==0.37.0 does not support Python 3.14. Use Python 3.10 or 3.11 with uv.
If you want to develop the package:
uv python install 3.11uv sync --python 3.11 --group testbash src/compile_c_libs.shuv run --python 3.11 pytest
Optional native scaffold (Phase 1):
uv sync --python 3.11 --group test --group native- Install Rust toolchain (
cargo,rustc). uv run --python 3.11 maturin develop --manifest-path native/Cargo.toml
Backend selection:
VOLUMIZER_BACKEND=python(default): use Python implementation (and local C helpers only whensrc/voxel.soandsrc/fib_sphere.soare present)VOLUMIZER_BACKEND=auto: use native if importable, otherwise Python modeVOLUMIZER_BACKEND=native: require native module and fail if unavailable
The package now includes a CLI entrypoint: volumizer.
Print CLI version:
volumizer --versionAnalyze a local structure file:
Control load behavior with assembly policy (biological default, asymmetric, auto):
volumizer analyze --input my_structure.cif --output-dir out --assembly-policy autovolumizer analyze --input my_structure.cif --output-dir outAnalyze one PDB ID (downloaded from RCSB as CIF):
volumizer analyze --pdb-id 4JPN --output-dir outAnalyze cluster representatives for an identity threshold:
volumizer cluster --cluster-identity 30 --max-structures 25 --output-dir outResume a previous run (skip entries that already have both output files):
volumizer cluster --cluster-identity 30 --max-structures 25 --output-dir out --resumePreview selection/filtering without downloading structures or running analysis:
volumizer cluster --cluster-identity 30 --max-structures 25 --output-dir out --dry-runWrite a reproducible manifest for selected cluster representatives:
volumizer cluster --cluster-identity 30 --max-structures 25 --output-dir out --write-manifest out/cluster.manifest.jsonReplay that exact set later:
volumizer analyze --manifest out/cluster.manifest.json --output-dir out-rerunReplay only failed structures from a previous summary:
volumizer analyze --from-summary out/run.summary.json --only failed --output-dir out-retryEmit a replayable manifest for failures during a run:
volumizer cluster --cluster-identity 30 --output-dir out --failures-manifest out/failed.manifest.jsonRetry only those failures later:
volumizer analyze --manifest out/failed.manifest.json --output-dir out-retryEnable periodic human-readable progress + ETA updates:
volumizer cluster --cluster-identity 30 --max-structures 100 --output-dir out --jobs 8 --progress-interval 15Deterministically shard a large cluster run across workers (example: shard 1 of 4):
volumizer cluster --cluster-identity 30 --output-dir out --num-shards 4 --shard-index 1Include hubs in CLI-written annotation outputs:
volumizer analyze --input my_structure.cif --output-dir out --include-hubsInspect metadata cache entries:
volumizer cache inspect --metadata-cache out/entry_metadata_cache.jsonClear only negative cache entries (e.g. permanent 404 metadata failures):
volumizer cache clear-negative --metadata-cache out/entry_metadata_cache.jsonLegacy compatibility:
- Existing flag-only invocations still work (
volumizer --input ...,volumizer --cluster-identity ...) and are auto-routed toanalyzeorcluster.
Cluster filtering defaults:
- Methods: X-ray + cryo-EM (RCSB method labels
X-RAY DIFFRACTIONandELECTRON MICROSCOPY) - Override with
--cluster-method(repeatable), e.g.--cluster-method xray --cluster-method neutron - Disable method filtering with
--cluster-allow-all-methods - Optional resolution gate with
--cluster-max-resolution, e.g.--cluster-max-resolution 3.0 - Residue-count gate defaults to
--cluster-max-residues 20000 - Parallel workers for metadata/download + analysis with
--jobs, e.g.--jobs 8 - Deterministic run partitioning with
--num-shards <N> --shard-index <K>to split representative lists across machines/jobs (0 <= K < N; both flags required) - Retry transient network errors with
--retriesand--retry-delay - Structure-load policy for
analyzeandclustercan be set with--assembly-policy biological|asymmetric|auto - Cluster metadata cache defaults to
<output-dir>/entry_metadata_cache.json; override with--metadata-cacheor disable with--no-metadata-cache - Cache stores both successful entry metadata and permanent metadata failures (e.g. HTTP 404) to avoid repeated failed fetches on later runs
- Checkpointing defaults to
<output-dir>/run.checkpoint.json; override with--checkpointor disable with--no-checkpoint - Structured progress events can be written with
--progress-jsonl <path>(JSON Lines format) - Human-readable progress + ETA updates are emitted every
--progress-intervalseconds (default 30, set<= 0to disable) - Cluster runs can emit selected/rejected structure manifests with
--write-manifest <path> - Analyze runs can replay any manifest with
--manifest <path>(entries supportpdb_idand/orinput_path) - Analyze runs can also replay structures from a prior
run.summary.jsonusing--from-summary <path> --only failed|skipped|planned|all - Any run can emit a failed-entry manifest via
--failures-manifest <path>for direct retry withanalyze --manifest <path> - CLI-written annotation outputs omit hubs by default; pass
--include-hubsto include them
CLI outputs:
<label>.annotated.cif: cleaned input plus volume pseudo-atoms (hubs omitted by default)<label>.annotation.json: web-friendly volume data payload (hubs omitted by default)run.summary.json: run configuration and per-structure status<path from --failures-manifest>(optional): replayable manifest containing failed structure inputs
For local browsing of modest indexed datasets, the repository now includes a small FastAPI app plus a static gallery UI.
Install the extra local web dependencies:
uv sync --python 3.11 --group test --group web
npm ci
npm run gallery:install-browserBuild the gallery index from a run summary:
uv run --python 3.11 python scripts/build_gallery_index.py --summary out/run.summary.json --db data/gallery.dbRender cached x/y/z thumbnails for indexed hits:
uv run --python 3.11 python scripts/render_gallery_thumbnails.py --db data/gallery.db --render-root data/renders --jobs 4 --render-backend autoBoth the thumbnail renderer and the browser UI now use locally installed Mol* assets from node_modules/molstar by default, so the gallery no longer depends on runtime CDN fetches. Override the asset location with MOLSTAR_ASSET_ROOT if needed. Optional profiling output is available via --timing-jsonl <path>. The default --axis-render-mode compatibility path reuses one Mol* browser/page/viewer context while loading axis-specific atom-filtered structures for x/y/z; --axis-render-mode fast keeps one unclipped structure loaded and captures full-structure x/y/z views.
Serve the local gallery:
uv run --python 3.11 python scripts/serve_gallery.py --db data/gallery.db --host 127.0.0.1 --port 8000Then open http://127.0.0.1:8000.
For the shortest end-to-end path from the repository root, use:
./gallery /path/to/run.summary.jsonIf Chromium is not installed yet, run bash scripts/bootstrap_linux.sh or npm run gallery:install-browser. If you want to browse the indexed data before rendering thumbnails, use:
./gallery /path/to/run.summary.json --skip-thumbnailsIf you want to retry rows whose thumbnails previously failed to render without rerendering successful rows, use:
./gallery /path/to/run.summary.json --include-failedIf you want to rerender thumbnails for one or more specific gallery entries, use:
uv run --python 3.11 python scripts/rerender_gallery_targets.py --db data/gallery.db 9bq2Current web-app scope:
GET /api/runs,GET /api/hits,GET /api/hits/{structure_id},GET /api/hits/{structure_id}/viewer-data- static browser UI for filtering and browsing hits
- file-serving endpoints for annotated CIF, annotation JSON, and cached PNG thumbnails
- Mol* detail viewer embedded in the browser page
Using the test file tests/pdbs/4jpn.pdb try out the following:
Performing end-to-end loading, cleaning, volumizing, and saving is done with a single convenience function:
from volumizer import volumizer
volumizer.volumize_pdb_and_save("my_input.pdb", "volumized_pdb.pdb", "volumized_df.json")
If you want access to the individual end-products: volume dataframe, the input structure after cleaning, and the structure of the volumes:
from volumizer import volumizer, pdb
pdb_structure = pdb.load_structure("my_input.pdb")
volumes_df, cleaned_structure, volumes_structure = volumizer.volumize_structure(pdb_structure)
# take the cleaned input and annotated volumes and convert them to a PDB format string and then save
# modify the `deliminator` to suit your visualization preference
# e.g. the default "END" allows Pymol to load the resulting PDB file as two separate objects, one for the cleaned input, and one for the volumes
pdb_lines = pdb.make_volumized_pdb_lines([cleaned_structure, volumes_structure], deliminator="END")
pdb.save_pdb_lines(pdb_lines, "volumized_pdb.pdb")
volumes_df.to_json("volumized_df.json")
If you are interested in additional control over the volumizing method:
- the resolution of the voxels can be changed
- cleaning can be skipped
Note: the default voxel resolution is 3.0 Angstroms, which gives sensible results in the majority of cases. Higher resolutions especially < 2.0 Angstroms will often find small paths through a protein structure, making e.g. cavities look like pores, etc. Lower resolutions are faster to compute, but may begin to under-estimate the true volume of solvent occluded elements.
Note: by default all residues that make L- or D- peptide bonds are retained through cleaning (e.g. Non-canonicals are kept, even if they are heteroatoms in PDB structure). By constrast all non-covalently attached residues are removed. Currently glycan residues are also removed as they make non-peptide bonds, below is shown an example of how would would retain glycans.
from volumizer import volumizer, pdb, utils
utils.set_resolution(2.0)
pdb_structure = pdb.load_structure("my_input.pdb")
cleaned_structure = volumizer.prepare_pdb_structure(pdb_structure) # skip this if you want to keep the exact input structure
volumes_df, volumes_structure = volumizer.annotate_structure_volumes(cleaned_structure)
# take the cleaned input and annotated volumes and convert them to a PDB format string and then save
# modify the `deliminator` to suit your visualization preference
# e.g. the default "END" allows Pymol to load the resulting PDB file as two separate objects, one for the cleaned input, and one for the volumes
pdb_lines = pdb.make_volumized_pdb_lines([cleaned_structure, volumes_structure], deliminator="END")
pdb.save_pdb_lines(pdb_lines, "volumized_pdb.pdb")
volumes_df.to_json("volumized_df.json")
volumizer identifies hydrated volumes in a protein structure that are not fully solvent exposed, e.g. a binding pocket.
It then computes the volume and dimensions of these and outputs that information along with an annotated
version of the input PDB showing where these volumes are (which can be visualized in e.g. Pymol, Chimerax, etc.).
- A large voxel-grid is built around the atoms of the protein or other structure supplied.
- All voxels within a van der Waals radius of a protein or other atom is flagged as being
non-solvent - Remaining
solventatoms are then broken into two groups:bulk solventandoccluded volumesThis is done by tracing a vector along each ordinal axis from a given voxel and if 2 or more of these vectors would cross anon-solventvoxel, then the query voxel is identified as anoccluded volumeto be further analyzed otherwise it is consideredbulk solventThe intention is to identify points on the grid that are outside the protein asbulk solvent - All
occluded volumevoxels are then grouped into a number of continuous volumes - For each continous volume the number of distinct surfaces that contact
bulk solventvoxels is computed and used to indicate the volume type: 0 surfaces interacting with solvent:cavity1 surface interacting with solvent:pocket2 surfaces interacting with solvent:pore3+ surfaces interacting with solvent:hub
Annotations are given as a pandas data frame saved as a .json file. The annotation lists all hydrated volumes ordered by total volume, giving the type of volume, and dimensions.
For CLI-written outputs, hub rows are omitted by default unless --include-hubs
is passed. The underlying library classifier still recognizes hubs.
The input PDB file will be annotated by adding atoms to represent the hydrated volumes. The ATOM entries
contain several points of information about the volume from which they come:
Type of volume: the residue name encodes the type of volume in 3-letter code
OCCforoccludedCAVforcavityPOKforpocketPORforporeHUBforhubwhen hub emission is enabled
Surface of the hydrated volume that interacts with bulk solvent: this is indicated by a B-factor of 50.0, whereas the remainder of the volume (that does not interact with the bulk solvent) has a value of 0.0.
All atoms of a particular volume are grouped under the same residue number.