iints-sdk-python35 0.0.18__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. iints/__init__.py +183 -0
  2. iints/analysis/__init__.py +12 -0
  3. iints/analysis/algorithm_xray.py +387 -0
  4. iints/analysis/baseline.py +92 -0
  5. iints/analysis/clinical_benchmark.py +198 -0
  6. iints/analysis/clinical_metrics.py +551 -0
  7. iints/analysis/clinical_tir_analyzer.py +136 -0
  8. iints/analysis/diabetes_metrics.py +43 -0
  9. iints/analysis/edge_efficiency.py +33 -0
  10. iints/analysis/edge_performance_monitor.py +315 -0
  11. iints/analysis/explainability.py +94 -0
  12. iints/analysis/explainable_ai.py +232 -0
  13. iints/analysis/hardware_benchmark.py +221 -0
  14. iints/analysis/metrics.py +117 -0
  15. iints/analysis/population_report.py +188 -0
  16. iints/analysis/reporting.py +345 -0
  17. iints/analysis/safety_index.py +311 -0
  18. iints/analysis/sensor_filtering.py +54 -0
  19. iints/analysis/validator.py +273 -0
  20. iints/api/__init__.py +0 -0
  21. iints/api/base_algorithm.py +307 -0
  22. iints/api/registry.py +103 -0
  23. iints/api/template_algorithm.py +195 -0
  24. iints/assets/iints_logo.png +0 -0
  25. iints/cli/__init__.py +0 -0
  26. iints/cli/cli.py +2598 -0
  27. iints/core/__init__.py +1 -0
  28. iints/core/algorithms/__init__.py +0 -0
  29. iints/core/algorithms/battle_runner.py +138 -0
  30. iints/core/algorithms/correction_bolus.py +95 -0
  31. iints/core/algorithms/discovery.py +92 -0
  32. iints/core/algorithms/fixed_basal_bolus.py +58 -0
  33. iints/core/algorithms/hybrid_algorithm.py +92 -0
  34. iints/core/algorithms/lstm_algorithm.py +138 -0
  35. iints/core/algorithms/mock_algorithms.py +162 -0
  36. iints/core/algorithms/pid_controller.py +88 -0
  37. iints/core/algorithms/standard_pump_algo.py +64 -0
  38. iints/core/device.py +0 -0
  39. iints/core/device_manager.py +64 -0
  40. iints/core/devices/__init__.py +3 -0
  41. iints/core/devices/models.py +160 -0
  42. iints/core/patient/__init__.py +9 -0
  43. iints/core/patient/bergman_model.py +341 -0
  44. iints/core/patient/models.py +285 -0
  45. iints/core/patient/patient_factory.py +117 -0
  46. iints/core/patient/profile.py +41 -0
  47. iints/core/safety/__init__.py +12 -0
  48. iints/core/safety/config.py +37 -0
  49. iints/core/safety/input_validator.py +95 -0
  50. iints/core/safety/supervisor.py +39 -0
  51. iints/core/simulation/__init__.py +0 -0
  52. iints/core/simulation/scenario_parser.py +61 -0
  53. iints/core/simulator.py +874 -0
  54. iints/core/supervisor.py +367 -0
  55. iints/data/__init__.py +53 -0
  56. iints/data/adapter.py +142 -0
  57. iints/data/column_mapper.py +398 -0
  58. iints/data/datasets.json +132 -0
  59. iints/data/demo/__init__.py +1 -0
  60. iints/data/demo/demo_cgm.csv +289 -0
  61. iints/data/importer.py +275 -0
  62. iints/data/ingestor.py +162 -0
  63. iints/data/nightscout.py +128 -0
  64. iints/data/quality_checker.py +550 -0
  65. iints/data/registry.py +166 -0
  66. iints/data/tidepool.py +38 -0
  67. iints/data/universal_parser.py +813 -0
  68. iints/data/virtual_patients/clinic_safe_baseline.yaml +9 -0
  69. iints/data/virtual_patients/clinic_safe_hyper_challenge.yaml +9 -0
  70. iints/data/virtual_patients/clinic_safe_hypo_prone.yaml +9 -0
  71. iints/data/virtual_patients/clinic_safe_midnight.yaml +9 -0
  72. iints/data/virtual_patients/clinic_safe_pizza.yaml +9 -0
  73. iints/data/virtual_patients/clinic_safe_stress_meal.yaml +9 -0
  74. iints/data/virtual_patients/default_patient.yaml +11 -0
  75. iints/data/virtual_patients/patient_559_config.yaml +11 -0
  76. iints/emulation/__init__.py +80 -0
  77. iints/emulation/legacy_base.py +414 -0
  78. iints/emulation/medtronic_780g.py +337 -0
  79. iints/emulation/omnipod_5.py +367 -0
  80. iints/emulation/tandem_controliq.py +393 -0
  81. iints/highlevel.py +451 -0
  82. iints/learning/__init__.py +3 -0
  83. iints/learning/autonomous_optimizer.py +194 -0
  84. iints/learning/learning_system.py +122 -0
  85. iints/metrics.py +34 -0
  86. iints/population/__init__.py +11 -0
  87. iints/population/generator.py +131 -0
  88. iints/population/runner.py +327 -0
  89. iints/presets/__init__.py +28 -0
  90. iints/presets/presets.json +114 -0
  91. iints/research/__init__.py +30 -0
  92. iints/research/config.py +68 -0
  93. iints/research/dataset.py +319 -0
  94. iints/research/losses.py +73 -0
  95. iints/research/predictor.py +329 -0
  96. iints/scenarios/__init__.py +3 -0
  97. iints/scenarios/generator.py +92 -0
  98. iints/templates/__init__.py +0 -0
  99. iints/templates/default_algorithm.py +91 -0
  100. iints/templates/scenarios/__init__.py +0 -0
  101. iints/templates/scenarios/chaos_insulin_stacking.json +29 -0
  102. iints/templates/scenarios/chaos_runaway_ai.json +25 -0
  103. iints/templates/scenarios/example_scenario.json +35 -0
  104. iints/templates/scenarios/exercise_stress.json +30 -0
  105. iints/utils/__init__.py +3 -0
  106. iints/utils/plotting.py +50 -0
  107. iints/utils/run_io.py +152 -0
  108. iints/validation/__init__.py +133 -0
  109. iints/validation/schemas.py +94 -0
  110. iints/visualization/__init__.py +34 -0
  111. iints/visualization/cockpit.py +691 -0
  112. iints/visualization/uncertainty_cloud.py +612 -0
  113. iints_sdk_python35-0.0.18.dist-info/METADATA +225 -0
  114. iints_sdk_python35-0.0.18.dist-info/RECORD +118 -0
  115. iints_sdk_python35-0.0.18.dist-info/WHEEL +5 -0
  116. iints_sdk_python35-0.0.18.dist-info/entry_points.txt +10 -0
  117. iints_sdk_python35-0.0.18.dist-info/licenses/LICENSE +28 -0
  118. iints_sdk_python35-0.0.18.dist-info/top_level.txt +1 -0
