Python SDK¶
The supported SDK covers archive inspection, validation, geometry, tables,
rendering and launch. The supported
surface is what the package root re-exports, so from vibeview import ...
is the whole import story:
from vibeview import (
QVFReader, QVFSource, QVFOpenError,
info, sections, has_section, validate, diff,
get_structure, get_volume, get_table, export_xyz,
capture_structure, capture_volume, render_terminal,
slice_qvf, launch_qvf,
)
Important
vibeview.__all__ is the API contract. A name imported from the package
root is supported and will not move without a deprecation note in the
changelog. A name reached through a submodule (vibeview.capture,
vibeview.animation, vibeview.file_watcher, vibeview.renderers.*) is an
internal detail that can be renamed or restructured in any release. Several
pages on this site show submodule calls where the root has no equivalent;
pin the version you script against when you use one.
The core install covers this entire page except launch_qvf, which needs
the [viewer] extra. Reading, inspecting, comparing, slicing and headless
PNG capture need no extra at all.
For a complete script with a bundled input and expected output, follow the worked workflow.
Numerical conversion convention¶
Length and energy conversions share CODATA 2018 factors: one bohr is 0.529177210903 Å and one Hartree is 27.211386245988 eV or 627.509474 thermochemical kcal/mol. CLI, SDK and batch energy comparisons use these same factors; printed decimal precision still depends on the output. Live optimization uses the reciprocal bohr/Å factor for positions and gradients. The source is the NIST CODATA 2018 table. This convention does not infer units for archive fields that omit them.
One argument type for every function¶
Every function here takes a QVFSource first. It is a union, not a class,
and anything in it works interchangeably:
str | Path | bytes | bytearray | memoryview | IO[bytes]
from pathlib import Path
from vibeview import info
info("water.qvf") # a path
info(Path("water.qvf"))
info(Path("water.qvf").read_bytes()) # raw bytes, no disk round-trip
with open("water.qvf", "rb") as fh: # any seekable binary file object
info(fh)
An open QVFReader is accepted anywhere a source is, which is how you avoid
reopening the archive; see Reading a file repeatedly.
Functions close readers they create on return or failure. A reader or binary
stream supplied by the caller stays open, including when an operation fails.
An unreadable or corrupt file raises QVFOpenError.
Inspecting¶
from vibeview import info, sections, has_section, validate
info("analysis.qvf")["scf_energy_eh"]
sections("analysis.qvf")
# [{'id': 'structure', 'kind': 'structure'},
# {'id': 'atom_properties', 'kind': 'atom_properties'}, ...]
has_section("analysis.qvf", "scf_history") # True
validate("analysis.qvf")
# {'valid': True, 'n_sections': 4, 'n_members': 5}
validate uses the optional qvf reference validator; see
installation and strict validation. It returns
valid, errors, warnings and structured findings with qvf’s exact codes
and locations. An unreadable or invalid archive returns valid: False and
error; missing validator support raises QVFError with an install hint.
A subsequent viewer-readability failure also returns valid: False with
reader_error, separate from qvf findings. Hash/layout diagnostics retain section, member and reason where
available. Success includes n_sections and n_members; the example above
shows those summary fields only.
Pass resource-policy overrides as validate(source, limits={"max_json_depth": 32}).
These use qvf’s own limits, before payload decoding. Paths, bytes, streams
and open readers are supported; borrowed streams/readers stay open and retain
their stream position. Reader validation checks the original stored archive,
independently of unsaved edits. Normal reading stays lazy.
The structure¶
from vibeview import get_structure, export_xyz
get_structure("water.qvf")
# {'atoms': [{'symbol': 'O', 'atomic_number': 8, 'position': [0.0, 0.0, 0.1173]}, ...],
# 'pbc': [False, False, False]}
print(export_xyz("water.qvf")) # the structure as an XYZ string
A periodic system also carries lattice_vectors, and pbc reports which
axes are periodic.
An archive can hold several structures under any section ids. Both functions
take the archive’s first structure (the first one
viewer_defaults.auto_open lists, else the first structure section; QVF spec
§ 4.1), and get_structure(source, "structure_m2") or
export_xyz(source, "structure_m2") another. On a reader, first_structure_id
names the first structure, structure_sections lists them all,
show_structure(id) changes the one read_structure() returns without an
id, and structure_identity(id) gives the label, name, charge, multiplicity
and line notations a structure section states (§ 5.1).
Volumes: summary or voxels¶
get_volume returns a JSON-serializable summary, the grid geometry and the
value range, not the voxels, and returns None rather than raising when the
section is absent or is not a volume, so it doubles as a probe:
from vibeview import get_volume
get_volume("density.qvf", "rho")
# {'kind': 'volume.density', 'origin': [...], 'voxel_vectors': [[...], ...],
# 'shape': [6, 6, 6], 'data_min': 0.0027, 'data_max': 0.9972}
The value range is that of the field the viewer draws. A real array, the
only kind QVF v1 allows, is reported as stored. A complex array is reduced
by the section’s component label first, as the browser and terminal do.
For the array itself, go through a reader:
from vibeview import QVFReader
with QVFReader("density.qvf") as r:
grid = r.read_volume_grid("rho") # origin, voxel_vectors, shape
data = r.read_volume_data("rho") # an ndarray in the stored dtype (float32 or float64)
Tables¶
get_table returns (headers, rows), the same data vibe-view table
prints, ready for csv.writer or a DataFrame:
from vibeview import get_table
headers, rows = get_table("analysis.qvf", "atom_properties")
Three kinds are tabulatable: vibrations, atom_properties and
wavefunction.gto. Any other kind raises ValueError naming the valid set.
A missing value is None, not a blank string.
Comparing¶
from vibeview import diff
diff("hf.qvf", "pbe.qvf")
# {'energy_a_eh': ..., 'energy_b_eh': ..., 'delta_e_eh': ..., 'delta_e_kcal_mol': ...,
# 'delta_e_ev': ..., 'geo_rmsd_a': ..., 'geo_rmsd_skipped': None,
# 'n_sections_a': ..., 'n_sections_b': ...,
# 'kinds_only_a': [], 'kinds_only_b': [], 'kinds_common': ['structure'],
# 'converged_a': ..., 'converged_b': ...}
Every numeric field is None when the inputs cannot support it. Two
structure-only files give delta_e_eh: None rather than a spurious zero, so
test for None before arithmetic. When geo_rmsd_a is None,
geo_rmsd_skipped says why: a structure that cannot be read (with the
reader’s error) or atom counts that differ.
Rendering¶
from vibeview import capture_structure, capture_volume, render_terminal
# PNG, offscreen. No display, but VTK wants a GL context; set PYVISTA_OFF_SCREEN=True.
capture_structure("h2o.qvf", "structure.png", representation="space_filling")
capture_volume("h2o.qvf", "vol_homo", "homo.png", isovalue=0.03, colormap="RdBu")
# The same renderers as text. No GL context at all, so this one works anywhere.
print(render_terminal("h2o.qvf", size=(80, 24)))
print(render_terminal("h2o.qvf", "vol_mo_3", isovalue=0.03))
open("frame.txt", "w").write(render_terminal("h2o.qvf", plain=True))
capture_structure takes size, representation, show_labels,
replication and publication; capture_volume takes isovalue,
colormap, opacity, size, replication, render ("auto", the
section’s hint; "isosurface"; or "volume", the browser’s volume mode)
and transfer_function, a function in the hint’s JSON shape that overrides
the section’s in volume mode. Both return True on success. render_terminal
takes the show flags as keywords and returns an explanation rather than
raising for a section with no graphical form. The chart and table captures,
the animation renderers and the on-demand orbital evaluator are in
Figures without a display.
Slicing¶
from vibeview import slice_qvf
out = slice_qvf("analysis.qvf", "structure_only.qvf", keep=["structure"])
slice_qvf("analysis.qvf", "no-volumes.qvf", drop=["volume.density"])
Slicing preserves scientific metadata and kept member bytes. It prunes viewer
hints for removed sections and refuses to drop a section still referenced by a
kept section. The output is validated before it replaces the destination;
keep and drop are mutually exclusive.
keep and drop take section ids or kinds, and the function returns the
output path. This is the cheap way to hand a colleague a 2 MB structure out
of a 400 MB archive.
Reading a file repeatedly¶
Each module-level call opens and closes the archive. For several calls
against one file, open a QVFReader once and pass it as the source:
from vibeview import QVFReader, info, get_structure, export_xyz
with QVFReader("analysis.qvf") as r:
meta = info(r)
geom = get_structure(r)
xyz = export_xyz(r)
The reader is also the lower-level surface, with one read_* method per
section kind: read_structure, read_bonds, read_volume_grid,
read_volume_data, read_bands, read_phonon_bands, read_phonon_dos,
read_equation_of_state, read_spectra, read_trajectory,
read_vibrations, read_wavefunction_gto, read_reaction_path,
read_reaction_waypoints, read_scan_surface, read_atom_properties,
read_nmr, read_epr, read_symmetry, read_scf_history,
read_citations, read_run_record, read_job_spec, read_bond_orders,
read_topology_qtaim, read_dos_coop, read_reaction_scheme and
read_preview. Each returns a typed data object
and takes the section id, not the kind. Ids often match the kind in
small files, but not always; take them from r.sections, which on the
reader is a property returning rich Section objects rather than the plain
dicts the module-level sections() returns.
with QVFReader("analysis.qvf") as r:
[s.id for s in r.sections]
r.read_scf_history("scf_history") # SCFHistoryData(iterations=[...])
r.read_bond_orders("bond_orders") # BondOrdersData(method='mayer', pairs=[...])
r.source.program, r.source.version # who wrote it
Without the context manager, call r.close() yourself. A reader you pass
into any SDK function stays open; the SDK closes only readers it opened.
Launching the viewer¶
from vibeview import launch_qvf
launch_qvf("water.qvf", host="127.0.0.1", port=8080, open_browser=True,
print_banner_to_stdout=True)
It boots the server and blocks until it stops. It takes any QVFSource or
an open reader, so an archive built in memory never has to touch disk. It closes
readers it creates when the server stops or fails; supplied readers stay open:
import io
launch_qvf(io.BytesIO(qvf_bytes), open_browser=False)
Set open_browser=False on a remote host and forward the port.
Jupyter¶
Needs the [jupyter] extra in the environment running the kernel.
%load_ext vibeview.jupyter
%vibeview calculation.qvf # structure image, section list, provenance
%vibeview calculation.qvf --table atom_properties # a charges table
%vibeview calculation.qvf --mo # the orbital table
%vibeview calculation.qvf --scf # SCF convergence chart
%vibeview calculation.qvf --bands # band structure
%vibeview calculation.qvf --capture density # a density isosurface image
%vibeview --help lists the options. vibeview.jupyter.qvf_to_image
returns a structure PNG as bytes for IPython.display.Image, rendered
exactly like vibe-view capture output,
qvf_to_html an embeddable snippet, and export_notebook_cell generates a
starter cell for an archive. For the full interactive viewer from a
notebook, launch_qvf(..., open_browser=False) and connect to the port.
Release codename¶
The codename catalogue is importable, which is what the CLI, the About boxes and this site read:
from vibeview.codenames import codename_for_version, version_label
codename_for_version("{{release}}")
version_label() # "<version> — <codename>", or the bare version
See Release codenames.
Extending vibe-view¶
There is one extension point today: importer plugins, declared through
the vibeview.importers entry-point group and described under
Input formats. There is no plugin
API for renderers, representations or panels. Those seams exist inside the
codebase but are internal, undocumented and free to move.
What you can do is compose: the functions on this page are ordinary Python, so a script that walks a directory, validates each archive, captures a PNG and writes a summary CSV needs nothing beyond them. For most “extend vibe-view” requests, batch rendering, custom reports, feeding another tool, that is the whole answer, and it is stable. If you need an in-process seam stabilized, say what you are building in an issue; which one comes first should follow a real use case.
Full surface¶
Name |
Purpose |
Extra |
|---|---|---|
|
Open once, read many sections |
|
|
The accepted source union (a type, not a class) |
|
|
Raised when a file cannot be opened |
|
|
Full metadata dict |
|
|
|
|
|
Test one section id |
|
|
Strict qvf reference validation |
|
|
Atoms, |
|
|
Structure as an XYZ string |
|
|
Grid geometry and value range, no voxels |
|
|
|
|
|
Energy delta, section overlap, geometry RMSD |
|
|
Structure to PNG, headless |
|
|
Volume to PNG, headless |
|
|
Section to braille text |
|
|
Subset of sections to a new archive |
|
|
The interactive browser viewer |
|
API reference¶
High-level Python API for vibe-view — programmatic access to all QVF operations. |
|
QVF reader — the core file-open lifecycle. |
|
Kind registry — the four-rule partial-support contract. |
|
Release codename catalogue. |