tpattern 0.1.12__tar.gz → 0.1.14__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.
Files changed (44) hide show
  1. tpattern-0.1.14/PKG-INFO +359 -0
  2. tpattern-0.1.14/README.md +324 -0
  3. {tpattern-0.1.12 → tpattern-0.1.14}/pyproject.toml +1 -1
  4. tpattern-0.1.14/tests/test_starter.py +34 -0
  5. {tpattern-0.1.12 → tpattern-0.1.14}/tpattern/__init__.py +3 -2
  6. tpattern-0.1.14/tpattern/starter.py +147 -0
  7. tpattern-0.1.14/tpattern.egg-info/PKG-INFO +359 -0
  8. {tpattern-0.1.12 → tpattern-0.1.14}/tpattern.egg-info/SOURCES.txt +2 -0
  9. tpattern-0.1.12/PKG-INFO +0 -215
  10. tpattern-0.1.12/README.md +0 -180
  11. tpattern-0.1.12/tpattern.egg-info/PKG-INFO +0 -215
  12. {tpattern-0.1.12 → tpattern-0.1.14}/LICENSE +0 -0
  13. {tpattern-0.1.12 → tpattern-0.1.14}/setup.cfg +0 -0
  14. {tpattern-0.1.12 → tpattern-0.1.14}/tests/test_calibrated_pins.py +0 -0
  15. {tpattern-0.1.12 → tpattern-0.1.14}/tests/test_contrast.py +0 -0
  16. {tpattern-0.1.12 → tpattern-0.1.14}/tests/test_dedup.py +0 -0
  17. {tpattern-0.1.12 → tpattern-0.1.14}/tests/test_guided.py +0 -0
  18. {tpattern-0.1.12 → tpattern-0.1.14}/tests/test_null_compare.py +0 -0
  19. {tpattern-0.1.12 → tpattern-0.1.14}/tests/test_outputs.py +0 -0
  20. {tpattern-0.1.12 → tpattern-0.1.14}/tests/test_read_table_validation.py +0 -0
  21. {tpattern-0.1.12 → tpattern-0.1.14}/tests/test_reference.py +0 -0
  22. {tpattern-0.1.12 → tpattern-0.1.14}/tests/test_report_dendrogram.py +0 -0
  23. {tpattern-0.1.12 → tpattern-0.1.14}/tests/test_reproduction.py +0 -0
  24. {tpattern-0.1.12 → tpattern-0.1.14}/tests/test_sofcoder.py +0 -0
  25. {tpattern-0.1.12 → tpattern-0.1.14}/tests/test_support_reporting.py +0 -0
  26. {tpattern-0.1.12 → tpattern-0.1.14}/tests/test_synthetic.py +0 -0
  27. {tpattern-0.1.12 → tpattern-0.1.14}/tpattern/advisor.py +0 -0
  28. {tpattern-0.1.12 → tpattern-0.1.14}/tpattern/ci.py +0 -0
  29. {tpattern-0.1.12 → tpattern-0.1.14}/tpattern/contrast.py +0 -0
  30. {tpattern-0.1.12 → tpattern-0.1.14}/tpattern/detect.py +0 -0
  31. {tpattern-0.1.12 → tpattern-0.1.14}/tpattern/diagnostics.py +0 -0
  32. {tpattern-0.1.12 → tpattern-0.1.14}/tpattern/guided.py +0 -0
  33. {tpattern-0.1.12 → tpattern-0.1.14}/tpattern/io.py +0 -0
  34. {tpattern-0.1.12 → tpattern-0.1.14}/tpattern/methods.py +0 -0
  35. {tpattern-0.1.12 → tpattern-0.1.14}/tpattern/pattern.py +0 -0
  36. {tpattern-0.1.12 → tpattern-0.1.14}/tpattern/randomise.py +0 -0
  37. {tpattern-0.1.12 → tpattern-0.1.14}/tpattern/reference.py +0 -0
  38. {tpattern-0.1.12 → tpattern-0.1.14}/tpattern/report.py +0 -0
  39. {tpattern-0.1.12 → tpattern-0.1.14}/tpattern/significance.py +0 -0
  40. {tpattern-0.1.12 → tpattern-0.1.14}/tpattern/synthetic.py +0 -0
  41. {tpattern-0.1.12 → tpattern-0.1.14}/tpattern/viz.py +0 -0
  42. {tpattern-0.1.12 → tpattern-0.1.14}/tpattern.egg-info/dependency_links.txt +0 -0
  43. {tpattern-0.1.12 → tpattern-0.1.14}/tpattern.egg-info/requires.txt +0 -0
  44. {tpattern-0.1.12 → tpattern-0.1.14}/tpattern.egg-info/top_level.txt +0 -0
