rerun-blueprint

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Rerun blueprint

Rerun 蓝图

A blueprint decides how a recording is shown; the recording decides what exists. Read the data, design a first layout, then iterate from screenshots until it reads at a glance. The constructors are discoverable (
dir(rrb)
,
help(rrb.Spatial3DView)
); this skill covers what you can't guess. Import as
import rerun.blueprint as rrb
.
Blueprint(蓝图)决定了录制内容的展示方式;而录制内容决定了存在哪些数据。先读取数据,设计初始布局,然后通过截图迭代优化,直到内容一目了然。构造函数可通过
dir(rrb)
、
help(rrb.Spatial3DView)
查看;本文档会介绍那些无法通过猜测得知的内容。导入方式为
import rerun.blueprint as rrb
。

1. Read the data

1. 读取数据

Enumerate every
(entity_path, archetype)
pair first — the archetype picks the view, the entity path scopes it. For a dataset (see
rerun-catalog-queries
):
python
for c in dataset.schema().component_columns():
    print(c.entity_path, c.archetype, c.component_name)
For a local recording, stream it with
RrdReader
and read
entity_path
and the archetype off each chunk (see
rerun-chunk-processing
).
首先枚举所有
(entity_path, archetype)
对——archetype(原型)决定视图,entity_path(实体路径)限定范围。对于数据集(参考
rerun-catalog-queries
):
python
for c in dataset.schema().component_columns():
    print(c.entity_path, c.archetype, c.component_name)
对于本地录制内容,使用
RrdReader
流式读取,并从每个数据块中获取
entity_path
和archetype(参考
rerun-chunk-processing
)。

2. Map archetype to view

2. 原型到视图的映射

Archetype familyView
Points2D
,
Image
,
EncodedImage
,
Boxes2D
,
LineStrips2D
,
Pinhole
projections
Spatial2DView
Points3D
,
Mesh3D
,
Boxes3D
,
LineStrips3D
,
Transform3D
,
Asset3D
Spatial3DView
Scalars
,
SeriesLines
,
SeriesPoints
TimeSeriesView
TextLog
/
TextDocument
/
BarChart
TextLogView
/
TextDocumentView
/
BarChartView
Tensor
,
DepthImage
(heatmap)
TensorView
GeoPoints
,
GeoLineStrings
MapView
GraphNodes
,
GraphEdges
GraphView
tabular / catalog data
DataframeView
原型类别视图
Points2D
、
Image
、
EncodedImage
、
Boxes2D
、
LineStrips2D
、
Pinhole
投影
Spatial2DView
Points3D
、
Mesh3D
、
Boxes3D
、
LineStrips3D
、
Transform3D
、
Asset3D
Spatial3DView
Scalars
、
SeriesLines
、
SeriesPoints
TimeSeriesView
TextLog
/
TextDocument
/
BarChart
TextLogView
/
TextDocumentView
/
BarChartView
Tensor
、
DepthImage
(热力图)
TensorView
GeoPoints
、
GeoLineStrings
MapView
GraphNodes
、
GraphEdges
GraphView
表格/目录数据
DataframeView

3. Group entities into views

3. 将实体分组到视图中

This step is just deciding which entities share a view. Sizing and placement are mechanics you tune by eye in the screenshot loop, not rules to settle up front.
  • Group by shared path prefix. Entities under a common prefix usually belong in one view. Don't give every entity its own pane: dozens of raw message entities go in one
    DataframeView
    , or get left out, rather than a pane each.
  • One spatial frame per spatial view. A whole
    Transform3D
    tree goes in one
    Spatial3DView
    at the common ancestor; a
    Pinhole
    camera gets its own
    Spatial2DView
    rooted at the camera so images inherit the projection.
  • Collapse scalars. Many
    Scalars
    under a prefix → one
    TimeSeriesView
    over the prefix, not one each. Split only when value ranges clash.
  • column_shares
    /
    row_shares
    are relative weights
    on a container's children, equal by default. Tune them from the screenshots.
这一步只需决定哪些实体共享一个视图。尺寸和布局是你在截图迭代过程中通过视觉调整的细节,无需预先制定规则。
  • 按共享路径前缀分组:具有共同前缀的实体通常属于同一个视图。不要给每个实体单独分配一个面板:数十个原始消息实体应放在一个
    DataframeView
    中,或直接忽略,而非每个实体占一个面板。
  • 每个空间视图对应一个空间坐标系:整个
    Transform3D
    树应放在以共同祖先为根的一个
    Spatial3DView
    中;
    Pinhole
    相机应单独使用一个以相机为根的
    Spatial2DView
    ,以便图像继承其投影关系。
  • 合并标量数据:同一前缀下的多个
    Scalars
    应合并到一个
    TimeSeriesView
    中,而非每个标量单独一个视图。仅当数值范围冲突时才拆分。
  • column_shares
    /
    row_shares
    是容器子元素的相对权重
    ,默认值相等。可通过截图调整这些值。

