abspc 0.2.1__tar.gz

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.
abspc-0.2.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2026 Aneurin Bevan University Health Board
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,5 @@
1
+ include LICENSE
2
+ include README.md
3
+ include pyproject.toml
4
+ recursive-include abspc *.py
5
+ recursive-include abspc/icons *.png
abspc-0.2.1/PKG-INFO ADDED
@@ -0,0 +1,571 @@
1
+ Metadata-Version: 2.4
2
+ Name: abspc
3
+ Version: 0.2.1
4
+ Summary: SPC chart visuals using the NHS Making Data Count methodology — Python, Looker & Looker Studio
5
+ Author: Aneurin Bevan University Health Board
6
+ Author-email: Daniel Westwood <daniel.westwood@wales.nhs.uk>
7
+ License: MIT License
8
+
9
+ Copyright (c) 2024-2026 Aneurin Bevan University Health Board
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
28
+
29
+ Project-URL: Documentation, https://github.com/Aneurin-Bevan-University-Health-Board/biu_Making_Data_Count_CustomVisuals#readme
30
+ Project-URL: Issues, https://github.com/Aneurin-Bevan-University-Health-Board/biu_Making_Data_Count_CustomVisuals/issues
31
+ Project-URL: Homepage, https://github.com/Aneurin-Bevan-University-Health-Board/biu_Making_Data_Count_CustomVisuals
32
+ Project-URL: Repository, https://github.com/Aneurin-Bevan-University-Health-Board/biu_Making_Data_Count_CustomVisuals
33
+ Keywords: spc,statistical process control,nhs,making data count,quality improvement,looker,looker studio
34
+ Classifier: Development Status :: 3 - Alpha
35
+ Classifier: Intended Audience :: Healthcare Industry
36
+ Classifier: Intended Audience :: Science/Research
37
+ Classifier: License :: OSI Approved :: MIT License
38
+ Classifier: Programming Language :: Python :: 3
39
+ Classifier: Programming Language :: Python :: 3.9
40
+ Classifier: Programming Language :: Python :: 3.10
41
+ Classifier: Programming Language :: Python :: 3.11
42
+ Classifier: Programming Language :: Python :: 3.12
43
+ Classifier: Topic :: Scientific/Engineering :: Visualization
44
+ Requires-Python: >=3.9
45
+ Description-Content-Type: text/markdown
46
+ License-File: LICENSE
47
+ Requires-Dist: numpy>=1.23
48
+ Requires-Dist: pandas>=1.5
49
+ Requires-Dist: matplotlib>=3.6
50
+ Provides-Extra: dev
51
+ Requires-Dist: pytest>=7.0; extra == "dev"
52
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
53
+ Requires-Dist: build>=1.0; extra == "dev"
54
+ Requires-Dist: twine>=5.0; extra == "dev"
55
+ Dynamic: license-file
56
+ Dynamic: requires-python
57
+
58
+ # abspc — Python SPC Charts
59
+
60
+ The `abspc` Python package provides publication-ready Statistical Process
61
+ Control (SPC) charts following the NHS
62
+ [Making Data Count](https://www.england.nhs.uk/publication/making-data-count/)
63
+ methodology.
64
+
65
+ Built on **matplotlib**, it produces high-quality static images suitable for
66
+ board reports, dashboards, and quality-improvement publications.
67
+
68
+ ---
69
+
70
+ ## Installation
71
+
72
+ ```bash
73
+ pip install abspc
74
+ ```
75
+
76
+ Or install the development version from source:
77
+
78
+ ```bash
79
+ git clone https://github.com/Aneurin-Bevan-University-Health-Board/biu_Making_Data_Count_CustomVisuals
80
+ cd biu_Making_Data_Count_CustomVisuals
81
+ pip install -e ".[dev]"
82
+ ```
83
+
84
+ ---
85
+
86
+ ## Quick Start
87
+
88
+ ```python
89
+ import pandas as pd
90
+ from abspc import plot_spc_chart, plot_run_chart
91
+
92
+ # Minimal XmR chart
93
+ data = pd.DataFrame({"value": [48, 52, 49, 55, 47, 51, 53, 50, 48, 54]})
94
+ fig, ax = plot_spc_chart(data, chart_type="XmR")
95
+ fig.savefig("my_xmr_chart.png")
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Chart Types
101
+
102
+ ### XmR Chart
103
+
104
+ The XmR (individuals / moving-range) chart is the most common SPC chart type.
105
+ It is suitable for individual measurements collected over time.
106
+
107
+ ```python
108
+ import numpy as np
109
+ import pandas as pd
110
+ from abspc import plot_spc_chart
111
+
112
+ data = pd.DataFrame({"value": np.random.normal(50, 3, 24)})
113
+
114
+ fig, ax = plot_spc_chart(
115
+ data,
116
+ chart_type="XmR",
117
+ title="XmR Chart – Individual Measurements",
118
+ xlabel="Month",
119
+ ylabel="Value",
120
+ shade_band=True,
121
+ improvement_direction="high",
122
+ )
123
+ ```
124
+
125
+ ![XmR Chart](https://raw.githubusercontent.com/Aneurin-Bevan-University-Health-Board/biu_Making_Data_Count_CustomVisuals/main/docs/images/chart_xmr.png)
126
+
127
+ ---
128
+
129
+ ### p Chart
130
+
131
+ The p chart is for proportion data (e.g., percentage of patients waiting
132
+ > 4 hours). It requires a `subgroup_size` column containing the denominator.
133
+
134
+ ```python
135
+ data = pd.DataFrame({
136
+ "value": [0.10, 0.12, 0.08, 0.15, 0.09, 0.11, 0.10, 0.13, 0.07, 0.12,
137
+ 0.09, 0.11, 0.10, 0.08, 0.14, 0.12, 0.09, 0.11, 0.08, 0.10,
138
+ 0.12, 0.09, 0.11, 0.10],
139
+ "subgroup_size": [200] * 24,
140
+ })
141
+
142
+ fig, ax = plot_spc_chart(
143
+ data,
144
+ chart_type="p",
145
+ title="p Chart – Proportion",
146
+ xlabel="Month",
147
+ ylabel="Proportion",
148
+ improvement_direction="low",
149
+ )
150
+ ```
151
+
152
+ ![p Chart](https://raw.githubusercontent.com/Aneurin-Bevan-University-Health-Board/biu_Making_Data_Count_CustomVisuals/main/docs/images/chart_p.png)
153
+
154
+ You can also pass a **numerator column** and a **denominator column**:
155
+
156
+ ```python
157
+ data = pd.DataFrame({
158
+ "events": [20, 24, 16, 30, 18],
159
+ "population": [200, 200, 200, 200, 200],
160
+ })
161
+ fig, ax = plot_spc_chart(
162
+ data,
163
+ chart_type="p",
164
+ value_col="population",
165
+ numerator_col="events",
166
+ improvement_direction="low",
167
+ )
168
+ ```
169
+
170
+ ---
171
+
172
+ ### c Chart
173
+
174
+ The c chart is for counts of events in a fixed sample size (e.g., adverse
175
+ events per ward per month).
176
+
177
+ ```python
178
+ data = pd.DataFrame({"value": [3, 5, 2, 6, 4, 3, 7, 5, 4, 6,
179
+ 5, 3, 4, 6, 5, 4, 3, 5, 6, 4,
180
+ 3, 5, 4, 6]})
181
+
182
+ fig, ax = plot_spc_chart(
183
+ data,
184
+ chart_type="c",
185
+ title="c Chart – Count of Events",
186
+ xlabel="Month",
187
+ ylabel="Count",
188
+ improvement_direction="low",
189
+ )
190
+ ```
191
+
192
+ ![c Chart](https://raw.githubusercontent.com/Aneurin-Bevan-University-Health-Board/biu_Making_Data_Count_CustomVisuals/main/docs/images/chart_c.png)
193
+
194
+ ---
195
+
196
+ ### Run Chart
197
+
198
+ The run chart plots data against time with a **median** centre line and no
199
+ control limits. It uses run-chart rules to detect signals (8-point shift and
200
+ 6-point trend).
201
+
202
+ ```python
203
+ from abspc import plot_run_chart
204
+
205
+ data = pd.DataFrame({"value": np.random.normal(40, 4, 24)})
206
+
207
+ fig, ax = plot_run_chart(
208
+ data,
209
+ title="Run Chart – Median Centre Line",
210
+ xlabel="Month",
211
+ ylabel="Value",
212
+ improvement_direction="high",
213
+ )
214
+ ```
215
+
216
+ ![Run Chart](https://raw.githubusercontent.com/Aneurin-Bevan-University-Health-Board/biu_Making_Data_Count_CustomVisuals/main/docs/images/chart_run.png)
217
+
218
+ `plot_spc_chart` also accepts `chart_type="run"` and will automatically
219
+ delegate to `plot_run_chart`:
220
+
221
+ ```python
222
+ fig, ax = plot_spc_chart(data, chart_type="run")
223
+ ```
224
+
225
+ ---
226
+
227
+ ## Features
228
+
229
+ ### Logo Placement
230
+
231
+ Pass any image (PNG, JPEG, etc.) via `logo_path` to display your
232
+ organisation's logo at the **top-right of the chart, level with the title**.
233
+
234
+ ```python
235
+ fig, ax = plot_spc_chart(
236
+ data,
237
+ chart_type="XmR",
238
+ title="A&E 4-Hour Waits – Aneurin Bevan UHB",
239
+ logo_path="path/to/logo.png",
240
+ logo_zoom=0.08,
241
+ )
242
+ ```
243
+
244
+ ![Chart with Logo](https://raw.githubusercontent.com/Aneurin-Bevan-University-Health-Board/biu_Making_Data_Count_CustomVisuals/main/docs/images/chart_with_logo.png)
245
+
246
+ > **Note:** `logo_path` places the logo in the title margin (top-right).
247
+ > The legacy `nhs_logo_path` parameter places an image inside the plot area.
248
+
249
+ ---
250
+
251
+ ### Date Axis
252
+
253
+ All chart functions automatically detect datetime data on the x-axis and
254
+ apply smart date tick formatting.
255
+
256
+ **Option 1 — `DatetimeIndex` (auto-detected):**
257
+
258
+ ```python
259
+ dates = pd.date_range("2022-01-01", periods=30, freq="MS")
260
+ data = pd.DataFrame({"value": np.random.normal(75, 6, 30)}, index=dates)
261
+
262
+ fig, ax = plot_spc_chart(data, chart_type="XmR", title="Monthly Date Axis")
263
+ ```
264
+
265
+ ![Date Axis](https://raw.githubusercontent.com/Aneurin-Bevan-University-Health-Board/biu_Making_Data_Count_CustomVisuals/main/docs/images/chart_date_axis.png)
266
+
267
+ **Option 2 — Explicit date column:**
268
+
269
+ ```python
270
+ fig, ax = plot_run_chart(data, x_col="period", date_format="%b %Y")
271
+ ```
272
+
273
+ | `date_format` | Example output |
274
+ |---------------|----------------|
275
+ | `"%b %Y"` | Jan 2024 |
276
+ | `"%Y-%m"` | 2024-01 |
277
+ | `"%d/%m/%Y"` | 01/01/2024 |
278
+ | `None` *(default)* | Auto (ConciseDateFormatter) |
279
+
280
+ ---
281
+
282
+ ### Change-Point Annotations
283
+
284
+ Mark known process changes with vertical lines and labels:
285
+
286
+ ```python
287
+ fig, ax = plot_spc_chart(
288
+ data,
289
+ chart_type="XmR",
290
+ change_points=[
291
+ {"x": 9, "label": "New protocol"},
292
+ {"x": 20, "label": "Staff training"},
293
+ ],
294
+ )
295
+ ```
296
+
297
+ ![Change Points](https://raw.githubusercontent.com/Aneurin-Bevan-University-Health-Board/biu_Making_Data_Count_CustomVisuals/main/docs/images/chart_change_points.png)
298
+
299
+ ---
300
+
301
+ ### Auto-Rebase on Sustained Improvement
302
+
303
+ When ≥ 8 consecutive points show sustained improvement, control limits can be
304
+ automatically recalculated for the new phase:
305
+
306
+ ```python
307
+ fig, ax = plot_spc_chart(
308
+ data,
309
+ chart_type="XmR",
310
+ improvement_direction="high",
311
+ auto_rebase=True,
312
+ )
313
+ ```
314
+
315
+ ![Auto-Rebase](https://raw.githubusercontent.com/Aneurin-Bevan-University-Health-Board/biu_Making_Data_Count_CustomVisuals/main/docs/images/chart_auto_rebase.png)
316
+
317
+ Use `rebase_control_limits` for programmatic access without plotting:
318
+
319
+ ```python
320
+ from abspc import rebase_control_limits
321
+
322
+ result = rebase_control_limits(data, chart_type="XmR", improvement_direction="high")
323
+ ```
324
+
325
+ > Auto-rebase is supported for XmR, p, u, and c charts (not run charts).
326
+
327
+ ---
328
+
329
+ ### MDC Variation & Assurance Icons
330
+
331
+ Set `show_icons=True` to display the official Making Data Count variation and
332
+ assurance icons at the top-left of the chart:
333
+
334
+ ```python
335
+ fig, ax = plot_spc_chart(
336
+ data,
337
+ chart_type="XmR",
338
+ improvement_direction="high",
339
+ target=60,
340
+ show_target=True,
341
+ show_icons=True,
342
+ )
343
+ ```
344
+
345
+ **Programmatic access:**
346
+
347
+ ```python
348
+ from abspc import (
349
+ calculate_control_limits,
350
+ detect_special_causes,
351
+ determine_variation_type,
352
+ determine_assurance_type,
353
+ )
354
+
355
+ result = detect_special_causes(calculate_control_limits(data, chart_type="XmR"))
356
+ variation = determine_variation_type(result, value_col="value", improvement_direction="high")
357
+ assurance = determine_assurance_type(result, target=60, improvement_direction="high")
358
+ ```
359
+
360
+ > For run charts only the variation icon is shown (no control limits means
361
+ > assurance cannot be calculated).
362
+
363
+ ---
364
+
365
+ ### MDC Summary Table
366
+
367
+ `plot_mdc_summary_table` renders an NHS MDC-style summary table showing
368
+ multiple measures at a glance:
369
+
370
+ ```python
371
+ from abspc import plot_mdc_summary_table
372
+
373
+ fig, ax = plot_mdc_summary_table(
374
+ [
375
+ {
376
+ "data": df,
377
+ "chart_type": "XmR",
378
+ "measure": "A&E 4-Hour Waits",
379
+ "description": "% patients seen within 4 hours",
380
+ "value_col": "value",
381
+ "improvement_direction": "high",
382
+ "target": 95,
383
+ },
384
+ {
385
+ "data": df_infections,
386
+ "chart_type": "p",
387
+ "measure": "Infection Rate",
388
+ "description": "Proportion of infections per month",
389
+ "value_col": "value",
390
+ "improvement_direction": "low",
391
+ "target": 0.05,
392
+ "subgroup_col": "subgroup_size",
393
+ },
394
+ ],
395
+ title="MDC Summary — Board Report",
396
+ )
397
+ ```
398
+
399
+ ---
400
+
401
+ ## Special-Cause Rules
402
+
403
+ Four NHS MDC rules (aligned with NHSRplotthedots):
404
+
405
+ | Rule | Name | Description |
406
+ |------|------|-------------|
407
+ | **1** | Astronomical point | Single value outside 3σ limits |
408
+ | **2** | Shift | ≥ 8 consecutive points above or below the mean |
409
+ | **3** | Trend | ≥ 6 consecutive points all rising or all falling |
410
+ | **4** | Two-in-three | 2 of 3 consecutive points in the warning zone |
411
+
412
+ Use the detection functions directly:
413
+
414
+ ```python
415
+ from abspc import calculate_control_limits, detect_special_causes
416
+
417
+ result = calculate_control_limits(data, chart_type="XmR")
418
+ flags = detect_special_causes(result)
419
+ print(flags[["value", "mean", "ucl", "lcl", "rule1", "rule2", "rule3", "rule4", "special_cause"]])
420
+ ```
421
+
422
+ ---
423
+
424
+ ## API Reference
425
+
426
+ ### `plot_spc_chart`
427
+
428
+ ```python
429
+ fig, ax = plot_spc_chart(
430
+ data,
431
+ chart_type, # "XmR" | "p" | "u" | "c" | "run"
432
+ value_col="value",
433
+ subgroup_col="subgroup_size",
434
+ numerator_col=None,
435
+ x_col=None,
436
+ title=None,
437
+ xlabel="Observation",
438
+ ylabel="Value",
439
+ improvement_direction="high",
440
+ target=None,
441
+ show_target=False,
442
+ shade_band=False,
443
+ shade_color="#41B6E6",
444
+ nhs_logo_path=None,
445
+ ax=None,
446
+ figsize=(12, 5),
447
+ show_legend=True,
448
+ change_points=None,
449
+ auto_rebase=False,
450
+ date_format=None,
451
+ logo_path=None,
452
+ logo_zoom=0.07,
453
+ show_icons=False,
454
+ icon_zoom=0.06,
455
+ )
456
+ ```
457
+
458
+ | Parameter | Type | Default | Description |
459
+ |-----------|------|---------|-------------|
460
+ | `data` | `pd.DataFrame` | *(required)* | Input DataFrame with at least the `value_col` column. |
461
+ | `chart_type` | `str` | *(required)* | `"XmR"`, `"p"`, `"u"`, `"c"`, or `"run"` (case-insensitive). |
462
+ | `value_col` | `str` | `"value"` | Column containing the measured values. |
463
+ | `subgroup_col` | `str \| None` | `"subgroup_size"` | Column with subgroup sizes. Required for `"p"` and `"u"`. |
464
+ | `numerator_col` | `str \| None` | `None` | For `"p"` charts: column with event counts when `value_col` holds the denominator. |
465
+ | `x_col` | `str \| None` | `None` | Column for the x-axis. Auto-detects `DatetimeIndex` if `None`. |
466
+ | `title` | `str \| None` | `None` | Chart title. Auto-generated if omitted. |
467
+ | `xlabel` | `str` | `"Observation"` | X-axis label. |
468
+ | `ylabel` | `str` | `"Value"` | Y-axis label. |
469
+ | `improvement_direction` | `str` | `"high"` | `"high"` or `"low"`. Controls point colouring. |
470
+ | `target` | `float \| None` | `None` | Optional target value for the target line and assurance calculation. |
471
+ | `show_target` | `bool` | `False` | Draw a dashed target line at `target`. |
472
+ | `shade_band` | `bool` | `False` | Fill between UCL and LCL with a translucent band. |
473
+ | `shade_color` | `str` | `"#41B6E6"` | Colour for tolerance-band shading. |
474
+ | `nhs_logo_path` | `str \| None` | `None` | Logo inside the axes (legacy). Use `logo_path` instead. |
475
+ | `ax` | `Axes \| None` | `None` | Existing axes to draw on. Creates a new figure when `None`. |
476
+ | `figsize` | `tuple` | `(12, 5)` | Figure size in inches. Ignored when `ax` is provided. |
477
+ | `show_legend` | `bool` | `True` | Add a colour legend. |
478
+ | `change_points` | `list[dict] \| None` | `None` | Vertical annotation lines. Each dict needs `"x"` and `"label"`. |
479
+ | `auto_rebase` | `bool` | `False` | Auto-detect sustained improvement and recalculate limits. |
480
+ | `date_format` | `str \| None` | `None` | `strftime`-style format for datetime x-axis. |
481
+ | `logo_path` | `str \| None` | `None` | Logo image at top-right of figure. |
482
+ | `logo_zoom` | `float` | `0.07` | Logo height as fraction of figure height. |
483
+ | `show_icons` | `bool` | `False` | Display MDC variation & assurance icons. |
484
+ | `icon_zoom` | `float` | `0.06` | Icon height as fraction of figure height. |
485
+
486
+ **Returns:** `(fig, ax)` — `matplotlib.figure.Figure` and `matplotlib.axes.Axes`.
487
+
488
+ ---
489
+
490
+ ### `plot_run_chart`
491
+
492
+ ```python
493
+ fig, ax = plot_run_chart(
494
+ data,
495
+ value_col="value",
496
+ x_col=None,
497
+ title=None,
498
+ xlabel="Observation",
499
+ ylabel="Value",
500
+ improvement_direction="high",
501
+ target=None,
502
+ show_target=False,
503
+ nhs_logo_path=None,
504
+ ax=None,
505
+ figsize=(12, 5),
506
+ show_legend=True,
507
+ change_points=None,
508
+ date_format=None,
509
+ logo_path=None,
510
+ logo_zoom=0.07,
511
+ show_icons=False,
512
+ icon_zoom=0.06,
513
+ )
514
+ ```
515
+
516
+ Same parameter semantics as `plot_spc_chart` (without `chart_type`,
517
+ `subgroup_col`, `numerator_col`, `shade_band`, `shade_color`, `auto_rebase`).
518
+
519
+ **Returns:** `(fig, ax)`.
520
+
521
+ ---
522
+
523
+ ### `calculate_control_limits`
524
+
525
+ Returns the input DataFrame extended with `mean`, `ucl`, `lcl`, `uwl`, `lwl`
526
+ columns (or just `mean` for run charts).
527
+
528
+ ### `detect_special_causes`
529
+
530
+ Returns the DataFrame extended with boolean columns `rule1`, `rule2`, `rule3`,
531
+ `rule4`, and `special_cause`.
532
+
533
+ ### `detect_run_chart_signals`
534
+
535
+ Returns the DataFrame extended with `run_shift`, `run_trend`, and `run_signal`.
536
+
537
+ ### `rebase_control_limits`
538
+
539
+ Returns the DataFrame with limits recalculated per improvement phase and a
540
+ `rebase_phase` integer column.
541
+
542
+ ### `show_summary`
543
+
544
+ Generates a programmatic summary dictionary for a chart, including variation
545
+ type, assurance status, descriptive statistics, triggered SPC rules, and a
546
+ list of signal points. Pass `show_summary=True` to `plot_spc_chart` or
547
+ `plot_run_chart` to render the summary as an additional figure.
548
+
549
+ ```python
550
+ from abspc import show_summary
551
+
552
+ summary = show_summary(data, chart_type="XmR", improvement_direction="high", target=60)
553
+ print(summary["variation"], summary["assurance"])
554
+ ```
555
+
556
+ ### `plot_mdc_summary_table`
557
+
558
+ Renders an NHS MDC-style summary table for one or more measures (see the
559
+ [MDC Summary Table](#mdc-summary-table) section above).
560
+
561
+ ---
562
+
563
+ ## Running Tests
564
+
565
+ ```bash
566
+ pip install -e ".[dev]"
567
+ pytest
568
+ ```
569
+
570
+ 160 unit tests covering all chart types, SPC rules, run-chart signals,
571
+ auto-rebase, change-point annotations, summary generation, and plotting.