@@ -0,0 +1,359 @@
1
+ Metadata-Version: 2.4
2
+ Name: tpattern
3
+ Version: 0.1.14
4
+ Summary: Open, auditable temporal & sequential pattern analysis (T-patterns) for sport and behaviour
5
+ Author-email: Andrew Callaway <acallaway@bournemouth.ac.uk>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/ajcallaway/TPattern
8
+ Project-URL: Repository, https://github.com/ajcallaway/TPattern
9
+ Project-URL: Archive (DOI), https://doi.org/10.5281/zenodo.21397543
10
+ Project-URL: Tagging tool (OpenTag), https://opentag.studio
11
+ Keywords: t-pattern,THEME,temporal,sequence,sport,behaviour,notation analysis
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Intended Audience :: Science/Research
20
+ Classifier: Topic :: Scientific/Engineering
21
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
22
+ Requires-Python: >=3.9
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: numpy>=1.21
26
+ Requires-Dist: scipy>=1.7
27
+ Requires-Dist: matplotlib>=3.4
28
+ Provides-Extra: test
29
+ Requires-Dist: pytest>=7; extra == "test"
30
+ Provides-Extra: gui
31
+ Requires-Dist: ipywidgets>=8; extra == "gui"
32
+ Requires-Dist: pandas>=1.3; extra == "gui"
33
+ Requires-Dist: openpyxl>=3; extra == "gui"
34
+ Dynamic: license-file
35
+
36
+ # tpattern — open, auditable analysis of recurring patterns in event sequences
37
+
38
+ [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ajcallaway/TPattern/blob/main/colab/tpattern_guided_analysis.ipynb)
39
+ [![DOI](https://img.shields.io/badge/DOI-10.5281%2Fzenodo.21397543-1682D4.svg)](https://doi.org/10.5281/zenodo.21397543)
40
+ [![R interface](https://img.shields.io/badge/R-interface-276DC3?logo=r&logoColor=white)](#using-tpattern-from-r)
41
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
42
+
43
+ `tpattern` detects recurring temporal patterns (T-patterns; Magnusson, 2000) in
44
+ **any sequence of timed, labelled events** — behaviour, sport, clinical or
45
+ physiological logs, interaction data — validates them properly against chance, and
46
+ produces clean, publication-ready output (tables, figures, pattern dendrograms). It
47
+ implements the published T-pattern detection algorithm (Magnusson, 2000) as free,
48
+ auditable code — the same critical-interval method the THEME software applies (see
49
+ [The method it implements](#the-method-it-implements)) — and is the analysis
50
+ companion to the [OpenTag.Studio](https://opentag.studio) tagging tool.
51
+
52
+ ## Two ways to use it
53
+
54
+ ### 🚀 In your browser — Google Colab, no install, no coding
55
+
56
+ Open a guided notebook, upload your events CSV, and it walks you through four steps —
57
+ **upload → inspect → the recommended settings appear → run** — then hands back a full
58
+ report inline and as a downloadable zip: a colour-coded results table with a
59
+ plain-English verdict for every pattern (🟢 robust · 🟡 borderline · ⚪ likely chance),
60
+ the pattern dendrograms, the code to restyle them, and a paste-ready Methods paragraph.
61
+ No data of your own yet? Point it at [`data/worldcup_goals.csv`](data/worldcup_goals.csv)
62
+ (choose **ms** for the time unit).
63
+
64
+ Three notebooks (all in [`colab/`](colab/)):
65
+
66
+ - [**Guided analysis**](https://colab.research.google.com/github/ajcallaway/TPattern/blob/main/colab/tpattern_guided_analysis.ipynb) — **recommended.** Installs the latest `tpattern` and opens the guided panel. This is the one the badge above opens.
67
+ - **Guided analysis (offline)** — the package is bundled inside the notebook (a snapshot), so it runs where you can't install from GitHub. Open `colab/tpattern_guided_analysis_offline.ipynb` via **File → Upload notebook**.
68
+ - **Worked example** — the companion to the tutorial paper. Runs the load → inspect → recommend → calibrate → report walk-through on the shipped World Cup goal sequences, cell by cell, so you can follow the whole analysis and then swap in your own data (`colab/tpattern_worked_example.ipynb`).
69
+
70
+ ### 🐍 As a Python library
71
+
72
+ `pip install tpattern` and script it — see [Getting started](#getting-started-in-a-minute), [Quickstart](#quickstart) and [`examples/`](examples/).
73
+
74
+ Bring your own data (one row per event — see [`SCHEMA.md`](SCHEMA.md)) or try the
75
+ included [`data/`](data/) example.
76
+
77
+ ## Getting started in a minute
78
+
79
+ Install, generate a starter script, point it at your data, run it:
80
+
81
+ ```bash
82
+ pip install tpattern
83
+ python -c "import tpattern; tpattern.new_analysis()" # writes my_analysis.py
84
+ ```
85
+
86
+ Open `my_analysis.py`, change the two lines marked `# <-- EDIT` (your file and its time
87
+ unit), and run `python my_analysis.py`. It loads your events, **checks the file and tells
88
+ you in plain language about any problem**, recommends the analysis settings with reasons,
89
+ calibrates every pattern against a chance model, and writes a folder of results with a
90
+ plain-English verdict for each pattern.
91
+
92
+ Doing something more specific? Generate a template for it:
93
+
94
+ ```python
95
+ from tpattern import new_analysis
96
+ new_analysis() # one group: detect, calibrate, report
97
+ new_analysis(template="two_groups") # compare two groups (odds ratios + forest plot)
98
+ new_analysis(template="null_choice") # core vs shell: which null a pattern survives
99
+ ```
100
+
101
+ Not sure what a setting means? Ask the code — every setting and output column is documented:
102
+
103
+ ```python
104
+ from tpattern import explain
105
+ print(explain("min_lag")) # what it does, its range, the recommended value, higher vs lower
106
+ print(explain("fdr_q")) # what an output column means
107
+ ```
108
+
109
+ ## What you get
110
+
111
+ - **Forgiving data import.** `read_table` checks your file as it reads it and reports, in
112
+ plain language, any problem, how much of the file it affects, and how to fix it — instead
113
+ of silently dropping rows. Each check has a stable code (Appendix A of the tutorial; also
114
+ [`PARAMETERS.md`](PARAMETERS.md)).
115
+ - **A proper chance model.** Every pattern is tested against a surrogate null, with p-values
116
+ corrected for repeated testing (Benjamini–Hochberg FDR for screening, Holm family-wise for
117
+ confirmatory claims), stratified by hierarchy level.
118
+ - **Temporal reporting.** Beyond *which* patterns are real, the output says *when*: each
119
+ pattern's occurrence timing (median lag and spread) is reported by default — on the
120
+ dendrogram, in the table, and in the plain-English verdict — for every pattern.
121
+ - **Readable output.** Results-table columns are named for what they are (`monte_carlo_p`,
122
+ `fdr_q`, `survives_fwer_holm`, `bout_support`, `duration_median_ms`), and each pattern
123
+ carries a plain-English `interpretation`. `explain()` documents every setting and column;
124
+ the full reference is in [`PARAMETERS.md`](PARAMETERS.md).
125
+ - **One reference, everywhere.** Settings and columns live in one registry that generates the
126
+ code's `explain()`, `PARAMETERS.md`, the Colab form labels, and the tutorial's tables — so
127
+ the software, the paper and the notebook can't drift apart.
128
+ - **Clean figures** — dendrograms, temporal signatures, forest plots — that share one
129
+ customisable style (`tpattern.viz.STYLE`).
130
+
131
+ ## The method it implements
132
+
133
+ T-pattern analysis (Magnusson, 1996, 2000, 2019) finds behaviourally meaningful
134
+ structure that event counts and simple transition tables miss: event types that
135
+ recur in the same order, separated by statistically consistent time intervals, more
136
+ often than chance predicts. `tpattern` implements the algorithm exactly as published,
137
+ in auditable code:
138
+
139
+ - **Critical-interval detection.** For an ordered pair of event types (A, B) it
140
+ searches for the time window after A within which B follows more often than B's
141
+ overall rate would predict. Significance is the **upper-tail binomial** probability
142
+ of the observed number of A→B matches, evaluated against that baseline rate (B's
143
+ occurrences spread over the observation length — the *NX/T* baseline), thresholded
144
+ at α (default 0.005). This is the critical-interval test set out in Magnusson (2000)
145
+ and the THEME manual.
146
+ - **Free search, one-to-one matching, distinct tokens.** A free search selects the
147
+ largest significant interval; occurrences are matched one-to-one by the greedy
148
+ procedure the algorithm specifies; a pattern must be built from distinct event
149
+ tokens.
150
+ - **Bottom-up hierarchy with completeness competition.** Patterns are grown level by
151
+ level, longer patterns competing with their sub-patterns so that only the most
152
+ complete survive.
153
+
154
+ On top of the published detection, `tpattern` adds what the method has historically
155
+ lacked:
156
+
157
+ - **a proper chance model** — every detected pattern is tested against a surrogate
158
+ null, with p-values **corrected for repeated testing** (Benjamini–Hochberg FDR for
159
+ screening, Holm family-wise for confirmatory claims), stratified by level;
160
+ - **explicit concurrency handling** — events sharing a timestamp are reported as
161
+ co-occurrence rather than sequence;
162
+ - **clear reporting** — tidy tables, effect sizes with confidence intervals,
163
+ purposeful figures, and clean **dendrograms** of the detected patterns.
164
+
165
+ The reference software for this method is THEME (PatternVision Ltd), with **SOF-CODER**
166
+ (Jonsson et al., 2006) as its coding front end. `tpattern` reads that ecosystem
167
+ directly — `read_sofcoder` ingests SOF-CODER/THEME (`DATANAME, T, Events`) files — so
168
+ existing THEME datasets can be re-analysed with the surrogate calibration, and
169
+ [OpenTag.Studio](https://opentag.studio) can play, for `tpattern`, the role SOF-CODER
170
+ plays for THEME.
171
+
172
+ ## Installation
173
+
174
+ ```bash
175
+ pip install tpattern
176
+ ```
177
+
178
+ Add the guided-wizard extras with `pip install tpattern[gui]`. To work from source
179
+ instead (for development or to run the reproduction scripts and shipped data):
180
+
181
+ ```bash
182
+ git clone https://github.com/ajcallaway/TPattern.git
183
+ cd tpattern
184
+ pip install -e .
185
+ ```
186
+
187
+ Requires Python ≥ 3.9 (depends on numpy, scipy, matplotlib).
188
+
189
+ ## Quickstart
190
+
191
+ ```python
192
+ from tpattern import read_table, Config, recommend, calibrate, report, methods_text
193
+
194
+ # 1. Load your events — one row per event (observation, event, start).
195
+ # Pass time_unit="ms" if your times are in milliseconds (default is seconds).
196
+ # See SCHEMA.md for the (simple) required format.
197
+ observations = read_table("events.csv", time_unit="s")
198
+
199
+ # 2. Let the tool inspect the data and recommend the method — which surrogate
200
+ # null, whether to require a genuine lag, which error control — with reasons.
201
+ print(recommend(observations))
202
+
203
+ # 3. Detect and calibrate in one call: every pattern is tested against a
204
+ # surrogate null with correction for repeated testing.
205
+ # (calibrate() runs the detection for you — you don't call detect() first.)
206
+ result = calibrate(observations, Config(), null="profile", B=200, q_target=0.05)
207
+ survivors = result.kept("fdr") # patterns that survive false-discovery control
208
+
209
+ # 4. Report: a tidy results table (monte_carlo_p, fdr_q, survives_fwer_holm, the observed
210
+ # timing, and a plain-English `interpretation` per pattern), pattern dendrograms, the
211
+ # temporal-signature and occurrence plots, the event-type roles/connections tables, and a
212
+ # paste-ready Methods paragraph stating every setting and what it does.
213
+ report(result, "report_out", observations=observations, title="My analysis")
214
+ print(methods_text(Config(), observations=observations, calibration=result))
215
+ ```
216
+
217
+ Prefer not to write the pipeline yourself? `python -c "import tpattern;
218
+ tpattern.new_analysis()"` writes a commented [`my_analysis.py`](examples/my_analysis.py)
219
+ you edit and run (see [Getting started](#getting-started-in-a-minute)).
220
+
221
+ Two runnable examples:
222
+
223
+ ```bash
224
+ pip install -e .
225
+ python examples/quickstart.py # no data needed (synthetic ground-truth demo)
226
+ python examples/reproduce_worldcup.py # a real read_table + full analysis on shipped data
227
+ ```
228
+
229
+ Just want the detected patterns without calibration? `Engine(observations,
230
+ Config()).detect()` returns them directly.
231
+
232
+ **Comparing two groups** (winner vs loser, goal vs non-goal, condition A vs B)?
233
+ `group_contrast(observations, group_of)` tests each pattern's occurrence between
234
+ the groups (Fisher's exact test, odds ratio + 95% CI) and feeds `forest_plot` — or run
235
+ `new_analysis(template="two_groups")` for a ready-made script.
236
+
237
+ ## Using tpattern from R
238
+
239
+ R users (common in psychology and behavioural science) can drive the **same
240
+ engine** from R — the algorithm stays in Python, called through
241
+ [`reticulate`](https://rstudio.github.io/reticulate/), so results match this
242
+ package and the paper exactly. The R interface lives in [`r/`](r/):
243
+
244
+ ```r
245
+ # install.packages("remotes")
246
+ remotes::install_github("ajcallaway/TPattern", subdir = "r")
247
+
248
+ library(tpattern)
249
+ install_tpattern() # once: sets up a Python environment R can use
250
+
251
+ # the whole analysis in one call — prints what the advisor recommends,
252
+ # calibrates every pattern, writes a report, returns the table:
253
+ out <- tpattern_analysis("my_events.csv", time_unit = "ms")
254
+ out$table
255
+ ```
256
+
257
+ Or step by step: `read_events()` → `advise()` (the advisor, pulled through in
258
+ full) → `calibrate_patterns()` → `results_table()` / `tpattern_report()`, with
259
+ `explain()` for any setting and `new_analysis()` to write a commented starter
260
+ script. See [`r/README.md`](r/README.md). (CRAN release to follow, then
261
+ `install.packages("tpattern")`.)
262
+
263
+ ## The workflow
264
+
265
+ ```
266
+ tag events export analyse report
267
+ (OpenTag / Sportscode) ──────▶ standard ──▶ tpattern ──▶ tables · figures · dendrograms
268
+ table (detect · validate ·
269
+ calibrate)
270
+ ```
271
+
272
+ 1. **Tag** your video/events in any coding tool.
273
+ 2. **Export** to the standard input structure — one row per event
274
+ (`observation, event, start`, plus optional `end`, descriptor and group
275
+ columns). See [`SCHEMA.md`](SCHEMA.md).
276
+ 3. **Set up your coding** so the export is analysis-ready — one event per action,
277
+ explicit outcomes, unit boundaries. See [`CODING_GUIDE.md`](CODING_GUIDE.md).
278
+ 4. **Detect** T-patterns, **validate** them against a surrogate null with corrected
279
+ significance (`recommend` advises the settings; `calibrate` runs it), and
280
+ **report** (tables, dendrograms, and a `methods_text` Methods paragraph).
281
+
282
+ ## Relationship to OpenTag.Studio
283
+
284
+ [OpenTag.Studio](https://opentag.studio) is a free, browser-based sports video
285
+ tagging tool. It is the natural front end for `tpattern`: tag your footage, export
286
+ a session, and analyse it here — no proprietary software anywhere in the pipeline.
287
+ OpenTag's **THEME & GSEQ setup guide** covers how to design a coding window so the
288
+ export is analysis-ready, and that guidance applies directly to `tpattern`
289
+ (`CODING_GUIDE.md` is the short bridge). Together they form a complete, open
290
+ tag → analysis pipeline.
291
+
292
+ ## Reproducing the published results
293
+
294
+ The derived 2022 World Cup event sequences ship in [`data/`](data/), so the
295
+ published analyses reproduce from this repository alone:
296
+
297
+ ```bash
298
+ python examples/reproduce_worldcup.py # concordance, exclusion, concurrency (~5 s)
299
+ python examples/reproduce_worldcup.py --calibrate # also the surrogate null (~10 min)
300
+ ```
301
+
302
+ This regenerates the tpattern-vs-THEME pattern counts by level, the interception
303
+ exclusion divergence, the co-occurrence-vs-sequence analysis, and how many patterns
304
+ survive the surrogate null. All seeded and deterministic. See
305
+ [`data/README.md`](data/README.md) for provenance and how the data was derived.
306
+
307
+ ## Documentation
308
+
309
+ - [`SCHEMA.md`](SCHEMA.md) — the input data structure (what your export must contain).
310
+ - [`CODING_GUIDE.md`](CODING_GUIDE.md) — how to set up a coding window to produce it.
311
+ - [`data/`](data/) — the derived World Cup sequences, in the canonical format.
312
+ - [`examples/`](examples/) — a runnable quickstart, the reproduction script, and the
313
+ `my_analysis.py` / `my_group_comparison.py` / `my_null_choice.py` starter templates.
314
+ - [`PARAMETERS.md`](PARAMETERS.md) — every setting and output column, with range, recommended
315
+ value, and what higher/lower does (generated from the code, so it never drifts).
316
+
317
+ ## Tests
318
+
319
+ ```bash
320
+ pip install -e .[test]
321
+ pytest -q
322
+ ```
323
+
324
+ Both the synthetic ground-truth tests and the reproduction tests run everywhere —
325
+ the latter check the detector still reproduces the occurrence counts published for
326
+ the reference datasets to the exact N.
327
+
328
+ ## Citation
329
+
330
+ If you use `tpattern` in research, please cite the software (a machine-readable
331
+ version is in [`CITATION.cff`](CITATION.cff)):
332
+
333
+ Callaway, A. (2026). *tpattern: open, auditable temporal & sequential analysis for
334
+ sport and behaviour* [Computer software]. Zenodo.
335
+ https://doi.org/10.5281/zenodo.21397543
336
+
337
+ This DOI is permanent and always resolves to the current release. To pin a specific
338
+ version instead, use that release's own DOI, listed on the Zenodo record.
339
+
340
+ And the method it implements:
341
+
342
+ Magnusson, M. S. (2000). Discovering hidden time patterns in behavior: T-patterns
343
+ and their detection. *Behavior Research Methods, Instruments, & Computers*, 32(1),
344
+ 93–110. https://doi.org/10.3758/BF03200792
345
+
346
+ The reference software for the method, and its coding front end:
347
+
348
+ Magnusson, M. S. (2019). T-pattern detection and analysis (TPA) with THEME: A mixed
349
+ methods approach. *Frontiers in Psychology*, 10, 2663.
350
+ https://doi.org/10.3389/fpsyg.2019.02663
351
+
352
+ Jonsson, G. K., Anguera, M. T., Blanco-Villaseñor, Á., Losada, J. L.,
353
+ Hernández-Mendo, A., Ardá, T., Camerino, O., & Castellano, J. (2006). Hidden
354
+ patterns of play interaction in soccer using SOF-CODER. *Behavior Research Methods*,
355
+ 38(3), 372–381. https://doi.org/10.3758/BF03192790
356
+
357
+ ## License
358
+
359
+ MIT — see [`LICENSE`](LICENSE).
@@ -0,0 +1,324 @@
1
+ # tpattern — open, auditable analysis of recurring patterns in event sequences
2
+
3
+ [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ajcallaway/TPattern/blob/main/colab/tpattern_guided_analysis.ipynb)
4
+ [![DOI](https://img.shields.io/badge/DOI-10.5281%2Fzenodo.21397543-1682D4.svg)](https://doi.org/10.5281/zenodo.21397543)
5
+ [![R interface](https://img.shields.io/badge/R-interface-276DC3?logo=r&logoColor=white)](#using-tpattern-from-r)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
+
8
+ `tpattern` detects recurring temporal patterns (T-patterns; Magnusson, 2000) in
9
+ **any sequence of timed, labelled events** — behaviour, sport, clinical or
10
+ physiological logs, interaction data — validates them properly against chance, and
11
+ produces clean, publication-ready output (tables, figures, pattern dendrograms). It
12
+ implements the published T-pattern detection algorithm (Magnusson, 2000) as free,
13
+ auditable code — the same critical-interval method the THEME software applies (see
14
+ [The method it implements](#the-method-it-implements)) — and is the analysis
15
+ companion to the [OpenTag.Studio](https://opentag.studio) tagging tool.
16
+
17
+ ## Two ways to use it
18
+
19
+ ### 🚀 In your browser — Google Colab, no install, no coding
20
+
21
+ Open a guided notebook, upload your events CSV, and it walks you through four steps —
22
+ **upload → inspect → the recommended settings appear → run** — then hands back a full
23
+ report inline and as a downloadable zip: a colour-coded results table with a
24
+ plain-English verdict for every pattern (🟢 robust · 🟡 borderline · ⚪ likely chance),
25
+ the pattern dendrograms, the code to restyle them, and a paste-ready Methods paragraph.
26
+ No data of your own yet? Point it at [`data/worldcup_goals.csv`](data/worldcup_goals.csv)
27
+ (choose **ms** for the time unit).
28
+
29
+ Three notebooks (all in [`colab/`](colab/)):
30
+
31
+ - [**Guided analysis**](https://colab.research.google.com/github/ajcallaway/TPattern/blob/main/colab/tpattern_guided_analysis.ipynb) — **recommended.** Installs the latest `tpattern` and opens the guided panel. This is the one the badge above opens.
32
+ - **Guided analysis (offline)** — the package is bundled inside the notebook (a snapshot), so it runs where you can't install from GitHub. Open `colab/tpattern_guided_analysis_offline.ipynb` via **File → Upload notebook**.
33
+ - **Worked example** — the companion to the tutorial paper. Runs the load → inspect → recommend → calibrate → report walk-through on the shipped World Cup goal sequences, cell by cell, so you can follow the whole analysis and then swap in your own data (`colab/tpattern_worked_example.ipynb`).
34
+
35
+ ### 🐍 As a Python library
36
+
37
+ `pip install tpattern` and script it — see [Getting started](#getting-started-in-a-minute), [Quickstart](#quickstart) and [`examples/`](examples/).
38
+
39
+ Bring your own data (one row per event — see [`SCHEMA.md`](SCHEMA.md)) or try the
40
+ included [`data/`](data/) example.
41
+
42
+ ## Getting started in a minute
43
+
44
+ Install, generate a starter script, point it at your data, run it:
45
+
46
+ ```bash
47
+ pip install tpattern
48
+ python -c "import tpattern; tpattern.new_analysis()" # writes my_analysis.py
49
+ ```
50
+
51
+ Open `my_analysis.py`, change the two lines marked `# <-- EDIT` (your file and its time
52
+ unit), and run `python my_analysis.py`. It loads your events, **checks the file and tells
53
+ you in plain language about any problem**, recommends the analysis settings with reasons,
54
+ calibrates every pattern against a chance model, and writes a folder of results with a
55
+ plain-English verdict for each pattern.
56
+
57
+ Doing something more specific? Generate a template for it:
58
+
59
+ ```python
60
+ from tpattern import new_analysis
61
+ new_analysis() # one group: detect, calibrate, report
62
+ new_analysis(template="two_groups") # compare two groups (odds ratios + forest plot)
63
+ new_analysis(template="null_choice") # core vs shell: which null a pattern survives
64
+ ```
65
+
66
+ Not sure what a setting means? Ask the code — every setting and output column is documented:
67
+
68
+ ```python
69
+ from tpattern import explain
70
+ print(explain("min_lag")) # what it does, its range, the recommended value, higher vs lower
71
+ print(explain("fdr_q")) # what an output column means
72
+ ```
73
+
74
+ ## What you get
75
+
76
+ - **Forgiving data import.** `read_table` checks your file as it reads it and reports, in
77
+ plain language, any problem, how much of the file it affects, and how to fix it — instead
78
+ of silently dropping rows. Each check has a stable code (Appendix A of the tutorial; also
79
+ [`PARAMETERS.md`](PARAMETERS.md)).
80
+ - **A proper chance model.** Every pattern is tested against a surrogate null, with p-values
81
+ corrected for repeated testing (Benjamini–Hochberg FDR for screening, Holm family-wise for
82
+ confirmatory claims), stratified by hierarchy level.
83
+ - **Temporal reporting.** Beyond *which* patterns are real, the output says *when*: each
84
+ pattern's occurrence timing (median lag and spread) is reported by default — on the
85
+ dendrogram, in the table, and in the plain-English verdict — for every pattern.
86
+ - **Readable output.** Results-table columns are named for what they are (`monte_carlo_p`,
87
+ `fdr_q`, `survives_fwer_holm`, `bout_support`, `duration_median_ms`), and each pattern
88
+ carries a plain-English `interpretation`. `explain()` documents every setting and column;
89
+ the full reference is in [`PARAMETERS.md`](PARAMETERS.md).
90
+ - **One reference, everywhere.** Settings and columns live in one registry that generates the
91
+ code's `explain()`, `PARAMETERS.md`, the Colab form labels, and the tutorial's tables — so
92
+ the software, the paper and the notebook can't drift apart.
93
+ - **Clean figures** — dendrograms, temporal signatures, forest plots — that share one
94
+ customisable style (`tpattern.viz.STYLE`).
95
+
96
+ ## The method it implements
97
+
98
+ T-pattern analysis (Magnusson, 1996, 2000, 2019) finds behaviourally meaningful
99
+ structure that event counts and simple transition tables miss: event types that
100
+ recur in the same order, separated by statistically consistent time intervals, more
101
+ often than chance predicts. `tpattern` implements the algorithm exactly as published,
102
+ in auditable code:
103
+
104
+ - **Critical-interval detection.** For an ordered pair of event types (A, B) it
105
+ searches for the time window after A within which B follows more often than B's
106
+ overall rate would predict. Significance is the **upper-tail binomial** probability
107
+ of the observed number of A→B matches, evaluated against that baseline rate (B's
108
+ occurrences spread over the observation length — the *NX/T* baseline), thresholded
109
+ at α (default 0.005). This is the critical-interval test set out in Magnusson (2000)
110
+ and the THEME manual.
111
+ - **Free search, one-to-one matching, distinct tokens.** A free search selects the
112
+ largest significant interval; occurrences are matched one-to-one by the greedy
113
+ procedure the algorithm specifies; a pattern must be built from distinct event
114
+ tokens.
115
+ - **Bottom-up hierarchy with completeness competition.** Patterns are grown level by
116
+ level, longer patterns competing with their sub-patterns so that only the most
117
+ complete survive.
118
+
119
+ On top of the published detection, `tpattern` adds what the method has historically
120
+ lacked:
121
+
122
+ - **a proper chance model** — every detected pattern is tested against a surrogate
123
+ null, with p-values **corrected for repeated testing** (Benjamini–Hochberg FDR for
124
+ screening, Holm family-wise for confirmatory claims), stratified by level;
125
+ - **explicit concurrency handling** — events sharing a timestamp are reported as
126
+ co-occurrence rather than sequence;
127
+ - **clear reporting** — tidy tables, effect sizes with confidence intervals,
128
+ purposeful figures, and clean **dendrograms** of the detected patterns.
129
+
130
+ The reference software for this method is THEME (PatternVision Ltd), with **SOF-CODER**
131
+ (Jonsson et al., 2006) as its coding front end. `tpattern` reads that ecosystem
132
+ directly — `read_sofcoder` ingests SOF-CODER/THEME (`DATANAME, T, Events`) files — so
133
+ existing THEME datasets can be re-analysed with the surrogate calibration, and
134
+ [OpenTag.Studio](https://opentag.studio) can play, for `tpattern`, the role SOF-CODER
135
+ plays for THEME.
136
+
137
+ ## Installation
138
+
139
+ ```bash
140
+ pip install tpattern
141
+ ```
142
+
143
+ Add the guided-wizard extras with `pip install tpattern[gui]`. To work from source
144
+ instead (for development or to run the reproduction scripts and shipped data):
145
+
146
+ ```bash
147
+ git clone https://github.com/ajcallaway/TPattern.git
148
+ cd tpattern
149
+ pip install -e .
150
+ ```
151
+
152
+ Requires Python ≥ 3.9 (depends on numpy, scipy, matplotlib).
153
+
154
+ ## Quickstart
155
+
156
+ ```python
157
+ from tpattern import read_table, Config, recommend, calibrate, report, methods_text
158
+
159
+ # 1. Load your events — one row per event (observation, event, start).
160
+ # Pass time_unit="ms" if your times are in milliseconds (default is seconds).
161
+ # See SCHEMA.md for the (simple) required format.
162
+ observations = read_table("events.csv", time_unit="s")
163
+
164
+ # 2. Let the tool inspect the data and recommend the method — which surrogate
165
+ # null, whether to require a genuine lag, which error control — with reasons.
166
+ print(recommend(observations))
167
+
168
+ # 3. Detect and calibrate in one call: every pattern is tested against a
169
+ # surrogate null with correction for repeated testing.
170
+ # (calibrate() runs the detection for you — you don't call detect() first.)
171
+ result = calibrate(observations, Config(), null="profile", B=200, q_target=0.05)
172
+ survivors = result.kept("fdr") # patterns that survive false-discovery control
173
+
174
+ # 4. Report: a tidy results table (monte_carlo_p, fdr_q, survives_fwer_holm, the observed
175
+ # timing, and a plain-English `interpretation` per pattern), pattern dendrograms, the
176
+ # temporal-signature and occurrence plots, the event-type roles/connections tables, and a
177
+ # paste-ready Methods paragraph stating every setting and what it does.
178
+ report(result, "report_out", observations=observations, title="My analysis")
179
+ print(methods_text(Config(), observations=observations, calibration=result))
180
+ ```
181
+
182
+ Prefer not to write the pipeline yourself? `python -c "import tpattern;
183
+ tpattern.new_analysis()"` writes a commented [`my_analysis.py`](examples/my_analysis.py)
184
+ you edit and run (see [Getting started](#getting-started-in-a-minute)).
185
+
186
+ Two runnable examples:
187
+
188
+ ```bash
189
+ pip install -e .
190
+ python examples/quickstart.py # no data needed (synthetic ground-truth demo)
191
+ python examples/reproduce_worldcup.py # a real read_table + full analysis on shipped data
192
+ ```
193
+
194
+ Just want the detected patterns without calibration? `Engine(observations,
195
+ Config()).detect()` returns them directly.
196
+
197
+ **Comparing two groups** (winner vs loser, goal vs non-goal, condition A vs B)?
198
+ `group_contrast(observations, group_of)` tests each pattern's occurrence between
199
+ the groups (Fisher's exact test, odds ratio + 95% CI) and feeds `forest_plot` — or run
200
+ `new_analysis(template="two_groups")` for a ready-made script.
201
+
202
+ ## Using tpattern from R
203
+
204
+ R users (common in psychology and behavioural science) can drive the **same
205
+ engine** from R — the algorithm stays in Python, called through
206
+ [`reticulate`](https://rstudio.github.io/reticulate/), so results match this
207
+ package and the paper exactly. The R interface lives in [`r/`](r/):
208
+
209
+ ```r
210
+ # install.packages("remotes")
211
+ remotes::install_github("ajcallaway/TPattern", subdir = "r")
212
+
213
+ library(tpattern)
214
+ install_tpattern() # once: sets up a Python environment R can use
215
+
216
+ # the whole analysis in one call — prints what the advisor recommends,
217
+ # calibrates every pattern, writes a report, returns the table:
218
+ out <- tpattern_analysis("my_events.csv", time_unit = "ms")
219
+ out$table
220
+ ```
221
+
222
+ Or step by step: `read_events()` → `advise()` (the advisor, pulled through in
223
+ full) → `calibrate_patterns()` → `results_table()` / `tpattern_report()`, with
224
+ `explain()` for any setting and `new_analysis()` to write a commented starter
225
+ script. See [`r/README.md`](r/README.md). (CRAN release to follow, then
226
+ `install.packages("tpattern")`.)
227
+
228
+ ## The workflow
229
+
230
+ ```
231
+ tag events export analyse report
232
+ (OpenTag / Sportscode) ──────▶ standard ──▶ tpattern ──▶ tables · figures · dendrograms
233
+ table (detect · validate ·
234
+ calibrate)
235
+ ```
236
+
237
+ 1. **Tag** your video/events in any coding tool.
238
+ 2. **Export** to the standard input structure — one row per event
239
+ (`observation, event, start`, plus optional `end`, descriptor and group
240
+ columns). See [`SCHEMA.md`](SCHEMA.md).
241
+ 3. **Set up your coding** so the export is analysis-ready — one event per action,
242
+ explicit outcomes, unit boundaries. See [`CODING_GUIDE.md`](CODING_GUIDE.md).
243
+ 4. **Detect** T-patterns, **validate** them against a surrogate null with corrected
244
+ significance (`recommend` advises the settings; `calibrate` runs it), and
245
+ **report** (tables, dendrograms, and a `methods_text` Methods paragraph).
246
+
247
+ ## Relationship to OpenTag.Studio
248
+
249
+ [OpenTag.Studio](https://opentag.studio) is a free, browser-based sports video
250
+ tagging tool. It is the natural front end for `tpattern`: tag your footage, export
251
+ a session, and analyse it here — no proprietary software anywhere in the pipeline.
252
+ OpenTag's **THEME & GSEQ setup guide** covers how to design a coding window so the
253
+ export is analysis-ready, and that guidance applies directly to `tpattern`
254
+ (`CODING_GUIDE.md` is the short bridge). Together they form a complete, open
255
+ tag → analysis pipeline.
256
+
257
+ ## Reproducing the published results
258
+
259
+ The derived 2022 World Cup event sequences ship in [`data/`](data/), so the
260
+ published analyses reproduce from this repository alone:
261
+
262
+ ```bash
263
+ python examples/reproduce_worldcup.py # concordance, exclusion, concurrency (~5 s)
264
+ python examples/reproduce_worldcup.py --calibrate # also the surrogate null (~10 min)
265
+ ```
266
+
267
+ This regenerates the tpattern-vs-THEME pattern counts by level, the interception
268
+ exclusion divergence, the co-occurrence-vs-sequence analysis, and how many patterns
269
+ survive the surrogate null. All seeded and deterministic. See
270
+ [`data/README.md`](data/README.md) for provenance and how the data was derived.
271
+
272
+ ## Documentation
273
+
274
+ - [`SCHEMA.md`](SCHEMA.md) — the input data structure (what your export must contain).
275
+ - [`CODING_GUIDE.md`](CODING_GUIDE.md) — how to set up a coding window to produce it.
276
+ - [`data/`](data/) — the derived World Cup sequences, in the canonical format.
277
+ - [`examples/`](examples/) — a runnable quickstart, the reproduction script, and the
278
+ `my_analysis.py` / `my_group_comparison.py` / `my_null_choice.py` starter templates.
279
+ - [`PARAMETERS.md`](PARAMETERS.md) — every setting and output column, with range, recommended
280
+ value, and what higher/lower does (generated from the code, so it never drifts).
281
+
282
+ ## Tests
283
+
284
+ ```bash
285
+ pip install -e .[test]
286
+ pytest -q
287
+ ```
288
+
289
+ Both the synthetic ground-truth tests and the reproduction tests run everywhere —
290
+ the latter check the detector still reproduces the occurrence counts published for
291
+ the reference datasets to the exact N.
292
+
293
+ ## Citation
294
+
295
+ If you use `tpattern` in research, please cite the software (a machine-readable
296
+ version is in [`CITATION.cff`](CITATION.cff)):
297
+
298
+ Callaway, A. (2026). *tpattern: open, auditable temporal & sequential analysis for
299
+ sport and behaviour* [Computer software]. Zenodo.
300
+ https://doi.org/10.5281/zenodo.21397543
301
+
302
+ This DOI is permanent and always resolves to the current release. To pin a specific
303
+ version instead, use that release's own DOI, listed on the Zenodo record.
304
+
305
+ And the method it implements:
306
+
307
+ Magnusson, M. S. (2000). Discovering hidden time patterns in behavior: T-patterns
308
+ and their detection. *Behavior Research Methods, Instruments, & Computers*, 32(1),
309
+ 93–110. https://doi.org/10.3758/BF03200792
310
+
311
+ The reference software for the method, and its coding front end:
312
+
313
+ Magnusson, M. S. (2019). T-pattern detection and analysis (TPA) with THEME: A mixed
314
+ methods approach. *Frontiers in Psychology*, 10, 2663.
315
+ https://doi.org/10.3389/fpsyg.2019.02663
316
+
317
+ Jonsson, G. K., Anguera, M. T., Blanco-Villaseñor, Á., Losada, J. L.,
318
+ Hernández-Mendo, A., Ardá, T., Camerino, O., & Castellano, J. (2006). Hidden
319
+ patterns of play interaction in soccer using SOF-CODER. *Behavior Research Methods*,
320
+ 38(3), 372–381. https://doi.org/10.3758/BF03192790
321
+
322
+ ## License
323
+
324
+ MIT — see [`LICENSE`](LICENSE).