4. Construct it

4. 构建蓝图

Containers (
Grid
,
Horizontal
,
Vertical
,
Tabs
) hold views. Default a flat set to
Grid
; use the others for a deliberate split,
Tabs
for alternatives competing for one slot (left/right/depth cameras). Always set an explicit
origin
and
name
—
origin
defaults to
/
, which dumps the whole tree into one view (the usual cause of an unreadable blob).
python
blueprint = rrb.Blueprint(
    rrb.Horizontal(
        rrb.Spatial3DView(origin="/world", name="Scene"),
        rrb.Vertical(
            rrb.Spatial2DView(origin="/world/camera", name="Camera"),
            rrb.TimeSeriesView(origin="/sensors", name="Sensors"),
        ),
        column_shares=[3, 2],
    ),
    rrb.TextLogView(origin="/logs", name="Logs"),
    collapse_panels=True,
)
contents
defaults to
"$origin/**"
. Scope a view with include/exclude rules, e.g.
contents=["+ $origin/**", "- $origin/internal/**"]
. A bare line is an include;
/**
is the only wildcard (matches a subtree). Most-specific rule wins, ties go to the last, unmatched paths are excluded.
Coordinate frames. A spatial view only renders entities it can place relative to its target frame.
Transform3D
/
Pinhole
logged on entities compose down the tree, so
origin
is enough. But named frames (
CoordinateFrame(frame=...)
, common in ROS/MCAP) live in a separate frame graph — point the view at a frame the data occupies via
spatial_information=rrb.SpatialInformation(target_frame="<frame>")
. The tell is an empty 3D view with "No transform path from
<frame>
…" errors:
origin="/"
targets the root
tf#/
, which connects to nothing if the tf tree was never materialized. Read the
CoordinateFrame:frame
values, target the one the main 3D content sits in, and exclude entities in unconnected frames.
容器(
Grid
、
Horizontal
、
Vertical
、
Tabs
)用于容纳视图。默认将一组平面视图设为
Grid
;对于需要刻意拆分的场景,使用其他容器,
Tabs
适用于在同一位置切换的替代视图(如左/右/深度相机)。务必设置明确的
origin
和
name
——
origin
默认值为
/
,这会将整个树结构放入一个视图中(这通常是导致内容难以阅读的原因)。
python
blueprint = rrb.Blueprint(
    rrb.Horizontal(
        rrb.Spatial3DView(origin="/world", name="Scene"),
        rrb.Vertical(
            rrb.Spatial2DView(origin="/world/camera", name="Camera"),
            rrb.TimeSeriesView(origin="/sensors", name="Sensors"),
        ),
        column_shares=[3, 2],
    ),
    rrb.TextLogView(origin="/logs", name="Logs"),
    collapse_panels=True,
)
contents
默认值为
"$origin/**"
。可通过包含/排除规则限定视图范围,例如
contents=["+ $origin/**", "- $origin/internal/**"]
。单独一行表示包含;
/**
是唯一的通配符(匹配子树)。最具体的规则优先,规则冲突时取最后一条,未匹配的路径会被排除。
坐标系:空间视图仅渲染其目标坐标系下可定位的实体。记录在实体上的
Transform3D
/
Pinhole
会沿树结构组合,因此设置
origin
即可。但命名坐标系(
CoordinateFrame(frame=...)
,在ROS/MCAP中常见)存在于单独的坐标系图中——需通过
spatial_information=rrb.SpatialInformation(target_frame="<frame>")
将视图指向数据所在的坐标系。如果3D视图为空且显示“No transform path from
<frame>
…”错误,原因在于
origin="/"
指向根坐标系
tf#/
,而如果tf树从未实例化,该根坐标系不会与任何内容关联。读取
CoordinateFrame:frame
的值,将视图指向主要3D内容所在的坐标系,并排除未连接坐标系中的实体。

5. Iterate from screenshots

5. 通过截图迭代优化

Spawn the viewer and load the recording once, then re-send blueprints into the same viewer; each send + screenshot is one cheap iteration. Render, look, revise.
The blueprint binds to the data by store identity, both application id and recording id. A loaded
.rrd
keeps its own identity, so build the stream from the rrd's values (set both;
recording_id
otherwise defaults to a random one). Mismatch either and the viewer keeps blueprint and data as separate recordings and never applies the blueprint.
python
import time
import rerun as rr
import rerun.blueprint as rrb
from rerun.experimental import ViewerClient, RrdReader

store = RrdReader("segment.rrd").recordings()[0]  # the rrd's application id + recording id

with ViewerClient.spawn(headless=True, port=9879) as viewer:
    rec = rr.RecordingStream(store.application_id, recording_id=store.recording_id)
    rec.connect_grpc(url=viewer.url)
    rec.log_file_from_path("segment.rrd")

    def shot(blueprint, path):
        rec.send_blueprint(blueprint, make_active=True, make_default=True)
        time.sleep(2)  # let the import finish and a frame render; bump if a view is blank
        viewer.save_screenshot(path)  # view_id=view.id for a single view

    shot(blueprint_v1, "bp_v1.png")
    # Read bp_v1.png, revise, send the next one into the same viewer.
    shot(blueprint_v2, "bp_v2.png")
To bake a finished blueprint in instead, pass
default_blueprint=
to
rr.init
/
spawn
/
connect_grpc
/
save
, or
blueprint=
to
notebook_show
.
启动查看器并加载一次录制内容,然后将新的蓝图发送到同一个查看器;每次发送+截图就是一次低成本的迭代。渲染、查看、修改。
蓝图通过存储标识(应用ID和录制ID)与数据绑定。已加载的
.rrd
文件保留自身标识,因此需从rrd的值构建流(同时设置两个ID;否则
recording_id
默认是随机值)。如果任一ID不匹配,查看器会将蓝图和数据视为单独的录制内容,不会应用该蓝图。
python
import time
import rerun as rr
import rerun.blueprint as rrb
from rerun.experimental import ViewerClient, RrdReader

store = RrdReader("segment.rrd").recordings()[0]  # rrd文件的应用ID + 录制ID

with ViewerClient.spawn(headless=True, port=9879) as viewer:
    rec = rr.RecordingStream(store.application_id, recording_id=store.recording_id)
    rec.connect_grpc(url=viewer.url)
    rec.log_file_from_path("segment.rrd")

    def shot(blueprint, path):
        rec.send_blueprint(blueprint, make_active=True, make_default=True)
        time.sleep(2)  # 等待导入完成并渲染一帧;如果视图为空则延长时间
        viewer.save_screenshot(path)  # 使用view_id=view.id可保存单个视图

    shot(blueprint_v1, "bp_v1.png")
    # 查看bp_v1.png,修改蓝图,然后将下一个版本发送到同一个查看器。
    shot(blueprint_v2, "bp_v2.png")
如果要将最终蓝图内置到录制内容中,可在
rr.init
/
spawn
/
connect_grpc
/
save
中传入
default_blueprint=
参数,或在
notebook_show
中传入
blueprint=
参数。

Gotchas

注意事项

  • A
    DataframeView
    shows "Unknown timeline" without a query:
    query=rrb.archetypes.DataframeQuery(timeline="<timeline>", apply_latest_at=True)
    .
  • A view back blank? The importer may not have finished (bump the settle) or the cursor sits before the data (add
    rrb.TimePanel(play_state=rrb.components.PlayState.Following)
    ).
  • rrb
    views and
    ViewerClient
    (
    rerun.experimental
    ) are unstable. Check
    help()
    if a constructor argument is rejected.
  • 如果没有设置查询条件,
    DataframeView
    会显示“Unknown timeline”:需设置
    query=rrb.archetypes.DataframeQuery(timeline="<timeline>", apply_latest_at=True)
    。
  • 视图显示空白?可能是导入未完成(延长等待时间),或者光标位置在数据之前(添加
    rrb.TimePanel(play_state=rrb.components.PlayState.Following)
    )。
  • rrb
    视图和
    ViewerClient
    (
    rerun.experimental
    )尚不稳定。如果构造函数参数被拒绝,请查看
    help()
    。

See also

另请参阅

  • rerun-data-model
    — entities, archetypes, timelines.
  • rerun-catalog-queries
    — enumerate entities in a dataset.
  • rerun-data-model
    —— 实体、原型、时间线。
  • rerun-catalog-queries
    —— 枚举数据集中的实体。