timelineviz 0.1.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.
- timelineviz-0.1.0/.gitignore +18 -0
- timelineviz-0.1.0/CHANGELOG.md +19 -0
- timelineviz-0.1.0/DEVELOPING.md +63 -0
- timelineviz-0.1.0/LICENSE +21 -0
- timelineviz-0.1.0/PKG-INFO +166 -0
- timelineviz-0.1.0/PROMTEST.md +265 -0
- timelineviz-0.1.0/README.md +130 -0
- timelineviz-0.1.0/examples/gen_charts.py +68 -0
- timelineviz-0.1.0/images/promtest_example_1.png +0 -0
- timelineviz-0.1.0/images/promtest_example_2.png +0 -0
- timelineviz-0.1.0/images/timeline1.png +0 -0
- timelineviz-0.1.0/pyproject.toml +80 -0
- timelineviz-0.1.0/src/timelineviz/__init__.py +65 -0
- timelineviz-0.1.0/src/timelineviz/_version.py +1 -0
- timelineviz-0.1.0/src/timelineviz/cli.py +305 -0
- timelineviz-0.1.0/src/timelineviz/promtest.py +650 -0
- timelineviz-0.1.0/src/timelineviz/py.typed +0 -0
- timelineviz-0.1.0/src/timelineviz/tests/__init__.py +1 -0
- timelineviz-0.1.0/src/timelineviz/tests/test_cli.py +517 -0
- timelineviz-0.1.0/src/timelineviz/tests/test_promtest.py +333 -0
- timelineviz-0.1.0/src/timelineviz/tests/test_timeline.py +657 -0
- timelineviz-0.1.0/src/timelineviz/tests/test_utils.py +377 -0
- timelineviz-0.1.0/src/timelineviz/timeline.py +497 -0
- timelineviz-0.1.0/src/timelineviz/utils.py +236 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2025-01-01
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Timeline visualisation from CSV / DataFrame timestamp data.
|
|
13
|
+
- Automatic timestamp column detection (columns ending `_utc`).
|
|
14
|
+
- Cluster detection for grouping related timestamps.
|
|
15
|
+
- Prometheus test file parser (`parse_promtest_file`, `parse_promtest_string`).
|
|
16
|
+
- `plot_promtest` step-chart visualiser with self-documenting annotations.
|
|
17
|
+
- `expand_values` helper for expanding Prometheus value notation.
|
|
18
|
+
- CLI entry point `timelineviz` with `--promtest` flag.
|
|
19
|
+
- 113 unit tests with >90 % coverage.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Development Guide
|
|
2
|
+
|
|
3
|
+
Setup, testing, and release instructions for `timelineviz`.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/garrywilliams/timeline_viz.git
|
|
9
|
+
cd timeline_viz
|
|
10
|
+
uv pip install -e ".[dev]"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Testing
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Run tests with coverage
|
|
17
|
+
pytest
|
|
18
|
+
|
|
19
|
+
# HTML coverage report
|
|
20
|
+
pytest --cov=timelineviz --cov-report=html
|
|
21
|
+
open htmlcov/index.html
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Coverage threshold is 90 % (enforced in `pyproject.toml`).
|
|
25
|
+
|
|
26
|
+
## Project Layout
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
src/timelineviz/
|
|
30
|
+
__init__.py # Public API re-exports
|
|
31
|
+
_version.py # Single source of truth for version
|
|
32
|
+
timeline.py # CSV/DataFrame visualisation
|
|
33
|
+
promtest.py # Prometheus test file parser + visualiser
|
|
34
|
+
utils.py # Shared helpers
|
|
35
|
+
cli.py # CLI entry point
|
|
36
|
+
py.typed # PEP 561 marker
|
|
37
|
+
tests/
|
|
38
|
+
test_timeline.py
|
|
39
|
+
test_promtest.py
|
|
40
|
+
test_utils.py
|
|
41
|
+
test_cli.py
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Building
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
uv build
|
|
48
|
+
# outputs dist/timelineviz-x.y.z-py3-none-any.whl
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Release Process
|
|
52
|
+
|
|
53
|
+
1. Bump version in `src/timelineviz/_version.py`
|
|
54
|
+
2. Update `CHANGELOG.md`
|
|
55
|
+
3. Commit, tag, push:
|
|
56
|
+
```bash
|
|
57
|
+
git tag v0.1.0
|
|
58
|
+
git push origin main --tags
|
|
59
|
+
```
|
|
60
|
+
4. Publish to PyPI:
|
|
61
|
+
```bash
|
|
62
|
+
uv publish
|
|
63
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Garry Williams
|
|
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,166 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: timelineviz
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Timeline visualisation for CSV data and Prometheus test files
|
|
5
|
+
Project-URL: Homepage, https://github.com/garrywilliams/timeline_viz
|
|
6
|
+
Project-URL: Source, https://github.com/garrywilliams/timeline_viz
|
|
7
|
+
Project-URL: Issues, https://github.com/garrywilliams/timeline_viz/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/garrywilliams/timeline_viz/blob/main/CHANGELOG.md
|
|
9
|
+
Author: Garry Williams
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: matplotlib,prometheus,promtool,timeline,visualisation
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.8
|
|
26
|
+
Requires-Dist: matplotlib>=3.4
|
|
27
|
+
Requires-Dist: numpy>=1.20
|
|
28
|
+
Requires-Dist: pandas>=1.3
|
|
29
|
+
Requires-Dist: python-dateutil>=2.8
|
|
30
|
+
Requires-Dist: pytz>=2021.1
|
|
31
|
+
Requires-Dist: pyyaml>=6.0
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# timelineviz
|
|
38
|
+
|
|
39
|
+
[](https://pypi.org/project/timelineviz/)
|
|
40
|
+
[](https://pypi.org/project/timelineviz/)
|
|
41
|
+
[](LICENSE)
|
|
42
|
+
|
|
43
|
+
Timeline visualisation for CSV data and Prometheus test files.
|
|
44
|
+
|
|
45
|
+

|
|
46
|
+
|
|
47
|
+
## Features
|
|
48
|
+
|
|
49
|
+
- Plot event timelines from CSV / DataFrame timestamp data
|
|
50
|
+
- Handle time gaps with broken timeline display
|
|
51
|
+
- Auto-detect timestamp columns based on naming patterns
|
|
52
|
+
- **Visualise Prometheus `promtool` unit-test files** — series values, eval checkpoints, and alert checks on a relative time axis
|
|
53
|
+
- Customisable colour schemes
|
|
54
|
+
- CLI and Python API
|
|
55
|
+
|
|
56
|
+
## Installation
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pip install timelineviz
|
|
60
|
+
|
|
61
|
+
# or with uv
|
|
62
|
+
uv add timelineviz
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
For development:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
git clone https://github.com/garrywilliams/timeline_viz.git
|
|
69
|
+
cd timeline_viz
|
|
70
|
+
uv pip install -e ".[dev]"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Quick Start
|
|
74
|
+
|
|
75
|
+
### CSV / DataFrame Timelines
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# Auto-detect timestamp columns
|
|
79
|
+
timelineviz data.csv --detect-timestamps --output-dir timelines
|
|
80
|
+
|
|
81
|
+
# Specify columns explicitly
|
|
82
|
+
timelineviz data.csv --timestamp-columns created_at updated_at completed_at
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from timelineviz import plot_timeline, plot_multiple_timelines
|
|
87
|
+
|
|
88
|
+
import pandas as pd
|
|
89
|
+
df = pd.read_csv("data.csv")
|
|
90
|
+
|
|
91
|
+
# Single entity
|
|
92
|
+
plot_timeline(df.iloc[0],
|
|
93
|
+
timestamp_columns=['created_at', 'updated_at', 'completed_at'],
|
|
94
|
+
entity_id="12345")
|
|
95
|
+
|
|
96
|
+
# Multiple entities
|
|
97
|
+
plot_multiple_timelines("data.csv",
|
|
98
|
+
timestamp_columns=['created_at', 'updated_at'],
|
|
99
|
+
id_column='entity_id',
|
|
100
|
+
output_dir="timeline_images")
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Prometheus Test Timelines
|
|
104
|
+
|
|
105
|
+
Visualise `promtool` unit-test YAML files — see series values change over time, where evaluations happen, and when alerts fire.
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
timelineviz my_rules_test.yml --promtest
|
|
109
|
+
timelineviz my_rules_test.yml --promtest --output-dir images --no-show
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from timelineviz import parse_promtest_file, plot_promtest
|
|
114
|
+
|
|
115
|
+
groups = parse_promtest_file("my_rules_test.yml")
|
|
116
|
+
plot_promtest(groups, output_file="promtest_timeline.png")
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+

|
|
120
|
+
|
|
121
|
+
Charts are self-documenting — each subplot shows the metric name and raw notation, value labels appear at transition points, eval/alert vertical lines are labelled, and a legend strip at the bottom explains all marker types.
|
|
122
|
+
|
|
123
|
+
> **Full guide:** [PROMTEST.md](PROMTEST.md) — notation reference, worked examples, and all parameters.
|
|
124
|
+
|
|
125
|
+
## How It Works
|
|
126
|
+
|
|
127
|
+
### CSV Timelines
|
|
128
|
+
|
|
129
|
+
Timestamps are plotted as labelled points along a horizontal axis. When time gaps exceed a threshold, the timeline is broken into segments with slash markers indicating the breaks.
|
|
130
|
+
|
|
131
|
+
### Promtest Timelines
|
|
132
|
+
|
|
133
|
+
Prometheus test files define metric series as values over discrete time steps (e.g. one value per minute). The library:
|
|
134
|
+
|
|
135
|
+
1. Parses the YAML and **expands the compact notation** (`1+2x5` → `1, 3, 5, 7, 9, 11`)
|
|
136
|
+
2. Plots each `input_series` as a **step chart** on its own subplot
|
|
137
|
+
3. Draws **vertical markers** at `eval_time` checkpoints
|
|
138
|
+
4. Shows **alert check points** with firing/pending status
|
|
139
|
+
5. Labels the x-axis with **relative time offsets** (`0s`, `1m`, `2m`, …)
|
|
140
|
+
|
|
141
|
+
## API Reference
|
|
142
|
+
|
|
143
|
+
### CSV Mode
|
|
144
|
+
|
|
145
|
+
| Parameter | Description |
|
|
146
|
+
|-----------|-------------|
|
|
147
|
+
| `timestamp_columns` | Columns containing timestamp data to visualise |
|
|
148
|
+
| `id_column` | Column that uniquely identifies each entity |
|
|
149
|
+
| `threshold_days` | Time gap (in days) that triggers a timeline break |
|
|
150
|
+
| `entity_name` | Type name for titles (e.g. "Patient", "Order") |
|
|
151
|
+
| `label_mappings` | Custom display names for timestamp columns |
|
|
152
|
+
| `color_scheme` | Dictionary of colour overrides |
|
|
153
|
+
|
|
154
|
+
### Promtest Mode
|
|
155
|
+
|
|
156
|
+
| Parameter | Description |
|
|
157
|
+
|-----------|-------------|
|
|
158
|
+
| `figsize` | Figure dimensions `(width, height)` in inches |
|
|
159
|
+
| `title` | Custom figure title |
|
|
160
|
+
| `color_scheme` | Override colours (see [PROMTEST.md](PROMTEST.md#colour-scheme)) |
|
|
161
|
+
| `output_file` | Save to PNG |
|
|
162
|
+
| `dpi` | Resolution (default 150) |
|
|
163
|
+
|
|
164
|
+
## License
|
|
165
|
+
|
|
166
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# Prometheus Test Visualisation
|
|
2
|
+
|
|
3
|
+
Visualise [promtool unit-test](https://prometheus.io/docs/prometheus/latest/configuration/unit_testing_rules/) YAML files as timeline charts — see how series values evolve, where evaluations happen, and when alerts fire.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
A promtool test file defines metric series as values over discrete time steps and then asserts the results of PromQL expressions or alerting rules at specific points. This module parses those files and produces a multi-panel chart:
|
|
8
|
+
|
|
9
|
+
- **One subplot per `input_series`** — step plot of metric values over relative time
|
|
10
|
+
- **Vertical dashed lines** at `eval_time` checkpoints (red for expression tests, dotted for alert checks)
|
|
11
|
+
- **Alert status markers** — diamonds for FIRING, circles for pending
|
|
12
|
+
- **Gap and stale indicators** — hollow squares for missing samples (`_`), × marks for `stale`
|
|
13
|
+
- **Relative x-axis** — labels like `0s`, `1m`, `2m` rather than real timestamps
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### CLI
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Display interactively
|
|
21
|
+
timelineviz my_rules_test.yml --promtest
|
|
22
|
+
|
|
23
|
+
# Save to file without displaying
|
|
24
|
+
timelineviz my_rules_test.yml --promtest --output-dir images --no-show
|
|
25
|
+
|
|
26
|
+
# Custom size and resolution
|
|
27
|
+
timelineviz my_rules_test.yml --promtest --figsize 18,10 --dpi 300
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Python API
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from timelineviz import parse_promtest_file, parse_promtest_string, plot_promtest
|
|
34
|
+
|
|
35
|
+
# From a file
|
|
36
|
+
groups = parse_promtest_file("my_rules_test.yml")
|
|
37
|
+
results = plot_promtest(groups, output_file="timeline.png")
|
|
38
|
+
|
|
39
|
+
# From a YAML string (handy in notebooks)
|
|
40
|
+
yaml_str = """
|
|
41
|
+
evaluation_interval: 1m
|
|
42
|
+
tests:
|
|
43
|
+
- interval: 1m
|
|
44
|
+
input_series:
|
|
45
|
+
- series: 'http_requests_total{method="GET"}'
|
|
46
|
+
values: '0+10x15'
|
|
47
|
+
promql_expr_test:
|
|
48
|
+
- expr: rate(http_requests_total[5m])
|
|
49
|
+
eval_time: 10m
|
|
50
|
+
exp_samples:
|
|
51
|
+
- labels: 'http_requests_total{method="GET"}'
|
|
52
|
+
value: 0.1666
|
|
53
|
+
"""
|
|
54
|
+
groups = parse_promtest_string(yaml_str)
|
|
55
|
+
plot_promtest(groups)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Jupyter Notebook
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from timelineviz import parse_promtest_string, plot_promtest
|
|
62
|
+
|
|
63
|
+
# plot_promtest returns a list of (figure, axes) tuples — one per test group
|
|
64
|
+
results = plot_promtest(groups, show_plot=False)
|
|
65
|
+
fig, axs = results[0]
|
|
66
|
+
fig # renders inline in Jupyter
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Promtool Notation Reference
|
|
70
|
+
|
|
71
|
+
This section summarises the promtool value notation so charts are easier to interpret.
|
|
72
|
+
|
|
73
|
+
### Durations
|
|
74
|
+
|
|
75
|
+
Used for `evaluation_interval`, `interval`, and `eval_time`:
|
|
76
|
+
|
|
77
|
+
| Example | Meaning |
|
|
78
|
+
|---------|---------|
|
|
79
|
+
| `1m` | 1 minute |
|
|
80
|
+
| `5m` | 5 minutes |
|
|
81
|
+
| `1h30m` | 1 hour 30 minutes |
|
|
82
|
+
| `2d` | 2 days |
|
|
83
|
+
| `500ms` | 500 milliseconds |
|
|
84
|
+
|
|
85
|
+
### Series Value Notation
|
|
86
|
+
|
|
87
|
+
Each space-separated token in a `values` string represents one or more time steps:
|
|
88
|
+
|
|
89
|
+
| Token | Expansion | Description |
|
|
90
|
+
|-------|-----------|-------------|
|
|
91
|
+
| `42` | `42` | Single sample |
|
|
92
|
+
| `1+2x3` | `1 3 5 7` | Start at 1, increment by 2, repeat 3 more times (4 total) |
|
|
93
|
+
| `10-3x2` | `10 7 4` | Start at 10, decrement by 3, repeat 2 more times (3 total) |
|
|
94
|
+
| `5x4` | `5 5 5 5 5` | Repeat 5 four more times (5 total) |
|
|
95
|
+
| `_` | *(missing)* | One missing/gap sample |
|
|
96
|
+
| `_x3` | *(missing × 3)* | Three consecutive missing samples |
|
|
97
|
+
| `stale` | *(stale)* | Stale marker |
|
|
98
|
+
|
|
99
|
+
Tokens can be combined freely:
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
values: '1+0x6 0+0x5'
|
|
103
|
+
# Expands to: 1 1 1 1 1 1 1 0 0 0 0 0 0
|
|
104
|
+
# ^^^^^^^^^^^^^^^ ^^^^^^^^^^^
|
|
105
|
+
# 7 ones 6 zeros
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### How Time Steps Map to the Chart
|
|
109
|
+
|
|
110
|
+
Given `interval: 1m` and `values: '0+1x4'`:
|
|
111
|
+
|
|
112
|
+
| Step | Time | Value |
|
|
113
|
+
|------|------|-------|
|
|
114
|
+
| 0 | 0m | 0 |
|
|
115
|
+
| 1 | 1m | 1 |
|
|
116
|
+
| 2 | 2m | 2 |
|
|
117
|
+
| 3 | 3m | 3 |
|
|
118
|
+
| 4 | 4m | 4 |
|
|
119
|
+
|
|
120
|
+
The chart plots these as a step function with dots at each sample.
|
|
121
|
+
|
|
122
|
+
## Worked Example
|
|
123
|
+
|
|
124
|
+
Given a test file for an `InstanceDown` alert:
|
|
125
|
+
|
|
126
|
+
```yaml
|
|
127
|
+
# rules_test.yml
|
|
128
|
+
evaluation_interval: 1m
|
|
129
|
+
|
|
130
|
+
tests:
|
|
131
|
+
- interval: 1m
|
|
132
|
+
input_series:
|
|
133
|
+
- series: 'up{job="api"}'
|
|
134
|
+
values: '1+0x14 0+0x5'
|
|
135
|
+
- series: 'up{job="web"}'
|
|
136
|
+
values: '1x19'
|
|
137
|
+
|
|
138
|
+
alert_rule_test:
|
|
139
|
+
- eval_time: 15m
|
|
140
|
+
alertname: InstanceDown
|
|
141
|
+
exp_alerts:
|
|
142
|
+
- exp_labels:
|
|
143
|
+
job: api
|
|
144
|
+
|
|
145
|
+
promql_expr_test:
|
|
146
|
+
- expr: up == 0
|
|
147
|
+
eval_time: 16m
|
|
148
|
+
exp_samples:
|
|
149
|
+
- labels: 'up{job="api"}'
|
|
150
|
+
value: 0
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from timelineviz import parse_promtest_file, plot_promtest
|
|
155
|
+
|
|
156
|
+
groups = parse_promtest_file("rules_test.yml")
|
|
157
|
+
plot_promtest(groups, title="InstanceDown Alert Test")
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
This produces:
|
|
161
|
+
|
|
162
|
+

