import React, { memo, useMemo } from "react"; import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, } from "recharts"; import { NonIndexedLeRobotDatasetRow } from "@lerobot/web"; interface TeleoperatorJointGraphProps { frames: NonIndexedLeRobotDatasetRow[]; refreshTick?: number; } const MAX_POINTS = 5000; export const TeleoperatorJointGraph = memo(function TeleoperatorJointGraph({ frames, refreshTick, }: TeleoperatorJointGraphProps) { // Skip rendering if no frames if (!frames || frames.length === 0) { return null; } // Use hardcoded joint names that match the LeRobot dataset format const jointNames = [ "shoulder_pan", "shoulder_lift", "elbow_flex", "wrist_flex", "wrist_roll", "gripper", ]; // Generate a color palette for the joints const colors = [ "#8884d8", "#82ca9d", "#ffc658", "#ff8042", "#0088fe", "#00C49F", "#FFBB28", "#FF8042", "#a4de6c", "#d0ed57", ]; // Prepare data for the chart - handling arrays const chartData = useMemo( () => frames.map((frame, index) => { // Create base data point with index const dataPoint: any = { name: index, timestamp: frame.timestamp, }; // Add action values (assuming action is an array) if (Array.isArray(frame.action)) { // Map each array index to the corresponding joint name jointNames.forEach((jointName, i) => { if (i < frame.action.length) { dataPoint[`action_${jointName}`] = frame.action[i]; } }); } // Add observation state values (assuming observation.state is an array) if (Array.isArray(frame["observation.state"])) { // Map each array index to the corresponding joint name jointNames.forEach((jointName, i) => { if (i < frame["observation.state"].length) { dataPoint[`state_${jointName}`] = frame["observation.state"][i]; } }); } return dataPoint; }), [frames, refreshTick] ); const limitedData = useMemo(() => { if (!chartData) return [] as typeof chartData; const len = chartData.length; if (len <= MAX_POINTS) return chartData; return chartData.slice(len - MAX_POINTS, len); }, [chartData]); // Create lines for each joint const linesToRender = jointNames.flatMap((jointName) => [ { key: `action_${jointName}`, dataKey: `action_${jointName}`, name: `Action: ${jointName}`, isDotted: true, }, { key: `state_${jointName}`, dataKey: `state_${jointName}`, name: `State: ${jointName}`, isDotted: false, }, ]); return (