pepijn223 HF Staff commited on
Commit
f32c7fc
·
unverified ·
1 Parent(s): d22edc0
src/app/[org]/[dataset]/[episode]/episode-viewer.tsx CHANGED
@@ -1,6 +1,13 @@
1
  "use client";
2
 
3
- import { useState, useEffect, useRef, lazy, Suspense, useCallback } from "react";
 
 
 
 
 
 
 
4
  import { useRouter, useSearchParams } from "next/navigation";
5
  import { postParentMessageWithParams } from "@/utils/postParentMessage";
6
  import { SimpleVideosPlayer } from "@/components/simple-videos-player";
 
1
  "use client";
2
 
3
+ import {
4
+ useState,
5
+ useEffect,
6
+ useRef,
7
+ lazy,
8
+ Suspense,
9
+ useCallback,
10
+ } from "react";
11
  import { useRouter, useSearchParams } from "next/navigation";
12
  import { postParentMessageWithParams } from "@/utils/postParentMessage";
13
  import { SimpleVideosPlayer } from "@/components/simple-videos-player";
src/app/[org]/[dataset]/[episode]/fetch-data.ts CHANGED
@@ -209,7 +209,9 @@ function pickProgressColumn(rows: Record<string, unknown>[]): string | null {
209
  const candidates = [...preferred, ...additionalProgressColumns];
210
 
211
  for (const column of candidates) {
212
- const hasFiniteValue = rows.some((row) => toFiniteNumber(row[column]) !== null);
 
 
213
  if (hasFiniteValue) {
214
  return column;
215
  }
@@ -260,13 +262,17 @@ async function loadEpisodeProgressGroup(
260
  if (orderedPoints.length === 0) continue;
261
  orderedPoints.sort((a, b) => a.order - b.order);
262
 
263
- const sampledPoints = evenlySampleArray(orderedPoints, MAX_EPISODE_POINTS);
 
 
 
264
  const progressKey = buildProgressSeriesKey(progressColumn);
265
  const denominator = Math.max(sampledPoints.length - 1, 1);
266
  const duration = Math.max(episodeDuration, 0);
267
 
268
  return sampledPoints.map((point, idx) => ({
269
- timestamp: sampledPoints.length === 1 ? 0 : (idx / denominator) * duration,
 
270
  [progressKey]: point.progress,
271
  }));
272
  } catch {
 
209
  const candidates = [...preferred, ...additionalProgressColumns];
210
 
211
  for (const column of candidates) {
212
+ const hasFiniteValue = rows.some(
213
+ (row) => toFiniteNumber(row[column]) !== null,
214
+ );
215
  if (hasFiniteValue) {
216
  return column;
217
  }
 
262
  if (orderedPoints.length === 0) continue;
263
  orderedPoints.sort((a, b) => a.order - b.order);
264
 
265
+ const sampledPoints = evenlySampleArray(
266
+ orderedPoints,
267
+ MAX_EPISODE_POINTS,
268
+ );
269
  const progressKey = buildProgressSeriesKey(progressColumn);
270
  const denominator = Math.max(sampledPoints.length - 1, 1);
271
  const duration = Math.max(episodeDuration, 0);
272
 
273
  return sampledPoints.map((point, idx) => ({
274
+ timestamp:
275
+ sampledPoints.length === 1 ? 0 : (idx / denominator) * duration,
276
  [progressKey]: point.progress,
277
  }));
278
  } catch {
src/app/[org]/[dataset]/[episode]/page.tsx CHANGED
@@ -25,11 +25,7 @@ export default async function EpisodePage({
25
  const episodeNumber = Number(episode.replace(/^episode_/, ""));
26
  return (
27
  <Suspense fallback={null}>
28
- <EpisodeViewer
29
- org={org}
30
- dataset={dataset}
31
- episodeId={episodeNumber}
32
- />
33
  </Suspense>
34
  );
35
  }
 
25
  const episodeNumber = Number(episode.replace(/^episode_/, ""));
26
  return (
27
  <Suspense fallback={null}>
28
+ <EpisodeViewer org={org} dataset={dataset} episodeId={episodeNumber} />
 
 
 
 
29
  </Suspense>
30
  );
31
  }
src/components/data-recharts.tsx CHANGED
@@ -1,6 +1,6 @@
1
  "use client";
2
 
3
- import { useEffect, useState } from "react";
4
  import { useTime } from "../context/time-context";
5
  import {
6
  LineChart,
@@ -20,8 +20,6 @@ type DataGraphProps = {
20
  onChartsReady?: () => void;
21
  };
22
 
23
- import React, { useMemo } from "react";
24
-
25
  const SERIES_NAME_DELIMITER = " | ";
26
 
27
  const CHART_COLORS = [
@@ -158,42 +156,45 @@ const SingleDataGraph = React.memo(
158
  tall?: boolean;
159
  }) => {
160
  const { currentTime, setCurrentTime } = useTime();
161
- function flattenRow(
162
- row: Record<string, number | Record<string, number>>,
163
- prefix = "",
164
- ): Record<string, number> {
165
- const result: Record<string, number> = {};
166
- for (const [key, value] of Object.entries(row)) {
167
- // Special case: if this is a group value that is a primitive, assign to prefix.key
168
- if (typeof value === "number") {
169
- if (prefix) {
170
- result[`${prefix}${SERIES_NAME_DELIMITER}${key}`] = value;
171
- } else {
172
- result[key] = value;
 
 
 
 
 
 
 
 
 
 
 
 
173
  }
174
- } else if (
175
- value !== null &&
176
- typeof value === "object" &&
177
- !Array.isArray(value)
178
- ) {
179
- // If it's an object, recurse
180
- Object.assign(
181
- result,
182
- flattenRow(
183
- value,
184
- prefix ? `${prefix}${SERIES_NAME_DELIMITER}${key}` : key,
185
- ),
186
- );
187
  }
188
- }
189
- if ("timestamp" in row && typeof row["timestamp"] === "number") {
190
- result["timestamp"] = row["timestamp"];
191
- }
192
- return result;
193
- }
 
194
 
195
  // Flatten all rows for recharts
196
- const chartData = useMemo(() => data.map((row) => flattenRow(row)), [data]);
 
 
 
197
  const [dataKeys, setDataKeys] = useState<string[]>([]);
198
  const [visibleKeys, setVisibleKeys] = useState<string[]>([]);
199
 
@@ -205,25 +206,27 @@ const SingleDataGraph = React.memo(
205
  setVisibleKeys(keys);
206
  }, [chartData]);
207
 
208
- // Parse dataKeys into groups (dot notation)
209
- const groups: Record<string, string[]> = {};
210
- const singles: string[] = [];
211
- dataKeys.forEach((key) => {
212
- const parts = key.split(SERIES_NAME_DELIMITER);
213
- if (parts.length > 1) {
214
- const group = parts[0];
215
- if (!groups[group]) groups[group] = [];
216
- groups[group].push(key);
217
- } else {
218
- singles.push(key);
219
- }
220
- });
221
 
222
- const allGroups = [...Object.keys(groups), ...singles];
223
- const groupColorMap: Record<string, string> = {};
224
- allGroups.forEach((group, idx) => {
225
- groupColorMap[group] = CHART_COLORS[idx % CHART_COLORS.length];
226
- });
 
 
227
 
228
  // Find the closest data point to the current time for highlighting
229
  const findClosestDataIndex = (time: number) => {
@@ -254,26 +257,6 @@ const SingleDataGraph = React.memo(
254
  );
255
  const currentData = chartData[closestIndex] || {};
256
 
257
- // Parse dataKeys into groups (dot notation)
258
- const groups: Record<string, string[]> = {};
259
- const singles: string[] = [];
260
- dataKeys.forEach((key) => {
261
- const parts = key.split(SERIES_NAME_DELIMITER);
262
- if (parts.length > 1) {
263
- const group = parts[0];
264
- if (!groups[group]) groups[group] = [];
265
- groups[group].push(key);
266
- } else {
267
- singles.push(key);
268
- }
269
- });
270
-
271
- const allGroups = [...Object.keys(groups), ...singles];
272
- const groupColorMap: Record<string, string> = {};
273
- allGroups.forEach((group, idx) => {
274
- groupColorMap[group] = CHART_COLORS[idx % CHART_COLORS.length];
275
- });
276
-
277
  const isGroupChecked = (group: string) =>
278
  groups[group].every((k) => visibleKeys.includes(k));
279
  const isGroupIndeterminate = (group: string) =>
 
1
  "use client";
2
 
3
+ import React, { useCallback, useEffect, useMemo, useState } from "react";
4
  import { useTime } from "../context/time-context";
5
  import {
6
  LineChart,
 
20
  onChartsReady?: () => void;
21
  };
22
 
 
 
23
  const SERIES_NAME_DELIMITER = " | ";
24
 
25
  const CHART_COLORS = [
 
156
  tall?: boolean;
157
  }) => {
158
  const { currentTime, setCurrentTime } = useTime();
159
+ const flattenRow = useCallback(
160
+ (row: Record<string, number | Record<string, number>>, prefix = "") => {
161
+ const result: Record<string, number> = {};
162
+ for (const [key, value] of Object.entries(row)) {
163
+ // Special case: if this is a group value that is a primitive, assign to prefix.key
164
+ if (typeof value === "number") {
165
+ if (prefix) {
166
+ result[`${prefix}${SERIES_NAME_DELIMITER}${key}`] = value;
167
+ } else {
168
+ result[key] = value;
169
+ }
170
+ } else if (
171
+ value !== null &&
172
+ typeof value === "object" &&
173
+ !Array.isArray(value)
174
+ ) {
175
+ // If it's an object, recurse
176
+ Object.assign(
177
+ result,
178
+ flattenRow(
179
+ value,
180
+ prefix ? `${prefix}${SERIES_NAME_DELIMITER}${key}` : key,
181
+ ),
182
+ );
183
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  }
185
+ if ("timestamp" in row && typeof row["timestamp"] === "number") {
186
+ result["timestamp"] = row["timestamp"];
187
+ }
188
+ return result;
189
+ },
190
+ [],
191
+ );
192
 
193
  // Flatten all rows for recharts
194
+ const chartData = useMemo(
195
+ () => data.map((row) => flattenRow(row)),
196
+ [data, flattenRow],
197
+ );
198
  const [dataKeys, setDataKeys] = useState<string[]>([]);
199
  const [visibleKeys, setVisibleKeys] = useState<string[]>([]);
200
 
 
206
  setVisibleKeys(keys);
207
  }, [chartData]);
208
 
209
+ const { groups, singles, groupColorMap } = useMemo(() => {
210
+ const grouped: Record<string, string[]> = {};
211
+ const singleList: string[] = [];
212
+ dataKeys.forEach((key) => {
213
+ const parts = key.split(SERIES_NAME_DELIMITER);
214
+ if (parts.length > 1) {
215
+ const group = parts[0];
216
+ if (!grouped[group]) grouped[group] = [];
217
+ grouped[group].push(key);
218
+ } else {
219
+ singleList.push(key);
220
+ }
221
+ });
222
 
223
+ const allGroups = [...Object.keys(grouped), ...singleList];
224
+ const colorMap: Record<string, string> = {};
225
+ allGroups.forEach((group, idx) => {
226
+ colorMap[group] = CHART_COLORS[idx % CHART_COLORS.length];
227
+ });
228
+ return { groups: grouped, singles: singleList, groupColorMap: colorMap };
229
+ }, [dataKeys]);
230
 
231
  // Find the closest data point to the current time for highlighting
232
  const findClosestDataIndex = (time: number) => {
 
257
  );
258
  const currentData = chartData[closestIndex] || {};
259
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
  const isGroupChecked = (group: string) =>
261
  groups[group].every((k) => visibleKeys.includes(k));
262
  const isGroupIndeterminate = (group: string) =>
src/components/urdf-viewer.tsx CHANGED
@@ -542,7 +542,10 @@ export default function URDFViewer({
542
 
543
  const [selectedGroup, setSelectedGroup] = useState(defaultGroup);
544
  useEffect(() => setSelectedGroup(defaultGroup), [defaultGroup]);
545
- const selectedColumns = columnGroups[selectedGroup] ?? [];
 
 
 
546
 
547
  // Joint mapping
548
  const autoMapping = useMemo(
@@ -640,7 +643,7 @@ export default function URDFViewer({
640
  }
641
  }
642
  return values;
643
- }, [chartData, frame, mapping, totalFrames, urdfJointNames]);
644
 
645
  const currentTime = totalFrames > 0 ? (frame / fps).toFixed(2) : "0.00";
646
  const totalTime = (totalFrames / fps).toFixed(2);
 
542
 
543
  const [selectedGroup, setSelectedGroup] = useState(defaultGroup);
544
  useEffect(() => setSelectedGroup(defaultGroup), [defaultGroup]);
545
+ const selectedColumns = useMemo(
546
+ () => columnGroups[selectedGroup] ?? [],
547
+ [columnGroups, selectedGroup],
548
+ );
549
 
550
  // Joint mapping
551
  const autoMapping = useMemo(
 
643
  }
644
  }
645
  return values;
646
+ }, [chartData, frame, gripperRanges, mapping, totalFrames, urdfJointNames]);
647
 
648
  const currentTime = totalFrames > 0 ? (frame / fps).toFixed(2) : "0.00";
649
  const totalTime = (totalFrames / fps).toFixed(2);