gaitsetpy.eda
eda: Provides exploratory data analysis tools for gait datasets.
This module provides both the new class-based EDA analyzers and legacy function-based API. All EDA analyzers inherit from BaseEDAAnalyzer and are registered with the EDAManager.
Features:
- Comprehensive visualization of sensor data (thigh, shank, trunk)
- Statistical analysis and summaries
- Feature visualization and overlay
- Dataset comparison and analysis
Maintainer: @aharshit123456
1""" 2eda: Provides exploratory data analysis tools for gait datasets. 3 4This module provides both the new class-based EDA analyzers and legacy function-based API. 5All EDA analyzers inherit from BaseEDAAnalyzer and are registered with the EDAManager. 6 7Features: 8- Comprehensive visualization of sensor data (thigh, shank, trunk) 9- Statistical analysis and summaries 10- Feature visualization and overlay 11- Dataset comparison and analysis 12 13Maintainer: @aharshit123456 14""" 15 16# Import the new class-based EDA analyzers 17from .analyzers import ( 18 DaphnetVisualizationAnalyzer, 19 SensorStatisticsAnalyzer 20) 21 22# Import legacy functions for backward compatibility 23from .visualization import ( 24 plot_thigh_data, 25 plot_shank_data, 26 plot_trunk_data, 27 plot_all_data, 28 plot_all_thigh_data, 29 plot_all_shank_data, 30 plot_all_trunk_data, 31 plot_all_datasets 32) 33 34from .statistics import plot_sensor_with_features 35 36# Import managers 37from ..core.managers import EDAManager 38 39# Register all EDA analyzers with the manager 40def _register_analyzers(): 41 """Register all available EDA analyzers with the EDAManager.""" 42 manager = EDAManager() 43 manager.register_analyzer("daphnet_visualization", DaphnetVisualizationAnalyzer) 44 manager.register_analyzer("sensor_statistics", SensorStatisticsAnalyzer) 45 46# Auto-register analyzers when module is imported 47_register_analyzers() 48 49# Convenient access to the EDA manager 50def get_eda_manager(): 51 """Get the singleton EDAManager instance.""" 52 return EDAManager() 53 54# Helper function to get available analyzers 55def get_available_analyzers(): 56 """Get list of available EDA analyzer names.""" 57 return EDAManager().get_available_components() 58 59# Helper function to analyze data using manager 60def analyze_data(analyzer_name: str, data, **kwargs): 61 """ 62 Analyze data using the EDAManager. 63 64 Args: 65 analyzer_name: Name of the EDA analyzer 66 data: Input data to analyze 67 **kwargs: Additional arguments for analysis 68 69 Returns: 70 Analysis results dictionary 71 """ 72 return EDAManager().analyze_data(analyzer_name, data, **kwargs) 73 74# Helper function to visualize data using manager 75def visualize_data(analyzer_name: str, data, **kwargs): 76 """ 77 Create visualizations using the EDAManager. 78 79 Args: 80 analyzer_name: Name of the EDA analyzer 81 data: Input data to visualize 82 **kwargs: Additional arguments for visualization 83 """ 84 return EDAManager().visualize_data(analyzer_name, data, **kwargs) 85 86# Convenient wrapper functions for common operations 87def plot_daphnet_data(data, names=None, sensor_type='all', dataset_index=0): 88 """ 89 Plot Daphnet dataset using the DaphnetVisualizationAnalyzer. 90 91 Args: 92 data: Input data (DataFrame or list of DataFrames) 93 names: List of dataset names 94 sensor_type: Type of sensor to plot ('all', 'thigh', 'shank', 'trunk') 95 dataset_index: Index of dataset to plot (if data is a list) 96 """ 97 analyzer = DaphnetVisualizationAnalyzer() 98 analyzer.visualize(data, sensor_type=sensor_type, dataset_index=dataset_index, names=names or []) 99 100def analyze_sensor_statistics(data): 101 """ 102 Analyze sensor statistics using the SensorStatisticsAnalyzer. 103 104 Args: 105 data: Input data (DataFrame or list of DataFrames) 106 107 Returns: 108 Dictionary containing statistical analysis results 109 """ 110 analyzer = SensorStatisticsAnalyzer() 111 return analyzer.analyze(data) 112 113def plot_sensor_features(sliding_windows, features, sensor_name='shank', start_idx=0, end_idx=1000, num_windows=10): 114 """ 115 Plot sensor data with overlaid features using the SensorStatisticsAnalyzer. 116 117 Args: 118 sliding_windows: List of sliding window dictionaries 119 features: List of feature dictionaries 120 sensor_name: Name of the sensor to plot 121 start_idx: Start index of the time window 122 end_idx: End index of the time window 123 num_windows: Number of sliding windows to plot 124 """ 125 analyzer = SensorStatisticsAnalyzer() 126 analyzer.visualize(sliding_windows, features, sensor_name=sensor_name, 127 start_idx=start_idx, end_idx=end_idx, num_windows=num_windows) 128 129__all__ = [ 130 # New class-based analyzers 131 'DaphnetVisualizationAnalyzer', 132 'SensorStatisticsAnalyzer', 133 # Legacy functions for backward compatibility 134 'plot_thigh_data', 135 'plot_shank_data', 136 'plot_trunk_data', 137 'plot_all_data', 138 'plot_all_thigh_data', 139 'plot_all_shank_data', 140 'plot_all_trunk_data', 141 'plot_all_datasets', 142 'plot_sensor_with_features', 143 # Manager functions 144 'get_eda_manager', 145 'get_available_analyzers', 146 'analyze_data', 147 'visualize_data', 148 # Convenient wrapper functions 149 'plot_daphnet_data', 150 'analyze_sensor_statistics', 151 'plot_sensor_features' 152]
18class DaphnetVisualizationAnalyzer(BaseEDAAnalyzer): 19 """ 20 EDA analyzer for Daphnet dataset visualization. 21 22 This analyzer provides comprehensive visualization capabilities for Daphnet dataset 23 including thigh, shank, and trunk sensor data. 24 """ 25 26 def __init__(self): 27 super().__init__( 28 name="daphnet_visualization", 29 description="Comprehensive visualization analyzer for Daphnet dataset sensor data" 30 ) 31 self.config = { 32 'figsize': (20, 16), 33 'colors': { 34 'no_freeze': 'orange', 35 'freeze': 'purple' 36 }, 37 'alpha': 0.6 38 } 39 40 def analyze(self, data: Union[pd.DataFrame, List[pd.DataFrame]], **kwargs) -> Dict[str, Any]: 41 """ 42 Analyze the data and return statistical summaries. 43 44 Args: 45 data: Input data to analyze 46 **kwargs: Additional arguments 47 48 Returns: 49 Dictionary containing analysis results 50 """ 51 if isinstance(data, list): 52 # Multiple datasets 53 results = {} 54 for i, df in enumerate(data): 55 results[f'dataset_{i}'] = self._analyze_single_dataset(df) 56 return results 57 else: 58 # Single dataset 59 return self._analyze_single_dataset(data) 60 61 def _analyze_single_dataset(self, df: pd.DataFrame) -> Dict[str, Any]: 62 """Analyze a single dataset.""" 63 # Basic statistics 64 stats = { 65 'shape': df.shape, 66 'columns': df.columns.tolist(), 67 'annotation_distribution': df['annotations'].value_counts().to_dict() if 'annotations' in df.columns else {}, 68 'missing_values': df.isnull().sum().to_dict(), 69 'data_range': { 70 'min': df.select_dtypes(include=[np.number]).min().to_dict(), 71 'max': df.select_dtypes(include=[np.number]).max().to_dict() 72 } 73 } 74 75 # Sensor-specific statistics 76 sensor_stats = {} 77 for sensor in ['thigh', 'shank', 'trunk']: 78 if sensor in df.columns: 79 sensor_stats[sensor] = { 80 'mean': df[sensor].mean(), 81 'std': df[sensor].std(), 82 'min': df[sensor].min(), 83 'max': df[sensor].max() 84 } 85 86 stats['sensor_statistics'] = sensor_stats 87 return stats 88 89 def visualize(self, data: Union[pd.DataFrame, List[pd.DataFrame]], **kwargs): 90 """ 91 Create visualizations of the data. 92 93 Args: 94 data: Input data to visualize 95 **kwargs: Additional arguments including sensor_type, dataset_index, names 96 """ 97 sensor_type = kwargs.get('sensor_type', 'all') 98 dataset_index = kwargs.get('dataset_index', 0) 99 names = kwargs.get('names', []) 100 101 if isinstance(data, list): 102 if dataset_index < len(data): 103 df = data[dataset_index] 104 dataset_name = names[dataset_index] if dataset_index < len(names) else f"Dataset {dataset_index}" 105 else: 106 print(f"Dataset index {dataset_index} out of range") 107 return 108 else: 109 df = data 110 dataset_name = names[0] if names else "Dataset" 111 112 if sensor_type == 'all': 113 self._plot_all_sensors(df, dataset_name) 114 elif sensor_type == 'thigh': 115 self._plot_thigh_data(df, dataset_name) 116 elif sensor_type == 'shank': 117 self._plot_shank_data(df, dataset_name) 118 elif sensor_type == 'trunk': 119 self._plot_trunk_data(df, dataset_name) 120 else: 121 print(f"Unknown sensor type: {sensor_type}") 122 123 def _plot_thigh_data(self, df: pd.DataFrame, dataset_name: str): 124 """Plot thigh sensor data.""" 125 print(f"Plotting thigh data for {dataset_name}") 126 127 # Filter data 128 df_filtered = df[df.annotations > 0] if 'annotations' in df.columns else df 129 130 if df_filtered.empty: 131 print("No valid data to plot") 132 return 133 134 # Create figure 135 fig, axes = plt.subplots(4, 1, sharex=True, figsize=self.config['figsize']) 136 fig.suptitle(f"Thigh Data from {dataset_name}") 137 138 # Separate freeze and no-freeze data 139 if 'annotations' in df.columns: 140 neg = df_filtered[df_filtered.annotations == 1] # No freeze 141 pos = df_filtered[df_filtered.annotations == 2] # Freeze 142 else: 143 neg = df_filtered 144 pos = pd.DataFrame() 145 146 # Plot each component 147 components = ['thigh_h_fd', 'thigh_v', 'thigh_h_l', 'thigh'] 148 labels = ['Horizontal Forward', 'Vertical', 'Horizontal Lateral', 'Overall'] 149 150 for i, (component, label) in enumerate(zip(components, labels)): 151 if component in df_filtered.columns: 152 # Plot main signal 153 axes[i].plot(df_filtered.index, df_filtered[component]) 154 axes[i].set_ylabel(f"{label} Thigh Acceleration") 155 156 # Plot annotations if available 157 if not neg.empty: 158 axes[i].scatter(neg.index, neg[component], 159 c=self.config['colors']['no_freeze'], 160 label="no freeze", alpha=self.config['alpha']) 161 if not pos.empty: 162 axes[i].scatter(pos.index, pos[component], 163 c=self.config['colors']['freeze'], 164 label="freeze", alpha=self.config['alpha']) 165 166 axes[i].legend() 167 168 plt.xlabel("Time") 169 plt.tight_layout() 170 plt.show() 171 172 def _plot_shank_data(self, df: pd.DataFrame, dataset_name: str): 173 """Plot shank sensor data.""" 174 print(f"Plotting shank data for {dataset_name}") 175 176 # Filter data 177 df_filtered = df[df.annotations > 0] if 'annotations' in df.columns else df 178 179 if df_filtered.empty: 180 print("No valid data to plot") 181 return 182 183 # Create figure 184 fig, axes = plt.subplots(4, 1, sharex=True, figsize=self.config['figsize']) 185 fig.suptitle(f"Shank Data from {dataset_name}") 186 187 # Separate freeze and no-freeze data 188 if 'annotations' in df.columns: 189 neg = df_filtered[df_filtered.annotations == 1] # No freeze 190 pos = df_filtered[df_filtered.annotations == 2] # Freeze 191 else: 192 neg = df_filtered 193 pos = pd.DataFrame() 194 195 # Plot each component 196 components = ['shank_h_fd', 'shank_v', 'shank_h_l', 'shank'] 197 labels = ['Horizontal Forward', 'Vertical', 'Horizontal Lateral', 'Overall'] 198 199 for i, (component, label) in enumerate(zip(components, labels)): 200 if component in df_filtered.columns: 201 # Plot main signal 202 axes[i].plot(df_filtered.index, df_filtered[component]) 203 axes[i].set_ylabel(f"{label} Shank Acceleration") 204 205 # Plot annotations if available 206 if not neg.empty: 207 axes[i].scatter(neg.index, neg[component], 208 c=self.config['colors']['no_freeze'], 209 label="no freeze", alpha=self.config['alpha']) 210 if not pos.empty: 211 axes[i].scatter(pos.index, pos[component], 212 c=self.config['colors']['freeze'], 213 label="freeze", alpha=self.config['alpha']) 214 215 axes[i].legend() 216 217 plt.xlabel("Time") 218 plt.tight_layout() 219 plt.show() 220 221 def _plot_trunk_data(self, df: pd.DataFrame, dataset_name: str): 222 """Plot trunk sensor data.""" 223 print(f"Plotting trunk data for {dataset_name}") 224 225 # Filter data 226 df_filtered = df[df.annotations > 0] if 'annotations' in df.columns else df 227 228 if df_filtered.empty: 229 print("No valid data to plot") 230 return 231 232 # Create figure 233 fig, axes = plt.subplots(4, 1, sharex=True, figsize=self.config['figsize']) 234 fig.suptitle(f"Trunk Data from {dataset_name}") 235 236 # Separate freeze and no-freeze data 237 if 'annotations' in df.columns: 238 neg = df_filtered[df_filtered.annotations == 1] # No freeze 239 pos = df_filtered[df_filtered.annotations == 2] # Freeze 240 else: 241 neg = df_filtered 242 pos = pd.DataFrame() 243 244 # Plot each component 245 components = ['trunk_h_fd', 'trunk_v', 'trunk_h_l', 'trunk'] 246 labels = ['Horizontal Forward', 'Vertical', 'Horizontal Lateral', 'Overall'] 247 248 for i, (component, label) in enumerate(zip(components, labels)): 249 if component in df_filtered.columns: 250 # Plot main signal 251 axes[i].plot(df_filtered.index, df_filtered[component]) 252 axes[i].set_ylabel(f"{label} Trunk Acceleration") 253 254 # Plot annotations if available 255 if not neg.empty: 256 axes[i].scatter(neg.index, neg[component], 257 c=self.config['colors']['no_freeze'], 258 label="no freeze", alpha=self.config['alpha']) 259 if not pos.empty: 260 axes[i].scatter(pos.index, pos[component], 261 c=self.config['colors']['freeze'], 262 label="freeze", alpha=self.config['alpha']) 263 264 axes[i].legend() 265 266 plt.xlabel("Time") 267 plt.tight_layout() 268 plt.show() 269 270 def _plot_all_sensors(self, df: pd.DataFrame, dataset_name: str): 271 """Plot all sensor data in a combined view.""" 272 print(f"Plotting all sensor data for {dataset_name}") 273 274 # Create figure with subplots for each sensor 275 fig, axes = plt.subplots(3, 1, sharex=True, figsize=self.config['figsize']) 276 fig.suptitle(f"All Sensor Data from {dataset_name}") 277 278 # Filter data 279 df_filtered = df[df.annotations > 0] if 'annotations' in df.columns else df 280 281 if df_filtered.empty: 282 print("No valid data to plot") 283 return 284 285 sensors = ['thigh', 'shank', 'trunk'] 286 for i, sensor in enumerate(sensors): 287 if sensor in df_filtered.columns: 288 axes[i].plot(df_filtered.index, df_filtered[sensor]) 289 axes[i].set_ylabel(f"{sensor.capitalize()} Acceleration") 290 291 # Add annotations if available 292 if 'annotations' in df_filtered.columns: 293 neg = df_filtered[df_filtered.annotations == 1] 294 pos = df_filtered[df_filtered.annotations == 2] 295 296 if not neg.empty: 297 axes[i].scatter(neg.index, neg[sensor], 298 c=self.config['colors']['no_freeze'], 299 label="no freeze", alpha=self.config['alpha']) 300 if not pos.empty: 301 axes[i].scatter(pos.index, pos[sensor], 302 c=self.config['colors']['freeze'], 303 label="freeze", alpha=self.config['alpha']) 304 305 axes[i].legend() 306 307 plt.xlabel("Time") 308 plt.tight_layout() 309 plt.show()
EDA analyzer for Daphnet dataset visualization.
This analyzer provides comprehensive visualization capabilities for Daphnet dataset including thigh, shank, and trunk sensor data.
26 def __init__(self): 27 super().__init__( 28 name="daphnet_visualization", 29 description="Comprehensive visualization analyzer for Daphnet dataset sensor data" 30 ) 31 self.config = { 32 'figsize': (20, 16), 33 'colors': { 34 'no_freeze': 'orange', 35 'freeze': 'purple' 36 }, 37 'alpha': 0.6 38 }
Initialize the EDA analyzer.
Args: name: Name of the EDA analyzer description: Description of the EDA analyzer
40 def analyze(self, data: Union[pd.DataFrame, List[pd.DataFrame]], **kwargs) -> Dict[str, Any]: 41 """ 42 Analyze the data and return statistical summaries. 43 44 Args: 45 data: Input data to analyze 46 **kwargs: Additional arguments 47 48 Returns: 49 Dictionary containing analysis results 50 """ 51 if isinstance(data, list): 52 # Multiple datasets 53 results = {} 54 for i, df in enumerate(data): 55 results[f'dataset_{i}'] = self._analyze_single_dataset(df) 56 return results 57 else: 58 # Single dataset 59 return self._analyze_single_dataset(data)
Analyze the data and return statistical summaries.
Args: data: Input data to analyze **kwargs: Additional arguments
Returns: Dictionary containing analysis results
89 def visualize(self, data: Union[pd.DataFrame, List[pd.DataFrame]], **kwargs): 90 """ 91 Create visualizations of the data. 92 93 Args: 94 data: Input data to visualize 95 **kwargs: Additional arguments including sensor_type, dataset_index, names 96 """ 97 sensor_type = kwargs.get('sensor_type', 'all') 98 dataset_index = kwargs.get('dataset_index', 0) 99 names = kwargs.get('names', []) 100 101 if isinstance(data, list): 102 if dataset_index < len(data): 103 df = data[dataset_index] 104 dataset_name = names[dataset_index] if dataset_index < len(names) else f"Dataset {dataset_index}" 105 else: 106 print(f"Dataset index {dataset_index} out of range") 107 return 108 else: 109 df = data 110 dataset_name = names[0] if names else "Dataset" 111 112 if sensor_type == 'all': 113 self._plot_all_sensors(df, dataset_name) 114 elif sensor_type == 'thigh': 115 self._plot_thigh_data(df, dataset_name) 116 elif sensor_type == 'shank': 117 self._plot_shank_data(df, dataset_name) 118 elif sensor_type == 'trunk': 119 self._plot_trunk_data(df, dataset_name) 120 else: 121 print(f"Unknown sensor type: {sensor_type}")
Create visualizations of the data.
Args: data: Input data to visualize **kwargs: Additional arguments including sensor_type, dataset_index, names
Inherited Members
312class SensorStatisticsAnalyzer(BaseEDAAnalyzer): 313 """ 314 EDA analyzer for sensor data statistics and feature visualization. 315 316 This analyzer provides statistical analysis and feature visualization capabilities 317 for sensor data including sliding windows and extracted features. 318 """ 319 320 def __init__(self): 321 super().__init__( 322 name="sensor_statistics", 323 description="Statistical analysis and feature visualization for sensor data" 324 ) 325 self.config = { 326 'figsize': (20, 10), 327 'feature_markers': { 328 'mean': 'x', 329 'rms': 'o', 330 'peak_height': 'v', 331 'mode': '<', 332 'median': '^' 333 } 334 } 335 336 def analyze(self, data: Union[pd.DataFrame, List[pd.DataFrame]], **kwargs) -> Dict[str, Any]: 337 """ 338 Analyze sensor data and return statistical summaries. 339 340 Args: 341 data: Input data to analyze 342 **kwargs: Additional arguments 343 344 Returns: 345 Dictionary containing analysis results 346 """ 347 if isinstance(data, list): 348 # Multiple datasets 349 results = {} 350 for i, df in enumerate(data): 351 results[f'dataset_{i}'] = self._compute_statistics(df) 352 return results 353 else: 354 # Single dataset 355 return self._compute_statistics(data) 356 357 def _compute_statistics(self, df: pd.DataFrame) -> Dict[str, Any]: 358 """Compute comprehensive statistics for a dataset.""" 359 stats = { 360 'basic_stats': df.describe().to_dict(), 361 'correlation_matrix': df.corr().to_dict() if len(df.select_dtypes(include=[np.number]).columns) > 1 else {}, 362 'skewness': df.skew().to_dict(), 363 'kurtosis': df.kurtosis().to_dict() 364 } 365 366 # Add sensor-specific statistics 367 sensor_stats = {} 368 for sensor in ['thigh', 'shank', 'trunk']: 369 if sensor in df.columns: 370 sensor_data = df[sensor].dropna() 371 sensor_stats[sensor] = { 372 'mean': sensor_data.mean(), 373 'std': sensor_data.std(), 374 'variance': sensor_data.var(), 375 'min': sensor_data.min(), 376 'max': sensor_data.max(), 377 'range': sensor_data.max() - sensor_data.min(), 378 'median': sensor_data.median(), 379 'q25': sensor_data.quantile(0.25), 380 'q75': sensor_data.quantile(0.75), 381 'iqr': sensor_data.quantile(0.75) - sensor_data.quantile(0.25) 382 } 383 384 stats['sensor_statistics'] = sensor_stats 385 return stats 386 387 def visualize(self, sliding_windows: List[Dict], features: List[Dict], **kwargs): 388 """ 389 Create visualizations of sensor data with overlaid features. 390 391 Args: 392 sliding_windows: List of sliding window dictionaries 393 features: List of feature dictionaries 394 **kwargs: Additional arguments including sensor_name, start_idx, end_idx, num_windows 395 """ 396 sensor_name = kwargs.get('sensor_name', 'shank') 397 start_idx = kwargs.get('start_idx', 0) 398 end_idx = kwargs.get('end_idx', 1000) 399 num_windows = kwargs.get('num_windows', 10) 400 save = kwargs.get('save', False) 401 402 self._plot_sensor_with_features(sliding_windows, features, start_idx, end_idx, 403 sensor_name, num_windows, save) 404 405 def _plot_sensor_with_features(self, sliding_windows: List[Dict], features: List[Dict], 406 start_idx: int, end_idx: int, sensor_name: str = "shank", 407 num_windows: int = 10, save: bool = False): 408 """ 409 Plot sliding windows of sensor data with overlaid statistical features. 410 411 Args: 412 sliding_windows: List of sliding window dictionaries 413 features: List of feature dictionaries 414 start_idx: Start index of the time window 415 end_idx: End index of the time window 416 sensor_name: Name of the sensor to plot 417 num_windows: Number of sliding windows to plot 418 save: Whether to save the plot 419 """ 420 fig, axes = plt.subplots(2, 1, figsize=self.config['figsize'], 421 gridspec_kw={'height_ratios': [3, 1]}) 422 423 # Extract sensor windows 424 sensor_windows = next((sw['data'] for sw in sliding_windows if sw['name'] == sensor_name), None) 425 if sensor_windows is None: 426 print(f"Sensor '{sensor_name}' not found in sliding_windows.") 427 return 428 429 # Extract corresponding features 430 sensor_features = next((feat['features'] for feat in features if feat['name'] == sensor_name), None) 431 if sensor_features is None: 432 print(f"Sensor '{sensor_name}' not found in features.") 433 return 434 435 # Filter windows based on start_idx and end_idx 436 filtered_windows = [series for series in sensor_windows 437 if start_idx <= series.index[0] and series.index[-1] <= end_idx] 438 439 if not filtered_windows: 440 print(f"No windows found in the specified index range ({start_idx} - {end_idx}).") 441 return 442 443 # Store entropy & frequency features for separate plotting 444 entropy_values = [] 445 dominant_frequencies = [] 446 447 # Plot first num_windows windows 448 for i in range(min(num_windows, len(filtered_windows))): 449 series = filtered_windows[i] 450 451 # Extract time and signal values 452 time_values = series.index.to_numpy() 453 signal_values = series.values 454 455 # Determine actual start and end indices for this window 456 window_start, window_end = time_values[0], time_values[-1] 457 458 # Plot time series data 459 axes[0].plot(time_values, signal_values, alpha=0.6) 460 461 # Mark start and end of each window with vertical dotted lines 462 axes[0].axvline(x=window_start, color='black', linestyle='dotted', alpha=0.7) 463 axes[0].axvline(x=window_end, color='black', linestyle='dotted', alpha=0.7) 464 465 # Overlay statistical features 466 for feature_name, marker in self.config['feature_markers'].items(): 467 if feature_name in sensor_features and len(sensor_features[feature_name]) > i: 468 feature_value = sensor_features[feature_name][i] 469 if feature_value != 0: # Skip zero values 470 closest_index = np.argmin(np.abs(signal_values - feature_value)) 471 closest_time = time_values[closest_index] 472 axes[0].scatter(closest_time, feature_value, color='red', 473 marker=marker, s=100, label=feature_name if i == 0 else "") 474 475 # Store entropy & frequency features for separate plotting 476 if 'entropy' in sensor_features and len(sensor_features['entropy']) > i: 477 entropy_values.append(sensor_features['entropy'][i]) 478 if 'dominant_frequency' in sensor_features and len(sensor_features['dominant_frequency']) > i: 479 dominant_frequencies.append(sensor_features['dominant_frequency'][i]) 480 481 # Labels and title for time-series plot 482 axes[0].set_xlabel('Time') 483 axes[0].set_ylabel(f'{sensor_name} Signal') 484 axes[0].set_title(f'First {num_windows} windows of {sensor_name} in range {start_idx}-{end_idx} with Features') 485 axes[0].legend() 486 487 # Frequency-domain & entropy plot 488 if dominant_frequencies: 489 window_indices = list(range(len(dominant_frequencies))) 490 axes[1].plot(window_indices, dominant_frequencies, 491 label="Dominant Frequency", marker="o", linestyle="dashed", color="blue") 492 493 if entropy_values: 494 axes[1].bar(window_indices, entropy_values, alpha=0.6, label="Entropy", color="green") 495 496 axes[1].set_xlabel("Window Index") 497 axes[1].set_ylabel("Feature Value") 498 axes[1].set_title("Frequency & Entropy Features") 499 axes[1].legend() 500 501 plt.tight_layout() 502 503 # Save or show plot 504 if save: 505 file_path = input("Enter the file path to save the plot (e.g., 'plot.png'): ") 506 plt.savefig(file_path, dpi=300) 507 print(f"Plot saved at {file_path}") 508 else: 509 plt.show()
EDA analyzer for sensor data statistics and feature visualization.
This analyzer provides statistical analysis and feature visualization capabilities for sensor data including sliding windows and extracted features.
320 def __init__(self): 321 super().__init__( 322 name="sensor_statistics", 323 description="Statistical analysis and feature visualization for sensor data" 324 ) 325 self.config = { 326 'figsize': (20, 10), 327 'feature_markers': { 328 'mean': 'x', 329 'rms': 'o', 330 'peak_height': 'v', 331 'mode': '<', 332 'median': '^' 333 } 334 }
Initialize the EDA analyzer.
Args: name: Name of the EDA analyzer description: Description of the EDA analyzer
336 def analyze(self, data: Union[pd.DataFrame, List[pd.DataFrame]], **kwargs) -> Dict[str, Any]: 337 """ 338 Analyze sensor data and return statistical summaries. 339 340 Args: 341 data: Input data to analyze 342 **kwargs: Additional arguments 343 344 Returns: 345 Dictionary containing analysis results 346 """ 347 if isinstance(data, list): 348 # Multiple datasets 349 results = {} 350 for i, df in enumerate(data): 351 results[f'dataset_{i}'] = self._compute_statistics(df) 352 return results 353 else: 354 # Single dataset 355 return self._compute_statistics(data)
Analyze sensor data and return statistical summaries.
Args: data: Input data to analyze **kwargs: Additional arguments
Returns: Dictionary containing analysis results
387 def visualize(self, sliding_windows: List[Dict], features: List[Dict], **kwargs): 388 """ 389 Create visualizations of sensor data with overlaid features. 390 391 Args: 392 sliding_windows: List of sliding window dictionaries 393 features: List of feature dictionaries 394 **kwargs: Additional arguments including sensor_name, start_idx, end_idx, num_windows 395 """ 396 sensor_name = kwargs.get('sensor_name', 'shank') 397 start_idx = kwargs.get('start_idx', 0) 398 end_idx = kwargs.get('end_idx', 1000) 399 num_windows = kwargs.get('num_windows', 10) 400 save = kwargs.get('save', False) 401 402 self._plot_sensor_with_features(sliding_windows, features, start_idx, end_idx, 403 sensor_name, num_windows, save)
Create visualizations of sensor data with overlaid features.
Args: sliding_windows: List of sliding window dictionaries features: List of feature dictionaries **kwargs: Additional arguments including sensor_name, start_idx, end_idx, num_windows
Inherited Members
19def plot_thigh_data(daphnetThigh, daphnetNames, i): 20 """ 21 Plot thigh acceleration data for a specific dataset. 22 Args: 23 daphnetThigh (list): List of DataFrames containing thigh acceleration data. 24 daphnetNames (list): List of dataset names. 25 i (int): Index of the dataset to plot. 26 """ 27 print(daphnetNames[i]) 28 fig, axes = plt.subplots(4, 1, sharex=True, sharey=True, figsize=(20, 16)) 29 fig.suptitle("Thigh Data from " + daphnetNames[i]) 30 plt.xlabel("Time") 31 32 df = daphnetThigh[i] 33 df = df[df.annotations > 0] # Filter out rows with no annotations 34 neg = df[df.annotations == 1] # No freeze 35 pos = df[df.annotations == 2] # Freeze 36 37 # Plot horizontal forward thigh acceleration 38 ax1 = axes[0] 39 ax1.plot(df.thigh_h_fd) 40 ax1.set_ylabel("Horizontal Forward Thigh Acceleration") 41 ax1.scatter(neg.index, neg.thigh_h_fd, c='orange', label="no freeze") 42 ax1.scatter(pos.index, pos.thigh_h_fd, c='purple', label="freeze") 43 ax1.legend() 44 45 # Plot vertical thigh acceleration 46 ax2 = axes[1] 47 ax2.plot(df.thigh_v) 48 ax2.set_ylabel("Vertical Thigh Acceleration") 49 ax2.scatter(neg.index, neg.thigh_v, c='orange', label="no freeze") 50 ax2.scatter(pos.index, pos.thigh_v, c='purple', label="freeze") 51 ax2.legend() 52 53 # Plot horizontal lateral thigh acceleration 54 ax3 = axes[2] 55 ax3.plot(df.thigh_h_l) 56 ax3.set_ylabel("Horizontal Lateral Thigh Acceleration") 57 ax3.scatter(neg.index, neg.thigh_h_l, c='orange', label="no freeze") 58 ax3.scatter(pos.index, pos.thigh_h_l, c='purple', label="freeze") 59 ax3.legend() 60 61 # Plot overall thigh acceleration 62 ax4 = axes[3] 63 ax4.plot(df.thigh) 64 ax4.set_ylabel("Overall Thigh Acceleration") 65 ax4.scatter(neg.index, neg.thigh, c='orange', label="no freeze") 66 ax4.scatter(pos.index, pos.thigh, c='purple', label="freeze") 67 ax4.legend() 68 69 plt.tight_layout() 70 plt.show()
Plot thigh acceleration data for a specific dataset. Args: daphnetThigh (list): List of DataFrames containing thigh acceleration data. daphnetNames (list): List of dataset names. i (int): Index of the dataset to plot.
73def plot_shank_data(daphnetShank, daphnetNames, i): 74 """ 75 Plot shank acceleration data for a specific dataset. 76 Args: 77 daphnetShank (list): List of DataFrames containing shank acceleration data. 78 daphnetNames (list): List of dataset names. 79 i (int): Index of the dataset to plot. 80 """ 81 print(daphnetNames[i]) 82 fig, axes = plt.subplots(4, 1, sharex=True, sharey=True, figsize=(20, 16)) 83 fig.suptitle("Shank Data from " + daphnetNames[i]) 84 plt.xlabel("Time") 85 86 df = daphnetShank[i] 87 df["shank"] = np.sqrt(df["shank_h_l"]**2 + df["shank_v"]**2 + df["shank_h_fd"]**2) 88 df = df[df.annotations > 0] 89 neg = df[df.annotations == 1] 90 pos = df[df.annotations == 2] 91 92 ax1 = axes[0] 93 ax1.plot(df.shank_h_fd) 94 ax1.set_ylabel("Horizontal Forward Shank Acceleration") 95 ax1.scatter(neg.index, neg.shank_h_fd, c='orange', label="no freeze") 96 ax1.scatter(pos.index, pos.shank_h_fd, c='purple', label="freeze") 97 ax1.legend() 98 99 ax2 = axes[1] 100 ax2.plot(df.shank_v) 101 ax2.set_ylabel("Vertical Shank Acceleration") 102 ax2.scatter(neg.index, neg.shank_v, c='orange', label="no freeze") 103 ax2.scatter(pos.index, pos.shank_v, c='purple', label="freeze") 104 ax2.legend() 105 106 ax3 = axes[2] 107 ax3.plot(df.shank_h_l) 108 ax3.set_ylabel("Horizontal Lateral Shank Acceleration") 109 ax3.scatter(neg.index, neg.shank_h_l, c='orange', label="no freeze") 110 ax3.scatter(pos.index, pos.shank_h_l, c='purple', label="freeze") 111 ax3.legend() 112 113 ax4 = axes[3] 114 ax4.plot(df.shank) 115 ax4.set_ylabel("Overall Shank Acceleration") 116 ax4.scatter(neg.index, neg.shank, c='orange', label="no freeze") 117 ax4.scatter(pos.index, pos.shank, c='purple', label="freeze") 118 ax4.legend() 119 120 plt.tight_layout() 121 plt.show()
Plot shank acceleration data for a specific dataset. Args: daphnetShank (list): List of DataFrames containing shank acceleration data. daphnetNames (list): List of dataset names. i (int): Index of the dataset to plot.
124def plot_trunk_data(daphnetTrunk, daphnetNames, i): 125 """ 126 Plot trunk acceleration data for a specific dataset. 127 Args: 128 daphnetTrunk (list): List of DataFrames containing trunk acceleration data. 129 daphnetNames (list): List of dataset names. 130 i (int): Index of the dataset to plot. 131 """ 132 print(daphnetNames[i]) 133 fig, axes = plt.subplots(4, 1, sharex=True, sharey=True, figsize=(20, 16)) 134 fig.suptitle("Trunk Data from " + daphnetNames[i]) 135 plt.xlabel("Time") 136 137 df = daphnetTrunk[i] 138 df["trunk"] = np.sqrt(df["trunk_h_l"]**2 + df["trunk_v"]**2 + df["trunk_h_fd"]**2) 139 df = df[df.annotations > 0] 140 neg = df[df.annotations == 1] 141 pos = df[df.annotations == 2] 142 143 ax1 = axes[0] 144 ax1.plot(df.trunk_h_fd) 145 ax1.set_ylabel("Horizontal Forward Trunk Acceleration") 146 ax1.scatter(neg.index, neg.trunk_h_fd, c='orange', label="no freeze") 147 ax1.scatter(pos.index, pos.trunk_h_fd, c='purple', label="freeze") 148 ax1.legend() 149 150 ax2 = axes[1] 151 ax2.plot(df.trunk_v) 152 ax2.set_ylabel("Vertical Trunk Acceleration") 153 ax2.scatter(neg.index, neg.trunk_v, c='orange', label="no freeze") 154 ax2.scatter(pos.index, pos.trunk_v, c='purple', label="freeze") 155 ax2.legend() 156 157 ax3 = axes[2] 158 ax3.plot(df.trunk_h_l) 159 ax3.set_ylabel("Horizontal Lateral Trunk Acceleration") 160 ax3.scatter(neg.index, neg.trunk_h_l, c='orange', label="no freeze") 161 ax3.scatter(pos.index, pos.trunk_h_l, c='purple', label="freeze") 162 ax3.legend() 163 164 ax4 = axes[3] 165 ax4.plot(df.trunk) 166 ax4.set_ylabel("Overall Trunk Acceleration") 167 ax4.scatter(neg.index, neg.trunk, c='orange', label="no freeze") 168 ax4.scatter(pos.index, pos.trunk, c='purple', label="freeze") 169 ax4.legend() 170 171 plt.tight_layout() 172 plt.show()
Plot trunk acceleration data for a specific dataset. Args: daphnetTrunk (list): List of DataFrames containing trunk acceleration data. daphnetNames (list): List of dataset names. i (int): Index of the dataset to plot.
191def plot_all_data(daphnetThigh, daphnetShank, daphnetTrunk, daphnetNames, i): 192 """ 193 Plot thigh, shank, and trunk acceleration data for a specific dataset. 194 Args: 195 daphnetThigh (list): List of DataFrames containing thigh acceleration data. 196 daphnetShank (list): List of DataFrames containing shank acceleration data. 197 daphnetTrunk (list): List of DataFrames containing trunk acceleration data. 198 daphnetNames (list): List of dataset names. 199 i (int): Index of the dataset to plot. 200 """ 201 plot_thigh_data(daphnetThigh, daphnetNames, i) 202 plot_shank_data(daphnetShank, daphnetNames, i) 203 plot_trunk_data(daphnetTrunk, daphnetNames, i)
Plot thigh, shank, and trunk acceleration data for a specific dataset. Args: daphnetThigh (list): List of DataFrames containing thigh acceleration data. daphnetShank (list): List of DataFrames containing shank acceleration data. daphnetTrunk (list): List of DataFrames containing trunk acceleration data. daphnetNames (list): List of dataset names. i (int): Index of the dataset to plot.
175def plot_all_thigh_data(daphnetThigh, daphnetNames): 176 """Plot thigh acceleration data for all datasets.""" 177 for i in range(len(daphnetThigh)): 178 plot_thigh_data(daphnetThigh, daphnetNames, i)
Plot thigh acceleration data for all datasets.
180def plot_all_shank_data(daphnetShank, daphnetNames): 181 """Plot shank acceleration data for all datasets.""" 182 for i in range(len(daphnetShank)): 183 plot_shank_data(daphnetShank, daphnetNames, i)
Plot shank acceleration data for all datasets.
185def plot_all_trunk_data(daphnetTrunk, daphnetNames): 186 """Plot trunk acceleration data for all datasets.""" 187 for i in range(len(daphnetTrunk)): 188 plot_trunk_data(daphnetTrunk, daphnetNames, i)
Plot trunk acceleration data for all datasets.
205def plot_all_datasets(daphnetThigh, daphnetShank, daphnetTrunk, daphnetNames): 206 """Plot thigh, shank, and trunk acceleration data for all datasets.""" 207 for i in range(len(daphnetThigh)): 208 plot_all_data(daphnetThigh, daphnetShank, daphnetTrunk, daphnetNames, i)
Plot thigh, shank, and trunk acceleration data for all datasets.
11def plot_sensor_with_features(sliding_windows, features, start_idx, end_idx, sensor_name="shank", num_windows=10, save=False): 12 """ 13 @brief Plots sliding windows of a sensor's time series data with overlaid statistical features. 14 15 This function plots the first `num_windows` sliding windows within the given `start_idx` and `end_idx` 16 for a specified sensor and overlays feature values at their corresponding time indices. 17 It also displays entropy and dominant frequency in a separate plot. 18 19 @param[in] sliding_windows List of dictionaries, where each dictionary contains: 20 - 'name': sensor name (str) 21 - 'data': List of time-series windows (each as a Pandas Series) 22 @param[in] features List of dictionaries, where each dictionary contains: 23 - 'name': sensor name (str) 24 - 'features': Dictionary of extracted feature lists 25 @param[in] start_idx Start index of the time window to be plotted. 26 @param[in] end_idx End index of the time window to be plotted. 27 @param[in] sensor_name Name of the sensor to be plotted (default: "shank"). 28 @param[in] num_windows Number of sliding windows to plot (default: 10). 29 @param[in] save If True, saves the plot to a file instead of displaying it. 30 31 @return None 32 """ 33 34 fig, axes = plt.subplots(2, 1, figsize=(20, 10), gridspec_kw={'height_ratios': [3, 1]}) 35 36 # Extract sensor windows 37 sensor_windows = next((sw['data'] for sw in sliding_windows if sw['name'] == sensor_name), None) 38 if sensor_windows is None: 39 print(f"Sensor '{sensor_name}' not found in sliding_windows.") 40 return 41 42 # Extract corresponding features 43 sensor_features = next((feat['features'] for feat in features if feat['name'] == sensor_name), None) 44 if sensor_features is None: 45 print(f"Sensor '{sensor_name}' not found in features.") 46 return 47 48 # Filter windows based on start_idx and end_idx 49 filtered_windows = [series for series in sensor_windows if start_idx <= series.index[0] and series.index[-1] <= end_idx] 50 51 if not filtered_windows: 52 print(f"No windows found in the specified index range ({start_idx} - {end_idx}).") 53 return 54 55 # Store entropy & frequency features for separate plotting 56 entropy_values = [] 57 dominant_frequencies = [] 58 59 # Plot first `num_windows` windows 60 for i in range(min(num_windows, len(filtered_windows))): 61 series = filtered_windows[i] # Each window is a Pandas Series 62 63 # Extract time and signal values 64 time_values = series.index.to_numpy() # Time is the index 65 signal_values = series.values # Sensor readings 66 67 # Determine actual start and end indices for this window 68 window_start, window_end = time_values[0], time_values[-1] 69 70 # Plot time series data 71 axes[0].plot(time_values, signal_values, alpha=0.6) 72 73 # Mark start and end of each window with vertical dotted lines 74 axes[0].axvline(x=window_start, color='black', linestyle='dotted', alpha=0.7) 75 axes[0].axvline(x=window_end, color='black', linestyle='dotted', alpha=0.7) 76 77 # Overlay statistical features 78 for feature, marker in zip(['mean', 'rms', 'peak_height', 'mode', 'median'], ['x', 'o', 'v', '<', '^']): 79 if feature in sensor_features and len(sensor_features[feature]) > i: 80 feature_value = sensor_features[feature][i] 81 if feature_value != 0: # Skip zero values 82 closest_index = np.argmin(np.abs(signal_values - feature_value)) 83 closest_time = time_values[closest_index] 84 axes[0].scatter(closest_time, feature_value, color='red', marker=marker, s=100) 85 86 # Store entropy & frequency features for separate plotting 87 if 'entropy' in sensor_features and len(sensor_features['entropy']) > i: 88 entropy_values.append(sensor_features['entropy'][i]) 89 if 'dominant_frequency' in sensor_features and len(sensor_features['dominant_frequency']) > i: 90 dominant_frequencies.append(sensor_features['dominant_frequency'][i]) 91 92 # Labels and title for time-series plot 93 axes[0].set_xlabel('Time') 94 axes[0].set_ylabel(f'{sensor_name} Signal') 95 axes[0].set_title(f'First {num_windows} windows of {sensor_name} in range {start_idx}-{end_idx} with Features') 96 97 # Frequency-domain & entropy plot (axes[1]) 98 if dominant_frequencies: 99 window_indices = list(range(len(dominant_frequencies))) 100 axes[1].plot(window_indices, dominant_frequencies, label="Dominant Frequency", marker="o", linestyle="dashed", color="blue") 101 102 if entropy_values: 103 axes[1].bar(window_indices, entropy_values, alpha=0.6, label="Entropy", color="green") 104 105 axes[1].set_xlabel("Window Index") 106 axes[1].set_ylabel("Feature Value") 107 axes[1].set_title("Frequency & Entropy Features") 108 axes[1].legend() 109 110 plt.tight_layout() 111 112 # Save or show plot 113 if save: 114 file_path = input("Enter the file path to save the plot (e.g., 'plot.png'): ") 115 plt.savefig(file_path, dpi=300) 116 print(f"Plot saved at {file_path}") 117 else: 118 plt.show()
@brief Plots sliding windows of a sensor's time series data with overlaid statistical features.
This function plots the first num_windows sliding windows within the given start_idx and end_idx
for a specified sensor and overlays feature values at their corresponding time indices.
It also displays entropy and dominant frequency in a separate plot.
@param[in] sliding_windows List of dictionaries, where each dictionary contains: - 'name': sensor name (str) - 'data': List of time-series windows (each as a Pandas Series) @param[in] features List of dictionaries, where each dictionary contains: - 'name': sensor name (str) - 'features': Dictionary of extracted feature lists @param[in] start_idx Start index of the time window to be plotted. @param[in] end_idx End index of the time window to be plotted. @param[in] sensor_name Name of the sensor to be plotted (default: "shank"). @param[in] num_windows Number of sliding windows to plot (default: 10). @param[in] save If True, saves the plot to a file instead of displaying it.
@return None
Get the singleton EDAManager instance.
56def get_available_analyzers(): 57 """Get list of available EDA analyzer names.""" 58 return EDAManager().get_available_components()
Get list of available EDA analyzer names.
61def analyze_data(analyzer_name: str, data, **kwargs): 62 """ 63 Analyze data using the EDAManager. 64 65 Args: 66 analyzer_name: Name of the EDA analyzer 67 data: Input data to analyze 68 **kwargs: Additional arguments for analysis 69 70 Returns: 71 Analysis results dictionary 72 """ 73 return EDAManager().analyze_data(analyzer_name, data, **kwargs)
Analyze data using the EDAManager.
Args: analyzer_name: Name of the EDA analyzer data: Input data to analyze **kwargs: Additional arguments for analysis
Returns: Analysis results dictionary
76def visualize_data(analyzer_name: str, data, **kwargs): 77 """ 78 Create visualizations using the EDAManager. 79 80 Args: 81 analyzer_name: Name of the EDA analyzer 82 data: Input data to visualize 83 **kwargs: Additional arguments for visualization 84 """ 85 return EDAManager().visualize_data(analyzer_name, data, **kwargs)
Create visualizations using the EDAManager.
Args: analyzer_name: Name of the EDA analyzer data: Input data to visualize **kwargs: Additional arguments for visualization
88def plot_daphnet_data(data, names=None, sensor_type='all', dataset_index=0): 89 """ 90 Plot Daphnet dataset using the DaphnetVisualizationAnalyzer. 91 92 Args: 93 data: Input data (DataFrame or list of DataFrames) 94 names: List of dataset names 95 sensor_type: Type of sensor to plot ('all', 'thigh', 'shank', 'trunk') 96 dataset_index: Index of dataset to plot (if data is a list) 97 """ 98 analyzer = DaphnetVisualizationAnalyzer() 99 analyzer.visualize(data, sensor_type=sensor_type, dataset_index=dataset_index, names=names or [])
Plot Daphnet dataset using the DaphnetVisualizationAnalyzer.
Args: data: Input data (DataFrame or list of DataFrames) names: List of dataset names sensor_type: Type of sensor to plot ('all', 'thigh', 'shank', 'trunk') dataset_index: Index of dataset to plot (if data is a list)
101def analyze_sensor_statistics(data): 102 """ 103 Analyze sensor statistics using the SensorStatisticsAnalyzer. 104 105 Args: 106 data: Input data (DataFrame or list of DataFrames) 107 108 Returns: 109 Dictionary containing statistical analysis results 110 """ 111 analyzer = SensorStatisticsAnalyzer() 112 return analyzer.analyze(data)
Analyze sensor statistics using the SensorStatisticsAnalyzer.
Args: data: Input data (DataFrame or list of DataFrames)
Returns: Dictionary containing statistical analysis results
114def plot_sensor_features(sliding_windows, features, sensor_name='shank', start_idx=0, end_idx=1000, num_windows=10): 115 """ 116 Plot sensor data with overlaid features using the SensorStatisticsAnalyzer. 117 118 Args: 119 sliding_windows: List of sliding window dictionaries 120 features: List of feature dictionaries 121 sensor_name: Name of the sensor to plot 122 start_idx: Start index of the time window 123 end_idx: End index of the time window 124 num_windows: Number of sliding windows to plot 125 """ 126 analyzer = SensorStatisticsAnalyzer() 127 analyzer.visualize(sliding_windows, features, sensor_name=sensor_name, 128 start_idx=start_idx, end_idx=end_idx, num_windows=num_windows)
Plot sensor data with overlaid features using the SensorStatisticsAnalyzer.
Args: sliding_windows: List of sliding window dictionaries features: List of feature dictionaries sensor_name: Name of the sensor to plot start_idx: Start index of the time window end_idx: End index of the time window num_windows: Number of sliding windows to plot