Skip to content

Instantly share code, notes, and snippets.

@bllchmbrs
Created December 3, 2025 17:33
Show Gist options
  • Select an option

  • Save bllchmbrs/057a10b4be42b987dda13687b35c0afb to your computer and use it in GitHub Desktop.

Select an option

Save bllchmbrs/057a10b4be42b987dda13687b35c0afb to your computer and use it in GitHub Desktop.
import rerun as rr
from numpy.random import default_rng
def main():
rr.init("step1_hello_rerun", spawn=True)
instructions = """# 🎯 Step 1: Hello, Rerun!
Welcome to your first Rerun visualization!
## What's happening:
1. We initialized Rerun with `rr.init()`
2. We generated random 2D and 3D points with colors and radii
3. We logged both 2D and 3D point clouds to the viewer
4. The viewer automatically opened to show our data
"""
rr.log(
"instructions",
rr.TextDocument(instructions, media_type=rr.MediaType.MARKDOWN),
static=True,
)
rng = default_rng(12345)
n_bubbles = 10
positions_d3 = rng.uniform(-3, 3, size=[n_bubbles, 3])
positions_d2 = positions_d3[:, :2]
colors = rng.uniform(0, 255, size=[n_bubbles, 4])
radii = rng.uniform(0, 1, size=[n_bubbles])
rr.log("points/2d", rr.Points2D(positions_d2, colors=colors, radii=radii))
rr.log("points/3d", rr.Points3D(positions_d3, colors=colors, radii=radii))
if __name__ == "__main__":
main()
import math
import rerun as rr
def new_location(center_x, center_y, x, y, angle):
cos_a = math.cos(angle)
sin_a = math.sin(angle)
# Translate to origin
translated_x = x - center_x
translated_y = y - center_y
# Rotate
new_x = translated_x * cos_a - translated_y * sin_a + center_x
new_y = translated_x * sin_a + translated_y * cos_a + center_y
return new_x, new_y
def main():
rr.init("step2_points_animation_colors", spawn=True)
square_points = [
[0, 0],
[1, 0],
[1, 1],
[0, 1],
]
center = [0.5, 0.5]
point_names = [f"Point_{x}" for x in range(4)]
rr.log(
"animated_square/origin",
rr.Points2D(
[center],
colors=[[0, 0, 0]],
radii=[0.1],
show_labels=True,
labels=["Origin"],
),
static=True,
)
for frame in range(360):
rr.set_time("frame", sequence=frame)
angle = frame * 0.05
rotated_points = []
for point in square_points:
new_x, new_y = new_location(center[0], center[1], point[0], point[1], angle)
rotated_points.append([new_x, new_y])
dynamic_colors = []
for i in range(len(square_points)):
hue = (frame * 2 + i * 90) % 360
c = 1.0
x_color = c * (1 - abs((hue / 60) % 2 - 1))
if 0 <= hue < 60:
r, g, b = c, x_color, 0
elif 60 <= hue < 120:
r, g, b = x_color, c, 0
elif 120 <= hue < 180:
r, g, b = 0, c, x_color
elif 180 <= hue < 240:
r, g, b = 0, x_color, c
elif 240 <= hue < 300:
r, g, b = x_color, 0, c
else:
r, g, b = c, 0, x_color
dynamic_colors.append([int(r * 255), int(g * 255), int(b * 255)])
dynamic_radii = []
for i in range(len(square_points)):
base_size = 0.04
pulse_amplitude = 0.025
pulse_rate = 0.15 + i * 0.03
pulse_factor = math.sin(frame * pulse_rate)
radius = base_size + pulse_amplitude * pulse_factor
dynamic_radii.append(max(radius, 0.01))
rr.log(
"animated_square/points",
rr.Points2D(
rotated_points,
colors=dynamic_colors,
radii=dynamic_radii,
labels=point_names,
show_labels=True,
),
)
for i, (point, name) in enumerate(zip(rotated_points, point_names)):
x, y = point
rr.log(f"position/{name}/x", rr.Scalars(x))
rr.log(f"position/{name}/y", rr.Scalars(y))
rr.log("overall/position/rotation_angle_radians", rr.Scalars(angle))
if __name__ == "__main__":
main()
import math
import numpy as np
import rerun as rr
def main():
rr.init("step3_3d_transforms", spawn=True)
rr.log("/", rr.ViewCoordinates.RIGHT_HAND_Z_UP, static=True)
rr.log("sun", rr.Points3D([0.0, 0.0, 0.0], radii=1.0, colors=[255, 200, 10]))
rr.log("sun/planet", rr.Points3D([0.0, 0.0, 0.0], radii=0.4, colors=[40, 80, 200]))
rr.log(
"sun/planet/moon",
rr.Points3D([0.0, 0.0, 0.0], radii=0.15, colors=[180, 180, 180]),
)
rr.log(
"sun/planet/moon2",
rr.Points3D([0.0, 0.0, 0.0], radii=0.12, colors=[150, 120, 100]),
)
# log the circle
input("Press Enter to continue...")
d_planet = 6.0
d_moon = 1.75
d_moon2_x = 2.5
d_moon2_y = 1.5
angles = np.arange(0.0, 1.01, 0.01) * np.pi * 2
circle = np.array(
[np.sin(angles), np.cos(angles), angles * 0.0], dtype=np.float32
).transpose()
# Create oval path for second moon
oval = np.array(
[np.sin(angles) * d_moon2_x, np.cos(angles) * d_moon2_y, angles * 0.0],
dtype=np.float32,
).transpose()
rr.log(
"sun/planet_path", rr.LineStrips3D(circle * d_planet, colors=[100, 100, 255])
)
rr.log(
"sun/planet/moon_path", rr.LineStrips3D(circle * d_moon, colors=[200, 200, 200])
)
rr.log("sun/planet/moon2_path", rr.LineStrips3D(oval, colors=[150, 120, 100]))
# log the circle
input("Press Enter to continue...")
total_frames = 6 * 360
for frame in range(total_frames):
time = frame / 120.0
r_planet = time * 2.0
r_moon = time * 5.0
r_moon2 = time * 3.5
planet_x = math.sin(r_planet) * d_planet
planet_y = math.cos(r_planet) * d_planet
planet_z = 0.0
rr.log(
"sun/planet",
rr.Transform3D(
translation=[planet_x, planet_y, planet_z],
rotation=rr.RotationAxisAngle(axis=(1, 0, 0), degrees=20),
),
)
moon_x = math.cos(r_moon) * d_moon
moon_y = math.sin(r_moon) * d_moon
moon_z = 0.0
rr.log(
"sun/planet/moon",
rr.Transform3D(
translation=[moon_x, moon_y, moon_z],
relation=rr.TransformRelation.ChildFromParent,
),
)
moon2_x = math.sin(r_moon2) * d_moon2_x
moon2_y = math.cos(r_moon2) * d_moon2_y
moon2_z = 0.0
rr.log(
"sun/planet/moon2",
rr.Transform3D(
translation=[moon2_x, moon2_y, moon2_z],
relation=rr.TransformRelation.ChildFromParent,
),
)
if frame == 0:
input("Press Enter to continue...")
if __name__ == "__main__":
main()
from __future__ import annotations
import argparse
import os
import tarfile
from pathlib import Path
import numpy as np
import pandas as pd
import requests
import rerun as rr
from rerun import blueprint as rrb
from tqdm.auto import tqdm
DATA_DIR = Path(__file__).parent / "dataset"
DATASET_URL = "https://storage.googleapis.com/rerun-example-datasets/imu_signals/tum_vi_corridor4_512_16.tar"
DATASET_NAME = "dataset-corridor4_512_16"
XYZ_AXIS_NAMES = ["x", "y", "z"]
XYZ_AXIS_COLORS = [[(231, 76, 60), (39, 174, 96), (52, 120, 219)]]
def main() -> None:
dataset_path = DATA_DIR / DATASET_NAME
if not dataset_path.exists():
_download_dataset(DATA_DIR)
parser = argparse.ArgumentParser(
description="Visualizes the TUM Visual-Inertial dataset using the Rerun SDK."
)
parser.add_argument(
"--seconds",
type=float,
default=float("inf"),
help="If specified, limits the number of seconds logged",
)
rr.script_add_args(parser)
args = parser.parse_args()
blueprint = rrb.Horizontal(
rrb.Vertical(
rrb.TimeSeriesView(
origin="gyroscope",
name="Gyroscope",
overrides={
"/gyroscope": rr.SeriesLines.from_fields(
names=XYZ_AXIS_NAMES, colors=XYZ_AXIS_COLORS
),
},
),
rrb.TimeSeriesView(
origin="accelerometer",
name="Accelerometer",
overrides={
"/accelerometer": rr.SeriesLines.from_fields(
names=XYZ_AXIS_NAMES, colors=XYZ_AXIS_COLORS
),
},
),
),
rrb.Spatial3DView(origin="/", name="World position"),
column_shares=[0.45, 0.55],
)
rr.script_setup(args, "rerun_example_imu_signals", default_blueprint=blueprint)
_log_imu_data(args.seconds)
_log_image_data(args.seconds)
_log_gt_imu(args.seconds)
def _download_dataset(root: Path, dataset_url: str = DATASET_URL) -> None:
os.makedirs(root, exist_ok=True)
tar_path = os.path.join(root, f"{DATASET_NAME}.tar")
response = requests.get(dataset_url, stream=True)
total_size = int(response.headers.get("content-length", 0))
block_size = 1024
with tqdm(
desc="Downloading dataset", total=total_size, unit="B", unit_scale=True
) as pb:
with open(tar_path, "wb") as file:
for data in response.iter_content(chunk_size=block_size):
pb.update(len(data))
file.write(data)
if total_size != 0 and pb.n != total_size:
raise RuntimeError("Failed to download complete dataset!")
print("Extracting dataset…")
with tarfile.open(tar_path, "r:") as tar:
tar.extractall(path=root)
os.remove(tar_path)
def _log_imu_data(max_time_sec: float) -> None:
imu_data = pd.read_csv(
DATA_DIR / DATASET_NAME / "dso/imu.txt",
sep=" ",
header=0,
names=[
"timestamp",
"gyro.x",
"gyro.y",
"gyro.z",
"accel.x",
"accel.y",
"accel.z",
],
comment="#",
)
timestamps = imu_data["timestamp"].to_numpy()
max_time_ns = imu_data["timestamp"][0] + max_time_sec * 1e9
selected = imu_data[imu_data["timestamp"] <= max_time_ns]
timestamps = selected["timestamp"].astype("datetime64[ns]")
times = rr.TimeColumn("timestamp", timestamp=timestamps)
gyro = selected[["gyro.x", "gyro.y", "gyro.z"]].to_numpy()
rr.send_columns(
"/gyroscope", indexes=[times], columns=rr.Scalars.columns(scalars=gyro)
)
accel = selected[["accel.x", "accel.y", "accel.z"]]
rr.send_columns(
"/accelerometer", indexes=[times], columns=rr.Scalars.columns(scalars=accel)
)
def _log_image_data(max_time_sec: float) -> None:
times = pd.read_csv(
DATA_DIR / DATASET_NAME / "dso/cam0/times.txt",
sep=" ",
header=0,
names=["filename", "timestamp", "exposure_time"],
comment="#",
dtype={"filename": str},
)
rr.set_time("timestamp", timestamp=times["timestamp"][0])
rr.log(
"/world",
rr.Transform3D(
rotation_axis_angle=rr.RotationAxisAngle(axis=(1, 0, 0), angle=-np.pi / 2)
),
static=True,
)
rr.log(
"/world/cam0",
rr.Pinhole(
focal_length=(0.373 * 512, 0.373 * 512),
resolution=(512, 512),
image_plane_distance=0.4,
),
static=True,
)
max_time_sec = times["timestamp"][0] + max_time_sec
for _, (filename, timestamp, _) in times.iterrows():
if timestamp > max_time_sec:
break
image_path = DATA_DIR / DATASET_NAME / "dso/cam0/images" / f"{filename}.png"
rr.set_time("timestamp", timestamp=timestamp)
rr.log("/world/cam0/image", rr.EncodedImage(path=image_path))
def _log_gt_imu(max_time_sec: float) -> None:
gt_imu = pd.read_csv(
DATA_DIR / DATASET_NAME / "dso/gt_imu.csv",
sep=",",
header=0,
names=["timestamp", "t.x", "t.y", "t.z", "q.w", "q.x", "q.y", "q.z"],
comment="#",
)
timestamps = gt_imu["timestamp"].to_numpy()
max_time_ns = gt_imu["timestamp"][0] + max_time_sec * 1e9
selected = gt_imu[gt_imu["timestamp"] <= max_time_ns]
timestamps = selected["timestamp"].astype("datetime64[ns]")
times = rr.TimeColumn("timestamp", timestamp=timestamps)
translations = selected[["t.x", "t.y", "t.z"]]
quaternions = selected[
[
"q.x",
"q.y",
"q.z",
"q.w",
]
]
rr.send_columns(
"/world/cam0",
indexes=[times],
columns=rr.Transform3D.columns(
translation=translations,
quaternion=quaternions,
),
)
if __name__ == "__main__":
main()
import math
import time
import rerun as rr
def main():
rr.init("step4_multiple_timelines", recording_id="example_timeline")
# expects to be run from the gentle-intro directory
rr.save("data/example_timeline/step4.rrd")
start_time = time.time()
for frame in range(60):
current_time = start_time + frame * 0.1
rr.set_time("imu_time", sequence=frame)
rr.set_time("simulation_time", timestamp=current_time)
imu_angle_x = frame * 0.08
imu_angle_y = frame * 0.05
imu_angle_z = frame * 0.12
orientation_points = []
for i in range(3):
x = i * 0.5 - 0.5
y = math.sin(imu_angle_x) * 0.3
z = math.cos(imu_angle_y) * 0.3
new_x = x * math.cos(imu_angle_z) - y * math.sin(imu_angle_z)
new_y = x * math.sin(imu_angle_z) + y * math.cos(imu_angle_z)
orientation_points.append([new_x, new_y, z])
rr.log(
"drone/imu_orientation",
rr.Points3D(orientation_points, colors=[[255, 100, 100]], radii=0.08),
)
if frame % 5 == 0:
gps_frame = frame // 5
rr.set_time("gps_time", sequence=gps_frame)
rr.set_time("simulation_time", timestamp=current_time)
gps_angle = gps_frame * 0.3
gps_x = math.cos(gps_angle) * 2
gps_y = math.sin(gps_angle) * 2
gps_z = 0.5 + math.sin(gps_frame * 0.2) * 0.3
rr.log(
"drone/gps_position",
rr.Points3D(
[[gps_x, gps_y, gps_z]], colors=[[100, 255, 100]], radii=0.12
),
)
if frame % 10 == 0:
obstacle_frame = frame // 10
rr.set_time("obstacle_time", sequence=obstacle_frame)
rr.set_time("simulation_time", timestamp=current_time)
obstacle_points = []
obstacle_colors = []
for i in range(3):
obs_angle = obstacle_frame * 0.4 + i * 2.1
obs_distance = 3 + i * 0.5
obs_x = math.cos(obs_angle) * obs_distance
obs_y = math.sin(obs_angle) * obs_distance
obs_z = 0.2 + i * 0.3
obstacle_points.append([obs_x, obs_y, obs_z])
obstacle_colors.append([255, 150, 50])
rr.log(
"environment/detected_obstacles",
rr.Points3D(obstacle_points, colors=obstacle_colors, radii=0.15),
)
rr.set_time("frame", sequence=frame)
if __name__ == "__main__":
main()
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
rerun data/droid-example.rrd
rerun server -d data/droid
rerun rerun+http://localhost:51234
rerun data/droid/droid-example.rrd data/droid/droid-blueprint.rbl
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment