Terminal viewer
Render molecules and crystals as images in a terminal — no graphical display
needed, which makes it a practical way to check a structure over ssh on a
machine that has no window system.
As a command
chmpy-view structure.cif # interactive
chmpy-view trajectory.xyz # n / p step through frames
chmpy-view relax/ # a directory is one ensemble
chmpy-view a.cif b.cif geometry.in # so is a list of files
cat structure.cif | chmpy-view - # format guessed from the contents
chmpy-view structure.cif --once # render one frame and exit
chmpy-view structure.cif --once -d '[111]' --cols 100
--once writes a single frame to stdout and returns, which is what you want
in a job script or when the link is slow enough that interaction is painful.
Keys
| key | does |
|---|---|
hjkl or arrows |
rotate in 15° steps — 15 divides 90, so repeated presses land exactly on an axis view |
1 2 3 |
look down a, b, c for a crystal, or x, y, z for a molecule |
d |
type a view direction (see below) |
n p |
next / previous frame; N P jump ten |
+ - |
zoom |
s |
ball-and-stick / space-filling |
f |
lit / flat shading |
c |
1–3 unit cells |
r |
reset the view |
tab q |
switch view, quit |
View directions
d accepts ordinary crystallographic notation:
| input | means |
|---|---|
[uvw], or bare digits like 111 |
a zone axis, ua + vb + wc |
(hkl) |
the normal to a plane, ha* + kb* + lc* |
a b c, a* b* c* |
the cell vectors and their reciprocals |
x y z |
cartesian axes |
A minus binds to the digit after it, so 1-10 is [1,-1,0]. Indices needing
more than one digit are separated by spaces: 10 -2 1.
For a cell that is not orthogonal [uvw] and (hkl) are genuinely different
directions, so both are supported rather than conflated.
As a library
render returns a string. It touches no terminal and has no side effects, so
it works in a script, a notebook, or a log file:
from chmpy import Crystal
from chmpy.tui import render
crystal = Crystal.load("structure.cif")
print(render(crystal, cols=100, direction="[111]"))
Render a structure to a string ready to print.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
structure
|
object
|
a |
required |
cols
|
int
|
width in terminal columns |
DEFAULT_COLS
|
rows
|
int | None
|
height in terminal rows; by default derived from the shape of the structure in this view, so a wide flat cell does not come out surrounded by blank lines |
None
|
direction
|
str | None
|
view direction, e.g. "a", "[111]", "(001)", "z". Defaults to down c for a crystal and down z for a molecule. |
None
|
style
|
str
|
"ball-and-stick" or "space-filling" |
'ball-and-stick'
|
shading
|
str
|
"lit" or "flat" |
'lit'
|
cells
|
int
|
for a crystal, how many unit cells along each axis |
1
|
terminal
|
Terminal | None
|
a |
None
|
theme
|
object | None
|
a |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
the rendered frame, including escape sequences unless the |
str
|
terminal reports no colour support. |
Source code in chmpy/tui/__init__.py
Output modes
The output adapts to what the terminal reports:
| mode | when | what it emits |
|---|---|---|
| graphics | terminal speaks the Kitty graphics protocol | a real image, at full resolution |
| half blocks | 24-bit or 256 colour | ▀ with a foreground and background colour, so one cell carries two square pixels |
| text | NO_COLOR, a pipe, or TERM=dumb |
shaded characters, since half blocks say nothing without colour |
Detection is environment-based. Two cases are worth knowing about:
- Over
ssh,TERMis forwarded butTERM_PROGRAMand the vendor variables are not, so detection relies onTERM. - Inside
tmuxorscreengraphics are disabled, because a multiplexer rewrites escape sequences and passes the protocol through only when explicitly configured. SetCHMPY_FORCE_GRAPHICS=1if yours is.
Reading structures
The viewer loads through chmpy.fmt.load, which dispatches
on its own rather than making you choose Crystal or Molecule in advance.
An FHI-aims geometry is periodic exactly when it declares lattice_vector,
decided from the contents rather than the file name, since the same format
arrives as geometry.in, geometry.in.next_step, and whatever a run
directory happened to call it.
A file may hold several structures — an XYZ trajectory, a multi-block CIF — and several files may be viewed as one ensemble, so a single structure is simply the one-frame case.