Python constructors and rendering for Gum, a language for creating vector graphics. Build plots, diagrams, documents, and math in Python, then render SVG, PNG, RGBA pixels, PDF, PowerPoint, or kitty terminal graphics. Elements also display in Jupyter notebooks.
This adapter targets the Gum 2.1.0 libraries. Rendering uses Node.js 24 or
newer. The Python wheel includes the compiled JavaScript backend and fonts.
GUM_JSX_RUNTIME can point to a different Node.js executable.
Installation
pip install gum-jsx
The base package requires only Pillow. Installing a wheel needs no
JavaScript dependency installation or build step. Importing gum and constructing
JSX do not start Node.js. The renderer starts on the first render request and is
reused until Python exits. Install the gum-jsx[plotting] target to use NumPy and
pandas for the high-level plotting helpers.
Python API
import gum
from gum import G, C, px, em
plot = G.Plot(
G.SymLine(
fy=C.sin, xlim=(0, 2*C.pi),
stroke=C.blue, stroke_width=px(2),
),
grid=True, aspect=C.phi, font_size=px(22),
xlabel='Phase', ylabel='Amplitude',
)
svg = gum.evaluate(plot) # SVG string
png = gum.render(plot, width=800) # PNG bytes
image = gum.evaluate(plot, output_format='png') # PIL image
gum.display(plot) # kitty terminal graphics
jsx = str(plot) # JSX source
In a notebook, leaving an element as the last expression displays its SVG.
Constructors live in gum.G or gum.gen. C references Gum constants, functions,
and expressions; V.name(data) declares a JavaScript variable when included in
G.Gum(element, vars=[variable]). Python lambdas become JavaScript functions:
decay = lambda x: C.exp(-x/2) * C.sin(3*x)
curve = G.SymLine(fy=decay, xlim=(0, 2*C.pi), samples=200)
Use px(20) for pixel lengths, em(1) for font-relative lengths, and fractions
such as 0.5 for relative lengths. Props use snake_case in Python and become
kebab-case JSX. A trailing underscore escapes a Python keyword, for example
G.Line(from_=(0, 0), to=(1, 1)).
Rendering options
gum.evaluate(source, **options) accepts Python elements or a JSX source string.
| Option | Meaning |
|---|---|
output_format |
svg (default), png, pixels, kitty, pdf, pptx, tree, or json |
page |
Select one document page, starting at 1; required for multi-page SVG/raster/kitty output |
width, height |
Independent viewport overrides in pixels |
ratio |
PNG/pixel/kitty sampling ratio, default 1; does not change layout |
select |
Raster crop dictionary with x, y, width, height |
theme |
Explicit light or dark override |
background |
Viewport background; transparent if omitted |
text_mode |
path, live, or mixed; raster output always uses paths |
seed |
Seed for the evaluation's independent random stream |
title, id_prefix, precision |
Current Gum export metadata and SVG/numeric output options |
return_format |
PNG: pil or bytes; pixels: pil, numpy, torch, or bytes |
With no width/height override, Gum offers a 640 × 480 layout budget. Explicit
source sizes win, short content hugs its contents, and tall content may grow.
One width override leaves height natural. Themes default to light for file
formats and dark for kitty, while source <Page theme=...> wins unless a theme
is explicitly passed to Python.
PDF and PPTX return bytes. SVG, tree, JSON, and kitty return strings. PDF defaults
to live text and PPTX to mixed text; PPTX requires dimensions of at least 96 pixels
on each side. G.Document exports all its pages to PDF/PPTX; page=... exports
just the selected page. Video/MP4 and file-based deck assembly remain available
through the Gum CLI.
evaluate_png() and evaluate_pixels() encode existing PNG/RGBA data for kitty;
the corresponding display_*() functions print it. Pixel buffers use
size=(width, height), while NumPy/Torch arrays use (height, width, 4) with
uint8 channels. PIL images are accepted too.
Pages and documents
G.Page sets a viewport's size and style. G.Document groups pages for export,
and its props provide defaults that individual pages can override. Slides are
also pages and can be children of a document.
document = G.Document(
G.Page(G.Text('First page')),
G.Page(G.Text('Second page')),
width=px(640), height=px(480), title='Example',
)
pdf = gum.evaluate(document, output_format='pdf')
pptx = gum.evaluate(document, output_format='pptx')
preview = gum.evaluate(document, page=2)
JSON output for a document contains title (when set) and pages; selecting a
page returns that page's fragment. Tree output lists each page.
Pandas integration
import numpy as np
import pandas as pd
from gum import lines, points, bars
phase = np.linspace(0, 2*np.pi, 100)
frame = pd.DataFrame({'sin': np.sin(phase), 'cos': np.cos(phase)}, index=phase)
lines(frame)
points(frame, point_size=px(5))
bars(pd.Series({'A': 3, 'B': 8, 'C': 5}), fill=C.blue)
Column labels may contain spaces, punctuation, or duplicate names. The adapter
uses separate, stable JavaScript identifiers. Bars convert category labels into
axis ticks; direction='horizontal' puts those labels on the vertical axis.
CLI
python -m gum -d plot # kitty display
python -m gum -d latex -o formula.svg
python -m gum -d plot -W 800 -r 2 -o plot.png
python -m gum -d slide -o slide.pdf
python -m gum -d slide -o slide.pptx
cat input.jsx | python -m gum -f svg
-W/--width and -H/--height set pixel dimensions. -r/--ratio, -t/--theme,
-b/--background, and --text-mode match the Python render options. Use
-f/--format to override a filename's format.
Use --page 2 to select the second page of a document supplied on stdin.
python -m gum --help lists the built-in demos.
See Gum's reference, gum/dem.py, and
gum.ipynb for current examples.
Development
Source builds and development require Bun 1.4.2 or newer. From this checkout:
python -m pip install -e '.[plotting]'
bun install --cwd gum/js --frozen-lockfile
bun run --cwd gum/js typecheck
python -m unittest discover -s test -v
The editable install builds the backend automatically. Run
bun run --cwd gum/js build after editing backend source.
To work against your current local Gum workspace, install that workspace's dependencies, then link this adapter to its checked-out packages:
bun install --cwd /home/doug/mlai/gum-jsx
bun run --cwd gum/js link /home/doug/mlai/gum-jsx
Linking updates the adapter's ignored node_modules entries and rebuilds its
backend. Run bun run --cwd gum/js build after changing the linked Gum sources.
Run bun install --cwd gum/js --force --frozen-lockfile to restore registry
dependencies.
Tests cover all demos, math, plotting, text escaping, sizing, themes, binary formats, pixel orientation, subprocess recovery, concurrent requests, notebook display, and the CLI. Optional integrations run when their Python packages are installed.
Building the Python package
python -m pip install build
python -m build
This creates a source archive and wheel in dist/. The wheel build uses Bun to
install the locked registry dependencies in a temporary directory and bundle the
backend. Local dependency links are preserved. Wheels contain the JavaScript
bundle, font assets, and third-party notices; they need only Node.js at runtime.
Source archives contain the TypeScript sources and Bun lockfile, so building a
wheel from source requires Bun.
Publishing to PyPI
The .github/workflows/pypi.yml workflow builds and tests distributions on pushes
and pull requests. Pushing a v tag matching the version in pyproject.toml
publishes those tested artifacts to PyPI through Trusted Publishing.
Create a GitHub environment named pypi, then register a GitHub publisher in
PyPI with these values:
| Field | Value |
|---|---|
| PyPI project | gum-jsx |
| Owner | CompendiumLabs |
| Repository | gum-py |
| Workflow filename | pypi.yml |
| Environment | pypi |
For the first release, register a pending publisher. For an existing project, add the publisher in the project's Publishing settings. No API token or GitHub secret is needed.
Once the release commit and workflow are pushed, publish the matching tag:
git tag v2.1.0
git push origin v2.1.0
Update the Python version and tag for subsequent releases. The publishing job runs only after typechecking, building, metadata checks, and tests of the installed wheel pass. Bun builds the bundled backend; Node runs the wheel tests.
Metadata
Release files for gum-jsx 2.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| gum_jsx-2.1.0.tar.gz | 37.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| gum_jsx-2.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.8 MB
Release files / gum_jsx-2.1.0.tar.gz
| Download URL | gum_jsx-2.1.0.tar.gz |
|---|---|
| Size | 37.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cf3cf1fb611442023c1bea14cfd1247e6e5af6a38d89487d0d878907d5f067d1
|
|
BLAKE2b-256 checksum How to use checksums |
02b285035b4a5dbdd1ed09b356b01d75e8942c87fae0629ccd9921eeb527ba69
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / gum_jsx-2.1.0-py3-none-any.whl
| Download URL | gum_jsx-2.1.0-py3-none-any.whl |
|---|---|
| Size | 1.8 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f6ab0622edd745f42e28c4e5c7988c2e433c46f95d0d7fde50828c360b48e75f
|
|
BLAKE2b-256 checksum How to use checksums |
58e472d4adbfc3c648c3e9d364442001ece513f8f8480a8cb57104cecff77763
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency log