termplot 0.2.1 → 0.3.0

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/README.md +124 -54
  4. data/Rakefile +27 -14
  5. data/doc/dash.png +0 -0
  6. data/doc/demo.png +0 -0
  7. data/doc/file.png +0 -0
  8. data/doc/memory.png +0 -0
  9. data/doc/ping.png +0 -0
  10. data/doc/sin.png +0 -0
  11. data/doc/tcp.png +0 -0
  12. data/examples/sample.rb +17 -0
  13. data/lib/termplot/character_map.rb +15 -4
  14. data/lib/termplot/cli.rb +16 -3
  15. data/lib/termplot/colors.rb +7 -0
  16. data/lib/termplot/commands.rb +27 -0
  17. data/lib/termplot/consumers.rb +12 -0
  18. data/lib/termplot/consumers/base_consumer.rb +132 -0
  19. data/lib/termplot/consumers/command_consumer.rb +14 -0
  20. data/lib/termplot/consumers/multi_source_consumer.rb +33 -0
  21. data/lib/termplot/consumers/single_source_consumer.rb +36 -0
  22. data/lib/termplot/consumers/stdin_consumer.rb +11 -0
  23. data/lib/termplot/cursors/buffered_console_cursor.rb +1 -1
  24. data/lib/termplot/cursors/virtual_cursor.rb +4 -0
  25. data/lib/termplot/dsl/panels.rb +80 -0
  26. data/lib/termplot/dsl/widgets.rb +128 -0
  27. data/lib/termplot/file_config.rb +37 -0
  28. data/lib/termplot/message_broker.rb +108 -0
  29. data/lib/termplot/options.rb +100 -20
  30. data/lib/termplot/positioned_widget.rb +8 -0
  31. data/lib/termplot/producer_options.rb +3 -0
  32. data/lib/termplot/producers.rb +3 -3
  33. data/lib/termplot/producers/base_producer.rb +12 -15
  34. data/lib/termplot/producers/command_producer.rb +25 -9
  35. data/lib/termplot/producers/stdin_producer.rb +1 -4
  36. data/lib/termplot/renderable.rb +35 -0
  37. data/lib/termplot/renderer.rb +16 -257
  38. data/lib/termplot/renderers.rb +6 -0
  39. data/lib/termplot/renderers/border_renderer.rb +48 -0
  40. data/lib/termplot/renderers/text_renderer.rb +73 -0
  41. data/lib/termplot/shell.rb +13 -9
  42. data/lib/termplot/utils/ansi_safe_string.rb +68 -0
  43. data/lib/termplot/version.rb +1 -1
  44. data/lib/termplot/widget_dsl.rb +130 -0
  45. data/lib/termplot/widgets.rb +8 -0
  46. data/lib/termplot/widgets/base_widget.rb +79 -0
  47. data/lib/termplot/widgets/border.rb +6 -0
  48. data/lib/termplot/widgets/dataset.rb +50 -0
  49. data/lib/termplot/widgets/histogram_widget.rb +196 -0
  50. data/lib/termplot/widgets/statistics.rb +21 -0
  51. data/lib/termplot/widgets/statistics_widget.rb +104 -0
  52. data/lib/termplot/widgets/time_series_widget.rb +248 -0
  53. data/lib/termplot/window.rb +25 -5
  54. data/termplot.gemspec +1 -6
  55. metadata +36 -24
  56. data/doc/MSFT.png +0 -0
  57. data/doc/cpu.png +0 -0
  58. data/doc/demo.cast +0 -638
  59. data/lib/termplot/consumer.rb +0 -75
  60. data/lib/termplot/cursors/console_cursor.rb +0 -57
  61. data/lib/termplot/series.rb +0 -37
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: af619edab0c7e963e4c03ba538d48ade05230afe5ef6e1572d39beffc4c56840
4
- data.tar.gz: 1b138486f66e7db0423d27ffb25656486579cdf918d05d5744a24a14c42f7525
3
+ metadata.gz: dda87efbf9aed716a37a8ca65eab2d8f773f9e4a18ea9db6ab7aff4dc820c2ff
4
+ data.tar.gz: 82a897c92653354d77de8515cd370507aaba295f9a35425134af1a0752fb6d2a
5
5
  SHA512:
