API Reference

Overview

Interactive data visualization for signals, videos, and complex data objects.

datanavigator provides the modality-agnostic data-navigation primitives – browsers, asset managers, events. The point-tracking UI, annotation containers (VideoAnnotation, VideoAnnotations), and Lucas-Kanade helpers (lucas_kanade, lucas_kanade_rstc) used to live here too; in 1.5.0 they were relocated to the dustrack package alongside its DeepLabCut workflow. See dustrack.DUSTrack / dustrack.VideoAnnotation for the new home. git log --follow dustrack/annotations.py traces the full pre-relocation history.

Browsers

  • GenericBrowser: Generic class to browse data. Meant to be extended.

  • SignalBrowser: Browse an array of pysampled.Data elements, or 2D arrays.

  • PlotBrowser: Scroll through an array of complex data where a plotting function is defined for each element.

  • VideoBrowser: Scroll through the frames of a video.

  • VideoPlotBrowser: Browse through video and 1D signals synced to the video side by side.

  • ComponentBrowser: Browse signals (e.g., from periodic motion) as scatterplots of components (e.g., from UMAP, PCA).

Video I/O

  • Video: Extended VideoReader class with additional functionalities.

  • VideoReader: PyAV-backed video reader with a TOC cache.

Assets

  • Button: Custom button widget with a ‘name’ state.

  • StateButton: Button widget that stores a number/coordinate state.

  • ToggleButton: Button widget with a toggle state.

  • Selector: Select points in a plot using the lasso selection widget.

  • StateVariable: Manage state variables with multiple states.

  • EventData: Manage the data from one event type in one trial.

  • Event: Manage selection of a sequence of events.

Assetcontainers

  • AssetContainer: Container for managing assets such as buttons, memory slots, etc.

  • Buttons: Manager for buttons in a matplotlib figure or GUI.

  • Selectors: Manager for selector objects for picking points on line2D objects.

  • MemorySlots: Manager for memory slots to store and navigate positions.

  • StateVariables: Manager for state variables.

  • Events: Manager for event objects.

class datanavigator.GenericBrowser(figure_handle: Figure = None)

Generic class that defines base functionality. Meant to be extended before use.

Features:
  • Navigate using arrow keys.

  • Store positions in memory using number keys (e.g. for flipping between positions when browsing a video).

  • Quickly add toggle and push buttons.

  • Design custom functions and assign hotkeys to them (add_key_binding).

Default Navigation (arrow keys):
  • ctrl+k - show all keybindings

  • right - forward one frame

  • left - back one frame

  • up - forward 10 frames

  • down - back 10 frames

  • shift+left - first frame

  • shift+right - last frame

  • shift+up - forward nframes/20 frames

  • shift+down - back nframes/20 frames

update_assets()

Update the display of various assets.

update(event=None)

Update the browser. Extended classes are expected to implement their update function.

Parameters:

event (optional) – Event that triggered the update. Defaults to None.

update_without_clear(event=None)

Update the browser without clearing the axis.

Parameters:

event (optional) – Event that triggered the update. Defaults to None.

add_item_dropdown(names: list[str] | None = None, var_name: str = 'item') StateVariable

Add a sidebar dropdown to jump straight to a browsed item by name.

Generic across browsers: the dropdown is two-way bound to _current_idx. Picking an entry moves the browse index and redraws; arrow-key navigation keeps the dropdown in step (see _sync_item_dropdown(), invoked from update_assets()). Built on the StateVariable(widget="dropdown") machinery – a QComboBox on Qt, read-only text fallback on non-Qt backends.

Suited to browsing tens-to-hundreds of named items (signals, plot items); not to scrubbing thousands of video frames, which is why the video browsers leave it off.

Idempotent: re-calling with the same var_name replaces the existing dropdown (e.g. to relabel once the items are known).

Parameters:
  • names – one label per browsed item. None -> _default_item_names(). Length must match len(self).

  • var_name – the state-variable name (the dropdown’s row label).

Returns:

The registered StateVariable.

mpl_remove_bindings(key_list: list[str])

Remove existing key bindings in matplotlib.

Parameters:

key_list (list[str]) – List of keys to remove bindings for.

cleanup()

Perform cleanup, for example, when the figure is closed.

mpl_restore_bindings()

Restore any modified default keybindings in matplotlib.

reset_axes(axis: str = 'both', event=None, axes=None)

Reframe data within matplotlib axes.

Parameters:
  • axis (str, optional) – Axis to reset. Defaults to “both”.

  • event (optional) – Event that triggered the reset. Defaults to None.

  • axes (Iterable[Axes] | None, optional) – Restrict the walk to this subset of axes. None (default) walks self.figure.axes — the historical behaviour. Cursor-aware dispatch in VideoPointAnnotator._reset_view_all passes a 2-element list [_ax_trace_x, _ax_trace_y] to scope the refit to the trace pair when the cursor is over one of them.

add_key_binding(key_name: str, on_press_function: callable, description: str = None, *, group: str | None = None, on_button: bool = False)

Add a key binding to the browser.

Parameters:
  • key_name – Key to bind (matplotlib key-event string, e.g. “s”, “ctrl+a”, “shift+left”).

  • on_press_function – Function to call when the key is pressed.

  • description – Human-readable label shown in the cheatsheet. Defaults to on_press_function.__name__.

  • group – Section header in the cheatsheet dialog. None falls into the “Other” section (rendered last).

  • on_button – When True, find a button whose action_func is identically on_press_function and append "  ({key_name})" to its label. The match is by is comparison — pass the same callable object to both Buttons.add() and this method (no intermediate lambdas) or the hint won’t attach. Resolution is symmetric: if the button is added after the binding, Buttons.add() performs the same scan.

remove_key_binding(key_name: str)

Remove a key binding from the browser.

Parameters:

key_name (str) – Key to remove the binding for.

set_default_keybindings()

Set default key bindings for navigation.

increment(step: int = 1)

Increment the current index.

Parameters:

step (int, optional) – Number of steps to increment. Defaults to 1.

decrement(step: int = 1)

Decrement the current index.

Parameters:

step (int, optional) – Number of steps to decrement. Defaults to 1.

go_to_start()

Go to the start of the data.

go_to_end()

Go to the end of the data.

increment_frac(n_steps: int = 20)

Browse the entire dataset in n_steps. Increment the current index by a fraction of the total length.

Parameters:

n_steps (int, optional) – Number of steps to divide the total length into. Defaults to 20.

decrement_frac(n_steps: int = 20)

Decrement the current index by a fraction of the total length.

Parameters:

n_steps (int, optional) – Number of steps to divide the total length into. Defaults to 20.

copy_to_clipboard()

Copy the current figure window to the clipboard.

On a Qt backend, grabs the entire QMainWindow – the matplotlib canvas plus every Qt-side widget parented to it (left-column dock with buttons / statevariables, fast_render image pane, downstream sidebars added by consumers such as DUSTrack). The pre-rc2 path savefig’d the figure alone and missed all of them; on a DUSTrack window the clipboard image would show the trace canvas with nothing where the sidebar / image pane visually sat.

On non-Qt backends (Agg, headless), falls back to copying just the matplotlib figure via savefig.

Requires a Qt binding (PyQt5 / PyQt6 / PySide2 / PySide6); imported lazily via qtpy so installs without Qt still get the rest of the package. pip install datanavigator[qt] pulls PyQt6.

show_key_bindings()

Open the keyboard-shortcut cheatsheet.

On a Qt-backed figure: a modeless QDialog with one section per KeyBinding.group (insertion order; None group rendered last as “Other”). Each section is a 2-column table — monospace shortcut on the left, description on the right.

On non-Qt backends: prints the same content to stdout. The pre-rc2 TextView overlay is gone; matplotlib doesn’t host a nice cheatsheet without the Qt path.

pan(direction: str = 'left', frac: float = 0.2)

Pan the view.

Parameters:
  • direction (str, optional) – Direction to pan. Defaults to “left”.

  • frac (float, optional) – Fraction of the view to pan. Defaults to 0.2.

has(asset_type: str) bool

Check if the browser has a specific asset type.

Parameters:

asset_type (str) – Type of asset to check for.

Returns:

True if the asset type is present, False otherwise.

Return type:

bool

class datanavigator.SignalBrowser(plot_data: list[pysampled.core.Data], titlefunc: Callable | None = None, figure_handle: Figure | None = None, reset_on_change: bool = False, signal_names: list[str] | None = None, show_signal_dropdown: bool = True)

Browse an array of pysampled.Data elements, or 2D arrays.

update(event=None)

Update the browser.

Parameters:

event (optional) – Event that triggered the update. Defaults to None.

add_signal_dropdown(names: list[str] | None = None, var_name: str = 'signal') StateVariable

Add the signal-selection dropdown (a thin wrapper).

Delegates to GenericBrowser.add_item_dropdown() with a "signal" row label. names=None derives labels from each entry’s name (falling back to "signal <i>" via _default_item_names()). See add_item_dropdown() for the full contract: idempotent relabeling, Qt vs text rendering, and the two-way _current_idx binding.

class datanavigator.PlotBrowser(plot_data: list, plot_func: tuple[callable, callable] | callable, figure_handle: plt.Figure = None, item_names: list[str] | None = None, show_item_dropdown: bool = True, **plot_kwargs)

Takes a list of data, and a plotting function (or a pair of setup and update functions) that parses each of the elements in the array. Assumes that the plotting function is going to make one figure.

get_current_data()

Data getter. Plotting data is a list of objects that are being plotted one at a time. This function returns the current object.

update(event: Any = None)

Update the browser.

class datanavigator.VideoBrowser(vid_name: str, titlefunc: ~typing.Callable | None = None, figure_or_ax_handle: ~matplotlib.axes._axes.Axes | ~matplotlib.figure.Figure | None = None, image_process_func: ~typing.Callable = <function VideoBrowser.<lambda>>, fast_render: bool = False)

Scroll through the frames of a video, extract clips of interest.

If figure_handle is an axis handle, the video will be plotted in that axis.

Future Enhancements:
  • Extend VideoBrowser to play, pause, and extract clips using hotkeys.

  • Show timeline in VideoBrowser.

  • Add clickable navigation.

