Spaces:
Build error
Build error
| #!/usr/bin/env python3 | |
| """ | |
| DI Trajectory Visualizer - Simple version without audio dependencies | |
| """ | |
| import json | |
| import numpy as np | |
| from pathlib import Path | |
| from dataclasses import dataclass | |
| from typing import List | |
| # Use basic imports only | |
| try: | |
| import gradio as gr | |
| GRADIO_AVAILABLE = True | |
| except ImportError: | |
| GRADIO_AVAILABLE = False | |
| import plotly.graph_objects as go | |
| from plotly.subplots import make_subplots | |
| class TrajectoryData: | |
| """Container for trajectory data.""" | |
| timestamps: np.ndarray | |
| camera_x: np.ndarray | |
| camera_y: np.ndarray | |
| camera_z: np.ndarray | |
| left_hand_x: np.ndarray | |
| left_hand_y: np.ndarray | |
| left_hand_z: np.ndarray | |
| right_hand_x: np.ndarray | |
| right_hand_y: np.ndarray | |
| right_hand_z: np.ndarray | |
| left_hand_roll: np.ndarray | |
| left_hand_pitch: np.ndarray | |
| left_hand_yaw: np.ndarray | |
| right_hand_roll: np.ndarray | |
| right_hand_pitch: np.ndarray | |
| right_hand_yaw: np.ndarray | |
| def create_sample_data() -> TrajectoryData: | |
| """Create sample trajectory data for demo.""" | |
| n = 300 # 10 seconds at 30fps | |
| t = np.linspace(0, 10, n) | |
| # Camera moving in a path | |
| camera_x = np.sin(t * 0.5) * 0.5 | |
| camera_y = np.cos(t * 0.3) * 0.3 | |
| camera_z = t * 0.1 | |
| # Left hand | |
| left_hand_x = camera_x + np.sin(t * 2) * 0.3 + 0.2 | |
| left_hand_y = camera_y + np.cos(t * 2) * 0.2 - 0.3 | |
| left_hand_z = camera_z + np.sin(t) * 0.1 | |
| # Right hand | |
| right_hand_x = camera_x + np.sin(t * 2 + np.pi) * 0.3 - 0.2 | |
| right_hand_y = camera_y + np.cos(t * 2 + np.pi) * 0.2 - 0.3 | |
| right_hand_z = camera_z + np.cos(t) * 0.1 | |
| # Orientations | |
| left_hand_roll = np.sin(t * 3) * 30 | |
| left_hand_pitch = np.cos(t * 2) * 20 | |
| left_hand_yaw = np.sin(t * 1.5) * 45 | |
| right_hand_roll = np.sin(t * 3 + 1) * 30 | |
| right_hand_pitch = np.cos(t * 2 + 1) * 20 | |
| right_hand_yaw = np.sin(t * 1.5 + 1) * 45 | |
| return TrajectoryData( | |
| timestamps=t, | |
| camera_x=camera_x, camera_y=camera_y, camera_z=camera_z, | |
| left_hand_x=left_hand_x, left_hand_y=left_hand_y, left_hand_z=left_hand_z, | |
| right_hand_x=right_hand_x, right_hand_y=right_hand_y, right_hand_z=right_hand_z, | |
| left_hand_roll=left_hand_roll, left_hand_pitch=left_hand_pitch, left_hand_yaw=left_hand_yaw, | |
| right_hand_roll=right_hand_roll, right_hand_pitch=right_hand_pitch, right_hand_yaw=right_hand_yaw | |
| ) | |
| def load_from_json(episode_path: str) -> TrajectoryData: | |
| """Load trajectory data from JSON files.""" | |
| path = Path(episode_path) | |
| # Try to load metadata | |
| metadata = {"poses": []} | |
| for meta_file in ["metadata.json", "extracted/metadata.json"]: | |
| meta_path = path / meta_file | |
| if meta_path.exists(): | |
| with open(meta_path) as f: | |
| metadata = json.load(f) | |
| break | |
| # Try to load hands_3d | |
| hands_3d = {"frames": []} | |
| hands_path = path / "hands_3d.json" | |
| if hands_path.exists(): | |
| with open(hands_path) as f: | |
| hands_3d = json.load(f) | |
| # Try to load end_effector | |
| end_effector = {"frames": []} | |
| ee_path = path / "end_effector.json" | |
| if ee_path.exists(): | |
| with open(ee_path) as f: | |
| end_effector = json.load(f) | |
| # Parse frames | |
| frames = metadata.get('frames', metadata.get('poses', [])) | |
| n = max(len(frames), 1) | |
| fps = metadata.get('fps', 30) | |
| timestamps = np.arange(n) / fps | |
| # Camera positions | |
| camera_x, camera_y, camera_z = [], [], [] | |
| for f in frames: | |
| pos = f.get('camera_pose', {}).get('position', f.get('position', [0, 0, 0])) | |
| camera_x.append(pos[0] if len(pos) > 0 else 0) | |
| camera_y.append(pos[1] if len(pos) > 1 else 0) | |
| camera_z.append(pos[2] if len(pos) > 2 else 0) | |
| # Hand positions | |
| hframes = hands_3d.get('frames', []) | |
| left_hand_x = [f.get('left_hand', {}).get('position', [0,0,0])[0] for f in hframes] or [0]*n | |
| left_hand_y = [f.get('left_hand', {}).get('position', [0,0,0])[1] for f in hframes] or [0]*n | |
| left_hand_z = [f.get('left_hand', {}).get('position', [0,0,0])[2] for f in hframes] or [0]*n | |
| right_hand_x = [f.get('right_hand', {}).get('position', [0,0,0])[0] for f in hframes] or [0]*n | |
| right_hand_y = [f.get('right_hand', {}).get('position', [0,0,0])[1] for f in hframes] or [0]*n | |
| right_hand_z = [f.get('right_hand', {}).get('position', [0,0,0])[2] for f in hframes] or [0]*n | |
| # Orientations | |
| eframes = end_effector.get('frames', []) | |
| left_hand_roll = [f.get('left_hand', {}).get('orientation', [0,0,0])[0] for f in eframes] or [0]*n | |
| left_hand_pitch = [f.get('left_hand', {}).get('orientation', [0,0,0])[1] for f in eframes] or [0]*n | |
| left_hand_yaw = [f.get('left_hand', {}).get('orientation', [0,0,0])[2] for f in eframes] or [0]*n | |
| right_hand_roll = [f.get('right_hand', {}).get('orientation', [0,0,0])[0] for f in eframes] or [0]*n | |
| right_hand_pitch = [f.get('right_hand', {}).get('orientation', [0,0,0])[1] for f in eframes] or [0]*n | |
| right_hand_yaw = [f.get('right_hand', {}).get('orientation', [0,0,0])[2] for f in eframes] or [0]*n | |
| return TrajectoryData( | |
| timestamps=np.array(timestamps) if len(timestamps) else np.array([0]), | |
| camera_x=np.array(camera_x) if camera_x else np.array([0]), | |
| camera_y=np.array(camera_y) if camera_y else np.array([0]), | |
| camera_z=np.array(camera_z) if camera_z else np.array([0]), | |
| left_hand_x=np.array(left_hand_x), | |
| left_hand_y=np.array(left_hand_y), | |
| left_hand_z=np.array(left_hand_z), | |
| right_hand_x=np.array(right_hand_x), | |
| right_hand_y=np.array(right_hand_y), | |
| right_hand_z=np.array(right_hand_z), | |
| left_hand_roll=np.array(left_hand_roll), | |
| left_hand_pitch=np.array(left_hand_pitch), | |
| left_hand_yaw=np.array(left_hand_yaw), | |
| right_hand_roll=np.array(right_hand_roll), | |
| right_hand_pitch=np.array(right_hand_pitch), | |
| right_hand_yaw=np.array(right_hand_yaw) | |
| ) | |
| def create_time_series_plot(data: TrajectoryData) -> go.Figure: | |
| """Create 15-subplot visualization.""" | |
| fig = make_subplots( | |
| rows=5, cols=3, | |
| subplot_titles=[ | |
| 'Camera X (m)', 'Camera Y (m)', 'Camera Z (m)', | |
| 'Left Hand X', 'Left Hand Y', 'Left Hand Z', | |
| 'Right Hand X', 'Right Hand Y', 'Right Hand Z', | |
| 'Left Roll', 'Left Pitch', 'Left Yaw', | |
| 'Right Roll', 'Right Pitch', 'Right Yaw', | |
| ], | |
| vertical_spacing=0.06, | |
| horizontal_spacing=0.04 | |
| ) | |
| t = data.timestamps | |
| colors = ['#2563eb', '#dc2626', '#16a34a', '#ea580c', '#9333ea'] | |
| # Row 1: Camera | |
| fig.add_trace(go.Scatter(x=t, y=data.camera_x, line=dict(color=colors[0], width=1), showlegend=False), row=1, col=1) | |
| fig.add_trace(go.Scatter(x=t, y=data.camera_y, line=dict(color=colors[0], width=1), showlegend=False), row=1, col=2) | |
| fig.add_trace(go.Scatter(x=t, y=data.camera_z, line=dict(color=colors[0], width=1), showlegend=False), row=1, col=3) | |
| # Row 2: Left hand position | |
| fig.add_trace(go.Scatter(x=t, y=data.left_hand_x, line=dict(color=colors[1], width=1), showlegend=False), row=2, col=1) | |
| fig.add_trace(go.Scatter(x=t, y=data.left_hand_y, line=dict(color=colors[1], width=1), showlegend=False), row=2, col=2) | |
| fig.add_trace(go.Scatter(x=t, y=data.left_hand_z, line=dict(color=colors[1], width=1), showlegend=False), row=2, col=3) | |
| # Row 3: Right hand position | |
| fig.add_trace(go.Scatter(x=t, y=data.right_hand_x, line=dict(color=colors[2], width=1), showlegend=False), row=3, col=1) | |
| fig.add_trace(go.Scatter(x=t, y=data.right_hand_y, line=dict(color=colors[2], width=1), showlegend=False), row=3, col=2) | |
| fig.add_trace(go.Scatter(x=t, y=data.right_hand_z, line=dict(color=colors[2], width=1), showlegend=False), row=3, col=3) | |
| # Row 4: Left hand orientation | |
| fig.add_trace(go.Scatter(x=t, y=data.left_hand_roll, line=dict(color=colors[3], width=1), showlegend=False), row=4, col=1) | |
| fig.add_trace(go.Scatter(x=t, y=data.left_hand_pitch, line=dict(color=colors[3], width=1), showlegend=False), row=4, col=2) | |
| fig.add_trace(go.Scatter(x=t, y=data.left_hand_yaw, line=dict(color=colors[3], width=1), showlegend=False), row=4, col=3) | |
| # Row 5: Right hand orientation | |
| fig.add_trace(go.Scatter(x=t, y=data.right_hand_roll, line=dict(color=colors[4], width=1), showlegend=False), row=5, col=1) | |
| fig.add_trace(go.Scatter(x=t, y=data.right_hand_pitch, line=dict(color=colors[4], width=1), showlegend=False), row=5, col=2) | |
| fig.add_trace(go.Scatter(x=t, y=data.right_hand_yaw, line=dict(color=colors[4], width=1), showlegend=False), row=5, col=3) | |
| fig.update_layout(height=1000, showlegend=False, title_text="57 Data Streams Visualization") | |
| fig.update_xaxes(title_text="Time (sec)") | |
| return fig | |
| def create_3d_plot(data: TrajectoryData) -> go.Figure: | |
| """Create 3D trajectory plot.""" | |
| fig = go.Figure() | |
| fig.add_trace(go.Scatter3d( | |
| x=data.camera_x, y=data.camera_y, z=data.camera_z, | |
| mode='lines', name='Camera', line=dict(color='#2563eb', width=4) | |
| )) | |
| fig.add_trace(go.Scatter3d( | |
| x=data.left_hand_x, y=data.left_hand_y, z=data.left_hand_z, | |
| mode='lines', name='Left Hand', line=dict(color='#dc2626', width=4) | |
| )) | |
| fig.add_trace(go.Scatter3d( | |
| x=data.right_hand_x, y=data.right_hand_y, z=data.right_hand_z, | |
| mode='lines', name='Right Hand', line=dict(color='#16a34a', width=4) | |
| )) | |
| fig.update_layout( | |
| title='3D Trajectory (World Frame)', | |
| scene=dict(xaxis_title='X', yaxis_title='Y', zaxis_title='Z', aspectmode='data'), | |
| height=600 | |
| ) | |
| return fig | |
| def visualize(source: str): | |
| """Main visualization function.""" | |
| if source == "Sample Data": | |
| data = create_sample_data() | |
| info = "Using generated sample data (10 seconds, 300 frames)" | |
| else: | |
| try: | |
| data = load_from_json(source) | |
| info = f"Loaded from: {source}" | |
| except Exception as e: | |
| data = create_sample_data() | |
| info = f"Error loading data: {e}. Using sample data." | |
| time_series = create_time_series_plot(data) | |
| plot_3d = create_3d_plot(data) | |
| stats = f""" | |
| ## Data Statistics | |
| | Metric | Value | | |
| |--------|-------| | |
| | Duration | {data.timestamps[-1]:.2f} sec | | |
| | Frames | {len(data.timestamps)} | | |
| | Visualized Streams | 15 | | |
| | Total Streams | 57 (including 42 joint positions) | | |
| **Info:** {info} | |
| """ | |
| return time_series, plot_3d, stats | |
| # Gradio Interface | |
| if GRADIO_AVAILABLE: | |
| with gr.Blocks(title="DI Trajectory Visualizer") as demo: | |
| gr.Markdown(""" | |
| # Dynamic Intelligence - Trajectory Visualizer | |
| Visualize 57 data streams from humanoid robot training data. | |
| ### Data Streams | |
| - **Camera**: X, Y, Z position (world frame) | |
| - **Left Hand**: X, Y, Z position + Roll, Pitch, Yaw | |
| - **Right Hand**: X, Y, Z position + Roll, Pitch, Yaw | |
| - **Joints**: 21 keypoints × 2 hands × XYZ (stored, not visualized) | |
| """) | |
| with gr.Row(): | |
| source_input = gr.Dropdown( | |
| choices=["Sample Data"], | |
| value="Sample Data", | |
| label="Data Source" | |
| ) | |
| load_btn = gr.Button("Visualize", variant="primary") | |
| stats_output = gr.Markdown() | |
| with gr.Tabs(): | |
| with gr.TabItem("Time Series (15 plots)"): | |
| time_plot = gr.Plot() | |
| with gr.TabItem("3D View"): | |
| plot_3d = gr.Plot() | |
| load_btn.click( | |
| fn=visualize, | |
| inputs=[source_input], | |
| outputs=[time_plot, plot_3d, stats_output] | |
| ) | |
| # Auto-load sample data | |
| demo.load( | |
| fn=lambda: visualize("Sample Data"), | |
| outputs=[time_plot, plot_3d, stats_output] | |
| ) | |
| demo.launch() | |
| else: | |
| print("Gradio not available. Install with: pip install gradio") | |