youplot 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d270d30bd2d7d0766d6e26704383ec25fd742d2ed12b8e3738f91c985e2b4f80
4
+ data.tar.gz: '01149b5a5bd05dbbfc544e207ea4345c602468f68e39d3965025c4f7c1ddb13f'
5
+ SHA512:
6
+ metadata.gz: 80c2894983ca5cc3a9e9833a95f7d11a8928db454fecc0b97b585a4903dd0ae77cf89a1929dc4cb526dc6e7b0f8b0019d5d0769ab6f1a63ab4acb3db8a125c35
7
+ data.tar.gz: 4c6b532a8b95ab2b9ba8aa5def4b368edd93fe5e9af224d1f7fc4f87a4b40d0a07cf7f874565c10f7630d257e393fb8175ec087e6da9e4740b4e31e76c3d1d12
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 kojix2
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
13
+ all 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
21
+ THE SOFTWARE.
@@ -0,0 +1,148 @@
1
+ # YouPlot
2
+
3
+ ![Build Status](https://github.com/kojix2/youplot/workflows/test/badge.svg)
4
+ [![Gem Version](https://badge.fury.io/rb/youplot.svg)](https://badge.fury.io/rb/youplot)
5
+ [![Docs Latest](https://img.shields.io/badge/docs-latest-blue.svg)](https://rubydoc.info/gems/youplot)
6
+ [![The MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.txt)
7
+
8
+ Create ASCII charts on the terminal with data from standard streams in the pipeline.
9
+
10
+ :bar_chart: Powered by [UnicodePlot](https://github.com/red-data-tools/unicode_plot.rb)
11
+
12
+ ## Installation
13
+
14
+ ```
15
+ gem install youplot
16
+ ```
17
+
18
+ ## Screenshots
19
+
20
+ **histogram**
21
+
22
+ ```sh
23
+ ruby -r numo/narray -e "puts Numo::DFloat.new(1000).rand_norm.to_a" \
24
+ | uplot hist --nbins 15
25
+ ```
26
+
27
+ <img src="https://i.imgur.com/wpsoGJq.png" width="75%" height="75%">
28
+
29
+ ```sh
30
+ echo -e "from numpy import random;" \
31
+ "n = random.randn(10000);" \
32
+ "print('\\\n'.join(str(i) for i in n))" \
33
+ | python \
34
+ | uplot hist --nbins 20
35
+ ```
36
+
37
+ <img src="https://i.imgur.com/97R2MQx.png" width="75%" height="75%">
38
+
39
+ **scatter**
40
+
41
+ ```sh
42
+ curl -s https://raw.githubusercontent.com/uiuc-cse/data-fa14/gh-pages/data/iris.csv \
43
+ | cut -f1-4 -d, \
44
+ | uplot scatter -H -d, -t IRIS
45
+ ```
46
+
47
+ <img src="https://i.imgur.com/STX7bFT.png" width="75%" height="75%">
48
+
49
+ **line**
50
+
51
+ ```sh
52
+ curl -s https://www.mhlw.go.jp/content/pcr_positive_daily.csv \
53
+ | cut -f2 -d, \
54
+ | uplot line -w 50 -h 15 -t 'PCR positive tests' --xlabel Date --ylabel number
55
+ ```
56
+
57
+ <img src="https://i.imgur.com/PVl5dsa.png" width="75%" height="75%">
58
+
59
+ **box**
60
+
61
+ ```sh
62
+ curl -s https://raw.githubusercontent.com/uiuc-cse/data-fa14/gh-pages/data/iris.csv \
63
+ | cut -f1-4 -d, \
64
+ | uplot box -H -d, -t IRIS
65
+ ```
66
+
67
+ <img src="https://i.imgur.com/sNI4SmN.png" width="75%" height="75%">
68
+
69
+ **colors**
70
+
71
+ ```sh
72
+ uplot colors
73
+ ```
74
+
75
+ <img src="https://i.imgur.com/LxyHQsz.png">
76
+
77
+ ## Usage
78
+
79
+ `uplot --help`
80
+
81
+ ```
82
+ Program: YouPlot (Tools for plotting on the terminal)
83
+ Version: 0.2.7 (using UnicodePlot 0.0.4)
84
+ Source: https://github.com/kojix2/youplot
85
+
86
+ Usage: uplot <command> [options] <in.tsv>
87
+
88
+ Commands:
89
+ barplot bar
90
+ histogram hist
91
+ lineplot line
92
+ lineplots lines
93
+ scatter s
94
+ density d
95
+ boxplot box
96
+ colors show the list of available colors
97
+
98
+ count c baplot based on the number of occurrences
99
+ (slower than `sort | uniq -c | sort -n -k1`)
100
+
101
+ Options:
102
+ -O, --pass [VAL] file to output standard input data to [stdout]
103
+ for inserting YouPlot in the middle of Unix pipes
104
+ -o, --output VAL file to output results to [stderr]
105
+ -d, --delimiter VAL use DELIM instead of TAB for field delimiter
106
+ -H, --headers specify that the input has header row
107
+ -T, --transpose transpose the axes of the input data
108
+ -t, --title VAL print string on the top of plot
109
+ -x, --xlabel VAL print string on the bottom of the plot
110
+ -y, --ylabel VAL print string on the far left of the plot
111
+ -w, --width VAL number of characters per row
112
+ -h, --height VAL number of rows
113
+ -b, --border VAL specify the style of the bounding box
114
+ -m, --margin VAL number of spaces to the left of the plot
115
+ -p, --padding VAL space of the left and right of the plot
116
+ -c, --color VAL color of the drawing
117
+ --[no-]labels hide the labels
118
+ --fmt VAL xyxy : header is like x1, y1, x2, y2, x3, y3...
119
+ xyy : header is like x, y1, y2, y2, y3...
120
+ ```
121
+
122
+ Use `--help` to print command-specific options.
123
+
124
+ `uplot hist --help`
125
+
126
+ ```
127
+ Usage: uplot histogram [options] <in.tsv>
128
+
129
+ Options for histogram:
130
+ --symbol VAL character to be used to plot the bars
131
+ --closed VAL
132
+ -n, --nbins VAL approximate number of bins
133
+
134
+ Options:
135
+ ...
136
+ ```
137
+
138
+ ## Development
139
+
140
+ Let's keep it simple.
141
+
142
+ ## Contributing
143
+
144
+ Bug reports and pull requests are welcome on GitHub at [https://github.com/kojix2/youplot](https://github.com/kojix2/youplot).
145
+
146
+ ## License
147
+
148
+ [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'youplot'
5
+
6
+ YouPlot::Command.new.run
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'youplot'
5
+
6
+ YouPlot::Command.new.run
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'unicode_plot'
4
+ require 'youplot/version'
5
+ require 'youplot/preprocessing'
6
+ require 'youplot/command'
7
+
8
+ module YouPlot
9
+ end
@@ -0,0 +1,167 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'unicode_plot'
4
+
5
+ module YouPlot
6
+ # plotting functions.
7
+ module Backends
8
+ module UnicodePlotBackend
9
+ module_function
10
+
11
+ def barplot(data, params, count: false)
12
+ headers = data.headers
13
+ series = data.series
14
+ # `uplot count`
15
+ if count
16
+ series = Preprocessing.count_values(series[0])
17
+ params.title = headers[0] if headers
18
+ end
19
+ if series.size == 1
20
+ # If there is only one series, use the line number for label.
21
+ params.title ||= headers[0] if headers
22
+ labels = Array.new(series[0].size) { |i| (i + 1).to_s }
23
+ values = series[0].map(&:to_f)
24
+ else
25
+ params.title ||= headers[1] if headers
26
+ labels = series[0]
27
+ values = series[1].map(&:to_f)
28
+ end
29
+ UnicodePlot.barplot(labels, values, **params.to_hc)
30
+ end
31
+
32
+ def histogram(data, params)
33
+ headers = data.headers
34
+ series = data.series
35
+ params.title ||= data.headers[0] if headers
36
+ values = series[0].map(&:to_f)
37
+ UnicodePlot.histogram(values, **params.to_hc)
38
+ end
39
+
40
+ def line(data, params)
41
+ headers = data.headers
42
+ series = data.series
43
+ if series.size == 1
44
+ # If there is only one series, it is assumed to be sequential data.
45
+ params.ylabel ||= headers[0] if headers
46
+ y = series[0].map(&:to_f)
47
+ UnicodePlot.lineplot(y, **params.to_hc)
48
+ else
49
+ # If there are 2 or more series,
50
+ # assume that the first 2 series are the x and y series respectively.
51
+ if headers
52
+ params.xlabel ||= headers[0]
53
+ params.ylabel ||= headers[1]
54
+ end
55
+ x = series[0].map(&:to_f)
56
+ y = series[1].map(&:to_f)
57
+ UnicodePlot.lineplot(x, y, **params.to_hc)
58
+ end
59
+ end
60
+
61
+ def get_method2(method1)
62
+ "#{method1}!".to_sym
63
+ end
64
+
65
+ def plot_xyy(data, method1, params)
66
+ headers = data.headers
67
+ series = data.series
68
+ method2 = get_method2(method1)
69
+ series.map! { |s| s.map(&:to_f) }
70
+ if headers
71
+ params.name ||= headers[1]
72
+ params.xlabel ||= headers[0]
73
+ end
74
+ params.ylim ||= series[1..-1].flatten.minmax # why need?
75
+ plot = UnicodePlot.public_send(method1, series[0], series[1], **params.to_hc)
76
+ 2.upto(series.size - 1) do |i|
77
+ UnicodePlot.public_send(method2, plot, series[0], series[i], name: headers&.[](i))
78
+ end
79
+ plot
80
+ end
81
+
82
+ def plot_xyxy(data, method1, params)
83
+ headers = data.headers
84
+ series = data.series
85
+ method2 = get_method2(method1)
86
+ series.map! { |s| s.map(&:to_f) }
87
+ series = series.each_slice(2).to_a
88
+ params.name ||= headers[0] if headers
89
+ params.xlim = series.map(&:first).flatten.minmax # why need?
90
+ params.ylim = series.map(&:last).flatten.minmax # why need?
91
+ x1, y1 = series.shift
92
+ plot = UnicodePlot.public_send(method1, x1, y1, **params.to_hc)
93
+ series.each_with_index do |(xi, yi), i|
94
+ UnicodePlot.public_send(method2, plot, xi, yi, name: headers&.[]((i + 1) * 2))
95
+ end
96
+ plot
97
+ end
98
+
99
+ def plot_fmt(data, fmt, method1, params)
100
+ case fmt
101
+ when 'xyy'
102
+ plot_xyy(data, method1, params)
103
+ when 'xyxy'
104
+ plot_xyxy(data, method1, params)
105
+ else
106
+ raise "Unknown format: #{fmt}"
107
+ end
108
+ end
109
+
110
+ def lines(data, params, fmt = 'xyy')
111
+ check_series_size(data, fmt)
112
+ plot_fmt(data, fmt, :lineplot, params)
113
+ end
114
+
115
+ def scatter(data, params, fmt = 'xyy')
116
+ check_series_size(data, fmt)
117
+ plot_fmt(data, fmt, :scatterplot, params)
118
+ end
119
+
120
+ def density(data, params, fmt = 'xyy')
121
+ check_series_size(data, fmt)
122
+ plot_fmt(data, fmt, :densityplot, params)
123
+ end
124
+
125
+ def boxplot(data, params)
126
+ headers = data.headers
127
+ series = data.series
128
+ headers ||= (1..series.size).map(&:to_s)
129
+ series.map! { |s| s.map(&:to_f) }
130
+ UnicodePlot.boxplot(headers, series, **params.to_hc)
131
+ end
132
+
133
+ def colors(color_names = false)
134
+ UnicodePlot::StyledPrinter::TEXT_COLORS.each do |k, v|
135
+ print v
136
+ print k
137
+ unless color_names
138
+ print "\t"
139
+ print ' ●'
140
+ end
141
+ print "\033[0m"
142
+ print "\t"
143
+ end
144
+ puts
145
+ end
146
+
147
+ def check_series_size(data, fmt)
148
+ series = data.series
149
+ if series.size == 1
150
+ warn 'youplot: There is only one series of input data. Please check the delimiter.'
151
+ warn ''
152
+ warn " Headers: \e[35m#{data.headers.inspect}\e[0m"
153
+ warn " The first item is: \e[35m\"#{series[0][0]}\"\e[0m"
154
+ warn " The last item is : \e[35m\"#{series[0][-1]}\"\e[0m"
155
+ exit 1
156
+ end
157
+ if fmt == 'xyxy' && series.size.odd?
158
+ warn 'YouPlot: In the xyxy format, the number of series must be even.'
159
+ warn ''
160
+ warn " Number of series: \e[35m#{series.size}\e[0m"
161
+ warn " Headers: \e[35m#{data.headers.inspect}\e[0m"
162
+ exit 1
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'preprocessing'
4
+ require_relative 'command/parser'
5
+
6
+ # FIXME
7
+ require_relative 'backends/unicode_plot_backend'
8
+
9
+ module YouPlot
10
+ Data = Struct.new(:headers, :series)
11
+
12
+ class Command
13
+ attr_accessor :params
14
+ attr_reader :data, :fmt, :parser
15
+
16
+ def initialize(argv = ARGV)
17
+ @argv = argv
18
+ @params = Params.new
19
+ @parser = Parser.new
20
+ @backend = YouPlot::Backends::UnicodePlotBackend
21
+ end
22
+
23
+ def run
24
+ parser.parse_options(@argv)
25
+ command = parser.command
26
+ params = parser.params
27
+ delimiter = parser.delimiter
28
+ transpose = parser.transpose
29
+ headers = parser.headers
30
+ pass = parser.pass
31
+ output = parser.output
32
+ fmt = parser.fmt
33
+ @debug = parser.debug
34
+
35
+ if command == :colors
36
+ @backend.colors(parser.color_names)
37
+ exit
38
+ end
39
+
40
+ # Sometimes the input file does not end with a newline code.
41
+ while (input = Kernel.gets(nil))
42
+ input.freeze
43
+ @data = Preprocessing.input(input, delimiter, headers, transpose)
44
+ pp @data if @debug
45
+ plot = case command
46
+ when :bar, :barplot
47
+ @backend.barplot(data, params)
48
+ when :count, :c
49
+ @backend.barplot(data, params, count: true)
50
+ when :hist, :histogram
51
+ @backend.histogram(data, params)
52
+ when :line, :lineplot
53
+ @backend.line(data, params)
54
+ when :lines, :lineplots
55
+ @backend.lines(data, params, fmt)
56
+ when :scatter, :s
57
+ @backend.scatter(data, params, fmt)
58
+ when :density, :d
59
+ @backend.density(data, params, fmt)
60
+ when :box, :boxplot
61
+ @backend.boxplot(data, params)
62
+ else
63
+ raise "unrecognized plot_type: #{command}"
64
+ end
65
+
66
+ case output
67
+ when IO
68
+ plot.render(output)
69
+ else
70
+ File.open(output, 'w') do |f|
71
+ plot.render(f)
72
+ end
73
+ end
74
+
75
+ case pass
76
+ when IO
77
+ pass.print(input)
78
+ else
79
+ if pass
80
+ File.open(pass, 'w') do |f|
81
+ f.print(input)
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YouPlot
4
+ class Command
5
+ # UnicodePlot parameters.
6
+ # * Normally in a Ruby program, you might use hash for the parameter object.
7
+ # * Here, I use Struct for 2 safety reason.
8
+ # * The keys are static in Struct.
9
+ # * Struct does not conflict with keyword arguments. Hash dose.
10
+ Params = Struct.new(
11
+ # Sort me!
12
+ :title,
13
+ :width,
14
+ :height,
15
+ :border,
16
+ :margin,
17
+ :padding,
18
+ :color,
19
+ :xlabel,
20
+ :ylabel,
21
+ :labels,
22
+ :symbol,
23
+ :xscale,
24
+ :nbins,
25
+ :closed,
26
+ :canvas,
27
+ :xlim,
28
+ :ylim,
29
+ :grid,
30
+ :name
31
+ ) do
32
+ def to_hc
33
+ to_h.compact
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,261 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'optparse'
4
+ require_relative 'params'
5
+
6
+ module YouPlot
7
+ class Command
8
+ class Parser
9
+ attr_reader :command, :params,
10
+ :delimiter, :transpose, :headers, :pass, :output, :fmt,
11
+ :color_names, :debug
12
+
13
+ def initialize
14
+ @command = nil
15
+ @params = Params.new
16
+
17
+ @delimiter = "\t"
18
+ @transpose = false
19
+ @headers = nil
20
+ @pass = false
21
+ @output = $stderr
22
+ @fmt = 'xyy'
23
+ @debug = false
24
+ @color_names = false
25
+ end
26
+
27
+ def create_default_parser
28
+ OptionParser.new do |opt|
29
+ opt.program_name = 'YouPlot'
30
+ opt.version = YouPlot::VERSION
31
+ opt.summary_width = 24
32
+ opt.on_tail('') # Add a blank line at the end
33
+ opt.separator('')
34
+ opt.on('Common options:')
35
+ opt.on('-O', '--pass [VAL]', 'file to output standard input data to [stdout]',
36
+ 'for inserting YouPlot in the middle of Unix pipes') do |v|
37
+ @pass = v || $stdout
38
+ end
39
+ opt.on('-o', '--output VAL', 'file to output results to [stderr]') do |v|
40
+ @output = v
41
+ end
42
+ opt.on('-d', '--delimiter VAL', String, 'use DELIM instead of TAB for field delimiter') do |v|
43
+ @delimiter = v
44
+ end
45
+ opt.on('-H', '--headers', TrueClass, 'specify that the input has header row') do |v|
46
+ @headers = v
47
+ end
48
+ opt.on('-T', '--transpose', TrueClass, 'transpose the axes of the input data') do |v|
49
+ @transpose = v
50
+ end
51
+ opt.on('-t', '--title VAL', String, 'print string on the top of plot') do |v|
52
+ params.title = v
53
+ end
54
+ opt.on('-x', '--xlabel VAL', String, 'print string on the bottom of the plot') do |v|
55
+ params.xlabel = v
56
+ end
57
+ opt.on('-y', '--ylabel VAL', String, 'print string on the far left of the plot') do |v|
58
+ params.ylabel = v
59
+ end
60
+ opt.on('-w', '--width VAL', Integer, 'number of characters per row') do |v|
61
+ params.width = v
62
+ end
63
+ opt.on('-h', '--height VAL', Numeric, 'number of rows') do |v|
64
+ params.height = v
65
+ end
66
+ opt.on('-b', '--border VAL', String, 'specify the style of the bounding box') do |v|
67
+ params.border = v.to_sym
68
+ end
69
+ opt.on('-m', '--margin VAL', Numeric, 'number of spaces to the left of the plot') do |v|
70
+ params.margin = v
71
+ end
72
+ opt.on('-p', '--padding VAL', Numeric, 'space of the left and right of the plot') do |v|
73
+ params.padding = v
74
+ end
75
+ opt.on('-c', '--color VAL', String, 'color of the drawing') do |v|
76
+ params.color = v =~ /\A[0-9]+\z/ ? v.to_i : v.to_sym
77
+ end
78
+ opt.on('--[no-]labels', TrueClass, 'hide the labels') do |v|
79
+ params.labels = v
80
+ end
81
+ opt.on('--fmt VAL', String, 'xyxy : header is like x1, y1, x2, y2, x3, y3...', 'xyy : header is like x, y1, y2, y2, y3...') do |v|
82
+ @fmt = v
83
+ end
84
+ # Optparse adds the help option, but it doesn't show up in usage.
85
+ # This is why you need the code below.
86
+ opt.on('--help', 'print sub-command help menu') do
87
+ puts opt.help
88
+ exit
89
+ end
90
+ opt.on('--debug', TrueClass, 'print preprocessed data') do |v|
91
+ @debug = v
92
+ end
93
+ yield opt if block_given?
94
+ end
95
+ end
96
+
97
+ def main_parser
98
+ @main_parser ||= create_default_parser do |main_parser|
99
+ # Here, help message is stored in the banner.
100
+ # Because help of main_parser may be referred by `sub_parser`.
101
+
102
+ main_parser.banner = \
103
+ <<~MSG
104
+
105
+ Program: YouPlot (Tools for plotting on the terminal)
106
+ Version: #{YouPlot::VERSION} (using UnicodePlot #{UnicodePlot::VERSION})
107
+ Source: https://github.com/kojix2/youplot
108
+
109
+ Usage: uplot <command> [options] <in.tsv>
110
+
111
+ Commands:
112
+ barplot bar draw a horizontal barplot
113
+ histogram hist draw a horizontal histogram
114
+ lineplot line draw a line chart
115
+ lineplots lines draw a line chart with multiple series
116
+ scatter s draw a scatter plot
117
+ density d draw a density plot
118
+ boxplot box draw a horizontal boxplot
119
+ colors show the list of available colors
120
+
121
+ count c draw a baplot based on the number of
122
+ occurrences (slow)
123
+
124
+ General options:
125
+ --help print command specific help menu
126
+ --version print the version of YouPlot
127
+ MSG
128
+
129
+ # Actually, main_parser can take common optional arguments.
130
+ # However, these options dose not be shown in the help menu.
131
+ # I think the main help should be simple.
132
+ main_parser.on('--help', 'print sub-command help menu') do
133
+ puts main_parser.banner
134
+ puts
135
+ exit
136
+ end
137
+ end
138
+ end
139
+
140
+ def sub_parser
141
+ @sub_parser ||= create_default_parser do |parser|
142
+ parser.banner = <<~MSG
143
+
144
+ Usage: YouPlot #{command} [options] <in.tsv>
145
+
146
+ Options for #{command}:
147
+ MSG
148
+
149
+ case command
150
+
151
+ # If you type only `uplot` in the terminal.
152
+ when nil
153
+ warn main_parser.banner
154
+ warn "\n"
155
+ exit 1
156
+
157
+ when :barplot, :bar
158
+ parser.on_head('--symbol VAL', String, 'character to be used to plot the bars') do |v|
159
+ params.symbol = v
160
+ end
161
+ parser.on_head('--xscale VAL', String, 'axis scaling') do |v|
162
+ params.xscale = v
163
+ end
164
+
165
+ when :count, :c
166
+ parser.on_head('--symbol VAL', String, 'character to be used to plot the bars') do |v|
167
+ params.symbol = v
168
+ end
169
+
170
+ when :histogram, :hist
171
+ parser.on_head('-n', '--nbins VAL', Numeric, 'approximate number of bins') do |v|
172
+ params.nbins = v
173
+ end
174
+ parser.on_head('--closed VAL', String) do |v|
175
+ params.closed = v
176
+ end
177
+ parser.on_head('--symbol VAL', String, 'character to be used to plot the bars') do |v|
178
+ params.symbol = v
179
+ end
180
+
181
+ when :lineplot, :line
182
+ parser.on_head('--canvas VAL', String, 'type of canvas') do |v|
183
+ params.canvas = v
184
+ end
185
+ parser.on_head('--xlim VAL', Array, 'plotting range for the x coordinate') do |v|
186
+ params.xlim = v.take(2)
187
+ end
188
+ parser.on_head('--ylim VAL', Array, 'plotting range for the y coordinate') do |v|
189
+ params.ylim = v.take(2)
190
+ end
191
+
192
+ when :lineplots, :lines
193
+ parser.on_head('--canvas VAL', String) do |v|
194
+ params.canvas = v
195
+ end
196
+ parser.on_head('--xlim VAL', Array, 'plotting range for the x coordinate') do |v|
197
+ params.xlim = v.take(2)
198
+ end
199
+ parser.on_head('--ylim VAL', Array, 'plotting range for the y coordinate') do |v|
200
+ params.ylim = v.take(2)
201
+ end
202
+
203
+ when :scatter, :s
204
+ parser.on_head('--canvas VAL', String) do |v|
205
+ params.canvas = v
206
+ end
207
+ parser.on_head('--xlim VAL', Array, 'plotting range for the x coordinate') do |v|
208
+ params.xlim = v.take(2)
209
+ end
210
+ parser.on_head('--ylim VAL', Array, 'plotting range for the y coordinate') do |v|
211
+ params.ylim = v.take(2)
212
+ end
213
+
214
+ when :density, :d
215
+ parser.on_head('--grid', TrueClass) do |v|
216
+ params.grid = v
217
+ end
218
+ parser.on_head('--xlim VAL', Array, 'plotting range for the x coordinate') do |v|
219
+ params.xlim = v.take(2)
220
+ end
221
+ parser.on_head('--ylim VAL', Array, 'plotting range for the y coordinate') do |v|
222
+ params.ylim = v.take(2)
223
+ end
224
+
225
+ when :boxplot, :box
226
+ parser.on_head('--xlim VAL', Array, 'plotting range for the x coordinate') do |v|
227
+ params.xlim = v.take(2)
228
+ end
229
+
230
+ when :colors
231
+ parser.on_head('-n', '--names', 'show color names only', TrueClass) do |v|
232
+ @color_names = v
233
+ end
234
+
235
+ else
236
+ warn "uplot: unrecognized command '#{command}'"
237
+ exit 1
238
+ end
239
+ end
240
+ end
241
+
242
+ def parse_options(argv = ARGV)
243
+ begin
244
+ main_parser.order!(argv)
245
+ rescue OptionParser::ParseError => e
246
+ warn "uplot: #{e.message}"
247
+ exit 1
248
+ end
249
+
250
+ @command = argv.shift&.to_sym
251
+
252
+ begin
253
+ sub_parser.parse!(argv)
254
+ rescue OptionParser::ParseError => e
255
+ warn "uplot: #{e.message}"
256
+ exit 1
257
+ end
258
+ end
259
+ end
260
+ end
261
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'csv'
4
+
5
+ module YouPlot
6
+ module Preprocessing
7
+ module_function
8
+
9
+ def input(input, delimiter, headers, transpose)
10
+ arr = parse_as_csv(input, delimiter)
11
+ headers = get_headers(arr, headers, transpose)
12
+ series = get_series(arr, headers, transpose)
13
+ if headers.nil?
14
+ Data.new(headers, series)
15
+ else
16
+ if headers.include?(nil)
17
+ warn "\e[35mHeaders contains nil in it.\e[0m"
18
+ elsif headers.include? ''
19
+ warn "\e[35mHeaders contains \"\" in it.\e[0m"
20
+ end
21
+ h_size = headers.size
22
+ s_size = series.size
23
+ if h_size == s_size
24
+ Data.new(headers, series)
25
+ elsif h_size > s_size
26
+ warn "\e[35mThe number of headers is greater than the number of series.\e[0m"
27
+ exit 1
28
+ elsif h_size < s_size
29
+ warn "\e[35mThe number of headers is less than the number of series.\e[0m"
30
+ exit 1
31
+ end
32
+ end
33
+ end
34
+
35
+ def parse_as_csv(input, delimiter)
36
+ CSV.parse(input, col_sep: delimiter)
37
+ .delete_if do |i|
38
+ i == [] or i.all? nil
39
+ end
40
+ end
41
+
42
+ # Transpose different sized ruby arrays
43
+ # https://stackoverflow.com/q/26016632
44
+ def transpose2(arr)
45
+ Array.new(arr.map(&:length).max) { |i| arr.map { |e| e[i] } }
46
+ end
47
+
48
+ def get_headers(arr, headers, transpose)
49
+ if headers
50
+ if transpose
51
+ arr.map(&:first)
52
+ else
53
+ arr[0]
54
+ end
55
+ end
56
+ end
57
+
58
+ def get_series(arr, headers, transpose)
59
+ if transpose
60
+ if headers
61
+ arr.map { |row| row[1..-1] }
62
+ else
63
+ arr
64
+ end
65
+ elsif headers
66
+ transpose2(arr[1..-1])
67
+ else
68
+ transpose2(arr)
69
+ end
70
+ end
71
+
72
+ def count_values(arr)
73
+ # tally was added in Ruby 2.7
74
+ if Enumerable.method_defined? :tally
75
+ arr.tally
76
+ else
77
+ # https://github.com/marcandre/backports
78
+ arr.each_with_object(Hash.new(0)) { |item, res| res[item] += 1 }
79
+ .tap { |h| h.default = nil }
80
+ end
81
+ .sort { |a, b| a[1] <=> b[1] }
82
+ .reverse
83
+ .transpose
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YouPlot
4
+ VERSION = '0.3.0'
5
+ end
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: youplot
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - kojix2
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-11-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: unicode_plot
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: test-unit
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: "Create ASCII charts on the terminal with data from standard streams
98
+ in the \npipeline. \n"
99
+ email:
100
+ - 2xijok@gmail.com
101
+ executables:
102
+ - uplot
103
+ - youplot
104
+ extensions: []
105
+ extra_rdoc_files: []
106
+ files:
107
+ - LICENSE.txt
108
+ - README.md
109
+ - exe/uplot
110
+ - exe/youplot
111
+ - lib/youplot.rb
112
+ - lib/youplot/backends/unicode_plot_backend.rb
113
+ - lib/youplot/command.rb
114
+ - lib/youplot/command/params.rb
115
+ - lib/youplot/command/parser.rb
116
+ - lib/youplot/preprocessing.rb
117
+ - lib/youplot/version.rb
118
+ homepage: https://github.com/kojix2/youplot
119
+ licenses:
120
+ - MIT
121
+ metadata: {}
122
+ post_install_message:
123
+ rdoc_options: []
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: 2.4.0
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ requirements: []
137
+ rubygems_version: 3.1.4
138
+ signing_key:
139
+ specification_version: 4
140
+ summary: Create Ascii charts on your terminal.
141
+ test_files: []