wigglystuff

repository·main·Indexed 43 days ago

https://github.com/koaning/wigglystuff

A collection of creative AnyWidgets for Python notebook environments, built on the anywidget framework. It provides interactive UI components across categories including data visualization (e.g., BezierCurve, GraphWidget), UI controls (e.g., ColorPicker, Knob), drawing tools (e.g., Paint, SplineDraw), and specialized utilities like AsyncFlow for asyncio task timelines and ApiDoc for inline Python API documentation. Includes specialized widgets optimized for marimo notebooks.

Tokens
81.6K
Snippets
214
Records
358
Agent score
54%

What's inside wigglystuff

  1. Overview of wigglystuff widget categories

    main

    The wigglystuff library provides a wide range of AnyWidgets categorized by their functional purpose. Developers can choose widgets based on the following interaction patterns:

    • Sliders and scalar inputs: For controlling single or coupled numeric parameters (e.g., Slider2D, Knob, Fader, Matrix, ColorPicker).
    • Curves: For editing or drawing mathematical curves (e.g., BezierCurve, SplineDraw).
    • Charts and plots: For visualizing data using established libraries (e.g., AltairWidget, ObservablePlot, RidgelineChart).
    • Selecting on top of charts: For adding interactive selection layers (box, lasso, or puck) over existing charts (e.g., ChartPuck, ChartSelect).
    • Hierarchies and tables: For exploring structured data (e.g., Treemap, NestedTable, ModuleTreeWidget).
    • Graphs and diagrams: For visualizing relationships and networks (e.g., GraphWidget, WidgetDAG, Neo4jWidget).
    • Drawing surfaces: For freehand or grid-based sketching (e.g., Paint, Excalidraw).
    • 3D: For spatial data visualization (e.g., ThreeWidget).
    • Device and browser input: For capturing hardware or browser-level events (e.g., GamepadWidget, WebcamCapture, WebkitSpeechToTextWidget).
    • Live output and tracing: For real-time feedback and debugging (e.g., ProgressBar, AsyncFlow, LiveEdit).
    • Images: For specialized image interactions (e.g., HoverZoom).
  2. Explore the wigglystuff widget gallery

    main

    The wigglystuff library provides a wide variety of interactive widgets designed for use in notebooks (specifically optimized for marimo). The widget gallery showcases different types of interactive components, ranging from data visualization tools to UI controls.

    Each widget in the gallery typically provides links to:

    • A live, interactive demo on molab where you can edit the notebook directly in your browser.
    • The API reference for that specific widget.
    • The MD (Markdown) documentation for detailed usage.

    Available widget categories include:

    • Data Visualization: BezierCurve, GraphWidget, HeatmapSelect, ParallelCoordinates, RidgelineChart, ScatterWidget, Treemap, ObservablePlot.
    • UI Controls: Slider2D, ColorPicker, SortableList, Knob, Fader, CircularSlider, ProgressBar.
    • Drawing & Editing: Paint, EdgeDraw, GridDraw, SplineDraw, AnnotationWidget.
    • Specialized Utilities: Excalidraw, WebcamCapture, SpeechToText, CopyToClipboard, ManimWeb.
  3. Use the BezierCurve widget

    main

    The BezierCurve widget is an arbitrary-degree Bezier editor that allows you to drag control points to shape a curve. It provides real-time feedback through several synced traitlets:

    • Control Points: Managed via the points traitlet, which accepts a list of dictionaries in the format {"x": float, "y": float}.
    • Sampling: The samples traitlet streams a list of n_samples evenly spaced points along the curve back to Python.
    • Animation/Playback: By setting playing to True, the widget sweeps the parameter t from 0 to 1. You can animate downstream components by watching the x and y traitlets, which represent the current Bezier point coordinates at the current t.
    • Looping: Use loop to determine if playback should wrap from t=1 back to t=0.

    For related tools, see CurveEditor for D3 line interpolators, SplineDraw for fitting splines to points, or Slider2D for single point manipulation.

    # Conceptual usage pattern
    from wigglystuff.bezier_curve import BezierCurve
    
    # Initialize with control points and bounds
    bc = BezierCurve(
        points=[{"x": 0, "y": 0}, {"x": 5, "y": 10}, {"x": 10, "y": 0}],
        x_bounds=(0, 10),
        y_bounds=(0, 10),
        n_samples=50
    )
    
    # bc.samples will now stream 50 points along the curve to Python
    # bc.playing = True will animate the x and y coordinates
  4. Use the RidgelineChart for joy plot visualizations

    main

    The RidgelineChart component visualizes each row of a pandas or polars DataFrame as an overlapping waveform (joy plot). It is ideal for comparing same-shaped series like spectra, distributions, or sensor channels to observe how peaks shift across rows.

    To control the visual density and legibility, you can tune the following parameters:

    • overlap: Controls vertical overlap between rows.
    • peak_scale: Adjusts the multiplier for peak height.
    • fill_opacity: Sets the opacity of the fill beneath each line.

    You can also interact with the chart to identify specific data points; the chart syncs the clicked row back to Python via selected_index and selected_row.

    ::: wigglystuff.ridgeline_chart.RidgelineChart
  5. Use EsmWidget to run inline JavaScript in notebooks

    main

    The EsmWidget serves as an escape hatch for running custom JavaScript ES modules directly within a Jupyter or marimo notebook. You provide a JavaScript module that follows the pattern export default { render }.

    Because the code is loaded as a real ES module in the browser, you can use top-level import statements to pull in libraries from any CDN (such as motion.dev, d3, three.js, or Observable Plot) with a single line of code.

    A key feature of EsmWidget is the data traitlet. This is a JSON-able value that is synced two-way between Python and the browser. When the data value changes in Python, it triggers a change:data event in the browser without re-running the render function. This allows your JavaScript code to perform smooth transitions or tweens toward the new state instead of performing a hard redraw.

    // Example of the required module structure
    export default {
      render: (container, data) => {
        // Your rendering logic here
      }
    }
  6. Understand Pip window constraints and behavior

    main

    The floating window is a separate document with its own window and document context, not a browser tab or iframe. This leads to several important behaviors:

    Browser Support

    • Supported: Chromium 116+ and Firefox 151+.
    • Unsupported: Safari (the button will not be drawn and the widget stays inline).
    • Limitations: A tab is allowed only one Pip window at a time. Opening a second Pip will close the first and restore its inline view. The request must come from a top-level page (it will not work if the notebook is inside an iframe).

    Event Handling

    Events and styles are scoped to the window they occur in:

    • Pointer Events: If a widget relies on listening to the window object to track movement (e.g., for dragging), it will stop working while floating because it is listening to the notebook's window, not the floating window.
    • Self-contained Widgets: Widgets that capture pointer events on their own element (e.g., GridDraw, CurveEditor, BezierCurve, HoverSlider, ThreeWidget) will continue to work while floating.
    • Broken Dragging: Widgets that listen to the window (e.g., Knob, Fader, Matrix, TangleSlider, Slider2D, CircularSlider) will stop responding to drags while floating.
    • Input: Widgets driven by clicks, buttons, or text entry work in both contexts.

    Styling

    • A widget's own stylesheet is automatically mounted into the floating window.
    • Pip explicitly copies the notebook's light/dark mode class to the floating document to keep themes in sync.
    • Warning: The floating window does not inherit the notebook's CSS. If a widget relies on notebook-specific CSS variables or classes (rather than its own internal styles), it will appear unstyled while floating.
  7. How Tangle widgets work

    main

    Tangle widgets allow you to embed interactive controls directly inside prose (markdown strings) rather than placing them next to the text. This follows the 'Tangle' design pattern by Bret Victor, where the sentence itself becomes the interface.

    Key widgets include:

    • TangleSlider: Renders a number that can be dragged left and right.
    • TangleChoice: Cycles through a list of labels in place when clicked.
    • TangleSelect: Functions as an inline dropdown for selecting from a list of options.

    You can interpolate these widgets into markdown strings to create interactive documentation or notebooks in environments like Jupyter or marimo.

  8. Use ParallelCoordinates for interactive data filtering

    main

    The ParallelCoordinates component wraps HiPlot to visualize tabular data as polylines across draggable axes. It is designed for sifting through hyperparameter sweeps or high-dimensional numeric datasets.

    Key Workflow:

    1. Visualize: Each row of data is rendered as a polyline. Use color_by to color lines based on a specific column.
    2. Interact: Brush an axis to select a range of rows. You can also drag axes to reorder them.
    3. Filter: Use keep() to retain only the selected rows or exclude() to remove them. Alternatively, use the UI buttons.
    4. Extract: Retrieve the resulting subset of data using filtered_data, filtered_as_pandas, or filtered_as_polars to use in your Python environment.
  9. How Hint works (Architecture and Geometry)

    main

    The Hint component uses a WidgetDAG pattern to manage layout and drawing:

    1. Layout: The target and the note are laid out as two light-DOM boxes using either mo.hstack (for left/right sides) or mo.vstack (for top/bottom sides).
    2. The Overlay: A contentless _Arc (an anywidget.AnyWidget) is placed in the layout. This widget escapes its own shadow root to draw an SVG arc in a shared coordinate space with the two boxes.
    3. Drawing: The arc is a quadratic bezier curve. For a side="right" configuration, the curve starts near the note and ends at the target's right edge. The arrowhead is drawn as an explicit two-stroke chevron path at the end of the curve.
    4. Responsiveness: The drawing is updated via ResizeObserver and requestAnimationFrame to ensure the arrow stays attached to the widgets during window resizing or layout changes.
  10. Use ModuleTreeWidget to visualize PyTorch nn.Module hierarchies

    main

    The ModuleTreeWidget provides an expandable tree view of a PyTorch nn.Module within Jupyter or other anywidget hosts. It displays submodules along with their parameter counts, per-tensor shapes, and badges indicating whether parameters are trainable, frozen, or buffers. It also includes a density indicator to show weight distribution.

    Note for marimo users: If you are using the marimo editor, you do not need to call this widget explicitly. Returning an nn.Module directly from a cell will automatically render this view, as the functionality is part of marimo core.

    # In plain Jupyter or anywidget hosts:
    from wigglystuff.module_tree import ModuleTreeWidget
    
    # Assuming 'model' is your torch.nn.Module
    ModuleTreeWidget(tree=model_tree_dict)
  11. How LiveEdit handles function arguments

    main

    When using LiveEdit, arguments (args and kwargs) are stored as plain Python objects on the Python side and are never synced to the browser. Only their repr() strings are sent across the wire to the frontend.

    Why this matters:

    • Non-serializable types: This allows you to pass complex, non-JSON-serializable objects like numpy arrays or pandas DataFrames without error.
    • Re-execution: Because the original Python objects are preserved on the server, the widget can re-run the function (e.g., if using the editable=True mode in the future) against the exact same data without needing to re-serialize it.