rerun-blueprint
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseRerun 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 (,
); this skill covers what you can't guess. Import as
.
dir(rrb)help(rrb.Spatial3DView)import rerun.blueprint as rrbBlueprint(蓝图)决定了录制内容的展示方式;而录制内容决定了存在哪些数据。先读取数据,设计初始布局,然后通过截图迭代优化,直到内容一目了然。构造函数可通过、查看;本文档会介绍那些无法通过猜测得知的内容。导入方式为。
dir(rrb)help(rrb.Spatial3DView)import rerun.blueprint as rrb1. Read the data
1. 读取数据
Enumerate every pair first — the archetype picks the
view, the entity path scopes it. For a dataset (see ):
(entity_path, archetype)rerun-catalog-queriespython
for c in dataset.schema().component_columns():
print(c.entity_path, c.archetype, c.component_name)For a local recording, stream it with and read and
the archetype off each chunk (see ).
RrdReaderentity_pathrerun-chunk-processing首先枚举所有对——archetype(原型)决定视图,entity_path(实体路径)限定范围。对于数据集(参考):
(entity_path, archetype)rerun-catalog-queriespython
for c in dataset.schema().component_columns():
print(c.entity_path, c.archetype, c.component_name)对于本地录制内容,使用流式读取,并从每个数据块中获取和archetype(参考)。
RrdReaderentity_pathrerun-chunk-processing2. Map archetype to view
2. 原型到视图的映射
| Archetype family | View |
|---|---|
| |
| |
| |
| |
| |
| |
| |
| tabular / catalog data | |
| 原型类别 | 视图 |
|---|---|
| |
| |
| |
| |
| |
| |
| |
| 表格/目录数据 | |
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 , or get left out, rather than a pane each.
DataframeView - One spatial frame per spatial view. A whole tree goes in one
Transform3Dat the common ancestor; aSpatial3DViewcamera gets its ownPinholerooted at the camera so images inherit the projection.Spatial2DView - Collapse scalars. Many under a prefix → one
Scalarsover the prefix, not one each. Split only when value ranges clash.TimeSeriesView - /
column_sharesare relative weights on a container's children, equal by default. Tune them from the screenshots.row_shares
这一步只需决定哪些实体共享一个视图。尺寸和布局是你在截图迭代过程中通过视觉调整的细节,无需预先制定规则。
- 按共享路径前缀分组:具有共同前缀的实体通常属于同一个视图。不要给每个实体单独分配一个面板:数十个原始消息实体应放在一个中,或直接忽略,而非每个实体占一个面板。
DataframeView - 每个空间视图对应一个空间坐标系:整个树应放在以共同祖先为根的一个
Transform3D中;Spatial3DView相机应单独使用一个以相机为根的Pinhole,以便图像继承其投影关系。Spatial2DView - 合并标量数据:同一前缀下的多个应合并到一个
Scalars中,而非每个标量单独一个视图。仅当数值范围冲突时才拆分。TimeSeriesView - /
column_shares是容器子元素的相对权重,默认值相等。可通过截图调整这些值。row_shares
4. Construct it
4. 构建蓝图
Containers (, , , ) hold views. Default a flat
set to ; use the others for a deliberate split, for alternatives
competing for one slot (left/right/depth cameras). Always set an explicit
and — defaults to , which dumps the whole tree into
one view (the usual cause of an unreadable blob).
GridHorizontalVerticalTabsGridTabsoriginnameorigin/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/**"]/**Coordinate frames. A spatial view only renders entities it can place relative
to its target frame. / logged on entities compose down the
tree, so is enough. But named frames (,
common in ROS/MCAP) live in a separate frame graph — point the view at a frame
the data occupies via .
The tell is an empty 3D view with "No transform path from …" errors:
targets the root , which connects to nothing if the tf tree
was never materialized. Read the values, target the one
the main 3D content sits in, and exclude entities in unconnected frames.
Transform3DPinholeoriginCoordinateFrame(frame=...)spatial_information=rrb.SpatialInformation(target_frame="<frame>")<frame>origin="/"tf#/CoordinateFrame:frame容器(、、、)用于容纳视图。默认将一组平面视图设为;对于需要刻意拆分的场景,使用其他容器,适用于在同一位置切换的替代视图(如左/右/深度相机)。务必设置明确的和——默认值为,这会将整个树结构放入一个视图中(这通常是导致内容难以阅读的原因)。
GridHorizontalVerticalTabsGridTabsoriginnameorigin/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/**"]/**坐标系:空间视图仅渲染其目标坐标系下可定位的实体。记录在实体上的/会沿树结构组合,因此设置即可。但命名坐标系(,在ROS/MCAP中常见)存在于单独的坐标系图中——需通过将视图指向数据所在的坐标系。如果3D视图为空且显示“No transform path from …”错误,原因在于指向根坐标系,而如果tf树从未实例化,该根坐标系不会与任何内容关联。读取的值,将视图指向主要3D内容所在的坐标系,并排除未连接坐标系中的实体。
Transform3DPinholeoriginCoordinateFrame(frame=...)spatial_information=rrb.SpatialInformation(target_frame="<frame>")<frame>origin="/"tf#/CoordinateFrame:frame5. 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 keeps its own identity, so build the stream from
the rrd's values (set both; otherwise defaults to a random one).
Mismatch either and the viewer keeps blueprint and data as separate recordings
and never applies the blueprint.
.rrdrecording_idpython
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 to /
/ / , or to .
default_blueprint=rr.initspawnconnect_grpcsaveblueprint=notebook_show启动查看器并加载一次录制内容,然后将新的蓝图发送到同一个查看器;每次发送+截图就是一次低成本的迭代。渲染、查看、修改。
蓝图通过存储标识(应用ID和录制ID)与数据绑定。已加载的文件保留自身标识,因此需从rrd的值构建流(同时设置两个ID;否则默认是随机值)。如果任一ID不匹配,查看器会将蓝图和数据视为单独的录制内容,不会应用该蓝图。
.rrdrecording_idpython
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.initspawnconnect_grpcsavedefault_blueprint=notebook_showblueprint=Gotchas
注意事项
- A shows "Unknown timeline" without a query:
DataframeView.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) - views and
rrb(ViewerClient) are unstable. Checkrerun.experimentalif a constructor argument is rejected.help()
- 如果没有设置查询条件,会显示“Unknown timeline”:需设置
DataframeView。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
另请参阅
- — entities, archetypes, timelines.
rerun-data-model - — enumerate entities in a dataset.
rerun-catalog-queries
- —— 实体、原型、时间线。
rerun-data-model - —— 枚举数据集中的实体。
rerun-catalog-queries