Rerun 绘制任意标量数据:用组件映射(Component Mappings)把非 Rerun 语义数据变成时序图
2026/9/16 13:32:25 网站建设 项目流程

Rerun 绘制任意标量数据:用组件映射(Component Mappings)把非 Rerun 语义数据变成时序图

【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun

本文讲解 Rerun 的「任意标量(Any Scalar)」可视化能力:通过组件映射(Component Mappings)将视觉化器(visualizer)的输入重定向到任意组件,从而绘制那些并非以 Rerun 原生语义记录的数值数据——例如来自 MCAP 文件的自定义消息、用DynamicArchetype/AnyValues记录的灵活数据。读完本文,你将掌握VisualizerComponentMapping的四种取值来源(SourceComponent/Override/Default/AnnotationContext)、jq风格嵌套字段选择器(selector)的写法,以及如何在蓝图(blueprint)中为同一实体配置多条曲线,实现「数据建模」与「数据可视化」的彻底解耦。

Rerun 可以将数值数据绘制为时间序列,即使这些数据当初并未以 Rerun 语义记录。通过重新指定视觉化器读取输入的位置(即组件映射),你可以把「如何建模数据」与「如何可视化数据」分开处理:数据仍按你的业务结构记录,而可视化时按需抽取任意字段。这对于绘制 MCAP 中的自定义消息、以及通过AnyValuesDynamicArchetype记录的灵活数据尤其有用。作为额外收益,把多个标量集中记录到同一个实体上,可以显著缩小.rrd文件的体积(降低实体与元数据开销)。

核心机制:视觉化器如何获取输入

在 Rerun Viewer 中,视图(view)负责展示实体,而视图依赖**视觉化器(visualizer)**来渲染每个实体。例如 时序视图 使用SeriesLines视觉化器绘制折线图,3D 视图使用Points3D视觉化器绘制点云(参见 Customize views 中的可视化产生流程)。

每个视觉化器都以若干**组件(component)**作为输入,例如SeriesLines的必填输入是Scalar,可选输入包括NamesColors等。默认情况下,视觉化器从数据存储中自动读取这些组件;当找不到匹配数据时(除位置、标量这类必填组件外),Viewer 会生成合理的默认值。

组件映射正是用来定制这一行为的机制:通过显式配置「目标组件 → 来源组件」,你可以精确控制视觉化器每个输入的数据来源。其核心价值体现在两点:

  • 控制从存储中拾取的数据——这允许你可视化任意数据,即使它没有按照 Rerun 语义记录;
  • 把可视化样式作为蓝图的一部分——例如颜色、名称等可选组件也可以映射到任意来源。

关于视觉化器如何解析组件值的完整背景,可阅读 Customize views;组件映射的通用机制(不限于标量)详见 Component mappings。

支持的数据类型

视觉化器的组件映射对来源数据类型有明确要求,Scalar输入支持以下类型:

  • Float32Float64
  • Int8Int16Int32Int64
  • UInt8UInt16UInt32UInt64
  • Boolean
  • 以上任意类型嵌套在 Arrow struct(StructArray)中

布尔值会被当作 0/1 标量绘制(在 any_scalar 示例 中,is_stable标志就是以步进函数形式绘制的 0/1 曲线)。类型兼容时数据会被自动转换,例如Float32数据会在视觉化器解析时自动转为所需的Float64

记录自定义数据:DynamicArchetype 与 AnyValues

要用组件映射绘制「非 Rerun 语义」的数据,第一步是把它记录到存储中。推荐使用DynamicArchetype发送带有自定义组件名的数据,它可以与常规 Rerun 数据(如Scalars)同时写入同一实体。扁平数组(flat arrays)和 ArrowStructArray两种形式都受支持。

在 docs/snippets/all/howto/component_mapping.py 中,/plot实体除了记录常规正弦标量外,还通过DynamicArchetype.columns记录了两个自定义组件:

# Custom scalar batch with a cos using a custom component name. *rr.DynamicArchetype.columns( archetype="custom", components={"my_custom_scalar": np.cos(times / 10.0)}, ), # Nested custom scalar batch with a sigmoid inside a struct. *rr.DynamicArchetype.columns( archetype="custom", components={"my_nested_scalar": make_sigmoid_struct_array(64)}, ),

对应的 Rust 版本见 docs/snippets/all/howto/component_mapping.rs:

