Crystal Structures

Python. Most xyzrender flags below map 1:1 to keyword arguments on render(). Cell reading is a load() option: mol = load("foo.xyz", cell=True) (auto-detected for VASP/QE/PDB-CRYST1/CIF/extXYZ inputs). The rendering flags are then render() kwargs — worth flagging: --supercell M N Lsupercell=(2, 2, 1) (tuple) and --axis HKLaxis="111" (string).

from xyzrender import load, render
mol = load("caffeine_cell.xyz", cell=True)
render(mol, supercell=(2, 2, 1), output="cell_221.svg")
render(mol, axis="111", no_cell=True)

extXYZ unit cell

Draw the unit cell box for periodic structures from an extXYZ file with a Lattice= header. The cell is detected automatically — no extra flag needed.

Unit cell

Cell rotation

Custom color

Unit cell

Cell rotation

Custom color

Default

No ghost atoms

No cell box

Default

No ghost atoms

No cell box

Caffeine 2×2×1 (ghosts)

Caffeine 2×2×1 (ghosts + --hy)

NV63 2×2×1 (ghosts)

ghosts

ghosts + hy

ghosts

xyzrender caffeine_cell.xyz -o caffeine_cell.svg
xyzrender caffeine_cell.xyz --gif-rot -go caffeine_cell.gif
xyzrender caffeine_cell.xyz --cell-color maroon -o caffeine_cell_custom.svg
xyzrender caffeine_cell.xyz --supercell 2 2 1 -o caffeine_cell_supercell_221.svg
xyzrender caffeine_cell.xyz --supercell 2 2 1 --hy -o caffeine_cell_supercell_221_hy.svg
xyzrender NV63_cell.xyz --no-ghosts --no-axes -o NV63_cell_no_ghosts.svg
xyzrender NV63_cell.xyz --no-cell -o NV63_cell_no_cell.svg
xyzrender NV63_cell.xyz --supercell 2 2 1 --no-axes -o NV63_cell_supercell_221.svg

Note

Bond orders are disabled by default for periodic structures — geometry-based perception is not PBC-aware.

The extXYZ comment line must contain a Lattice= key with the 3×3 cell matrix as nine space-separated floats. Tools like ASE can export to extXYZ from CIF or other periodic formats.

Supercell expansion

Expand a periodic structure into a supercell with --supercell M N L, which repeats the unit cell M×N×L times along the lattice vectors (a, b, c). This option is available for any input that includes unit-cell lattice data (e.g. extXYZ Lattice= headers, PDB CRYST1, CIF, VASP, QE, SIESTA, ABINIT, CP2K).

Ghost atoms show the periodic images of the supercell (not the unit cell), while the cell-box overlay always shows the original unit cell. The --hy / --no-hy flags apply to ghost H atoms too.

xyzrender NV63.vasp -o NV63_vasp.svg
xyzrender NV63.vasp --gif-rot -go NV63_vasp.gif
xyzrender NV63.in --no-axes -o NV63_qe.svg

Unwrap molecules across boundaries

Molecular crystals are often stored with molecules wrapped into the unit cell, so a molecule that straddles a face is split across the periodic boundary. --unwrap reassembles each molecule as a single whole fragment by shifting atoms by integer lattice translations, anchoring every molecule at the image where most of its atoms already sat. Ghost atoms are turned off (the molecules are already contiguous), and fully-connected frameworks — ionic or covalent networks with no discrete molecules — are left unchanged.

Wrapped (default)

Unwrapped (--unwrap)

Wrapped

Unwrapped

xyzrender caffeine_cell.xyz --unwrap -o caffeine_cell_unwrap.svg

In the Python API this is a render() kwarg, or the standalone unwrap_molecules() transform on a graph:

from xyzrender import load, render
from xyzrender.crystal import unwrap_molecules

mol = load("caffeine_cell.xyz", cell=True)
render(mol, unwrap=True, output="caffeine_cell_unwrap.svg")

unwrap_molecules(mol.graph, mol.cell_data)  # apply the transform directly

Periodic codes

VASP, Quantum ESPRESSO, SIESTA, ABINIT, and CP2K periodic input files are auto-detected from file content. No extra dependencies or flags required.

VASP (NV63)

VASP rotation

QE (no axes)

VASP (NV63)

VASP rotation

QE (no axes)

Format is auto-detected from extension (.vasp, POSCAR, CONTCAR → VASP; .in → QE/ABINIT; .fdf → SIESTA; .abi → ABINIT; .inp → CP2K).

Crystallographic viewing direction

Periodic structures are not PCA auto-oriented; they render in the raw crystallographic frame (a‖x, b‖y, c≈z). If one cell edge is much shorter than the others the default view looks cramped — pick a direction with --axis (3-digit Miller index), often the shortest edge:

xyzrender structure.res --axis 100 --unwrap   # look down a short a-axis; reassemble whole molecules

For a periodic material, any Miller index works as a viewing direction:

View along [001]

View along [111]

Rotate around [111]

View along [001]

View along [111]

Rotate around [111]

xyzrender NV63_cell.xyz --axis 001 -o NV63_001.svg
xyzrender NV63_cell.xyz --axis 111 -o NV63_111.svg
xyzrender NV63_cell.xyz --axis 111 --gif-rot 111 -o NV63_111.svg -go NV63_111.gif

Crystal flags

Flag

Description

--cell

Force cell rendering for extXYZ (usually not needed)

--no-cell

Hide the unit cell box

--ghosts / --no-ghosts

Show/hide ghost (periodic image) atoms outside the cell

--ghost-opacity

Opacity of ghost atoms/bonds (default: 0.5)

--axes / --no-axes

Show/hide the a/b/c axis arrows

--cell-color

Unit cell box color (hex or named, default: gray)

--cell-width

Unit cell box line width (default: 2.0)

--axis HKL

Orient looking down a crystallographic direction (e.g. 111, 001)

--supercell M N L

Repeat the unit cell M×N×L times along a/b/c (requires lattice/unit-cell data; default: 1 1 1)

--unwrap

Reassemble molecules split across periodic boundaries so each is drawn whole (disables ghost atoms; frameworks left unchanged)