Feeding a clanker? Grab this page as raw `.md` →

# CurveEditor API


 Bases: `AnyWidget`


Chart-space curve editor powered by D3 line interpolators.


Drag knots on an x/y chart and switch among D3's chart-oriented curve factories. Open curves store points in x order so step, monotone, and bump curves behave like normal chart lines instead of freeform paths. Closed curves preserve point order so they can be edited as drawn loops.



```
from wigglystuff import CurveEditor

from wigglystuff import CurveEditor

editor = CurveEditor(curve="catmull_rom", alpha=0.5)
editor
```


Create a CurveEditor widget.


  Source code in `wigglystuff/curve_editor.py`

```
def __init__(
    self,
    points: Iterable[dict[str, Any]] | None = None,
    *,
    curve: str = "natural",
    x_bounds: tuple[float, float] = (0.0, 1.0),
    y_bounds: tuple[float, float] = (0.0, 1.0),
    width: int = 600,
    height: int = 360,
    tension: float = 0.0,
    alpha: float = 0.5,
    closed: bool = False,
    playing: bool = False,
    loop: bool = False,
    t: float = 0.0,
    interval_ms: int = 30,
    duration_ms: int = 12000,
    sync_throttle_ms: int = 250,
    selected_index: int = -1,
    **kwargs: Any,
) -> None:
    """Create a CurveEditor widget.

    Args:
        points: Initial knots as ``{"x": float, "y": float}`` dicts.
            Open curves store points sorted by x-coordinate. Closed curves
            preserve point order.
        curve: D3 curve name. One of ``linear``, ``step``,
            ``step_before``, ``step_after``, ``basis``, ``natural``,
            ``cardinal``, ``catmull_rom``, ``monotone_x``, or ``bump_x``.
        x_bounds: Data-coordinate x bounds.
        y_bounds: Data-coordinate y bounds.
        width: SVG width in pixels.
        height: SVG height in pixels.
        tension: Cardinal spline tension, clamped to ``[0, 1]``.
        alpha: Catmull-Rom alpha, clamped to ``[0, 1]``.
        closed: Whether to append the first point virtually when rendering.
        playing: Whether playback starts immediately.
        loop: Whether playback wraps from ``t=1`` back to ``t=0``.
        t: Initial path progress in ``[0, 1]``.
        interval_ms: Milliseconds between browser playback ticks.
        duration_ms: Milliseconds for one full ``t=0`` to ``t=1`` traversal.
        sync_throttle_ms: Minimum milliseconds between playback updates synced to Python.
        selected_index: Selected point index, or ``-1``.
        **kwargs: Forwarded to ``anywidget.AnyWidget``.
    """
    coerced_points = _coerce_points(points, sort_by_x=not closed)
    initial_t = _clamp01(t)
    initial_x, initial_y = _point_at_t(
        _effective_points(coerced_points, closed), initial_t
    )
    super().__init__(
        closed=closed,
        points=coerced_points,
        x=initial_x,
        y=initial_y,
        t=initial_t,
        curve=curve,
        x_bounds=x_bounds,
        y_bounds=y_bounds,
        width=width,
        height=height,
        tension=tension,
        alpha=alpha,
        playing=playing,
        loop=loop,
        interval_ms=interval_ms,
        duration_ms=duration_ms,
        sync_throttle_ms=sync_throttle_ms,
        selected_index=selected_index,
        **kwargs,
    )
    self.observe(self._refresh_current_point, names=["points", "t", "closed"])
    self.observe(self._sort_points_when_opened, names=["closed"])
```


## current_point


```
current_point() -> tuple[float, float]
```


Return the current path progress point as `(x, y)`.


In Python this is a linear distance approximation through the knots. The browser syncs `x` and `y` from the actual rendered D3 SVG path whenever the widget is displayed.

 Source code in `wigglystuff/curve_editor.py`

```
def current_point(self) -> tuple[float, float]:
    """Return the current path progress point as ``(x, y)``.

    In Python this is a linear distance approximation through the knots.
    The browser syncs ``x`` and ``y`` from the actual rendered D3 SVG path
    whenever the widget is displayed.
    """
    return _point_at_t(_effective_points(self.points, self.closed), self.t)
```


## Synced traitlets


| Traitlet | Type | Notes |
| --- | --- | --- |
| `points` | `list[dict]` | Chart knots as `{"x": float, "y": float}` in data coordinates. Open curves store points sorted by x-coordinate; closed curves preserve drawing order. |
| `x` | `float` | Current rendered path x-coordinate at `t`. |
| `y` | `float` | Current rendered path y-coordinate at `t`. |
| `t` | `float` | Path progress, clamped to `[0, 1]`. |
| `curve` | `str` | One of `linear`, `step`, `step_before`, `step_after`, `basis`, `natural`, `cardinal`, `catmull_rom`, `monotone_x`, or `bump_x`. |
| `tension` | `float` | Cardinal curve tension, clamped to `[0, 1]`. |
| `alpha` | `float` | Catmull-Rom alpha, clamped to `[0, 1]`. |
| `closed` | `bool` | Whether to virtually append the first point so the path returns to the start. |
| `playing` | `bool` | Whether playback is currently advancing `t`. |
| `loop` | `bool` | Whether playback wraps from `t=1` to `t=0`. |
| `interval_ms` | `int` | Milliseconds between browser playback ticks. |
| `duration_ms` | `int` | Milliseconds for one full `t=0` to `t=1` traversal. |
| `sync_throttle_ms` | `int` | Minimum milliseconds between playback updates synced to Python. |
| `selected_index` | `int` | Selected point index, or `-1` when no point is selected. |
| `x_bounds` | `tuple[float, float]` | Data-coordinate x bounds. |
| `y_bounds` | `tuple[float, float]` | Data-coordinate y bounds. |
| `width` | `int` | SVG width in pixels. |
| `height` | `int` | SVG height in pixels. |


## Helper methods


| Method | Returns | Description |
| --- | --- | --- |
| `current_point()` | `tuple[float, float]` | Current path progress point. In Python this is a linear knot approximation; the browser syncs from the actual rendered D3 path. |
