Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
for more information, see https://pre-commit.ci
|
Not 100% sure, but it might also be fun to play around with |
|
With regards to the name, do we really want to call it |
To me, this naming would suggest I could pass in n-dimensional arrays (well beyond 1D and 2D). |
Maybe in the future? I see the appeal. But historically we've chosen not to implement overrides (e.g., for
I can add a convenience |
|
|
||
| _name: Final[str] = "marimo-matrix" | ||
|
|
||
| def __init__( |
There was a problem hiding this comment.
Would it be overkill to consider using @overload on __init__ for some nice ergnomics/typing behavior? e.g. .value returns np.ndarray when constructed from an ndarray, list[list[Numeric]] when constructed from a list:
_T = TypeVar("_T")
class matrix(UIElement[list[list[Numeric]], _T]):
@overload
def __init__(self: matrix[np.ndarray], value: np.ndarray, ...) -> None: ...
@overload
def __init__(self: matrix[list[list[Numeric]]], value: list[list[Numeric]], ...) -> None: ...
def _convert_value(self, value: list[list[Numeric]]) -> _T:
if self._return_numpy:
return np.asarray(value)
return valueThere was a problem hiding this comment.
It's not overkill on the implementation. But I wonder about the ergonomics. Is it confusing for value's type at runtime to depend on what was passed in?
There was a problem hiding this comment.
If we did support returning NumPy out, then we might also need to support returning as a torch.Tensor, jax.Array, tensorflow.Tensor, since these are all arraylike objects that should work with the matrix constructor. I am mildly worried this may add too much complexity.
There was a problem hiding this comment.
i honestly had the same thought. We'd need some kind of narwhals abstraction which i'm not sure there is for arrays.
this current api seems the most forward thinking.
There was a problem hiding this comment.
See my comment below, there's already an interop standard
| // Local display value – always tracks the latest visual state. | ||
| // When debounce is true we update this locally during drag and only | ||
| // call setValue on pointer-up. | ||
| const [internalValue, setInternalValue] = useState(value); | ||
| useEffect(() => { | ||
| setInternalValue(value); | ||
| }, [value]); |
There was a problem hiding this comment.
nit: useEffect sync causes an extra render. I think we could just read the prop directly when not dragging instead. Not a big deal though.
const [draft, setDraft] = useState(value);
const internalValue = activeCell != null ? draft : value;And then setDraft in various handlers.
for more information, see https://pre-commit.ci
|
@dmadisetti @manzt I've added |
The flex-based layout couldn't right-align numbers within columns because each cell sized to its content independently. Switching to an HTML [`table`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/table) gives automatic column-width equalization, so `text-right` on each `<td>` properly aligns numbers like numpy output. It is also semantically more appropriate here since a matrix is tabular data. Also adds `tabular-nums` for consistent digit widths. | before | after | |-------------|---------| | <img src="https://github.com/user-attachments/assets/99fad98b-8c5e-47e5-98c2-b64cd94d612a" /> | <img src="https://github.com/user-attachments/assets/5f090179-73a8-4388-8d72-484cedd3e295" /> | https://github.com/user-attachments/assets/e08b905e-73a8-4f1e-8f78-f7b7b67b4acd
| args=args, | ||
| on_change=None, | ||
| ) | ||
|
|
There was a problem hiding this comment.
think defining an __array__/__array_interface__ would be ideal (for our own apis as well like mo.image) https://numpy.org/doc/stable/user/basics.interoperability.html#the-array-interface-protocol
There was a problem hiding this comment.
I think the api looks great, mirrors slider which is awesome.
One comment on interop, which I think manzt mentioned as well (https://numpy.org/doc/stable/user/basics.interoperability.html#the-array-interface-protocol)
|
|
||
| _name: Final[str] = "marimo-matrix" | ||
|
|
||
| def __init__( |
There was a problem hiding this comment.
See my comment below, there's already an interop standard
|
@dmadisetti for inter-op, we would still need to hardcode the original value's data type, and hardcode its constructor when returning the matrix via the value attribute, no? That's not hard for numpy, torch, jax, but it feels cumbersome and not very maintainable long term. |
When `mo.ui.vector` changes shape (e.g. toggling `transpose`), the component crashed because `internalValue` state held the old shape while props like `disabled` already had the new shape, causing out-of-bounds access (`disabled[1]` on a 1-row array). Replace the `useEffect`-synced `internalValue` with a simpler `draft`/`displayValue` pattern: use local draft state only during active drag, otherwise read directly from the `value` prop. This avoids the one-render-behind stale-state problem entirely. Ref: #8354 (comment)
When `mo.ui.vector` changes shape (e.g. toggling `transpose`), the component crashed because `internalValue` state held the old shape while props like `disabled` already had the new shape, causing out-of-bounds access (`disabled[1]` on a 1-row array). Replace the `useEffect`-synced `internalValue` with a simpler `draft`/`displayValue` pattern: use local draft state only during active drag, otherwise read directly from the `value` prop. This avoids the one-render-behind stale-state problem entirely. Ref: #8354 (comment)
This PR adds two new public APIs: 1. `mo.ui.matrix()`, which adds a reactive matrix component inspired by @koaning's wigglystuff matrix input 2. `mo.ui.vector()`, which is analogous to `matrix` but for vectors ## Signature remarks * An initial value for the matrix is required. This value can be a Python list of lists, with each list a row of the matrix. It can also be a NumPy array. * Minimum and maximum values can be provided, as well as a step size. These can be scalars or `ArrayLike` objects. * The matrix can be constrained to be symmetric with a keyword argument * The matrix can be disabled, either entirely or on an element wise basis with a boolean array mask. The latter provides a convenient way to constrain a matrix to be (for example) upper triangular, diagonal, or banded. * The precision at which to display the entries is chosen intelligently on the user's behalf, but can be overriden ## Python usage With Python built-in types: ```python mat = mo.ui.matrix([[1, 0], [0, 1]]) ``` ```python matrix.value ``` With NumPy: ```python mat = mo.ui.matrix(np.eye(2)) ``` ```python np.asarray(matrix.value) ``` The value, bounds, step, and disabled arguments can optionally be NumPy arrays, interpreted elementwise. ```python mat = mo.ui.matrix( np.zeros((3, 3)), min_value=np.full((3, 3), -10.0), max_value=np.full((3, 3), 10.0), step=np.full((3, 3), 0.5), ) ``` ## `value` type The element's `value` is a list of scalar (int or float) lists for `matrix`, and a flat list for `vector`. This is readily converted to a NumPy array by the user. ## Implementation `mo.ui.vector` reuses the frontend implementation of `ui.matrix`, promoting its input to a 2D array ## Media <img width="786" height="331" alt="image" src="https://github.com/user-attachments/assets/d66afbd7-9cf3-4f5b-a728-3a25e82b592b" /> https://github.com/user-attachments/assets/c5bf1ff5-3cfc-4cd0-9254-42a5364f4941 --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Trevor Manz <trevor.j.manz@gmail.com>
This PR adds two new public APIs:
mo.ui.matrix(), which adds a reactive matrix component inspired by @koaning's wigglystuff matrix inputmo.ui.vector(), which is analogous tomatrixbut for vectorsSignature remarks
ArrayLikeobjects.Python usage
With Python built-in types:
With NumPy:
The value, bounds, step, and disabled arguments can optionally be NumPy
arrays, interpreted elementwise.
valuetypeThe element's
valueis a list of scalar (int or float) lists formatrix, and a flat list forvector. This is readily converted to a NumPy array by the user.Implementation
mo.ui.vectorreuses the frontend implementation ofui.matrix, promoting its input to a 2D arrayMedia
ui-matrix.mp4