increment_frac(n_steps: int = 100) None

Browse entire dataset in n_steps.

Parameters:

n_steps (int) – Number of steps to increment.

decrement_frac(n_steps: int = 100) None

Browse entire dataset in n_steps.

Parameters:

n_steps (int) – Number of steps to decrement.

update() None

Update the video frame.

extract_clip(start_frame: int | None = None, end_frame: int | None = None, fname_out: str | None = None, out_rate: int | None = None) str

Extract a clip from the video.

Parameters:
  • start_frame (Optional[int]) – Starting frame of the clip.

  • end_frame (Optional[int]) – Ending frame of the clip.

  • fname_out (Optional[str]) – Output filename.

  • out_rate (Optional[int]) – Output frame rate.

Returns:

Path to the extracted clip.

Return type:

str

class datanavigator.VideoPlotBrowser(vid_name: str, signals: Dict[str, Data], titlefunc: Callable | None = None, figure_handle: Figure | None = None, event_win: tuple | None = None)

Browse a video and an array of pysampled.Data side by side.

Parameters:
  • vid_name (str) – Path to the video file.

  • signals (Dict[str, pysampled.Data]) – Dictionary of signals.

  • titlefunc (Optional[Callable]) – Function to generate the title for the plot.

  • figure_handle (Optional[plt.Figure]) – Handle to the figure.

  • event_win (Optional[tuple]) – Event window. Visualize signals around an event. Use this to create “scrolling” plot visualizations, e.g. [-0.5, 1.].

update() None

Update the video frame and signals.

onclick(event) None

Right click mouse to seek to that frame.

Parameters:

event – Matplotlib event.

extract_clip(start_frame: int | None = None, end_frame: int | None = None, sav_dir: str | None = None, out_rate: float = None) str

Save a video of screengrabs.

Parameters:
  • start_frame (Optional[int]) – Starting frame of the clip. Defaults to the first memory slot.

  • end_frame (Optional[int]) – Ending frame of the clip. Defaults to the second memory slot.

  • sav_dir (Optional[str]) – Directory to save the clip. If not provided, a timestamped directory is created.

Returns:

Path to the saved video file.

class datanavigator.ComponentBrowser(data: ndarray, data_transform: ndarray, labels: ndarray | None = None, figure_handle: Figure | None = None, class_names: dict[int, str] | None = None, desired_class_names: dict[int, str] | None = None, annotation_names: dict[int, str] | None = None)
property n_signals: int

Return the number of signals.

property n_timepts: int

Return the number of time points.

property colors: list[tuple]

Return the colors for each class.

property signal: Data

Return the 2D Numpy array as a signal.

select_signal_piece_dblclick(event: Any) None

Double click a signal piece in the timecourse view to highlight that point.

Parameters:

event (Any) – The mouse event.

onpick(event: Any) None

Single click a projected point.

Parameters:

event (Any) – The pick event.

update() None

Update the plot with the current data index.

update_class_info_text(draw: bool = True) None

Update the class info text.

Parameters:

draw (bool) – Whether to draw the plot after updating.

update_desired_class_info_text(draw: bool = True) None

Update the desired class info text.

Parameters:

draw (bool) – Whether to draw the plot after updating.

update_mode_text(draw: bool = True) None

Update the mode text.

Parameters:

draw (bool) – Whether to draw the plot after updating.

update_message_text(text: str, draw: bool = True) None

Update the message text.

Parameters:
  • text (str) – The message text.

  • draw (bool) – Whether to draw the plot after updating.

toggle_mode(event: Any | None = None) None

Toggle between correction and annotation modes.

Parameters:

event (Any | None) – The key event.

update_colors(data_idx: list[int] | None = None, draw: bool = True) None

Update the colors of the plot.

Parameters:
  • data_idx (list[int] | None) – list of data indices to update.

  • draw (bool) – Whether to draw the plot after updating.

update_all() None

Update all components of the plot.

clear_axes(event: Any | None = None) None

Clear the axes.

Parameters:

event (Any | None) – The key event.

classlabels_to_dict() dict[int, dict[str, int | str | list[str]]]

Convert class labels to a dictionary.

Returns:

Dictionary of class labels.

Return type:

dict[int, dict[str, int | str | list[str]]]

set_classlabels(classlabels_dict: dict[int, dict[str, int | str | list[str]]]) None

Set class labels from a dictionary.

Parameters:

classlabels_dict (dict[int, dict[str, int | str | list[str]]]) – Dictionary of class labels.

class datanavigator.Video(uri: str, ctx=cpu(0), width: int = -1, height: int = -1, num_threads: int = 0, fault_tol: int = -1)

Extended VideoReader class with additional methods.

gray(frame_num: int) ndarray

Convert a frame to grayscale.

Parameters:

frame_num (int) – Frame number to convert.

Returns:

Grayscale frame.

Return type:

np.ndarray

class datanavigator.VideoReader(uri, ctx=None, width: int = -1, height: int = -1, num_threads: int = 0, fault_tol: int = -1, pix_fmt: str | None = None)

decord-compatible random-access video reader backed by PyAV+TOC.

The constructor signature mirrors decord.VideoReader so existing call sites and subclasses continue to work; ctx, width, height, num_threads, fault_tol are accepted but ignored (PyAV honors the source resolution and is CPU-only here).

A frame-index TOC and per-frame pts/duration table are built from the video at open time and cached next to it as <video>.dnav-toc (JSON content; the .json extension is intentionally omitted so *.json walkers in downstream tooling don’t pick the sidecar up). The key is path + size + mtime + head/tail SHA-256. On a cache hit the second open is sub-second; on a miss the first open prints a one-line “building TOC…” notice. Use precompute_toc() to warm the cache for a set of videos before an interactive session.

get_frame_timestamp(indices) ndarray

Return (N, 2) array of [start, end] times in seconds for each requested frame — decord-compatible.

On a v2 cache hit this is a slice; on a v1 cache hit (legacy sidecar) or never-cached file, the per-frame pts/duration table is built from a full demux+decode pass on first call (announced with a one-line notice) and the sidecar is upgraded in place if writable.

datanavigator.cpu(device_id: int = 0) _CpuCtx

decord.cpu() compatibility shim. Returns a sentinel; PyAV is CPU-only.

datanavigator.precompute_toc(paths: Iterable[str | PathLike], *, force: bool = False, show_progress: bool = True, progress_callback: Callable[[int, int, str, str], None] | None = None, cancel_check: Callable[[], bool] | None = None) dict

Batch-build and cache TOCs + per-frame timestamps for a sequence of video files.

Useful before an annotation session, so the per-video “Building TOC…” pause doesn’t happen interactively:

import glob, datanavigator
datanavigator.precompute_toc(glob.glob("data/*.mp4"))

For folder-walking semantics, see precompute_toc_folder().

Parameters:
  • paths – Iterable of video file paths.

  • force – If True, rebuild + overwrite even when a valid cache exists. (A valid v1 sidecar counts as a hit; pass force=True to upgrade pre-1.3 sidecars to schema v2 with per-frame timestamps.)

  • show_progress – If True (default), wrap iteration in a tqdm bar. Suppressed when progress_callback is set, so UI callers don’t get both a bar and their own per-file updates.

  • progress_callback – Optional fn(idx, total, path, status) invoked after each video is resolved (hit / built / error). idx is the zero-based position in the input list, total is the full length, path is the string path passed in, status is the same per-file string written into the return dict. Lets UI consumers drive their own progress widget without parsing tqdm output.

  • cancel_check – Optional zero-arg callable polled at the top of each video. If it returns truthy, the loop exits early and the partial {path: status} dict is returned (already- processed entries kept). Used by UI consumers’ Cancel button.

Returns:

{path: status} where status is "hit" (cache already valid), "built" (rebuilt and cached), "built (uncached)" (built but sidecar save failed), or f"error: {msg}" (skipped).

datanavigator.precompute_toc_folder(folder: str | PathLike | Iterable[str | PathLike], *, extensions: Iterable[str] = ('.mp4', '.mov', '.mkv', '.avi', '.m4v'), recursive: bool = True, force: bool = False, show_progress: bool = True, progress_callback: Callable[[int, int, str, str], None] | None = None, cancel_check: Callable[[], bool] | None = None) dict

Walk a folder (or list of folders / files) and build TOCs for each video.

Thin sibling of precompute_toc() that handles directory walking so callers don’t have to glob themselves. Each folder entry may be a directory (walked for extensions) or a file (kept as-is). Non-existent entries that were named explicitly are surfaced as "error: missing" in the returned dict; directories that turn up no matching videos are silently empty.

Example:

import datanavigator
results = datanavigator.precompute_toc_folder(
    "M:/us_videos_for_tracking2",
)
# {'M:/.../foo.mp4': 'hit', 'M:/.../bar.mp4': 'built', ...}
Parameters:
  • folder – A directory path, a file path, or an iterable mixing both.

  • extensions – File extensions to include (case-insensitive). Default covers the common video container formats.

  • recursive – If True (default), recurse into subdirectories.

  • force – Forwarded to precompute_toc() — rebuild even on hit.

  • show_progress – Forwarded to precompute_toc() — tqdm bar.

  • progress_callback – Forwarded to precompute_toc().

  • cancel_check – Forwarded to precompute_toc().

Returns:

{path: status} per precompute_toc(), with an extra "error: missing" entry for any explicitly-named path that doesn’t exist.

class datanavigator.Button(ax, name: str, **kwargs)

Add a ‘name’ state to a matplotlib widget button.

class datanavigator.StateButton(ax, name: str, start_state: Any, **kwargs)

Store a number/coordinate in a button.

class datanavigator.ToggleButton(ax, name: str, start_state: bool = True, **kwargs)

Add a toggle button to a matplotlib figure.

For example usage, see PlotBrowser.

set_text() None

Set the text of the toggle button.

toggle(event=None) None

Toggle the state of the button.

set_state(state: bool) None

Set the state of the button.

class datanavigator.Selector(plot_handle: Line2D)

Select points in a plot using the lasso selection widget.

Indices of selected points are stored in self.sel.

Example

