Skip to content

About

No description, website, or topics provided.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

figgyplot

Plot with NumPy. Edit directly. Reuse the settings in Python.

Python plotting powered by the Rust figgy renderer. Open a native editor, adjust the view and layout, then copy executable Python settings into a script or apply them across a batch of datasets.

Quick start · Edit → copy → reuse · Gallery · Jupyter · Examples · Documentation

Actual native editor: zoom the axes, move an overlapping legend, copy and paste Python, then reuse the layout across three datasets

100,000 samples per series. Edit the native plot, copy Python, paste into VS Code and run the same settings on three independent datasets. Exported Python · Run the demo · Recording details

Gallery

Click a chart to open the Python example that generates it. All data is synthetic; every image is actual native Figgy output. Each example exports a PNG and can open the same chart for interactive editing with --show.

Scientific plots

Signals and references
Damped oscillation and reference envelopes
Populations and markers
Three synthetic scatter populations
Interpolated heatmap
Signed interference field
Logarithmic axes
Power laws on logarithmic X and Y axes
Correlation matrix
Twelve-channel correlation matrix
Spectrogram
NumPy short-time spectrum of a chirp
Parametric curves
Layered parametric traces
Lines and measurements
Model curve and measured markers

Draw styles

Sketch / handwriting
Hand-drawn curves and Comic Neue lettering on warm ivory paper
Constellation
Stars at source samples joined by lines
Milkyway / lines only
Line-only star chains and nebula ribbons

Pies, donuts and procedural materials

Pie
Pie with labeled and exploded slices
Raised ceramic donut
Raised ceramic donut with rounded corners
Procedural materials
Paper · Wood · Hatch · Pearl

Python recipes · Material API
python examples/heatmap_field.py                  # Export output/gallery/heatmap-field.png
python examples/scatter_clusters.py --show        # Edit, then save when the window closes
python examples/donut_chart.py --show             # Edit slices, camera and material
python examples/material_textures.py --material pearl
python scripts/render_gallery.py                 # Reproduce all 17 gallery images

Example index and commands · Rendering provenance. Chart and style API documents every exposed constructor, host coverage, materials and draw modes, including the line-only Milkyway restriction.

What you can do

  • Edit the plot you are looking at. Zoom each axis around the pointer, pan the view, drag the legend or titles, and adjust text, colors, line widths and ranges.
  • Keep the result as code. Copy Python produces familiar calls such as ax.set_title(...) and ax.set_xlim(...), plus readable patches for advanced layout and styling. Save PNG exports the current chart.
  • Reuse a layout across datasets. Apply the exported code to figures with matching series IDs and DPI. Their data stays independent.
  • Work in separate windows or Jupyter. Native figures share a GPU context; Jupyter renders through WASM/WebGPU in the browser.

Install

This checkout documents figgyplot 0.3.0. Before that release is published, PyPI installs the previous release (0.2.1); use the source-checkout instructions below to try the features described here.

Install from PyPI with Python 3.8–3.15:

python -m pip install figgyplot
# Interactive Jupyter editor:
python -m pip install 'figgyplot[notebook]'

A compatible Windows, macOS or Linux wheel needs no Rust compiler and includes the notebook JS/WASM assets. TestPyPI is used to verify upcoming releases; the publishing guide documents that developer workflow.

Alternatively, install from source with Python 3.8–3.15, Rust 1.99+, a system C/C++ toolchain and an available graphics driver:

git clone https://github.com/shim9610/figgy-python.git
cd figgy-python
python -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install .

On Windows, activate with .venv\Scripts\Activate.ps1 and use MSVC C++ Build Tools. On macOS, use Xcode Command Line Tools. Native desktop rendering uses wgpu (Vulkan on Linux, DX12 on Windows, Metal on macOS); Metal support is experimental. The native editor does not require Qt or PySide6.

Linux X11 windows additionally need the system keyboard libraries libxkbcommon0 and libxkbcommon-x11-0 (Debian/Ubuntu package names), plus the window system and GPU driver. Minimal/headless Linux images may omit these libraries even when offscreen rendering works.

The distribution/import name is figgyplot, independent of the unrelated figgy package on PyPI. The repository name remains figgy-python. Platform/Python coverage and release status distinguish configured wheels from executed verification. Wheel CI remains manual only.

Contributions follow the contributing guide and code of conduct. For private vulnerability reports, see the security policy. Repository setup and PR CI rollout describe the prepared security workflows and main-branch check names.

For a source checkout, add notebook support with python -m pip install ".[notebook]". The WASM assets are included in the package; normal installation does not require a WASM build.

Quick start

import numpy as np
import figgyplot as figgy

x = np.linspace(0, 20, 100_000, dtype=np.float32)
fig, ax = figgy.subplots(backend="native", figsize=(8, 5), dpi=120)
ax.plot(x, np.sin(x), color="#2467ad", label="Signal", id="signal")
ax.set_title("Interactive signal", fontsize=18)
ax.set_xlabel("Time (s)")
ax.set_ylabel("Amplitude")
ax.legend()

