processbehavior 0.2.0__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 (56) hide show
  1. processbehavior/__init__.py +133 -0
  2. processbehavior/analysis.py +2944 -0
  3. processbehavior/analysis_dataset.py +361 -0
  4. processbehavior/analysis_result.py +1276 -0
  5. processbehavior/calibration.py +70 -0
  6. processbehavior/capability.py +720 -0
  7. processbehavior/data_preparation.py +792 -0
  8. processbehavior/datasets/__init__.py +37 -0
  9. processbehavior/datasets/data/coffee_shop_demo_long.csv +385 -0
  10. processbehavior/datasets/loaders.py +66 -0
  11. processbehavior/datasets/synthetic.py +1711 -0
  12. processbehavior/derivations.py +602 -0
  13. processbehavior/effects_calculator.py +603 -0
  14. processbehavior/exceptions.py +216 -0
  15. processbehavior/exporters/__init__.py +5 -0
  16. processbehavior/exporters/excel_exporter.py +708 -0
  17. processbehavior/focused_result.py +329 -0
  18. processbehavior/formulation_spec.py +144 -0
  19. processbehavior/loss_function.py +517 -0
  20. processbehavior/maximum_information.py +285 -0
  21. processbehavior/plotting/__init__.py +46 -0
  22. processbehavior/plotting/_math.py +121 -0
  23. processbehavior/plotting/capability_chart.py +858 -0
  24. processbehavior/plotting/contracts.py +176 -0
  25. processbehavior/plotting/control_chart.py +206 -0
  26. processbehavior/plotting/effects_charts.py +640 -0
  27. processbehavior/plotting/lane_boundaries.py +78 -0
  28. processbehavior/plotting/limits.py +157 -0
  29. processbehavior/plotting/maximum_information_chart.py +395 -0
  30. processbehavior/plotting/plotter.py +1469 -0
  31. processbehavior/plotting/renderers.py +660 -0
  32. processbehavior/plotting/report.py +211 -0
  33. processbehavior/plotting/residuals.py +282 -0
  34. processbehavior/plotting/run_rules_viz.py +150 -0
  35. processbehavior/plotting/stats_box.py +183 -0
  36. processbehavior/plotting/themes.py +544 -0
  37. processbehavior/plotting/x_axis_layout.py +474 -0
  38. processbehavior/plotting/zones.py +127 -0
  39. processbehavior/process_behavior.py +1290 -0
  40. processbehavior/py.typed +0 -0
  41. processbehavior/residual_calculator.py +572 -0
  42. processbehavior/result_signals.py +149 -0
  43. processbehavior/result_tabular.py +296 -0
  44. processbehavior/sds_detector.py +1432 -0
  45. processbehavior/signals/__init__.py +14 -0
  46. processbehavior/signals/config.py +435 -0
  47. processbehavior/signals/detector.py +328 -0
  48. processbehavior/signals/detectors.py +368 -0
  49. processbehavior/signals/result.py +232 -0
  50. processbehavior/spc_constants.py +692 -0
  51. processbehavior/study.py +2733 -0
  52. processbehavior/types.py +154 -0
  53. processbehavior-0.2.0.dist-info/METADATA +279 -0
  54. processbehavior-0.2.0.dist-info/RECORD +56 -0
  55. processbehavior-0.2.0.dist-info/WHEEL +4 -0
  56. processbehavior-0.2.0.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,544 @@
