Skip to content

Charts

Lets-Plot grammar

golit.charts re-exports the full Lets-Plot grammar of graphics — ggplot, aes, every geom_*, ggsize, labs, scales, and themes. Return a plot spec from a view and Golit renders it to static SVG. See the Lets-Plot reference for the grammar itself, and the Charts tutorial for usage.

Plotly, Altair, and Bokeh figures need no helper — return one from a view and Golit auto-detects and renders it as an interactive client-side chart.

chart_spec

The hot path for an interactive view that rebuilds its chart every interaction: hand Golit the raw wire-format spec (a plain dict) instead of a figure object, skipping the graph_objects build and to_json. See the Charts tutorial.

chart_spec

chart_spec(
    lib: str, spec: Any, *, version: str | None = None
) -> str

Mount a chart from a raw spec already in the JS runtime's wire format — a plain dict (or pre-serialized JSON string) — skipping the heavy Python figure object.

Returning a plotly.graph_objects.Figure (or an Altair chart) is convenient, but constructing and to_json-ing it costs hundreds of microseconds and ships kilobytes of default template on every interaction — a tax a view that rebuilds its chart each update pays in full. Handing Golit the spec directly is the same JSON the runtime draws, far cheaper to produce and far smaller on the wire::

@app.view
def revenue(by_region: pl.DataFrame):
    return chart_spec("plotly", {
        "data": [{"type": "bar", "x": by_region["region"].to_list(),
                  "y": by_region["revenue"].to_list()}],
        "layout": {"margin": {"t": 10}},
    })

lib is any runtime the shell bootstrap knows (plotly, vega, bokeh, anychart); the spec must be in that runtime's own format (e.g. a Plotly {"data": [...], "layout": {...}}). version pins the runtime where it matters (Bokeh). For the convenient path, just return the figure object — :func:try_interactive serializes it; for the hot path, build the spec and use this.

Source code in python/golit/rendering/interactive.py
def chart_spec(lib: str, spec: Any, *, version: str | None = None) -> str:
    """Mount a chart from a *raw spec* already in the JS runtime's wire format — a
    plain ``dict`` (or pre-serialized JSON string) — skipping the heavy Python figure
    object.

    Returning a ``plotly.graph_objects.Figure`` (or an Altair chart) is convenient, but
    constructing and ``to_json``-ing it costs hundreds of microseconds and ships
    kilobytes of default template on *every* interaction — a tax a view that rebuilds
    its chart each update pays in full. Handing Golit the spec directly is the same JSON
    the runtime draws, far cheaper to produce and far smaller on the wire::

        @app.view
        def revenue(by_region: pl.DataFrame):
            return chart_spec("plotly", {
                "data": [{"type": "bar", "x": by_region["region"].to_list(),
                          "y": by_region["revenue"].to_list()}],
                "layout": {"margin": {"t": 10}},
            })

    ``lib`` is any runtime the shell bootstrap knows (``plotly``, ``vega``, ``bokeh``,
    ``anychart``); the spec must be in that runtime's own format (e.g. a Plotly
    ``{"data": [...], "layout": {...}}``). ``version`` pins the runtime where it matters
    (Bokeh). For the convenient path, just return the figure object — :func:`try_interactive`
    serializes it; for the hot path, build the spec and use this."""
    spec_json = spec if isinstance(spec, str) else json.dumps(spec)
    return _mount(lib, spec_json, version=version)

anychart

For AnyChart (which has no Python figure object), build a mount explicitly:

anychart

anychart(
    data: Any,
    x: str | None = None,
    y: str | None = None,
    *,
    kind: str = "column",
    title: str | None = None,
) -> str

Build an AnyChart mount from a Polars DataFrame (x/y columns) or a sequence of [label, value] rows.

@app.view
def revenue(by_region: pl.DataFrame):
    return anychart(by_region, "region", "revenue", kind="column", title="Revenue")

kind is any AnyChart constructor: column/bar/line/area/ spline/pie/donut.

Source code in python/golit/rendering/interactive.py
def anychart(
    data: Any,
    x: str | None = None,
    y: str | None = None,
    *,
    kind: str = "column",
    title: str | None = None,
) -> str:
    """Build an AnyChart mount from a Polars ``DataFrame`` (``x``/``y`` columns) or
    a sequence of ``[label, value]`` rows.

        @app.view
        def revenue(by_region: pl.DataFrame):
            return anychart(by_region, "region", "revenue", kind="column", title="Revenue")

    ``kind`` is any AnyChart constructor: ``column``/``bar``/``line``/``area``/
    ``spline``/``pie``/``donut``."""
    spec: dict[str, Any] = {"kind": kind, "data": _anychart_rows(data, x, y)}
    if title is not None:
        spec["title"] = title
    return _mount("anychart", json.dumps(spec))

try_interactive

The detector used internally to turn a Plotly/Altair/Bokeh figure into a chart mount. Returns the mount HTML, or None if the value isn't a recognized figure.

try_interactive

try_interactive(value: Any) -> str | None

Render a Plotly/Altair/Bokeh figure to a mount fragment, else None.

Detection is by the value's defining module, so the framework never imports these libraries itself — only Bokeh's serializer is imported, and only when a Bokeh figure actually shows up (so it's necessarily installed).

Source code in python/golit/rendering/interactive.py
def try_interactive(value: Any) -> str | None:
    """Render a Plotly/Altair/Bokeh figure to a mount fragment, else ``None``.

    Detection is by the value's defining module, so the framework never imports
    these libraries itself — only Bokeh's serializer is imported, and only when a
    Bokeh figure actually shows up (so it's necessarily installed)."""
    root = (type(value).__module__ or "").split(".", 1)[0]

    if root == "plotly" and callable(getattr(value, "to_json", None)):
        return _mount("plotly", value.to_json())  # {"data": …, "layout": …}

    if root == "altair" and callable(getattr(value, "to_json", None)):
        return _mount("vega", value.to_json())  # a Vega-Lite spec

    if root == "bokeh":
        import bokeh
        from bokeh.embed import json_item

        # Pin BokehJS to the installed Bokeh so the wire format matches.
        return _mount("bokeh", json.dumps(json_item(value)), version=bokeh.__version__)

    return None