terminalboard 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.
- terminalboard-0.1.0/LICENSE +21 -0
- terminalboard-0.1.0/PKG-INFO +249 -0
- terminalboard-0.1.0/README.md +228 -0
- terminalboard-0.1.0/pyproject.toml +37 -0
- terminalboard-0.1.0/setup.cfg +4 -0
- terminalboard-0.1.0/terminalboard/__init__.py +9 -0
- terminalboard-0.1.0/terminalboard/__main__.py +4 -0
- terminalboard-0.1.0/terminalboard/app.py +425 -0
- terminalboard-0.1.0/terminalboard/cli.py +111 -0
- terminalboard-0.1.0/terminalboard/iterm2.py +64 -0
- terminalboard-0.1.0/terminalboard/keys.py +69 -0
- terminalboard-0.1.0/terminalboard/model.py +46 -0
- terminalboard-0.1.0/terminalboard/reader.py +129 -0
- terminalboard-0.1.0/terminalboard/reader_light.py +210 -0
- terminalboard-0.1.0/terminalboard/render.py +296 -0
- terminalboard-0.1.0/terminalboard/screen.py +70 -0
- terminalboard-0.1.0/terminalboard.egg-info/PKG-INFO +249 -0
- terminalboard-0.1.0/terminalboard.egg-info/SOURCES.txt +20 -0
- terminalboard-0.1.0/terminalboard.egg-info/dependency_links.txt +1 -0
- terminalboard-0.1.0/terminalboard.egg-info/entry_points.txt +2 -0
- terminalboard-0.1.0/terminalboard.egg-info/requires.txt +11 -0
- terminalboard-0.1.0/terminalboard.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dongfangyixi
|
|
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,249 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: terminalboard
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A pure-SSH terminal TensorBoard scalar viewer — live scalar curves in iTerm2, no browser, no X11, no port forwarding.
|
|
5
|
+
Author: dongfangyixi
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Repository, https://github.com/dongfangyixi/terminalboard
|
|
8
|
+
Keywords: tensorboard,terminal,iterm2,plotext,ssh,ml
|
|
9
|
+
Requires-Python: >=3.9
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: plotext>=5.2
|
|
13
|
+
Provides-Extra: tb
|
|
14
|
+
Requires-Dist: tensorboard>=2.9; extra == "tb"
|
|
15
|
+
Provides-Extra: hq
|
|
16
|
+
Requires-Dist: matplotlib>=3.5; extra == "hq"
|
|
17
|
+
Provides-Extra: full
|
|
18
|
+
Requires-Dist: tensorboard>=2.9; extra == "full"
|
|
19
|
+
Requires-Dist: matplotlib>=3.5; extra == "full"
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# terminalboard
|
|
23
|
+
|
|
24
|
+
A **pure-SSH terminal TensorBoard scalar viewer**.
|
|
25
|
+
|
|
26
|
+
Train on a remote box, SSH in, and watch your **live-updating scalar curves
|
|
27
|
+
right inside the terminal** — crisp Unicode/braille text by default, or real
|
|
28
|
+
iTerm2 inline images with `--hq`. No browser, no X11, no port forwarding.
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
ssh remote
|
|
32
|
+
terminalboard path/to/tb_logs
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Why this exists
|
|
38
|
+
|
|
39
|
+
The usual TensorBoard workflow over SSH is painful: you either forward a port
|
|
40
|
+
(`ssh -L 6006:...`) and open a browser, or you give up and `grep` the logs. On a
|
|
41
|
+
headless training box you often can't do either cleanly. terminalboard reads the
|
|
42
|
+
event files directly and draws the curves in the terminal, so a plain SSH session
|
|
43
|
+
is all you need.
|
|
44
|
+
|
|
45
|
+
## How it works
|
|
46
|
+
|
|
47
|
+
1. **Read** the TensorBoard event files (`events.out.tfevents.*`) from a log
|
|
48
|
+
directory (scanned recursively for multiple runs) and collect the scalar series.
|
|
49
|
+
2. **Render** the selected curves — by default as Unicode/braille **text** (works
|
|
50
|
+
in any terminal), or with `--hq` as a matplotlib PNG.
|
|
51
|
+
3. **Display** them: braille text is printed directly; the `--hq` PNG is streamed
|
|
52
|
+
via the [iTerm2 inline-image protocol](https://iterm2.com/documentation-images.html)
|
|
53
|
+
(built in-memory, no temp file).
|
|
54
|
+
4. **Watch** the log directory and re-render whenever new data lands, giving a
|
|
55
|
+
live dashboard. Repaints are **flicker-free**: the alternate screen buffer is
|
|
56
|
+
redrawn in place under synchronized output (DEC mode 2026), and an idle
|
|
57
|
+
dashboard isn't repainted at all (only changed data/views trigger a redraw).
|
|
58
|
+
|
|
59
|
+
## Language: Python
|
|
60
|
+
|
|
61
|
+
The viewer is written in **Python**, chosen after weighing it against a
|
|
62
|
+
Next.js/TypeScript implementation:
|
|
63
|
+
|
|
64
|
+
| Factor | Python ✅ | Next.js / TypeScript |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| Reading TB event logs | First-class. The format is TFRecord-framed protobuf; `tensorboard`/`tbparse` parse it natively, or a small self-contained parser does. | No mature TFRecord/TB-protobuf reader — you'd reimplement framing + protobuf decoding by hand. |
|
|
67
|
+
| High-quality curves | matplotlib → PNG → iTerm2 inline image. | No native terminal-plotting story. |
|
|
68
|
+
| Live tailing | `watchdog` / offset polling. | Doable, no advantage. |
|
|
69
|
+
| Fit for purpose | It's a terminal CLI, and Python is the lingua franca of the ML/TensorBoard ecosystem. | Next.js is a web/SSR framework; its core value (React, routing, browser) is unused here. |
|
|
70
|
+
| This machine | Python 3.12 already present. | Node isn't installed. |
|
|
71
|
+
|
|
72
|
+
The decisive factor: TensorBoard logs are a TF-specific protobuf format with
|
|
73
|
+
first-class Python tooling, and the target terminal (iTerm2) supports an
|
|
74
|
+
inline-image protocol — so we can render genuine matplotlib-quality curves rather
|
|
75
|
+
than ASCII art.
|
|
76
|
+
|
|
77
|
+
## Two rendering backends
|
|
78
|
+
|
|
79
|
+
- **Default — text/braille** (`plotext`): curves drawn directly as Unicode/braille
|
|
80
|
+
characters. No image is generated, so it works over **any** SSH session, tmux, or
|
|
81
|
+
plain terminal, and redraws instantly. *(See the example below.)*
|
|
82
|
+
- **`--hq` — iTerm2 image**: matplotlib rendered to an **in-memory** PNG (no temp
|
|
83
|
+
file) and streamed via the iTerm2 inline-image protocol. Pixel-perfect, but only
|
|
84
|
+
in iTerm2/WezTerm-class terminals.
|
|
85
|
+
- **`--auto`**: use the image renderer in iTerm2-class terminals, else fall back to
|
|
86
|
+
text automatically.
|
|
87
|
+
|
|
88
|
+
## Two parsing backends
|
|
89
|
+
|
|
90
|
+
- **Default** (no flag): parse with the official `tensorboard` library
|
|
91
|
+
(`EventAccumulator`) — most robust, handles exotic summary encodings. If
|
|
92
|
+
`tensorboard` isn't installed, terminalboard falls back to `--light` automatically.
|
|
93
|
+
- **`--light`**: a self-contained pure-Python TFRecord + protobuf-wire parser with
|
|
94
|
+
no heavy dependencies — tiny install, fast startup, ideal for a thin remote box.
|
|
95
|
+
|
|
96
|
+
The two axes are independent: pick any parser with any renderer.
|
|
97
|
+
|
|
98
|
+
## Install
|
|
99
|
+
|
|
100
|
+
> ⚠️ **Not published to PyPI yet**, so `pip install terminalboard` won't work
|
|
101
|
+
> until it is. Install from source for now.
|
|
102
|
+
|
|
103
|
+
**From a clone** (recommended for development):
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
git clone https://github.com/dongfangyixi/terminalboard.git
|
|
107
|
+
cd terminalboard
|
|
108
|
+
pip install -e '.[full]' # editable; full = tensorboard + matplotlib
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Directly from GitHub:**
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
pip install "git+https://github.com/dongfangyixi/terminalboard.git"
|
|
115
|
+
# with extras (default parser + --hq image renderer):
|
|
116
|
+
pip install "terminalboard[full] @ git+https://github.com/dongfangyixi/terminalboard.git"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The base install pulls only `plotext` — enough for the text renderer and the
|
|
120
|
+
dependency-free `--light` parser. Extras add the heavy bits:
|
|
121
|
+
|
|
122
|
+
| Extra | Adds | Enables |
|
|
123
|
+
|---|---|---|
|
|
124
|
+
| `[tb]` | `tensorboard` | the default (robust) parser |
|
|
125
|
+
| `[hq]` | `matplotlib` | the `--hq` iTerm2 image renderer |
|
|
126
|
+
| `[full]` | both | everything |
|
|
127
|
+
|
|
128
|
+
<details>
|
|
129
|
+
<summary>Once it's on PyPI</summary>
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
pip install terminalboard # text renderer + pure-Python --light parser
|
|
133
|
+
pip install 'terminalboard[tb]' # + tensorboard (default parser)
|
|
134
|
+
pip install 'terminalboard[hq]' # + matplotlib (--hq image renderer)
|
|
135
|
+
pip install 'terminalboard[full]' # everything
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Publishing checklist: `pip install build twine` → `python -m build` →
|
|
139
|
+
`twine upload dist/*` (needs a PyPI account + the name `terminalboard` being free).
|
|
140
|
+
</details>
|
|
141
|
+
|
|
142
|
+
## Usage
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
terminalboard LOGDIR [options]
|
|
146
|
+
|
|
147
|
+
LOGDIR / --logdir directory of TensorBoard event files (scanned recursively)
|
|
148
|
+
--light use the dependency-free pure-Python parser
|
|
149
|
+
--hq / --text/--auto image / text (default) / auto-detect renderer
|
|
150
|
+
--tags GLOB filter tags, e.g. 'train/*loss*,val/*' (live-editable: t)
|
|
151
|
+
--experiments GLOB filter experiments/runs (live-editable: f)
|
|
152
|
+
--smooth ALPHA EMA smoothing weight in [0,1) (default: 0.6; 0 disables)
|
|
153
|
+
--grid RxC panels per page (default: 2x3)
|
|
154
|
+
--interval SECONDS live refresh interval (default: 2.0)
|
|
155
|
+
--once render a single frame and exit
|
|
156
|
+
--list list all scalar tags and exit
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
terminalboard ../tb_logs # live text dashboard
|
|
161
|
+
terminalboard ../tb_logs --tags 'train/*loss*' # filter to loss curves
|
|
162
|
+
terminalboard ../tb_logs --hq --grid 2x2 # high-quality iTerm2 images
|
|
163
|
+
terminalboard ../tb_logs --light --once # one frame, no deps, no loop
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Interactive controls (live mode)
|
|
167
|
+
|
|
168
|
+
| Key | Action |
|
|
169
|
+
|---|---|
|
|
170
|
+
| `q` | quit |
|
|
171
|
+
| `n` / `space`, `p` | next / previous page of tags |
|
|
172
|
+
| `t` | edit the **tag** filter live (Enter apply · Esc cancel · ^U clear) |
|
|
173
|
+
| `f` | edit the **experiment/run** filter live |
|
|
174
|
+
| `r` | refresh now |
|
|
175
|
+
| `+` / `-` | more / less smoothing |
|
|
176
|
+
| `0` | disable smoothing |
|
|
177
|
+
| `z` / `Z` | zoom out / in — panels per page: `1·2·4·6·9·12·16·24·36` |
|
|
178
|
+
|
|
179
|
+
Filters match per comma-separated token: a plain word is a case-insensitive
|
|
180
|
+
**substring** (`loss` → `train/loss`, `val/loss`), while `* ? [` make it a glob
|
|
181
|
+
(`train/*loss*`). The plots re-filter as you type. Tag and experiment filters
|
|
182
|
+
combine — a tag only shows if a currently-visible experiment has it.
|
|
183
|
+
|
|
184
|
+
### Multiple experiments
|
|
185
|
+
|
|
186
|
+
When a logdir holds several runs, their curves are **overlaid in each panel**,
|
|
187
|
+
each experiment in its own color, with a legend above the grid. Colors are
|
|
188
|
+
**stable** — an experiment keeps its color no matter which others you filter in
|
|
189
|
+
or out — so you can always tell which curve is which. Use `f` (or
|
|
190
|
+
`--experiments`) to focus on a subset.
|
|
191
|
+
|
|
192
|
+
In the filter prompt: **←/→** move the cursor, **↑/↓** recall previous patterns,
|
|
193
|
+
**Home/End** (or `^A`/`^E`) jump, `^U` clears. If a pattern matches nothing the
|
|
194
|
+
current plots are **kept** (no jarring re-layout) and a red warning is shown
|
|
195
|
+
until you fix or cancel it.
|
|
196
|
+
|
|
197
|
+
### Example (text renderer)
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
train/text_token_accuracy
|
|
201
|
+
┌──────────────────────────────────────────────────────────────────────────┐
|
|
202
|
+
0.97┤ ⡠⣄⣀⣀⡠⠖⠦⠤⠤⠖⠒⠒⠒⠒⠉⠙⠒⠒⠉⠉⠉⠉⠉│
|
|
203
|
+
│ ⣠⠒⠒⠒⠞ │
|
|
204
|
+
│ ⡤⠲⠴⠤⠇ │
|
|
205
|
+
0.82┤ ⢰⠁ │
|
|
206
|
+
│ ⢠⠒⠲⠤⠎ │
|
|
207
|
+
0.67┤ ⣀⣀⣀⣠⠃ │
|
|
208
|
+
│ ⢀⠔⠒⠒⠲⠇ │
|
|
209
|
+
0.52┤ ⣀⣀⣀⣀⣀⣀⣀⣀⡠⠤⠤⠤⠤⠞⠉⠉⠉⠛ │
|
|
210
|
+
│ ⡴⠲⠒⠉⠉⠉⠉⠉⠁ │
|
|
211
|
+
└┬─────────────────┬──────────────────┬─────────────────┬─────────────────┬┘
|
|
212
|
+
10 1510 3010 4510 6010
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Roadmap
|
|
216
|
+
|
|
217
|
+
- [x] **Reader — `--light`**: pure-Python TFRecord + protobuf-wire parser
|
|
218
|
+
(Event → Summary → Value; both `simple_value` and tensor-encoded scalars).
|
|
219
|
+
- [x] **Reader — default**: `tensorboard` `EventAccumulator` backend with a shared
|
|
220
|
+
`ScalarSeries` data model and recursive multi-run logdir scan.
|
|
221
|
+
- [x] **Render — text**: `plotext` braille grid, the default (no image).
|
|
222
|
+
- [x] **Render — `--hq`**: matplotlib grid → in-memory PNG → iTerm2 inline image.
|
|
223
|
+
- [x] **Live loop + CLI**: flicker-free repaints, keyboard navigation; argparse front end.
|
|
224
|
+
- [x] **Zoom** (`z`/`Z`): 1·2·4·6·9·12·16·24·36 panels per page.
|
|
225
|
+
- [x] **Interactive filters** (`t`/`f`): live tag & experiment filtering with a
|
|
226
|
+
line editor (cursor, history, no-match warning).
|
|
227
|
+
- [x] **Multi-experiment overlay** with stable per-run colors and a legend.
|
|
228
|
+
- [ ] Publish to PyPI.
|
|
229
|
+
- [ ] Sixel fallback for non-iTerm2 terminals; config file; per-tag y-axis options.
|
|
230
|
+
|
|
231
|
+
## Status
|
|
232
|
+
|
|
233
|
+
Working. The default text dashboard, `--hq` iTerm2 images, the `--light` parser,
|
|
234
|
+
multi-experiment overlay, zoom, and live interactive tag/experiment filtering are
|
|
235
|
+
all functional. Test event logs are kept in the **parent working folder** (e.g.
|
|
236
|
+
`../tb_logs/`), deliberately outside this repository — they're real training data
|
|
237
|
+
and don't belong in a public repo.
|
|
238
|
+
|
|
239
|
+
## Development
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
python3 -m venv .venv
|
|
243
|
+
.venv/bin/pip install -e '.[full]'
|
|
244
|
+
.venv/bin/terminalboard ../tb_logs --once
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## License
|
|
248
|
+
|
|
249
|
+
[MIT](LICENSE).
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# terminalboard
|
|
2
|
+
|
|
3
|
+
A **pure-SSH terminal TensorBoard scalar viewer**.
|
|
4
|
+
|
|
5
|
+
Train on a remote box, SSH in, and watch your **live-updating scalar curves
|
|
6
|
+
right inside the terminal** — crisp Unicode/braille text by default, or real
|
|
7
|
+
iTerm2 inline images with `--hq`. No browser, no X11, no port forwarding.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
ssh remote
|
|
11
|
+
terminalboard path/to/tb_logs
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Why this exists
|
|
17
|
+
|
|
18
|
+
The usual TensorBoard workflow over SSH is painful: you either forward a port
|
|
19
|
+
(`ssh -L 6006:...`) and open a browser, or you give up and `grep` the logs. On a
|
|
20
|
+
headless training box you often can't do either cleanly. terminalboard reads the
|
|
21
|
+
event files directly and draws the curves in the terminal, so a plain SSH session
|
|
22
|
+
is all you need.
|
|
23
|
+
|
|
24
|
+
## How it works
|
|
25
|
+
|
|
26
|
+
1. **Read** the TensorBoard event files (`events.out.tfevents.*`) from a log
|
|
27
|
+
directory (scanned recursively for multiple runs) and collect the scalar series.
|
|
28
|
+
2. **Render** the selected curves — by default as Unicode/braille **text** (works
|
|
29
|
+
in any terminal), or with `--hq` as a matplotlib PNG.
|
|
30
|
+
3. **Display** them: braille text is printed directly; the `--hq` PNG is streamed
|
|
31
|
+
via the [iTerm2 inline-image protocol](https://iterm2.com/documentation-images.html)
|
|
32
|
+
(built in-memory, no temp file).
|
|
33
|
+
4. **Watch** the log directory and re-render whenever new data lands, giving a
|
|
34
|
+
live dashboard. Repaints are **flicker-free**: the alternate screen buffer is
|
|
35
|
+
redrawn in place under synchronized output (DEC mode 2026), and an idle
|
|
36
|
+
dashboard isn't repainted at all (only changed data/views trigger a redraw).
|
|
37
|
+
|
|
38
|
+
## Language: Python
|
|
39
|
+
|
|
40
|
+
The viewer is written in **Python**, chosen after weighing it against a
|
|
41
|
+
Next.js/TypeScript implementation:
|
|
42
|
+
|
|
43
|
+
| Factor | Python ✅ | Next.js / TypeScript |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| Reading TB event logs | First-class. The format is TFRecord-framed protobuf; `tensorboard`/`tbparse` parse it natively, or a small self-contained parser does. | No mature TFRecord/TB-protobuf reader — you'd reimplement framing + protobuf decoding by hand. |
|
|
46
|
+
| High-quality curves | matplotlib → PNG → iTerm2 inline image. | No native terminal-plotting story. |
|
|
47
|
+
| Live tailing | `watchdog` / offset polling. | Doable, no advantage. |
|
|
48
|
+
| Fit for purpose | It's a terminal CLI, and Python is the lingua franca of the ML/TensorBoard ecosystem. | Next.js is a web/SSR framework; its core value (React, routing, browser) is unused here. |
|
|
49
|
+
| This machine | Python 3.12 already present. | Node isn't installed. |
|
|
50
|
+
|
|
51
|
+
The decisive factor: TensorBoard logs are a TF-specific protobuf format with
|
|
52
|
+
first-class Python tooling, and the target terminal (iTerm2) supports an
|
|
53
|
+
inline-image protocol — so we can render genuine matplotlib-quality curves rather
|
|
54
|
+
than ASCII art.
|
|
55
|
+
|
|
56
|
+
## Two rendering backends
|
|
57
|
+
|
|
58
|
+
- **Default — text/braille** (`plotext`): curves drawn directly as Unicode/braille
|
|
59
|
+
characters. No image is generated, so it works over **any** SSH session, tmux, or
|
|
60
|
+
plain terminal, and redraws instantly. *(See the example below.)*
|
|
61
|
+
- **`--hq` — iTerm2 image**: matplotlib rendered to an **in-memory** PNG (no temp
|
|
62
|
+
file) and streamed via the iTerm2 inline-image protocol. Pixel-perfect, but only
|
|
63
|
+
in iTerm2/WezTerm-class terminals.
|
|
64
|
+
- **`--auto`**: use the image renderer in iTerm2-class terminals, else fall back to
|
|
65
|
+
text automatically.
|
|
66
|
+
|
|
67
|
+
## Two parsing backends
|
|
68
|
+
|
|
69
|
+
- **Default** (no flag): parse with the official `tensorboard` library
|
|
70
|
+
(`EventAccumulator`) — most robust, handles exotic summary encodings. If
|
|
71
|
+
`tensorboard` isn't installed, terminalboard falls back to `--light` automatically.
|
|
72
|
+
- **`--light`**: a self-contained pure-Python TFRecord + protobuf-wire parser with
|
|
73
|
+
no heavy dependencies — tiny install, fast startup, ideal for a thin remote box.
|
|
74
|
+
|
|
75
|
+
The two axes are independent: pick any parser with any renderer.
|
|
76
|
+
|
|
77
|
+
## Install
|
|
78
|
+
|
|
79
|
+
> ⚠️ **Not published to PyPI yet**, so `pip install terminalboard` won't work
|
|
80
|
+
> until it is. Install from source for now.
|
|
81
|
+
|
|
82
|
+
**From a clone** (recommended for development):
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
git clone https://github.com/dongfangyixi/terminalboard.git
|
|
86
|
+
cd terminalboard
|
|
87
|
+
pip install -e '.[full]' # editable; full = tensorboard + matplotlib
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Directly from GitHub:**
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
pip install "git+https://github.com/dongfangyixi/terminalboard.git"
|
|
94
|
+
# with extras (default parser + --hq image renderer):
|
|
95
|
+
pip install "terminalboard[full] @ git+https://github.com/dongfangyixi/terminalboard.git"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The base install pulls only `plotext` — enough for the text renderer and the
|
|
99
|
+
dependency-free `--light` parser. Extras add the heavy bits:
|
|
100
|
+
|
|
101
|
+
| Extra | Adds | Enables |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| `[tb]` | `tensorboard` | the default (robust) parser |
|
|
104
|
+
| `[hq]` | `matplotlib` | the `--hq` iTerm2 image renderer |
|
|
105
|
+
| `[full]` | both | everything |
|
|
106
|
+
|
|
107
|
+
<details>
|
|
108
|
+
<summary>Once it's on PyPI</summary>
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
pip install terminalboard # text renderer + pure-Python --light parser
|
|
112
|
+
pip install 'terminalboard[tb]' # + tensorboard (default parser)
|
|
113
|
+
pip install 'terminalboard[hq]' # + matplotlib (--hq image renderer)
|
|
114
|
+
pip install 'terminalboard[full]' # everything
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Publishing checklist: `pip install build twine` → `python -m build` →
|
|
118
|
+
`twine upload dist/*` (needs a PyPI account + the name `terminalboard` being free).
|
|
119
|
+
</details>
|
|
120
|
+
|
|
121
|
+
## Usage
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
terminalboard LOGDIR [options]
|
|
125
|
+
|
|
126
|
+
LOGDIR / --logdir directory of TensorBoard event files (scanned recursively)
|
|
127
|
+
--light use the dependency-free pure-Python parser
|
|
128
|
+
--hq / --text/--auto image / text (default) / auto-detect renderer
|
|
129
|
+
--tags GLOB filter tags, e.g. 'train/*loss*,val/*' (live-editable: t)
|
|
130
|
+
--experiments GLOB filter experiments/runs (live-editable: f)
|
|
131
|
+
--smooth ALPHA EMA smoothing weight in [0,1) (default: 0.6; 0 disables)
|
|
132
|
+
--grid RxC panels per page (default: 2x3)
|
|
133
|
+
--interval SECONDS live refresh interval (default: 2.0)
|
|
134
|
+
--once render a single frame and exit
|
|
135
|
+
--list list all scalar tags and exit
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
terminalboard ../tb_logs # live text dashboard
|
|
140
|
+
terminalboard ../tb_logs --tags 'train/*loss*' # filter to loss curves
|
|
141
|
+
terminalboard ../tb_logs --hq --grid 2x2 # high-quality iTerm2 images
|
|
142
|
+
terminalboard ../tb_logs --light --once # one frame, no deps, no loop
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Interactive controls (live mode)
|
|
146
|
+
|
|
147
|
+
| Key | Action |
|
|
148
|
+
|---|---|
|
|
149
|
+
| `q` | quit |
|
|
150
|
+
| `n` / `space`, `p` | next / previous page of tags |
|
|
151
|
+
| `t` | edit the **tag** filter live (Enter apply · Esc cancel · ^U clear) |
|
|
152
|
+
| `f` | edit the **experiment/run** filter live |
|
|
153
|
+
| `r` | refresh now |
|
|
154
|
+
| `+` / `-` | more / less smoothing |
|
|
155
|
+
| `0` | disable smoothing |
|
|
156
|
+
| `z` / `Z` | zoom out / in — panels per page: `1·2·4·6·9·12·16·24·36` |
|
|
157
|
+
|
|
158
|
+
Filters match per comma-separated token: a plain word is a case-insensitive
|
|
159
|
+
**substring** (`loss` → `train/loss`, `val/loss`), while `* ? [` make it a glob
|
|
160
|
+
(`train/*loss*`). The plots re-filter as you type. Tag and experiment filters
|
|
161
|
+
combine — a tag only shows if a currently-visible experiment has it.
|
|
162
|
+
|
|
163
|
+
### Multiple experiments
|
|
164
|
+
|
|
165
|
+
When a logdir holds several runs, their curves are **overlaid in each panel**,
|
|
166
|
+
each experiment in its own color, with a legend above the grid. Colors are
|
|
167
|
+
**stable** — an experiment keeps its color no matter which others you filter in
|
|
168
|
+
or out — so you can always tell which curve is which. Use `f` (or
|
|
169
|
+
`--experiments`) to focus on a subset.
|
|
170
|
+
|
|
171
|
+
In the filter prompt: **←/→** move the cursor, **↑/↓** recall previous patterns,
|
|
172
|
+
**Home/End** (or `^A`/`^E`) jump, `^U` clears. If a pattern matches nothing the
|
|
173
|
+
current plots are **kept** (no jarring re-layout) and a red warning is shown
|
|
174
|
+
until you fix or cancel it.
|
|
175
|
+
|
|
176
|
+
### Example (text renderer)
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
train/text_token_accuracy
|
|
180
|
+
┌──────────────────────────────────────────────────────────────────────────┐
|
|
181
|
+
0.97┤ ⡠⣄⣀⣀⡠⠖⠦⠤⠤⠖⠒⠒⠒⠒⠉⠙⠒⠒⠉⠉⠉⠉⠉│
|
|
182
|
+
│ ⣠⠒⠒⠒⠞ │
|
|
183
|
+
│ ⡤⠲⠴⠤⠇ │
|
|
184
|
+
0.82┤ ⢰⠁ │
|
|
185
|
+
│ ⢠⠒⠲⠤⠎ │
|
|
186
|
+
0.67┤ ⣀⣀⣀⣠⠃ │
|
|
187
|
+
│ ⢀⠔⠒⠒⠲⠇ │
|
|
188
|
+
0.52┤ ⣀⣀⣀⣀⣀⣀⣀⣀⡠⠤⠤⠤⠤⠞⠉⠉⠉⠛ │
|
|
189
|
+
│ ⡴⠲⠒⠉⠉⠉⠉⠉⠁ │
|
|
190
|
+
└┬─────────────────┬──────────────────┬─────────────────┬─────────────────┬┘
|
|
191
|
+
10 1510 3010 4510 6010
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Roadmap
|
|
195
|
+
|
|
196
|
+
- [x] **Reader — `--light`**: pure-Python TFRecord + protobuf-wire parser
|
|
197
|
+
(Event → Summary → Value; both `simple_value` and tensor-encoded scalars).
|
|
198
|
+
- [x] **Reader — default**: `tensorboard` `EventAccumulator` backend with a shared
|
|
199
|
+
`ScalarSeries` data model and recursive multi-run logdir scan.
|
|
200
|
+
- [x] **Render — text**: `plotext` braille grid, the default (no image).
|
|
201
|
+
- [x] **Render — `--hq`**: matplotlib grid → in-memory PNG → iTerm2 inline image.
|
|
202
|
+
- [x] **Live loop + CLI**: flicker-free repaints, keyboard navigation; argparse front end.
|
|
203
|
+
- [x] **Zoom** (`z`/`Z`): 1·2·4·6·9·12·16·24·36 panels per page.
|
|
204
|
+
- [x] **Interactive filters** (`t`/`f`): live tag & experiment filtering with a
|
|
205
|
+
line editor (cursor, history, no-match warning).
|
|
206
|
+
- [x] **Multi-experiment overlay** with stable per-run colors and a legend.
|
|
207
|
+
- [ ] Publish to PyPI.
|
|
208
|
+
- [ ] Sixel fallback for non-iTerm2 terminals; config file; per-tag y-axis options.
|
|
209
|
+
|
|
210
|
+
## Status
|
|
211
|
+
|
|
212
|
+
Working. The default text dashboard, `--hq` iTerm2 images, the `--light` parser,
|
|
213
|
+
multi-experiment overlay, zoom, and live interactive tag/experiment filtering are
|
|
214
|
+
all functional. Test event logs are kept in the **parent working folder** (e.g.
|
|
215
|
+
`../tb_logs/`), deliberately outside this repository — they're real training data
|
|
216
|
+
and don't belong in a public repo.
|
|
217
|
+
|
|
218
|
+
## Development
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
python3 -m venv .venv
|
|
222
|
+
.venv/bin/pip install -e '.[full]'
|
|
223
|
+
.venv/bin/terminalboard ../tb_logs --once
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## License
|
|
227
|
+
|
|
228
|
+
[MIT](LICENSE).
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "terminalboard"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A pure-SSH terminal TensorBoard scalar viewer — live scalar curves in iTerm2, no browser, no X11, no port forwarding."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "dongfangyixi" }]
|
|
13
|
+
keywords = ["tensorboard", "terminal", "iterm2", "plotext", "ssh", "ml"]
|
|
14
|
+
|
|
15
|
+
# Base install is intentionally light: the text renderer (plotext) and the
|
|
16
|
+
# pure-Python --light parser work with just this.
|
|
17
|
+
dependencies = [
|
|
18
|
+
"plotext>=5.2",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[project.optional-dependencies]
|
|
22
|
+
# Default parser backend (EventAccumulator).
|
|
23
|
+
tb = ["tensorboard>=2.9"]
|
|
24
|
+
# High-quality --hq image renderer (matplotlib -> iTerm2 inline image).
|
|
25
|
+
hq = ["matplotlib>=3.5"]
|
|
26
|
+
# Everything.
|
|
27
|
+
full = ["tensorboard>=2.9", "matplotlib>=3.5"]
|
|
28
|
+
|
|
29
|
+
[project.scripts]
|
|
30
|
+
terminalboard = "terminalboard.cli:main"
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
Repository = "https://github.com/dongfangyixi/terminalboard"
|
|
34
|
+
|
|
35
|
+
[tool.setuptools.packages.find]
|
|
36
|
+
where = ["."]
|
|
37
|
+
include = ["terminalboard*"]
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""terminalboard — a pure-SSH terminal TensorBoard scalar viewer.
|
|
2
|
+
|
|
3
|
+
Reads TensorBoard event logs and renders live-updated scalar curves directly
|
|
4
|
+
inside the terminal — by default as Unicode/braille text (works over any SSH
|
|
5
|
+
session), or as high-quality matplotlib images via the iTerm2 inline-image
|
|
6
|
+
protocol with ``--hq``. No browser, no X11, no port forwarding.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__version__ = "0.1.0"
|