priorityx 0.3.0__tar.gz → 0.5.0__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 (54) hide show
  1. priorityx-0.5.0/.github/workflows/docs.yml +31 -0
  2. {priorityx-0.3.0 → priorityx-0.5.0}/.github/workflows/release.yml +2 -2
  3. {priorityx-0.3.0 → priorityx-0.5.0}/.github/workflows/test.yml +1 -1
  4. priorityx-0.5.0/CHANGELOG.md +74 -0
  5. {priorityx-0.3.0 → priorityx-0.5.0}/PKG-INFO +56 -1
  6. {priorityx-0.3.0 → priorityx-0.5.0}/README.md +55 -0
  7. priorityx-0.5.0/docs/api-reference.md +407 -0
  8. priorityx-0.5.0/docs/changelog.md +59 -0
  9. priorityx-0.5.0/docs/index.md +106 -0
  10. {priorityx-0.3.0 → priorityx-0.5.0}/docs/methodology.md +7 -0
  11. {priorityx-0.3.0 → priorityx-0.5.0}/docs/output_naming.md +4 -5
  12. {priorityx-0.3.0 → priorityx-0.5.0}/docs/priority_classification.md +1 -1
  13. {priorityx-0.3.0 → priorityx-0.5.0}/docs/quickstart.md +28 -21
  14. priorityx-0.5.0/mkdocs.yml +40 -0
  15. {priorityx-0.3.0 → priorityx-0.5.0}/pyproject.toml +4 -1
  16. {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/__init__.py +25 -4
  17. {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/api.py +9 -5
  18. priorityx-0.5.0/src/priorityx/core/glmm.py +784 -0
  19. {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/core/quadrants.py +11 -10
  20. priorityx-0.5.0/src/priorityx/metrics.py +397 -0
  21. {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/tracking/drivers.py +252 -43
  22. {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/tracking/movement.py +17 -5
  23. {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/tracking/transitions.py +5 -5
  24. {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/viz/matrix.py +204 -70
  25. {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/viz/timeline.py +71 -23
  26. priorityx-0.5.0/src/priorityx/viz/trajectory.py +486 -0
  27. priorityx-0.5.0/tests/test_api_axes.py +90 -0
  28. {priorityx-0.3.0 → priorityx-0.5.0}/tests/test_drivers.py +173 -0
  29. {priorityx-0.3.0 → priorityx-0.5.0}/tests/test_glmm.py +77 -2
  30. priorityx-0.5.0/tests/test_metrics.py +78 -0
  31. priorityx-0.5.0/tests/test_movement_monthly.py +189 -0
  32. {priorityx-0.3.0 → priorityx-0.5.0}/tests/test_quadrants.py +4 -2
  33. priorityx-0.5.0/tests/test_viz_matrix.py +47 -0
  34. {priorityx-0.3.0 → priorityx-0.5.0}/uv.lock +207 -1
  35. priorityx-0.3.0/docs/README.md +0 -15
  36. priorityx-0.3.0/docs/api-reference.md +0 -239
  37. priorityx-0.3.0/src/priorityx/core/glmm.py +0 -429
  38. priorityx-0.3.0/src/priorityx/viz/trajectory.py +0 -335
  39. priorityx-0.3.0/tests/test_movement_monthly.py +0 -108
  40. {priorityx-0.3.0 → priorityx-0.5.0}/.gitignore +0 -0
  41. {priorityx-0.3.0 → priorityx-0.5.0}/LICENSE +0 -0
  42. {priorityx-0.3.0 → priorityx-0.5.0}/Makefile +0 -0
  43. {priorityx-0.3.0 → priorityx-0.5.0}/examples/README.md +0 -0
  44. {priorityx-0.3.0 → priorityx-0.5.0}/examples/bugs/bugs_monitoring.py +0 -0
  45. {priorityx-0.3.0 → priorityx-0.5.0}/examples/incidents/incident_monitoring.py +0 -0
  46. {priorityx-0.3.0 → priorityx-0.5.0}/examples/violations/violations_monitoring.py +0 -0
  47. {priorityx-0.3.0 → priorityx-0.5.0}/scripts/version.py +0 -0
  48. {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/core/__init__.py +0 -0
  49. {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/core/filters.py +0 -0
  50. {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/tracking/__init__.py +0 -0
  51. {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/utils/__init__.py +0 -0
  52. {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/utils/helpers.py +0 -0
  53. {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/viz/__init__.py +0 -0
  54. {priorityx-0.3.0 → priorityx-0.5.0}/tests/test_transitions.py +0 -0
@@ -0,0 +1,31 @@
1
+ name: Deploy Docs
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ paths:
8
+ - 'docs/**'
9
+ - 'mkdocs.yml'
10
+ - '.github/workflows/docs.yml'
11
+ workflow_dispatch:
12
+
13
+ permissions:
14
+ contents: write
15
+
16
+ jobs:
17
+ deploy:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v6
21
+
22
+ - name: Set up Python
23
+ uses: actions/setup-python@v6
24
+ with:
25
+ python-version: '3.11'
26
+
27
+ - name: Install dependencies
28
+ run: pip install mkdocs mkdocs-material pymdown-extensions
29
+
30
+ - name: Deploy to GitHub Pages
31
+ run: mkdocs gh-deploy --force
@@ -13,7 +13,7 @@ jobs:
13
13
  name: Build package
14
14
  runs-on: ubuntu-latest
15
15
  steps:
16
- - uses: actions/checkout@v5
16
+ - uses: actions/checkout@v6
17
17
 
18
18
  - name: Set up Python
19
19
  uses: actions/setup-python@v6
@@ -87,7 +87,7 @@ jobs:
87
87
  contents: write
88
88
 
89
89
  steps:
90
- - uses: actions/checkout@v5
90
+ - uses: actions/checkout@v6
91
91
 
92
92
  - name: Create Release
93
93
  uses: softprops/action-gh-release@v2
@@ -14,7 +14,7 @@ jobs:
14
14
  python-version: ['3.10', '3.11', '3.12']
15
15
 
16
16
  steps:
17
- - uses: actions/checkout@v5
17
+ - uses: actions/checkout@v6
18
18
 
19
19
  - uses: actions/setup-python@v6
20
20
  with:
@@ -0,0 +1,74 @@
1
+ # Changelog
2
+
3
+ Only major releases (v0.x.0) are listed.
4
+
5
+ ---
6
+
7
+ ## v0.4.0 (2025-01)
8
+
9
+ **Unified API with Axis Metrics**
10
+
11
+ - Introduced `x_metric` / `y_metric` parameters to `fit_priority_matrix()` for flexible axis definitions beyond default volume/growth
12
+ - Added `x_score` / `y_score` coordinate-based quadrant classification (replaces Random_Intercept/Random_Slope naming in outputs)
13
+ - Added Gamma family support for continuous GLMM (e.g., duration or amount metrics)
14
+ - Gaussian GLMM support for metric-based axes
15
+ - Improved quadrant label rendering with configurable legend position (`legend_loc`, `show_legend`)
16
+ - Row-aligned quadrant label offsetting to avoid legend overlap
17
+
18
+ **Trajectory Auto-Selection**
19
+
20
+ - Added `highlight_top_n` parameter to `plot_entity_trajectories()` for automatic entity selection
21
+ - Added `highlight_by` parameter: `"trajectory_distance"` (euclidean path) or `"total_movement"` (manhattan)
22
+ - Added `recent_periods` parameter to limit trajectory window to last N periods
23
+
24
+ **Enhanced Driver Analysis**
25
+
26
+ - Added `numeric_cols` parameter to `extract_transition_drivers()` for amount/duration breakdowns
27
+ - Explicit bins: `{"amount": [0, 1e6, 5e6, 10e6]}`
28
+ - Auto quantiles: `{"duration": 4}` (4 bins)
29
+ - Renamed `quarter_from`/`quarter_to` to `period_from`/`period_to` (backwards compatible)
30
+ - Renamed `top_n_subcategories` to `top_n`, `min_subcategory_delta` to `min_delta` (backwards compatible)
31
+ - Added `save_txt`, `txt_path`, `txt_mode` parameters to `display_transition_drivers()` for file output
32
+
33
+ ---
34
+
35
+ ## v0.3.0 (2024-12)
36
+
37
+ **Entity Metrics and Priority Indices**
38
+
39
+ - Implemented `add_priority_indices()` for composite index calculation:
40
+ - **RI** (Risk Index): volume + growth + severity
41
+ - **SQI** (Service Quality Index): resolution speed + recovery rate
42
+ - **EWI** (Early Warning Index): blends RI and SQI for prioritization
43
+ - Added `aggregate_entity_metrics()` helper for per-entity metric aggregation
44
+ - Added `sensitivity_analysis()` for weight stability testing
45
+ - Monthly granularity support (beta) in GLMM and visualizations
46
+ - Unified `px.*` namespace imports pattern
47
+
48
+ ---
49
+
50
+ ## v0.2.0 (2024-11)
51
+
52
+ **Transition Tracking and Visualization**
53
+
54
+ - Implemented `track_cumulative_movement()` for entity trajectory tracking
55
+ - Added `extract_transitions()` for quadrant movement detection
56
+ - Transition timeline visualization with priority-based coloring (Crisis/Investigate/Monitor/Low)
57
+ - Spike markers (`*X`, `*Y`, `*XY`) for volume/growth spikes
58
+ - Deterministic seeding via `PRIORITYX_GLMM_SEED` for reproducible GLMM fits
59
+ - `plot_entity_trajectories()` for movement path visualization
60
+ - Transition driver analysis (experimental)
61
+
62
+ ---
63
+
64
+ ## v0.1.0 (2024-10)
65
+
66
+ **Initial Release**
67
+
68
+ - Core GLMM estimation with Poisson mixed effects (statsmodels backend)
69
+ - `fit_priority_matrix()` main API for entity prioritization
70
+ - Quadrant classification (Q1-Q4) based on volume and growth
71
+ - Priority matrix scatter plot visualization
72
+ - Quarterly, yearly, and semiannual temporal granularity
73
+ - Date filtering and minimum observation thresholds
74
+ - CSV and plot export with configurable output directories
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: priorityx
3
- Version: 0.3.0
3
+ Version: 0.5.0
4
4
  Summary: Entity prioritization and escalation detection using GLMM statistical models
5
5
  Project-URL: Homepage, https://github.com/okkymabruri/priorityx
6
6
  Project-URL: Repository, https://github.com/okkymabruri/priorityx
@@ -50,16 +50,71 @@ import priorityx as px
50
50
 
51
51
  df = pd.read_csv("data.csv")
52
52
 
53
+ # Default: volume x growth (single GLMM)
53
54
  results, stats = px.fit_priority_matrix(
54
55
  df,
55
56
  entity_col="service",
56
57
  timestamp_col="date",
57
58
  temporal_granularity="quarterly",
58
59
  )
60
+ # Returns: entity, x_score, y_score, count, quadrant
59
61
 
60
62
  px.plot_priority_matrix(results, entity_name="Service", save_plot=True)
61
63
  ```
62
64
 
65
+ ### Custom Axes
66
+
67
+ ```python
68
+ # Custom Y axis: volume × resolution_days (two GLMMs)
69
+ results, _ = px.fit_priority_matrix(
70
+ df,
71
+ entity_col="service",
72
+ timestamp_col="date",
73
+ y_metric="resolution_days",
74
+ )
75
+
76
+ # Custom both axes: disputed_amount × paid_amount
77
+ results, _ = px.fit_priority_matrix(
78
+ df,
79
+ entity_col="service",
80
+ timestamp_col="date",
81
+ x_metric="disputed_amount",
82
+ y_metric="paid_amount",
83
+ )
84
+ ```
85
+
86
+ ### Composite Indices
87
+
88
+ ```python
89
+ # Add entity metrics
90
+ metrics = px.aggregate_entity_metrics(
91
+ df,
92
+ entity_col="service",
93
+ duration_start_col="opened_at",
94
+ duration_end_col="closed_at",
95
+ primary_col="exposure",
96
+ secondary_col="recovery",
97
+ )
98
+ results = results.merge(metrics, left_on="entity", right_on="service", how="left")
99
+
100
+ # Add weighted indices: RI (Risk), SQI (Service Quality), EWI (Early Warning)
101
+ results = px.add_priority_indices(
102
+ results,
103
+ volume_col="count",
104
+ growth_col="y_score",
105
+ severity_col="total_primary",
106
+ resolution_col="mean_duration",
107
+ recovery_col="secondary_to_primary_ratio",
108
+ # customize weights (default shown)
109
+ w_volume=0.4, w_growth=0.4, w_severity=0.2,
110
+ w_resolution=0.5, w_recovery=0.5,
111
+ w_risk=0.7, w_quality=0.3,
112
+ )
113
+
114
+ # Top priority entities
115
+ top_risks = results.nlargest(10, "EWI")
116
+ ```
117
+
63
118
  ## Features
64
119
 
65
120
  - GLMM-based priority matrix (Q1–Q4) with entity-level intercept/slope insights
@@ -22,16 +22,71 @@ import priorityx as px
22
22
 
23
23
  df = pd.read_csv("data.csv")
24
24
 
25
+ # Default: volume x growth (single GLMM)
25
26
  results, stats = px.fit_priority_matrix(
26
27
  df,
27
28
  entity_col="service",
28
29
  timestamp_col="date",
29
30
  temporal_granularity="quarterly",
30
31
  )
32
+ # Returns: entity, x_score, y_score, count, quadrant
31
33
 
32
34
  px.plot_priority_matrix(results, entity_name="Service", save_plot=True)
33
35
  ```
34
36
 
37
+ ### Custom Axes
38
+
39
+ ```python
40
+ # Custom Y axis: volume × resolution_days (two GLMMs)
41
+ results, _ = px.fit_priority_matrix(
42
+ df,
43
+ entity_col="service",
44
+ timestamp_col="date",
45
+ y_metric="resolution_days",
46
+ )
47
+
48
+ # Custom both axes: disputed_amount × paid_amount
49
+ results, _ = px.fit_priority_matrix(
50
+ df,
51
+ entity_col="service",
52
+ timestamp_col="date",
53
+ x_metric="disputed_amount",
54
+ y_metric="paid_amount",
55
+ )
56
+ ```
57
+
58
+ ### Composite Indices
59
+
60
+ ```python
61
+ # Add entity metrics
62
+ metrics = px.aggregate_entity_metrics(
63
+ df,
64
+ entity_col="service",
65
+ duration_start_col="opened_at",
66
+ duration_end_col="closed_at",
67
+ primary_col="exposure",
68
+ secondary_col="recovery",
69
+ )
70
+ results = results.merge(metrics, left_on="entity", right_on="service", how="left")
71
+
72
+ # Add weighted indices: RI (Risk), SQI (Service Quality), EWI (Early Warning)
73
+ results = px.add_priority_indices(
74
+ results,
75
+ volume_col="count",
76
+ growth_col="y_score",
77
+ severity_col="total_primary",
78
+ resolution_col="mean_duration",
79
+ recovery_col="secondary_to_primary_ratio",
80
+ # customize weights (default shown)
81
+ w_volume=0.4, w_growth=0.4, w_severity=0.2,
82
+ w_resolution=0.5, w_recovery=0.5,
83
+ w_risk=0.7, w_quality=0.3,
84
+ )
85
+
86
+ # Top priority entities
87
+ top_risks = results.nlargest(10, "EWI")
88
+ ```
89
+
35
90
  ## Features
36
91
 
37
92
  - GLMM-based priority matrix (Q1–Q4) with entity-level intercept/slope insights
@@ -0,0 +1,407 @@
1
+ # API Reference
2
+
3
+ ## Core Functions
4
+
5
+ ### fit_priority_matrix
6
+
7
+ ```python
8
+ import priorityx as px
9
+
10
+ # Default: volume × growth (single GLMM)
11
+ results, stats = px.fit_priority_matrix(
12
+ df,
13
+ entity_col="service",
14
+ timestamp_col="date",
15
+ temporal_granularity="quarterly",
16
+ )
17
+ # Returns: entity, x_score, y_score, count, quadrant
18
+
19
+ # Custom Y axis: volume × resolution_days (two GLMMs)
20
+ results, stats = px.fit_priority_matrix(
21
+ df,
22
+ entity_col="service",
23
+ timestamp_col="date",
24
+ y_metric="resolution_days",
25
+ )
26
+
27
+ # Custom both axes with Gamma family for right-skewed data
28
+ results, stats = px.fit_priority_matrix(
29
+ df,
30
+ entity_col="service",
31
+ timestamp_col="date",
32
+ x_metric="disputed_amount",
33
+ y_metric="paid_amount",
34
+ family="gamma",
35
+ )
36
+ ```
37
+
38
+ Unified entry point for GLMM-based entity prioritization. Supports count-based (Poisson) and metric-based (Gaussian/Gamma) axes.
39
+
40
+ **Parameters:**
41
+
42
+ - `df`: pandas DataFrame with one row per event
43
+ - `entity_col`: Entity identifier column name
44
+ - `timestamp_col`: Date column name
45
+ - `x_metric`: Optional metric column for X axis (None = count-based)
46
+ - `y_metric`: Optional metric column for Y axis (None = count-based)
47
+ - `x_effect`: Random effect for X score ("intercept" or "slope", default: "intercept")
48
+ - `y_effect`: Random effect for Y score ("intercept" or "slope", default: "slope")
49
+ - `family`: Distribution for continuous metrics ("gaussian" or "gamma", default: "gaussian")
50
+ - `count_col`: Optional count column (default: row count per entity-period)
51
+ - `date_filter`: Date filter string (e.g., "< 2025-01-01", ">= 2024-01-01")
52
+ - `min_observations`: Minimum time periods required per entity
53
+ - `min_total_count`: Minimum total count threshold
54
+ - `decline_window_quarters`: Filter entities inactive >N quarters
55
+ - `temporal_granularity`: "yearly", "quarterly", "semiannual", or "monthly"
56
+ - `vcp_p`: Random effects prior scale (default: 3.5)
57
+ - `fe_p`: Fixed effects prior scale (default: 3.0)
58
+
59
+ **Returns:**
60
+
61
+ - `results`: DataFrame with `entity`, `x_score`, `y_score`, `count`, `quadrant`
62
+ - `stats`: Dictionary with model statistics
63
+
64
+ **Family Selection:**
65
+
66
+ - `"gaussian"` (default): Works for any data, robust for entity ranking
67
+ - `"gamma"`: Use for right-skewed positive data (durations, monetary amounts)
68
+
69
+ > **Reproducibility:** set the environment variable `PRIORITYX_GLMM_SEED` or call `set_glmm_random_seed(value)` before invoking `fit_priority_matrix` to obtain deterministic variational Bayes estimates.
70
+
71
+ ---
72
+
73
+ ## Metrics Functions
74
+
75
+ ### aggregate_entity_metrics
76
+
77
+ ```python
78
+ import priorityx as px
79
+
80
+ metrics = px.aggregate_entity_metrics(
81
+ df,
82
+ entity_col="service",
83
+ duration_start_col="opened_at",
84
+ duration_end_col="closed_at",
85
+ primary_col="exposure",
86
+ secondary_col="recovery",
87
+ )
88
+ # Returns: entity, mean_duration, total_primary, total_secondary, secondary_to_primary_ratio
89
+ ```
90
+
91
+ Computes per-entity aggregated metrics for enrichment.
92
+
93
+ ### add_priority_indices
94
+
95
+ ```python
96
+ import priorityx as px
97
+
98
+ enriched = px.add_priority_indices(
99
+ results,
100
+ volume_col="count",
101
+ growth_col="y_score",
102
+ severity_col="total_primary",
103
+ resolution_col="mean_duration",
104
+ recovery_col="secondary_to_primary_ratio",
105
+ # Weights (defaults shown)
106
+ w_volume=0.4, w_growth=0.4, w_severity=0.2,
107
+ w_resolution=0.5, w_recovery=0.5,
108
+ w_risk=0.7, w_quality=0.3,
109
+ )
110
+ ```
111
+
112
+ Adds composite risk indices to enriched entity data.
113
+
114
+ **Output columns:**
115
+
116
+ - `z_volume`, `z_growth`, `z_severity`: Z-scored risk components
117
+ - `z_neg_resolution`, `z_recovery`: Z-scored quality components
118
+ - `RI`: Risk Index = weighted sum of z_volume, z_growth, z_severity
119
+ - `SQI`: Service Quality Index = weighted sum of z_neg_resolution, z_recovery
120
+ - `EWI`: Early Warning Index = w_risk × RI + w_quality × (-SQI)
121
+
122
+ **Usage:**
123
+ ```python
124
+ # Top priority entities
125
+ top_risks = enriched.nlargest(10, "EWI")
126
+ ```
127
+
128
+ ### sensitivity_analysis
129
+
130
+ ```python
131
+ import priorityx as px
132
+
133
+ results = px.sensitivity_analysis(
134
+ df,
135
+ index_col="EWI",
136
+ entity_col="entity",
137
+ weight_ranges={
138
+ "w_risk": [0.6, 0.7, 0.8],
139
+ "w_quality": [0.2, 0.3, 0.4],
140
+ },
141
+ top_n=10,
142
+ )
143
+ ```
144
+
145
+ Tests ranking stability across weight variations.
146
+
147
+ ---
148
+
149
+ ## Tracking Functions
150
+
151
+ ### track_cumulative_movement
152
+
153
+ ```python
154
+ import priorityx as px
155
+
156
+ movement, meta = px.track_cumulative_movement(
157
+ df,
158
+ entity_col,
159
+ timestamp_col,
160
+ quarters=None,
161
+ min_total_count=20,
162
+ decline_window_quarters=6,
163
+ temporal_granularity="quarterly",
164
+ vcp_p=3.5,
165
+ fe_p=3.0
166
+ )
167
+ ```
168
+
169
+ Tracks entity movement through priority quadrants over time.
170
+
171
+ **Returns:**
172
+
173
+ - `movement`: DataFrame with quarterly X/Y positions
174
+ - `meta`: Dictionary with tracking metadata
175
+
176
+ ### extract_transitions
177
+
178
+ ```python
179
+ import priorityx as px
180
+
181
+ transitions = px.extract_transitions(
182
+ movement_df,
183
+ focus_risk_increasing=True
184
+ )
185
+ ```
186
+
187
+ Extracts quadrant transitions from movement data.
188
+
189
+ **Returns:**
190
+
191
+ - DataFrame with transition details and risk levels
192
+
193
+ ### extract_transition_drivers
194
+
195
+ ```python
196
+ import priorityx as px
197
+
198
+ # Basic usage with categorical breakdowns
199
+ analysis = px.extract_transition_drivers(
200
+ movement_df,
201
+ df_raw,
202
+ entity_name="Service A",
203
+ period_from="2024-Q2",
204
+ period_to="2024-Q3",
205
+ entity_col="service",
206
+ timestamp_col="date",
207
+ subcategory_cols=["type", "category"], # categorical breakdowns
208
+ )
209
+
210
+ # With numeric column breakdowns (amounts, durations)
211
+ analysis = px.extract_transition_drivers(
212
+ movement_df,
213
+ df_raw,
214
+ entity_name="Fintech - Pinjaman Online",
215
+ period_from="2024-Q3",
216
+ period_to="2024-Q4",
217
+ entity_col="product",
218
+ timestamp_col="date",
219
+ subcategory_cols=["region", "gender"],
220
+ numeric_cols={
221
+ "disputed_amount": [0, 1e6, 5e6, 10e6], # explicit bin edges
222
+ "resolution_days": 4, # 4 quantile bins (auto)
223
+ },
224
+ )
225
+ ```
226
+
227
+ Analyzes root causes of a quadrant transition.
228
+
229
+ **Parameters:**
230
+
231
+ - `movement_df`: Output from track_cumulative_movement()
232
+ - `df_raw`: Raw event data (pandas DataFrame)
233
+ - `entity_name`: Entity to analyze
234
+ - `period_from`: Starting period (e.g., "2024-Q2", "2024-01")
235
+ - `period_to`: Ending period (e.g., "2024-Q3", "2024-02")
236
+ - `entity_col`: Entity column name
237
+ - `timestamp_col`: Timestamp column name
238
+ - `subcategory_cols`: Optional list of categorical columns for breakdown (auto-detected when omitted)
239
+ - `numeric_cols`: Optional dict of numeric columns with bin specs:
240
+ - List of floats: explicit bin edges (e.g., `[0, 1e6, 5e6, 10e6]`)
241
+ - Integer: number of quantile bins (e.g., `4` for quartiles)
242
+ - `top_n`: Limit of drivers per column (default: 3)
243
+ - `min_delta`: Minimum count delta for inclusion (default: 1)
244
+
245
+ **Returns:**
246
+
247
+ - Dictionary with:
248
+ - `transition`: includes risk-level change and `is_concerning` flag
249
+ - `magnitude`: cumulative deltas plus period-specific weekly averages and complaint counts
250
+ - `spike_drivers`: summary notes aligned with spike indicators (`*X`, `*Y`, `*XY`)
251
+ - `subcategory_drivers`: per-column driver lists for categorical columns
252
+ - `numeric_drivers`: per-column driver lists for numeric columns (with bin edges)
253
+ - `priority`: priority tier, trigger reason, spike axis
254
+ - `meta`: diagnostic flags (e.g., whether subcategory columns were auto-detected)
255
+
256
+ ### classify_priority
257
+
258
+ ```python
259
+ from priorityx.tracking.drivers import classify_priority
260
+
261
+ priority, reason, spike_axis = classify_priority(
262
+ from_quadrant="Q3",
263
+ to_quadrant="Q1",
264
+ x=0.5, y=0.6,
265
+ x_delta=0.5, y_delta=0.5,
266
+ count_delta=100,
267
+ percent_change=200
268
+ )
269
+ ```
270
+
271
+ Classifies supervisory priority (1=Critical, 2=Investigate, 3=Monitor, 4=Low).
272
+
273
+ **Returns:**
274
+
275
+ - Tuple of (priority, reason, spike_axis)
276
+
277
+ ---
278
+
279
+ ## Visualization Functions
280
+
281
+ ### plot_priority_matrix
282
+
283
+ ```python
284
+ import priorityx as px
285
+
286
+ fig = px.plot_priority_matrix(
287
+ results_df,
288
+ entity_name="Entity",
289
+ figsize=(16, 12),
290
+ top_n_labels=5,
291
+ show_quadrant_labels=False,
292
+ save_plot=False,
293
+ output_dir="plot"
294
+ )
295
+ ```
296
+
297
+ Creates scatter plot of priority matrix.
298
+
299
+ ### plot_transition_timeline
300
+
301
+ ```python
302
+ import priorityx as px
303
+
304
+ fig = px.plot_transition_timeline(
305
+ transitions_df,
306
+ entity_name="Entity",
307
+ filter_risk_levels=["critical", "high"],
308
+ max_entities=20,
309
+ save_plot=False,
310
+ output_dir="plot",
311
+ movement_df=movement_df
312
+ )
313
+ ```
314
+
315
+ Creates timeline heatmap of transitions. Passing `movement_df` is required to compute the Crisis/Investigate/Monitor/Low priority tiers and spike markers (`*X`, `*Y`, `*XY`). Omitting it falls back to legacy risk-level tags.
316
+
317
+ ### plot_entity_trajectories
318
+
319
+ ```python
320
+ import priorityx as px
321
+
322
+ # Basic usage
323
+ fig = px.plot_entity_trajectories(
324
+ movement_df,
325
+ entity_name="Entity",
326
+ max_entities=10,
327
+ save_plot=False,
328
+ plot_dir="plot"
329
+ )
330
+
331
+ # Auto-select top movers (recommended)
332
+ fig = px.plot_entity_trajectories(
333
+ movement_df,
334
+ entity_name="product",
335
+ highlight_top_n=4, # auto-select top 4 entities
336
+ highlight_by="trajectory_distance", # by path length (or "total_movement")
337
+ recent_periods=6, # limit to last 6 periods
338
+ save_plot=True,
339
+ plot_dir="results/plot",
340
+ )
341
+ ```
342
+
343
+ Creates trajectory plot showing entity paths through priority space.
344
+
345
+ **Parameters:**
346
+
347
+ - `movement_df`: Output from track_cumulative_movement()
348
+ - `entity_name`: Label for entity type (e.g., "product", "service")
349
+ - `max_entities`: Maximum entities to show (default: 10)
350
+ - `highlight_entities`: List of specific entities to highlight
351
+ - `highlight_top_n`: Auto-select top N entities by movement (overrides max_entities)
352
+ - `highlight_by`: Selection method when using highlight_top_n:
353
+ - `"trajectory_distance"`: Euclidean path length (sum of sqrt(dx² + dy²))
354
+ - `"total_movement"`: Manhattan distance (sum of |dx| + |dy|)
355
+ - `recent_periods`: Limit trajectory to last N periods (useful for long histories)
356
+ - `temporal_granularity`: "quarterly", "monthly", etc.
357
+ - `save_plot`: Save to file (default: False)
358
+ - `save_csv`: Save trajectory data to CSV (default: False)
359
+ - `plot_dir`: Output directory for plots
360
+ - `csv_dir`: Output directory for CSVs
361
+ - `close_fig`: Close figure after rendering (set True for Jupyter to avoid duplicates)
362
+
363
+ ---
364
+
365
+ ## Utility Functions
366
+
367
+ ### Display Summaries
368
+
369
+ ```python
370
+ from priorityx.utils.helpers import (
371
+ display_quadrant_summary,
372
+ display_transition_summary,
373
+ display_movement_summary
374
+ )
375
+
376
+ display_quadrant_summary(results_df, entity_name="Service")
377
+ display_transition_summary(transitions_df, entity_name="Service")
378
+ display_movement_summary(movement_df, entity_name="Service")
379
+ ```
380
+
381
+ Prints formatted summaries of analysis results.
382
+
383
+ ### display_transition_drivers
384
+
385
+ ```python
386
+ import priorityx as px
387
+
388
+ # Print to console
389
+ px.display_transition_drivers(analysis)
390
+
391
+ # Print and save to file
392
+ px.display_transition_drivers(
393
+ analysis,
394
+ save_txt=True,
395
+ txt_path="driver_analysis.txt",
396
+ txt_mode="a", # append (default) or "w" to overwrite
397
+ )
398
+ ```
399
+
400
+ Prints transition driver analysis in human-readable format.
401
+
402
+ **Parameters:**
403
+
404
+ - `analysis`: Output from extract_transition_drivers()
405
+ - `save_txt`: Save output to text file (default: False)
406
+ - `txt_path`: Path for text file (required if save_txt=True)
407
+ - `txt_mode`: File mode - "a" to append (default), "w" to overwrite