diff --git a/examples/c3d/gait.py b/examples/c3d/gait.py index ecf151b..50d9417 100644 --- a/examples/c3d/gait.py +++ b/examples/c3d/gait.py @@ -5,6 +5,6 @@ show_floor=True, show_force_plates=True, show_forces=True, - down_sampled_forces=False, + down_sampled_forces=True, show_events=False, ) diff --git a/examples/c3d/main.py b/examples/c3d/main.py index 098fae3..e3d28e3 100644 --- a/examples/c3d/main.py +++ b/examples/c3d/main.py @@ -1,3 +1,3 @@ import pyorerun as prr -prr.c3d("example.c3d", show_forces=False, show_events=False) +prr.c3d("example.c3d", show_forces=False, show_events=False, marker_trajectories=True) diff --git a/examples/c3d/running_gait.py b/examples/c3d/running_gait.py index bbb860c..7b566b5 100644 --- a/examples/c3d/running_gait.py +++ b/examples/c3d/running_gait.py @@ -6,5 +6,6 @@ show_force_plates=True, show_forces=True, down_sampled_forces=True, + show_events=False, video=("Running_0002_Oqus_6_15004.avi", "Running_0002_Oqus_9_15003.avi"), ) diff --git a/pyorerun/multi_frame_rate_phase_rerun.py b/pyorerun/multi_frame_rate_phase_rerun.py index fff2adc..1f3ec2b 100644 --- a/pyorerun/multi_frame_rate_phase_rerun.py +++ b/pyorerun/multi_frame_rate_phase_rerun.py @@ -107,6 +107,56 @@ def rerun( ]: rr.log(component, rr.Clear(recursive=False)) + def rerun_with_chunks( + self, name: str = "animation_phase", init: bool = True, clear_last_node: bool = False, notebook: bool = False + ) -> None: + if self.nb_phases == 1: + self.phase_reruns[0].rerun_with_chunks(name, init, clear_last_node, notebook) + return + + if init: + rr.init(f"{name}_{0}", spawn=True if not notebook else False) + + for phase_rerun in self.phase_reruns: + frame = 0 + rr.set_time_seconds("stable_time", phase_rerun.t_span[frame]) + phase_rerun.timeless_components.to_rerun() + phase_rerun.biorbd_models.initialize() + phase_rerun.xp_data.initialize() + + times = [rr.TimeSecondsColumn("stable_time", phase_rerun.t_span)] + + for name, chunk in phase_rerun.xp_data.to_chunk().items(): + rr.send_columns( + name, + times=times, + components=chunk, + ) + + for name, chunk in phase_rerun.biorbd_models.to_chunk().items(): + rr.send_columns( + name, + times=times, + components=chunk, + ) + + # cumulative_frames_in_merged_t_span = self.cumulative_frames_in_merged_t_span + # for frame, (t, idx) in enumerate(zip(self.merged_t_span[1:], self.frame_t_span_idx[1:])): + # rr.set_time_seconds("stable_time", t) + # for i in idx: + # frame_i = cumulative_frames_in_merged_t_span[i][frame + 1] + # self.phase_reruns[i].biorbd_models.to_rerun(frame_i) + # self.phase_reruns[i].xp_data.to_rerun(frame_i) + # + # if clear_last_node: + # for phase_rerun in self.phase_reruns: + # for component in [ + # *phase_rerun.biorbd_models.component_names, + # *phase_rerun.xp_data.component_names, + # *phase_rerun.timeless_components.component_names, + # ]: + # rr.log(component, rr.Clear(recursive=False)) + def calculate_cumulative_frames(id: int, frame_t_span_idx) -> list[int]: """ diff --git a/pyorerun/phase_rerun.py b/pyorerun/phase_rerun.py index c2a57d2..e88aa80 100644 --- a/pyorerun/phase_rerun.py +++ b/pyorerun/phase_rerun.py @@ -223,8 +223,9 @@ def rerun_with_chunks( frame = 0 rr.set_time_seconds("stable_time", self.t_span[frame]) - # self.timeless_components.to_rerun() + self.timeless_components.to_rerun() self.biorbd_models.initialize() + self.xp_data.initialize() times = [rr.TimeSecondsColumn("stable_time", self.t_span)] diff --git a/pyorerun/rrbiomod.py b/pyorerun/rrbiomod.py index 5a5beb5..22426ca 100644 --- a/pyorerun/rrbiomod.py +++ b/pyorerun/rrbiomod.py @@ -21,4 +21,4 @@ def rr_biorbd(biomod: str, q: np.ndarray, tspan: np.ndarray) -> None: phase_rerun = PhaseRerun(tspan) phase_rerun.add_animated_model(model, q) - phase_rerun.rerun() + phase_rerun.rerun_with_chunks() diff --git a/pyorerun/rrc3d.py b/pyorerun/rrc3d.py index 02d5325..177b387 100644 --- a/pyorerun/rrc3d.py +++ b/pyorerun/rrc3d.py @@ -111,10 +111,11 @@ def rrc3d( ) phase_reruns.append(PhaseRerun(time)) - phase_reruns[-1].add_video(vid_name, vid) + phase_reruns[-1].add_video(vid_name, np.array(vid, dtype=np.uint8)) multi_phase_rerun = MultiFrameRatePhaseRerun(phase_reruns) - multi_phase_rerun.rerun(filename, notebook=notebook) + # multi_phase_rerun.rerun(filename, notebook=notebook) + multi_phase_rerun.rerun_with_chunks(filename, notebook=notebook) if show_events: try: diff --git a/pyorerun/xp_components/force_vector.py b/pyorerun/xp_components/force_vector.py index ce6b039..2a1f2ac 100644 --- a/pyorerun/xp_components/force_vector.py +++ b/pyorerun/xp_components/force_vector.py @@ -21,7 +21,7 @@ def nb_components(self): @property def nb_frames(self): - return len(self.vector_origins) + return self.vector_origins.shape[1] def to_component(self, frame: int) -> np.ndarray: return rr.Arrows3D( @@ -30,6 +30,9 @@ def to_component(self, frame: int) -> np.ndarray: colors=np.array([201, 219, 227]), ) + def initialize(self): + pass + def to_rerun(self, frame) -> None: rr.log( self.name, @@ -40,9 +43,9 @@ def to_chunk(self, **kwargs) -> dict[str, list]: return {self.name: [ rr.Arrows3D.indicator(), - rr.components.Vector3DBatch(self.vector_origins), - rr.components.Position3DBatch(self.vector_magnitude), - rr.components.ColorBatch(np.array([201, 219, 227])), + rr.components.Position3DBatch(self.vector_origins.T), + rr.components.Vector3DBatch(self.vector_magnitude.T), + rr.components.ColorBatch([np.array([201, 219, 227]) for _ in range(self.nb_frames)]), ]} diff --git a/pyorerun/xp_components/markers.py b/pyorerun/xp_components/markers.py index 357070e..c241633 100644 --- a/pyorerun/xp_components/markers.py +++ b/pyorerun/xp_components/markers.py @@ -47,6 +47,9 @@ def nb_frames(self): def nb_components(self): return 1 + def initialize(self): + pass + def to_rerun(self, frame: int) -> None: rr.log( self.name, diff --git a/pyorerun/xp_components/timeseries_q.py b/pyorerun/xp_components/timeseries_q.py index 8e0cf19..0b55946 100644 --- a/pyorerun/xp_components/timeseries_q.py +++ b/pyorerun/xp_components/timeseries_q.py @@ -28,6 +28,9 @@ def nb_frames(self): def nb_components(self): return 1 + def initialize(self): + pass + def to_rerun(self, frame: int) -> None: if self.properties.ranges is None: for joint_idx in range(self.nb_q): diff --git a/pyorerun/xp_components/video.py b/pyorerun/xp_components/video.py index ce0ef1f..90aeca5 100644 --- a/pyorerun/xp_components/video.py +++ b/pyorerun/xp_components/video.py @@ -7,22 +7,38 @@ class Video(ExperimentalData): def __init__(self, name: str, video_array: np.ndarray): self.name = name - self.video = video_array + if video_array.dtype != np.uint8: + raise ValueError("Video array should be a np.uint8") + self.video = video_array # shape (nb_frames, nb_vertical_pixels, nb_horizontal_pixels, nb_components) @property def nb_frames(self): return self.video.shape[0] def nb_vertical_pixels(self): - return self.video.shape[2] + return self.video.shape[1] def nb_horizontal_pixels(self): - return self.video.shape[1] + return self.video.shape[2] @property def nb_components(self): return 1 + def initialize(self): + format_static = rr.components.ImageFormat( + width=self.nb_horizontal_pixels(), + height=self.nb_vertical_pixels(), + color_model="RGB", + channel_datatype="U8", + ) + rr.log( + self.name, + [format_static, rr.Image.indicator()], + static=True, + ) + + def to_rerun(self, frame: int) -> None: rr.log( self.name, @@ -36,6 +52,5 @@ def to_component(self, frame: int) -> rr.Image: def to_chunk(self, **kwargs) -> dict[str, list]: return {self.name: [ - rr.Image.indicator(), - rr.components.ImageBufferBatch(self.video), + rr.components.ImageBufferBatch(self.video.reshape(self.nb_frames, -1)), ]} \ No newline at end of file diff --git a/pyorerun/xp_phase.py b/pyorerun/xp_phase.py index 4c1e72a..738056b 100644 --- a/pyorerun/xp_phase.py +++ b/pyorerun/xp_phase.py @@ -10,6 +10,10 @@ def __init__(self, name, phase: int): def add_data(self, xp_data: ExperimentalData): self.xp_data.append(xp_data) + def initialize(self): + for data in self.xp_data: + data.initialize() + def to_rerun(self, frame: int): for data in self.xp_data: data.to_rerun(frame)