Skip to content

Commit d8e7391

Browse files
committed
Add plot gallery to README with generated PNG examples
1 parent 350596a commit d8e7391

11 files changed

Lines changed: 158 additions & 1 deletion

File tree

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,20 @@ pserver.flush_queue()
5656

5757
More examples in the [`examples/`](examples/) directory.
5858

59+
## Plot Gallery
60+
61+
| Lines | Scatter | Histogram |
62+
|:---:|:---:|:---:|
63+
| ![Lines](docs/images/lines.png) | ![Scatter](docs/images/scatter.png) | ![Histogram](docs/images/histogram.png) |
64+
65+
| Error Bars | Filled Curves | Boxplot |
66+
|:---:|:---:|:---:|
67+
| ![Error Bars](docs/images/error_bars.png) | ![Filled Curves](docs/images/filled_curves.png) | ![Boxplot](docs/images/boxplot.png) |
68+
69+
| Heatmap | Multiplot |
70+
|:---:|:---:|
71+
| ![Heatmap](docs/images/heatmap.png) | ![Multiplot](docs/images/multiplot.png) |
72+
5973
## File System Monitor
6074

6175
The package also includes a cross-platform file system monitor based on

docs/images/boxplot.png

14.8 KB
Loading

docs/images/error_bars.png

15.5 KB
Loading

docs/images/filled_curves.png

20.3 KB
Loading

docs/images/heatmap.png

21.1 KB
Loading

docs/images/histogram.png

17.2 KB
Loading

docs/images/lines.png

79.5 KB
Loading

docs/images/multiplot.png

109 KB
Loading

docs/images/scatter.png

22.1 KB
Loading

scripts/generate_images.py

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
"""Generate PNG screenshots of each plot type for the README."""
2+
3+
from __future__ import annotations
4+
5+
import sys
6+
from pathlib import Path
7+
8+
import numpy as np
9+
10+
from liveplots.plotter import RTplot
11+
12+
OUT = Path(__file__).resolve().parent.parent / "docs" / "images"
13+
OUT.mkdir(parents=True, exist_ok=True)
14+
15+
SIZE = "set terminal pngcairo size 800,500 enhanced font 'Arial,12'"
16+
np.random.seed(42)
17+
18+
19+
def save(plotter: RTplot, name: str) -> None:
20+
plotter._write(f"set output '{OUT / name}'")
21+
plotter._gp.stdin.flush()
22+
print(f" saved {name}")
23+
24+
25+
def make_plotter() -> RTplot:
26+
p = RTplot(persist=0)
27+
p._write(SIZE)
28+
return p
29+
30+
31+
def gen_lines() -> None:
32+
p = make_plotter()
33+
save(p, "lines.png")
34+
x = np.linspace(0, 4 * np.pi, 200)
35+
data = [np.sin(x * f).tolist() for f in [0.5, 1.0, 1.5, 2.0]]
36+
p.lines(data, x.tolist(), ["0.5 Hz", "1 Hz", "1.5 Hz", "2 Hz"], "Sine Waves")
37+
38+
39+
def gen_scatter() -> None:
40+
p = make_plotter()
41+
save(p, "scatter.png")
42+
x = [np.random.normal(cx, 0.5, 100).tolist() for cx in [1, 4, 7]]
43+
y = [np.random.normal(cy, 0.5, 100).tolist() for cy in [1, 5, 2]]
44+
p.scatter(x, y, ["A", "B", "C"], "Three Clusters", jitter=False)
45+
46+
47+
def gen_histogram() -> None:
48+
p = make_plotter()
49+
save(p, "histogram.png")
50+
d1 = np.random.normal(0, 1, 2000).tolist()
51+
d2 = np.random.normal(2, 0.8, 2000).tolist()
52+
d3 = np.random.normal(-2, 1.5, 2000).tolist()
53+
p.histogram([d1, d2, d3], ["N(0,1)", "N(2,0.8)", "N(-2,1.5)"], "Three Distributions")
54+
55+
56+
def gen_error_bars() -> None:
57+
p = make_plotter()
58+
save(p, "error_bars.png")
59+
x = np.linspace(0, 10, 30)
60+
y = 2 * np.sin(x) + np.random.normal(0, 0.3, 30)
61+
err = 0.3 + 0.2 * np.random.rand(30)
62+
p.error_bars(
63+
x.tolist(),
64+
y.tolist(),
65+
err.tolist(),
66+
labels=["sensor"],
67+
title="Sensor Readings",
68+
)
69+
70+
71+
def gen_filled_curves() -> None:
72+
p = make_plotter()
73+
save(p, "filled_curves.png")
74+
x = np.linspace(0, 10, 200)
75+
mean = np.sin(x) * np.exp(-0.2 * x)
76+
lower = mean - 0.3 - 0.1 * x
77+
upper = mean + 0.3 + 0.1 * x
78+
p.filled_curves(
79+
x.tolist(),
80+
lower.tolist(),
81+
upper.tolist(),
82+
labels=["band"],
83+
title="Damped Sine ± Confidence",
84+
fill_color="purple",
85+
)
86+
87+
88+
def gen_boxplot() -> None:
89+
p = make_plotter()
90+
save(p, "boxplot.png")
91+
data = [
92+
np.random.normal(50, 5, 200).tolist(),
93+
np.random.normal(60, 10, 200).tolist(),
94+
np.random.normal(45, 8, 200).tolist(),
95+
np.random.normal(70, 3, 200).tolist(),
96+
np.random.normal(55, 15, 200).tolist(),
97+
]
98+
p.boxplot(data, labels=["A", "B", "C", "D", "E"], title="Benchmark Scores")
99+
100+
101+
def gen_heatmap() -> None:
102+
p = make_plotter()
103+
save(p, "heatmap.png")
104+
x = np.linspace(-4, 4, 80)
105+
y = np.linspace(-4, 4, 80)
106+
xx, yy = np.meshgrid(x, y, indexing="ij")
107+
matrix = np.exp(-((xx - 1) ** 2 + yy**2) / 2) + 0.5 * np.exp(
108+
-((xx + 2) ** 2 + (yy - 1) ** 2) / 1.0
109+
)
110+
p.heatmap(matrix.tolist(), title="Two Gaussian Bumps", colormap="hot")
111+
112+
113+
def gen_multiplot() -> None:
114+
p = make_plotter()
115+
save(p, "multiplot.png")
116+
data = [
117+
np.sin(np.linspace(0, f * 4 * np.pi, 100) + ph).tolist()
118+
for f, ph in zip([1, 2, 3, 4, 0.5, 1.5], [0, 1, 2, 3, 4, 5], strict=True)
119+
]
120+
p.lines(data, None, [f"ch{i}" for i in range(6)], "6-Channel Signal", "lines", 1)
121+
122+
123+
GENS = [
124+
("lines", gen_lines),
125+
("scatter", gen_scatter),
126+
("histogram", gen_histogram),
127+
("error_bars", gen_error_bars),
128+
("filled_curves", gen_filled_curves),
129+
("boxplot", gen_boxplot),
130+
("heatmap", gen_heatmap),
131+
("multiplot", gen_multiplot),
132+
]
133+
134+
135+
def main() -> None:
136+
for name, fn in GENS:
137+
print(f"Generating {name}...")
138+
fn()
139+
print(f"\nAll plots saved to {OUT}/")
140+
141+
142+
if __name__ == "__main__":
143+
sys.exit(main())

0 commit comments

Comments
 (0)