f, ax = plt.subplots(1, 1) ph, = ax.plot(np.random.rand(20)) plt.show(block=False) ls = gui.Lasso(ph) ls.start() – play around with selecting points – ls.stop() -> disconnects the events

get_data() ndarray

Get the data points of the plot.

onselect(verts: List[tuple]) None

Select if not previously selected; Unselect if previously selected.

start(event=None) None

Start the lasso selection.

stop(event=None) None

Stop the lasso selection.

toggle(event=None) None

Toggle the lasso selection.

class datanavigator.StateVariable(name: str, states: list, widget: str = 'label')

Manage state variables with multiple states.

The widget hint is metadata read by the rc2 Qt sidebar to choose a control surface for this state variable: "label" (read-only text line; default), "dropdown" (QComboBox), or "toggle" (mutually-exclusive row of checkable QToolButtons). On non-Qt backends the hint is ignored and the value renders as plain text via the legacy TextView path.

property current_state: Any

Get the current state.

n_states() int

Get the number of states.

add_on_change(callback: Callable[[], None]) None

Register a no-arg callback fired after state mutations.

Fires on every set_state() / cycle() / cycle_back() call, regardless of whether the index actually changed – consumers that need a real-change guard should track the previous value themselves (e.g. VideoPointAnnotator._on_active_label_change()).

cycle() None

Cycle to the next state.

cycle_back() None

Cycle to the previous state.

set_state(state: int | str) None

Set the state.

class datanavigator.AssetContainer(parent: Any)

Container for assets such as a button, memoryslot, etc.

Parameters:

parent (Any) – matplotlib figure, or something that has a ‘figure’ attribute that is a figure.

__getitem__(key: int | str) Any

Return an asset by the name key or by position in the list.

add(asset: Any) Any

Add an asset to the container.

remove(name: str) Any

Remove and return the asset with this name.

Counterpart to add(); raises KeyError if no asset in the container carries that name. The caller is responsible for tearing down any plot handles / Qt widgets the asset owns – AssetContainer only manages the membership list.

class datanavigator.Buttons(parent: Any)

Manager for buttons in a matplotlib figure or GUI (see GenericBrowser for example).

Phase 3 of the 1.4.0 Qt refactor (soft mode): when the parent’s figure is on a Qt canvas AND no explicit pos is given, add() builds a native QPushButton in a QVBoxLayout column hosted by a QDockWidget on the QMainWindow’s LeftDockWidgetArea (pre-rc2: QToolBar; see _qt._get_buttons_widget()). On every other backend, or when an explicit pos is given, the original matplotlib-widgets path runs unchanged. The returned object exposes the same public surface either way (name, on_clicked, plus toggle-specific state / toggle / set_text / set_state).

Lifecycle gotcha: Buttons.add() reads the figure’s canvas at call time. If a Figure subclass adds buttons inside its own __init__ (as in datanavigator.examples.ButtonDemo), this runs before matplotlib attaches a Qt canvas to the figure, so those buttons end up on the mpl path even under QtAgg. The buttons still function; they just miss the Phase 3 perf win. Browsers that take a figure_handle (the common case) are unaffected, because the figure is fully constructed before any button is added.

rc2 row-cursor note: _mpl_row_cursor tracks the next vertical slot for the mpl-fallback layout independent of len(self). add() and add_separator() used to derive y from len(self), which assumed one button per row. add_multi() (one row, N buttons) breaks that assumption, so the cursor is bumped by 1 per row (regardless of how many buttons land on it) while len(self) still grows by N. For single-add-only flows the two stay equal, preserving pre-rc2 placement.

add(text: str = 'Button', action_func: Callable | List[Callable] | None = None, pos: tuple | None = None, w: float = 0.25, h: float = 0.05, buf: float = 0.01, type_: str = 'Push', style_tag: str | None = None, **kwargs) Button

Add a button to the parent figure / object.

If pos is provided, then w, h, and buf will be ignored.

register_style(name: str, styler: Callable[[Any], None]) None

Register a per-button styler under name.

Consumers call this once at setup, then pass style_tag=name to add() / add_multi(). Re-registering an existing name (including a styles built-in) replaces the binding – consumer registrations always win over built-ins.

styler is invoked with the freshly-constructed button as its sole argument at the tail of _finalize_button(). It should detect the Qt path via getattr(b, "_qt_btn", None) and apply QSS / palette manipulation; mpl-path styling is the styler’s choice (the dnav built-ins no-op there).

reapply_styles() None

Re-run the styler for every already-added button.

Useful after register_style() changes a binding (e.g. a theme swap re-registers "primary" with a dark-mode palette and the existing buttons need to repaint).

add_multi(*specs: dict) List[Any]

Add N buttons side-by-side in a single row.

Each spec is a dict of kwargs accepted by add() – typically {text=..., action_func=..., type_=...}. Returns the list of created button objects in spec order.

On the Qt path, all N buttons are children of a single QWidget with a QHBoxLayout inserted into the buttons column’s QVBoxLayout; the row therefore consumes one vertical slot in the sidebar regardless of N. On the mpl fallback path, the row’s width is divided evenly across N buttons at a shared y, and _mpl_row_cursor is bumped by 1 (not N) so a following add() lands on the next row, not N rows down.

Edge cases: - add_multi() with no specs is a no-op and returns []. - add_multi(one_spec) is equivalent to add(**one_spec)

full-width single button – and returns a one-element list.

  • Per-spec pos= is rejected (row layout is the whole point; explicit pos is a single-button-only escape hatch).

add_separator(name: str | None = None, style: str = 'single') None

Add a visual group boundary between buttons.

On the Qt path (figure on a Qt canvas), inserts a sunken QFrame.HLine into the buttons-column QVBoxLayout – a thin line marking a group boundary. style="double" inserts two stacked HLines for a stronger section break, used by DUSTrack to mark major button groups in its rc2 sidebar. On the mpl path, inserts one (or two, for style="double") invisible buttons that occupy layout slots so subsequent buttons are pushed down. (Pre-rc2 the Qt-path inserted a QToolBar.addSeparator() QAction; single-HLine only.)

Promoted to a first-class API for downstream consumers (DUSTrack) that previously hand-rolled invisible spacers by mutating matplotlib.widgets.Button internals (.ax, .label, .ax.patch) – internals that don’t exist on the Qt path.

Parameters:
  • name – Internal name for the mpl-path spacer slot; auto-generated if None. Ignored on the Qt path.

  • style"single" (default) or "double". See above.

class datanavigator.Selectors(parent: Any)

Manager for selector objects - for picking points on line2D objects.

add(plot_handle: Line2D) Selector

Add a selector to the container.

class datanavigator.MemorySlots(parent: Any)

Manager for memory slots to store and navigate positions.

static initialize() dict

Initialize memory slots.

disable() None

Disable memory slots.

enable() None

Enable memory slots.

show(pos: str = 'bottom left') None

Show memory slot text.

update(key: str) None

Handle memory slot updates.

Initiate when None, go to the slot if it exists, free slot if pressed when it exists. key is the event.key triggered by a callback.

update_display() None

Refresh memory slot text if it is not hidden.

hide() None

Hide the memory slot text.

is_enabled() bool

Check if memory slots are enabled.

class datanavigator.StateVariables(parent: Any)

Manager for state variables.

asdict() dict

Return state variables as a dictionary.

add(name: str, states: list, widget: str = 'label') StateVariable

Add a state variable to the container.

Parameters:
  • name – identifier; must be unique within the container.

  • states – the rotation of values this variable can take.

  • widget – rc2 Qt-sidebar control surface hint – one of "label" (read-only text; default; matches pre-rc2 behavior), "dropdown" (QComboBox), or "toggle" (mutually-exclusive QToolButton row). Ignored on non-Qt backends.

show(pos: str = 'bottom right', fax=None) None

Show state variables.

rc2: tries the interactive Qt widget first (dropdowns / toggles / labels per each StateVariable’s widget hint), mounted in the QDockWidget column beneath the buttons. Falls back to the pre-rc2 utils.TextView path on non-Qt backends or if no Qt window is found. The pos / fax arguments are only consulted on the TextView fallback; on the Qt path they’re ignored (the widget’s position is dock-managed).

update_display(draw: bool = True) None

Update the display of state variables.

class datanavigator.Events(parent: Any)

Manager for Event objects.

add(name: str, size: int, fname: str, data_id_func: ~typing.Callable, color: str | int, pick_action: str = 'overwrite', ax_list: list | None = None, win_remove: tuple[float, float] = (-0.1, 0.1), win_add: tuple[float, float] = (-0.25, 0.25), add_key: str | None = None, remove_key: str | None = None, save_key: str | None = None, show: bool = True, data_func: ~typing.Callable = <class 'float'>, **plot_kwargs) Event

Add an event.

Parameters:
  • name (str) – Name of the event.

  • size (int) – Length of the sequence. For example, if this is 2, then the event is a pair of start and end times.

  • fname (str) – File name to save the event.

  • data_id_func (Callable) – Function to get the current data ID from the parent UI.

  • color (str | int) – Color used to display the event

  • pick_action (str, optional) – Action to take when picking an event (‘overwrite’ or ‘append’). Use overwrite if there can only be one sequence per ‘signal’. If there can be multiple, use ‘append’. Defaults to overwrite. Defaults to ‘overwrite’.

  • ax_list (list | None, optional) – list of axes on which to show the event. Defaults to None.

  • win_remove (tuple[float, float], optional) – Window relative to the mouse position to search for removing an event. Defaults to (-0.1, 0.1).

  • win_add (tuple[float, float], optional) – Window relative to the mouse position to search for adding an event. Defaults to (-0.25, 0.25). For future use.

  • add_key (str | None, optional) – Keyboard shortcut for adding the event. Defaults to None.

  • remove_key (str | None, optional) – Keyboard shortcut for removing the event. Defaults to None.

  • save_key (str | None, optional) – Keyboard shortcut for saving the events to a JSON file. Defaults to None.

  • show (bool, optional) – Event visibility. Defaults to True.

  • data_func (Callable, optional) – Function to apply on the incoming event. Intended use is for type casting. Defaults to float.

Returns:

_description_

Return type:

Event