6
- metadata.gz: 4550da91464682e063918b5655e27f14fcebae4d17905c6bb7584eed545030fa4212e43ce32d659cd53b10795aa1c8ffded70bdde53eca5400413b6aa65702d8
7
- data.tar.gz: e41b6eae186fb4ce0dc69a2fb2851b96addc211f7304512ea6139d9588dc2e305ba9dcb382d96389ebe1783d865719ee6bdfa54619a2b1fa9dd772bc70fc6aed
6
+ metadata.gz: 16969163d4b669fd5cf930310af369aaa6e4a83d25e16bd51ba528d1ebb71c303d1beead130f4a9ef6d39992f7c92017fc149b2dbf0fcd46be6c0df15ed9b760
7
+ data.tar.gz: d509eeb9d34180fe4b338de314bcab5060e9f25a9d63d1ad4ff04e137c4d3b282209df7ff660a74a30e82c663d2eedd96fcc3d1204d8f3e16bf88d0ea47f1e76
data/.gitignore CHANGED
@@ -8,3 +8,4 @@
8
8
 
9
9
  squiggles.txt
10
10
  Gemfile.lock
11
+ README.md.html
data/README.md CHANGED
@@ -2,15 +2,13 @@
2
2
 
3
3
  Termplot is a simple terminal plotting tool for visualising streaming data.
4
4
 