let custom_columns: Vec<_> = rerun::DynamicArchetype::new("custom") .with_component_from_data("my_custom_scalar", cos_array) .as_serialized_batches() .into_iter() .map(|batch| batch.column_of_unit_batches()) .try_collect()?;

数据通过send_columns以列式(columnar)方式批量写入,配合时间列TimeColumn("step", sequence=times)

rr.send_columns( "plot", indexes=[rr.TimeColumn("step", sequence=times)], columns=[ # Regular scalar batch with a sin. *rr.Scalars.columns(scalars=np.sin(times / 10.0)), # ...自定义组件如上 ], )

从源码看,DynamicArchetype(rerun_py/rerun_sdk/rerun/dynamic_archetype.py)是「动态定义的原型」:archetype参数指定原型名,components字典的键作为组件名、值作为组件数据(可以是任意可转为 pyarrow 数组的数据,也可以是 Rerun 批类型)。与之类似的 AnyValues 则直接以关键字参数形式记录任意组件集合。二者都要求:同一组件只能保持单一类型,首次记录的类型将决定后续所有日志的类型。

记录完成后,实体的组件列表中就会同时存在标准组件(如Scalars:scalars)与自定义组件(如custom:my_custom_scalarcustom:my_nested_scalar)。

重映射组件:把 Scalar 输入指向自定义组件

视觉化器可以从任何数据类型兼容的组件获取输入。例如SeriesLines视觉化器对Scalar输入接受任意数值数据——无论它来自 MCAP 文件、AnyValues还是DynamicArchetype。可选组件如NamesColors也可以用同样的方式从任意数据源获取。

下面这段映射把Scalars:scalars输入重定向到custom:my_custom_scalar(见 docs/snippets/all/howto/component_mapping.py):

rr.SeriesLines(names="cosine (custom)").visualizer( mappings=[ # Map scalars to the custom component. VisualizerComponentMapping( target="Scalars:scalars", source_kind=ComponentSourceKind.SourceComponent, # Map from custom component source_component="custom:my_custom_scalar", ), ] )

Rust 等价写法(docs/snippets/all/howto/component_mapping.rs):

rerun::SeriesLines::new() .with_names(["cosine (custom)"]) .visualizer() .with_mappings(vec![ rerun::blueprint::VisualizerComponentMapping::new_source_component( rerun::Scalars::descriptor_scalars().component, "custom:my_custom_scalar", ) .into(), ]),

映射的四个字段

VisualizerComponentMapping是蓝图编码类型(encoding),其 Python 定义位于 rerun_py/rerun_sdk/rerun/blueprint/encodings/visualizer_component_mapping.py,四个字段的含义如下:

字段含义
target映射的目标组件名,即视觉化器上的输入「插槽」,例如Scalars:scalarsSeriesLines:colors
source_kind取值的来源类型(见下文四种枚举值)
source_component来源组件选择器;未指定时默认等于target
selector可选的jq风格选择器字符串,用于从source_component中挑选具体字段;例如.x表示取名为x的字段;未指定时默认为空字符串

映射在 Arrow 层面对应一个 struct 批(pa.struct([...])),source_kind编码为uint8,其余三个字段为 UTF-8 字符串。

四种取值来源:ComponentSourceKind

source_kindComponentSourceKind枚举(rerun_py/rerun_sdk/rerun/blueprint/encodings/component_source_kind.py),共四个变体:

  • SourceComponent(1):使用source_component显式选定的组件,可搭配selector字符串使用。注意:若所选源组件在实体上不存在,会报错。
  • Override(2):使用蓝图中定义的无时间(timeless)覆盖值,覆盖值存储在视觉化器指令所在实体上、以target作为组件名。若目标组件没有对应的覆盖值,会报错。
  • Default(3):使用视图蓝图上指定的默认值;若视图未为目标组件指定默认值,则使用启发式确定的值。
  • AnnotationContext(4):根据记录(recording)的标注上下文,从类别 ID 和关键点 ID 解析值;若标注上下文没有提供值,则回退到默认值(目标组件的记录值被忽略)。仅对支持标注上下文的视觉化器可用,用于不支持的组件会报错。

Rust 侧对应的四个构造器见 crates/store/re_sdk_types/src/blueprint/encodings/visualizer_component_mapping_ext.rs:new_defaultnew_source_componentnew_source_component_with_selectornew_override

注意,组件映射 API 仍处于演进阶段:Python 文档字符串与示例头部均标注了TODO(#12600)(参见 docs/snippets/all/howto/component_mapping.py),未来可能发生变化。

交互式添加:拖拽组件到时序视图

除了通过蓝图 API 编写映射,你也可以完全在 Viewer 界面中完成设置:

从流树(streams tree)中把一个组件拖拽到时序视图上。如果该组件具有兼容的(数值)数据类型,就会新增一个SeriesLines视觉化器,并把Scalars:scalars重映射到该组件。非数值组件(例如字符串)会被拒绝;已经由该视图绘制的组件再次拖入也会被拒绝。

具体而言,在 UI 中还可以展开视觉化器的某个组件行,从其Source下拉菜单切换不同的输入表示(自动、来源组件、自定义值等),详见 Customize views 与 Component mappings 的界面操作说明。

嵌套数据与选择器:jq 风格语法

当数据位于 ArrowStructArray内部时,需要用**选择器(selector)**抽取特定字段。选择器采用受jq启发的语法,例如.values选择名为values的字段。

首先创建嵌套的StructArray(docs/snippets/all/howto/component_mapping.py):

def make_sigmoid_struct_array(steps: int) -> pa.StructArray: """Creates a StructArray with a `values` field containing sigmoid data. Note: We intentionally use float32 here to demonstrate that the data will be automatically cast to the correct type (float64) when resolved by the visualizer. """ x = np.arange(steps, dtype=np.float32) / 10.0 sigmoid_values = 1.0 / (1.0 + np.exp(-(x - 3.0))) return pa.StructArray.from_arrays( [pa.array(sigmoid_values, type=pa.float32())], names=["values"] )

Rust 版本使用 Arrow 的StructArray::from(vec![(Field, Array), ...])构造(docs/snippets/all/howto/component_mapping.rs)。这里刻意使用Float32以演示自动类型转换:视觉化器解析时会自动把Float32转为所需的Float64

下面的映射把Scalars:scalars输入重定向到custom:my_nested_scalar,并用选择器.values抽取 struct 中的values字段(docs/snippets/all/howto/component_mapping.py):

rr.SeriesLines( names="sigmoid (nested)", colors=[0, 0, 255] ).visualizer( mappings=[ VisualizerComponentMapping( target="Scalars:scalars", source_kind=ComponentSourceKind.SourceComponent, source_component="custom:my_nested_scalar", selector=".values", ), ] )

Rust 等价写法(docs/snippets/all/howto/component_mapping.rs):

rerun::SeriesLines::new() .with_names(["sigmoid (nested)"]) .with_colors([[0, 0, 255]]) .visualizer() .with_mappings(vec![ rerun::blueprint::VisualizerComponentMapping::new_source_component_with_selector( "Scalars:scalars", "custom:my_nested_scalar", ".values", ) .into(), ]),

深度嵌套:真实项目中的多级选择器

选择器支持任意深度的链式访问。在 any_scalar 示例 中,市场数据演示(market_demo.py)把每个 ticker 的行情记录为单个嵌套结构{"prices": {"close": ..., "normalized": ...}, "details": {"volume": ...}},再用选择器分别绘图:

  • .prices.normalized→ 相对开盘价的涨跌幅(%),用于「相对表现」视图;
  • .prices.close→ 原始收盘价,用于「收盘价」视图。

机器人 PID 演示(robotics_demo.py)同样把每步遥测记录为一个嵌套结构,并用选择器抽出:

  • .state.setpoint.state.position→ 目标轨迹与实际位置;
  • .control.error→ 误差(同一字段同时映射给SeriesLinesSeriesPoints两个视觉化器,分别展示趋势与采样点);
  • .control.effort→ 控制输出(配合interpolation_mode="StepAfter"反映数字控制器在步间保持输出恒定的特性);
  • .status.is_stable→ 布尔稳定标志(0/1 步进曲线)。

可以看到,记录时只记录一份结构化遥测,可视化时通过蓝图选择器自由抽取任意字段,这正是「解耦」的实战体现。

提供默认值:把来源设为 Default

有时需要强制视觉化器使用特定来源类型。将source_kind设为Default会让视觉化器忽略存储中的数据,改用视图蓝图上的默认值:

rr.SeriesLines(names="sine (store)").visualizer( mappings=[ VisualizerComponentMapping( target="SeriesLines:colors", source_kind=ComponentSourceKind.Default, ), ] )

(代码见 docs/snippets/all/howto/component_mapping.py;Rust 对应new_default,见 docs/snippets/all/howto/component_mapping.rs。)

在这个映射中,SeriesLines:colors的来源被明确指定为「视图默认值」:即使实体自身记录了颜色(示例中向/plot记录了静态红色rr.SeriesLines(colors=[255, 0, 0])),这条曲线也会使用视图默认的绿色。映射之外的其他输入(如Scalars:scalars)保持自动行为,继续从存储中读取。

完整示例:三条曲线、三种映射策略

完整示例把三条曲线记录到同一个实体/plot上,并为每条曲线配置不同的组件映射策略:

  1. 正弦(sine):来自标准Scalars组件(存储数据),名称覆盖为 "sine (store)",颜色显式使用视图默认值(Default);
  2. 余弦(cosine):来自自定义组件custom:my_custom_scalarSourceComponent),名称覆盖为 "cosine (custom)",颜色自动使用视图默认值;
  3. Sigmoid(nested):来自嵌套组件custom:my_nested_scalar+ 选择器.valuesSourceComponent+selector),名称覆盖为 "sigmoid (nested)",颜色显式设为蓝色。

这三条曲线通过TimeSeriesView蓝图上的overrides={"plot": [...]}一次性配置(docs/snippets/all/howto/component_mapping.py):

blueprint = rrb.Blueprint( rrb.TimeSeriesView( name="Component Mapping Demo", origin="/", # Set default color for series to blue. defaults=[rr.SeriesLines(colors=[0, 255, 0])], overrides={ # Three line series visualizations for the "plot" entity: "plot": [ rr.SeriesLines(names="sine (store)").visualizer( mappings=[ VisualizerComponentMapping( target="SeriesLines:colors", source_kind=ComponentSourceKind.Default, ), ] ), rr.SeriesLines(names="cosine (custom)").visualizer( mappings=[ VisualizerComponentMapping( target="Scalars:scalars", source_kind=ComponentSourceKind.SourceComponent, source_component="custom:my_custom_scalar", ), ] ), rr.SeriesLines( names="sigmoid (nested)", colors=[0, 0, 255] ).visualizer( mappings=[ VisualizerComponentMapping( target="Scalars:scalars", source_kind=ComponentSourceKind.SourceComponent, source_component="custom:my_nested_scalar", selector=".values", ), ] ), ], }, ), ) rr.send_blueprint(blueprint)

完整可运行的 Python 与 Rust 代码分别在 docs/snippets/all/howto/component_mapping.py 与 docs/snippets/all/howto/component_mapping.rs。运行后,/plot实体上会存在三个SeriesLines视觉化器:选中视图时,选择面板会列出所有已配置的视觉化器概览,三条曲线分别呈现红色正弦(存储标量 + 视图默认色)、绿色余弦(自定义组件标量)、蓝色 Sigmoid(嵌套字段 + 选择器)。

同样的映射机制在 re_view_time_series 的蓝图测试 中有系统性的验证,包括SeriesLines/SeriesPoints视觉化器组合、MarkerShape到标量的映射、颜色/名称目标映射等场景(例如target: SeriesLines::descriptor_colors().component的用法),可作为理解映射目标命名的参考。

限制与注意事项

  • API 演进中:组件映射 API 标注为TODO(#12600)「仍在演进,未来可能变化」,且类型本身标记为 unstable、数据可能不向后兼容(见 visualizer_component_mapping.py 的文档字符串)。
  • 必填组件重映射范围有限:目前只有时序视图(标量)与状态时间线视图(状态值)允许重映射必填组件;其他视觉化器的必填字段仍要求匹配的 Rerun 语义(正确的原型与类型元数据),见 Customize views 中的说明。
  • 来源组件必须存在SourceComponent选择的组件在实体上不存在会报错;Override没有对应覆盖值也是错误。
  • 组件类型必须单一:Rerun 要求同一组件只能保持一种类型,首次记录的类型决定后续类型,跨类型转换由 numpy/arrow 尽力完成,无法转换时会告警(strict 模式下抛异常)。
  • 类型自动转换:数值类型兼容时自动转换(如Float32Float64),但非数值来源(如字符串)无法映射到标量输入。

参考文档

  • Plot any scalar(本文档源)
  • Customize views(视觉化器与视图定制概念)
  • Component mappings(组件映射通用指南)
  • Any Scalar 完整示例(机器人 PID 遥测与实时行情演示)
  • 蓝图编码实现:VisualizerComponentMapping、ComponentSourceKind、Rust 构造器
  • 数据记录工具:DynamicArchetype、AnyValues

【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询