Use table blueprints to order, rename, or hide columns, embed segment previews, and display rows as cards in catalog tables and dataset segment tables.
Table blueprints are separate from blueprints for individual recordings, though both are saved as .rbl files, and segment previews use the same view classes, such as Spatial3DView.
An agent changes the table on screen through the Viewer MCP server, which reads and writes the same blueprint as JSON.
It writes the table blueprint rather than clicking through the Columns menu.
The rerun-blueprint skill covers both the Python API and the MCP tools.
The runnable Python example downloads 20 recordings from the public DROID sample dataset, starts a local catalog server, and opens the Viewer.
Prerequisites
You'll need the Rerun Python SDK and a running catalog server with an existing table or dataset. For an introduction to catalog tables, see Table entries. For creating and populating tables from query results, follow Storing query results in catalog tables.
The example used here creates my_table with a recording_uri for each segment and uuid and current_task columns copied from DROID's episode properties.
It also adds an id row key and a boolean reviewed column, used for editable flags.
(These are example-specific columns, not required table fields.)
Configuring a catalog table
Defining a preview column
Let's start by defining a preview for the recording_uri column that we'll use on cards.
This only creates a column configuration — we'll add it to the card layout below, then save and register the blueprint.
import rerun.blueprint as rrb
preview = rrb.table.Column(
"recording_uri",
name="Recording", # Give the column a nicer name.
# Show a 3D view for recordings in this row.
column_type=rrb.table.PreviewCell(rrb.Spatial3DView()),
)Column takes the source column's physical name; name overrides its display label.
column_type overrides the component the column's values are shown as.
It takes any component class, e.g. rr.components.Url, rr.components.Thumbnail or rr.components.Color.
For the UI of one archetype field, pass its component descriptor, e.g. rr.TextDocument.descriptor_text().
Instead of a component, column_type also takes a PreviewCell, which is what we use here.
PreviewCell renders the referenced recording using one or more views.
You configure these views just as you would in a recording blueprint, including their contents and view properties.
Pass the views directly to PreviewCell, without the container layout tree (Horizontal, Vertical, Tabs, etc.) used to arrange a recording's viewport.
Multiple views are shown side by side.
Previews only come from a table blueprint, since the Viewer has no option to turn a column into a preview.
Configuring card and table layouts
A card displays one table row as a tile with a title, selected fields, and optional segment previews. Cards provide a visual alternative to rows and columns and are often much better suited to show a series of segment previews.
Let's show previews on cards, and put the recording link and episode metadata first in the table:
table_layout = rrb.table.TableLayout(
# Show these columns first.
columns=[
rrb.table.Column("recording_uri", name="Recording"),
rrb.table.Column("uuid"),
rrb.table.Column("current_task"),
],
)
card_layout = rrb.table.CardLayout(
title="uuid", # Use the uuid column as the card title.
link="recording_uri",
# Columns on the card layout are opt-in.
fields=[preview, rrb.table.Column("current_task")],
)
blueprint = rrb.TableBlueprint(
table_layout=table_layout,
card_layout=card_layout, # Cards become the default layout.
previews_config=rrb.table.PreviewsConfig(timeline="real_time"),
)Card layout:
title: the column used as the card's heading.link: the URI column to open when the card is activated.fields: the columns to display, in order, including any previews; unlisted fields are hidden.
Table layout: TableLayout.columns puts listed columns first and makes them visible unless visible=False; unlisted columns retain their default order and visibility.
Column settings are independent between the two layouts: here, the Viewer automatically displays recording_uri as a link in the table, while PreviewCell turns it into a preview on cards.
Setting card_layout enables cards and makes them the initial layout.
PreviewsConfig sets the timeline, play state, playback speed, and start point of the previews.
These settings are shared by all preview columns, whether they're in a table or on cards.
Without a timeline, the Viewer picks one automatically.
Pass play_state="playing" to start all previews playing, and playback_speed to change their speed, e.g. playback_speed=0.5 for half speed.
It defaults to 0.5, the middle of the recording.
The play and speed buttons in the table toolbar change the same settings, and a single preview can still be played or paused on its own.
Saving and registering the blueprint
Save the blueprint to an .rbl file, then register it on the table (catalog_url is your server's URL):
path = Path("table.rbl").resolve()
blueprint.save("my_app", path)
client = rr.catalog.CatalogClient(catalog_url)
# Register a file the server can access.
client.get_table("my_table").register_blueprint(path.as_uri())register_blueprint sets the default unless you pass set_default=False.
Editing columns
To make a column editable, configure it with editable=True and add it to the layout's columns or fields list.
A cell can be edited when its component type has an editor in the Viewer.
To edit the boolean reviewed column as flag buttons, use column_type=rr.components.Flag.
Card layouts show the first flag field in the card header:
# Edit the `reviewed` column through flag buttons.
flag = rrb.table.Column(
"reviewed",
editable=True,
column_type=rr.components.Flag,
)
flag_blueprint = rrb.TableBlueprint(
table_layout=rrb.table.TableLayout(columns=[flag, *table_layout.columns]),
card_layout=rrb.table.CardLayout(
title="uuid",
link="recording_uri",
fields=[flag, *card_layout.fields],
),
previews_config=rrb.table.PreviewsConfig(timeline="real_time"),
)
To edit a string notes column as text, use column_type=rr.components.Text:
# Edit the `notes` column as text.
notes = rrb.table.Column(
"notes",
editable=True,
column_type=rr.components.Text,
)
notes_blueprint = rrb.TableBlueprint(
table_layout=rrb.table.TableLayout(columns=[notes, *table_layout.columns]),
)Editing requires write access to a catalog table with a row-key column marked with rr.SORBET_IS_TABLE_INDEX metadata.
The Viewer uses this key to persist edits. See Update a table for details.
Editing is currently not supported on dataset segment tables.
Filtering rows
filters hides the rows that don't match every filter, in both layouts:
filter_blueprint = replace(
blueprint,
filters=[
# These show as editable filters in the Viewer's filter bar.
#
# Nothing here knows about the tables schema, if the type of
# the given column doesn't work in the operation it will show
# up as 'Custom' in the viewer and might error.
rrb.table.col("current_task").str.contains("cup"),
rrb.table.col("reviewed").is_false(),
# Any other SQL expression shows as SQL text.
'length("uuid") > 10',
],
)rrb.table.col builds filters for one column.
It only builds the filters that can be edited in the Viewer's filter bar:
- numbers:
eq(),ne(),lt(),le(),gt(),ge(), or the operators==,!=,<,<=,>,>= - booleans:
is_true(),is_false(),is_null(),is_not_true(),is_not_false(),is_not_null() - strings:
str.contains(),str.does_not_contain(),str.starts_with(),str.ends_with(), matched as plain text ignoring case - timestamps:
before(),after(),between(), and relative ranges such astoday()andlast_week(), and the negated ranges such asnot_between()andnot_today()
The negated filters such as ne() and str.does_not_contain() also select the rows where the value is null.
For a list column, use the same filters on .list, e.g. col("tags").list.str.contains("pick"), to select the rows where any value of the list matches.
The negated filters then select the rows where no value matches.
col doesn't know the type of the column, so make sure the filter matches the given column.
The Viewer shows a filter for another type, such as str.contains() on a number column, as SQL text.
If the SQL doesn't work on the column, the Viewer shows the error on that filter and doesn't apply it.
Instead of using rrb.table.col, you can also provide a string with a raw SQL expression in DataFusion's SQL dialect, with double-quoted column names.
It filters the table like any other filter, and the Viewer shows it as SQL text.
Configuring a dataset's segment table
Dataset segment tables use the same blueprint API.
The Viewer provides a "recording link" column for previews and card links; metadata columns use property names, such as DROID's "property:episode:uuid".
Register the saved blueprint with segment_table=True:
preview = rrb.table.Column(
# Use the recording links provided by the segment table.
"recording link",
column_type=rrb.table.PreviewCell(rrb.Spatial3DView()),
)
blueprint = rrb.TableBlueprint(
table_layout=rrb.table.TableLayout(
columns=[
rrb.table.Column("recording link"),
],
),
card_layout=rrb.table.CardLayout(
title="property:episode:uuid",
link="recording link",
fields=[preview],
),
previews_config=rrb.table.PreviewsConfig(timeline="real_time"),
)
path = Path("segments.rbl").resolve()
blueprint.save("my_app", path)
client.get_dataset("my_dataset").register_blueprint(
path.as_uri(),
# Apply to the segment table, not individual recordings.
segment_table=True,
)Without segment_table=True, registration sets the blueprint for opening individual recordings, not the segment table.
Using remote storage
Upload the .rbl file to storage the server has permission to read, then register its URI:
# Upload the .rbl to this URI first.
client.get_table("my_table").register_blueprint(
"s3://my-bucket/blueprints/table.rbl"
)For dataset segment tables, use get_dataset(…).register_blueprint(uri, segment_table=True) instead.
What the blueprint stores
A table blueprint is stored as blueprint entities, which is what an .rbl file holds and what the Viewer MCP server reads and writes as JSON.
Each Python class maps to these entity paths and archetypes:
| Python | Entity path | Archetypes |
|---|---|---|
TableBlueprint | /table | TableBlueprint, PreviewsConfig |
TableLayout | /table/layouts/table | TableLayout, with the columns in column_order |
Column in a TableLayout | /table/layouts/table/columns/{column} | TableColumn, and TableColumnPreview for a PreviewCell |
CardLayout | /table/layouts/cards | CardLayout, with the fields in field_order |
Column in a CardLayout | /table/layouts/cards/fields/{column} | TableColumn, and TableColumnPreview for a PreviewCell |
A view in a PreviewCell | /view/{view_id} | ViewBlueprint and its view properties, as in a recording blueprint |
In an entity path, : and spaces in a column name are escaped as \: and \ .
TableColumnPreview.views lists the /view/{view_id} paths of its views.
A column with a TableColumnPreview shows as a preview.
TableColumn.column_type holds the component identifier and component type set by column_type, e.g. rerun.components.Flag.
Further examples
The runnable snippet above covers the basic workflow. For more complete examples, including setup and usage instructions, see:
- Table blueprints: multiple preview views (3D, 2D, and plots), editable flags, and registration on local or remote catalogs.
- Table grid with flags: a standalone editable table demonstrating row keys and persisted flag updates, without segment previews.
For more about catalog entries and their blueprints, see the Catalog object model. For the available configuration options, see the Python table blueprint API reference.