Skip to content

Commit 28d3504

Browse files
committed
New versions
1 parent d2ba9c3 commit 28d3504

File tree

2 files changed

+231
-6
lines changed

2 files changed

+231
-6
lines changed

README.md

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,79 @@
1-
# Awesome Code Template
1+
# Interactive Console-based Time Window Plotter
22

3-
This repository is a template with basic elements that every repository at Stratosphere should follow.
3+
Terminal Plotter is script that reads numeric data from a file (by default `data.txt`) and displays it as a live-updating plot in the terminal using [plotext](https://pypi.org/project/plotext/). The plot shows a moving time window (TW) of the data, and you can interactively adjust the window's size and position using keyboard controls.
44

55
## Features
66

7-
Write about what makes your [tool|code|data|repo] special.
7+
- **Live Plotting:**
8+
Continuously reads new data from a file and updates the plot in real time.
9+
10+
- **Moving Time Window:**
11+
Displays only the last X data points (a configurable "time window").
12+
13+
- **Interactive Controls:**
14+
Adjust the plot on the fly using these keys:
15+
- `k`: Increase window size by **1**
16+
- `K`: Increase window size by **100**
17+
- `j`: Decrease window size by **1** (minimum window size is 1)
18+
- `J`: Decrease window size by **100** (minimum window size is 1)
19+
- `h`: Move the window to older data (shift left) by the current window size
20+
- `H`: Move the window to older data by **100** points
21+
- `l`: Move the window to newer data (shift right) by the current window size
22+
- `L`: Move the window to newer data by **100** points
23+
- `q`: Quit the program
24+
25+
- **Auto-Scrolling:**
26+
When the plot is showing the latest data (the last TW), new data automatically scrolls into view.
27+
28+
- **Legend Display:**
29+
The plot includes a legend on top displaying the current time window length.
30+
31+
## Installation
32+
33+
1. **Python 3:**
34+
Ensure you have Python 3 installed on your Unix-like system (Linux, macOS). This script uses the `termios` and `tty` modules, which are available on Unix.
35+
36+
2. **Install Dependencies:**
37+
Install the `plotext` package using pip:
38+
```bash
39+
pip install plotext
40+
```
841

942
## Usage
43+
Run the script from your terminal. It supports several command-line options:
44+
45+
`python a.py [--window WINDOW] [--file FILE] [--interval INTERVAL]`
46+
47+
## Command-line Options
48+
`-w / --window`
49+
Set the initial number of points in the moving window (default: 10).
50+
51+
`-f / --file`
52+
Specify the path to the data file (default: data.txt).
53+
54+
`-i / --interval`
55+
Set the refresh interval in seconds (default: 2 seconds).
56+
57+
58+
## Example
59+
60+
### Run the script
61+
First, Run the script with a 20-point window, reading from mydata.txt, and updating every 1.5 seconds:
62+
63+
`python a.py --window 20 --file mydata.txt --interval 1.5`
64+
65+
66+
### Feeding Data to the Plot
67+
68+
The script reads numeric values from the data file—one value per line. To see the moving window effect, add data to the file using these example commands:
69+
70+
Test by appending single values by hand:
1071

11-
Write about how others can use your [tool|code|data|repo].
72+
```bash
73+
echo "3.14" >> data.txt
74+
echo "4" >> data.txt
75+
```
1276

13-
# About
77+
Test of plotting a ping command
1478

15-
This [tool|code|data|repo] was developed at the Stratosphere Laboratory at the Czech Technical University in Prague.
79+
`ping www.toyota.co |awk '{print $7; fflush()}'|awk -F'=' '{print $2; fflush()}' >> data.txt`

terminal-plotter.py

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import time
2+
import sys
3+
import select
4+
import tty
5+
import termios
6+
import argparse
7+
import plotext as plt
8+
9+
def get_key():
10+
"""Non-blocking read of a single key from stdin."""
11+
dr, _, _ = select.select([sys.stdin], [], [], 0)
12+
if dr:
13+
return sys.stdin.read(1)
14+
return None
15+
16+
def read_values(filename):
17+
"""Read a list of y-values (one per line) from the file."""
18+
y_vals = []
19+
try:
20+
with open(filename, "r") as file:
21+
for line in file:
22+
line = line.strip()
23+
if not line or line.startswith("#"):
24+
continue
25+
try:
26+
y_vals.append(float(line))
27+
except ValueError:
28+
print("Could not convert line:", line)
29+
except FileNotFoundError:
30+
print(f"File '{filename}' not found.")
31+
return y_vals
32+
33+
def parse_args():
34+
parser = argparse.ArgumentParser(
35+
description="Plot a moving window of data from a file with interactive control."
36+
)
37+
parser.add_argument(
38+
"-w", "--window", type=int, default=10,
39+
help="Initial number of points in the moving window (default: 10)"
40+
)
41+
parser.add_argument(
42+
"-f", "--file", type=str, default="data.txt",
43+
help="Path to the data file (default: data.txt)"
44+
)
45+
parser.add_argument(
46+
"-i", "--interval", type=float, default=2,
47+
help="Refresh interval in seconds (default: 2)"
48+
)
49+
return parser.parse_args()
50+
51+
def main():
52+
args = parse_args()
53+
filename = args.file
54+
window_size = args.window
55+
interval = args.interval
56+
57+
# offset is the starting index of the window in the data.
58+
# When auto-scrolling, offset is updated to show the newest data.
59+
offset = None
60+
# last_max_offset holds the maximum valid offset from the previous update.
61+
last_max_offset = None
62+
63+
# Save current terminal settings and set cbreak mode for immediate key reads.
64+
old_settings = termios.tcgetattr(sys.stdin)
65+
tty.setcbreak(sys.stdin.fileno())
66+
67+
# Clear the terminal once at startup.
68+
sys.stdout.write("\033[2J")
69+
sys.stdout.flush()
70+
71+
last_update = time.time()
72+
update_plot = False
73+
74+
try:
75+
while True:
76+
key = get_key()
77+
if key:
78+
if key == 'k':
79+
window_size += 1
80+
update_plot = True
81+
elif key == 'K':
82+
window_size += 100
83+
update_plot = True
84+
elif key == 'j':
85+
window_size = max(1, window_size - 1)
86+
update_plot = True
87+
elif key == 'J':
88+
window_size = max(1, window_size - 100)
89+
update_plot = True
90+
elif key == 'h':
91+
if offset is not None:
92+
offset = max(0, offset - window_size)
93+
update_plot = True
94+
elif key == 'H':
95+
if offset is not None:
96+
offset = max(0, offset - 100)
97+
update_plot = True
98+
elif key == 'l':
99+
if offset is not None:
100+
offset += window_size
101+
update_plot = True
102+
elif key == 'L':
103+
if offset is not None:
104+
offset += 100
105+
update_plot = True
106+
elif key == 'q':
107+
break
108+
109+
# Update the plot if enough time has passed or a key forced an update.
110+
if time.time() - last_update >= interval or update_plot:
111+
data = read_values(filename)
112+
if data:
113+
# Compute the maximum valid offset so that a full window is shown.
114+
new_max_offset = max(0, len(data) - window_size)
115+
# If offset is not set or we are auto-scrolling, update offset.
116+
if offset is None or (last_max_offset is not None and offset == last_max_offset):
117+
offset = new_max_offset
118+
else:
119+
# Clamp offset to valid range.
120+
if offset > new_max_offset:
121+
offset = new_max_offset
122+
last_max_offset = new_max_offset
123+
124+
window_data = data[offset: offset + window_size]
125+
x_vals = list(range(offset, offset + len(window_data)))
126+
127+
plt.clear_figure()
128+
plt.title("Moving Time Window Graph")
129+
plt.xlabel("Index")
130+
plt.ylabel("Value")
131+
plt.plot(x_vals, window_data, marker="dot", color="cyan")
132+
plt.grid(True)
133+
134+
# Prepare legend text showing TW length.
135+
legend_text = f"TW Length: {window_size}"
136+
# If the plot library supports legend(), use it.
137+
if hasattr(plt, "legend"):
138+
plt.legend([legend_text])
139+
else:
140+
# Otherwise, append the legend info to the title.
141+
plt.title("Moving Time Window Graph (" + legend_text + ")")
142+
else:
143+
plt.clear_figure()
144+
plt.title("No data available in file")
145+
146+
# Build the plot as a string and update display without flickering.
147+
plot_str = plt.build()
148+
sys.stdout.write("\033[H") # Move cursor to top-left.
149+
sys.stdout.write(plot_str)
150+
sys.stdout.flush()
151+
152+
last_update = time.time()
153+
update_plot = False
154+
155+
time.sleep(0.05)
156+
finally:
157+
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
158+
159+
if __name__ == "__main__":
160+
main()
161+

0 commit comments

Comments
 (0)