|
|
163
|
+
|
|
164
|
+
**Reading the chart:**
|
|
165
|
+
|
|
166
|
+
1. **Top subplot** — `up{job="api"}`: value 1 for 0m–14m, drops to 0 at 15m. The raw notation `'1+0x14 0+0x5'` is shown in the italic subtitle below each series name.
|
|
167
|
+
2. **Middle subplot** — `up{job="web"}`: constant 1 across all 20 steps.
|
|
168
|
+
3. **Bottom row** (Alert Checks) — `InstanceDown` is marked FIRING at 15m with a red diamond and boxed label.
|
|
169
|
+
4. **Vertical markers** — dashed red line labelled `eval: up == 0 @ 16m` for the expression eval, dotted line for the alert check time.
|
|
170
|
+
5. **Value labels** appear above transition points (where the value changes) so you can read exact values without consulting a y-axis.
|
|
171
|
+
6. **Legend strip** at the bottom explains all marker types used in the chart.
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
## Multi-Series Example
|
|
175
|
+
|
|
176
|
+
A more complex example with gaps, stale markers, and multiple series:
|
|
177
|
+
|
|
178
|
+
```yaml
|
|
179
|
+
evaluation_interval: 1m
|
|
180
|
+
tests:
|
|
181
|
+
- interval: 1m
|
|
182
|
+
input_series:
|
|
183
|
+
- series: 'http_requests_total{method="GET"}'
|
|
184
|
+
values: '0+10x9'
|
|
185
|
+
- series: 'http_requests_total{method="POST"}'
|
|
186
|
+
values: '0+5x4 _ stale 30+5x2'
|
|
187
|
+
- series: 'error_rate'
|
|
188
|
+
values: '0x4 0.5+0.5x3 2x2'
|
|
189
|
+
promql_expr_test:
|
|
190
|
+
- expr: error_rate > 1
|
|
191
|
+
eval_time: 8m
|
|
192
|
+
exp_samples:
|
|
193
|
+
- labels: 'error_rate'
|
|
194
|
+
value: 2
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+

|
|
198
|
+
|
|
199
|
+
**Things to notice:**
|
|
200
|
+
|
|
201
|
+
- The POST series has a **missing sample** (hollow square at 5m) and a **stale marker** (× at 6m) before resuming at 30.
|
|
202
|
+
- The error_rate series shows a **gradual ramp** from 0 → 0.5 → 1.0 → 1.5 → 2.0 then holds at 2.
|
|
203
|
+
- The eval line at 8m checks `error_rate > 1` — at that point the value is indeed 2.
|
|
204
|
+
- Each subplot's italic subtitle shows the raw promtool notation, making it easy to cross-reference with your YAML test file.
|
|
205
|
+
|
|
206
|
+
## API Reference
|
|
207
|
+
|
|
208
|
+
### Parsing
|
|
209
|
+
|
|
210
|
+
| Function | Description |
|
|
211
|
+
|----------|-------------|
|
|
212
|
+
| `parse_promtest_file(path)` | Parse a YAML file, returns `list[PromTestGroup]` |
|
|
213
|
+
| `parse_promtest_string(yaml_string)` | Parse a YAML string, returns `list[PromTestGroup]` |
|
|
214
|
+
| `parse_duration(s)` | Parse a Prometheus duration (`'5m'`) → `timedelta` |
|
|
215
|
+
| `expand_values(notation)` | Expand series notation (`'1+2x3'`) → `[1.0, 3.0, 5.0, 7.0]` |
|
|
216
|
+
|
|
217
|
+
### Data Model
|
|
218
|
+
|
|
219
|
+
| Class | Key Fields |
|
|
220
|
+
|-------|------------|
|
|
221
|
+
| `PromTestGroup` | `interval`, `series`, `eval_points`, `alert_checks`, `name` |
|
|
222
|
+
| `SeriesData` | `metric`, `labels`, `values`, `interval`, `raw_values`, `display_name`, `time_offsets` |
|
|
223
|
+
| `EvalPoint` | `expr`, `eval_time`, `expected_results` |
|
|
224
|
+
| `AlertCheck` | `alertname`, `eval_time`, `exp_alerts` |
|
|
225
|
+
|
|
226
|
+
### Visualisation
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
plot_promtest(
|
|
230
|
+
groups, # list[PromTestGroup]
|
|
231
|
+
figsize=None, # (width, height) or auto-sized
|
|
232
|
+
show_plot=True, # display interactively
|
|
233
|
+
output_file=None, # save PNG path
|
|
234
|
+
dpi=150, # resolution
|
|
235
|
+
title=None, # custom figure title
|
|
236
|
+
color_scheme=None, # override PROMTEST_COLOR_SCHEME keys
|
|
237
|
+
)
|
|
238
|
+
# Returns list[(matplotlib.Figure, list[matplotlib.Axes])]
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Colour Scheme
|
|
242
|
+
|
|
243
|
+
Override any of these keys via the `color_scheme` parameter:
|
|
244
|
+
|
|
245
|
+
```python
|
|
246
|
+
{
|
|
247
|
+
'series_colors': ['#0046be', '#e6194b', '#3cb44b', '#f58231',
|
|
248
|
+
'#911eb4', '#42d4f4', '#f032e6', '#bfef45'],
|
|
249
|
+
'eval_line': '#e6194b', # eval_time vertical lines
|
|
250
|
+
'alert_pending': '#ffc107', # pending alert markers
|
|
251
|
+
'alert_firing': '#dc3545', # firing alert markers
|
|
252
|
+
'grid': '#e0e0e0',
|
|
253
|
+
'background': '#fafafa',
|
|
254
|
+
'text': '#333333',
|
|
255
|
+
'stale_marker': '#999999', # × marks for stale samples
|
|
256
|
+
'missing_marker': '#cccccc', # □ marks for missing samples
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Limitations
|
|
261
|
+
|
|
262
|
+
- **No PromQL evaluation** — the chart shows raw input series and where checks happen, but does not compute derived expressions like `rate()` or `avg()`.
|
|
263
|
+
- **Alert state transitions are not computed** — we show whether `exp_alerts` is populated (FIRING) or empty (pending) at each `eval_time`, but we don't simulate the `for` duration logic.
|
|
264
|
+
- **Native histogram notation** is not yet supported — histogram-valued series will raise a parse error.
|
|
265
|
+
- **One figure per test group** — if your YAML has several `tests:` entries, each gets a separate figure.
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# timelineviz
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/timelineviz/)
|
|
4
|
+
[](https://pypi.org/project/timelineviz/)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
Timeline visualisation for CSV data and Prometheus test files.
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- Plot event timelines from CSV / DataFrame timestamp data
|
|
14
|
+
- Handle time gaps with broken timeline display
|
|
15
|
+
- Auto-detect timestamp columns based on naming patterns
|
|
16
|
+
- **Visualise Prometheus `promtool` unit-test files** — series values, eval checkpoints, and alert checks on a relative time axis
|
|
17
|
+
- Customisable colour schemes
|
|
18
|
+
- CLI and Python API
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install timelineviz
|
|
24
|
+
|
|
25
|
+
# or with uv
|
|
26
|
+
uv add timelineviz
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
For development:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
git clone https://github.com/garrywilliams/timeline_viz.git
|
|
33
|
+
cd timeline_viz
|
|
34
|
+
uv pip install -e ".[dev]"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
### CSV / DataFrame Timelines
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Auto-detect timestamp columns
|
|
43
|
+
timelineviz data.csv --detect-timestamps --output-dir timelines
|
|
44
|
+
|
|
45
|
+
# Specify columns explicitly
|
|
46
|
+
timelineviz data.csv --timestamp-columns created_at updated_at completed_at
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from timelineviz import plot_timeline, plot_multiple_timelines
|
|
51
|
+
|
|
52
|
+
import pandas as pd
|
|
53
|
+
df = pd.read_csv("data.csv")
|
|
54
|
+
|
|
55
|
+
# Single entity
|
|
56
|
+
plot_timeline(df.iloc[0],
|
|
57
|
+
timestamp_columns=['created_at', 'updated_at', 'completed_at'],
|
|
58
|
+
entity_id="12345")
|
|
59
|
+
|
|
60
|
+
# Multiple entities
|
|
61
|
+
plot_multiple_timelines("data.csv",
|
|
62
|
+
timestamp_columns=['created_at', 'updated_at'],
|
|
63
|
+
id_column='entity_id',
|
|
64
|
+
output_dir="timeline_images")
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Prometheus Test Timelines
|
|
68
|
+
|
|
69
|
+
Visualise `promtool` unit-test YAML files — see series values change over time, where evaluations happen, and when alerts fire.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
timelineviz my_rules_test.yml --promtest
|
|
73
|
+
timelineviz my_rules_test.yml --promtest --output-dir images --no-show
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from timelineviz import parse_promtest_file, plot_promtest
|
|
78
|
+
|
|
79
|
+
groups = parse_promtest_file("my_rules_test.yml")
|
|
80
|
+
plot_promtest(groups, output_file="promtest_timeline.png")
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+

|
|
84
|
+
|
|
85
|
+
Charts are self-documenting — each subplot shows the metric name and raw notation, value labels appear at transition points, eval/alert vertical lines are labelled, and a legend strip at the bottom explains all marker types.
|
|
86
|
+
|
|
87
|
+
> **Full guide:** [PROMTEST.md](PROMTEST.md) — notation reference, worked examples, and all parameters.
|
|
88
|
+
|
|
89
|
+
## How It Works
|
|
90
|
+
|
|
91
|
+
### CSV Timelines
|
|
92
|
+
|
|
93
|
+
Timestamps are plotted as labelled points along a horizontal axis. When time gaps exceed a threshold, the timeline is broken into segments with slash markers indicating the breaks.
|
|
94
|
+
|
|
95
|
+
### Promtest Timelines
|
|
96
|
+
|
|
97
|
+
Prometheus test files define metric series as values over discrete time steps (e.g. one value per minute). The library:
|
|
98
|
+
|
|
99
|
+
1. Parses the YAML and **expands the compact notation** (`1+2x5` → `1, 3, 5, 7, 9, 11`)
|
|
100
|
+
2. Plots each `input_series` as a **step chart** on its own subplot
|
|
101
|
+
3. Draws **vertical markers** at `eval_time` checkpoints
|
|
102
|
+
4. Shows **alert check points** with firing/pending status
|
|
103
|
+
5. Labels the x-axis with **relative time offsets** (`0s`, `1m`, `2m`, …)
|
|
104
|
+
|
|
105
|
+
## API Reference
|
|
106
|
+
|
|
107
|
+
### CSV Mode
|
|
108
|
+
|
|
109
|
+
| Parameter | Description |
|
|
110
|
+
|-----------|-------------|
|
|
111
|
+
| `timestamp_columns` | Columns containing timestamp data to visualise |
|
|
112
|
+
| `id_column` | Column that uniquely identifies each entity |
|
|
113
|
+
| `threshold_days` | Time gap (in days) that triggers a timeline break |
|
|
114
|
+
| `entity_name` | Type name for titles (e.g. "Patient", "Order") |
|
|
115
|
+
| `label_mappings` | Custom display names for timestamp columns |
|
|
116
|
+
| `color_scheme` | Dictionary of colour overrides |
|
|
117
|
+
|
|
118
|
+
### Promtest Mode
|
|
119
|
+
|
|
120
|
+
| Parameter | Description |
|
|
121
|
+
|-----------|-------------|
|
|
122
|
+
| `figsize` | Figure dimensions `(width, height)` in inches |
|
|
123
|
+
| `title` | Custom figure title |
|
|
124
|
+
| `color_scheme` | Override colours (see [PROMTEST.md](PROMTEST.md#colour-scheme)) |
|
|
125
|
+
| `output_file` | Save to PNG |
|
|
126
|
+
| `dpi` | Resolution (default 150) |
|
|
127
|
+
|
|
128
|
+
## License
|
|
129
|
+
|
|
130
|
+
[MIT](LICENSE)
|