add_from_file(fname: str, data_id_func: ~typing.Callable, ax_list: list | None = None, add_key: str | None = None, remove_key: str | None = None, save_key: str | None = None, show: bool = True, data_func: ~typing.Callable = <class 'float'>, **plot_kwargs) Event

Add events from an existing file. Intended use case - events are created by another algorithm meant to be edited using a browser in the datanavigator.

Parameters:
  • fname (str) – File name to load the events.

  • data_id_func (Callable) – Function to get the current data ID from the parent UI.

  • ax_list (list | None, optional) – list of axes on which to show the event. Defaults to None.

  • add_key (str | None, optional) – Keyboard shortcut for adding the event. Defaults to None.

  • remove_key (str | None, optional) – Keyboard shortcut for removing the event. Defaults to None.

  • save_key (str | None, optional) – Keyboard shortcut for saving the events to a JSON file. Defaults to None.

  • show (bool, optional) – Event visibility. Defaults to True.

  • data_func (Callable, optional) – Function to apply on the incoming event. Intended use is for type casting. Defaults to float.

Returns:

The created Event object.

Return type:

Event

setup_display() None

Setup display for all events.

update_display(draw: bool = True) None

Update display for all events

class datanavigator.Event(name: str, size: int, fname: str, data_id_func: ~typing.Callable | None = <function Event.<lambda>>, color: str | int = 'random', pick_action: str = 'overwrite', ax_list: list | None = None, win_remove: tuple[float, float] = (-0.1, 0.1), win_add: tuple[float, float] = (-0.25, 0.25), data_func: ~typing.Callable = <class 'float'>, **plot_kwargs)

Manage selection of a sequence of events (of length >= 1).

Variables:
  • name (str) – Name of the event.

  • size (int) – Length of the sequence.

  • fname (str) – File name to load and save events.

  • data_id_func (Callable) – Function to get the current data ID from the parent UI.

  • color (str) – Color of the event. Defaults to a random color.

  • pick_action (str) – Action to take when picking an event (‘overwrite’ or ‘append’). Use overwrite if there can only be one sequence per ‘signal’. If there can be multiple, use ‘append’. Defaults to overwrite

  • ax_list (list) – list of axes on which to show the event.

  • win_remove (tuple) – Window relative to the mouse position to search for removing an event. Defaults to (-0.1, 0.1).

  • win_add (tuple) – Window relative to the mouse position to search for adding an event. Defaults to (-0.25, 0.25).

  • data_func (Callable) – Function to process the data.

  • plot_kwargs (dict) – Keyword arguments for plotting. Commonly used keys are ‘display_type’ (line or fill) and ‘alpha’ to set the transparency level.

classmethod from_file(fname: str, **kwargs) Event

Create an empty events file with the given file name (fname) and any parameters. Assigns best-guess defaults.

classmethod from_data(data: dict, name: str = 'Event', fname: str = '', overwrite: bool = False, **kwargs) Event

Create an event file by filling in the ‘default’ events extracted by an algorithm.

Parameters:
  • data (dict) – Data to create the event file.

  • name (str) – Name of the event.

  • fname (str) – File name to save the event.

  • overwrite (bool) – Whether to overwrite the existing file.

  • **kwargs – Additional keyword arguments. tags, algorithm_name, and params will be passed to EventData. All other keyword arguments will be passed to Event.

Returns:

The created Event object.

Return type:

Event

all_keys_are_tuples() bool

Check if all keys are tuples.

get_header() dict

Get the header information of the event.

load() tuple[dict, dict]

Load the event data from the file.

save() None

Save the event data to the file.

add(event: Any) None

Pick the time points of an interval and associate it with a supplied ID. If the first selection is outside the axis, then select the first available time point. If the last selection is outside the axis, then select the last available time point. If the selections are not monotonically increasing, then empty the buffer. If any of the ‘middle’ picks (i.e. not first or last in the sequence) are outside the axes, then empty the buffer.

The parent UI would invoke this method.

Parameters:

event (Any) – The event to add.

remove(event: Any) None

Remove an event.

Parameters:

event (Any) – The event to remove.

get_current_event_times() list

Get the current event times.

setup_display() None

Setup event display on one or more axes.

update_display(draw: bool = True) None

Update the event display.

to_dict() dict

Convert the event data to a dictionary.

to_portions() dict

Convert the event data to portions.

class datanavigator.EventData(default: list | None = None, added: list | None = None, removed: list | None = None, tags: list | None = None, algorithm_name: str = '', params: dict | None = None)

Manage the data from one event type in one trial.

Variables:
  • default (list) – Default events created by an algorithm.

  • added (list) – Manually added events. Note that if an ‘added’ point is removed, then it will simply be deleted. There will be no record of it.

  • removed (list) – Events removed from the default list.

  • tags (list) – Tags associated with the events.

  • algorithm_name (str) – Name of the algorithm used to generate the default list.

  • params (dict) – Parameters used to generate the default list.

asdict() dict

Convert the event data to a dictionary.

get_size() int

Return the size of the envent, for example, 2 for start and stop events.

get_times() list

Get the times of all events.

to_portions() _PNInterval

Convert the event times to portions.

overlap_duration(other: 'portion.Interval' | tuple) float

Calculate the duration of overlap with another interval.

class datanavigator.TextView(text: List[str] | dict, fax: None | Figure | Axes = None, pos: str | Tuple[float, float, str, str] = 'bottom left')

Show text array line by line.

Phase 2 of the 1.4.0 Qt refactor (soft mode): when fax resolves to a figure whose canvas is a matplotlib Qt canvas, the text renders as a native QLabel overlay parented to the canvas (self._overlay set, self._text stays None). On every other backend the original Axes.text path runs unchanged (self._overlay is None, self._text is the mpl Text artist).

The public surface (__init__ signature, .text, .update) is identical across both paths.

parse_text(text: List[str] | dict) List[str]

Parse text input into a list of strings.

Parameters:

text (Union[List[str], dict]) – Text input.

Returns:

Parsed text.

Return type:

List[str]

setup() None

Setup for showing the text.

update(new_text: List[str] | dict = None) None

Update the text view with new text.

Parameters:

new_text (Union[List[str], dict], optional) – New text to display. Defaults to None.

datanavigator.get_palette(palette_name: str = 'Set2', n_colors: int = 10) List[Tuple[float, float, float]]

Get a color palette, with fallback if seaborn is not available.

Parameters:
  • palette_name (str, optional) – Name of the palette. Defaults to “Set2”.

  • n_colors (int, optional) – Number of colors. Defaults to 10.

Returns:

List of RGB tuples.

Return type:

List[Tuple[float, float, float]]

datanavigator.is_path_exists_or_creatable(pathname: str) bool

True if the passed pathname is a valid pathname for the current OS _and_ either currently exists or is hypothetically creatable; False otherwise.

This function is guaranteed to _never_ raise exceptions.

datanavigator.ticks_from_times(times: List[float], tick_lim: Tuple[float, float]) Tuple[List[float], List[float]]

Generate x, y arrays to supply to plt.plot function to plot a set of x-values (times) as ticks.

Parameters:
  • times (List[float]) – List of time values.

  • tick_lim (Tuple[float, float]) – Limits for the y-axis ticks.

Returns:

x and y arrays for plotting ticks.

Return type:

Tuple[List[float], List[float]]

datanavigator.get_example_video(dest_folder: str = None, source_url: str = None) str

Download a sample video file if it doesn’t exist locally and return its path.

Uses a default destination folder and source URL if none are provided. The default destination is retrieved from _config.get_clip_folder(). The default source URL points to a small jellyfish video.

Parameters:
  • dest_folder (str, optional) – The folder where the video should be saved. Defaults to the folder specified in the configuration.

  • source_url (str, optional) – The URL from which to download the video. Defaults to a known test video URL.

Returns:

The local file path to the downloaded (or existing) video.

Return type:

str

Raises:
  • AssertionError – If a dest_folder is provided but does not exist.

  • urllib.error.URLError – If the video download fails (e.g., network issue, invalid URL).

class datanavigator.EventPickerDemo

Demonstrates browsing signals and picking events using the SignalBrowser.

This class extends SignalBrowser to showcase how to: - Load multiple signals (random noise in this case). - Define and manage different types of events (‘pick1’, ‘pick2’, ‘pick3’)

with varying sizes and picking behaviors (‘append’, ‘overwrite’).

  • Assign keyboard shortcuts for adding, removing, and saving events.

  • Customize event display (line vs. fill).

  • Override the update method to ensure event displays are refreshed.

Key Bindings:

‘1’: Add a ‘pick1’ event (size 1, append). ‘alt+1’: Remove the nearest ‘pick1’ event. ‘ctrl+1’: Save ‘pick1’ events to file. ‘2’: Add a ‘pick2’ event (size 2, append, fill display). ‘alt+2’: Remove the nearest ‘pick2’ event. ‘ctrl+2’: Save ‘pick2’ events to file. ‘3’: Add a ‘pick3’ event (size 3, overwrite). ‘alt+3’: Remove the nearest ‘pick3’ event. ‘ctrl+3’: Save ‘pick3’ events to file.

update(event: Any | None = None) None

The update method is often one that needs to be specified when extending a class.

class datanavigator.ButtonDemo(*args: Any, **kwargs: Any)

Demonstrates creating and using custom buttons within a Matplotlib figure.

This class creates a figure and adds two buttons using the datanavigator.core.Buttons manager: - A ‘Toggle’ button. - A ‘Push’ button that triggers a callback function (test_callback) when clicked.

test_callback(event: Any | None = None) None

Callback function executed when the ‘push button’ is clicked.

Prints the triggering mouse event to the console.

Parameters:

event (Optional[Any], optional) – The matplotlib event object associated with the button click. Defaults to None.

set(*, agg_filter=<UNSET>, alpha=<UNSET>, animated=<UNSET>, canvas=<UNSET>, clip_box=<UNSET>, clip_on=<UNSET>, clip_path=<UNSET>, constrained_layout=<UNSET>, constrained_layout_pads=<UNSET>, dpi=<UNSET>, edgecolor=<UNSET>, facecolor=<UNSET>, figheight=<UNSET>, figwidth=<UNSET>, frameon=<UNSET>, gid=<UNSET>, in_layout=<UNSET>, label=<UNSET>, layout_engine=<UNSET>, linewidth=<UNSET>, mouseover=<UNSET>, path_effects=<UNSET>, picker=<UNSET>, rasterized=<UNSET>, size_inches=<UNSET>, sketch_params=<UNSET>, snap=<UNSET>, tight_layout=<UNSET>, transform=<UNSET>, url=<UNSET>, visible=<UNSET>, zorder=<UNSET>)