1
+ """
2
+ Theme definitions for control chart plotting.
3
+
4
+ Provides a comprehensive theme system with full customization of colors,
5
+ sizes, fonts, and layout properties. Inspired by ggplot2's theme system.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass
11
+ from typing import TYPE_CHECKING
12
+
13
+ from ..exceptions import ValidationError
14
+
15
+ if TYPE_CHECKING:
16
+ import plotly.graph_objects as go
17
+
18
+
19
+ @dataclass
20
+ class ChartTheme:
21
+ """
22
+ Complete theme specification for control charts.
23
+
24
+ This dataclass defines all visual properties for control chart rendering,
25
+ following ggplot2's philosophy of sensible defaults with full customization.
26
+
27
+ Attributes
28
+ ----------
29
+ name : str
30
+ Theme identifier
31
+
32
+ # Data appearance
33
+ data_color : str
34
+ Color for data points and lines
35
+ data_marker_size : int
36
+ Size of data point markers
37
+ data_line_width : float
38
+ Width of data connecting lines
39
+
40
+ # Control limits
41
+ ucl_color : str
42
+ Upper control limit line color
43
+ lcl_color : str
44
+ Lower control limit line color
45
+ center_color : str
46
+ Centerline color
47
+ limit_line_dash : str
48
+ Dash style for control limits ('dash', 'dot', 'solid')
49
+ limit_line_width : float
50
+ Width of control limit lines
51
+ center_line_width : float
52
+ Width of centerline
53
+
54
+ # Signal/out-of-control markers
55
+ signal_color : str
56
+ Color for out-of-control points
57
+ signal_marker_size : int
58
+ Size of signal markers
59
+ signal_marker_symbol : str
60
+ Plotly marker symbol ('x', 'circle', 'diamond', etc.)
61
+ signal_marker_line_width : float
62
+ Line width of signal marker border
63
+ signal_marker_line_color : str
64
+ Border color of signal markers
65
+
66
+ # Zone shading (for Western Electric rules visualization)
67
+ zone_a_color : str
68
+ Zone A (±2σ to ±3σ) fill color
69
+ zone_b_color : str
70
+ Zone B (±1σ to ±2σ) fill color
71
+ zone_c_color : str
72
+ Zone C (±0σ to ±1σ) fill color
73
+ zone_opacity : float
74
+ Opacity for zone shading (0-1)
75
+
76
+ # Layout
77
+ plot_bgcolor : str
78
+ Plot area background color
79
+ paper_bgcolor : str
80
+ Figure background color
81
+ grid_color : str
82
+ Grid line color
83
+ grid_width : float
84
+ Grid line width
85
+ show_grid : bool
86
+ Whether to show grid lines
87
+ axis_line_color : str
88
+ Axis line color
89
+ axis_line_width : float
90
+ Axis line width
91
+
92
+ # Typography
93
+ font_family : str
94
+ Font family for all text
95
+ font_size : int
96
+ Base font size
97
+ font_color : str
98
+ Default text color
99
+ title_font_size : int
100
+ Title font size
101
+ title_font_color : str
102
+ Title color
103
+ axis_title_font_size : int
104
+ Axis title font size
105
+ annotation_font_size : int
106
+ Annotation (limit labels) font size
107
+ data_opacity : float
108
+ Opacity for data points and lines (0-1)
109
+ show_axis_line : bool
110
+ Whether to show axis lines
111
+ facet_col_spacing : float
112
+ Horizontal spacing between facet columns (fraction of figure width)
113
+ facet_row_spacing : float
114
+ Vertical spacing between facet rows (fraction of figure height)
115
+ lane_boundary_color : str
116
+ Color for lane boundary lines (vertical separators for collapsed factors)
117
+ lane_boundary_width : float
118
+ Width of lane boundary lines
119
+ lane_label_font_size : int
120
+ Font size for lane boundary annotations
121
+ stats_box_bgcolor : str
122
+ Background color for statistics box annotations
123
+ stats_box_bordercolor : str
124
+ Border color for statistics box
125
+ stats_box_borderwidth : int
126
+ Border width for statistics box
127
+ stats_box_font_size : int
128
+ Font size for statistics box text
129
+ stats_box_font_color : str
130
+ Font color for statistics box text
131
+ pattern_signal_color : str
132
+ Color for pattern-based signal markers (Rules 2-8)
133
+
134
+ Examples
135
+ --------
136
+ Create custom theme:
137
+
138
+ >>> theme = ChartTheme(
139
+ ... name='custom',
140
+ ... data_color='navy',
141
+ ... signal_color='orange',
142
+ ... center_color='darkgreen'
143
+ ... )
144
+
145
+ Modify existing theme:
146
+
147
+ >>> theme = get_theme('processbehavior')
148
+ >>> theme.data_color = 'purple'
149
+ """
150
+
151
+ # Theme name
152
+ name: str = 'processbehavior'
153
+
154
+ # Data appearance
155
+ data_color: str = 'steelblue'
156
+ data_marker_size: int = 5
157
+ data_line_width: float = 1.0
158
+ data_opacity: float = 1.0
159
+
160
+ # Control limits
161
+ ucl_color: str = 'red'
162
+ lcl_color: str = 'red'
163
+ center_color: str = '#2E8B57' # SeaGreen - professional green
164
+ limit_line_dash: str = 'dash'
165
+ limit_line_width: float = 1.5
166
+ center_line_width: float = 1.5
167
+
168
+ # Signal markers - Two-tier system:
169
+ # Both tiers use same marker style/size as data (circle, size 5), differentiated only by color
170
+ # Tier 1 (Rule 1): Red - points outside control limits
171
+ signal_color: str = 'red'
172
+ signal_marker_size: int = 5 # Same size as data points
173
+ signal_marker_symbol: str = 'circle' # Same as data points
174
+ signal_marker_line_width: float = 0.5
175
+ signal_marker_line_color: str = 'darkred'
176
+ # Tier 2 (Rules 2-8): Orange - pattern-based signals
177
+ pattern_signal_color: str = '#FF8C00' # Dark Orange
178
+
179
+ # Limit summary annotation (above subplot)
180
+ limit_summary_color: str = '#333333'
181
+ limit_summary_bgcolor: str = 'rgba(255,255,255,0.7)'
182
+
183
+ # Zone shading
184
+ zone_a_color: str = '#FFB3B3' # Light red
185
+ zone_b_color: str = '#FFFFB3' # Light yellow
186
+ zone_c_color: str = '#B3FFB3' # Light green
187
+ zone_opacity: float = 0.15
188
+
189
+ # Layout
190
+ plot_bgcolor: str = 'white'
191
+ paper_bgcolor: str = 'white'
192
+ grid_color: str = '#E5E5E5'
193
+ grid_width: float = 1.0
194
+ show_grid: bool = True
195
+ axis_line_color: str = '#999999'
196
+ axis_line_width: float = 1.0
197
+ show_axis_line: bool = True
198
+
199
+ # Typography
200
+ font_family: str = 'Arial, sans-serif'
201
+ font_size: int = 12
202
+ font_color: str = '#333333'
203
+ title_font_size: int = 16
204
+ title_font_color: str = '#222222'
205
+ axis_title_font_size: int = 12
206
+ annotation_font_size: int = 10
207
+
208
+ # Faceted plot settings
209
+ facet_marker_size: int = 5
210
+ facet_line_width: float = 1.5
211
+
212
+ # Lane boundaries (vertical separators for collapsed factors)
213
+ lane_boundary_color: str = '#888888' # Medium gray
214
+ lane_boundary_dash: str = 'dot'
215
+ lane_boundary_width: float = 1.0
216
+ lane_boundary_annotation_size: int = 8
217
+
218
+ # Stats box
219
+ stats_box_bgcolor: str = 'rgba(255, 255, 255, 0.9)'
220
+ stats_box_bordercolor: str = '#CCCCCC'
221
+ stats_box_borderwidth: int = 1
222
+ stats_box_font_size: int = 10
223
+ stats_box_font_color: str = '#333333'
224
+
225
+ def to_layout_dict(self) -> dict:
226
+ """
227
+ Convert theme to Plotly layout dictionary.
228
+
229
+ Returns
230
+ -------
231
+ dict
232
+ Layout properties for fig.update_layout()
233
+ """
234
+ return {
235
+ 'plot_bgcolor': self.plot_bgcolor,
236
+ 'paper_bgcolor': self.paper_bgcolor,
237
+ 'font': {'family': self.font_family, 'size': self.font_size, 'color': self.font_color},
238
+ 'title': {
239
+ 'font': {'size': self.title_font_size, 'color': self.title_font_color},
240
+ 'x': 0.5,
241
+ 'xanchor': 'center',
242
+ },
243
+ 'xaxis': {
244
+ 'showgrid': self.show_grid,
245
+ 'gridcolor': self.grid_color,
246
+ 'gridwidth': self.grid_width,
247
+ 'showline': self.show_axis_line,
248
+ 'linecolor': self.axis_line_color,
249
+ 'linewidth': self.axis_line_width,
250
+ },
251
+ 'yaxis': {
252
+ 'showgrid': self.show_grid,
253
+ 'gridcolor': self.grid_color,
254
+ 'gridwidth': self.grid_width,
255
+ 'showline': self.show_axis_line,
256
+ 'linecolor': self.axis_line_color,
257
+ 'linewidth': self.axis_line_width,
258
+ 'zeroline': False,
259
+ },
260
+ }
261
+
262
+
263
+ # =============================================================================
264
+ # Built-in Themes
265
+ # =============================================================================
266
+
267
+
268
+ def _create_processbehavior_theme() -> ChartTheme:
269
+ """Default theme with professional, balanced appearance."""
270
+ return ChartTheme(
271
+ name='processbehavior',
272
+ data_opacity=0.8,
273
+ )
274
+
275
+
276
+ def _create_ggplot_theme() -> ChartTheme:
277
+ """Theme inspired by ggplot2's default appearance."""
278
+ return ChartTheme(
279
+ name='ggplot',
280
+ # Data - ggplot2's default blue
281
+ data_color='#3366CC',
282
+ # Control limits
283
+ ucl_color='#E31A1C', # ggplot2 red
284
+ lcl_color='#E31A1C',
285
+ center_color='#33A02C', # ggplot2 green
286
+ limit_line_width=1.2,
287
+ center_line_width=1.2,
288
+ # Signals - same marker as data, just red fill
289
+ signal_color='#E31A1C',
290
+ signal_marker_symbol='circle',
291
+ signal_marker_line_color='#B2182B',
292
+ # Zones
293
+ zone_a_color='#FDAE61',
294
+ zone_b_color='#FEE08B',
295
+ zone_c_color='#D9EF8B',
296
+ zone_opacity=0.2,
297
+ # Layout - ggplot2's gray panel background
298
+ plot_bgcolor='#EBEBEB',
299
+ paper_bgcolor='white',
300
+ grid_color='white',
301
+ grid_width=1.0,
302
+ axis_line_color='#EBEBEB',
303
+ # Typography
304
+ font_family='sans-serif',
305
+ font_size=11,
306
+ font_color='#333333',
307
+ title_font_size=14,
308
+ )
309
+
310
+
311
+ def _create_minimal_theme() -> ChartTheme:
312
+ """Clean, minimalist theme with reduced visual elements."""
313
+ return ChartTheme(
314
+ name='minimal',
315
+ # Data
316
+ data_color='#2C3E50', # Dark slate
317
+ # Control limits - subtle
318
+ ucl_color='#95A5A6', # Gray
319
+ lcl_color='#95A5A6',
320
+ center_color='#7F8C8D',
321
+ limit_line_dash='dot',
322
+ limit_line_width=1.0,
323
+ center_line_width=1.0,
324
+ # Signals - same marker as data, just red fill
325
+ signal_color='#E74C3C', # Flat red
326
+ signal_marker_symbol='circle',
327
+ signal_marker_line_color='#C0392B',
328
+ # Zones - very subtle
329
+ zone_a_color='#FADBD8',
330
+ zone_b_color='#FCF3CF',
331
+ zone_c_color='#D5F5E3',
332
+ zone_opacity=0.1,
333
+ # Layout - minimal grid
334
+ plot_bgcolor='white',
335
+ paper_bgcolor='white',
336
+ grid_color='#F5F5F5',
337
+ show_grid=True, # Only y-grid
338
+ axis_line_color='#CCCCCC',
339
+ # Typography
340
+ font_family='Helvetica, sans-serif',
341
+ font_size=11,
342
+ font_color='#2C3E50',
343
+ title_font_size=14,
344
+ title_font_color='#2C3E50',
345
+ )
346
+
347
+
348
+ def _create_dark_theme() -> ChartTheme:
349
+ """Dark theme for presentations and dark mode UIs."""
350
+ return ChartTheme(
351
+ name='dark',
352
+ # Data - bright for contrast
353
+ data_color='#00D4AA', # Teal/cyan
354
+ # Control limits
355
+ ucl_color='#FF6B6B', # Soft red
356
+ lcl_color='#FF6B6B',
357
+ center_color='#4ECDC4', # Bright teal
358
+ limit_line_width=1.5,
359
+ center_line_width=1.5,
360
+ # Signals - same marker as data, just red fill
361
+ signal_color='#FF4757', # Bright red
362
+ signal_marker_symbol='circle',
363
+ signal_marker_line_color='#FF6B81',
364
+ # Zones - semi-transparent on dark
365
+ zone_a_color='#FF6B6B',
366
+ zone_b_color='#FFA502',
367
+ zone_c_color='#2ED573',
368
+ zone_opacity=0.15,
369
+ # Layout
370
+ plot_bgcolor='#1E1E1E',
371
+ paper_bgcolor='#2D2D2D',
372
+ grid_color='#444444',
373
+ axis_line_color='#666666',
374
+ # Typography
375
+ font_family='Arial, sans-serif',
376
+ font_size=12,
377
+ font_color='#E0E0E0',
378
+ title_font_size=16,
379
+ title_font_color='#FFFFFF',
380
+ # Limit summary
381
+ limit_summary_color='#FFFFFF',
382
+ limit_summary_bgcolor='rgba(30,30,30,0.7)',
383
+ )
384
+
385
+
386
+ def _create_publication_theme() -> ChartTheme:
387
+ """Theme optimized for academic publications and print."""
388
+ return ChartTheme(
389
+ name='publication',
390
+ # Data - high contrast black
391
+ data_color='#000000',
392
+ data_marker_size=5,
393
+ # Control limits - grayscale for B&W printing
394
+ ucl_color='#666666',
395
+ lcl_color='#666666',
396
+ center_color='#333333',
397
+ limit_line_dash='dash',
398
+ limit_line_width=0.8,
399
+ center_line_width=1.0,
400
+ # Signals - red to stand out against black data
401
+ signal_color='red',
402
+ signal_marker_size=5, # Same as data_marker_size
403
+ signal_marker_symbol='circle',
404
+ signal_marker_line_width=0.5,
405
+ signal_marker_line_color='darkred',
406
+ # Zones - not used in print (set opacity to 0)
407
+ zone_opacity=0.0,
408
+ # Layout - clean white
409
+ plot_bgcolor='white',
410
+ paper_bgcolor='white',
411
+ grid_color='#CCCCCC',
412
+ grid_width=0.5,
413
+ axis_line_color='#000000',
414
+ axis_line_width=1.0,
415
+ # Typography - serif for academic
416
+ font_family='Times New Roman, serif',
417
+ font_size=10,
418
+ font_color='#000000',
419
+ title_font_size=12,
420
+ title_font_color='#000000',
421
+ axis_title_font_size=10,
422
+ annotation_font_size=9,
423
+ facet_line_width=0.8,
424
+ )
425
+
426
+
427
+ # =============================================================================
428
+ # Theme Registry and Access Functions
429
+ # =============================================================================
430
+
431
+ # Registry of built-in themes (lazily populated)
432
+ _THEME_REGISTRY: dict[str, ChartTheme] = {}
433
+
434
+
435
+ def _ensure_registry():
436
+ """Populate theme registry if empty."""
437
+ global _THEME_REGISTRY
438
+ if not _THEME_REGISTRY:
439
+ _THEME_REGISTRY = {
440
+ 'processbehavior': _create_processbehavior_theme(),
441
+ 'ggplot': _create_ggplot_theme(),
442
+ 'minimal': _create_minimal_theme(),
443
+ 'dark': _create_dark_theme(),
444
+ 'publication': _create_publication_theme(),
445
+ }
446
+
447
+
448
+ def get_theme(name: str) -> ChartTheme:
449
+ """
450
+ Get a theme by name.
451
+
452
+ Parameters
453
+ ----------
454
+ name : str
455
+ Theme name ('processbehavior', 'ggplot', 'minimal', 'dark', 'publication')
456
+
457
+ Returns
458
+ -------
459
+ ChartTheme
460
+ Copy of the requested theme (safe to modify)
461
+
462
+ Raises
463
+ ------
464
+ ValueError
465
+ If theme name is not found
466
+
467
+ Examples
468
+ --------
469
+ >>> theme = get_theme('ggplot')
470
+ >>> theme.data_color = 'purple' # Safe to modify
471
+ """
472
+ _ensure_registry()
473
+
474
+ if name not in _THEME_REGISTRY:
475
+ available = list(_THEME_REGISTRY.keys())
476
+ raise ValidationError(f"Unknown theme: '{name}'.\nAvailable themes: {available}")
477
+
478
+ # Return a copy so modifications don't affect the registry
479
+ import copy
480
+
481
+ return copy.copy(_THEME_REGISTRY[name])
482
+
483
+
484
+ def list_themes() -> list[str]:
485
+ """
486
+ List all available theme names.
487
+
488
+ Returns
489
+ -------
490
+ list of str
491
+ Available theme names
492
+ """
493
+ _ensure_registry()
494
+ return list(_THEME_REGISTRY.keys())
495
+
496
+
497
+ def register_theme(theme: ChartTheme):
498
+ """
499
+ Register a custom theme.
500
+
501
+ Parameters
502
+ ----------
503
+ theme : ChartTheme
504
+ Theme to register (uses theme.name as key)
505
+
506
+ Examples
507
+ --------
508
+ >>> custom = ChartTheme(name='corporate', data_color='#003366')
509
+ >>> register_theme(custom)
510
+ >>> fig = plotter.plot(theme='corporate')
511
+ """
512
+ _ensure_registry()
513
+ _THEME_REGISTRY[theme.name] = theme
514
+
515
+
516
+ def apply_theme(fig: go.Figure, theme: str | ChartTheme = 'processbehavior') -> go.Figure:
517
+ """
518
+ Apply a theme to a Plotly figure.
519
+
520
+ Parameters
521
+ ----------
522
+ fig : go.Figure
523
+ Plotly figure to apply theme to
524
+ theme : str or ChartTheme
525
+ Theme name or ChartTheme instance
526
+
527
+ Returns
528
+ -------
529
+ go.Figure
530
+ Figure with theme applied
531
+
532
+ Examples
533
+ --------
534
+ >>> fig = go.Figure()
535
+ >>> fig = apply_theme(fig, 'dark')
536
+
537
+ >>> custom_theme = ChartTheme(name='custom', plot_bgcolor='#F0F0F0')
538
+ >>> fig = apply_theme(fig, custom_theme)
539
+ """
540
+ theme = get_theme(theme) if isinstance(theme, str) else theme
541
+
542
+ fig.update_layout(**theme.to_layout_dict())
543
+
544
+ return fig