SurfaceViewer
Cube-backed isosurface viewer for orbital, density, and two-cube delta-density data.
SurfaceViewer renders on top of the same browser runtime as
MolecularViewer, so the standard molecule controls, frame slider, camera
presets, PNG export, and GIF export remain available for surface pages.
GIF export uses an opaque viewer background by default to avoid transparent
frame trails; PNG export can still be transparent.
Install the optional surface dependencies before using it:
See the Surface Viewer example for complete single-cube, density, diff, and multi-isovalue snippets.
Constructor
Parameters
| Parameter | Type | Description | Default |
|---|---|---|---|
source |
str, Path, cube.Cube, cube.GridField, payload |
Cube-like input or a prebuilt compact surface payload | Required |
surface_kind |
str |
"orbital" or "density" for single-cube inputs |
"orbital" |
dataset |
str, int, None |
Dataset selector for multi-dataset cube inputs | None |
molecule |
ASE Atoms, viewer dict, path, list, None |
Optional molecule context shown with the surface | None |
theme |
str, None |
Visual theme. None uses the global default. |
None |
Use SurfaceViewer.from_cube_diff(left, right, ...) for two-cube
delta-density surfaces. Use SurfaceViewer(source, surface_kind="delta_density")
when source is already a signed CHGDIFF/charge-density-difference field.
Surface Options
| Parameter | Type | Description | Default |
|---|---|---|---|
isovalue |
float, list[float], str, "auto" |
Surface level, multiple shell levels, or a range spec | "auto" |
surface_color |
str |
Color for unsigned density shells | "#3b82f6" |
positive_color |
str |
Color for positive orbital or delta-density shells | "#ef4444" |
negative_color |
str |
Color for negative orbital or delta-density shells | "#2563eb" |
opacity |
float |
Maximum shell opacity | 0.65 |
opacity_ramp |
list[float], None |
Per-isovalue opacity values. Length must match isovalue=[...]. |
None |
surface_style |
str |
"solid", "mesh", "contour", or "dot" |
"solid" |
quality |
str |
"low", "medium", or "high" extraction budget |
"medium" |
max_grid_points |
int, None |
Explicit grid downsampling budget | None |
max_triangles |
int, None |
Explicit triangle budget | None |
smoothing |
float, None |
Optional scalar-field smoothing before extraction | None |
normalize_orbital |
bool |
Normalize orbital data before isosurface extraction | True |
Display Options
| Parameter | Type | Description | Default |
|---|---|---|---|
show_molecule |
bool |
Show the optional molecule context | True |
show_cell |
bool |
Show the molecule cell when available | True |
show_bonds |
bool |
Show molecule bonds when available | True |
Camera options such as viewMode, viewPreset, viewDirection, viewEuler,
viewUp, viewFit, and rotationMode follow the same conventions as the
other Python viewers.
isovalue range strings are accepted anywhere a Python or CLI surface
isovalue is parsed:
| Syntax | Meaning |
|---|---|
"0.02,0.04,0.08" |
Explicit levels |
"0.02:0.08:4" |
NumPy-style evenly spaced count, equivalent to 4 points from start to stop |
"linspace(0.02,0.08,4)" |
Explicit linspace form with both endpoints included |
surface_style="contour" uses a denser default extraction grid than solid or
mesh surfaces and renders dense horizontal slice lines instead of mesh edges.
Solid Surface Transparency
surface_style="solid" keeps transparent orbital and density shells readable
with the molecule layer by rendering each transparent shell as separate
back-face and front-face passes. The front pass uses opacity; the back pass is
attenuated so overlapping lobes remain visible without creating the hard
clipping artifacts that depth pre-passes can introduce. Opaque shells still use
a single mesh pass.
This is a practical browser-rendering compromise for Three.js r128. It improves the usual orbital and charge-density cases, but it is not full order-independent transparency for every possible self-overlapping mesh.
Single Orbital Cube
from aseview import SurfaceViewer
viewer = SurfaceViewer(
"HOMO.cube",
surface_kind="orbital",
isovalue=0.04,
positive_color="#ef4444",
negative_color="#2563eb",
)
viewer.show()
Density Cube
from aseview import SurfaceViewer
viewer = SurfaceViewer(
"density.cube",
surface_kind="density",
isovalue=0.002,
surface_color="#22c55e",
opacity=0.55,
)
viewer.save_html("density-surface.html")
Two-Cube Difference
from aseview import SurfaceViewer
viewer = SurfaceViewer.from_cube_diff(
"state-a-density.cube",
"state-b-density.cube",
diff_sign="1-2",
isovalue=0.0015,
positive_color="#f97316",
negative_color="#0ea5e9",
)
viewer.show()
Precomputed Difference Field
from aseview import SurfaceViewer
viewer = SurfaceViewer(
"CHGDIFF.vasp",
surface_kind="delta_density",
isovalue=0.02,
positive_color="#f97316",
negative_color="#2563eb",
)
viewer.show()
Surface Sequences
Use SurfaceViewer.sequence() when the surface geometry changes frame by
frame. The Python API takes an explicit list of frame dictionaries; each frame
can contain one surface or a named surfaces mapping.
from aseview import SurfaceViewer
frames = [
{
"label": "0 fs",
"molecule": atoms_0,
"surfaces": {
"HOMO": "frame_000/HOMO.cube",
"LUMO": "frame_000/LUMO.cube",
},
},
{
"label": "1 fs",
"molecule": atoms_1,
"surfaces": {
"HOMO": "frame_001/HOMO.cube",
"LUMO": "frame_001/LUMO.cube",
},
},
]
viewer = SurfaceViewer.sequence(frames, surface_kind="orbital", isovalue=0.03)
viewer.save_html("homo-lumo-trajectory.html")
For a single frame with multiple related density fields, put each field under a
surface label. Two-path entries are treated as delta-density surfaces unless a
different surface_kind is set explicitly:
viewer = SurfaceViewer.sequence(
[
{
"label": "adsorbate comparison",
"surfaces": {
"AB": {"path": "AB_CHGCAR", "surface_kind": "density"},
"A": {"path": "A_CHGCAR", "surface_kind": "density"},
"B": {"path": "B_CHGCAR", "surface_kind": "density"},
"AB - A": {
"paths": ["AB_CHGCAR", "A_CHGCAR"],
"isovalue": 0.01,
},
},
}
],
surface_kind="density",
isovalue=0.02,
)
For CLI or archive workflows, use a JSONL manifest with one frame object per
line. Paths in JSONL are resolved relative to the manifest file. As an import
convenience, extxyz trajectories can store per-frame surface paths in
Atoms.info["surface_path"].
Multi-Isovalue Shells
from aseview import SurfaceViewer
viewer = SurfaceViewer(
"HOMO.cube",
surface_kind="orbital",
isovalue="0.03:0.09:4",
surface_color="#3b82f6",
positive_color="#ef4444",
negative_color="#2563eb",
opacity_ramp=[0.25, 0.45, 0.65, 0.8],
)
viewer.show()
For unsigned density surfaces, each parsed isovalue entry creates one shell
using surface_color. For signed orbital and delta-density surfaces, each
level creates positive and negative shells using positive_color and
negative_color; the same opacity_ramp is applied to both phases.
v1 Scope
SurfaceViewer v1 intentionally excludes ESP/NCI workflows: no ESP
colormaps, ESP colorbars, NCI modes, NCI color controls, solvent surfaces, or
VS Code .cube editor integration are implemented. Use it for cube-backed
orbital, density, and two-cube delta-density isosurfaces in Python, Jupyter,
and saved HTML.