radioviz.geometry.line_selector

Interactive line selector for matplotlib plots.

This module provides functionality to create and manipulate interactive line selectors on matplotlib axes. It allows users to draw lines, edit their endpoints, and snap to specific angles during interaction.

Functions

snap_to_angle(origin, target[, step_deg])

Snap a target point to the nearest angle multiple.

Classes

LineGeometry(start, end)

Represents the geometric properties of an oriented line.

LineSelector(ax, /, *[, color, linewidth, ...])

Interactive selector for an oriented line (arrow).

class radioviz.geometry.line_selector.LineGeometry(start: tuple[float, float], end: tuple[float, float])[source]

Bases: object

Represents the geometric properties of an oriented line.

This dataclass stores the start and end coordinates of a line segment and provides utility methods for vector operations and geometric calculations.

as_vector() ndarray[tuple[Any, ...], dtype[float64]][source]

Convert the line to a vector representation.

Returns:

NumPy array representing the vector from start to end point

Return type:

numpy.ndarray

direction() ndarray[tuple[Any, ...], dtype[Any]][source]

Calculate the normalized direction vector of the line.

Returns:

Normalized direction vector

Return type:

numpy.ndarray

end: tuple[float, float]

End point of the line as (x, y) coordinates.

property mid: tuple[float, float]

Calculate the midpoint of the line.

Returns:

Midpoint coordinates as (x, y)

Return type:

tuple[float, float]

start: tuple[float, float]

Start point of the line as (x, y) coordinates.

class radioviz.geometry.line_selector.LineSelector(ax: Axes, /, *, color: str = 'orange', linewidth: float = 2.0, handle_size: float = 8.0, picker_tol: float = 10.0, snap_deg: float = 30, arrowstyle: str = '-|>, head_width=4, head_length=8')[source]

Bases: QObject

Interactive selector for an oriented line (arrow).

Provides an interactive interface for creating and editing lines on matplotlib axes. Supports snapping to specific angles, visual handles for manipulation, and keyboard shortcuts.

Lifecycle:

idle -> creating -> editing -> cleared

Initialize the LineSelector.

Parameters:
  • ax (matplotlib.axes.Axes) – Matplotlib axes object where the selector will be displayed

  • color (str) – Color of the line and handles (default: ‘orange’)

  • linewidth (float) – Width of the line (default: 2.0)

  • handle_size (float) – Size of the handle markers (default: 8.0)

  • picker_tol (float) – Tolerance for picking handles (default: 10.0)

  • snap_deg (float) – Angle snapping step in degrees (default: 30)

  • arrowstyle (str) – Matplotlib arrow style string (default: '-|>, head_width=4, head_length=8')

_create_artists(geom: LineGeometry) None[source]

Create visual artists for the line and handles.

Parameters:

geom (LineGeometry) – Line geometry to create artists for

_drag_edit(event: MouseEvent) None[source]

Handle dragging during editing mode.

Parameters:

event (matplotlib.backend_bases.MouseEvent) – Mouse motion event data

_make_handle(xy: tuple[float, float], role: str) Line2D[source]

Create a handle marker for the line.

Parameters:
  • xy (tuple[float, float]) – Position coordinates (x, y)

  • role (str) – Role of the handle (‘start’, ‘end’, or ‘mid’)

Returns:

Line2D handle object

Return type:

matplotlib.lines.Line2D

_on_accept() None[source]

Accept the current selection and emit the corresponding signal.

_on_key_press(event: object) None[source]

Handle key press events.

Parameters:

event (matplotlib.backend_bases.KeyEvent) – Key event data

_on_motion(event: object) None[source]

Handle mouse motion events.

Parameters:

event (matplotlib.backend_bases.MouseEvent) – Mouse motion event data

_on_pick(event: object) None[source]

Handle pick events (clicking on handles).

Parameters:

event (matplotlib.backend_bases.PickEvent) – Pick event data

_on_press(event: object) None[source]

Handle mouse press events.

Parameters:

event (matplotlib.backend_bases.MouseEvent) – Mouse event data

_on_release(event: object) None[source]

Handle mouse release events.

Parameters:

event (matplotlib.backend_bases.MouseEvent) – Mouse release event data

_restore_focus() None[source]

Restore focus to the previously focused widget.

_update_artists(geom: LineGeometry) None[source]

Update visual artists with new geometry.

Parameters:

geom (LineGeometry) – Updated line geometry

clear() None[source]

Clear the selector and reset to idle state.

Removes all visual elements and resets internal state.

disconnect_signals() None[source]

Disconnect all event signals and restore focus.

Cleans up event connections and restores previous focus state.

property geometry: LineGeometry | None

Get the current line geometry.

Returns:

Current line geometry or None if not set

Return type:

Optional[LineGeometry]

selector_accepted

Signal emitted when the selector is accepted.

selector_canceled

Signal emitted when the selector is canceled.

selector_created

Signal emitted when a new selector is created.

radioviz.geometry.line_selector.snap_to_angle(origin: tuple[float, float], target: tuple[float, float], step_deg: float = 45.0) tuple[float, float][source]

Snap a target point to the nearest angle multiple.

Snaps the target point to the nearest angle multiple based on the specified step size, keeping the same distance from the origin.

Parameters:
  • origin (tuple[float, float]) – Origin point (x, y) coordinates

  • target (tuple[float, float]) – Target point (x, y) coordinates

  • step_deg (float) – Angle step in degrees (default: 45.0)

Returns:

Snapped point coordinates

Return type:

tuple[float, float]