Set multiple properties at once.

Supported properties are

Properties:

agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array and two offsets from the bottom left corner of the image alpha: float or None animated: bool canvas: FigureCanvas clip_box: ~matplotlib.transforms.BboxBase or None clip_on: bool clip_path: Patch or (Path, Transform) or None constrained_layout: unknown constrained_layout_pads: unknown dpi: float edgecolor: :mpltype:`color` facecolor: :mpltype:`color` figheight: float figure: unknown figwidth: float frameon: bool gid: str in_layout: bool label: object layout_engine: {‘constrained’, ‘compressed’, ‘tight’, ‘none’, .LayoutEngine, None} linewidth: number mouseover: bool path_effects: list of .AbstractPathEffect picker: None or bool or float or callable rasterized: bool size_inches: (float, float) or float sketch_params: (scale: float, length: float, randomness: float) snap: bool or None tight_layout: unknown transform: ~matplotlib.transforms.Transform url: str visible: bool zorder: float

class datanavigator.SelectorDemo

Demonstrates using the Matplotlib LassoSelector widget to select data points.

Creates a scatter plot and adds buttons to start and stop the lasso selection mode. Selected points are highlighted, and selections can be toggled (selecting an already selected point unselects it).

get_points() ndarray

Returns the data points currently plotted on the axes.

Used by the LassoSelector to determine which points are inside the lasso path.

Returns:

A 2D array where each row is (t, x) coordinate of a point.

Return type:

np.ndarray

onselect(verts: list) None

Callback function executed when a lasso selection is completed.

Determines which points fall within the lasso path defined by verts. Updates the set of selected indices (self.ind), toggling the selection state for points within the lasso. Refreshes the plot to show the currently selected points.

Parameters:

verts (list) – A list of (x, y) tuples defining the vertices of the lasso path in display coordinates.

start(event: Any | None = None) None

Activates the LassoSelector widget.

Connected as the callback for the ‘Start selection’ button.

Parameters:

event (Optional[Any], optional) – The event triggering the start. Defaults to None.

stop(event: Any | None = None) None

Deactivates the LassoSelector widget.

Connected as the callback for the ‘Stop selection’ button.

Parameters:

event (Optional[Any], optional) – The event triggering the stop. Defaults to None.

datanavigator.get_cache_folder() str

Get the current path of the cache folder.

datanavigator.get_clip_folder() str

Get the current path of the clip folder.

datanavigator.set_cache_folder(folder: str) None

Set the path for the cache folder.

datanavigator.set_clip_folder(folder: str) None

Set the path for storing video clips.

The default on Windows is C:\data\_clipcollection; on macOS / Linux it is ~/datanavigator/_clipcollection. Either can be overridden via the CLIP_FOLDER environment variable at import time, or via this setter at runtime.

Browsers

This module defines the core class called GenericBrowser. It defines basic functionalities for browsing data, such as navigating using arrow keys, storing positions in memory (e.g. video frame numbers), adding buttons, and assigning hotkeys to custom functions. This class can be extended to create interactive browsers for various types of data, including plots, signals, and videos.

class datanavigator.core.KeyBinding(callback: Callable, description: str, group: str | None = None, on_button: bool = False)

One entry in GenericBrowser._keypressdict.

group drives the section header in GenericBrowser.show_key_bindings() (None falls into the “Other” section, rendered last). on_button opts the binding into button-face hint rendering: the cheatsheet dialog and a matching button get the shortcut shown alongside the action.

Pre-rc2 this slot was a (callback, description) tuple; the dataclass is a hard cut — no tuple-style backward compat. Downstream callers that poke _keypressdict directly (rare) need to migrate to attribute access.

callback: Callable
description: str
group: str | None = None
on_button: bool = False
class datanavigator.core.GenericBrowser(figure_handle: Figure = None)

Generic class that defines base functionality. Meant to be extended before use.

Features:
  • Navigate using arrow keys.

  • Store positions in memory using number keys (e.g. for flipping between positions when browsing a video).

  • Quickly add toggle and push buttons.

  • Design custom functions and assign hotkeys to them (add_key_binding).

Default Navigation (arrow keys):
  • ctrl+k - show all keybindings

  • right - forward one frame

  • left - back one frame

  • up - forward 10 frames

  • down - back 10 frames

  • shift+left - first frame

  • shift+right - last frame

  • shift+up - forward nframes/20 frames

  • shift+down - back nframes/20 frames

update_assets()

Update the display of various assets.

update(event=None)

Update the browser. Extended classes are expected to implement their update function.

Parameters:

event (optional) – Event that triggered the update. Defaults to None.

update_without_clear(event=None)

Update the browser without clearing the axis.

Parameters:

event (optional) – Event that triggered the update. Defaults to None.

add_item_dropdown(names: list[str] | None = None, var_name: str = 'item') StateVariable

Add a sidebar dropdown to jump straight to a browsed item by name.

Generic across browsers: the dropdown is two-way bound to _current_idx. Picking an entry moves the browse index and redraws; arrow-key navigation keeps the dropdown in step (see _sync_item_dropdown(), invoked from update_assets()). Built on the StateVariable(widget="dropdown") machinery – a QComboBox on Qt, read-only text fallback on non-Qt backends.

Suited to browsing tens-to-hundreds of named items (signals, plot items); not to scrubbing thousands of video frames, which is why the video browsers leave it off.

Idempotent: re-calling with the same var_name replaces the existing dropdown (e.g. to relabel once the items are known).

Parameters:
  • names – one label per browsed item. None -> _default_item_names(). Length must match len(self).

  • var_name – the state-variable name (the dropdown’s row label).

Returns:

The registered StateVariable.

mpl_remove_bindings(key_list: list[str])

Remove existing key bindings in matplotlib.

Parameters:

key_list (list[str]) – List of keys to remove bindings for.

cleanup()

Perform cleanup, for example, when the figure is closed.

mpl_restore_bindings()

Restore any modified default keybindings in matplotlib.

reset_axes(axis: str = 'both', event=None, axes=None)

Reframe data within matplotlib axes.

Parameters:
  • axis (str, optional) – Axis to reset. Defaults to “both”.

  • event (optional) – Event that triggered the reset. Defaults to None.

  • axes (Iterable[Axes] | None, optional) – Restrict the walk to this subset of axes. None (default) walks self.figure.axes — the historical behaviour. Cursor-aware dispatch in VideoPointAnnotator._reset_view_all passes a 2-element list [_ax_trace_x, _ax_trace_y] to scope the refit to the trace pair when the cursor is over one of them.

add_key_binding(key_name: str, on_press_function: callable, description: str = None, *, group: str | None = None, on_button: bool = False)

Add a key binding to the browser.

Parameters:
  • key_name – Key to bind (matplotlib key-event string, e.g. “s”, “ctrl+a”, “shift+left”).

  • on_press_function – Function to call when the key is pressed.

  • description – Human-readable label shown in the cheatsheet. Defaults to on_press_function.__name__.

  • group – Section header in the cheatsheet dialog. None falls into the “Other” section (rendered last).

  • on_button – When True, find a button whose action_func is identically on_press_function and append "  ({key_name})" to its label. The match is by is comparison — pass the same callable object to both Buttons.add() and this method (no intermediate lambdas) or the hint won’t attach. Resolution is symmetric: if the button is added after the binding, Buttons.add() performs the same scan.

remove_key_binding(key_name: str)

Remove a key binding from the browser.

Parameters:

key_name (str) – Key to remove the binding for.

set_default_keybindings()

Set default key bindings for navigation.

increment(step: int = 1)

Increment the current index.

Parameters:

step (int, optional) – Number of steps to increment. Defaults to 1.

decrement(step: int = 1)

Decrement the current index.

Parameters:

step (int, optional) – Number of steps to decrement. Defaults to 1.

go_to_start()

Go to the start of the data.

go_to_end()

Go to the end of the data.

increment_frac(n_steps: int = 20)

Browse the entire dataset in n_steps. Increment the current index by a fraction of the total length.

Parameters:

n_steps (int, optional) – Number of steps to divide the total length into. Defaults to 20.

decrement_frac(n_steps: int = 20)

Decrement the current index by a fraction of the total length.

Parameters:

n_steps (int, optional) – Number of steps to divide the total length into. Defaults to 20.

copy_to_clipboard()

Copy the current figure window to the clipboard.

On a Qt backend, grabs the entire QMainWindow – the matplotlib canvas plus every Qt-side widget parented to it (left-column dock with buttons / statevariables, fast_render image pane, downstream sidebars added by consumers such as DUSTrack). The pre-rc2 path savefig’d the figure alone and missed all of them; on a DUSTrack window the clipboard image would show the trace canvas with nothing where the sidebar / image pane visually sat.

On non-Qt backends (Agg, headless), falls back to copying just the matplotlib figure via savefig.

Requires a Qt binding (PyQt5 / PyQt6 / PySide2 / PySide6); imported lazily via qtpy so installs without Qt still get the rest of the package. pip install datanavigator[qt] pulls PyQt6.

show_key_bindings()

Open the keyboard-shortcut cheatsheet.

On a Qt-backed figure: a modeless QDialog with one section per KeyBinding.group (insertion order; None group rendered last as “Other”). Each section is a 2-column table — monospace shortcut on the left, description on the right.

On non-Qt backends: prints the same content to stdout. The pre-rc2 TextView overlay is gone; matplotlib doesn’t host a nice cheatsheet without the Qt path.

pan(direction: str = 'left', frac: float = 0.2)

Pan the view.

Parameters:
  • direction (str, optional) – Direction to pan. Defaults to “left”.

  • frac (float, optional) – Fraction of the view to pan. Defaults to 0.2.

has(asset_type: str) bool

Check if the browser has a specific asset type.

