anytimeline 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.
- anytimeline-0.1.0/.gitignore +29 -0
- anytimeline-0.1.0/CHANGELOG.md +34 -0
- anytimeline-0.1.0/LICENSE +21 -0
- anytimeline-0.1.0/PKG-INFO +144 -0
- anytimeline-0.1.0/README.md +110 -0
- anytimeline-0.1.0/js/package-lock.json +2053 -0
- anytimeline-0.1.0/js/package.json +23 -0
- anytimeline-0.1.0/js/playwright.config.ts +42 -0
- anytimeline-0.1.0/js/src/core/bars.ts +402 -0
- anytimeline-0.1.0/js/src/core/camera.ts +93 -0
- anytimeline-0.1.0/js/src/core/dodge.ts +55 -0
- anytimeline-0.1.0/js/src/core/help.ts +117 -0
- anytimeline-0.1.0/js/src/core/icons.ts +36 -0
- anytimeline-0.1.0/js/src/core/legend.ts +143 -0
- anytimeline-0.1.0/js/src/core/link.ts +96 -0
- anytimeline-0.1.0/js/src/core/renderers/canvas2d.ts +182 -0
- anytimeline-0.1.0/js/src/core/renderers/renderer.ts +134 -0
- anytimeline-0.1.0/js/src/core/renderers/select.ts +39 -0
- anytimeline-0.1.0/js/src/core/renderers/symbols.ts +112 -0
- anytimeline-0.1.0/js/src/core/renderers/webgl2.ts +470 -0
- anytimeline-0.1.0/js/src/core/renderers/webgpu.ts +477 -0
- anytimeline-0.1.0/js/src/core/scene.ts +154 -0
- anytimeline-0.1.0/js/src/core/snapshot.ts +107 -0
- anytimeline-0.1.0/js/src/core/time.ts +422 -0
- anytimeline-0.1.0/js/src/core/toolbar.ts +205 -0
- anytimeline-0.1.0/js/src/core/transport.ts +193 -0
- anytimeline-0.1.0/js/src/core/types.ts +169 -0
- anytimeline-0.1.0/js/src/core/values.ts +294 -0
- anytimeline-0.1.0/js/src/core/view.ts +2478 -0
- anytimeline-0.1.0/js/src/standalone.ts +111 -0
- anytimeline-0.1.0/js/src/widget.css +390 -0
- anytimeline-0.1.0/js/src/widget.ts +222 -0
- anytimeline-0.1.0/js/test/core.test.ts +180 -0
- anytimeline-0.1.0/js/tsconfig.json +17 -0
- anytimeline-0.1.0/js/vitest.config.ts +4 -0
- anytimeline-0.1.0/pyproject.toml +126 -0
- anytimeline-0.1.0/src/anytimeline/__init__.py +12 -0
- anytimeline-0.1.0/src/anytimeline/codec.py +98 -0
- anytimeline-0.1.0/src/anytimeline/data.py +120 -0
- anytimeline-0.1.0/src/anytimeline/events.py +336 -0
- anytimeline-0.1.0/src/anytimeline/grouping.py +258 -0
- anytimeline-0.1.0/src/anytimeline/intervals.py +427 -0
- anytimeline-0.1.0/src/anytimeline/lanes.py +67 -0
- anytimeline-0.1.0/src/anytimeline/otel.py +200 -0
- anytimeline-0.1.0/src/anytimeline/presets.py +79 -0
- anytimeline-0.1.0/src/anytimeline/states.py +169 -0
- anytimeline-0.1.0/src/anytimeline/static/standalone.js +407 -0
- anytimeline-0.1.0/src/anytimeline/static/widget.css +1 -0
- anytimeline-0.1.0/src/anytimeline/static/widget.js +407 -0
- anytimeline-0.1.0/src/anytimeline/styling.py +306 -0
- anytimeline-0.1.0/src/anytimeline/synthetic.py +397 -0
- anytimeline-0.1.0/src/anytimeline/timebase.py +243 -0
- anytimeline-0.1.0/src/anytimeline/tree.py +171 -0
- anytimeline-0.1.0/src/anytimeline/values.py +240 -0
- anytimeline-0.1.0/src/anytimeline/widget.py +1249 -0
- anytimeline-0.1.0/tests/test_events.py +164 -0
- anytimeline-0.1.0/tests/test_groups.py +118 -0
- anytimeline-0.1.0/tests/test_intervals.py +144 -0
- anytimeline-0.1.0/tests/test_linked.py +45 -0
- anytimeline-0.1.0/tests/test_spans.py +258 -0
- anytimeline-0.1.0/tests/test_states_values.py +136 -0
- anytimeline-0.1.0/tests/test_timebase.py +90 -0
- anytimeline-0.1.0/tests/test_widget.py +167 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
.venv/
|
|
4
|
+
.venv-*/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
*.egg-info/
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
.ruff_cache/
|
|
10
|
+
node_modules/
|
|
11
|
+
.DS_Store
|
|
12
|
+
.ipynb_checkpoints/
|
|
13
|
+
__marimo__/
|
|
14
|
+
|
|
15
|
+
# built JavaScript bundle (npm run build in js/)
|
|
16
|
+
src/anytimeline/static/
|
|
17
|
+
|
|
18
|
+
# visual tests (Playwright)
|
|
19
|
+
js/test/visual/dist/
|
|
20
|
+
js/test/visual/scenes/
|
|
21
|
+
js/test-results/
|
|
22
|
+
js/playwright-report/
|
|
23
|
+
|
|
24
|
+
# personal experiments (notebooks, scripts); not part of the project
|
|
25
|
+
_scratch/
|
|
26
|
+
|
|
27
|
+
# user documentation: the built site, and the plot bundle copied in by scripts/build_docs.py
|
|
28
|
+
site/
|
|
29
|
+
docs/user/assets/anytimeline/
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to anytimeline. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions follow
|
|
5
|
+
[Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-10-11
|
|
8
|
+
|
|
9
|
+
The first release: interactive timeline charts for Jupyter, VS Code and marimo notebooks,
|
|
10
|
+
drawn with WebGPU, WebGL2 or Canvas 2D.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Event charts** (`Timeline.events`): a mark per event on lanes, coloured, shaped and sized
|
|
15
|
+
by columns; overlapping events spread out; routes join the events of a group; labels and
|
|
16
|
+
tooltips. Time can be datetimes in any time zone and century, durations from nanoseconds,
|
|
17
|
+
or plain numbers; the **Order** scale spaces events by the order they happened in.
|
|
18
|
+
- **Intervals and Gantt charts** (`Timeline.intervals`, `gantt`): bars from a start to an end,
|
|
19
|
+
packed per lane, with milestones, open bars, progress, dependency arrows and markers.
|
|
20
|
+
- **Traces** (`Timeline.spans`, `anytimeline.otel.read_otlp`): spans as a waterfall that folds,
|
|
21
|
+
with each span's duration and the critical path; OpenTelemetry OTLP/JSON reader.
|
|
22
|
+
- **States and values** (`Timeline.states`, `Timeline.values`): what state a lane was in, and
|
|
23
|
+
a number over time as a line, area or steps behind the events.
|
|
24
|
+
- **Groups** (`group=` on every layer): hosts, days or runs as groups of lanes in one plot;
|
|
25
|
+
`Timeline(align="start")` compares groups from their start.
|
|
26
|
+
- **Linked plots** (`Timeline.link`): separate plots that zoom and pan together.
|
|
27
|
+
- **Sharing**: `save_html` (one file that works without Python), Save as PNG in the toolbar
|
|
28
|
+
and `Timeline.save_png`.
|
|
29
|
+
- Toolbar with Pan, Zoom and Select tools, Time / Order, Back and Home, legend, text size and
|
|
30
|
+
full screen; selections come back to Python as rows of your tables; light and dark themes
|
|
31
|
+
that follow the notebook.
|
|
32
|
+
- Synthetic example data (`anytimeline.synthetic`) and documentation with live examples.
|
|
33
|
+
|
|
34
|
+
[0.1.0]: https://github.com/mluttikh/anytimeline/releases/tag/v0.1.0
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 mluttikh
|
|
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,144 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: anytimeline
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: GPU-accelerated timeline and event charts for notebooks
|
|
5
|
+
Project-URL: Homepage, https://github.com/mluttikh/anytimeline
|
|
6
|
+
Project-URL: Documentation, https://mluttikh.github.io/anytimeline/
|
|
7
|
+
Project-URL: Repository, https://github.com/mluttikh/anytimeline
|
|
8
|
+
Project-URL: Issues, https://github.com/mluttikh/anytimeline/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/mluttikh/anytimeline/blob/main/CHANGELOG.md
|
|
10
|
+
Author-email: mluttikh <mluttikhof@gmail.com>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: anywidget,event chart,gantt,jupyter,marimo,opentelemetry,timeline,traces,visualization,webgpu
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Framework :: Jupyter
|
|
16
|
+
Classifier: Framework :: Jupyter :: JupyterLab
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: Intended Audience :: Science/Research
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
25
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
26
|
+
Classifier: Topic :: System :: Monitoring
|
|
27
|
+
Requires-Python: >=3.12
|
|
28
|
+
Requires-Dist: anywidget>=0.9.13
|
|
29
|
+
Requires-Dist: ipywidgets>=8
|
|
30
|
+
Requires-Dist: narwhals>=1.30
|
|
31
|
+
Requires-Dist: numpy>=1.24
|
|
32
|
+
Requires-Dist: traitlets>=5.9
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# anytimeline
|
|
36
|
+
|
|
37
|
+
Interactive timeline and event charts for Jupyter and marimo notebooks, drawn on the GPU
|
|
38
|
+
(WebGPU, WebGL2, or Canvas 2D on machines without a usable GPU).
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install anytimeline
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Documentation: <https://mluttikh.github.io/anytimeline/> · Changelog:
|
|
45
|
+
[CHANGELOG.md](CHANGELOG.md) · Licence: MIT.
|
|
46
|
+
|
|
47
|
+
Status: version 0.1. It draws **event charts**: one mark per event at the moment it
|
|
48
|
+
happened, on lanes, so the order of what happened is easy to see. Time can be datetimes (any
|
|
49
|
+
time zone, any century), durations from nanoseconds up, or plain numbers; a Time | Order switch
|
|
50
|
+
spaces events by rank instead of time. Up to about a million events. It also draws **Gantt
|
|
51
|
+
charts** and schedules: bars from a start to an end, with dependencies, progress and
|
|
52
|
+
milestones, and overlapping bars stacked per lane; and **traces**: spans under spans.
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from anytimeline import Timeline
|
|
56
|
+
from anytimeline.synthetic import service_log
|
|
57
|
+
|
|
58
|
+
log = service_log() # a dict of columns; any Polars, pandas or PyArrow table works too
|
|
59
|
+
tl = Timeline()
|
|
60
|
+
tl.events(
|
|
61
|
+
log,
|
|
62
|
+
time="time",
|
|
63
|
+
lane="service",
|
|
64
|
+
color="level",
|
|
65
|
+
symbol="event",
|
|
66
|
+
route="request",
|
|
67
|
+
order="seq",
|
|
68
|
+
tooltip=["request", "user", "bytes"],
|
|
69
|
+
)
|
|
70
|
+
tl # click it, then scroll to zoom time; drag to pan; the toolbar has Zoom and Select
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
A Gantt chart from a table with a row per task:
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from anytimeline import gantt
|
|
77
|
+
|
|
78
|
+
gantt(plan, task="task", start="start", end="end", depends="after", progress="done",
|
|
79
|
+
color="phase", today="2026-10-12")
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Bars on other lanes (machines, people, services) come from `Timeline.intervals(...)`, and mix
|
|
83
|
+
with events on the same lanes.
|
|
84
|
+
|
|
85
|
+
Traces (OpenTelemetry, or any table of spans with a parent) plot as a waterfall that folds,
|
|
86
|
+
with each span's duration and the critical path:
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from anytimeline import Timeline
|
|
90
|
+
from anytimeline.otel import read_otlp
|
|
91
|
+
|
|
92
|
+
tr = read_otlp("traces.jsonl") # or anytimeline.synthetic.traces()
|
|
93
|
+
Timeline().spans(tr.spans, color="service").events(tr.events, time="time", lane="span_id")
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The toolbar has three tools: **Pan** (drag moves through time and lanes), **Zoom** (drag a
|
|
97
|
+
time range to show it) and **Select** (drag a box, or click an event; the selection is rows of
|
|
98
|
+
your table in `tl.selection`). Time and Order switch the scale; Aa sets the text size (also `Timeline(font_size=14)`).
|
|
99
|
+
Press `?` in the plot for every mouse gesture and key; `f` or
|
|
100
|
+
the button shows it full screen, where lanes fill the screen and overlapping events spread
|
|
101
|
+
out.
|
|
102
|
+
|
|
103
|
+
States (`Timeline.states`: up, degraded, down per lane) and values (`Timeline.values`: a
|
|
104
|
+
number over time, as a line, area or steps) go on the same lanes, behind the events.
|
|
105
|
+
|
|
106
|
+
`group="host"` on a layer puts each host's lanes under a header of their own, in one plot
|
|
107
|
+
(`Timeline(align="start")` compares groups from their start); separate plots link with
|
|
108
|
+
`a.link(b)` and zoom and pan together.
|
|
109
|
+
|
|
110
|
+
`plot.save_html("plot.html")` writes the plot to one file that opens in any browser, still
|
|
111
|
+
interactive; the toolbar saves it as a PNG, and so does `plot.save_png("plot.png")`.
|
|
112
|
+
|
|
113
|
+
Documentation online: <https://mluttikh.github.io/anytimeline/>; or build it with
|
|
114
|
+
`uv run python scripts/build_docs.py` and open `site/index.html`. Example notebook: [`examples/event_charts.ipynb`](examples/event_charts.ipynb). How the code
|
|
115
|
+
is built: [`docs/architecture.md`](docs/architecture.md).
|
|
116
|
+
|
|
117
|
+
## Development
|
|
118
|
+
|
|
119
|
+
Needs Python (via [uv](https://docs.astral.sh/uv/)) and Node.js 20+ for the JavaScript bundle.
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
(cd js && npm ci && npm run build) # build src/anytimeline/static/widget.js
|
|
123
|
+
uv sync # create .venv with dev tools
|
|
124
|
+
uv run pytest # Python tests
|
|
125
|
+
(cd js && npm run typecheck && npm test)
|
|
126
|
+
uv run ruff check . && uv run ruff format --check . && uv run ty check
|
|
127
|
+
uv run python scripts/make_scenes.py # scenes for the visual tests
|
|
128
|
+
(cd js && npx playwright install chromium && npm run test:visual) # every scene × backend, marimo
|
|
129
|
+
uv run nbstripout --install # once per clone: commit notebooks without outputs
|
|
130
|
+
uv run python scripts/build_docs.py # user documentation into site/ (examples run; warnings fail)
|
|
131
|
+
uv run python scripts/build_docs.py serve # preview it at http://localhost:8000
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
The user documentation is in `docs/user/`, built with [Zensical](https://zensical.org) and
|
|
135
|
+
organised as tutorials, how-to guides, reference and explanation. Its examples are
|
|
136
|
+
```` ```python exec="on" ```` blocks that run while building, and its plots are live: each
|
|
137
|
+
example prints `plot._embed_html()`, which `standalone.js` draws in the page. The API
|
|
138
|
+
reference comes from the docstrings (Google style). The browser tests check the built site
|
|
139
|
+
too (`docs.spec.ts`, skipped until it is built).
|
|
140
|
+
|
|
141
|
+
Visual tests draw the scenes in `js/test/visual/scenes/` with each backend and compare them
|
|
142
|
+
with stored screenshots (macOS); `npm run test:visual:update` stores new ones after an
|
|
143
|
+
intended change. `PERF=1 npx playwright test perf` measures a million events (after
|
|
144
|
+
`uv run python scripts/make_scenes.py --million`).
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# anytimeline
|
|
2
|
+
|
|
3
|
+
Interactive timeline and event charts for Jupyter and marimo notebooks, drawn on the GPU
|
|
4
|
+
(WebGPU, WebGL2, or Canvas 2D on machines without a usable GPU).
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
pip install anytimeline
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Documentation: <https://mluttikh.github.io/anytimeline/> · Changelog:
|
|
11
|
+
[CHANGELOG.md](CHANGELOG.md) · Licence: MIT.
|
|
12
|
+
|
|
13
|
+
Status: version 0.1. It draws **event charts**: one mark per event at the moment it
|
|
14
|
+
happened, on lanes, so the order of what happened is easy to see. Time can be datetimes (any
|
|
15
|
+
time zone, any century), durations from nanoseconds up, or plain numbers; a Time | Order switch
|
|
16
|
+
spaces events by rank instead of time. Up to about a million events. It also draws **Gantt
|
|
17
|
+
charts** and schedules: bars from a start to an end, with dependencies, progress and
|
|
18
|
+
milestones, and overlapping bars stacked per lane; and **traces**: spans under spans.
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
from anytimeline import Timeline
|
|
22
|
+
from anytimeline.synthetic import service_log
|
|
23
|
+
|
|
24
|
+
log = service_log() # a dict of columns; any Polars, pandas or PyArrow table works too
|
|
25
|
+
tl = Timeline()
|
|
26
|
+
tl.events(
|
|
27
|
+
log,
|
|
28
|
+
time="time",
|
|
29
|
+
lane="service",
|
|
30
|
+
color="level",
|
|
31
|
+
symbol="event",
|
|
32
|
+
route="request",
|
|
33
|
+
order="seq",
|
|
34
|
+
tooltip=["request", "user", "bytes"],
|
|
35
|
+
)
|
|
36
|
+
tl # click it, then scroll to zoom time; drag to pan; the toolbar has Zoom and Select
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
A Gantt chart from a table with a row per task:
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from anytimeline import gantt
|
|
43
|
+
|
|
44
|
+
gantt(plan, task="task", start="start", end="end", depends="after", progress="done",
|
|
45
|
+
color="phase", today="2026-10-12")
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Bars on other lanes (machines, people, services) come from `Timeline.intervals(...)`, and mix
|
|
49
|
+
with events on the same lanes.
|
|
50
|
+
|
|
51
|
+
Traces (OpenTelemetry, or any table of spans with a parent) plot as a waterfall that folds,
|
|
52
|
+
with each span's duration and the critical path:
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from anytimeline import Timeline
|
|
56
|
+
from anytimeline.otel import read_otlp
|
|
57
|
+
|
|
58
|
+
tr = read_otlp("traces.jsonl") # or anytimeline.synthetic.traces()
|
|
59
|
+
Timeline().spans(tr.spans, color="service").events(tr.events, time="time", lane="span_id")
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The toolbar has three tools: **Pan** (drag moves through time and lanes), **Zoom** (drag a
|
|
63
|
+
time range to show it) and **Select** (drag a box, or click an event; the selection is rows of
|
|
64
|
+
your table in `tl.selection`). Time and Order switch the scale; Aa sets the text size (also `Timeline(font_size=14)`).
|
|
65
|
+
Press `?` in the plot for every mouse gesture and key; `f` or
|
|
66
|
+
the button shows it full screen, where lanes fill the screen and overlapping events spread
|
|
67
|
+
out.
|
|
68
|
+
|
|
69
|
+
States (`Timeline.states`: up, degraded, down per lane) and values (`Timeline.values`: a
|
|
70
|
+
number over time, as a line, area or steps) go on the same lanes, behind the events.
|
|
71
|
+
|
|
72
|
+
`group="host"` on a layer puts each host's lanes under a header of their own, in one plot
|
|
73
|
+
(`Timeline(align="start")` compares groups from their start); separate plots link with
|
|
74
|
+
`a.link(b)` and zoom and pan together.
|
|
75
|
+
|
|
76
|
+
`plot.save_html("plot.html")` writes the plot to one file that opens in any browser, still
|
|
77
|
+
interactive; the toolbar saves it as a PNG, and so does `plot.save_png("plot.png")`.
|
|
78
|
+
|
|
79
|
+
Documentation online: <https://mluttikh.github.io/anytimeline/>; or build it with
|
|
80
|
+
`uv run python scripts/build_docs.py` and open `site/index.html`. Example notebook: [`examples/event_charts.ipynb`](examples/event_charts.ipynb). How the code
|
|
81
|
+
is built: [`docs/architecture.md`](docs/architecture.md).
|
|
82
|
+
|
|
83
|
+
## Development
|
|
84
|
+
|
|
85
|
+
Needs Python (via [uv](https://docs.astral.sh/uv/)) and Node.js 20+ for the JavaScript bundle.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
(cd js && npm ci && npm run build) # build src/anytimeline/static/widget.js
|
|
89
|
+
uv sync # create .venv with dev tools
|
|
90
|
+
uv run pytest # Python tests
|
|
91
|
+
(cd js && npm run typecheck && npm test)
|
|
92
|
+
uv run ruff check . && uv run ruff format --check . && uv run ty check
|
|
93
|
+
uv run python scripts/make_scenes.py # scenes for the visual tests
|
|
94
|
+
(cd js && npx playwright install chromium && npm run test:visual) # every scene × backend, marimo
|
|
95
|
+
uv run nbstripout --install # once per clone: commit notebooks without outputs
|
|
96
|
+
uv run python scripts/build_docs.py # user documentation into site/ (examples run; warnings fail)
|
|
97
|
+
uv run python scripts/build_docs.py serve # preview it at http://localhost:8000
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The user documentation is in `docs/user/`, built with [Zensical](https://zensical.org) and
|
|
101
|
+
organised as tutorials, how-to guides, reference and explanation. Its examples are
|
|
102
|
+
```` ```python exec="on" ```` blocks that run while building, and its plots are live: each
|
|
103
|
+
example prints `plot._embed_html()`, which `standalone.js` draws in the page. The API
|
|
104
|
+
reference comes from the docstrings (Google style). The browser tests check the built site
|
|
105
|
+
too (`docs.spec.ts`, skipped until it is built).
|
|
106
|
+
|
|
107
|
+
Visual tests draw the scenes in `js/test/visual/scenes/` with each backend and compare them
|
|
108
|
+
with stored screenshots (macOS); `npm run test:visual:update` stores new ones after an
|
|
109
|
+
intended change. `PERF=1 npx playwright test perf` measures a million events (after
|
|
110
|
+
`uv run python scripts/make_scenes.py --million`).
|