neu_glance.movie.animate¶
Keyframe animation over neuroglancer states — a timeline, and the interpolation under it.
A Timeline wraps one base state (a link tuned in the browser) and a list of
tweens (Tween), each moving one property over a window of time with an easing.
Anything no tween mentions keeps its base value, so the base can be edited without
touching the tweens.
Pure: plain dicts in and out, stdlib only, no neuroglancer. neu_glance.movie.rendering
is the half that needs a viewer.
neuroglancer’s own ViewerState.interpolate is not used: in 2.41.2 it raises for any
state with a layer (it reads a nonexistent layer_position), it covers few layer
properties, and it adds orientations a state did not have. Its zoom and quaternion
formulas are ported here (interpolate_zoom(), interpolate_quaternion()), and a
test checks them against neuroglancer’s.
Attributes¶
Exceptions¶
A timeline could not be built, or would not animate what it claims to. |
Classes¶
Functions¶
|
A rotation of |
|
|
|
|
|
A colour ramp, in linear light by default. Returns |
|
Straight lerp, element-wise for equal-length sequences. |
|
Rotate |
|
Spherical linear interpolation. Ported from |
|
Hold |
|
Exponential interpolation, for the two zoom scales. Ported from |
|
Scale |
|
The interpolator name for |
Module Contents¶
- exception neu_glance.movie.animate.AnimateProblem¶
Bases:
RuntimeErrorA timeline could not be built, or would not animate what it claims to.
Initialize self. See help(type(self)) for accurate signature.
- class neu_glance.movie.animate.Timeline¶
A base state plus tweens over it. Every frame it emits is a plain state dict.
Frame i is at
i / fps;fpsis kept here so a saved timeline fully describes its frames.- at(seconds: float) dict¶
The state at
seconds. A plain dict; the caller’s base is never mutated.
- check() list[str]¶
Raise on anything unworkable; return notes worth printing. Called by the renderer.
- frame_on(box: Any, *, at: float | None = None, seconds: float, ease: str = DEFAULT_EASE, margin: float = 1.15, units: str = 'nm', zoom: bool = True, min_scale: float | None = None, rotation_safe: bool = False) Timeline¶
Pan (and by default zoom) so
boxfills the view.boxis(lo_zyx, hi_zyx)or anything with.lo/.hi(aneu_lib.BBox), e.g. fromneu_glance.sources.segment_boxes().units="nm"(the default, whatsegment_boxesreturns) is converted to the state’s voxels with itsdimensions, since neuroglancer’spositionis in voxels; passunits="voxels"for a box already in viewer coordinates. A wrong choice does not raise; it misplaces the camera by the voxel size.Framing matches
neu_glance.state.default_view(), withmarginas the room around the box;zoom=Falseonly pans.rotation_safe=Truefits the box’s diagonal, for a shot that turns:projectionScalefixes the vertical extent, so a box framed at one angle can overflow at another.min_scalecaps how close the camera goes. An orbit pivots aboutposition, which this also centres.
- frames(*, start_frame: int = 0, end_frame: int | None = None) Iterator[tuple[int, float, dict]]¶
(index, seconds, state)per frame.Times are
index / fps, computed rather than accumulated, so they do not drift.
- classmethod from_json(obj: Mapping[str, Any]) Timeline¶
The inverse of
to_json(), so a rendered timeline can be edited and re-run.
- group(name: str, layers: Sequence[str]) Timeline¶
Name a set of layers that appear together — a neuron and the neuropils it innervates.
- orbit(degrees: float, *, axis: Any = 'up', at: float | None = None, seconds: float, ease: str = DEFAULT_EASE) Timeline¶
Rotate the camera
degreesaboutaxis. Relative — no keyframe needed.axisdefaults to"up", the screen’s vertical: a turntable from any starting view. A volume axis ("z", or a 3-sequence) is reproducible across scenes. A full turn isorbit(360)(seeinterpolate_orbit()).
- resolved() list[Tween]¶
The tweens in application order, each with its
startfilled in.On each property, the first tween starts from the base state and each later one from where the previous ended.
- sequence(names: Sequence[str], *, start: float | None = None, seconds: float = 1.2, stagger: float | None = None, ease: str = DEFAULT_EASE, fade_from: float = FADE_FROM) Timeline¶
Fade in each group in turn,
staggerseconds apart. Returnsself.stagger=Nonemeans back to back; a shorter stagger overlaps the fades. Each layer also starts atobjectAlpha = fade_fromfromt=0, so the scene starts empty.
- set(*, layer: str | None = None, **props: Any) Timeline¶
An opening value at
t=0, held until a later tween takes the property over.
- sets(layer: str, subsets: Mapping[str, Sequence[Any]], *, colors: Mapping[str, str] | None = None, object_alpha: float | None = None) dict[str, str]¶
One layer per named SET of segments. Returns
{set: layer_name}.For populations that fade together (
neu_glance.subset_layers()); usesplit()for individual objects.
- split(layer: str, *, prefix: str | None = None, names: Mapping[str, str] | None = None, segments: Sequence[Any] | None = None) dict[str, str]¶
One layer per segment of
layer. Returns{segment_id: layer_name}.Needed to fade objects individually (
neu_glance.split_segment_layer()). Build groups from the returned layer names.
- to_json() dict¶
The whole timeline, base state included, for writing beside the frames.
- tween(*, layer: str | None = None, at: float | None = None, seconds: float, ease: str = DEFAULT_EASE, start: Any = None, kind: str | None = None, **props: Any) Timeline¶
Move each named property to its given value over
seconds, starting atat.at=Noneuses the cursor, which onlyhold()moves, so consecutive calls run at the same time unless the cursor is advanced.start=Nonetakes the value the property last held: an earlier tween’s end, else the base state, elseLAYER_DEFAULTS/VIEW_DEFAULTS(not zero).
- view(target: Mapping[str, Any] | str, *, at: float | None = None, seconds: float, ease: str = DEFAULT_EASE) Timeline¶
Move the camera to the view held by another state. Returns
self.targetis a state dict or a neuroglancer URL: fly the camera in the browser, copy the link, paste it here. OnlyCAMERA_KEYSare taken; the target’s layers and layout are ignored.
- voxel_size_nm() tuple[float, float, float]¶
The state’s own voxel size in nm, zyx, from its
dimensions.
- zoom(factor: float, *, at: float | None = None, seconds: float, ease: str = DEFAULT_EASE) Timeline¶
Scale the 3D zoom by
factor. Relative:0.5is twice as close.Needs no knowledge of the current
projectionScale.
- base: dict¶
- cursor: float = 0.0¶
- property duration: float¶
Seconds. The furthest tween end, or the cursor, whichever is later.
- fps: float = 30.0¶
- property frame_count: int¶
Frames, including the last one — a 2 s timeline at 30 fps is 61 frames.
- groups: dict[str, tuple[str, ...]]¶
- notes: list[str] = []¶
- class neu_glance.movie.animate.Tween¶
One property, moving from one value to another over one window of time.
- to_json() dict¶
- value_at(t: float, start: Any) Any¶
The value at
t, or_NOTHINGbefore the tween begins (so the earlier value shows). After the window, the end value holds.
- at: float = 0.0¶
- ease: str = 'in-out'¶
- end: Any¶
- kind: str | None = None¶
- path: tuple[str, ...]¶
- seconds: float = 0.0¶
- start: Any = None¶
- property stop: float¶
- neu_glance.movie.animate.axis_quaternion(axis: Any, degrees: float) list[float]¶
A rotation of
degreesaboutaxisas a unit quaternion,xyzw.
- neu_glance.movie.animate.ease(name: str, t: float) float¶
EASINGS[name]applied tot, clamped to[0, 1].
- neu_glance.movie.animate.interpolate_color_map(a: Any, b: Any, t: float, *, default: str | None = None) dict¶
segmentColors, interpolated per segment id.A key on both sides ramps. A key on one side only ramps to or from
default(the layer’ssegmentDefaultColor) if given, and otherwise steps at the end of the window.
- neu_glance.movie.animate.interpolate_hex_color(a: Any, b: Any, t: float, *, space: str = 'linear') str¶
A colour ramp, in linear light by default. Returns
#rrggbb.Endpoints are anything
neu_glance.shaders.as_hex_color()accepts. Hex channels are gamma-encoded, so averaging them directly makes black-to-red pass through a dark maroon; mixing in linear light gives a midpoint that looks halfway.space="srgb"mixes the encoded values, to match ramps made elsewhere.
- neu_glance.movie.animate.interpolate_linear(a: Any, b: Any, t: float) Any¶
Straight lerp, element-wise for equal-length sequences.
Sequences of different lengths hold
a, as neuroglancer does.
- neu_glance.movie.animate.interpolate_orbit(a: Any, b: Any, t: float) list[float]¶
Rotate
aprogressively about an axis.bis{"axis", "degrees", "screen"}.Slerp between two views always takes the shortest arc, so a full turn would be a no-op and 200 degrees would become 160 the other way. Here the angle varies, so any rotation works, including several turns.
screenreads the axis in the camera’s frame (post-multiply) or, if false, the volume’s (pre-multiply).
- neu_glance.movie.animate.interpolate_quaternion(a: Any, b: Any, t: float) list[float]¶
Spherical linear interpolation. Ported from
viewer_state.py:75-104(via gl-matrix).qand-qare the same rotation, sobis negated when needed to take the short way round (otherwise two views 20 degrees apart can turn 340 degrees). Inputs are assumed to be unit quaternions, as neuroglancer writes them.
- neu_glance.movie.animate.interpolate_step(a: Any, b: Any, t: float) Any¶
Hold
a, takebat the end of the transition.Not at the midpoint, where a flip mid-move looks like an artefact. For a change at another time, use a zero-length tween there.
- neu_glance.movie.animate.interpolate_zoom(a: Any, b: Any, t: float) Any¶
Exponential interpolation, for the two zoom scales. Ported from
viewer_state.py:107.Zoom is perceived multiplicatively, so a linear zoom visibly accelerates towards the close end. A non-positive endpoint falls back to a linear lerp rather than raising mid-render.
- neu_glance.movie.animate.interpolate_zoom_by(a: Any, b: Any, t: float) Any¶
Scale
aby a factor, geometrically.bis the factor at the end of the window.Relative and exponential, like
interpolate_zoom(): a factor of 0.5 is twice as close, from wherever the camera is.
- neu_glance.movie.animate.kind_for(prop: str) str¶
The interpolator name for
prop. Unknown properties step; seePROPERTY_KINDS.
- neu_glance.movie.animate.AXES: dict[str, tuple[float, float, float]]¶
- neu_glance.movie.animate.CAMERA_KEYS = ('position', 'projectionOrientation', 'projectionScale', 'projectionDepth',...¶
- neu_glance.movie.animate.DEFAULT_EASE = 'in-out'¶
- neu_glance.movie.animate.EASINGS: dict[str, Callable[[float], float]]¶
- neu_glance.movie.animate.FADE_FROM = 0.001¶
- neu_glance.movie.animate.INTERPOLATORS: dict[str, Callable[[Any, Any, float], Any]]¶
- neu_glance.movie.animate.LAYER_DEFAULTS: dict[str, Any]¶
- neu_glance.movie.animate.PROPERTY_KINDS: dict[str, str]¶
- neu_glance.movie.animate.SCREEN_AXES¶
- neu_glance.movie.animate.VIEW_DEFAULTS: dict[str, Any]¶