Parameters:

asset_type (str) – Type of asset to check for.

Returns:

True if the asset type is present, False otherwise.

Return type:

bool

Module for browsing and visualizing time series data.

Classes:

SignalBrowser: A browser for navigating through an array of pysampled.Data elements or 2D arrays.

class datanavigator.signals.SignalBrowser(plot_data: list[pysampled.core.Data], titlefunc: Callable | None = None, figure_handle: Figure | None = None, reset_on_change: bool = False, signal_names: list[str] | None = None, show_signal_dropdown: bool = True)

Browse an array of pysampled.Data elements, or 2D arrays.

update(event=None)

Update the browser.

Parameters:

event (optional) – Event that triggered the update. Defaults to None.

add_signal_dropdown(names: list[str] | None = None, var_name: str = 'signal') StateVariable

Add the signal-selection dropdown (a thin wrapper).

Delegates to GenericBrowser.add_item_dropdown() with a "signal" row label. names=None derives labels from each entry’s name (falling back to "signal <i>" via _default_item_names()). See add_item_dropdown() for the full contract: idempotent relabeling, Qt vs text rendering, and the two-way _current_idx binding.

Module for browsing and visualizing data using customizable plotting functions.

Classes:

PlotBrowser: A browser for navigating through a list of data objects and visualizing them using custom plotting functions.

class datanavigator.plots.PlotBrowser(plot_data: list, plot_func: tuple[callable, callable] | callable, figure_handle: plt.Figure = None, item_names: list[str] | None = None, show_item_dropdown: bool = True, **plot_kwargs)

Takes a list of data, and a plotting function (or a pair of setup and update functions) that parses each of the elements in the array. Assumes that the plotting function is going to make one figure.

add_selectors()
get_current_data()

Data getter. Plotting data is a list of objects that are being plotted one at a time. This function returns the current object.

update(event: Any = None)

Update the browser.

Module for browsing videos and extracting clips from videos.

Classes:

VideoBrowser: Scroll through the frames of a video, extract clips of interest. VideoPlotBrowser: Browse a video and an array of pysampled.Data side by side.

class datanavigator.videos.VideoBrowser(vid_name: str, titlefunc: ~typing.Callable | None = None, figure_or_ax_handle: ~matplotlib.axes._axes.Axes | ~matplotlib.figure.Figure | None = None, image_process_func: ~typing.Callable = <function VideoBrowser.<lambda>>, fast_render: bool = False)

Scroll through the frames of a video, extract clips of interest.

If figure_handle is an axis handle, the video will be plotted in that axis.

Future Enhancements:
  • Extend VideoBrowser to play, pause, and extract clips using hotkeys.

  • Show timeline in VideoBrowser.

  • Add clickable navigation.

increment_frac(n_steps: int = 100) None

Browse entire dataset in n_steps.

Parameters:

n_steps (int) – Number of steps to increment.

decrement_frac(n_steps: int = 100) None

Browse entire dataset in n_steps.

Parameters:

n_steps (int) – Number of steps to decrement.

update() None

Update the video frame.

extract_clip(start_frame: int | None = None, end_frame: int | None = None, fname_out: str | None = None, out_rate: int | None = None) str

Extract a clip from the video.

Parameters:
  • start_frame (Optional[int]) – Starting frame of the clip.

  • end_frame (Optional[int]) – Ending frame of the clip.

  • fname_out (Optional[str]) – Output filename.

  • out_rate (Optional[int]) – Output frame rate.

Returns:

Path to the extracted clip.

Return type:

str

class datanavigator.videos.VideoPlotBrowser(vid_name: str, signals: Dict[str, Data], titlefunc: Callable | None = None, figure_handle: Figure | None = None, event_win: tuple | None = None)

Browse a video and an array of pysampled.Data side by side.

Parameters:
  • vid_name (str) – Path to the video file.

  • signals (Dict[str, pysampled.Data]) – Dictionary of signals.

  • titlefunc (Optional[Callable]) – Function to generate the title for the plot.

  • figure_handle (Optional[plt.Figure]) – Handle to the figure.

  • event_win (Optional[tuple]) – Event window. Visualize signals around an event. Use this to create “scrolling” plot visualizations, e.g. [-0.5, 1.].

update() None

Update the video frame and signals.

onclick(event) None

Right click mouse to seek to that frame.

Parameters:

event – Matplotlib event.

extract_clip(start_frame: int | None = None, end_frame: int | None = None, sav_dir: str | None = None, out_rate: float = None) str

Save a video of screengrabs.

Parameters:
  • start_frame (Optional[int]) – Starting frame of the clip. Defaults to the first memory slot.

  • end_frame (Optional[int]) – Ending frame of the clip. Defaults to the second memory slot.

  • sav_dir (Optional[str]) – Directory to save the clip. If not provided, a timestamped directory is created.

Returns:

Path to the saved video file.

This module is for visualizing and interacting with time series data that can be analyzed using dimesionality reduction techniques such as PCA. It was originally developed to visualize and classify periodic motion data during running.

class datanavigator.components.ComponentBrowser(data: ndarray, data_transform: ndarray, labels: ndarray | None = None, figure_handle: Figure | None = None, class_names: dict[int, str] | None = None, desired_class_names: dict[int, str] | None = None, annotation_names: dict[int, str] | None = None)
property n_signals: int

Return the number of signals.

property n_timepts: int

Return the number of time points.

property colors: list[tuple]

Return the colors for each class.

property signal: Data

Return the 2D Numpy array as a signal.

select_signal_piece_dblclick(event: Any) None

Double click a signal piece in the timecourse view to highlight that point.

Parameters:

event (Any) – The mouse event.

onpick(event: Any) None

Single click a projected point.

Parameters:

event (Any) – The pick event.

update() None

Update the plot with the current data index.

update_class_info_text(draw: bool = True) None

Update the class info text.

Parameters:

draw (bool) – Whether to draw the plot after updating.

update_desired_class_info_text(draw: bool = True) None

Update the desired class info text.

Parameters:

draw (bool) – Whether to draw the plot after updating.

update_mode_text(draw: bool = True) None

Update the mode text.

Parameters:

draw (bool) – Whether to draw the plot after updating.

update_message_text(text: str, draw: bool = True) None

Update the message text.

Parameters:
  • text (str) – The message text.

  • draw (bool) – Whether to draw the plot after updating.

toggle_mode(event: Any | None = None) None

Toggle between correction and annotation modes.

Parameters:

event (Any | None) – The key event.

update_colors(data_idx: list[int] | None = None, draw: bool = True) None

Update the colors of the plot.

Parameters:
  • data_idx (list[int] | None) – list of data indices to update.

  • draw (bool) – Whether to draw the plot after updating.

update_all() None

Update all components of the plot.

clear_axes(event: Any | None = None) None

Clear the axes.

Parameters:

event (Any | None) – The key event.

classlabels_to_dict() dict[int, dict[str, int | str | list[str]]]

Convert class labels to a dictionary.

Returns:

Dictionary of class labels.

Return type:

dict[int, dict[str, int | str | list[str]]]

set_classlabels(classlabels_dict: dict[int, dict[str, int | str | list[str]]]) None

Set class labels from a dictionary.

Parameters:

classlabels_dict (dict[int, dict[str, int | str | list[str]]]) – Dictionary of class labels.

class datanavigator.components.ClassLabel(label: int, name: str | None = None, assignment_type: str = 'auto', annotations: list[str] | None = None, original_label: int | None = None)
property color: tuple

Return the color of the class.

property label: int

Return the class label.

is_auto() bool

Return whether the class label was assigned automatically.

Returns:

True if the class label was assigned automatically, False otherwise.

Return type:

bool

is_manual() bool

Return whether the class label was assigned manually.

Returns:

True if the class label was assigned manually, False otherwise.

Return type:

bool

set_auto() None

Set the class label assignment type to automatic.

set_manual() None

Set the class label assignment type to manual.

add_annotation(annot: str) None

Add an annotation to the class instance.

Parameters:

annot (str) – The annotation to add.

Assets

Assets that power the functionality of the GenericBrowser class.

This module provides classes and functions for managing various assets such as buttons, selectors, and state variables in a graphical user interface.

Classes:

Button - Add a ‘name’ state to a matplotlib widget button. StateButton - Store a number/coordinate in a button. ToggleButton - Add a toggle button to a matplotlib figure. Selector - Select points in a plot using the lasso selection widget. StateVariable - Manage state variables with multiple states.

AssetContainer - Container for managing assets such as buttons, memory slots, etc.

Buttons - Manager for buttons in a matplotlib figure or GUI. Selectors - Manager for selector objects for picking points on line2D objects. MemorySlots - Manager for memory slots to store and navigate positions. StateVariables - Manager for state variables.

datanavigator.assets.apply_shortcut_hint(button, key_name: str) None

Append "  (key_name)" to button’s visible label.

Used by the keybinding cheatsheet wiring: when a binding declared on_button=True matches a button (by action_func identity), we want the shortcut visible on the button face. Handles both backends:

  • mpl Button / ToggleButton carry a matplotlib.text.Text label at .label. Toggle buttons rebuild the label every state flip via set_text(); we patch .name so the suffix survives across toggles.

  • The Qt-path _QtPushButton / _QtToggleButton wrappers (in _qt) expose .name + ._qt_btn; we mutate .name and call setText (push) or set_text() (toggle, which rebuilds from name).

Idempotent on the same key_name: if the suffix is already present, returns without re-appending.

class datanavigator.assets.Button(ax, name: str, **kwargs)

Add a ‘name’ state to a matplotlib widget button.

class datanavigator.assets.StateButton(ax, name: str, start_state: Any, **kwargs)

Store a number/coordinate in a button.

class datanavigator.assets.ToggleButton(ax, name: str, start_state: bool = True, **kwargs)

Add a toggle button to a matplotlib figure.

For example usage, see PlotBrowser.

set_text() None

Set the text of the toggle button.

toggle(event=None) None

Toggle the state of the button.

set_state(state: bool) None

Set the state of the button.

class datanavigator.assets.Selector(plot_handle: Line2D)

Select points in a plot using the lasso selection widget.

Indices of selected points are stored in self.sel.

Example

