VoltClient (Python)
Python SDK for the Volt platform — run native plugins locally, browse REST resources, convert Apache Parquet to DataFrames, and visualize GLB models.
Overview
voltsdk wraps the Volt REST API and also: downloads, caches, and runs native C++ analysis plugins locally (PluginHub); browses resources; assembles and renders GLB 3D models (SpatialAssembler, open_in_volt); and loads analysis output into pandas DataFrames.
Installation
pip install voltsdkOptional extras:
pip install "voltsdk[visualization]" # VTK desktop render window for view_glb
pip install "voltsdk[notebook]" # VTK + k3d for inline rendering in Jupyter
pip install "voltsdk[ovito]" # OVITO pipeline integration
pip install "voltsdk[all]" # everything aboveQuick Start
from voltsdk import VoltClient, PluginHub
# Run a native plugin locally — no Volt account required
hub = PluginHub(default_publisher="voltlabs")
ptm = hub.get("polyhedral-template-matching")
run = ptm("frame.dump", output_dir="out", crystal_structure="FCC", rmsd=0.1)
print(run["annotated.dump"].path)
# Or browse Volt resources with an authenticated client
client = VoltClient.from_env()
traj = client.trajectories.get("trajectory-id")
for analysis in traj.analyses:
print(analysis.id, analysis.status, analysis.plugin_name)Authentication
The authenticated client uses secret keys (prefixed with vsk_), generated from your Volt team settings. The constructor takes secret_key and base_url; no network calls happen during construction — the first request fires lazily when you access a resource.
from voltsdk import VoltClient
client = VoltClient(
secret_key="vsk_abc123...",
base_url="https://server.voltcloud.dev",
)VoltClient.from_env() (recommended) reads VOLT_SECRET_KEY and VOLT_BASE_URL from the environment. Inside a Volt Jupyter container the base URL is auto-detected from the Jupyter/server proxy configuration, so from_env() is zero-config there.
client = VoltClient.from_env()base_url is the server origin. The /api suffix is optional — both https://server.voltcloud.dev and https://server.voltcloud.dev/api work, since the client appends /api when it is missing. The constructor accepts only secret_key and base_url — there is no timeout parameter.
Resources
VoltClient exposes resource collections as lazy, auto-paginating properties — iterating fetches pages on demand. Resources are typed objects, not dicts, so use attribute access (analysis.status), not subscripting.
| Property | Returns |
|---|---|
client.team | The Team tied to the secret key |
client.trajectories | TrajectoryCollection (team-wide) |
client.analyses | AnalysisCollection (team-wide) |
client.plugins | PluginHub (download/cache/run native plugins) |
Trajectories
# Iterate the team's trajectories (lazy pagination)
for traj in client.trajectories:
print(traj.id, traj.name, traj.frame_count)
# Optional server-side name filter
coppers = client.trajectories.list(search="copper")
# Fetch one by ID
traj = client.trajectories.get("trajectory-id")
print(traj.name, traj.status, traj.is_public)
# Download the original trajectory file(s)
traj.download(dest="downloads/")Each Trajectory exposes sub-resources: traj.frames, traj.analyses, traj.simulation_cell, and traj.listings.
Frames
traj.frames is built from the trajectory metadata (no extra API call). Each Frame has timestep and natoms.
frame = traj.frames[0]
print(frame.timestep, frame.natoms)
# Per-atom data as a DataFrame (optionally scoped to an analysis)
df = frame.atoms(analysis_id="analysis-id")
# Downloads
frame.download_dump(dest="downloads/") # raw LAMMPS dump (.dump.gz)
frame.download_glb(analysis_id="analysis-id") # GLB for this frameframe.download_glb() accepts analysis_id (default 'default') and dest.
Analyses
# Analyses for a trajectory
for analysis in traj.analyses:
print(analysis.id, analysis.status, analysis.plugin_name, analysis.progress)
# Team-wide analyses
for analysis in client.analyses:
print(analysis.id, analysis.plugin_name)Analysis properties: id, status, plugin_name, plugin_id, trajectory_id, config, and progress (fraction of frames completed, 0.0–1.0).
Download every artifact (parquet + GLB) for an analysis as a zip:
# Download and recursively extract (default)
path = analysis.download_artifacts(dest="out/")
# Keep the zip
zip_path = analysis.download_artifacts(dest="out/", unzip=False)Analysis results
analysis.df() returns the listing rows (one per timestep) as a DataFrame. analysis.listings exposes the same data with extra controls (columns=, to_csv(...)).
analysis = traj.analyses.first()
df = analysis.df() # results table
df = analysis.listings.to_dataframe(columns=["timestep", "energy"])
analysis.listings.to_csv("out.csv")
# 3D model for a frame, and the raw artifact bundle:
frame.download_glb(analysis_id=analysis.id, dest="out/")
analysis.download_artifacts(dest="out/")Plugin Hub
PluginHub (new in VoltSDK 3.0) is also available on an authenticated client via client.plugins.
from voltsdk import PluginHub
hub = PluginHub(default_publisher="voltlabs")
print(hub.list()) # publisher-qualified marketplace listing
ptm = hub.get("polyhedral-template-matching")
run = ptm(
"frame.dump",
output_dir="out",
crystal_structure="FCC",
rmsd=0.1,
)
print(run["annotated.dump"].path)Plugin arguments are passed as snake_case keyword arguments matching the plugin's plugin.json argument keys. Calling a plugin returns a PluginRun; index it by artifact name to get a PluginArtifact (a path-like object) with helpers such as .path, .df(), .json(), .glb(), and .open_in_volt().
df = run["annotated.dump"].df() # artifact as a DataFrame
glb = run["dislocations"].glb() # assemble a GLB from an exporter payload
run["dislocations"].open_in_volt() # render in the Volt web canvasIdentifiers and versions
Plugin keys use the canonical @scope/name form. Versions may be exact, the literal latest, or a semver range.
hub.get("@voltlabs/opendxa", "1.0.0") # explicit version
hub.get("@voltlabs/opendxa", "^1.0.0") # semver range
hub["@voltlabs/opendxa"] # shorthand for the latest version
hub.install("@voltlabs/opendxa") # pre-download the latest bundle
hub.uninstall("@voltlabs/opendxa") # drop every cached versionConfiguration
| Variable | Purpose | Default |
|---|---|---|
VOLT_PLUGIN_REGISTRY | Volt-Registry base URL | https://registry.voltcloud.dev |
VOLT_CACHE_DIR | Local plugin cache | $XDG_CACHE_HOME/volt |
VOLT_REGISTRY_TOKEN | Optional Bearer JWT/PAT for authenticated reads | unset |
Visualization
open_in_volt(source, *, title=None, volt_url=None, open_browser=True)
Renders local GLB files, a GLB sequence, or an existing Volt resource using the Volt web canvas. Inside a Volt notebook it serves files through the Jupyter proxy; on a local machine it starts a background file server. The browser still needs an authenticated Volt session.
from voltsdk import open_in_volt
# A single GLB
open_in_volt("out/frame.glb")
# A timestep-keyed sequence
open_in_volt({
0: "out/frame-0000.glb",
5000: "out/frame-5000.glb",
10000: "out/frame-10000.glb",
})Resource objects expose the same helper to open their exact canvas route: trajectory.open_in_volt(timestep=5000), frame.open_in_volt(), analysis.open_in_volt(timestep=5000), and exposure.open_in_volt(5000).
By default the viewer opens against https://app.voltcloud.dev; override it with volt_url=... or the VOLT_APP_URL environment variable.
SpatialAssembler
Builds GLBs locally from Volt exporter payloads (AtomisticExporter, MeshExporter, LineExporter). It accepts the full artifact file (.json or a line-entity-table .parquet) or the raw nested payload.
from voltsdk import SpatialAssembler, open_in_volt
assembler = SpatialAssembler()
glb_path = assembler.lines_glb(
"out/ptm-dxa_dislocations.parquet",
output_path="out/ptm-dxa_dislocations.glb",
color_by="burgers_family",
)
open_in_volt(glb_path)assembler.glb(source, output_path=..., exporter=...) auto-dispatches to the right exporter; atomistic_glb, mesh_glb, and lines_glb are the per-exporter entry points.
view_glb(file_path)
Renders a GLB 3D model interactively. In a Jupyter notebook it uses k3d for inline rendering; otherwise it opens a VTK desktop window.
from voltsdk import view_glb
view_glb("out/frame-5000.glb")Requires voltsdk[visualization] (VTK desktop window). For the inline notebook path, install voltsdk[notebook] to add k3d.
Utility Functions
parquet_as_df(file_path, iterable_key=None)
Converts a Volt Apache Parquet result file to a pandas DataFrame, merging chunked (streamed) messages.
from voltsdk import parquet_as_df
df = parquet_as_df("out/output.parquet")
print(df.head())
print(df.columns.tolist())iterable_key is a dot-separated path extracted from each chunk before merging — for results that wrap their rows under a named key:
df = parquet_as_df("out/output.parquet", iterable_key="main_listing")Example Workflow
from voltsdk import VoltClient, parquet_as_df
client = VoltClient.from_env()
# 1. Pick a trajectory and its first analysis
traj = client.trajectories.get("my-trajectory-id")
analysis = traj.analyses.first()
print(analysis.plugin_name, analysis.status)
# 2. Download all artifacts (extracted)
out_dir = analysis.download_artifacts(dest="out/")
# 3. Convert a result file to a DataFrame
df = parquet_as_df(f"{out_dir}/output.parquet")
print(f"Rows: {len(df)}")
print(f"Columns: {df.columns.tolist()}")
print(df.describe())