try:
    fig.show()                  # Edit the chart; close the window to continue.
    fig.savefig("edited.png")  # Saves the edited figure, without the editor UI.
finally:
    fig.close()

A small figgy.pyplot interface is also available. The API is familiar to matplotlib users, but does not implement the full matplotlib API.

Native editor input Action
Ctrl + wheel Zoom X around the pointer
Shift + wheel Zoom Y around the pointer
Wheel Zoom X and Y around the pointer
Drag inside the plot Pan the view
Drag a title or legend Move that element
Click an element Open its properties
Undo / Redo; Ctrl/Cmd + Z / Shift + Z Restore a committed chart edit
Show / hide Toggle titles and legend, including hidden elements
Esc / arrow keys Clear / move the current selection

Layout mode moves or resizes the plot area. The properties panel keeps the chart size and aspect ratio; it overlays the chart in maximized/full-screen windows.

Select Figure in the object tree for named-grid placement, spacing and Reset edits. Reset restores the initially presented document and can itself be undone. Contextual controls and the same Python command API are described in Editor commands and history.

Edit once, reuse across datasets

For an optional multi-Figure agent review workflow, use figgyplot.review.Session and the review controller example. Review comments are separate from chart annotations. Approval checkpoints exact SSOT edits and binary source data before closing the view; the complete next round is published after source execution and rendering validation. The ordinary editor needs no session.

Run the example shown in the GIF:

python examples/edit_and_reuse.py --output output/edit-and-reuse
  1. The automatic upper-right legend covers the late response peak. Use Ctrl/Shift
    • wheel to adjust the axes, widen the left margin in Layout mode, position the Y-axis title and drag the legend into the empty upper-left corner.
  2. Copy Python puts the edited settings on the clipboard. It includes axis ranges, text, visibility, legend position and series styling.
  3. Close the first window. The example saves chart_style.py, applies it to three different datasets, writes three PNGs and opens the resulting figures.

The exported code uses setters for common properties:

ax = fig.axes[0]
ax.set_title("Response / Run 01", fontsize=18)
ax.set_xlabel("Time (s)", fontsize=11)
ax.set_ylabel("Amplitude", fontsize=11)
ax.set_xlim(2.5, 17.5)
ax.set_ylim(0.0, 2.7)
# The complete export also preserves legend placement and advanced styling.

Ranges, ticks and titles:

  • Property-panel edits and fig.update("axis_bottom", major_spacing=2) share changed fields with the opposite axis when the pair had exactly equal min, max, scale and inverted values before the edit. The same rule applies in either direction to bottom/top and left/right, including tick_labels_* edits. For example, fig.update("tick_labels_right", format="Scientific", significant_digits=4) changes only those label fields on a matching left/right pair. Unedited differences in fonts, colors or tick settings remain intact. Axis-line visibility, titles, margins and offsets remain independent. Different coordinate ranges/scales remain independent too; comparison uses exact values without rounding. Use the raw SSOT APIs below for a deliberate one-sided edit.

  • ax.set_xlim(a, b) / set_ylim set the range and derive readable ticks for it. To keep tick spacing you chose explicitly, use ax.set_xlim_without_tick_auto(a, b) / set_ylim_without_tick_auto. These change only the paired axes' SSOT bounds; they do not create a persistent range lock. Plot-creation helpers fit the data again when adding a series, and fig.fit() explicitly fits all axes. Apply manual ranges after adding the series when they should be the final view.

  • fig.fit() and both UI Fit buttons use zero padding for figures containing only heatmaps, contours or filled contours, including combinations. Mixing in lines, scatter or other Cartesian series uses 5%. Explicit padding overrides either default: fig.fit(padding=0.05) adds 5%, while fig.fit(padding=0) fits tightly to the rendered data extent.

  • For selective control, use fig.configure(config={...}) or read the current state with fig.get_settings(), edit only the intended fields, then submit it through fig.apply_settings(state). For example:

    fig.configure(config={"bottom_x": {"min": 20.0, "max": 80.0}})

    This preserves that axis's tick and label settings and leaves the top axis untouched. Include top_x too when the pair should share bounds. In contrast, set_xlim / set_ylim choose ticks and label formatting, fit also derives bounds from data, and title helpers can enlarge the title band. Direct SSOT edits do not run these adjustments. Rendering still validates settings and applies safety limits; visible tick positions and label counts depend on range.

  • A tick setting the renderer cannot draw as written is replaced: a spacing that would draw thousands of ticks falls back to automatic spacing, and minor_count is capped at 99. Each change is reported once as a figgy.RenderWarning by the next native PNG/RGBA render (render_rgba, to_png, savefig, the PNG widget). Desktop windows and the browser (webgpu) backend do not report it.

  • fig.update("chart_title", text="Line 1\nLine 2", align="center") aligns the lines of multi-line text (left, center, right); a title taller than its band grows the band instead of being clipped. Unicode super/subscripts such as 10⁻³ are drawn as super/subscript text.

  • font= must name an installed family or "Liberation Sans" (or "" for the default); an unknown name raises ValueError on the native backend. The browser backend cannot see installed fonts and draws an unknown family with the bundled font. Characters a font lacks are drawn from another available font (natively including installed fonts).

