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
| Method | Description |
|---|---|
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
enableLowPassFilterwith 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