Repository navigation
Phased limits on Xbar and S charts (#144, PR 2) - #150
Merged
Merged
Conversation
This was referenced Oct 18, 2026
execute(chart='Xbar' | 'S', phased=True) gives each factor combination its own centre line and limits on one chart, drawn as stepped lines with a labelled divider at each change, as phased X/mR does for its lanes. Each phase is computed as the per-condition chart of by=[time] computes one stratum: the mean of its subgroup means as centre, its own S-bar and sigma-hat, its own limits (10-12 manual Eqs 11-5, 11-8, 11-9, 11-16, 11-17). With other factors pooled into the subgroup (by=['stage', time]) the centre is the mean of the pooled subgroup averages, as Dr. Bishop specified on 2026-10-18. On Wheeler's four-cavity thickness data the per-cavity centres and limits match Minitab's staged Xbar-S chart to the digit. New result.phase_statistics(chart); chart data and chart_table gain a phase column; metadata carries phase_by, lane_boundaries, single_point_phases and insufficient_phases. by=[time], residual values and calibrations are refused with messages that say what to use instead. phased=False output is unchanged (validation/xbar_s_sweep.py: 0 differing lines); gate 1547 / 0 / 4; full suite 2628 passed.
cnicholas
force-pushed
the
feat/phased-xbar-s-refactor
branch
from
October 18, 2026 22:21
732512f to
57f499c
Compare
cnicholas
force-pushed
the
feat/phased-xbar-s
branch
from
October 18, 2026 22:21
881f6aa to
fb8f10d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #144 (PR 2 of 4). Stacked on #149: the base is
feat/phased-xbar-s-refactor, so the diff shows only the feature; it retargets when #149 merges.Summary
execute(chart='Xbar' | 'S', phased=True)gives each factor combination its own centre line and limits on one chart, drawn as stepped lines with a labelled divider at each change, the way phased X/mR does for its lanes. Newresult.phase_statistics(chart)returns one row per phase; chart data andchart_tablegain aphasecolumn.by=[time]computes one per-condition chart, through the helpers Extract the per-group Xbar/S estimator for phased charts (#144, PR 1) #149 extracted, and the phases are concatenated in display order.by=None(or all factors + time) phases on every combination;by=['stage', time]pools the other factors into the subgroup and phases on the stage.by=[time], residual values and calibrations are refused with messages that say what to use instead.Contract / invariants
validation/xbar_s_sweep.py: identical fingerprints for all 504phased=FalseXbar/S requests on PM SDS 1 and 3, before and aftertest_unphased_output_is_unchanged)phasecolumn,phasespayload key, new metadata keys; the four-key statistics shape holds (None+limits_vary, as phased X/mR). Existing golden masters untouched; one new scenario (phased_xbar_s) addedtest_phased_requires_xmr_or_rbecametest_phased_requires_a_limits_chart: Histogram is refused with the sameonly valid forfragment, Xbar is acceptedBehaviour changes
phased=Trueis accepted on Xbar and S (it raisedonly valid for X or mR charts).{'N': None, 'center': None, 'lpl': None, 'upl': None, 'limits_vary': True}; metadataphased,run_rules_applicable=False,phase_by,lane_boundaries,single_point_phases,insufficient_phases,group_col; non_avg(per-phaseNis inphase_statistics).detect_signalsruns Rule 1 against each phase's limits.insufficient_phases; the request raises only when no phase has one.execute()docstring forphasedrewritten (it still said "requires by=[]").Methodology
by=[time]charts cover the arithmetic. Tom's cavity data: the phased chart reproduces every per-cavity value in his file and Minitab screenshot (A 14.65 / 12.677 / 16.623, S̄ 1.382, S UPL 2.888; B 8.97; C 7.47; D 7.86).Key design decisions
test_pooled_phase_equals_reformulated_studypins the unbalanced case, where phasedby=['FACTOR 1', time]equals a study formulated without FACTOR 2. The unphased pooled chart keeps its fine-cell centre (invariant); whether it should also follow Tom's rule is a question for him, outside this PR._fit_xbar_group/_apply_xbar_limits/_apply_s_limits, so a phase equalsfocus(k)to the last digit, including the round-then-slice order the stratified S chart uses. 1,000 phases run in well under 5 s (slow-marked test).phaseis the lane label ('A','1_2'), the same string as thefocus()key and the divider label.by=[time]refused, not treated as a no-op: it would return a stratified result with nested statistics, the opposite of what the caller asked for; the message points toby=None.Tests
tests/test_phased_xbar_s.py(45): oracles — phased frames equal the concatenatedby=[time]focus(k)frames on PM SDS 1 and 3 for Xbar and S,phase_statisticsequals the per-stratum statistics, pooled phases equal the re-formulated study (balanced and unbalanced),by=None=[]= fullbyin any order, Tom's cavity file against its VAS columns; hand-computed two-stage example (c4/b3/b4), Eq 11-5 within a phase,n_mode='average'per phase,n_sigma=2; edge cases — one-reading subgroups on Xbar only, a single-subgroup phase, an insufficient phase, no replicated phase; contracts — solo = companion, statistics/metadata/column shapes, lane positions,chart_table,phase_statisticsrefusals, Rule 1 per phase, stage order (strings, sortable labels, ordered Categorical), unphased output unchanged, 1,000 phases under 5 s; one test per refused request and the accepted shapes; calibration context'phased Xbar'/'phased S'; plotting smoke (stepped CL/UPL/LPL, the note, labelled dividers, no zones)test_phased_limits.py(Histogram refused, Xbar accepted),test_supports_calibration.py(grid runsphasedfor all four charts; new context test),test_result_tabular.py(phasein_NON_VALUE_COLS), golden scenariophased_xbar_spytest tests/— 2628 passed, 7 skippedruff check .mypy processbehavior— 14 errors, all pre-existing, none in the touched codepython validation/e2e_bishop_report.py— 1547 passed, 0 failed, 4 pending;docs/reference/validation.mdunchangedvalidation/xbar_s_sweep.py— 0 differing lines against the pre-Extract the per-group Xbar/S estimator for phased charts (#144, PR 1) #149 baselineNotes
chart-types.mdgains "Staged Xbar/S" plus rows in the order-free and summary tables;api.mdgains "Phases" and thephasedcomment; CHANGELOG Added / Changed / Fixed.tests/fixtures/data/wheeler_cavity_thickness.csvis Tom's file verbatim, including VAS's per-cavity chart columns, which the oracle test reads.phasecolumn andphase_statisticson phased X/mR, companion mRsingle_point_phases), PR 4 (ordered Categoricals on X/mR lane order); ask Tom about the unphased pooled centre; the app's "Phased limits" option for Xbar/S.