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

# CubeWidget API


 Bases: `AnyWidget`


Select a plane, line, and point by progressively locking cube axes.


Clicking an axis locks it and reveals a slider for its value. The first locked axis selects a plane, the second selects a line, and the third selects a point. Lock order is exposed so downstream code can preserve the same progressive slicing semantics.



```
from wigglystuff import CubeWidget

import marimo as mo
from wigglystuff import CubeWidget

cube = mo.ui.anywidget(
    CubeWidget(
        x_axis={"name": "Angle", "values": [0, 45, 90]},
        y_axis={"name": "Force", "values": [0, 50, 100]},
        z_axis={"name": "Time", "values": [0, 1, 2]},
    )
)
cube
```


  Source code in `wigglystuff/cube_widget.py`

```
def __init__(
    self,
    x_axis: dict[str, Any] | None = None,
    y_axis: dict[str, Any] | None = None,
    z_axis: dict[str, Any] | None = None,
    **kwargs: Any,
) -> None:
    supplied_axis_values = kwargs.pop("axis_values", None)
    self._initializing_axes = True
    try:
        super().__init__(
            x_axis=_axis_default("X") if x_axis is None else x_axis,
            y_axis=_axis_default("Y") if y_axis is None else y_axis,
            z_axis=_axis_default("Z") if z_axis is None else z_axis,
            **kwargs,
        )
    finally:
        self._initializing_axes = False

    initial_axis_values = {
        axis_key: _axis_midpoint(self._get_axis_config(axis_key))
        for axis_key in _AXIS_KEYS
    }
    if supplied_axis_values is not None:
        if not isinstance(supplied_axis_values, dict):
            raise ValueError("axis_values must be a dictionary.")
        initial_axis_values.update(supplied_axis_values)
    self.axis_values = initial_axis_values

    self.observe(
        self._update_outputs,
        names=[
            "locked_order",
            "axis_values",
            "x_axis",
            "y_axis",
            "z_axis",
        ],
    )
    self._update_outputs()
```


## lock_axis


```
lock_axis(axis_key: str, value: Real | None = None) -> None
```


Lock an axis, optionally assigning its current value.

 Source code in `wigglystuff/cube_widget.py`

```
def lock_axis(self, axis_key: str, value: Real | None = None) -> None:
    """Lock an axis, optionally assigning its current value."""
    self._require_axis_key(axis_key)
    if value is not None:
        if not _is_finite_number(value):
            raise ValueError("value must be a finite number.")
        config = self._get_axis_config(axis_key)
        low = min(config["values"])
        high = max(config["values"])
        if not _value_in_axis_range(value, config):
            raise ValueError(
                f"value must be within the {config['name']} axis range "
                f"[{low}, {high}]."
            )
    if axis_key not in self.locked_order:
        self.locked_order = [*self.locked_order, axis_key]
    if value is not None:
        self.axis_values = {**self.axis_values, axis_key: value}
```


## reset


```
reset() -> None
```


Return to the volume view by unlocking every axis.

 Source code in `wigglystuff/cube_widget.py`

```
def reset(self) -> None:
    """Return to the volume view by unlocking every axis."""
    self.locked_order = []
```


## unlock_axis


```
unlock_axis(axis_key: str) -> None
```


Unlock an axis while preserving the order of the remaining axes.

 Source code in `wigglystuff/cube_widget.py`

```
def unlock_axis(self, axis_key: str) -> None:
    """Unlock an axis while preserving the order of the remaining axes."""
    self._require_axis_key(axis_key)
    if axis_key in self.locked_order:
        self.locked_order = [
            key for key in self.locked_order if key != axis_key
        ]
```


## Synced traitlets


| Traitlet | Type | Notes |
| --- | --- | --- |
| `x_axis` | `dict` | X-axis display name and numeric values. |
| `y_axis` | `dict` | Y-axis display name and numeric values. |
| `z_axis` | `dict` | Z-axis display name and numeric values. |
| `locked_order` | `list[str]` | Axis keys in plane → line → point lock order. |
| `axis_values` | `dict[str, float]` | Current value for each axis key. |
| `plane` | `dict \| None` | First locked axis display name and value. |
| `line` | `dict \| None` | Second locked axis display name and value. |
| `point` | `dict \| None` | Third locked axis display name and value. |


## Helpers



- `lock_axis(axis_key, value=None)` locks an axis and optionally sets its value.

- `unlock_axis(axis_key)` removes an axis from the lock order.

- `reset()` clears every lock while preserving the current axis values.