@@ -0,0 +1,612 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Uncertainty Cloud Visualizer - IINTS-AF
4
+ Creates visualization of AI confidence as shadow around glucose predictions.
5
+
6
+ The Uncertainty Cloud provides:
7
+ - Visual representation of AI confidence
8
+ - Confidence intervals around glucose predictions
9
+ - Color-coded uncertainty levels
10
+ - "Why" annotations for key decisions
11
+ """
12
+
13
+ import numpy as np
14
+ import pandas as pd
15
+ import matplotlib.pyplot as plt
16
+ import matplotlib.patches as mpatches
17
+ from matplotlib.collections import PatchCollection
18
+ from typing import Dict, List, Optional, Tuple, Any
19
+ from dataclasses import dataclass
20
+ from datetime import datetime
21
+
22
+
23
+ @dataclass
24
+ class UncertaintyData:
25
+ """Data structure for uncertainty visualization"""
26
+ timestamps: np.ndarray
27
+ glucose_values: np.ndarray
28
+ predictions: np.ndarray
29
+ lower_bounds: np.ndarray
30
+ upper_bounds: np.ndarray
31
+ confidence_scores: np.ndarray # 0.0 to 1.0
32
+ decision_points: Optional[List[Dict]] = None
33
+
34
+ def __post_init__(self):
35
+ if self.decision_points is None:
36
+ self.decision_points = []
37
+
38
+
39
+ @dataclass
40
+ class VisualizationConfig:
41
+ """Configuration for uncertainty cloud visualization"""
42
+ # Figure settings
43
+ figure_size: Tuple[int, int] = (14, 8)
44
+ dpi: int = 150
45
+ style: str = 'default'
46
+
47
+ # Glucose target zones
48
+ target_low: float = 70.0
49
+ target_high: float = 180.0
50
+ tight_low: float = 70.0
51
+ tight_high: float = 140.0
52
+
53
+ # Colors
54
+ glucose_color: str = '#2196F3'
55
+ prediction_color: str = '#4CAF50'
56
+ uncertainty_color: str = '#81C784' # Light green
57
+ cloud_alpha: float = 0.3
58
+
59
+ # Thresholds for coloring
60
+ critical_low: float = 54.0
61
+ critical_high: float = 250.0
62
+
63
+ # Annotation settings
64
+ show_annotations: bool = True
65
+ annotation_fontsize: int = 8
66
+
67
+
68
+ class UncertaintyCloud:
69
+ """
70
+ Creates uncertainty cloud visualizations for glucose predictions.
71
+
72
+ The cloud represents AI confidence through:
73
+ 1. Semi-transparent shaded regions showing prediction bounds
74
+ 2. Color intensity based on confidence score
75
+ 3. Annotation markers for key decision points
76
+
77
+ Usage:
78
+ cloud = UncertaintyCloud()
79
+
80
+ # Create data
81
+ data = UncertaintyData(
82
+ timestamps=np.arange(0, 480, 5),
83
+ glucose_values=glucose,
84
+ predictions=predictions,
85
+ lower_bounds=lower,
86
+ upper_bounds=upper,
87
+ confidence_scores=confidence
88
+ )
89
+
90
+ # Generate plot
91
+ fig = cloud.plot(data)
92
+ plt.savefig("uncertainty_cloud.png")
93
+ """
94
+
95
+ def __init__(self, config: Optional[VisualizationConfig] = None):
96
+ """
97
+ Initialize uncertainty cloud visualizer.
98
+
99
+ Args:
100
+ config: Visualization configuration (uses default if None)
101
+ """
102
+ self.config = config or VisualizationConfig()
103
+ self.style_applied = False
104
+
105
+ def _apply_style(self):
106
+ """Apply matplotlib style settings"""
107
+ if not self.style_applied:
108
+ plt.style.use(self.config.style)
109
+ self.style_applied = True
110
+
111
+ def _create_target_zones(self, ax: plt.Axes, time_range: Tuple[float, float]):
112
+ """Create shaded regions for target glucose zones"""
113
+ # Very tight range (70-140) - green
114
+ ax.axhspan(
115
+ self.config.tight_low, self.config.tight_high,
116
+ xmin=0, xmax=1,
117
+ alpha=0.15, color='green',
118
+ label='Tight Range (70-140)'
119
+ )
120
+
121
+ # Standard target range (70-180) - yellow
122
+ ax.axhspan(
123
+ self.config.target_low, self.config.target_high,
124
+ xmin=0, xmax=1,
125
+ alpha=0.1, color='orange',
126
+ label='Target Range (70-180)'
127
+ )
128
+
129
+ # Critical zones
130
+ ax.axhspan(
131
+ 0, self.config.critical_low,
132
+ xmin=0, xmax=1,
133
+ alpha=0.3, color='red',
134
+ label='Critical Low (<54)'
135
+ )
136
+
137
+ ax.axhspan(
138
+ self.config.critical_high, 400,
139
+ xmin=0, xmax=1,
140
+ alpha=0.3, color='red',
141
+ label='Critical High (>250)'
142
+ )
143
+
144
+ def _plot_uncertainty_cloud(self,
145
+ ax: plt.Axes,
146
+ data: UncertaintyData) -> plt.Axes:
147
+ """Plot the uncertainty cloud as filled region"""
148
+ # Calculate cloud properties based on confidence
149
+ # Higher confidence = narrower cloud, darker color
150
+
151
+ alpha_values = self.config.cloud_alpha * (1 - data.confidence_scores * 0.5)
152
+
153
+ # Plot multiple layers for visual depth
154
+ for i in range(len(data.timestamps) - 1):
155
+ # Main cloud (prediction bounds)
156
+ polygon = plt.Polygon(
157
+ [
158
+ (data.timestamps[i], data.lower_bounds[i]),
159
+ (data.timestamps[i+1], data.lower_bounds[i+1]),
160
+ (data.timestamps[i+1], data.upper_bounds[i+1]),
161
+ (data.timestamps[i], data.upper_bounds[i])
162
+ ],
163
+ alpha=alpha_values[i] if i < len(alpha_values) else self.config.cloud_alpha,
164
+ facecolor=self.config.uncertainty_color,
165
+ edgecolor='none'
166
+ )
167
+ ax.add_patch(polygon)
168
+
169
+ # Center line (prediction)
170
+ ax.plot(
171
+ data.timestamps, data.predictions,
172
+ color=self.config.prediction_color,
173
+ linewidth=2,
174
+ linestyle='--',
175
+ label='AI Prediction',
176
+ zorder=3
177
+ )
178
+
179
+ return ax
180
+
181
+ def _plot_glucose_line(self,
182
+ ax: plt.Axes,
183
+ data: UncertaintyData,
184
+ time_range: Tuple[float, float]) -> plt.Axes:
185
+ """Plot actual glucose values"""
186
+ # Color glucose line based on values
187
+ colors = []
188
+ for g in data.glucose_values:
189
+ if g < self.config.critical_low:
190
+ colors.append('darkred')
191
+ elif g < self.config.target_low:
192
+ colors.append('red')
193
+ elif g > self.config.critical_high:
194
+ colors.append('darkred')
195
+ elif g > self.config.target_high:
196
+ colors.append('orange')
197
+ else:
198
+ colors.append(self.config.glucose_color)
199
+
200
+ ax.plot(
201
+ data.timestamps, data.glucose_values,
202
+ color=self.config.glucose_color,
203
+ linewidth=2,
204
+ label='Actual Glucose',
205
+ zorder=4
206
+ )
207
+
208
+ # Fill below line with gradient
209
+ ax.fill_between(
210
+ data.timestamps,
211
+ 0,
212
+ data.glucose_values,
213
+ alpha=0.1,
214
+ color=self.config.glucose_color
215
+ )
216
+
217
+ return ax
218
+
219
+ def _add_annotations(self,
220
+ ax: plt.Axes,
221
+ data: UncertaintyData,
222
+ time_range: Tuple[float, float]):
223
+ """Add decision point annotations"""
224
+ if not self.config.show_annotations or not data.decision_points:
225
+ return
226
+
227
+ # Find annotation-worthy points
228
+ for point in data.decision_points:
229
+ timestamp = point.get('timestamp', 0)
230
+ glucose = point.get('glucose', 0)
231
+ reason = point.get('reason', '')
232
+ uncertainty = point.get('uncertainty', 0.5)
233
+
234
+ # Skip if outside time range
235
+ if timestamp < time_range[0] or timestamp > time_range[1]:
236
+ continue
237
+
238
+ # Only annotate significant events
239
+ if abs(uncertainty) > 0.3 or glucose < 70 or glucose > 200:
240
+ # Create annotation text
241
+ if glucose < 70:
242
+ text = f" Low: {glucose:.0f}"
243
+ elif glucose > 200:
244
+ text = f" High: {glucose:.0f}"
245
+ else:
246
+ text = f"Conf: {1-uncertainty:.0%}"
247
+
248
+ ax.annotate(
249
+ text,
250
+ xy=(timestamp, glucose),
251
+ xytext=(timestamp, glucose + 30),
252
+ fontsize=self.config.annotation_fontsize,
253
+ ha='center',
254
+ arrowprops=dict(
255
+ arrowstyle='->',
256
+ color='gray',
257
+ lw=0.5
258
+ ),
259
+ bbox=dict(
260
+ boxstyle='round,pad=0.2',
261
+ facecolor='white',
262
+ alpha=0.8
263
+ ),
264
+ zorder=5
265
+ )
266
+
267
+ def _format_axes(self,
268
+ ax: plt.Axes,
269
+ data: UncertaintyData,
270
+ time_range: Tuple[float, float]):
271
+ """Format plot axes"""
272
+ # Set limits
273
+ ax.set_xlim(time_range)
274
+ ax.set_ylim(40, 350)
275
+
276
+ # Labels
277
+ ax.set_xlabel('Time (minutes)', fontsize=12)
278
+ ax.set_ylabel('Glucose (mg/dL)', fontsize=12)
279
+
280
+ # Title
281
+ ax.set_title(
282
+ 'Glucose Prediction with Uncertainty Cloud',
283
+ fontsize=14,
284
+ fontweight='bold'
285
+ )
286
+
287
+ # Grid
288
+ ax.grid(True, alpha=0.3, linestyle='--')
289
+
290
+ # Y-axis reference lines
291
+ ax.axhline(y=120, color='gray', linestyle=':', alpha=0.5, linewidth=1)
292
+ ax.axhline(y=180, color='orange', linestyle=':', alpha=0.5, linewidth=1)
293
+ ax.axhline(y=70, color='red', linestyle=':', alpha=0.5, linewidth=1)
294
+
295
+ # X-axis ticks (every 60 minutes)
296
+ ax.set_xticks(np.arange(0, data.timestamps.max() + 60, 60))
297
+
298
+ # Legend
299
+ ax.legend(loc='upper right', fontsize=9)
300
+
301
+ def _add_confidence_legend(self,
302
+ fig: plt.Figure,
303
+ ax: plt.Axes):
304
+ """Add confidence level legend"""
305
+ # Create legend for uncertainty
306
+ legend_elements = [
307
+ mpatches.Patch(
308
+ color=self.config.uncertainty_color,
309
+ alpha=0.5,
310
+ label='High Confidence (>80%)'
311
+ ),
312
+ mpatches.Patch(
313
+ color=self.config.uncertainty_color,
314
+ alpha=0.2,
315
+ label='Low Confidence (<50%)'
316
+ )
317
+ ]
318
+
319
+ ax.legend(
320
+ handles=legend_elements,
321
+ loc='lower right',
322
+ fontsize=9,
323
+ title='Uncertainty Level'
324
+ )
325
+
326
+ def plot(self,
327
+ data: UncertaintyData,
328
+ time_range: Optional[Tuple[float, float]] = None,
329
+ save_path: Optional[str] = None) -> plt.Figure:
330
+ """
331
+ Generate uncertainty cloud visualization.
332
+
333
+ Args:
334
+ data: UncertaintyData with all required arrays
335
+ time_range: Optional (min_time, max_time) to display
336
+ save_path: Optional path to save the figure
337
+
338
+ Returns:
339
+ matplotlib Figure object
340
+ """
341
+ self._apply_style()
342
+
343
+ # Determine time range
344
+ if time_range is None:
345
+ time_range = (data.timestamps.min(), data.timestamps.max())
346
+
347
+ # Create figure
348
+ fig, ax = plt.subplots(
349
+ figsize=self.config.figure_size,
350
+ dpi=self.config.dpi
351
+ )
352
+
353
+ # Create target zones
354
+ self._create_target_zones(ax, time_range)
355
+
356
+ # Plot uncertainty cloud
357
+ self._plot_uncertainty_cloud(ax, data)
358
+
359
+ # Plot actual glucose
360
+ self._plot_glucose_line(ax, data, time_range)
361
+
362
+ # Add annotations
363
+ self._add_annotations(ax, data, time_range)
364
+
365
+ # Format axes
366
+ self._format_axes(ax, data, time_range)
367
+
368
+ # Add confidence legend
369
+ self._add_confidence_legend(fig, ax)
370
+
371
+ plt.tight_layout()
372
+
373
+ # Save if requested
374
+ if save_path:
375
+ plt.savefig(save_path, dpi=self.config.dpi, bbox_inches='tight')
376
+ print(f" Saved uncertainty cloud to: {save_path}")
377
+
378
+ return fig
379
+
380
+ def plot_comparison(self,
381
+ data_list: List[Tuple[str, UncertaintyData]],
382
+ save_path: Optional[str] = None) -> plt.Figure:
383
+ """
384
+ Plot multiple uncertainty clouds for comparison.
385
+
386
+ Args:
387
+ data_list: List of (name, data) tuples
388
+ save_path: Optional path to save
389
+
390
+ Returns:
391
+ matplotlib Figure
392
+ """
393
+ self._apply_style()
394
+
395
+ # Create figure with subplots
396
+ n_plots = len(data_list)
397
+ fig, axes = plt.subplots(
398
+ n_plots, 1,
399
+ figsize=(self.config.figure_size[0],
400
+ self.config.figure_size[1] * n_plots / 2),
401
+ dpi=self.config.dpi
402
+ )
403
+
404
+ if n_plots == 1:
405
+ axes = [axes]
406
+
407
+ time_range = (data_list[0][1].timestamps.min(),
408
+ data_list[0][1].timestamps.max())
409
+
410
+ for idx, (name, data) in enumerate(data_list):
411
+ ax = axes[idx]
412
+
413
+ # Target zones
414
+ self._create_target_zones(ax, time_range)
415
+
416
+ # Uncertainty cloud
417
+ self._plot_uncertainty_cloud(ax, data)
418
+
419
+ # Glucose line
420
+ self._plot_glucose_line(ax, data, time_range)
421
+
422
+ # Format
423
+ ax.set_ylabel(f'{name}\nGlucose (mg/dL)', fontsize=10)
424
+ ax.grid(True, alpha=0.3)
425
+ ax.set_xlim(time_range)
426
+ ax.set_ylim(40, 350)
427
+
428
+ # Calculate average confidence
429
+ avg_conf = data.confidence_scores.mean()
430
+ ax.set_title(f'{name} - Avg Confidence: {avg_conf:.0%}', fontsize=11)
431
+
432
+ axes[-1].set_xlabel('Time (minutes)', fontsize=12)
433
+
434
+ plt.tight_layout()
435
+
436
+ if save_path:
437
+ plt.savefig(save_path, dpi=self.config.dpi, bbox_inches='tight')
438
+
439
+ return fig
440
+
441
+ def create_dashboard_widget(self,
442
+ data: UncertaintyData,
443
+ width: int = 400,
444
+ height: int = 200) -> plt.Figure:
445
+ """
446
+ Create a compact widget for dashboard display.
447
+
448
+ Args:
449
+ data: UncertaintyData
450
+ width: Widget width in pixels
451
+ height: Widget height in pixels
452
+
453
+ Returns:
454
+ matplotlib Figure
455
+ """
456
+ self._apply_style()
457
+
458
+ # Create compact figure
459
+ fig, ax = plt.subplots(
460
+ figsize=(width / 100, height / 100),
461
+ dpi=100
462
+ )
463
+
464
+ # Simplified visualization
465
+ ax.fill_between(
466
+ data.timestamps,
467
+ data.lower_bounds,
468
+ data.upper_bounds,
469
+ alpha=0.3,
470
+ color=self.config.uncertainty_color,
471
+ label='Uncertainty'
472
+ )
473
+
474
+ ax.plot(
475
+ data.timestamps, data.glucose_values,
476
+ color=self.config.glucose_color,
477
+ linewidth=1.5
478
+ )
479
+
480
+ ax.plot(
481
+ data.timestamps, data.predictions,
482
+ color=self.config.prediction_color,
483
+ linewidth=1,
484
+ linestyle='--',
485
+ alpha=0.7
486
+ )
487
+
488
+ # Target zone
489
+ ax.axhspan(70, 180, alpha=0.1, color='green')
490
+
491
+ # Formatting
492
+ ax.set_xlim(data.timestamps.min(), data.timestamps.max())
493
+ ax.set_ylim(40, 300)
494
+ ax.set_xticks([])
495
+ ax.set_yticks([70, 120, 180, 250])
496
+ ax.set_yticklabels(['70', '120', '180', '250'], fontsize=8)
497
+ ax.grid(True, alpha=0.2)
498
+
499
+ # Confidence indicator
500
+ avg_conf = data.confidence_scores.mean()
501
+ conf_color = 'green' if avg_conf > 0.7 else 'orange' if avg_conf > 0.5 else 'red'
502
+ ax.text(
503
+ 0.98, 0.95,
504
+ f'Conf: {avg_conf:.0%}',
505
+ transform=ax.transAxes,
506
+ fontsize=8,
507
+ ha='right',
508
+ color=conf_color,
509
+ fontweight='bold'
510
+ )
511
+
512
+ return fig
513
+
514
+
515
+ def generate_sample_data() -> UncertaintyData:
516
+ """Generate sample data for demonstration"""
517
+ np.random.seed(42)
518
+ n_points = 97 # 8 hours at 5-min intervals
519
+
520
+ timestamps = np.arange(0, n_points * 5, 5)
521
+
522
+ # Simulate glucose with realistic patterns
523
+ base_glucose = 120 + 30 * np.sin(timestamps / (24 * 12 / (2 * np.pi)))
524
+ glucose = base_glucose + np.random.normal(0, 10, n_points)
525
+ glucose = np.clip(glucose, 40, 350)
526
+
527
+ # Predictions (slightly ahead of actual)
528
+ predictions = np.roll(glucose, 1)
529
+ predictions[0] = glucose[0]
530
+ predictions = predictions + np.random.normal(0, 5, n_points)
531
+
532
+ # Confidence scores (lower during meals/changes)
533
+ confidence = 0.9 - 0.3 * np.abs(np.gradient(glucose)) / 10
534
+ confidence = np.clip(confidence, 0.4, 0.95)
535
+
536
+ # Uncertainty bounds
537
+ uncertainty = 1 - confidence
538
+ lower_bounds = predictions - 20 * (1 + uncertainty)
539
+ upper_bounds = predictions + 20 * (1 + uncertainty)
540
+ lower_bounds = np.clip(lower_bounds, 20, 350)
541
+ upper_bounds = np.clip(upper_bounds, 20, 350)
542
+
543
+ # Decision points
544
+ decision_points = [
545
+ {'timestamp': 100, 'glucose': 170, 'reason': 'High glucose correction', 'uncertainty': 0.2},
546
+ {'timestamp': 250, 'glucose': 65, 'reason': 'Low glucose detected', 'uncertainty': 0.1},
547
+ ]
548
+
549
+ return UncertaintyData(
550
+ timestamps=timestamps,
551
+ glucose_values=glucose,
552
+ predictions=predictions,
553
+ lower_bounds=lower_bounds,
554
+ upper_bounds=upper_bounds,
555
+ confidence_scores=confidence,
556
+ decision_points=decision_points
557
+ )
558
+
559
+
560
+ def demo_uncertainty_cloud():
561
+ """Demonstrate uncertainty cloud visualization"""
562
+ print("=" * 70)
563
+ print("UNCERTAINTY CLOUD VISUALIZATION DEMONSTRATION")
564
+ print("=" * 70)
565
+
566
+ # Generate sample data
567
+ print("\n Generating sample data...")
568
+ data = generate_sample_data()
569
+
570
+ print(f" Data points: {len(data.timestamps)}")
571
+ print(f" Time range: {data.timestamps.min()}-{data.timestamps.max()} minutes")
572
+ print(f" Avg confidence: {data.confidence_scores.mean():.1%}")
573
+
574
+ # Create visualizer
575
+ cloud = UncertaintyCloud()
576
+
577
+ # Generate main plot
578
+ print("\n Generating main uncertainty cloud...")
579
+ fig = cloud.plot(data, save_path="results/visualization/uncertainty_cloud_main.png")
580
+
581
+ # Generate comparison plot
582
+ print("\n Generating comparison visualization...")
583
+
584
+ # Create second dataset (improved algorithm)
585
+ data2 = generate_sample_data()
586
+ data2.predictions = data2.predictions * 0.95 # Better predictions
587
+ data2.confidence_scores = np.clip(data2.confidence_scores + 0.05, 0, 1)
588
+
589
+ comparison_fig = cloud.plot_comparison(
590
+ [("Original Algorithm", data), ("Improved Algorithm", data2)],
591
+ save_path="results/visualization/uncertainty_cloud_comparison.png"
592
+ )
593
+
594
+ # Generate dashboard widget
595
+ print("\n Generating dashboard widget...")
596
+ widget = cloud.create_dashboard_widget(data)
597
+ widget.savefig("results/visualization/uncertainty_widget.png",
598
+ dpi=100, bbox_inches='tight')
599
+
600
+ print("\n Visualization files saved:")
601
+ print(" - results/visualization/uncertainty_cloud_main.png")
602
+ print(" - results/visualization/uncertainty_cloud_comparison.png")
603
+ print(" - results/visualization/uncertainty_widget.png")
604
+
605
+ print("\n" + "=" * 70)
606
+ print("UNCERTAINTY CLOUD DEMONSTRATION COMPLETE")
607
+ print("=" * 70)
608
+
609
+
610
+ if __name__ == "__main__":
611
+ demo_uncertainty_cloud()
612
+