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.
- processbehavior/__init__.py +133 -0
- processbehavior/analysis.py +2944 -0
- processbehavior/analysis_dataset.py +361 -0
- processbehavior/analysis_result.py +1276 -0
- processbehavior/calibration.py +70 -0
- processbehavior/capability.py +720 -0
- processbehavior/data_preparation.py +792 -0
- processbehavior/datasets/__init__.py +37 -0
- processbehavior/datasets/data/coffee_shop_demo_long.csv +385 -0
- processbehavior/datasets/loaders.py +66 -0
- processbehavior/datasets/synthetic.py +1711 -0
- processbehavior/derivations.py +602 -0
- processbehavior/effects_calculator.py +603 -0
- processbehavior/exceptions.py +216 -0
- processbehavior/exporters/__init__.py +5 -0
- processbehavior/exporters/excel_exporter.py +708 -0
- processbehavior/focused_result.py +329 -0
- processbehavior/formulation_spec.py +144 -0
- processbehavior/loss_function.py +517 -0
- processbehavior/maximum_information.py +285 -0
- processbehavior/plotting/__init__.py +46 -0
- processbehavior/plotting/_math.py +121 -0
- processbehavior/plotting/capability_chart.py +858 -0
- processbehavior/plotting/contracts.py +176 -0
- processbehavior/plotting/control_chart.py +206 -0
- processbehavior/plotting/effects_charts.py +640 -0
- processbehavior/plotting/lane_boundaries.py +78 -0
- processbehavior/plotting/limits.py +157 -0
- processbehavior/plotting/maximum_information_chart.py +395 -0
- processbehavior/plotting/plotter.py +1469 -0
- processbehavior/plotting/renderers.py +660 -0
- processbehavior/plotting/report.py +211 -0
- processbehavior/plotting/residuals.py +282 -0
- processbehavior/plotting/run_rules_viz.py +150 -0
- processbehavior/plotting/stats_box.py +183 -0
- processbehavior/plotting/themes.py +544 -0
- processbehavior/plotting/x_axis_layout.py +474 -0
- processbehavior/plotting/zones.py +127 -0
- processbehavior/process_behavior.py +1290 -0
- processbehavior/py.typed +0 -0
- processbehavior/residual_calculator.py +572 -0
- processbehavior/result_signals.py +149 -0
- processbehavior/result_tabular.py +296 -0
- processbehavior/sds_detector.py +1432 -0
- processbehavior/signals/__init__.py +14 -0
- processbehavior/signals/config.py +435 -0
- processbehavior/signals/detector.py +328 -0
- processbehavior/signals/detectors.py +368 -0
- processbehavior/signals/result.py +232 -0
- processbehavior/spc_constants.py +692 -0
- processbehavior/study.py +2733 -0
- processbehavior/types.py +154 -0
- processbehavior-0.2.0.dist-info/METADATA +279 -0
- processbehavior-0.2.0.dist-info/RECORD +56 -0
- processbehavior-0.2.0.dist-info/WHEEL +4 -0
- processbehavior-0.2.0.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"""Statistics box rendering for control charts."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
import plotly.graph_objects as go
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
import pandas as pd
|
|
12
|
+
|
|
13
|
+
from .themes import ChartTheme
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def format_stat_value(value: float, compact: bool = False) -> str:
|
|
19
|
+
"""
|
|
20
|
+
Format a statistic value for display.
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
value : float
|
|
25
|
+
The statistic value to format
|
|
26
|
+
compact : bool
|
|
27
|
+
If True, use fewer decimal places for compact display
|
|
28
|
+
|
|
29
|
+
Returns
|
|
30
|
+
-------
|
|
31
|
+
str
|
|
32
|
+
Formatted value string
|
|
33
|
+
"""
|
|
34
|
+
if compact:
|
|
35
|
+
if abs(value) >= 100:
|
|
36
|
+
return f'{value:.0f}'
|
|
37
|
+
elif abs(value) >= 10:
|
|
38
|
+
return f'{value:.1f}'
|
|
39
|
+
else:
|
|
40
|
+
return f'{value:.2f}'
|
|
41
|
+
else:
|
|
42
|
+
if abs(value) >= 100:
|
|
43
|
+
return f'{value:.2f}'
|
|
44
|
+
elif abs(value) >= 10:
|
|
45
|
+
return f'{value:.3f}'
|
|
46
|
+
else:
|
|
47
|
+
return f'{value:.4f}'
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def build_stats_text(stats: dict, data: pd.DataFrame, compact: bool = False) -> str | None:
|
|
51
|
+
"""
|
|
52
|
+
Build statistics text for display in a stats box.
|
|
53
|
+
|
|
54
|
+
Parameters
|
|
55
|
+
----------
|
|
56
|
+
stats : dict
|
|
57
|
+
Chart statistics with 'center', 'upl', 'lpl' keys
|
|
58
|
+
data : DataFrame
|
|
59
|
+
Chart data (for calculating n)
|
|
60
|
+
compact : bool, default False
|
|
61
|
+
If True, use compact format (n=X | CL=Y) for faceted charts.
|
|
62
|
+
If False, use full format with line breaks.
|
|
63
|
+
|
|
64
|
+
Returns
|
|
65
|
+
-------
|
|
66
|
+
str or None
|
|
67
|
+
Formatted stats text, or None if no stats available
|
|
68
|
+
"""
|
|
69
|
+
n = len(data)
|
|
70
|
+
|
|
71
|
+
if compact:
|
|
72
|
+
parts = [f'n={n}']
|
|
73
|
+
center = stats.get('center')
|
|
74
|
+
if center is not None:
|
|
75
|
+
parts.append(f'CL={format_stat_value(center, compact=True)}')
|
|
76
|
+
return ' | '.join(parts) if parts else None
|
|
77
|
+
else:
|
|
78
|
+
lines = [f'n = {n}']
|
|
79
|
+
|
|
80
|
+
center = stats.get('center')
|
|
81
|
+
if center is not None:
|
|
82
|
+
lines.append(f'CL = {format_stat_value(center)}')
|
|
83
|
+
|
|
84
|
+
ucl = stats.get('upl')
|
|
85
|
+
if ucl is not None:
|
|
86
|
+
lines.append(f'UPL = {format_stat_value(ucl)}')
|
|
87
|
+
|
|
88
|
+
lcl = stats.get('lpl')
|
|
89
|
+
if lcl is not None:
|
|
90
|
+
lines.append(f'LPL = {format_stat_value(lcl)}')
|
|
91
|
+
|
|
92
|
+
return '<br>'.join(lines) if lines else None
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def add_stats_box(
|
|
96
|
+
fig: go.Figure,
|
|
97
|
+
stats: dict,
|
|
98
|
+
data: pd.DataFrame,
|
|
99
|
+
theme: ChartTheme,
|
|
100
|
+
row: int | None = None,
|
|
101
|
+
col: int | None = None,
|
|
102
|
+
nrows: int | None = None,
|
|
103
|
+
ncols: int | None = None,
|
|
104
|
+
) -> None:
|
|
105
|
+
"""
|
|
106
|
+
Add a statistics box annotation to a chart.
|
|
107
|
+
|
|
108
|
+
Unified function for both single charts and faceted subplots.
|
|
109
|
+
When row/col are None, positions at paper (0.02, 0.98) with full text.
|
|
110
|
+
When provided, calculates subplot-relative position with compact text.
|
|
111
|
+
|
|
112
|
+
Parameters
|
|
113
|
+
----------
|
|
114
|
+
fig : go.Figure
|
|
115
|
+
Plotly figure to add annotation to
|
|
116
|
+
stats : dict
|
|
117
|
+
Chart statistics with 'center', 'upl', 'lpl' keys
|
|
118
|
+
data : DataFrame
|
|
119
|
+
Chart data (for calculating n)
|
|
120
|
+
theme : ChartTheme
|
|
121
|
+
Theme with stats box styling
|
|
122
|
+
row : int, optional
|
|
123
|
+
Row number of subplot (1-indexed). None for single charts.
|
|
124
|
+
col : int, optional
|
|
125
|
+
Column number of subplot (1-indexed). None for single charts.
|
|
126
|
+
nrows : int, optional
|
|
127
|
+
Total number of rows in the facet grid. Required when row/col are set.
|
|
128
|
+
ncols : int, optional
|
|
129
|
+
Total number of columns in the facet grid. Required when row/col are set.
|
|
130
|
+
"""
|
|
131
|
+
if row is not None and col is not None:
|
|
132
|
+
if not ncols or not nrows or ncols <= 0 or nrows <= 0:
|
|
133
|
+
logger.debug('Invalid grid dimensions (nrows=%s, ncols=%s); skipping stats box', nrows, ncols)
|
|
134
|
+
return
|
|
135
|
+
|
|
136
|
+
# Faceted: compact text, subplot-relative position, smaller font
|
|
137
|
+
stats_text = build_stats_text(stats, data, compact=True)
|
|
138
|
+
if stats_text is None:
|
|
139
|
+
return
|
|
140
|
+
|
|
141
|
+
col_width = 1.0 / ncols
|
|
142
|
+
row_height = 1.0 / nrows
|
|
143
|
+
x_pos = (col - 1) * col_width + 0.02 * col_width
|
|
144
|
+
y_pos = 1.0 - (row - 1) * row_height - 0.05 * row_height
|
|
145
|
+
|
|
146
|
+
fig.add_annotation(
|
|
147
|
+
text=stats_text,
|
|
148
|
+
xref='paper',
|
|
149
|
+
yref='paper',
|
|
150
|
+
x=x_pos,
|
|
151
|
+
y=y_pos,
|
|
152
|
+
xanchor='left',
|
|
153
|
+
yanchor='top',
|
|
154
|
+
showarrow=False,
|
|
155
|
+
font=dict(size=theme.stats_box_font_size - 1, color=theme.stats_box_font_color, family='monospace'),
|
|
156
|
+
bgcolor=theme.stats_box_bgcolor,
|
|
157
|
+
bordercolor=theme.stats_box_bordercolor,
|
|
158
|
+
borderwidth=theme.stats_box_borderwidth,
|
|
159
|
+
borderpad=3,
|
|
160
|
+
align='left',
|
|
161
|
+
)
|
|
162
|
+
else:
|
|
163
|
+
# Single chart: full text, fixed position, standard font
|
|
164
|
+
stats_text = build_stats_text(stats, data, compact=False)
|
|
165
|
+
if stats_text is None:
|
|
166
|
+
return
|
|
167
|
+
|
|
168
|
+
fig.add_annotation(
|
|
169
|
+
text=stats_text,
|
|
170
|
+
xref='paper',
|
|
171
|
+
yref='paper',
|
|
172
|
+
x=0.02,
|
|
173
|
+
y=0.98,
|
|
174
|
+
xanchor='left',
|
|
175
|
+
yanchor='top',
|
|
176
|
+
showarrow=False,
|
|
177
|
+
font=dict(size=theme.stats_box_font_size, color=theme.stats_box_font_color, family='monospace'),
|
|
178
|
+
bgcolor=theme.stats_box_bgcolor,
|
|
179
|
+
bordercolor=theme.stats_box_bordercolor,
|
|
180
|
+
borderwidth=theme.stats_box_borderwidth,
|
|
181
|
+
borderpad=6,
|
|
182
|
+
align='left',
|
|
183
|
+
)
|