f, ax = plt.subplots(1, 1) ph, = ax.plot(np.random.rand(20)) plt.show(block=False) ls = gui.Lasso(ph) ls.start() – play around with selecting points – ls.stop() -> disconnects the events

get_data() ndarray

Get the data points of the plot.

onselect(verts: List[tuple]) None

Select if not previously selected; Unselect if previously selected.

start(event=None) None

Start the lasso selection.

stop(event=None) None

Stop the lasso selection.

toggle(event=None) None

Toggle the lasso selection.

class datanavigator.assets.AssetContainer(parent: Any)

Container for assets such as a button, memoryslot, etc.

Parameters:

parent (Any) – matplotlib figure, or something that has a ‘figure’ attribute that is a figure.

property names: List[str]
add(asset: Any) Any

Add an asset to the container.

remove(name: str) Any

Remove and return the asset with this name.

Counterpart to add(); raises KeyError if no asset in the container carries that name. The caller is responsible for tearing down any plot handles / Qt widgets the asset owns – AssetContainer only manages the membership list.

class datanavigator.assets.Buttons(parent: Any)

Manager for buttons in a matplotlib figure or GUI (see GenericBrowser for example).

Phase 3 of the 1.4.0 Qt refactor (soft mode): when the parent’s figure is on a Qt canvas AND no explicit pos is given, add() builds a native QPushButton in a QVBoxLayout column hosted by a QDockWidget on the QMainWindow’s LeftDockWidgetArea (pre-rc2: QToolBar; see _qt._get_buttons_widget()). On every other backend, or when an explicit pos is given, the original matplotlib-widgets path runs unchanged. The returned object exposes the same public surface either way (name, on_clicked, plus toggle-specific state / toggle / set_text / set_state).

Lifecycle gotcha: Buttons.add() reads the figure’s canvas at call time. If a Figure subclass adds buttons inside its own __init__ (as in datanavigator.examples.ButtonDemo), this runs before matplotlib attaches a Qt canvas to the figure, so those buttons end up on the mpl path even under QtAgg. The buttons still function; they just miss the Phase 3 perf win. Browsers that take a figure_handle (the common case) are unaffected, because the figure is fully constructed before any button is added.

rc2 row-cursor note: _mpl_row_cursor tracks the next vertical slot for the mpl-fallback layout independent of len(self). add() and add_separator() used to derive y from len(self), which assumed one button per row. add_multi() (one row, N buttons) breaks that assumption, so the cursor is bumped by 1 per row (regardless of how many buttons land on it) while len(self) still grows by N. For single-add-only flows the two stay equal, preserving pre-rc2 placement.

add(text: str = 'Button', action_func: Callable | List[Callable] | None = None, pos: tuple | None = None, w: float = 0.25, h: float = 0.05, buf: float = 0.01, type_: str = 'Push', style_tag: str | None = None, **kwargs) Button

Add a button to the parent figure / object.

If pos is provided, then w, h, and buf will be ignored.

register_style(name: str, styler: Callable[[Any], None]) None

Register a per-button styler under name.

Consumers call this once at setup, then pass style_tag=name to add() / add_multi(). Re-registering an existing name (including a styles built-in) replaces the binding – consumer registrations always win over built-ins.

styler is invoked with the freshly-constructed button as its sole argument at the tail of _finalize_button(). It should detect the Qt path via getattr(b, "_qt_btn", None) and apply QSS / palette manipulation; mpl-path styling is the styler’s choice (the dnav built-ins no-op there).

reapply_styles() None

Re-run the styler for every already-added button.

Useful after register_style() changes a binding (e.g. a theme swap re-registers "primary" with a dark-mode palette and the existing buttons need to repaint).

add_multi(*specs: dict) List[Any]

Add N buttons side-by-side in a single row.

Each spec is a dict of kwargs accepted by add() – typically {text=..., action_func=..., type_=...}. Returns the list of created button objects in spec order.

On the Qt path, all N buttons are children of a single QWidget with a QHBoxLayout inserted into the buttons column’s QVBoxLayout; the row therefore consumes one vertical slot in the sidebar regardless of N. On the mpl fallback path, the row’s width is divided evenly across N buttons at a shared y, and _mpl_row_cursor is bumped by 1 (not N) so a following add() lands on the next row, not N rows down.

Edge cases: - add_multi() with no specs is a no-op and returns []. - add_multi(one_spec) is equivalent to add(**one_spec)

full-width single button – and returns a one-element list.

  • Per-spec pos= is rejected (row layout is the whole point; explicit pos is a single-button-only escape hatch).

add_separator(name: str | None = None, style: str = 'single') None

Add a visual group boundary between buttons.

On the Qt path (figure on a Qt canvas), inserts a sunken QFrame.HLine into the buttons-column QVBoxLayout – a thin line marking a group boundary. style="double" inserts two stacked HLines for a stronger section break, used by DUSTrack to mark major button groups in its rc2 sidebar. On the mpl path, inserts one (or two, for style="double") invisible buttons that occupy layout slots so subsequent buttons are pushed down. (Pre-rc2 the Qt-path inserted a QToolBar.addSeparator() QAction; single-HLine only.)

Promoted to a first-class API for downstream consumers (DUSTrack) that previously hand-rolled invisible spacers by mutating matplotlib.widgets.Button internals (.ax, .label, .ax.patch) – internals that don’t exist on the Qt path.

Parameters:
  • name – Internal name for the mpl-path spacer slot; auto-generated if None. Ignored on the Qt path.

  • style"single" (default) or "double". See above.

class datanavigator.assets.Selectors(parent: Any)

Manager for selector objects - for picking points on line2D objects.

add(plot_handle: Line2D) Selector

Add a selector to the container.

class datanavigator.assets.MemorySlots(parent: Any)

Manager for memory slots to store and navigate positions.

static initialize() dict

Initialize memory slots.

disable() None

Disable memory slots.

enable() None

Enable memory slots.

show(pos: str = 'bottom left') None

Show memory slot text.

update(key: str) None

Handle memory slot updates.

Initiate when None, go to the slot if it exists, free slot if pressed when it exists. key is the event.key triggered by a callback.

update_display() None

Refresh memory slot text if it is not hidden.

hide() None

Hide the memory slot text.

is_enabled() bool

Check if memory slots are enabled.

class datanavigator.assets.StateVariable(name: str, states: list, widget: str = 'label')

Manage state variables with multiple states.

The widget hint is metadata read by the rc2 Qt sidebar to choose a control surface for this state variable: "label" (read-only text line; default), "dropdown" (QComboBox), or "toggle" (mutually-exclusive row of checkable QToolButtons). On non-Qt backends the hint is ignored and the value renders as plain text via the legacy TextView path.

property current_state: Any

Get the current state.

n_states() int

Get the number of states.

add_on_change(callback: Callable[[], None]) None

Register a no-arg callback fired after state mutations.

Fires on every set_state() / cycle() / cycle_back() call, regardless of whether the index actually changed – consumers that need a real-change guard should track the previous value themselves (e.g. VideoPointAnnotator._on_active_label_change()).

cycle() None

Cycle to the next state.

cycle_back() None

Cycle to the previous state.

set_state(state: int | str) None

Set the state.

class datanavigator.assets.StateVariables(parent: Any)

Manager for state variables.

asdict() dict

Return state variables as a dictionary.

add(name: str, states: list, widget: str = 'label') StateVariable

Add a state variable to the container.

Parameters:
  • name – identifier; must be unique within the container.

  • states – the rotation of values this variable can take.

  • widget – rc2 Qt-sidebar control surface hint – one of "label" (read-only text; default; matches pre-rc2 behavior), "dropdown" (QComboBox), or "toggle" (mutually-exclusive QToolButton row). Ignored on non-Qt backends.

show(pos: str = 'bottom right', fax=None) None

Show state variables.

rc2: tries the interactive Qt widget first (dropdowns / toggles / labels per each StateVariable’s widget hint), mounted in the QDockWidget column beneath the buttons. Falls back to the pre-rc2 utils.TextView path on non-Qt backends or if no Qt window is found. The pos / fax arguments are only consulted on the TextView fallback; on the Qt path they’re ignored (the widget’s position is dock-managed).

update_display(draw: bool = True) None

Update the display of state variables.

This module provides classes and functions for managing events and event data.

Classes:

EventData - Manage the data from one event type in one trial. Event - Manage selection of a sequence of events. Events - Manager for event objects.

class datanavigator.events.EventData(default: list | None = None, added: list | None = None, removed: list | None = None, tags: list | None = None, algorithm_name: str = '', params: dict | None = None)

Manage the data from one event type in one trial.

Variables:
  • default (list) – Default events created by an algorithm.

  • added (list) – Manually added events. Note that if an ‘added’ point is removed, then it will simply be deleted. There will be no record of it.

  • removed (list) – Events removed from the default list.

  • tags (list) – Tags associated with the events.

  • algorithm_name (str) – Name of the algorithm used to generate the default list.

  • params (dict) – Parameters used to generate the default list.

asdict() dict

Convert the event data to a dictionary.

get_size() int

Return the size of the envent, for example, 2 for start and stop events.

get_times() list

Get the times of all events.

to_portions() _PNInterval

Convert the event times to portions.

overlap_duration(other: 'portion.Interval' | tuple) float

Calculate the duration of overlap with another interval.

class datanavigator.events.Event(name: str, size: int, fname: str, data_id_func: ~typing.Callable | None = <function Event.<lambda>>, color: str | int = 'random', pick_action: str = 'overwrite', ax_list: list | None = None, win_remove: tuple[float, float] = (-0.1, 0.1), win_add: tuple[float, float] = (-0.25, 0.25), data_func: ~typing.Callable = <class 'float'>, **plot_kwargs)

Manage selection of a sequence of events (of length >= 1).