To reuse the saved code yourself, from the repository root:

from pathlib import Path
from examples.edit_and_reuse import make_figure

style_code = Path("output/edit-and-reuse/chart_style.py").read_text()
for run in range(3):
    with make_figure(run) as fig:
        exec(style_code, {"fig": fig})
        fig.axes[0].set_title(f"Response / Run {run + 1:02d}")
        fig.savefig(f"run-{run + 1:02d}.png")

You can also obtain the code directly with edited_fig.to_code(). An export contains settings, not NumPy arrays: recreate the plotted series with the same IDs, kinds and DPI before applying it. Axis ranges and titles are included; override them afterward when a dataset needs different values. Advanced settings use fig.configure(...) with ordinary Python dictionaries.

Multiple windows

Open each figure without blocking, then run the shared event loop:

from figgyplot.desktop import run_events

fig.show(block=False)
fig2.show(block=False)
run_events()

Each window can close independently. Run window creation and event processing on the Python main thread. For an external main-thread loop, call figgy.desktop.poll_events() regularly. See the complete multiple-window example.

Jupyter

python -m pip install jupyterlab ".[notebook]"
jupyter lab examples/interactive.ipynb
import numpy as np
import figgyplot as figgy

fig, ax = figgy.subplots(backend="webgpu")
x = np.linspace(0, 20, 100_000, dtype=np.float32)
ax.plot(x, np.sin(x), id="signal", label="Signal")
ax.set_title("Edit in the browser")
ax.legend()
display(fig)

The browser owns rendering and interaction after the initial data transfer; a GPU in the notebook kernel is not required. WebGPU needs a supported browser and HTTPS or localhost. backend="auto" chooses WebGPU in an IPython kernel and native rendering elsewhere.

Wait for pending browser edits before reading or exporting the Python state:

await fig.sync()
code = fig.to_code()
await fig.savefig_async("edited.png", dpi=240)

Create all series before displaying the widget. Browser export is asynchronous; there is no silent fallback when WebGPU is unavailable. An explicit kernel PNG fallback is available when a native kernel GPU exists. See notebook and host details.

Examples

See the complete example index for gallery recipes, commands and expected outputs.

Example Purpose
edit_and_reuse.py Edit one chart, export Python, apply it to three datasets
desktop_editor.py Open a native editor with an adjusted example layout
multiple_windows.py Edit independent figures in separate windows
quickstart.py Plot and export a PNG
interactive.ipynb Browser WebGPU editing in Jupyter

Scope and performance

The Python API provides line/scatter/errorbar plots, histograms, heatmaps, contours, categorical bars, boxplots, pies and donuts, with multiple series on one Axes, linear/log and inverted axes, picking, editable text/legend/styles, and PNG export. Cartesian plots support Precise, Sketch, Constellation and Milkyway draw modes. Milkyway accepts line-only series; scatter and marker lines are intentionally disabled. Constellation uses marker lines so stars remain at source samples.

Pies/donuts on both native and browser WebGPU hosts expose 11 upstream materials, camera tilt, extrusion, rounded corners, textures and slice editing. Their bounded model contains up to 64 categories and uses the upstream radial renderer on the shared GPU device. All chart families support native desktop and Jupyter WebGPU editing and PNG export. Categorical bars and boxplots use their upstream bounded models; histograms and contours use resident Cartesian columns. Multi-panel figures remain unsupported.

figsize is in inches; fontsize, linewidth and markersize use points. Native Cartesian arrays are uploaded to a resident GPU column pool and reused during edits. Source-array mutations do not change the figure after upload. There is no automatic downsampling or streaming fallback; exceeding a device’s allocation limit raises an error. fig.close() releases a figure’s resources; figgy.release_gpu() releases the shared native context after all figures close.

See the measured Linux / Radeon 8060S results and Windows results, including methodology, first-frame cost and limitations. RGBA readback timings and surface submission rates are reported separately; they are not monitor FPS measurements.

Renderer and documentation

The native extension uses the published figgy-renderer 0.18.1 and figgy-model 0.12.1 crates from crates.io, pinned in Cargo.lock. The packaged browser kernel is built from their upstream release commit f3f569c4c0e32d3d0682632444b6fe7ce84cba8d with a recorded web-binding patch for non-borrowing GPU completion and current annotation hit geometry. Asset provenance checks pair the registry versions and checksums with that source revision and verify the binding patch hash. Rust owns chart layout, rendering, picking and drag policies; this repository adds the NumPy-facing API, native editing host, browser widgets and Python settings export.

Licensed under MIT OR Apache-2.0. Bundled assets retain their respective licenses; see third-party notices.

About

No description, website, or topics provided.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages