priorityx 0.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,302 @@
1
+ """Transition timeline heatmap visualization."""
2
+
3
+ from typing import List, Literal, Optional, Tuple
4
+
5
+ import matplotlib.pyplot as plt
6
+ import pandas as pd
7
+
8
+
9
+ def plot_transition_timeline(
10
+ transitions_df: pd.DataFrame,
11
+ entity_filter: Optional[List[str]] = None,
12
+ highlight_risk_levels: List[str] = ["critical", "high"],
13
+ filter_risk_levels: List[str] = ["critical", "high", "medium"],
14
+ max_entities: Optional[int] = 20,
15
+ figsize: Tuple[int, int] = (14, 8),
16
+ title: Optional[str] = None,
17
+ x_axis_granularity: Literal["quarterly", "semiannual", "yearly"] = "quarterly",
18
+ sort_by_risk_first: bool = True,
19
+ entity_name: str = "Entity",
20
+ show_all_periods: bool = False,
21
+ save_plot: bool = False,
22
+ save_csv: bool = False,
23
+ output_dir: str = "plot",
24
+ temporal_granularity: str = "quarterly",
25
+ ) -> plt.Figure:
26
+ """
27
+ Visualize transition timeline as heatmap.
28
+
29
+ Creates a timeline showing when entities transition between quadrants,
30
+ color-coded by risk level.
31
+
32
+ Args:
33
+ transitions_df: DataFrame from extract_transitions()
34
+ Required columns: entity, transition_quarter, from_quadrant,
35
+ to_quadrant, risk_level
36
+ entity_filter: Optional list of entities to include
37
+ highlight_risk_levels: Risk levels to highlight (default: critical, high)
38
+ filter_risk_levels: Only show these risk levels (default: critical, high, medium)
39
+ max_entities: Maximum entities to display (default: 20)
40
+ figsize: Figure size (width, height)
41
+ title: Optional custom title
42
+ x_axis_granularity: Time grouping ('quarterly', 'semiannual', 'yearly')
43
+ sort_by_risk_first: Sort by risk level first (True) or count first (False)
44
+ entity_name: Name for y-axis label
45
+ show_all_periods: Include starting period even if no transitions
46
+ save_plot: Save plot to file
47
+ save_csv: Save data to CSV
48
+ output_dir: Output directory for saved files
49
+ temporal_granularity: Time granularity for file naming
50
+
51
+ Returns:
52
+ Matplotlib figure
53
+
54
+ Examples:
55
+ >>> # basic timeline
56
+ >>> fig = plot_transition_timeline(transitions_df, entity_name="Service")
57
+
58
+ >>> # focus on critical transitions only
59
+ >>> fig = plot_transition_timeline(
60
+ ... transitions_df,
61
+ ... filter_risk_levels=["critical"],
62
+ ... max_entities=10
63
+ ... )
64
+ """
65
+ if transitions_df.empty:
66
+ print("No transitions to visualize")
67
+ return None
68
+
69
+ # filter out invalid entities
70
+ df = transitions_df[
71
+ transitions_df["entity"].notna() & (transitions_df["entity"] != "nan")
72
+ ].copy()
73
+
74
+ if df.empty:
75
+ print("No valid transitions to visualize")
76
+ return None
77
+
78
+ # filter by risk levels
79
+ if filter_risk_levels:
80
+ df = df[df["risk_level"].isin(filter_risk_levels)]
81
+ if df.empty:
82
+ print(f"No transitions with risk levels: {filter_risk_levels}")
83
+ return None
84
+
85
+ # apply entity filter
86
+ if entity_filter:
87
+ df = df[df["entity"].isin(entity_filter)]
88
+
89
+ # map risk levels to numeric order
90
+ risk_order = {"critical": 0, "high": 1, "medium": 2, "low": 3}
91
+ df["risk_order"] = df["risk_level"].map(risk_order)
92
+
93
+ # aggregate quarters based on granularity
94
+ if x_axis_granularity == "semiannual":
95
+ def quarter_to_semester(q_str):
96
+ if "-Q" in q_str:
97
+ year, quarter = q_str.split("-Q")
98
+ semester = "H1" if int(quarter) <= 2 else "H2"
99
+ return f"{year}-{semester}"
100
+ return q_str
101
+ df["period"] = df["transition_quarter"].apply(quarter_to_semester)
102
+ elif x_axis_granularity == "yearly":
103
+ def quarter_to_year(q_str):
104
+ if "-Q" in q_str:
105
+ return q_str.split("-Q")[0]
106
+ return q_str
107
+ df["period"] = df["transition_quarter"].apply(quarter_to_year)
108
+ else: # quarterly
109
+ df["period"] = df["transition_quarter"]
110
+
111
+ periods = sorted(df["period"].unique())
112
+
113
+ # add starting period if requested
114
+ if show_all_periods and len(periods) > 0:
115
+ first_period = periods[0]
116
+ if x_axis_granularity == "semiannual" and "-H" in first_period:
117
+ year, semester = first_period.split("-H")
118
+ prev_semester = "H1" if semester == "H2" else "H2"
119
+ prev_year = str(int(year) - 1) if prev_semester == "H2" else year
120
+ prev_period = f"{prev_year}-{prev_semester}"
121
+ if prev_period not in periods:
122
+ periods = [prev_period] + periods
123
+ elif x_axis_granularity == "quarterly" and "-Q" in first_period:
124
+ year, quarter = first_period.split("-Q")
125
+ prev_q = str((int(quarter) - 2) % 4 + 1)
126
+ prev_year = year if int(quarter) > 1 else str(int(year) - 1)
127
+ prev_period = f"{prev_year}-Q{prev_q}"
128
+ if prev_period not in periods:
129
+ periods = [prev_period] + periods
130
+
131
+ # sort entities by priority
132
+ if sort_by_risk_first:
133
+ # sort by: most recent activity, then risk level
134
+ entity_max_period = df.groupby("entity")["period"].max()
135
+ period_rank = {p: i for i, p in enumerate(periods)}
136
+ entity_priority = pd.DataFrame({
137
+ "latest_period": entity_max_period,
138
+ "period_rank": entity_max_period.map(period_rank),
139
+ })
140
+
141
+ # get risk level in most recent period
142
+ def get_latest_risk(entity):
143
+ latest_p = entity_priority.loc[entity, "latest_period"]
144
+ entity_trans = df[(df["entity"] == entity) & (df["period"] == latest_p)]
145
+ return entity_trans["risk_order"].min() if len(entity_trans) > 0 else 99
146
+
147
+ entity_priority["risk_order"] = entity_priority.index.map(get_latest_risk)
148
+ entity_priority = entity_priority.sort_values(
149
+ ["period_rank", "risk_order"],
150
+ ascending=[False, True]
151
+ )
152
+ else:
153
+ # sort by count/volume
154
+ entity_priority = df.groupby("entity").agg({"risk_order": "min"})
155
+ entity_priority = entity_priority.sort_values("risk_order")
156
+
157
+ # limit to top N entities
158
+ if max_entities and len(entity_priority) > max_entities:
159
+ top_entities = entity_priority.head(max_entities).index.tolist()
160
+ df = df[df["entity"].isin(top_entities)]
161
+ entity_priority = entity_priority.loc[top_entities]
162
+
163
+ # get entities in priority order
164
+ entities = [e for e in entity_priority.index if e in df["entity"].values]
165
+
166
+ # create y-axis positions
167
+ y_positions = {entity: i for i, entity in enumerate(entities)}
168
+
169
+ # color map for risk levels
170
+ risk_colors = {
171
+ "critical": "#d62728", # red
172
+ "high": "#ff7f0e", # orange
173
+ "medium": "#ffdd57", # yellow
174
+ "low": "#2ca02c", # green
175
+ }
176
+
177
+ # create figure
178
+ fig, ax = plt.subplots(figsize=figsize)
179
+
180
+ # plot transitions
181
+ for _, transition in df.iterrows():
182
+ y_pos = y_positions[transition["entity"]]
183
+ x_pos = periods.index(transition["period"])
184
+
185
+ color = risk_colors.get(transition["risk_level"], "#95a5a6")
186
+
187
+ # plot circle
188
+ ax.scatter(x_pos, y_pos, s=100, c=color, alpha=0.8, zorder=2)
189
+
190
+ # add transition label
191
+ label = f"{transition['from_quadrant']}->{transition['to_quadrant']}"
192
+ ax.annotate(
193
+ label,
194
+ (x_pos, y_pos),
195
+ xytext=(8, 0),
196
+ textcoords="offset points",
197
+ fontsize=9,
198
+ color="black",
199
+ va="center",
200
+ alpha=0.8,
201
+ )
202
+
203
+ # customize plot
204
+ ax.set_yticks(range(len(entities)))
205
+ ax.set_yticklabels(entities)
206
+ ax.invert_yaxis() # highest priority at top
207
+
208
+ # x-axis labels
209
+ if x_axis_granularity == "quarterly":
210
+ quarter_to_month = {"Q1": "Mar", "Q2": "Jun", "Q3": "Sep", "Q4": "Dec"}
211
+ period_labels = []
212
+ for p in periods:
213
+ if "-Q" in p:
214
+ year, quarter = p.split("-Q")
215
+ month = quarter_to_month.get(f"Q{quarter}", quarter)
216
+ period_labels.append(f"{month} {year}")
217
+ else:
218
+ period_labels.append(p)
219
+ elif x_axis_granularity == "semiannual":
220
+ period_labels = []
221
+ for p in periods:
222
+ if "-H" in p:
223
+ year, semester = p.split("-H")
224
+ period_labels.append(f"H{semester} {year}")
225
+ else:
226
+ period_labels.append(p)
227
+ else: # yearly
228
+ period_labels = periods
229
+
230
+ ax.set_xticks(range(len(periods)))
231
+ ax.set_xticklabels(period_labels, rotation=45, ha="right")
232
+ ax.set_xlim(-0.5, len(periods) - 0.5)
233
+
234
+ # clean up borders
235
+ ax.spines["left"].set_visible(False)
236
+ ax.spines["right"].set_visible(False)
237
+ ax.spines["top"].set_visible(False)
238
+
239
+ # build legend
240
+ legend_elements = []
241
+ for risk_level in ["critical", "high", "medium", "low"]:
242
+ if risk_level in df["risk_level"].values:
243
+ legend_elements.append(
244
+ plt.scatter([], [], s=100, c=risk_colors[risk_level],
245
+ alpha=0.8, label=risk_level.capitalize())
246
+ )
247
+
248
+ if legend_elements:
249
+ ax.legend(
250
+ handles=legend_elements,
251
+ loc="center left",
252
+ bbox_to_anchor=(1.02, 0.5),
253
+ title="Risk Level",
254
+ fontsize=10,
255
+ title_fontsize=11,
256
+ frameon=False,
257
+ )
258
+
259
+ # set labels
260
+ xlabel_map = {"quarterly": "Quarter", "semiannual": "Semester", "yearly": "Year"}
261
+ ax.set_xlabel(xlabel_map.get(x_axis_granularity, "Period"), fontsize=13)
262
+ ax.set_ylabel(entity_name, fontsize=13)
263
+
264
+ if title:
265
+ ax.set_title(title, fontsize=14, fontweight="bold", pad=20)
266
+
267
+ ax.tick_params(axis='both', which='major', labelsize=10)
268
+ plt.tight_layout()
269
+
270
+ # save plot if requested
271
+ if save_plot:
272
+ import os
273
+ from datetime import datetime
274
+
275
+ os.makedirs(output_dir, exist_ok=True)
276
+ timestamp = datetime.now().strftime("%Y%m%d")
277
+ granularity_suffix = {
278
+ "quarterly": "Q",
279
+ "yearly": "Y",
280
+ "semiannual": "S",
281
+ }.get(temporal_granularity, "Q")
282
+ plot_path = f"{output_dir}/transitions-{entity_name.lower()}-{granularity_suffix}-{timestamp}.png"
283
+ plt.savefig(plot_path, dpi=300, bbox_inches="tight", format="png")
284
+ print(f"Transition plot saved: {plot_path}")
285
+
286
+ # save CSV if requested
287
+ if save_csv:
288
+ import os
289
+ from datetime import datetime
290
+
291
+ os.makedirs(f"{output_dir}/../results", exist_ok=True)
292
+ timestamp = datetime.now().strftime("%Y%m%d")
293
+ granularity_suffix = {
294
+ "quarterly": "Q",
295
+ "yearly": "Y",
296
+ "semiannual": "S",
297
+ }.get(temporal_granularity, "Q")
298
+ csv_path = f"{output_dir}/../results/transitions-{entity_name.lower()}-{granularity_suffix}-{timestamp}.csv"
299
+ df.to_csv(csv_path, index=False)
300
+ print(f"Transitions CSV saved: {csv_path}")
301
+
302
+ return fig
@@ -0,0 +1,231 @@
1
+ """Entity movement trajectory plots."""
2
+
3
+ from typing import List, Optional, Tuple
4
+
5
+ import matplotlib.pyplot as plt
6
+ import pandas as pd
7
+
8
+
9
+ def plot_movement_trajectories(
10
+ movement_df: pd.DataFrame,
11
+ entity_name: str = "Entity",
12
+ highlight_entities: Optional[List[str]] = None,
13
+ max_entities: int = 10,
14
+ figsize: Tuple[int, int] = (14, 10),
15
+ title: Optional[str] = None,
16
+ save_plot: bool = True,
17
+ output_dir: str = "plot",
18
+ temporal_granularity: str = "quarterly",
19
+ ) -> plt.Figure:
20
+ """
21
+ Visualize entity trajectories through priority space.
22
+
23
+ Shows how entities move through (X, Y) coordinates over time,
24
+ with arrows indicating direction and markers for start/end points.
25
+
26
+ Args:
27
+ movement_df: DataFrame from track_cumulative_movement()
28
+ Required columns: entity, quarter, period_x, period_y,
29
+ period_quadrant, global_quadrant
30
+ entity_name: Name for entity type (default: "Entity")
31
+ highlight_entities: Specific entities to highlight (default: None = auto-select)
32
+ max_entities: Maximum entities to show (default: 10)
33
+ figsize: Figure size (width, height)
34
+ title: Optional custom title
35
+ save_plot: Save plot to file
36
+ output_dir: Output directory for saved files
37
+ temporal_granularity: Time granularity for file naming
38
+
39
+ Returns:
40
+ Matplotlib figure
41
+
42
+ Examples:
43
+ >>> # auto-select top movers
44
+ >>> fig = plot_movement_trajectories(movement_df, entity_name="Service")
45
+
46
+ >>> # highlight specific entities
47
+ >>> fig = plot_movement_trajectories(
48
+ ... movement_df,
49
+ ... highlight_entities=["Service A", "Service B"],
50
+ ... max_entities=5
51
+ ... )
52
+ """
53
+ if movement_df.empty:
54
+ print("No movement data to visualize")
55
+ return None
56
+
57
+ # select entities to plot
58
+ if highlight_entities:
59
+ entities_to_plot = [
60
+ e for e in highlight_entities if e in movement_df["entity"].values
61
+ ]
62
+ else:
63
+ # select entities with largest movements
64
+ entity_movement = movement_df.groupby("entity").agg({
65
+ "x_delta": lambda x: abs(x).sum(),
66
+ "y_delta": lambda x: abs(x).sum(),
67
+ })
68
+ entity_movement["total_movement"] = (
69
+ entity_movement["x_delta"] + entity_movement["y_delta"]
70
+ )
71
+ top_movers = entity_movement.nlargest(max_entities, "total_movement")
72
+ entities_to_plot = top_movers.index.tolist()
73
+
74
+ # filter movement data
75
+ df_plot = movement_df[movement_df["entity"].isin(entities_to_plot)].copy()
76
+
77
+ if df_plot.empty:
78
+ print("No entities to plot")
79
+ return None
80
+
81
+ # create figure
82
+ fig, ax = plt.subplots(figsize=figsize)
83
+
84
+ # define colors for quadrants
85
+ colors = {
86
+ "Q1": "#c2104b", # red - crisis
87
+ "Q2": "#FF9636", # orange - investigate
88
+ "Q3": "#5cb85c", # green - monitor
89
+ "Q4": "#792f88", # purple - low priority
90
+ }
91
+
92
+ # plot trajectories for each entity
93
+ for entity in entities_to_plot:
94
+ entity_data = df_plot[df_plot["entity"] == entity].sort_values("quarter")
95
+
96
+ if len(entity_data) < 2:
97
+ continue
98
+
99
+ # get trajectory coordinates
100
+ x = entity_data["period_x"].values
101
+ y = entity_data["period_y"].values
102
+
103
+ # get color from global quadrant
104
+ global_quad = entity_data.iloc[0]["global_quadrant"]
105
+ color = colors.get(global_quad, "#95a5a6")
106
+
107
+ # plot trajectory line
108
+ ax.plot(x, y, color=color, alpha=0.5, linewidth=2, zorder=1)
109
+
110
+ # add arrows
111
+ for i in range(len(x) - 1):
112
+ dx = x[i + 1] - x[i]
113
+ dy = y[i + 1] - y[i]
114
+ ax.arrow(
115
+ x[i], y[i], dx * 0.9, dy * 0.9,
116
+ head_width=0.1,
117
+ head_length=0.1,
118
+ fc=color,
119
+ ec=color,
120
+ alpha=0.6,
121
+ zorder=2,
122
+ )
123
+
124
+ # mark start point (circle)
125
+ ax.scatter(
126
+ x[0], y[0],
127
+ s=150,
128
+ c=color,
129
+ marker='o',
130
+ edgecolors='black',
131
+ linewidth=2,
132
+ alpha=0.8,
133
+ zorder=3,
134
+ )
135
+
136
+ # mark end point (square)
137
+ ax.scatter(
138
+ x[-1], y[-1],
139
+ s=150,
140
+ c=color,
141
+ marker='s',
142
+ edgecolors='black',
143
+ linewidth=2,
144
+ alpha=0.8,
145
+ zorder=3,
146
+ )
147
+
148
+ # add entity label at end point
149
+ ax.annotate(
150
+ entity,
151
+ (x[-1], y[-1]),
152
+ xytext=(5, 5),
153
+ textcoords="offset points",
154
+ fontsize=10,
155
+ color=color,
156
+ fontweight='bold',
157
+ alpha=0.9,
158
+ )
159
+
160
+ # add quadrant dividers
161
+ ax.axhline(0, color='grey', linestyle='--', alpha=0.7, linewidth=1, zorder=0)
162
+ ax.axvline(0, color='grey', linestyle='--', alpha=0.7, linewidth=1, zorder=0)
163
+
164
+ # add quadrant labels
165
+ xlim = ax.get_xlim()
166
+ ylim = ax.get_ylim()
167
+
168
+ quadrant_labels = {
169
+ "Q1": ("Q1: Critical", (xlim[1] * 0.9, ylim[1] * 0.9)),
170
+ "Q2": ("Q2: Investigate", (xlim[0] * 0.9, ylim[1] * 0.9)),
171
+ "Q3": ("Q3: Monitor", (xlim[0] * 0.9, ylim[0] * 0.9)),
172
+ "Q4": ("Q4: Low Priority", (xlim[1] * 0.9, ylim[0] * 0.9)),
173
+ }
174
+
175
+ for label, (x_pos, y_pos) in quadrant_labels.values():
176
+ ax.text(
177
+ x_pos, y_pos,
178
+ label,
179
+ ha="center",
180
+ va="center",
181
+ fontsize=12,
182
+ color="gray",
183
+ alpha=0.3,
184
+ fontweight="bold",
185
+ zorder=0,
186
+ )
187
+
188
+ # set labels
189
+ ax.set_xlabel(f"{entity_name} Volume (Relative)", fontsize=13)
190
+ ax.set_ylabel(f"{entity_name} Growth Rate (Relative)", fontsize=13)
191
+
192
+ if title:
193
+ ax.set_title(title, fontsize=16, fontweight="bold", pad=20)
194
+ else:
195
+ ax.set_title(f"{entity_name} Movement Trajectories", fontsize=16,
196
+ fontweight="bold", pad=20)
197
+
198
+ # add legend for markers
199
+ from matplotlib.lines import Line2D
200
+ marker_legend = [
201
+ Line2D([0], [0], marker='o', color='w', markerfacecolor='gray',
202
+ markersize=10, label='Start', markeredgecolor='black', markeredgewidth=2),
203
+ Line2D([0], [0], marker='s', color='w', markerfacecolor='gray',
204
+ markersize=10, label='End', markeredgecolor='black', markeredgewidth=2),
205
+ ]
206
+ ax.legend(
207
+ handles=marker_legend,
208
+ loc='upper left',
209
+ frameon=False,
210
+ fontsize=10,
211
+ )
212
+
213
+ plt.tight_layout()
214
+
215
+ # save plot if requested
216
+ if save_plot:
217
+ import os
218
+ from datetime import datetime
219
+
220
+ os.makedirs(output_dir, exist_ok=True)
221
+ timestamp = datetime.now().strftime("%Y%m%d")
222
+ granularity_suffix = {
223
+ "quarterly": "Q",
224
+ "yearly": "Y",
225
+ "semiannual": "S",
226
+ }.get(temporal_granularity, "Q")
227
+ plot_path = f"{output_dir}/cumulative_movement-{entity_name.lower()}-{granularity_suffix}-{timestamp}.png"
228
+ plt.savefig(plot_path, dpi=300, bbox_inches="tight", format="png")
229
+ print(f"Movement plot saved: {plot_path}")
230
+
231
+ return fig
@@ -0,0 +1,73 @@
1
+ Metadata-Version: 2.4
2
+ Name: priorityx
3
+ Version: 0.1.2
4
+ Summary: Entity prioritization and escalation detection using GLMM statistical models
5
+ Project-URL: Homepage, https://github.com/okkymabruri/priorityx
6
+ Project-URL: Repository, https://github.com/okkymabruri/priorityx
7
+ Project-URL: Issues, https://github.com/okkymabruri/priorityx/issues
8
+ Author-email: Okky Mabruri <okkymbrur@gmail.com>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: escalation-detection,glmm,prioritization,risk-analysis,statistical-modeling
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Scientific/Engineering
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Requires-Python: >=3.9
23
+ Requires-Dist: adjusttext>=1.3.0
24
+ Requires-Dist: matplotlib>=3.9.4
25
+ Requires-Dist: pandas>=2.3.3
26
+ Requires-Dist: polars>=1.35.1
27
+ Requires-Dist: pyarrow>=21.0.0
28
+ Requires-Dist: statsmodels>=0.14.5
29
+ Description-Content-Type: text/markdown
30
+
31
+ # Priorityx: Entity prioritization and escalation detection using GLMM statistical models
32
+
33
+ ## Installation
34
+
35
+ ```bash
36
+ pip install priorityx
37
+ ```
38
+
39
+ ## Quick Start
40
+
41
+ ```python
42
+ import polars as pl
43
+ from priorityx.core.glmm import fit_priority_matrix
44
+ from priorityx.viz.matrix import plot_priority_matrix
45
+
46
+ df = pl.read_csv("data.csv")
47
+
48
+ results, stats = fit_priority_matrix(
49
+ df,
50
+ entity_col="service",
51
+ timestamp_col="date",
52
+ temporal_granularity="quarterly"
53
+ )
54
+
55
+ plot_priority_matrix(results, entity_name="Service", save_plot=True)
56
+ ```
57
+
58
+ ## Features
59
+
60
+ - GLMM-based priority classification (Q1-Q4 quadrants)
61
+ - Transition detection over time
62
+ - Movement tracking
63
+ - Visualization
64
+
65
+ ## Use Cases
66
+
67
+ IT incidents, software bugs, compliance violations, performance monitoring.
68
+
69
+ ## Documentation
70
+
71
+ - [Quick Start](docs/quickstart.md)
72
+ - [API Reference](docs/api-reference.md)
73
+ - [Methodology](docs/methodology.md)
@@ -0,0 +1,20 @@
1
+ priorityx/__init__.py,sha256=oaQkbWhGBsq0j9arjJdAF14BPe9Jm2dUEyDm3Sgnlko,169
2
+ priorityx/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ priorityx/core/filters.py,sha256=RH6bqep8sFIQ346s77Hm-vyJ3Z4lya5qRjXRUcAOXpU,7329
4
+ priorityx/core/glmm.py,sha256=x-qdCdz2Hp4C8FVGO_Or_CBh6n06h2bCFSVaGMyXhNY,13603
5
+ priorityx/core/quadrants.py,sha256=BuHxeD6k-_6GJkbvU59eoW81UzVi1YnMl6evLyf38ks,1910
6
+ priorityx/drivers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ priorityx/tracking/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ priorityx/tracking/drivers.py,sha256=f3-ia36uCFWn4yLDFAqi5re6STmJNXF15luBP1hwH1k,19045
9
+ priorityx/tracking/movement.py,sha256=bqFq0kJjuqxCNkyp1Vr9b2Ed62JVzxaSKOfV7u0iDD0,16580
10
+ priorityx/tracking/transitions.py,sha256=b6r8Bj8i1_N_iUomn-8K162i0k_xdlnNZV48uMKj1Iw,8668
11
+ priorityx/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ priorityx/utils/helpers.py,sha256=yA5mgCCv34MwLSec72PrX1PJY5jt8kN3oZVu6DHKhtQ,7380
13
+ priorityx/viz/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ priorityx/viz/matrix.py,sha256=s5WZ0UWirlau7CpQctVhTNVqd7DXvL5nr3ekZUmuXUs,10413
15
+ priorityx/viz/timeline.py,sha256=-KZ3VM5URRspQbP77HGeLfvV9aEzji8ar2EGN-FxDNo,11039
16
+ priorityx/viz/trajectory.py,sha256=EQ42W5XyFwq7LcCTiWSDZzdW4t5FiDXAWbHD2_K6-Ic,7218
17
+ priorityx-0.1.2.dist-info/METADATA,sha256=bEYIgPOuJWqOZe5XsdaQdro6kTozvA5zCltp5WCOsHg,2167
18
+ priorityx-0.1.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
19
+ priorityx-0.1.2.dist-info/licenses/LICENSE,sha256=653HZgD9wm-uBS8gPWzbTbA4BYPoApwTdRNK-0tbagw,1069
20
+ priorityx-0.1.2.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Okky Mabruri
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.