Loading...
Loading...
Core mechanics of the Rerun Chunk Processing API (rerun.experimental) — LazyChunkStream pipelines, Chunk, lenses (MutateLens/DeriveLens/Selector), RrdReader, writing optimized RRDs. Read BEFORE writing any ingestion/conversion/preprocessing code (convert an MCAP, build a recording from a dataset, preprocess an .rrd, port an old converter): it mandates reader+lens pipelines and steers away from hand-built chunks — no Chunk.from_columns for data a reader/lens can produce, no per-message rr.log, no manual pa.array assembly. Source-specific knowledge lives in the importer skills (rerun-mcap, rerun-urdf, rerun-parquet, rerun-mp4, rerun-lerobot); read rerun-data-model first to decide what the data should become.
npx skill4agent add rerun-io/rerun rerun-chunk-processingChunkrerun-data-model| Source | Reader | Skill |
|---|---|---|
| MCAP file (ROS2, protobuf, Foxglove) | | |
| URDF robot model (+ joint states → FK) | | |
| Parquet table (trajectories, sensor logs) | | |
| mp4 camera video | | |
| LeRobot dataset directory | built-in importer, then | |
| Existing RRD | | here, below |
| Sidecar files (JSON calib, metadata) | | here, below |
rerun.experimentalpython -c "from rerun.experimental import LazyChunkStream; help(LazyChunkStream)".stream()McapReaderUrdfTreeParquetReaderMp4ReaderRrdReaderlog_file_from_pathTransform3DPinholeVideoStream<Name>:messagererun-mcapMutateLensoutput_mode="forward_unmatched"/tfDeriveLens/tfoutput_mode="forward_all"DeriveLensscatter=Trueoutput_mode="drop_unmatched"robot_data_preprocessingChunk.from_columnsfrom_iterLazyChunkStream.merge(...).collect(optimize=OptimizationProfile.OBJECT_STORE)write_rrd(application_id, recording_id)OBJECT_STOREpa.arrayforSelector(...).pipe(...)rr.initrr.logwrite_rrdchunk.to_record_batch()pc.filterChunk.from_columnsstream.drop(content=...).split(...)MutateLenspa.arraypa.arraypa.RecordBatchnp.frombufferMutateLensDeriveLensrr.send_columnsMcapReaderUrdfTreeChunk.from_columnsPinholeVideoStreamTransform3DMutateLenspyarrow.computepc.filterpc.list_elementpc.*Selector.pipeChunk.from_columnsLazyChunkStreamwrite_rrd(...)collect()to_chunks()filterdroplensesmapflat_mapcollect()ChunkStorestream.collect()ChunkStore.from_chunksLazyStoreRrdReader(path).store()schema()summary()stream()write_rrd(...)from rerun.experimental import Chunk, LazyChunkStream, OptimizationProfilestream.filter(content=, has_timeline=, is_static=, components=)stream.drop(...)contentstream.map(fn)Chunk -> Chunkstream.flat_map(fn)Chunk -> Iterable[Chunk]stream.split(content=, ...)(matching, non_matching)LazyChunkStream.merge(*streams)LazyChunkStream.from_iter(chunks)stream = source_stream() # any importer skill
stream = stream.drop(content="/video_raw/**")
stream = stream.lenses(fix_lens, content="/cam/**", output_mode="forward_unmatched")
merged = LazyChunkStream.merge(stream, sidecar_stream)
merged.write_rrd(out_path, application_id="my_app", recording_id=recording_id)Chunk.from_columnsMcapReaderUrdfTreeParquetReaderrobot_data_preprocessing/tfChunk.from_columns(entity_path, indexes, columns)rr.send_columns(...).columns(...)indexeschunk = Chunk.from_columns(
"/tf_static/robot_offsets",
indexes=[], # static
columns=rr.Transform3D.columns(
translation=translations,
quaternion=quaternions_xyzw,
parent_frame=parents,
child_frame=children,
),
)
sidecar_stream = LazyChunkStream.from_iter([chunk])rr.AnyValues.columns(...)Chunkentity_pathnum_rowsis_statictimeline_namesto_record_batch()format()stream.lenses(lenses, output_mode=..., content=...)MutateLens(component, selector, keep_row_ids=False)DeriveLens(component, output_entity=None, scatter=False).to_component(descriptor, selector).to_timeline(name, "sequence" | "duration_ns" | "timestamp_ns", selector)scatter=Truecontent=drop_unmatcheddrop_unmatchedforward_unmatchedforward_allstream = stream.lenses(
MutateLens(
"Pinhole:resolution",
Selector(".").pipe(
lambda res: pa.array(
[(h, w) for w, h in res.to_pylist()],
type=res.type,
)
),
),
content=["/external/cam_low", "/external/cam_high"],
output_mode="forward_unmatched",
)DeriveLens("schemas.proto.JointState:message", output_entity="/joints_deg/waist").to_component(
rr.Scalars.descriptor_scalars(),
Selector(".joint_positions").pipe(lambda arr: pc.multiply(pc.list_element(arr, 0), 180.0 / math.pi)),
)Selector("<query>")..field[][N]?!|.pipe(fn).execute(array).execute_per_row(array)stream.write_rrd(path, application_id=..., recording_id=...)stream.collect(optimize=OptimizationProfile.OBJECT_STORE).write_rrd(...)OBJECT_STORELIVErecording_idOptimizationProfile.OBJECT_STORErr.logrr.send_columnsRecordingStreamRrdReaderRrdReader(path)recordings()blueprints()StoreEntrykindapplication_idrecording_id.stream(store=entry).store(store=entry)rerun.experimental.send_chunks(chunks, recording=...)ChunkLazyChunkStreamLazyStoreChunkStoreapplication_idrecording_idoutput_modedrop_unmatchedforward_unmatchedLazyChunkStreamsplitcontent=MutateLensrecording_idrerun.experimentalhttps://github.com/rerun-io/rerun/tree/main/examples/python/robot_data_preprocessinghttps://rerun.io/docs/concepts/logging-and-ingestion/chunk-processing-apihttps://rerun.io/docs/concepts/query-and-transform/lenses