Presentations
Python JQL chart and table inputs and typed presentation-frame output.
.chart(*, chart_type, title, x_axis, y_axis, series_by=None, description=None) -> dict
.table(*, title, columns, description=None) -> dict.chart() and .table() are available on both the query builder and the pipeline
builder. They return a presentation query object that wraps a source query or
pipeline. Execute that object with client.present(...), not client.query(...).
Presentation input keys are snake_case in both runtimes. Unlike other
Python options, these are passed straight through to the wire without
renaming, so the accepted keys are exactly chart_type, x_axis, y_axis, series_by, title, description, columns.
Presentation field
Every axis, series, or table column is an object — never a bare string — with:
| Field | Type/default | Constraint |
|---|---|---|
key | string, required | 1–80 chars; ^[A-Za-z_][A-Za-z0-9_]*$; must be produced by the wrapped query |
label | string or null | At most 120 chars |
format | "auto" | auto number compact percent currency_usd duration_ms datetime |
Chart
| Input key | Type | Constraint |
|---|---|---|
chart_type | bar | line | area | pie | Required |
title | string | 1–200 chars |
description | string or null | At most 500 chars |
x_axis | presentation field | Required |
y_axis | presentation field | Required |
series_by | presentation field or null | Forbidden for pie charts |
Axis/series keys must be unique.
Table
A table requires a title and 1–16 ordered presentation fields in columns.
Column keys must be unique. Title and description use the same length limits as a
chart.
Example
from judgeval.jql import agg_expr, spans
presentation = (
spans()
.last("7d")
.pipe()
.summarize({"spend": agg_expr("sum", "cost")}, by="model")
.chart(
chart_type="bar",
title="Spend by model",
x_axis={"key": "model", "label": "Model"},
y_axis={"key": "spend", "label": "Spend", "format": "currency_usd"},
)
)
result = client.present(presentation)Exact response behavior
present returns normalized presentation metadata and a renderer-neutral frame:
{
"query_id": "q_123",
"presentation": {
"op": "chart",
"chart_type": "bar",
"title": "Spend by model",
"description": null,
"x_axis": { "key": "model", "label": "Model", "format": "auto" },
"y_axis": {
"key": "spend",
"label": "Spend",
"format": "currency_usd"
},
"series_by": null
},
"frame": {
"schema": [
{ "key": "model", "data_type": "string", "nullable": false },
{ "key": "spend", "data_type": "number", "nullable": true }
],
"rows": [{ "model": "gpt-4.1", "spend": 12.5 }]
},
"elapsed_ms": 18
}data_type is string, number, duration, or datetime. Frame rows
contain only the requested presentation keys, in schema order.
Rendering boundary
client.present(...) does not render HTML, an image, a React component, or a chart.
It validates the presentation, runs the query, and returns metadata plus typed rows.
Your application chooses a renderer and maps presentation and frame into it.
If a requested presentation key is not produced by the query, execution fails with
BAD_PRESENTATION and a hint listing available result columns.