better-rtplot 0.2.5__tar.gz → 0.3.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.
- {better_rtplot-0.2.5 → better_rtplot-0.3.0}/PKG-INFO +253 -109
- {better_rtplot-0.2.5 → better_rtplot-0.3.0}/README.md +252 -106
- {better_rtplot-0.2.5 → better_rtplot-0.3.0}/pyproject.toml +3 -5
- {better_rtplot-0.2.5 → better_rtplot-0.3.0}/rtplot/client.py +82 -77
- {better_rtplot-0.2.5 → better_rtplot-0.3.0}/rtplot/server.py +8 -118
- {better_rtplot-0.2.5 → better_rtplot-0.3.0}/rtplot/server_browser.py +268 -159
- {better_rtplot-0.2.5 → better_rtplot-0.3.0}/rtplot/server_browser_gui.py +1 -64
- better_rtplot-0.2.5/rtplot/example_code.py +0 -293
- better_rtplot-0.2.5/rtplot/plot_log.py +0 -64
- {better_rtplot-0.2.5 → better_rtplot-0.3.0}/LICENSE +0 -0
- {better_rtplot-0.2.5 → better_rtplot-0.3.0}/rtplot/interactive_test.py +0 -0
- {better_rtplot-0.2.5 → better_rtplot-0.3.0}/rtplot/saved_plots/.gitignore +0 -0
- {better_rtplot-0.2.5 → better_rtplot-0.3.0}/rtplot/static/uPlot.iife.min.js +0 -0
- {better_rtplot-0.2.5 → better_rtplot-0.3.0}/rtplot/static/uPlot.min.css +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: better-rtplot
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary:
|
|
5
5
|
License: GPL V3.0
|
|
6
6
|
Author: jmontp
|
|
@@ -16,15 +16,11 @@ Provides-Extra: browser
|
|
|
16
16
|
Provides-Extra: server
|
|
17
17
|
Requires-Dist: aiohttp (>=3.9.0) ; extra == "browser"
|
|
18
18
|
Requires-Dist: numpy (>=1.23.5)
|
|
19
|
-
Requires-Dist: pandas (>=1.5.3) ; extra == "server" or extra == "browser"
|
|
20
|
-
Requires-Dist: pyarrow (>=11.0.0) ; extra == "server" or extra == "browser"
|
|
21
19
|
Requires-Dist: pyqtgraph (>=0.13.0) ; extra == "server"
|
|
22
20
|
Requires-Dist: pyside6 (>6.4.0) ; extra == "server"
|
|
23
21
|
Requires-Dist: pyzmq (>=25.0.0)
|
|
24
22
|
Description-Content-Type: text/markdown
|
|
25
23
|
|
|
26
|
-

