Figures without a display¶
Everything on this page is the core install: no [viewer] extra, no
browser, and no display server. It is what a CI job, a batch pipeline or a
figure script for a paper runs. The data and geometry conventions are
shared with the browser; the offscreen and browser rendering backends differ,
so a PNG is not a pixel-identical capture of your browser session.
One caveat separates the two halves of the page. PNG capture, video and the scene exporters render through VTK, which needs an offscreen OpenGL context even with no display attached. Terminal rendering and the vector and data exporters need nothing at all.
Setting up a headless host¶
vibe-view capture-selftest
renders a tiny built-in structure through the real capture path, checks the PNG is not blank, and reports the render backend. Exit 0 means capture works here; non-zero means the GL stack is missing, and the message says what it found. Run it before the first real capture on a new host, and as a healthcheck in a queue or CI job.
On a bare Linux container the usual fixes are a Mesa runtime and a virtual framebuffer:
apt-get install libgl1 libglx-mesa0 libxrender1 libxext6 libsm6 libglib2.0-0 xvfb xauth
PYVISTA_OFF_SCREEN=True xvfb-run -a vibe-view capture job.qvf -o structure.png
PYVISTA_OFF_SCREEN=True tells PyVista not to look for a window; set it in
the environment of any script that captures. If a GL context is impossible
on a host, vibe-view show and render_terminal still work, because they
never touch one.
vibe-view capture¶
vibe-view capture job.qvf -o structure.png # the structure
vibe-view capture job.qvf -s vol_dens_0 -o density.png # a volume section
vibe-view capture job.qvf -s vol_mo_0 --isovalue 0.03 --colormap RdBu -o homo.png
vibe-view capture job.qvf -s bands -o bands.png
-s selects a section ID from vibe-view info FILE.qvf. The CLI
supports structures, stored volumes / basis.ao, and bands; other kinds
need the capture API or the browser export controls.
Volumes take --isovalue and --colormap. --size WxH sets structure and
volume image dimensions; the default is 900x600. Bands use their chart
renderer rather than the 3-D image-size setting, and draw their energy axis
in the browser’s saved Band / DOS energy unit. --publication renders a
structure in the browser’s Publication view preset: the scientific
material on a near-white background, with a black outline around every atom
and bond. --render draws a volume section as its isosurface or as a
volume, the browser’s volume mode off-screen: the
same capped grid, the same transfer function from the section’s hint or
the kind’s preset, so a figure and the viewer agree. The default, auto,
follows the section’s render hint and draws the isosurface when there is
none, so an archive without the hint captures exactly as before.
Replication and --isovalue apply to the isosurface only; a skewed grid
is resampled onto its axis-aligned bounding box, as the browser does.
Without -o, the PNG is written beside the archive as <stem>_<section>.png
(<stem>_structure.png for the structure); animate and export follow the
same rule with their own suffixes.
Signed volumes retain both lobe colours and the grid’s full voxel-vector geometry, including skewed grids and reversed axes, as in the browser viewer.
capture renders the supported stored sections. It has no flag for evaluating an
orbital from a wavefunction.gto section on demand; the
Python API can do that.
Keep a figure reproducible¶
Record the archive, section ID, viewer version, contour and output size
alongside the image. For example, after selecting a stored density section
whose ID is density:
vibe-view --version > figure-version.txt
vibe-view info calculation.qvf --json > figure-input.json
vibe-view validate calculation.qvf
vibe-view capture calculation.qvf -s density --isovalue 0.05 --size 1600x1000 -o density.png
Replace density with your actual section ID. Report the units supplied by
the producer and retain the original QVF; a PNG cannot recover the numerical
field. To compare two surfaces, keep their contour and view settings fixed.
For a runnable structure-only example, use the worked workflow.
vibe-view batch¶
vibe-view batch runs/*.qvf # one structure PNG per archive
vibe-view batch runs/*.qvf --volumes -o gallery/ # plus one PNG per volume section
vibe-view batch a.qvf --size 1200x800
Renders a gallery from many archives with the same view defaults, one PNG
per section, into ./vibe-view-gallery unless -o says otherwise. No
server is started. vibe-view dashboard PATTERNS... builds a grid preview
of many files instead, as one image or, with --html, one page.
Every headless image, from capture, batch, dashboard, the animate
frames and the Jupyter helper, is rendered the same way: the dark vibe-view
background and an isometric camera fitted to the scene. Only
capture --publication departs from that background, on purpose.
vibe-view animate¶
vibe-view animate opt.qvf # auto-detect: trajectory, reaction path, vibrations or orbitals
vibe-view animate neb.qvf --kind reaction # reactant → transition state → product
vibe-view animate vib.qvf --kind vibration --mode 7 # one normal mode, 0-based
vibe-view animate opt.qvf -k trajectory --fps 8 --format gif
vibe-view animate si.qvf --kind turntable -o rotation.mp4
MP4 needs ffmpeg on PATH; without it the command falls back to GIF when
Pillow is installed. --format frames writes the individual PNGs instead.
--kind auto, the default, takes the first of trajectory,
reaction.path, vibrations or wavefunction.gto it finds;
--kind orbital sweeps every orbital of a wavefunction at --isovalue.
Export¶
vibe-view export job.qvf -f xyz -o geometry.xyz
vibe-view export job.qvf -f html -o viewer.html
vibe-view export job.qvf -f pov -o scene.pov
Twelve formats, none of which needs a display:
|
Writes |
Notes |
|---|---|---|
|
The structure |
CIF carries fractional coordinates with a periodic cell, or Cartesian Å coordinates for a molecule; no box is invented. |
|
A vibe-qc input script |
Reuses the archive’s own provenance (method, basis, functional) so the script reproduces the calculation, and carries the lattice so a periodic file exports a periodic system. |
|
A mesh of atoms and bonds |
glTF 2.0 with PBR materials, for any 3-D tool. |
|
A POV-Ray scene |
CPK spheres and bond cylinders with finish blocks, three-point studio lighting, the cell wireframe for a crystal. Render with |
|
A Blender Python script |
Builds the scene when run with |
|
A shareable structure page |
Opens without a Python server, but fetches Three.js from a CDN and therefore needs network access. It carries the geometry, not the full QVF analysis panels. |
|
Vector graphics |
CPK circles and bond lines, for journals that want line art. |
|
A vector PDF |
For |
Python exports preserve literal parameter text, including quotes, backslashes and line breaks in output names. Each line of a multiline calculation title remains a comment. The same formatting is used by the calculation panel and queue input generation.
Flat SVG and PDF figures fit the complete drawn atom circles, with their style-dependent radii and surrounding margin. Large atoms in space-filling figures keep their full outlines in both vector PDF output and the raster fallback used when matplotlib is unavailable.
Every export carries the connectivity the viewer shows: the archive’s explicit bonds when it has them, with their orders, otherwise the same covalent-radius inference. POV-Ray scenes draw a bond through a periodic cell face to the image it reaches; CML, the Blender script, the standalone HTML page and the flat SVG and PDF figures address atoms by index and leave such bonds out.
The browser’s Export geometry / scene menu offers the same formats.
Both CIF export paths use the same coordinate convention and write unique
atom-site labels separately from element symbols. A stored cell with
all QVF periodic flags disabled is treated as molecular. CIF cell parameters
do not preserve individual QVF periodic-axis flags. The
interactive High-Quality Raytrace Render is browser-only; from a script,
vibeview.raytrace.RaytraceEngine drives the same OSPRay path tracer when
the installed VTK ships it.
Tables and data¶
vibe-view table job.qvf # what is tabulatable
vibe-view table job.qvf --kind atom_properties --format csv > charges.csv
vibe-view table job.qvf --kind wavefunction.gto --format json
vibe-view info job.qvf --json
Three kinds are tabulatable: vibrations, atom_properties and
wavefunction.gto. See the CLI reference for diff,
batch-compare and stats, and the Python API for the
same data as Python objects.
The capture API¶
Every function on the public SDK takes a path, bytes, a file object or an
open reader, and returns True on success:
from vibeview import capture_structure, capture_volume
capture_structure("job.qvf", "structure.png",
representation="space_filling", show_labels=True, replication=(2, 2, 1))
capture_volume("job.qvf", "vol_dens_0", "density.png",
isovalue=0.05, colormap="viridis", opacity=0.6, size=(1600, 1000))
The lower-level module covers the chart and table kinds too. These take an
open QVFReader and auto-detect the section when none is named:
Function |
Output |
|---|---|
|
PNG |
|
PNG |
|
PNG |
|
HTML |
|
HTML |
|
HTML |
|
HTML |
|
HTML |
|
a dict describing the render backend |
from vibeview import QVFReader
from vibeview.capture import capture_bands, capture_dos, capture_scf_history
with QVFReader("crystal.qvf") as r:
capture_bands(r, "bands.png")
capture_dos(r, "dos.html")
capture_scf_history(r, "scf.html")
capture_bands and capture_dos frame the energy axis the way the viewer
does: an all-electron archive opens on its valence states rather than
autoscaling over core levels thousands of eV below E_F. Pass
energy_window=(min, max) in eV relative to E_F for a specific window, or
auto_window=False for the full range. See
the bands and DOS panels. Both take energy_unit
("ev", "hartree" or "kcal_mol"; eV unless given), capture_energy_diagram
takes it with a Hartree default, and capture_bond_orders takes length_unit
("angstrom" or "bohr") for its distance column; the CSV that page offers
stays in Å. The API does not read the browser’s settings; the capture
command does.
capture_bands(r, "bands.png", energy_window=(-15.0, 10.0))
The chart kinds other than bands write interactive HTML through Plotly; for a PNG of one of those, save the figure with matplotlib from your own script, or screenshot the page.
To render an orbital that is not stored as a grid, evaluate it first:
vibeview.renderers.wavefunction.WavefunctionRenderer has evaluate_mo,
evaluate_density, evaluate_spin_density, evaluate_elf and
evaluate_nci. That module is below the supported surface, so pin the
version you script against.
The animation API¶
from vibeview import QVFReader
from vibeview.animation import (
render_trajectory_video, render_reaction_video,
render_vibration_video, render_orbital_animation,
)
with QVFReader("neb.qvf") as r:
render_reaction_video(r, "neb.mp4", fps=5, format="mp4")
with QVFReader("vib.qvf") as r:
render_vibration_video(r, "mode7.gif", mode=7, n_frames=60, fps=15, format="gif")
Each returns the output path, or None when the archive has no matching
section. render_turntable takes a PyVista plotter rather than a reader and
orbits the camera through a full rotation.
Recipes¶
A figure set for a paper
export PYVISTA_OFF_SCREEN=True
vibe-view capture result.qvf -o figs/structure.png --size 1800x1200
vibe-view capture result.qvf -s vol_dens_0 -o figs/density.png
vibe-view capture result.qvf -s vol_mo_0 -o figs/homo.png --colormap RdBu
vibe-view export result.qvf -f svg -o figs/structure.svg
A regression check in CI
vibe-view validate result.qvf
vibe-view diff result.qvf reference.qvf --json | jq '.delta_e_kcal_mol'
vibe-view capture-selftest && vibe-view batch results/*.qvf -o gallery/
Everything about one file, as text
vibe-view show result.qvf --all --plain > report.txt
That last one needs no GL at all, so it is the one to attach to a job’s log.