Variables:
  • name (str) – Name of the event.

  • size (int) – Length of the sequence.

  • fname (str) – File name to load and save events.

  • data_id_func (Callable) – Function to get the current data ID from the parent UI.

  • color (str) – Color of the event. Defaults to a random color.

  • pick_action (str) – Action to take when picking an event (‘overwrite’ or ‘append’). Use overwrite if there can only be one sequence per ‘signal’. If there can be multiple, use ‘append’. Defaults to overwrite

  • ax_list (list) – list of axes on which to show the event.

  • win_remove (tuple) – Window relative to the mouse position to search for removing an event. Defaults to (-0.1, 0.1).

  • win_add (tuple) – Window relative to the mouse position to search for adding an event. Defaults to (-0.25, 0.25).

  • data_func (Callable) – Function to process the data.

  • plot_kwargs (dict) – Keyword arguments for plotting. Commonly used keys are ‘display_type’ (line or fill) and ‘alpha’ to set the transparency level.

classmethod from_file(fname: str, **kwargs) Event

Create an empty events file with the given file name (fname) and any parameters. Assigns best-guess defaults.

classmethod from_data(data: dict, name: str = 'Event', fname: str = '', overwrite: bool = False, **kwargs) Event

Create an event file by filling in the ‘default’ events extracted by an algorithm.

Parameters:
  • data (dict) – Data to create the event file.

  • name (str) – Name of the event.

  • fname (str) – File name to save the event.

  • overwrite (bool) – Whether to overwrite the existing file.

  • **kwargs – Additional keyword arguments. tags, algorithm_name, and params will be passed to EventData. All other keyword arguments will be passed to Event.

Returns:

The created Event object.

Return type:

Event

all_keys_are_tuples() bool

Check if all keys are tuples.

get_header() dict

Get the header information of the event.

load() tuple[dict, dict]

Load the event data from the file.

save() None

Save the event data to the file.

add(event: Any) None

Pick the time points of an interval and associate it with a supplied ID. If the first selection is outside the axis, then select the first available time point. If the last selection is outside the axis, then select the last available time point. If the selections are not monotonically increasing, then empty the buffer. If any of the ‘middle’ picks (i.e. not first or last in the sequence) are outside the axes, then empty the buffer.

The parent UI would invoke this method.

Parameters:

event (Any) – The event to add.

remove(event: Any) None

Remove an event.

Parameters:

event (Any) – The event to remove.

get_current_event_times() list

Get the current event times.

setup_display() None

Setup event display on one or more axes.

update_display(draw: bool = True) None

Update the event display.

to_dict() dict

Convert the event data to a dictionary.

to_portions() dict

Convert the event data to portions.

class datanavigator.events.Events(parent: Any)

Manager for Event objects.

add(name: str, size: int, fname: str, data_id_func: ~typing.Callable, color: str | int, pick_action: str = 'overwrite', ax_list: list | None = None, win_remove: tuple[float, float] = (-0.1, 0.1), win_add: tuple[float, float] = (-0.25, 0.25), add_key: str | None = None, remove_key: str | None = None, save_key: str | None = None, show: bool = True, data_func: ~typing.Callable = <class 'float'>, **plot_kwargs) Event

Add an event.

Parameters:
  • name (str) – Name of the event.

  • size (int) – Length of the sequence. For example, if this is 2, then the event is a pair of start and end times.

  • fname (str) – File name to save the event.

  • data_id_func (Callable) – Function to get the current data ID from the parent UI.

  • color (str | int) – Color used to display the event

  • pick_action (str, optional) – Action to take when picking an event (‘overwrite’ or ‘append’). Use overwrite if there can only be one sequence per ‘signal’. If there can be multiple, use ‘append’. Defaults to overwrite. Defaults to ‘overwrite’.

  • ax_list (list | None, optional) – list of axes on which to show the event. Defaults to None.

  • win_remove (tuple[float, float], optional) – Window relative to the mouse position to search for removing an event. Defaults to (-0.1, 0.1).

  • win_add (tuple[float, float], optional) – Window relative to the mouse position to search for adding an event. Defaults to (-0.25, 0.25). For future use.

  • add_key (str | None, optional) – Keyboard shortcut for adding the event. Defaults to None.

  • remove_key (str | None, optional) – Keyboard shortcut for removing the event. Defaults to None.

  • save_key (str | None, optional) – Keyboard shortcut for saving the events to a JSON file. Defaults to None.

  • show (bool, optional) – Event visibility. Defaults to True.

  • data_func (Callable, optional) – Function to apply on the incoming event. Intended use is for type casting. Defaults to float.

Returns:

_description_

Return type:

Event

add_from_file(fname: str, data_id_func: ~typing.Callable, ax_list: list | None = None, add_key: str | None = None, remove_key: str | None = None, save_key: str | None = None, show: bool = True, data_func: ~typing.Callable = <class 'float'>, **plot_kwargs) Event

Add events from an existing file. Intended use case - events are created by another algorithm meant to be edited using a browser in the datanavigator.

Parameters:
  • fname (str) – File name to load the events.

  • data_id_func (Callable) – Function to get the current data ID from the parent UI.

  • ax_list (list | None, optional) – list of axes on which to show the event. Defaults to None.

  • add_key (str | None, optional) – Keyboard shortcut for adding the event. Defaults to None.

  • remove_key (str | None, optional) – Keyboard shortcut for removing the event. Defaults to None.

  • save_key (str | None, optional) – Keyboard shortcut for saving the events to a JSON file. Defaults to None.

  • show (bool, optional) – Event visibility. Defaults to True.

  • data_func (Callable, optional) – Function to apply on the incoming event. Intended use is for type casting. Defaults to float.

Returns:

The created Event object.

Return type:

Event

setup_display() None

Setup display for all events.

update_display(draw: bool = True) None

Update display for all events

Utilities

Utility functions and classes for video processing and plotting.

This module provides various utility functions and classes to assist with video processing, plotting, and other miscellaneous tasks.

datanavigator.utils.ticks_from_times(times: List[float], tick_lim: Tuple[float, float]) Tuple[List[float], List[float]]

Generate x, y arrays to supply to plt.plot function to plot a set of x-values (times) as ticks.

Parameters:
  • times (List[float]) – List of time values.

  • tick_lim (Tuple[float, float]) – Limits for the y-axis ticks.

Returns:

x and y arrays for plotting ticks.

Return type:

Tuple[List[float], List[float]]

datanavigator.utils.find_nearest(x, y)

Find the nearest x-values for every value in y.

Parameters:
  • x – Iterable of candidate values.

  • y – Iterable of query values.

Returns:

List with the same length as y, where each element is the value in x closest to the corresponding element of y.

datanavigator.utils.find_nearest_idx_val(array, value)

Index and value of the element in array closest to value.

Parameters:
  • array – Iterable of candidate values.

  • value – Query value.

Returns:

Tuple (idx, val) where idx is the index of the nearest entry in array and val is that entry.

datanavigator.utils.find_nearest_idx(array, value)

Index of the element in array closest to value.

Parameters:
  • array – Iterable of candidate values.

  • value – Query value.

Returns:

Integer index of the nearest entry in array.

datanavigator.utils.find_nearest_val(array, value)

Value in array closest to value.

Parameters:
  • array – Iterable of candidate values.

  • value – Query value.

Returns:

The entry of array closest to value.

class datanavigator.utils.TextView(text: List[str] | dict, fax: None | Figure | Axes = None, pos: str | Tuple[float, float, str, str] = 'bottom left')

Show text array line by line.

Phase 2 of the 1.4.0 Qt refactor (soft mode): when fax resolves to a figure whose canvas is a matplotlib Qt canvas, the text renders as a native QLabel overlay parented to the canvas (self._overlay set, self._text stays None). On every other backend the original Axes.text path runs unchanged (self._overlay is None, self._text is the mpl Text artist).

The public surface (__init__ signature, .text, .update) is identical across both paths.

parse_text(text: List[str] | dict) List[str]

Parse text input into a list of strings.

Parameters:

text (Union[List[str], dict]) – Text input.

Returns:

Parsed text.

Return type:

List[str]

setup() None

Setup for showing the text.

update(new_text: List[str] | dict = None) None

Update the text view with new text.

Parameters:

new_text (Union[List[str], dict], optional) – New text to display. Defaults to None.

datanavigator.utils.get_palette(palette_name: str = 'Set2', n_colors: int = 10) List[Tuple[float, float, float]]

Get a color palette, with fallback if seaborn is not available.

Parameters:
  • palette_name (str, optional) – Name of the palette. Defaults to “Set2”.

  • n_colors (int, optional) – Number of colors. Defaults to 10.

Returns:

List of RGB tuples.

Return type:

List[Tuple[float, float, float]]

datanavigator.utils.is_video(vid_file: str)
class datanavigator.utils.Video(uri: str, ctx=cpu(0), width: int = -1, height: int = -1, num_threads: int = 0, fault_tol: int = -1)

Extended VideoReader class with additional methods.

gray(frame_num: int) ndarray

Convert a frame to grayscale.

Parameters:

frame_num (int) – Frame number to convert.

Returns:

Grayscale frame.

Return type:

np.ndarray

datanavigator.utils.removeprefix(s: str, prefix: str) str

Remove the specified prefix from the string, if present.

Parameters:
  • s (str) – The original string.

  • prefix (str) – The prefix to remove.

Returns:

The string with the prefix removed, if it starts with the prefix.

Return type:

str

datanavigator.utils.removesuffix(s: str, suffix: str) str

Remove the specified suffix from the string, if present.

Parameters:
  • s (str) – The original string.

  • suffix (str) – The suffix to remove.

Returns:

The string with the suffix removed, if it ends with the suffix.

Return type:

str

datanavigator.utils.is_pathname_valid(pathname: str) bool

True if the passed pathname is a valid pathname for the current OS; False otherwise.

datanavigator.utils.is_path_creatable(pathname: str) bool

True if the current user has sufficient permissions to create the passed pathname; False otherwise.

datanavigator.utils.is_path_exists_or_creatable(pathname: str) bool

True if the passed pathname is a valid pathname for the current OS _and_ either currently exists or is hypothetically creatable; False otherwise.

This function is guaranteed to _never_ raise exceptions.

Point tracking + optical flow (relocated)

The point-tracking UI, annotation containers (VideoAnnotation / VideoAnnotations), and Lucas-Kanade helpers (lucas_kanade / lucas_kanade_rstc) relocated to the DUSTrack package in 1.5.0 alongside its DeepLabCut workflow. See dustrack.DUSTrack for the new home.