|
|
27
|
-
|
|
28
24
|
# rtplot — real-time plotting over ZMQ
|
|
29
25
|
|
|
30
26
|
**rtplot** lets a Python script push live data to a plot window — locally, or
|
|
@@ -37,25 +33,114 @@ Typical use: a robot or data-acquisition script runs on a Raspberry Pi or
|
|
|
37
33
|
microcontroller host, and you watch live signals and tweak gains from a
|
|
38
34
|
laptop on the same network.
|
|
39
35
|
|
|
36
|
+
**Looking for runnable examples?** Every subfolder in
|
|
37
|
+
[`examples/`](examples/) is a small, self-contained script with its own
|
|
38
|
+
`README.md` and a static `snapshot.html` you can open in a browser to
|
|
39
|
+
preview what the plot looks like without running anything.
|
|
40
|
+
|
|
40
41
|
---
|
|
41
42
|
|
|
42
43
|
## Table of contents
|
|
43
44
|
|
|
45
|
+
- [How it works](#how-it-works)
|
|
46
|
+
- [Your first plot, step by step](#your-first-plot-step-by-step)
|
|
44
47
|
- [Highlights](#highlights)
|
|
45
48
|
- [Install](#install)
|
|
46
|
-
- [60-second quickstart](#60-second-quickstart)
|
|
47
49
|
- [Interactive controls](#interactive-controls)
|
|
48
|
-
- [Reading controls from Python](#reading-controls-from-python)
|
|
49
|
-
- [Pushing values into displays](#pushing-values-into-displays)
|
|
50
|
-
- [Element reference](#element-reference)
|
|
51
50
|
- [Plot configuration](#plot-configuration)
|
|
52
51
|
- [Sending data](#sending-data)
|
|
53
|
-
- [
|
|
52
|
+
- [Static HTML snapshots](#static-html-snapshots)
|
|
53
|
+
- [Browser UI features](#browser-ui-features)
|
|
54
54
|
- [Networking modes](#networking-modes)
|
|
55
55
|
- [Viewing the plot from another device](#viewing-the-plot-from-another-device)
|
|
56
56
|
- [Performance tuning](#performance-tuning)
|
|
57
57
|
- [CLI reference](#cli-reference)
|
|
58
|
-
- [
|
|
58
|
+
- [Client API reference](#client-api-reference)
|
|
59
|
+
- [Examples gallery](#examples-gallery)
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## How it works
|
|
64
|
+
|
|
65
|
+
rtplot has two pieces that run independently:
|
|
66
|
+
|
|
67
|
+
- The **server** is a small program that shows plots in a web browser.
|
|
68
|
+
You start it once (or download it as a standalone Windows / Linux /
|
|
69
|
+
macOS binary from the
|
|
70
|
+
[Releases page](https://github.com/jmontp/rtplot/releases)) and it
|
|
71
|
+
sits there waiting for data.
|
|
72
|
+
- The **client** is a tiny Python library you import from your own
|
|
73
|
+
script. Calling `client.send_array(value)` in your loop makes a new
|
|
74
|
+
data point appear on the server's plot.
|
|
75
|
+
|
|
76
|
+
Picture it like this:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
┌──────────────────────┐ ┌──────────────────────┐
|
|
80
|
+
│ Your Python script │ │ rtplot-server │
|
|
81
|
+
│ │ │ │
|
|
82
|
+
│ from rtplot import │── ZMQ ───▶ │ ┌────────────────┐ │
|
|
83
|
+
│ client │ :5555 │ │ browser tab at │ │
|
|
84
|
+
│ │ │ │ localhost:8050 │ │
|
|
85
|
+
│ client.send_array() │ ◀── ZMQ ── │ └────────────────┘ │
|
|
86
|
+
│ │ :5556 │ │
|
|
87
|
+
└──────────────────────┘ └──────────────────────┘
|
|
88
|
+
(the client lib) (the exe or module)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Data flows from your script to the server on **ZMQ port 5555**. When
|
|
92
|
+
the server runs the interactive-controls feature, button clicks and
|
|
93
|
+
slider values flow **back** to your script on port **5556**. The
|
|
94
|
+
server also hosts an HTTP page on port **8050** that any browser can
|
|
95
|
+
open to see the live plot.
|
|
96
|
+
|
|
97
|
+
The two pieces don't have to run on the same machine. Running rtplot
|
|
98
|
+
on a Raspberry Pi and watching the plots from your laptop is the same
|
|
99
|
+
code — just tell the client where the server is (or vice versa).
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Your first plot, step by step
|
|
104
|
+
|
|
105
|
+
**Step 0** — install rtplot with the browser server bundled:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
pip install "better-rtplot[browser]"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Step 1** — start the server. In **one** terminal:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
python -m rtplot.server_browser
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
It prints a URL like `http://localhost:8050`. Open that in a browser.
|
|
118
|
+
The page is blank for now — no data has been sent yet, which is fine.
|
|
119
|
+
|
|
120
|
+
**Step 2** — write and run your script. In **another** terminal, save
|
|
121
|
+
this as `my_plot.py`:
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from rtplot import client
|
|
125
|
+
import time
|
|
126
|
+
|
|
127
|
+
client.local_plot() # point at the server on this machine
|
|
128
|
+
client.initialize_plots(["my signal"]) # declare one plot with one trace
|
|
129
|
+
|
|
130
|
+
for i in range(1000):
|
|
131
|
+
client.send_array(i * 0.01) # ship one sample per iteration
|
|
132
|
+
time.sleep(0.01)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Run it: `python my_plot.py`.
|
|
136
|
+
|
|
137
|
+
**Step 3** — switch back to the browser tab. A rising-line plot is
|
|
138
|
+
now drawing itself in real time.
|
|
139
|
+
|
|
140
|
+
That's everything you need to get started. The rest of this README is
|
|
141
|
+
a reference for options, styling, interactive controls, and remote
|
|
142
|
+
networking, plus a [gallery of example scripts](examples/) you can
|
|
143
|
+
preview as static snapshots before running them yourself.
|
|
59
144
|
|
|
60
145
|
---
|
|
61
146
|
|
|
@@ -71,31 +156,35 @@ laptop on the same network.
|
|
|
71
156
|
works over SSH port forwarding out of the box.
|
|
72
157
|
- **Remote-friendly.** Either the sender or the plot host can bind —
|
|
73
158
|
pick whichever fits your network. Works across LAN, WSL, and SSH
|
|
74
|
-
tunnels.
|
|
159
|
+
tunnels. The browser UI has live Bind / Connect buttons so you can
|
|
160
|
+
retarget without restarting the server.
|
|
75
161
|
- **Plot config lives with the data.** The sender declares the plot
|
|
76
162
|
layout, so a Pi running your experiment owns the look of its own
|
|
77
163
|
dashboards.
|
|
78
|
-
- **Interactive controls.** Declare buttons, sliders, dials,
|
|
79
|
-
numeric/text displays in the same `initialize_plots` call. Poll
|
|
80
|
-
your tight loop; no threads, no callbacks.
|
|
81
|
-
- **
|
|
82
|
-
|
|
164
|
+
- **Interactive controls.** Declare buttons, sliders, dials, and
|
|
165
|
+
numeric / text displays in the same `initialize_plots` call. Poll
|
|
166
|
+
from your tight loop; no threads, no callbacks.
|
|
167
|
+
- **Static HTML snapshots.** `client.save_snapshot("out.html")` writes
|
|
168
|
+
a self-contained HTML file with the current trace data and uPlot
|
|
169
|
+
inlined. Perfect for commit-to-repo gallery previews or emailing a
|
|
170
|
+
"here's what I saw" artifact.
|
|
83
171
|
|
|
84
172
|
---
|
|
85
173
|
|
|
86
174
|
## Install
|
|
87
175
|
|
|
88
|
-
|
|
89
|
-
|
|
176
|
+
### Normal path — pip
|
|
177
|
+
|
|
178
|
+
Install rtplot with the server bundle:
|
|
90
179
|
|
|
91
180
|
```bash
|
|
92
181
|
pip install "better-rtplot[browser]"
|
|
93
182
|
```
|
|
94
183
|
|
|
95
|
-
This pulls `aiohttp` (for serving the plot UI)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
184
|
+
This pulls `aiohttp` (for serving the plot UI). If you only need the
|
|
185
|
+
sender side — your script pushes data to someone else's plot host and
|
|
186
|
+
you don't run a server locally — you can install the client-only
|
|
187
|
+
minimum:
|
|
99
188
|
|
|
100
189
|
```bash
|
|
101
190
|
pip install better-rtplot
|
|
@@ -107,36 +196,27 @@ clear error telling you to add the `[browser]` extra.
|
|
|
107
196
|
WSL users: nothing extra needed. The plot window is served by HTTP, so
|
|
108
197
|
just open the URL rtplot prints in your Windows browser.
|
|
109
198
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
## 60-second quickstart
|
|
113
|
-
|
|
114
|
-
**Terminal 1 — start the plot server:**
|
|
115
|
-
|
|
116
|
-
```bash
|
|
117
|
-
python -m rtplot.server_browser
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
It prints a URL like `http://localhost:8050` — open that in your
|
|
121
|
-
browser. The page stays blank until a client sends a plot config.
|
|
122
|
-
|
|
123
|
-
**Terminal 2 — send data:**
|
|
124
|
-
|
|
125
|
-
```python
|
|
126
|
-
from rtplot import client
|
|
127
|
-
import numpy as np, time
|
|
199
|
+
### No-Python path — prebuilt binary
|
|
128
200
|
|
|
129
|
-
|
|
130
|
-
|
|
201
|
+
Every tagged release on GitHub ships a standalone `rtplot-server`
|
|
202
|
+
binary built for **windows-x64**, **linux-x86_64**, and
|
|
203
|
+
**macos-arm64**. Download from the
|
|
204
|
+
[Releases page](https://github.com/jmontp/rtplot/releases) and run
|
|
205
|
+
directly — no Python install needed on that machine.
|
|
131
206
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
207
|
+
On Windows the binary opens a small Tk status window
|
|
208
|
+
(`rtplot/server_browser_gui.py`) that shows the listening URL, ZMQ
|
|
209
|
+
status, an optional demo sender for smoke-testing end-to-end
|
|
210
|
+
connectivity, and a collapsable log panel.
|
|
211
|
+
Senders still need Python + `pip install better-rtplot`; the binary
|
|
212
|
+
only replaces the *server* side, which is the part most people don't
|
|
213
|
+
want to set up on a plot-viewing machine.
|
|
137
214
|
|
|
138
|
-
|
|
139
|
-
|
|
215
|
+
| Platform | Asset name |
|
|
216
|
+
|---|---|
|
|
217
|
+
| Windows | `rtplot-server-<version>-windows-x64.exe` |
|
|
218
|
+
| Linux | `rtplot-server-<version>-linux-x86_64.tar.gz` |
|
|
219
|
+
| macOS (Apple Silicon) | `rtplot-server-<version>-macos-arm64.tar.gz` |
|
|
140
220
|
|
|
141
221
|
---
|
|
142
222
|
|
|
@@ -223,19 +303,28 @@ server and rebroadcast to every connected browser at ~30 Hz.
|
|
|
223
303
|
|
|
224
304
|
| Type | Purpose | Notable fields |
|
|
225
305
|
|---|---|---|
|
|
226
|
-
| `button` | Fires a discrete event when clicked | `id`, `label` |
|
|
227
|
-
| `slider` | Scalar input via horizontal range | `id`, `label`, `min`, `max`, `value`, `step`, `format` |
|
|
228
|
-
| `dial` | Scalar input via
|
|
229
|
-
| `display` | Read-only numeric readout | `id`, `label`, `format` |
|
|
230
|
-
| `text` | Read-only text field (prompts, status) | `id`, `label`, `value` |
|
|
306
|
+
| `button` | Fires a discrete event when clicked | `id`, `label`, `height` |
|
|
307
|
+
| `slider` | Scalar input via horizontal range | `id`, `label`, `min`, `max`, `value`, `step`, `format`, `height` |
|
|
308
|
+
| `dial` | Scalar input via vertical drag on a circular indicator | same as slider, plus `sensitivity` (fraction of value range per rotation; default `1.0`) |
|
|
309
|
+
| `display` | Read-only numeric readout | `id`, `label`, `format`, `height` |
|
|
310
|
+
| `text` | Read-only text field (prompts, status) | `id`, `label`, `value`, `height` |
|
|
231
311
|
|
|
232
312
|
Slider and dial widgets both render as **`[widget] [−] [number input] [+]`**,
|
|
233
313
|
so you can drag, type a value directly, or nudge by `step`. The dial
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
314
|
+
uses a vertical pointer drag — drag up to increase — and the
|
|
315
|
+
`sensitivity` field controls how many units of value change one full
|
|
316
|
+
rotation covers. `sensitivity: 1.0` (default) maps one rotation to the
|
|
317
|
+
full `(max − min)` range; `sensitivity: 0.25` needs four rotations to
|
|
318
|
+
sweep the range for finer control.
|
|
237
319
|
|
|
238
|
-
The `format` field accepts Python-style `{:.Nf}` strings (e.g.
|
|
320
|
+
The `format` field accepts Python-style `{:.Nf}` strings (e.g.
|
|
321
|
+
`"{:.2f}"`). The `height` field is an optional multiplier on the
|
|
322
|
+
standard row height (default `1`) — e.g. `"height": 2` gives a dial
|
|
323
|
+
that's twice as tall (and therefore twice as wide), or a button with
|
|
324
|
+
twice the click target.
|
|
325
|
+
|
|
326
|
+
See [`examples/03_interactive_controls/`](examples/03_interactive_controls/)
|
|
327
|
+
for a runnable walkthrough of the full control palette.
|
|
239
328
|
|
|
240
329
|
---
|
|
241
330
|
|
|
@@ -243,10 +332,10 @@ The `format` field accepts Python-style `{:.Nf}` strings (e.g. `"{:.2f}"`).
|
|
|
243
332
|
|
|
244
333
|
Each entry in `initialize_plots` is one of:
|
|
245
334
|
|
|
246
|
-
- an **integer** — `client.initialize_plots(3)` → one plot with 3
|
|
247
|
-
traces
|
|
248
|
-
- a **string** — `client.initialize_plots("torque")` → one plot with
|
|
249
|
-
named trace
|
|
335
|
+
- an **integer** — `client.initialize_plots(3)` → one plot with 3
|
|
336
|
+
anonymous traces
|
|
337
|
+
- a **string** — `client.initialize_plots("torque")` → one plot with
|
|
338
|
+
one named trace
|
|
250
339
|
- a **list of strings** — one plot, one trace per name
|
|
251
340
|
- a **list of lists of strings** — one plot per sublist
|
|
252
341
|
- a **dict** — one plot, with full styling options (below)
|
|
@@ -258,20 +347,18 @@ A styled plot dict accepts any of:
|
|
|
258
347
|
|---|---|
|
|
259
348
|
| `names` | **Required.** List of trace names. |
|
|
260
349
|
| `colors` | List of per-trace colors. Single letter (`r g b c m y k w`) or any CSS color string. |
|
|
261
|
-
| `line_style` |
|
|
350
|
+
| `line_style` | Per-trace dash style. `"-"` means dashed; anything else is solid. |
|
|
262
351
|
| `line_width` | Per-trace line width in pixels. |
|
|
263
352
|
| `title` | Plot title. |
|
|
264
353
|
| `xlabel` / `ylabel` | Axis labels. |
|
|
265
354
|
| `yrange` | `[ymin, ymax]` — pins the Y axis and significantly speeds up rendering. |
|
|
266
355
|
| `xrange` | Integer number of samples visible at once (default 200). |
|
|
356
|
+
| `height` | Per-plot height multiplier (default `1.0`). Use `2` for a plot that's twice as tall as the others in the layout. |
|
|
267
357
|
|
|
268
358
|
Special row entries (not plots themselves):
|
|
269
359
|
|
|
270
360
|
- `{"controls": [...]}` — a row of interactive controls (see
|
|
271
361
|
[Interactive controls](#interactive-controls))
|
|
272
|
-
- `{"non_plot_labels": ["name1", "name2"]}` — extra scalar names that ride
|
|
273
|
-
along with `send_array` and get saved into the output Parquet file, but
|
|
274
|
-
aren't rendered as traces
|
|
275
362
|
|
|
276
363
|
---
|
|
277
364
|
|
|
@@ -290,38 +377,58 @@ without dropping frames.
|
|
|
290
377
|
|
|
291
378
|
---
|
|
292
379
|
|
|
293
|
-
##
|
|
380
|
+
## Static HTML snapshots
|
|
294
381
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
382
|
+
rtplot deliberately doesn't persist runs as a file format — it's a
|
|
383
|
+
live-plotting tool, not a data logger. When you do want a reproducible
|
|
384
|
+
artifact of what the plot looked like at a given moment, call:
|
|
298
385
|
|
|
299
|
-
|
|
386
|
+
```python
|
|
387
|
+
client.save_snapshot("preview.html", animate=True)
|
|
388
|
+
```
|
|
300
389
|
|
|
301
|
-
-
|
|
302
|
-
|
|
390
|
+
It writes a self-contained HTML file with uPlot JS + CSS inlined and
|
|
391
|
+
the current window of trace data embedded. Opens offline in any
|
|
392
|
+
browser, around 65 KB. Control widgets aren't captured — only the
|
|
393
|
+
plot portion — so the snapshot is the right artifact to commit to a
|
|
394
|
+
repo as a visual-regression baseline, attach to an email, or drop
|
|
395
|
+
into a GitHub Pages gallery. With `animate=True` the snapshot embeds
|
|
396
|
+
a small replay loop so the trace keeps scrolling (nicer for gallery
|
|
397
|
+
previews).
|
|
303
398
|
|
|
304
|
-
|
|
399
|
+
The `server_url` argument defaults to `http://localhost:8050`; set it
|
|
400
|
+
explicitly when snapshotting a remote server or one running on a
|
|
401
|
+
non-default `--port`.
|
|
305
402
|
|
|
306
|
-
|
|
307
|
-
python -m rtplot.server_browser -sd ./saved_plots -sn experiment1
|
|
308
|
-
```
|
|
403
|
+
---
|
|
309
404
|
|
|
310
|
-
|
|
311
|
-
- `-sn` / `--save-name` — filename prefix (a timestamp is always appended)
|
|
405
|
+
## Browser UI features
|
|
312
406
|
|
|
313
|
-
|
|
407
|
+
The browser tab isn't just a passive plot — the header bar and a
|
|
408
|
+
hamburger-menu settings panel give you live control over the server
|
|
409
|
+
without restarting it.
|
|
314
410
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
411
|
+
**Header controls**
|
|
412
|
+
|
|
413
|
+
| Element | What it does |
|
|
414
|
+
|---|---|
|
|
415
|
+
| Status pill | Live data rate + render rate (e.g. `Data 480 Hz · Render 60 Hz`). Turns red when the server marks the stream unhealthy. |
|
|
416
|
+
| `ZMQ …` indicator | Shows whether the server is currently **binding** (`ZMQ bind *:5555`) or **connecting outbound** (`ZMQ → host:port`). |
|
|
417
|
+
| IP input | Type a `host[:port]` to retarget before clicking **Connect**. |
|
|
418
|
+
| **Connect** / **Bind** buttons | Flip the server between *connect-to-a-sender* and *bind-and-wait* modes at runtime. The active mode is highlighted; the other is clickable. |
|
|
419
|
+
| WebSocket status | `connected` / `disconnected, retrying…` — for the browser-to-server link, not the ZMQ link. |
|
|
420
|
+
| **☰** menu button | Opens the Settings panel (below). |
|
|
421
|
+
|
|
422
|
+
**Settings panel (☰)**
|
|
423
|
+
|
|
424
|
+
| Setting | Meaning |
|
|
425
|
+
|---|---|
|
|
426
|
+
| UI font scale | 0.7× – 2.0× multiplier on every piece of browser-side text. Good for demos, projectors, and high-DPI screens. |
|
|
427
|
+
| Visible samples per plot | Overrides the declared `xrange` — lets a viewer zoom out or in without touching the sender script. |
|
|
428
|
+
| Max plot refresh rate | Caps repaints at N Hz. The panel reports the monitor's measured refresh rate via `requestAnimationFrame` calibration, so you know the ceiling. Leave blank to use the monitor Hz as the cap. |
|
|
321
429
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
will land in the Parquet file.
|
|
430
|
+
All settings are persisted in `localStorage`, so a refresh keeps your
|
|
431
|
+
preferences. The **Reset to defaults** button clears them.
|
|
325
432
|
|
|
326
433
|
---
|
|
327
434
|
|
|
@@ -329,7 +436,8 @@ will land in the Parquet file.
|
|
|
329
436
|
|
|
330
437
|
rtplot uses ZMQ, so either the sender or the plot host can be the one
|
|
331
438
|
that *binds* a socket. Pick whichever works for your network and
|
|
332
|
-
firewalls.
|
|
439
|
+
firewalls. You can also flip modes from the browser UI's **Bind** /
|
|
440
|
+
**Connect** buttons without restarting the server.
|
|
333
441
|
|
|
334
442
|
**Mode A — plot host binds, sender connects** *(typical for lab laptops)*
|
|
335
443
|
|
|
@@ -491,12 +599,15 @@ If you start running out of frames, try these, in roughly this order:
|
|
|
491
599
|
renderer skip autoscaling work and gives the single biggest win.
|
|
492
600
|
2. **Batch your samples.** Pass a 2-D numpy array to `send_array` so N
|
|
493
601
|
samples ship per call.
|
|
494
|
-
3. **
|
|
495
|
-
|
|
496
|
-
|
|
602
|
+
3. **Cap the plot refresh rate** from the browser's ☰ Settings menu.
|
|
603
|
+
The ring buffers keep accumulating samples; only the repaint rate
|
|
604
|
+
is throttled.
|
|
605
|
+
4. **Shrink the window.** Fewer pixels to redraw per frame.
|
|
606
|
+
5. **Reduce `line_width`.** Thicker lines cost more to rasterize.
|
|
607
|
+
6. **Use the `-n N` / `--skip N` server flag** to push every Nth sample
|
|
497
608
|
batch to the browser instead of every one. Add `-a` / `--adaptable`
|
|
498
609
|
to let the server tune `N` to your data rate automatically.
|
|
499
|
-
|
|
610
|
+
7. **Increase `xrange`.** Counterintuitively, a longer visible history
|
|
500
611
|
can be cheaper than a short one because the browser ring-buffers the
|
|
501
612
|
data and only replaces the tail on each push.
|
|
502
613
|
|
|
@@ -508,7 +619,7 @@ If you start running out of frames, try these, in roughly this order:
|
|
|
508
619
|
|
|
509
620
|
| Flag | Default | Meaning |
|
|
510
621
|
|---|---|---|
|
|
511
|
-
| `-p HOST[:PORT]` | (bind) | Connect to a sender at this address instead of binding |
|
|
622
|
+
| `-p HOST[:PORT]` / `--pi_ip` | (bind) | Connect to a sender at this address instead of binding |
|
|
512
623
|
| `--host HOST` | `0.0.0.0` | HTTP bind interface |
|
|
513
624
|
| `--port N` | `8050` | HTTP port |
|
|
514
625
|
| `--no-browser` | off | Don't try to open a browser on startup |
|
|
@@ -517,22 +628,55 @@ If you start running out of frames, try these, in roughly this order:
|
|
|
517
628
|
| `-a` / `--adaptable` | off | Auto-tune skip rate to data rate |
|
|
518
629
|
| `-c` / `--column` | row | Lay plots out in columns instead of rows |
|
|
519
630
|
| `-d` / `--debug` | off | Extra debug logging |
|
|
520
|
-
| `-sd DIR` / `--save-dir DIR` | cwd | Where to write `.parquet` saves |
|
|
521
|
-
| `-sn NAME` / `--save-name NAME` | — | Prefix for saved filenames |
|
|
522
631
|
|
|
523
632
|
---
|
|
524
633
|
|
|
525
|
-
##
|
|
634
|
+
## Client API reference
|
|
526
635
|
|
|
527
|
-
|
|
528
|
-
every `initialize_plots` signature, plus a controls demo at the bottom.
|
|
529
|
-
- [`rtplot/interactive_test.py`](rtplot/interactive_test.py) — a guided
|
|
530
|
-
end-to-end test that walks you through clicking buttons, dragging
|
|
531
|
-
sliders, typing into the number input, using the ± nudge arrows, and
|
|
532
|
-
spinning the dial. Good for smoke-testing a fresh install.
|
|
636
|
+
Every function below is imported from `rtplot.client`:
|
|
533
637
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
638
|
+
| Function | Purpose |
|
|
639
|
+
|---|---|
|
|
640
|
+
| `local_plot()` | Point the client at a server on `127.0.0.1:5555`. Shorthand for `configure_ip("127.0.0.1")`. |
|
|
641
|
+
| `plot_to_neurobionics_tv()` | Point at the lab's wall-display host (`141.212.77.23:5555`). |
|
|
642
|
+
| `configure_ip(ip)` | Connect to a server at `ip`, `host:port`, or a full `tcp://host:port` string. Also connects the control return-channel socket to `port+1`. |
|
|
643
|
+
| `configure_port(port)` | Rebind the local publisher to a different port (for senders running in bind mode). |
|
|
644
|
+
| `initialize_plots(desc)` | Declare the plot layout. Accepts int, str, dict, list-of-strings, list-of-lists, or list-of-dicts (see [Plot configuration](#plot-configuration)). |
|
|
645
|
+
| `send_array(A)` | Push one or more samples. Accepts float, list, 1-D numpy array, or 2-D `(num_traces, N)` numpy array. |
|
|
646
|
+
| `set_display(id, value)` | Update a `display` (numeric) or `text` (string) element. |
|
|
647
|
+
| `poll_controls()` | Drain the return channel non-blocking; returns `ControlState(values, buttons)`. |
|
|
648
|
+
| `save_snapshot(path, server_url=None, animate=False)` | Download a self-contained static HTML snapshot of the current plot to `path`. |
|
|
649
|
+
|
|
650
|
+
---
|
|
651
|
+
|
|
652
|
+
## Examples gallery
|
|
653
|
+
|
|
654
|
+
The [`examples/`](examples/) directory is a small, self-contained
|
|
655
|
+
gallery. Each folder has a `run.py` you can copy, a `README.md` that
|
|
656
|
+
explains what the code is teaching, and a pre-generated `snapshot.html`
|
|
657
|
+
you can open in a browser to see what the live plot looked like —
|
|
658
|
+
no server, no Python, no network required.
|
|
659
|
+
|
|
660
|
+
| Example | What it teaches |
|
|
661
|
+
|---|---|
|
|
662
|
+
| [`examples/01_hello_world/`](examples/01_hello_world/) | The minimum three client calls: `local_plot`, `initialize_plots`, `send_array`. One plot, one sine wave. |
|
|
663
|
+
| [`examples/02_multiple_subplots/`](examples/02_multiple_subplots/) | Multi-plot layouts, multi-trace plots, per-plot styling, flat-list `send_array`. Three subplots, four traces. |
|
|
664
|
+
| [`examples/03_interactive_controls/`](examples/03_interactive_controls/) | Buttons, sliders, dials, and display boxes that drive your Python loop live. |
|
|
665
|
+
|
|
666
|
+
To run any example, start the server in one terminal and `python run.py`
|
|
667
|
+
in another from inside the example's folder — see
|
|
668
|
+
[`examples/README.md`](examples/README.md) for details and the
|
|
669
|
+
regenerate-all-snapshots one-liner.
|
|
670
|
+
|
|
671
|
+
For an end-to-end smoke test of the full control palette (the gallery's
|
|
672
|
+
snapshots can't capture interactive widget state),
|
|
673
|
+
[`rtplot/interactive_test.py`](rtplot/interactive_test.py) walks a
|
|
674
|
+
human through clicking each button, dragging the slider to specific
|
|
675
|
+
values, typing into the number input, using the ± nudge arrows, and
|
|
676
|
+
spinning the dial:
|
|
677
|
+
|
|
678
|
+
```bash
|
|
679
|
+
python -m rtplot.server_browser &
|
|
680
|
+
python -m rtplot.interactive_test
|
|
681
|
+
```
|
|
538
682
|
|