5
- See the demo on Asciinema:
6
-
7
- [![Termplot Demo Asciicast](https://asciinema.org/a/370325.svg)](https://asciinema.org/a/3rzeUSXp2fRjnErX0p3SptP5e)
5
+ ![Termplot Demo Image](doc/demo.png)
8
6
 
9
7
  ## Overview
10
8
 
11
- Termplot draws trendlines of data piped into the command from standard input.
12
- It's handy for quickly visualising streaming data in your terminal and works
13
- with any numeric data you can pipe into stdin.
9
+ Termplot draws live plots of data in your terminal. It's handy for quickly
10
+ visualising streaming data and works with any numeric data you can pipe into
11
+ stdin or otherwise obtain by running a shell command.
14
12
 
15
13
  ## Installation
16
14
 
@@ -20,87 +18,156 @@ The tool is a ruby gem and can be installed with:
20
18
 
21
19
  ## Usage
22
20
 
23
- The basic usage is simple:
21
+ There are 3 ways to provide input to termplot:
22
+ - **Stdin:** Pipe data into standard input
23
+ - **Command:** Specify a command to be ran at an interval
24
+ - **Configuration file:** Read a multi-chart configuration from a file
24
25
 
26
+ ### Pipe data into standard input
25
27
  ```
26
- {command} | termplot [OPTIONS]
28
+ COMMAND | termplot [OPTIONS]
27
29
  ```
28
30
 
29
- `{command}` is any command that will periodically output numbers to standard out
30
- delimited by a newline. You can also instead specify a command to run at a given
31
- interval to produce the data.
32
-
33
- Options and examples are given below. All command line options are
34
- optional.
31
+ `COMMAND` is any command that will periodically output numbers to standard out
32
+ delimited by a newline. These will be consumed by termplot and drawn to a chart.
35
33
 
34
+ You can specify the following options (all are optional):
35
+ ```
36
+ -r, --rows ROWS Number of rows in the chart window (default: 19)
37
+ -c, --cols COLS Number of cols in the chart window (default: 100)
38
+ --full-screen Render to the full available terminal size
39
+
40
+ --type TYPE The type of chart to render.
41
+ Options are: timeseries (default), stats, hist
42
+
43
+ --timeseries Shorthand for --type timeseries
44
+ --stats Shorthand for --type stats
45
+ --hist Shorthand for --type hist
46
+
47
+ -t, --title TITLE Title of the series (default: 'Series')
48
+ --color COLOR Series color, specified as ansi 16-bit color name:
49
+ (i.e. black, light_black, red, light_red,
50
+ green (default), light_green, yellow,
51
+ light_yellow, blue, light_blue, magenta,
52
+ light_magenta, cyan, light_cyan, white,
53
+ light_white, default)
54
+
55
+ --line-style STYLE Line style.
56
+ Options are: line, heavy-line (default), dot, star, x, bar
36
57
  ```
37
- Usage: termplot [OPTIONS]
38
- -r, --rows ROWS Number of rows in the chart window (default: 19)
39
58
 
40
- -c, --cols COLS Number of cols in the chart window (default: 80)
59
+ #### Examples
41
60
 
42
- -t, --title TITLE Title of the series (default: 'Series')
61
+ ##### Plot a sine wave from standard in:
43
62
 
44
- --line-style STYLE Line style. Options are: line (default), heavy-line, dot, star, x
63
+ ```
64
+ for i in $(seq 500); do \
65
+ echo $i | awk '{ print sin($0/10) }'; \
66
+ sleep 0.5; \
67
+ done | termplot -t "Sin(x)" --color red
68
+ ```
69
+ ![Sine Wave Plot](doc/sin.png)
45
70
 
46
- --color COLOR Series color, specified as ansi 16-bit color name:
47
- (i.e. black, light_black, red (default), light_red, green,
48
- light_green, yellow, light_yellow, blue, light_blue, magenta,
49
- light_magenta, cyan, light_cyan, white, light_white, default)
71
+ ##### Plot histogram of network times as reported by `ping`:
72
+ ```
73
+ ping example.com |
74
+ awk '{ split($8,arr,"="); print arr[2]; fflush("/dev/stdout") }' |
75
+ termplot -t "Ping Response Times (ms)" --hist
76
+ ```
77
+ ![Ping Response Times Plot](doc/ping.png)
50
78
 
51
- --command COMMAND Enables command mode, where input is received by executing
52
- the specified command in intervals rather than from stdin
79
+ ##### Plot histogram of data from column 33 of a CSV file
80
+ ```
81
+ cat file.csv | cut -d, -f33 | tail -n +2 |
82
+ termplot -- --hist -r30 -t "Data" --color light_black
83
+ ```
84
+ ![File Data Plot](doc/file.png)
53
85
 
54
- --interval INTERVAL The interval at which to run the specified command in
55
- command mode in milliseconds (default: 1000)
56
86
 
57
- -h, --help Display this help message
87
+ ### Run command at an interval
88
+ To run a command at an interval, specify `--command`, and optionally
89
+ `--interval` to termplot:
90
+ ```
91
+ termplot --command 'COMMAND' --interval INTERVAL [OPTIONS]
58
92
  ```
59
- Note: Make sure to wrap your command in single quotes when using `--command` if
60
- you use shell variables (e.g. `$1`) in your command.
61
93
 
62
- ## Examples
94
+ `COMMAND` will be invoked at the specified interval in milliseconds (default:
95
+ 1000) and its output will be used as the data for the chart. You can specify all
96
+ the same additional options as in stdin mode above.
63
97
 
64
- #### Sine wave
98
+ #### Examples
99
+ ##### Plot number of TCP connections over time:
65
100
 
66
101
  ```
67
- for i in $(seq 500); do \
68
- echo $i | awk '{ print sin($0/10) }'; \
69
- sleep 0.5; \
70
- done | termplot -t "Sin(x)"
102
+ termplot --command 'ss -s | head -n1 | cut -d" " -f2' \
103
+ --interval 500 -t "TCP Connections"
71
104
  ```
72
- ![Sine Wave Plot](doc/sin.png)
105
+ ![TCP Connections Plot](doc/tcp.png)
106
+
107
+ ##### Plot memory usage of process with PID 4396:
73
108
 
74
- #### Memory usage (%)
75
109
  ```
76
- termplot --command 'free | awk "NR==2 { print ($3/$2) * 100 }"' \
77
- -t "Memory (% used)" --color light_magenta --line-style heavy-line
110
+ termplot --command "ps -q 4396 -o rss= | awk '{ print (\$0/1024.0) }'" \
111
+ -t "Process 4396 Memory (MB)" --color light_magenta
78
112
  ```
79
- ![Free Memory % Chart](doc/memory.png)
113
+ ![Process Memory Plot](doc/memory.png)
80
114
 
81
- #### Real time stock ticker
115
+ ### Specify a multi-chart configuration
116
+ You can configure termplot to set up a multi-chart dashboard using a ruby
117
+ configuration file:
82
118
 
83
- (Using [ticker.sh](https://github.com/pstadler/ticker.sh)) 😉:
119
+ ```
120
+ termplot --file FILE
121
+ ```
84
122
 
123
+ The configuration file uses a simple ruby DSL to arrange charts into rows and
124
+ columns. Each chart will take a command and optionally an interval as well as
125
+ formatting options. Termplot will then run the command at the specified interval
126
+ and render the resulting data into the charts.
127
+
128
+ Example file (sample.rb):
129
+ ```ruby
130
+ col do
131
+ row do
132
+ cpu_command =
133
+ "top -b -n 1 | awk -F',' 'NR==3{ split($4, arr, \" \"); print 100.0 - arr[1] }'"
134
+
135
+ histogram title: "CPU (%)", command: cpu_command, color: "light_cyan"
136
+ timeseries title: "CPU (%)", command: cpu_command, color: "light_cyan"
137
+ statistics title: "CPU (%)", command: cpu_command
138
+ end
139
+
140
+ row do
141
+ memory_command = "free | awk 'NR==2 { print ($3/$2) * 100 }'"
142
+
143
+ histogram title: "Memory (%)", command: memory_command, color: "light_magenta"
144
+ timeseries title: "Memory (%)", command: memory_command, color: "light_magenta"
145
+ statistics title: "Memory (%)", command: memory_command
146
+ end
147
+ end
148
+ ```
149
+ Run it with:
85
150
  ```
86
- termplot --command 'NO_COLOR=1 ticker.sh MSFT | awk "{ print $2 }"' \
87
- --interval 10000 -t "MSFT" --color light_green
151
+ termplot -f sample.rb --cols 150 --rows 20
88
152
  ```
89
- ![MSFT ticker chart](doc/MSFT.png)
153
+
154
+ Result:
155
+ ![CPU_Ram_dashboard](doc/dash.png)
156
+
90
157
 
91
158
  ## Notes
92
159
 
93
- - The command should work just fine if you have a monospaced unicode font.
160
+ - Termplot should work just fine if you have a monospaced unicode font.
94
161
  Tested on linux, and should work on MacOS too. Not too sure about windows.
95
- - The samples received are plotted in sequence order, and there is no notion of
96
- temporal spacing. So even if the time between samples is inconsistent, they
97
- will be plotted with the same amount of space between them.
162
+ - On timeseries plots, samples received are plotted in sequence order, and there
163
+ is no notion of temporal spacing. So even if the time between samples is
164
+ inconsistent, they will be plotted with the same amount of space between them.
98
165
 
99
- ## Background
166
+ ## Background
100
167
 
101
- I recently needed to be able to monitor the number of open TCP connections on my
102
- linux machine. I could get the data I needed from `ss` with some text processing
103
- but I didn't have a quick and easy way to eyeball the overall trend.
168
+ A while back I needed to be able to monitor the number of open TCP connections
169
+ on my linux machine. I could get the data I needed from `ss` with some text
170
+ processing but I didn't have a quick and easy way to eyeball the overall trend.
104
171
 
105
172
  I mainly work with ruby, so taking
106
173
  inspiration from fantastic libraries like [Unicode Plots
@@ -116,6 +183,9 @@ termplot --command 'ss -s | head -n1 | cut -d" " -f2' --interval 500 -t "TCP Con
116
183
 
117
184
  ![TCP Connections](doc/tcp.png)
118
185
 
186
+ In the end termplot turned out to be useful for all sorts of command line
187
+ visualisation tasks.
188
+
119
189
  ## Development
120
190
 
121
191
  After checking out the repo, run `bin/setup` to install dependencies. There are
data/Rakefile CHANGED
@@ -1,20 +1,33 @@
1
+ require_relative "./lib/termplot/commands"
1
2
  require "bundler/gem_tasks"
2
3
 
3
- task :bin do
4
- exec "ruby", "-Ilib", "bin/termplot", *ARGV[2..-1]
5
- end
4
+ extend Termplot::Commands
5
+ extend Termplot::StdinCommands
6
6
 
7
- task :sin_test do
8
- cmd = <<-CMD
9
- for i in $(seq 5000);
10
- do
11
- echo $i | awk '{ print sin($0/10)* 10; fflush("/dev/stdout") }';
12
- sleep 0.1;
13
- done | ruby -Ilib bin/termplot -- -t 'sin(x)'
14
- CMD
15
- exec cmd
7
+ SAMPLE_FILES_PATH = "examples"
8
+ def termplot_binary
9
+ "ruby -Ilib bin/termplot"
16
10
  end
17
11
 
18
- task :command_test do
19
- exec "ruby -Ilib bin/termplot --command 'echo $RANDOM' --interval 900"
12
+ namespace :test do
13
+ task :bin do
14
+ exec "ruby", "-Ilib", "bin/termplot", *ARGV[2..-1]
15
+ end
16
+
17
+ task :file do
18
+ cmd = %( #{termplot_binary} -f #{File.join(SAMPLE_FILES_PATH, ARGV[2])} #{ARGV[3..-1].join(" ")})
19
+ exec cmd
20
+ end
21
+
22
+ namespace :timeseries do
23
+ task :sin do
24
+ cmd = "#{sin(500)} | #{termplot_binary} -t 'sin(x)'"
25
+ exec cmd
26
+ end
27
+
28
+ task :random do
29
+ cmd = %( #{termplot_binary} --command '#{random}' --interval 900% )
30
+ exec cmd
31
+ end
32
+ end
20
33
  end
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,17 @@
1
+ col do
2
+ row do
3
+ cpu_command = "top -b -n 1 | awk -F',' 'NR==3{ split($4, arr, \" \"); print 100.0 - arr[1] }'"
4
+
5
+ histogram title: "CPU (%)", command: cpu_command, color: "light_cyan"
6
+ timeseries title: "CPU (%)", command: cpu_command, color: "light_cyan"
7
+ statistics title: "CPU (%)", command: cpu_command
8
+ end
9
+
10
+ row do
11
+ memory_command = "free | awk 'NR==2 { print ($3/$2) * 100 }'"
12
+
13
+ histogram title: "Memory (%)", command: memory_command, color: "light_magenta"
14
+ timeseries title: "Memory (%)", command: memory_command, color: "light_magenta"
15
+ statistics title: "Memory (%)", command: memory_command
16
+ end
17
+ end
@@ -12,7 +12,9 @@ module Termplot
12
12
  top_left: "┌",
13
13
  bot_right: "┘",
14
14
  tick_right: "┤",
15
- extended: true
15
+ tick_left: "├",
16
+ extended: true,
17
+ filled: false
16
18
  }
17
19
  DEFAULT = LINE
18
20
 
@@ -26,13 +28,15 @@ module Termplot
26
28
  top_right: "┓",
27
29
  top_left: "┏",
28
30
  bot_right: "┛",
29
- tick_right: "┫"
31
+ tick_right: "┫",
32
+ tick_left: "┣",
30
33
  )
31
34
 
32
35
  BASIC = {
33
36
  empty: " ",
34
37
  point: "•",
35
- extended: false
38
+ extended: false,
39
+ filled: false
36
40
  }
37
41
  DOTS = BASIC
38
42
 
@@ -44,12 +48,19 @@ module Termplot
44
48
  point: "*"
45
49
  )
46
50
 
51
+ BAR = LINE.merge(
52
+ point: "▄",
53
+ extended: false,
54
+ filled: true
55
+ )
56
+
47
57
  LINE_STYLES = {
48
58
  "line" => LINE,
49
59
  "heavy-line" => HEAVY_LINE,
50
60
  "dot" => DOTS,
51
61
  "star" => STAR,
52
- "x" => X
62
+ "x" => X,
63
+ "bar" => BAR,
53
64
  }
54
65
  end
55
66
  end
@@ -1,12 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
  require "termplot/options"
3
- require "termplot/consumer"
3
+ require "termplot/consumers"
4
4
 
5
5
  module Termplot
6
6
  class CLI
7
7
  def self.run
8
- opts = Options.new.parse_options!
9
- Consumer.new(opts).run
8
+ options = Termplot::Options.new
9
+ options.parse_options!
10
+ run_consumer(options)
11
+ end
12
+
13
+ private
14
+
15
+ CONSUMERS = {
16
+ file: "Termplot::Consumers::MultiSourceConsumer",
17
+ command: "Termplot::Consumers::CommandConsumer",
18
+ stdin: "Termplot::Consumers::StdinConsumer",
19
+ }
20
+ def self.run_consumer(options)
21
+ consumer = Object.const_get(CONSUMERS[options.input_mode])
22
+ consumer.new(options).run
10
23
  end
11
24
  end
12
25
  end
@@ -35,6 +35,9 @@ module Termplot
35
35
  define_method(color) do |str|
36
36
  escape_color(color) + str + escape_mode(:default)
37
37
  end
38
+ define_method("#{color}_bg") do |str|
39
+ escape_bg_color(color) + str + escape_mode(:default)
40
+ end
38
41
  end
39
42
 
40
43
  def fetch(color, default)
@@ -47,6 +50,10 @@ module Termplot
47
50
  "\e[#{COLORS[color] + 30}m"
48
51
  end
49
52
 
53
+ def escape_bg_color(color)
54
+ "\e[#{COLORS[color] + 40}m"
55
+ end
56
+
50
57
  def escape_mode(mode)
51
58
  "\e[#{MODES[mode]}m"
52
59
  end
@@ -0,0 +1,27 @@
1
+ module Termplot
2
+ module Commands
3
+ def random
4
+ "echo $RANDOM"
5
+ end
6
+
7
+ def memory
8
+ "free | awk 'NR==2 { print ($3/$2) * 100 }'"
9
+ end
10
+
11
+ def cpu
12
+ "top -b -n 1 | awk -F',' 'NR==3{ split($4, arr, \" \"); print 100.0 - arr[1] }'"
13
+ end
14
+ end
15
+
16
+ module StdinCommands
17
+ def sin(n)
18
+ <<-CMD.chomp
19
+ for i in $(seq #{n});
20
+ do
21
+ echo $i | awk '{ print sin($0/10)* 10; fflush("/dev/stdout") }';
22
+ sleep 0.1;
23
+ done
24
+ CMD
25
+ end
26
+ end
27
+ end