Skip to content

Signal Visualizer ​

The Signal Visualizer displays real-time scrolling PPG and respiratory waveform data alongside the camera feed. It provides immediate visual feedback about signal quality and measurement stability.

How It Works ​

During realtime estimation, the SDK continuously processes video frames to extract physiological signals. The Signal Visualizer captures this signal data and renders a scrolling waveform chart that updates with each processed frame. Multiple signal channels can be displayed simultaneously with customizable colors.

Configuration ​

The Signal Visualizer is created as a standalone component and connected to the camera's frame processing callback. It renders into any HTML container element.

typescript
import { createVitalSignCamera, SignalVisualizer } from 'ts-vital-sign-camera';

const camera = createVitalSignCamera({
  userId: 'user-123',
  apiKey: 'your-api-key',
  enableRealtimeEstimation: true
});

// Create the visualizer with a container element
const visualizer = new SignalVisualizer(
  document.getElementById('signal-chart'),  // Container element
  {
    signalColors: ['#ff6b6b', '#4ecdc4'],  // Colors for each signal channel
    windowSeconds: 10,                      // Display window size (default: 10)
    pixelsPerSecond: 60,                    // Horizontal resolution (default: 60)
    height: 200,                            // Chart height in pixels (default: 200)
    lineWidth: 2,                           // Stroke width (default: 2)
    backgroundColor: '#1a1a2e',             // Background color
    gridColor: '#16213e',                   // Grid line color
    enableAutoScale: true,                  // Auto-adjust Y-axis (default: true)
    yAxisMin: -1.5,                         // Fixed Y-axis minimum (autoScale: false)
    yAxisMax: 1.5,                          // Fixed Y-axis maximum (autoScale: false)
    showLegend: true,                       // Channel label legend (default: false)
    enableLowPassFilter: true,              // Noise reduction filter (default: false)
    lowPassFilterCutoff: 5,                 // Filter cutoff in Hz (default: 5)
    showGrid: true,                         // Grid lines (default: true)
    label: 'PPG Waveform',                  // Chart label string
  }
);

// Connect visualizer to frame processing
camera.visualizer = visualizer;

// Alternative: manual connection via callback
camera.onVideoFrameProcessed = (event) => {
  if (event.signalData) {
    visualizer.updateSignal(event.signalData, event.realtimeEstimation);
  }
};
tsx
import { VitalSignCamera, SignalVisualizer } from 'react-vital-sign-camera';
import { useEffect, useRef } from 'react';

const App = () => {
  const chartRef = useRef(null);
  const visualizerRef = useRef(null);

  useEffect(() => {
    if (chartRef.current) {
      visualizerRef.current = new SignalVisualizer(chartRef.current, {
        signalColors: ['#ff6b6b'],
        windowSeconds: 8,
        height: 180
      });
    }
    return () => visualizerRef.current?.destroy();
  }, []);

  return (
    <div>
      <VitalSignCamera
        enableRealtimeEstimation={true}
        visualizer={visualizerRef.current}
      />
      <div ref={chartRef} />
    </div>
  );
};
vue
<template>
  <div>
    <VitalSignCamera
      :enableRealtimeEstimation="true"
      :visualizer="visualizer"
    />
    <div ref="chartContainer" class="signal-chart" />
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import { SignalVisualizer } from 'ts-vital-sign-camera';

const chartContainer = ref(null);
const visualizer = ref(null);

onMounted(() => {
  visualizer.value = new SignalVisualizer(chartContainer.value, {
    signalColors: ['#4ecdc4', '#ff6b6b'],
    windowSeconds: 10,
    height: 200,
    showLegend: true,
    enableLowPassFilter: true
  });
});

onUnmounted(() => {
  visualizer.value?.destroy();
});
</script>

<style scoped>
.signal-chart {
  width: 100%;
  max-width: 800px;
  margin-top: 16px;
}
</style>

SignalVisualizerConfig Interface ​

typescript
interface SignalVisualizerConfig {
  signalColors?: string[];          // CSS color strings for each channel
  windowSeconds?: number;           // Time window in seconds (default: 10)
  pixelsPerSecond?: number;         // Horizontal pixels per second (default: 60)
  height?: number;                  // Chart height in pixels (default: 200)
  lineWidth?: number;               // Stroke width in pixels (default: 2)
  backgroundColor?: string;         // Background CSS color
  gridColor?: string;               // Grid line CSS color
  enableAutoScale?: boolean;        // Auto Y-axis scaling (default: true)
  yAxisMin?: number;                // Fixed Y min (when autoScale: false)
  yAxisMax?: number;                // Fixed Y max (when autoScale: false)
  showLegend?: boolean;             // Show channel legend (default: false)
  enableLowPassFilter?: boolean;    // Enable signal smoothing (default: false)
  lowPassFilterCutoff?: number;     // Low-pass filter cutoff Hz (default: 5)
  showGrid?: boolean;               // Show grid lines (default: true)
  label?: string;                   // Chart label
}

Methods ​

MethodDescription
updateSignal(data, estimation?)Push new signal data point, optionally with estimation context
destroy()Clean up resources and DOM elements

VisualSignalType ​

typescript
enum VisualSignalType {
  PPG = 'PPG',
  Respiratory = 'Respiratory'
}

Tips ​

  • Place the visualizer container below or beside the camera element for best layout
  • Use enableLowPassFilter with a cutoff of 3-5 Hz to reduce high-frequency noise while preserving pulse waveform features
  • Multiple signal channels automatically map to the colors in signalColors[]; provide one color per expected channel