Documentation · Complete NMR script
DOCUMENTATION / EXAMPLES
Complete NMR script
Animate a ubiquitin NMR ensemble with camera focus and region highlights.
On this page
examples/nmr_regions.py animates a ubiquitin NMR ensemble with 3D highlights, camera focus, and a transition to ball-and-stick.
PDB 2K39 contains 116 models of ubiquitin. This example interpolates between models to show their structural variation. Model order is not a time sequence.
Run a scene#
proteinmotion render examples/nmr_regions.py RegionTour -o regions.mp4 --fps 60The camera focuses on the helix and tail of ubiquitin. Spheres, boxes, and atom highlights mark the selected regions during NMR playback.
proteinmotion render examples/nmr_regions.py NMRStates -o cartoon.mp4 --fps 60All 116 deposited ubiquitin models, aligned using core Cα atoms. The animation interpolates between consecutive models.
proteinmotion render examples/nmr_regions.py NMRAtoms -o atoms.mp4 --fps 60The same ensemble with 602 heavy atoms per model and element-colored bonds and spheres.
Full source#
"""Real ubiquitin NMR conformers (2K39), camera focus and moving 3D region highlights.
Deposited model order is a visualization order, not a measured time series.
"""
from pathlib import Path
from proteinmotion import (
FadeIn,
FadeOut,
Focus,
PlayTrajectory,
Protein,
ProteinScene,
Representation,
smooth,
)
DATA = Path(__file__).parent / "data/2k39.cif"
def ubiquitin():
loaded = Protein.from_file(DATA, chains="A")
# Align the core, leaving the flexible C-terminal tail free to move.
core = loaded.select(chain="A", residues=(1, 70), atoms="CA")
aligned = loaded.trajectory.aligned(indices=core.atom_indices)
return Protein.from_trajectory(aligned).cartoon().center()
class NMRStates(ProteinScene):
"""All 116 deposited states, smoothly interpolated at five transitions per second."""
show_atoms = False
def construct(self):
p = ubiquitin()
if self.show_atoms:
p.ball_and_stick()
self.add(p)
self.camera.frame(p, margin=1.25, aspect=self.width / self.height)
self.camera.theta, self.camera.phi = 0.7, 0.18
self.camera.depth_cue = 0.4
self.wait(0.5)
self.play(PlayTrajectory(p, state_easing=smooth), run_time=23)
self.wait(0.5)
class NMRAtoms(NMRStates):
show_atoms = True
class RegionTour(ProteinScene):
"""Gold: helix 23–34; cyan: tail 71–76. Highlights follow the moving model."""
def construct(self):
p = ubiquitin()
helix = p.select(chain="A", residues=(23, 34))
tail = p.select(chain="A", residues=(71, 76))
sphere = helix.highlight(style="sphere", color="#f2ba67", opacity=0.13, padding=1.4)
box = helix.highlight(style="box", color="#f2ba67", padding=1.6, line_width=0.09)
halo = tail.highlight(style="atoms", color="#50e0d0", opacity=0.38, padding=0.4)
tail_box = tail.highlight(style="box", color="#50e0d0", padding=1.4, line_width=0.09)
self.add(p)
self.camera.frame(p, margin=1.2, aspect=self.width / self.height)
self.camera.theta, self.camera.phi = 0.7, 0.18
self.camera.depth_cue = 0.38
self.wait(0.5)
self.play(PlayTrajectory(p, start=0, end=20, state_easing=smooth), run_time=4)
self.play(FadeIn(sphere), FadeIn(box), run_time=0.8)
self.focus(helix, margin=1.8, run_time=1.8)
self.play(PlayTrajectory(p, start=20, end=35, state_easing=smooth), run_time=4.5)
self.play(
FadeOut(sphere),
FadeOut(box),
Focus(self.camera, p, margin=1.2, aspect=self.width / self.height),
run_time=1.8,
)
self.play(FadeIn(halo), FadeIn(tail_box), run_time=0.8)
self.focus(tail, margin=2.0, run_time=1.8)
self.play(Representation(p, "ball_and_stick"), run_time=0.8)
self.play(PlayTrajectory(p, start=35, end=45, state_easing=smooth), run_time=5)
self.play(
FadeOut(halo),
FadeOut(tail_box),
Focus(self.camera, p, margin=1.2, aspect=self.width / self.height),
run_time=1.8,
)
self.wait(0.5)
if __name__ == "__main__":
RegionTour(fps=60).render("nmr-region-tour.mp4")The camera focuses on the helix and tail of ubiquitin. Spheres, boxes, and atom highlights mark the selected regions during NMR playback.
Adapt the scene#
Change residues=(23, 34) for an inclusive author-number range, or use [8, 44, 70] for specific residues. start and end are zero-based model indices. run_time is the clip duration in seconds. margin controls camera framing; padding controls the 3D annotation size in ångströms.
Download the Python script or browse the examples on GitHub.