youplot 0.3.1 → 0.4.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.
- checksums.yaml +4 -4
- data/README.md +177 -67
- data/exe/uplot +1 -1
- data/exe/youplot +1 -1
- data/lib/youplot.rb +12 -4
- data/lib/youplot/backends/processing.rb +11 -7
- data/lib/youplot/backends/{unicode_plot_backend.rb → unicode_plot.rb} +53 -34
- data/lib/youplot/command.rb +189 -70
- data/lib/youplot/dsv.rb +87 -0
- data/lib/youplot/options.rb +18 -0
- data/lib/youplot/parameters.rb +34 -0
- data/lib/youplot/parser.rb +306 -0
- data/lib/youplot/version.rb +1 -1
- metadata +10 -10
- data/lib/youplot/command/params.rb +0 -37
- data/lib/youplot/command/parser.rb +0 -277
- data/lib/youplot/dsv_reader.rb +0 -73
data/lib/youplot/command.rb
CHANGED
@@ -1,97 +1,216 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
3
|
+
require_relative 'dsv'
|
4
|
+
require_relative 'parser'
|
5
5
|
|
6
6
|
# FIXME
|
7
|
-
require_relative 'backends/
|
7
|
+
require_relative 'backends/unicode_plot'
|
8
8
|
|
9
9
|
module YouPlot
|
10
10
|
Data = Struct.new(:headers, :series)
|
11
11
|
|
12
12
|
class Command
|
13
|
-
attr_accessor :params
|
14
|
-
attr_reader :data, :
|
13
|
+
attr_accessor :command, :params, :options
|
14
|
+
attr_reader :data, :parser
|
15
15
|
|
16
16
|
def initialize(argv = ARGV)
|
17
17
|
@argv = argv
|
18
|
-
@params = Params.new
|
19
18
|
@parser = Parser.new
|
20
|
-
@
|
19
|
+
@command = nil
|
20
|
+
@params = nil
|
21
|
+
@options = nil
|
22
|
+
@backend = YouPlot::Backends::UnicodePlot
|
23
|
+
end
|
24
|
+
|
25
|
+
def run_as_executable
|
26
|
+
YouPlot.run_as_executable = true
|
27
|
+
run
|
21
28
|
end
|
22
29
|
|
23
30
|
def run
|
24
31
|
parser.parse_options(@argv)
|
25
|
-
command
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
@debug = parser.debug
|
35
|
-
|
36
|
-
if command == :colors
|
37
|
-
@backend.colors(parser.color_names)
|
38
|
-
exit
|
32
|
+
@command ||= parser.command
|
33
|
+
@options ||= parser.options
|
34
|
+
@params ||= parser.params
|
35
|
+
|
36
|
+
# color command
|
37
|
+
if %i[colors color colours colour].include? @command
|
38
|
+
plot = create_plot
|
39
|
+
output_plot(plot)
|
40
|
+
return
|
39
41
|
end
|
40
42
|
|
41
|
-
#
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
43
|
+
# progressive mode
|
44
|
+
if options[:progressive]
|
45
|
+
stop = false
|
46
|
+
Signal.trap(:INT) { stop = true }
|
47
|
+
|
48
|
+
# make cursor invisible
|
49
|
+
options[:output].print "\e[?25l"
|
50
|
+
|
51
|
+
# mainloop
|
52
|
+
while (input = Kernel.gets)
|
53
|
+
n = main_progressive(input)
|
54
|
+
break if stop
|
55
|
+
|
56
|
+
options[:output].print "\e[#{n}F"
|
57
|
+
end
|
58
|
+
|
59
|
+
options[:output].print "\e[0J"
|
60
|
+
# make cursor visible
|
61
|
+
options[:output].print "\e[?25h"
|
62
|
+
|
63
|
+
# normal mode
|
64
|
+
else
|
65
|
+
# Sometimes the input file does not end with a newline code.
|
66
|
+
while (input = Kernel.gets(nil))
|
67
|
+
main(input)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def main(input)
|
75
|
+
# Outputs input data to a file or stdout.
|
76
|
+
output_data(input)
|
77
|
+
|
78
|
+
@data = parse_dsv(input)
|
79
|
+
|
80
|
+
# Debug mode, show parsed results
|
81
|
+
pp @data if options[:debug]
|
82
|
+
|
83
|
+
# When run as a program instead of a library
|
84
|
+
if YouPlot.run_as_executable?
|
85
|
+
begin
|
86
|
+
plot = create_plot
|
87
|
+
rescue ArgumentError => e
|
88
|
+
# Show only one line of error.
|
89
|
+
warn e.backtrace[0]
|
90
|
+
# Show error message in purple
|
91
|
+
warn "\e[35m#{e}\e[0m"
|
92
|
+
# Explicitly terminated with exit code: 1
|
93
|
+
exit 1
|
94
|
+
end
|
95
|
+
|
96
|
+
# When running YouPlot as a library (e.g. for testing)
|
97
|
+
else
|
98
|
+
plot = create_plot
|
99
|
+
end
|
100
|
+
|
101
|
+
output_plot(plot)
|
102
|
+
end
|
103
|
+
|
104
|
+
def main_progressive(input)
|
105
|
+
output_data(input)
|
106
|
+
|
107
|
+
# FIXME
|
108
|
+
# Worked around the problem of not being able to draw
|
109
|
+
# plots when there is only one header line.
|
110
|
+
if @raw_data.nil?
|
111
|
+
@raw_data = String.new
|
112
|
+
if options[:headers]
|
113
|
+
@raw_data << input
|
114
|
+
return
|
54
115
|
end
|
116
|
+
end
|
117
|
+
@raw_data << input
|
118
|
+
|
119
|
+
# FIXME
|
120
|
+
@data = parse_dsv(@raw_data)
|
121
|
+
|
122
|
+
plot = create_plot
|
123
|
+
output_plot_progressive(plot)
|
124
|
+
end
|
125
|
+
|
126
|
+
def parse_dsv(input)
|
127
|
+
# If encoding is specified, convert to UTF-8
|
128
|
+
if options[:encoding]
|
129
|
+
input.force_encoding(options[:encoding])
|
130
|
+
.encode!('utf-8')
|
131
|
+
end
|
132
|
+
|
133
|
+
begin
|
134
|
+
data = DSV.parse(input, options[:delimiter], options[:headers], options[:transpose])
|
135
|
+
rescue CSV::MalformedCSVError => e
|
136
|
+
warn 'Failed to parse the text. '
|
137
|
+
warn 'Please try to set the correct character encoding with --encoding option.'
|
138
|
+
raise e
|
139
|
+
end
|
140
|
+
|
141
|
+
data
|
142
|
+
end
|
55
143
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
File.open(output, 'w') do |f|
|
91
|
-
plot.render(f)
|
144
|
+
def create_plot
|
145
|
+
case command
|
146
|
+
when :bar, :barplot
|
147
|
+
@backend.barplot(data, params, options[:fmt])
|
148
|
+
when :count, :c
|
149
|
+
@backend.barplot(data, params, count: true)
|
150
|
+
when :hist, :histogram
|
151
|
+
@backend.histogram(data, params)
|
152
|
+
when :line, :lineplot
|
153
|
+
@backend.line(data, params, options[:fmt])
|
154
|
+
when :lines, :lineplots
|
155
|
+
@backend.lines(data, params, options[:fmt])
|
156
|
+
when :scatter, :s
|
157
|
+
@backend.scatter(data, params, options[:fmt])
|
158
|
+
when :density, :d
|
159
|
+
@backend.density(data, params, options[:fmt])
|
160
|
+
when :box, :boxplot
|
161
|
+
@backend.boxplot(data, params)
|
162
|
+
when :colors, :color, :colours, :colour
|
163
|
+
@backend.colors(options[:color_names])
|
164
|
+
else
|
165
|
+
raise "unrecognized plot_type: #{command}"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def output_data(input)
|
170
|
+
# Pass the input to subsequent pipelines
|
171
|
+
case options[:pass]
|
172
|
+
when IO
|
173
|
+
options[:pass].print(input)
|
174
|
+
else
|
175
|
+
if options[:pass]
|
176
|
+
File.open(options[:pass], 'w') do |f|
|
177
|
+
f.print(input)
|
92
178
|
end
|
93
179
|
end
|
180
|
+
end
|
181
|
+
end
|
94
182
|
|
183
|
+
def output_plot(plot)
|
184
|
+
case options[:output]
|
185
|
+
when IO, StringIO
|
186
|
+
plot.render(options[:output])
|
187
|
+
when String, Tempfile
|
188
|
+
File.open(options[:output], 'w') do |f|
|
189
|
+
plot.render(f)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def output_plot_progressive(plot)
|
195
|
+
case options[:output]
|
196
|
+
when IO, StringIO
|
197
|
+
# RefactorMe
|
198
|
+
out = StringIO.new(String.new)
|
199
|
+
def out.tty?
|
200
|
+
true
|
201
|
+
end
|
202
|
+
plot.render(out)
|
203
|
+
lines = out.string.lines
|
204
|
+
lines.each do |line|
|
205
|
+
options[:output].print line.chomp
|
206
|
+
options[:output].print "\e[0K"
|
207
|
+
options[:output].puts
|
208
|
+
end
|
209
|
+
options[:output].print "\e[0J"
|
210
|
+
options[:output].flush
|
211
|
+
out.string.lines.size
|
212
|
+
else
|
213
|
+
raise 'In progressive mode, output to a file is not possible.'
|
95
214
|
end
|
96
215
|
end
|
97
216
|
end
|
data/lib/youplot/dsv.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'csv'
|
4
|
+
|
5
|
+
module YouPlot
|
6
|
+
# Module to handle DSV (Delimiter-separated values) format.
|
7
|
+
# Extract header and series.
|
8
|
+
module DSV
|
9
|
+
module_function
|
10
|
+
|
11
|
+
def parse(input, delimiter, headers, transpose)
|
12
|
+
# Parse as CSV
|
13
|
+
arr = CSV.parse(input, col_sep: delimiter)
|
14
|
+
|
15
|
+
# Remove blank lines
|
16
|
+
arr.delete_if do |i|
|
17
|
+
i == [] or i.all? nil
|
18
|
+
end
|
19
|
+
|
20
|
+
# get header
|
21
|
+
headers = get_headers(arr, headers, transpose)
|
22
|
+
|
23
|
+
# get series
|
24
|
+
series = get_series(arr, headers, transpose)
|
25
|
+
|
26
|
+
# Return if No header
|
27
|
+
return Data.new(headers, series) if headers.nil?
|
28
|
+
|
29
|
+
# Warn if header contains nil
|
30
|
+
warn "\e[35mHeaders contains nil in it.\e[0m" if headers.include?(nil)
|
31
|
+
|
32
|
+
# Warn if header contains ''
|
33
|
+
warn "\e[35mHeaders contains \"\" in it.\e[0m" if headers.include? ''
|
34
|
+
|
35
|
+
# Make sure the number of elements in the header matches the number of series.
|
36
|
+
h_size = headers.size
|
37
|
+
s_size = series.size
|
38
|
+
|
39
|
+
if h_size > s_size
|
40
|
+
warn "\e[35mThe number of headers is greater than the number of series.\e[0m"
|
41
|
+
exit 1 if YouPlot.run_as_executable?
|
42
|
+
|
43
|
+
elsif h_size < s_size
|
44
|
+
warn "\e[35mThe number of headers is less than the number of series.\e[0m"
|
45
|
+
exit 1 if YouPlot.run_as_executable?
|
46
|
+
end
|
47
|
+
|
48
|
+
Data.new(headers, series) if h_size == s_size
|
49
|
+
end
|
50
|
+
|
51
|
+
# Transpose different sized ruby arrays
|
52
|
+
# https://stackoverflow.com/q/26016632
|
53
|
+
def transpose2(arr)
|
54
|
+
Array.new(arr.map(&:length).max) { |i| arr.map { |e| e[i] } }
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_headers(arr, headers, transpose)
|
58
|
+
# header(-)
|
59
|
+
return nil unless headers
|
60
|
+
|
61
|
+
# header(+) trenspose(+)
|
62
|
+
return arr.map(&:first) if transpose
|
63
|
+
|
64
|
+
# header(+) transpose(-)
|
65
|
+
arr[0]
|
66
|
+
end
|
67
|
+
|
68
|
+
def get_series(arr, headers, transpose)
|
69
|
+
# header(-)
|
70
|
+
unless headers
|
71
|
+
return arr if transpose
|
72
|
+
|
73
|
+
return transpose2(arr)
|
74
|
+
end
|
75
|
+
|
76
|
+
# header(+) but no element in the series.
|
77
|
+
# TODO: should raise error?
|
78
|
+
return Array.new(arr[0].size, []) if arr.size == 1
|
79
|
+
|
80
|
+
# header(+) transpose(+)
|
81
|
+
return arr.map { |row| row[1..-1] } if transpose
|
82
|
+
|
83
|
+
# header(+) transpose(-)
|
84
|
+
transpose2(arr[1..-1])
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module YouPlot
|
4
|
+
# Command line options that are not Plot parameters
|
5
|
+
Options = Struct.new(
|
6
|
+
:delimiter,
|
7
|
+
:transpose,
|
8
|
+
:headers,
|
9
|
+
:pass,
|
10
|
+
:output,
|
11
|
+
:fmt,
|
12
|
+
:progressive,
|
13
|
+
:encoding,
|
14
|
+
:color_names,
|
15
|
+
:debug,
|
16
|
+
keyword_init: true
|
17
|
+
)
|
18
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module YouPlot
|
4
|
+
# UnicodePlot parameters.
|
5
|
+
# Why Struct, not Hash?
|
6
|
+
# * The keys are static in Struct.
|
7
|
+
# * Struct does not conflict with keyword arguments. Hash dose.
|
8
|
+
Parameters = Struct.new(
|
9
|
+
# Sort me!
|
10
|
+
:title,
|
11
|
+
:width,
|
12
|
+
:height,
|
13
|
+
:border,
|
14
|
+
:margin,
|
15
|
+
:padding,
|
16
|
+
:color,
|
17
|
+
:xlabel,
|
18
|
+
:ylabel,
|
19
|
+
:labels,
|
20
|
+
:symbol,
|
21
|
+
:xscale,
|
22
|
+
:nbins,
|
23
|
+
:closed,
|
24
|
+
:canvas,
|
25
|
+
:xlim,
|
26
|
+
:ylim,
|
27
|
+
:grid,
|
28
|
+
:name
|
29
|
+
) do
|
30
|
+
def to_hc
|
31
|
+
to_h.compact
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,306 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require_relative 'options'
|
5
|
+
|
6
|
+
module YouPlot
|
7
|
+
# Class for parsing command line options
|
8
|
+
class Parser
|
9
|
+
class Error < StandardError; end
|
10
|
+
|
11
|
+
attr_reader :command, :options, :params,
|
12
|
+
:main_parser, :sub_parser
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@command = nil
|
16
|
+
|
17
|
+
@options = Options.new(
|
18
|
+
delimiter: "\t",
|
19
|
+
transpose: false,
|
20
|
+
headers: nil,
|
21
|
+
pass: false,
|
22
|
+
output: $stderr,
|
23
|
+
fmt: 'xyy',
|
24
|
+
progressive: false,
|
25
|
+
encoding: nil,
|
26
|
+
color_names: false,
|
27
|
+
debug: false
|
28
|
+
)
|
29
|
+
|
30
|
+
@params = Parameters.new
|
31
|
+
end
|
32
|
+
|
33
|
+
def create_base_parser
|
34
|
+
OptionParser.new do |parser|
|
35
|
+
parser.program_name = 'YouPlot'
|
36
|
+
parser.version = YouPlot::VERSION
|
37
|
+
parser.summary_width = 23
|
38
|
+
parser.on_tail('') # Add a blank line at the end
|
39
|
+
parser.separator('')
|
40
|
+
parser.on('Common options:')
|
41
|
+
parser.on('-O', '--pass [FILE]', 'file to output input data to [stdout]',
|
42
|
+
'for inserting YouPlot in the middle of Unix pipes') do |v|
|
43
|
+
options[:pass] = v || $stdout
|
44
|
+
end
|
45
|
+
parser.on('-o', '--output [FILE]', 'file to output plots to [stdout]',
|
46
|
+
'If no option is specified, plot will print to stderr') do |v|
|
47
|
+
options[:output] = v || $stdout
|
48
|
+
end
|
49
|
+
parser.on('-d', '--delimiter DELIM', String, 'use DELIM instead of [TAB] for field delimiter') do |v|
|
50
|
+
options[:delimiter] = v
|
51
|
+
end
|
52
|
+
parser.on('-H', '--headers', TrueClass, 'specify that the input has header row') do |v|
|
53
|
+
options[:headers] = v
|
54
|
+
end
|
55
|
+
parser.on('-T', '--transpose', TrueClass, 'transpose the axes of the input data') do |v|
|
56
|
+
options[:transpose] = v
|
57
|
+
end
|
58
|
+
parser.on('-t', '--title STR', String, 'print string on the top of plot') do |v|
|
59
|
+
params.title = v
|
60
|
+
end
|
61
|
+
parser.on('-x', '--xlabel STR', String, 'print string on the bottom of the plot') do |v|
|
62
|
+
params.xlabel = v
|
63
|
+
end
|
64
|
+
parser.on('-y', '--ylabel STR', String, 'print string on the far left of the plot') do |v|
|
65
|
+
params.ylabel = v
|
66
|
+
end
|
67
|
+
parser.on('-w', '--width INT', Integer, 'number of characters per row') do |v|
|
68
|
+
params.width = v
|
69
|
+
end
|
70
|
+
parser.on('-h', '--height INT', Numeric, 'number of rows') do |v|
|
71
|
+
params.height = v
|
72
|
+
end
|
73
|
+
border_options = UnicodePlot::BORDER_MAP.keys.join(', ')
|
74
|
+
parser.on('-b', '--border STR', String, 'specify the style of the bounding box', "(#{border_options})") do |v|
|
75
|
+
params.border = v.to_sym
|
76
|
+
end
|
77
|
+
parser.on('-m', '--margin INT', Numeric, 'number of spaces to the left of the plot') do |v|
|
78
|
+
params.margin = v
|
79
|
+
end
|
80
|
+
parser.on('--padding INT', Numeric, 'space of the left and right of the plot') do |v|
|
81
|
+
params.padding = v
|
82
|
+
end
|
83
|
+
parser.on('-c', '--color VAL', String, 'color of the drawing') do |v|
|
84
|
+
params.color = v =~ /\A[0-9]+\z/ ? v.to_i : v.to_sym
|
85
|
+
end
|
86
|
+
parser.on('--[no-]labels', TrueClass, 'hide the labels') do |v|
|
87
|
+
params.labels = v
|
88
|
+
end
|
89
|
+
parser.on('-p', '--progress', TrueClass, 'progressive mode [experimental]') do |v|
|
90
|
+
options[:progressive] = v
|
91
|
+
end
|
92
|
+
parser.on('-C', '--color-output', TrueClass, 'colorize even if writing to a pipe') do |_v|
|
93
|
+
UnicodePlot::IOContext.define_method(:color?) { true } # FIXME
|
94
|
+
end
|
95
|
+
parser.on('-M', '--monochrome', TrueClass, 'no colouring even if writing to a tty') do |_v|
|
96
|
+
UnicodePlot::IOContext.define_method(:color?) { false } # FIXME
|
97
|
+
end
|
98
|
+
parser.on('--encoding STR', String, 'Specify the input encoding') do |v|
|
99
|
+
options[:encoding] = v
|
100
|
+
end
|
101
|
+
# Optparse adds the help option, but it doesn't show up in usage.
|
102
|
+
# This is why you need the code below.
|
103
|
+
parser.on('--help', 'print sub-command help menu') do
|
104
|
+
puts parser.help
|
105
|
+
exit if YouPlot.run_as_executable?
|
106
|
+
end
|
107
|
+
parser.on('--debug', TrueClass, 'print preprocessed data') do |v|
|
108
|
+
options[:debug] = v
|
109
|
+
end
|
110
|
+
# yield opt if block_given?
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def create_main_parser
|
115
|
+
@main_parser = create_base_parser
|
116
|
+
main_parser.banner = \
|
117
|
+
<<~MSG
|
118
|
+
|
119
|
+
Program: YouPlot (Tools for plotting on the terminal)
|
120
|
+
Version: #{YouPlot::VERSION} (using UnicodePlot #{UnicodePlot::VERSION})
|
121
|
+
Source: https://github.com/kojix2/youplot
|
122
|
+
|
123
|
+
Usage: uplot <command> [options] <in.tsv>
|
124
|
+
|
125
|
+
Commands:
|
126
|
+
barplot bar draw a horizontal barplot
|
127
|
+
histogram hist draw a horizontal histogram
|
128
|
+
lineplot line draw a line chart
|
129
|
+
lineplots lines draw a line chart with multiple series
|
130
|
+
scatter s draw a scatter plot
|
131
|
+
density d draw a density plot
|
132
|
+
boxplot box draw a horizontal boxplot
|
133
|
+
colors color show the list of available colors
|
134
|
+
|
135
|
+
count c draw a baplot based on the number of
|
136
|
+
occurrences (slow)
|
137
|
+
|
138
|
+
General options:
|
139
|
+
--help print command specific help menu
|
140
|
+
--version print the version of YouPlot
|
141
|
+
MSG
|
142
|
+
|
143
|
+
# Help for the main parser is simple.
|
144
|
+
# Simply show the banner above.
|
145
|
+
main_parser.on('--help', 'print sub-command help menu') do
|
146
|
+
puts main_parser.banner
|
147
|
+
puts
|
148
|
+
exit if YouPlot.run_as_executable?
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def sub_parser_add_symbol
|
153
|
+
sub_parser.on_head('--symbol STR', String, 'character to be used to plot the bars') do |v|
|
154
|
+
params.symbol = v
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def sub_parser_add_xscale
|
159
|
+
xscale_options = UnicodePlot::ValueTransformer::PREDEFINED_TRANSFORM_FUNCTIONS.keys.join(', ')
|
160
|
+
sub_parser.on_head('--xscale STR', String, "axis scaling (#{xscale_options})") do |v|
|
161
|
+
params.xscale = v.to_sym
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def sub_parser_add_canvas
|
166
|
+
sub_parser.on_head('--canvas STR', String, 'type of canvas') do |v|
|
167
|
+
params.canvas = v.to_sym
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def sub_parser_add_xlim
|
172
|
+
sub_parser.on_head('--xlim FLOAT,FLOAT', Array, 'plotting range for the x coordinate') do |v|
|
173
|
+
params.xlim = v
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def sub_parser_add_ylim
|
178
|
+
sub_parser.on_head('--ylim FLOAT,FLOAT', Array, 'plotting range for the y coordinate') do |v|
|
179
|
+
params.ylim = v
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def sub_parser_add_grid
|
184
|
+
sub_parser.on_head('--[no-]grid', TrueClass, 'draws grid-lines at the origin') do |v|
|
185
|
+
params.grid = v
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def sub_parser_add_fmt_xyxy
|
190
|
+
sub_parser.on_head('--fmt STR', String,
|
191
|
+
'xyxy : header is like x1, y1, x2, y2, x3, y3...',
|
192
|
+
'xyy : header is like x, y1, y2, y2, y3...') do |v|
|
193
|
+
options[:fmt] = v
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def sub_parser_add_fmt_yx
|
198
|
+
sub_parser.on_head('--fmt STR', String,
|
199
|
+
'xy : header is like x, y...',
|
200
|
+
'yx : header is like y, x...') do |v|
|
201
|
+
options[:fmt] = v
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def create_sub_parser
|
206
|
+
@sub_parser = create_base_parser
|
207
|
+
sub_parser.banner = \
|
208
|
+
<<~MSG
|
209
|
+
|
210
|
+
Usage: YouPlot #{command} [options] <in.tsv>
|
211
|
+
|
212
|
+
Options for #{command}:
|
213
|
+
MSG
|
214
|
+
|
215
|
+
case command
|
216
|
+
|
217
|
+
# If you type only `uplot` in the terminal.
|
218
|
+
when nil
|
219
|
+
warn main_parser.banner
|
220
|
+
warn "\n"
|
221
|
+
exit 1 if YouPlot.run_as_executable?
|
222
|
+
|
223
|
+
when :barplot, :bar
|
224
|
+
sub_parser_add_symbol
|
225
|
+
sub_parser_add_fmt_yx
|
226
|
+
sub_parser_add_xscale
|
227
|
+
|
228
|
+
when :count, :c
|
229
|
+
sub_parser_add_symbol
|
230
|
+
sub_parser_add_xscale
|
231
|
+
|
232
|
+
when :histogram, :hist
|
233
|
+
sub_parser_add_symbol
|
234
|
+
sub_parser.on_head('--closed STR', String, 'side of the intervals to be closed [left]') do |v|
|
235
|
+
params.closed = v
|
236
|
+
end
|
237
|
+
sub_parser.on_head('-n', '--nbins INT', Numeric, 'approximate number of bins') do |v|
|
238
|
+
params.nbins = v
|
239
|
+
end
|
240
|
+
|
241
|
+
when :lineplot, :line
|
242
|
+
sub_parser_add_canvas
|
243
|
+
sub_parser_add_grid
|
244
|
+
sub_parser_add_fmt_yx
|
245
|
+
sub_parser_add_ylim
|
246
|
+
sub_parser_add_xlim
|
247
|
+
|
248
|
+
when :lineplots, :lines
|
249
|
+
sub_parser_add_canvas
|
250
|
+
sub_parser_add_grid
|
251
|
+
sub_parser_add_fmt_xyxy
|
252
|
+
sub_parser_add_ylim
|
253
|
+
sub_parser_add_xlim
|
254
|
+
|
255
|
+
when :scatter, :s
|
256
|
+
sub_parser_add_canvas
|
257
|
+
sub_parser_add_grid
|
258
|
+
sub_parser_add_fmt_xyxy
|
259
|
+
sub_parser_add_ylim
|
260
|
+
sub_parser_add_xlim
|
261
|
+
|
262
|
+
when :density, :d
|
263
|
+
sub_parser_add_canvas
|
264
|
+
sub_parser_add_grid
|
265
|
+
sub_parser_add_fmt_xyxy
|
266
|
+
sub_parser_add_ylim
|
267
|
+
sub_parser_add_xlim
|
268
|
+
|
269
|
+
when :boxplot, :box
|
270
|
+
sub_parser_add_xlim
|
271
|
+
|
272
|
+
when :colors, :color, :colours, :colour
|
273
|
+
sub_parser.on_head('-n', '--names', 'show color names only', TrueClass) do |v|
|
274
|
+
options[:color_names] = v
|
275
|
+
end
|
276
|
+
|
277
|
+
else
|
278
|
+
error_message = "uplot: unrecognized command '#{command}'"
|
279
|
+
if YouPlot.run_as_executable?
|
280
|
+
warn error_message
|
281
|
+
exit 1
|
282
|
+
else
|
283
|
+
raise Error, error_message
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
def parse_options(argv = ARGV)
|
289
|
+
begin
|
290
|
+
create_main_parser.order!(argv)
|
291
|
+
rescue OptionParser::ParseError => e
|
292
|
+
warn "uplot: #{e.message}"
|
293
|
+
exit 1 if YouPlot.run_as_executable?
|
294
|
+
end
|
295
|
+
|
296
|
+
@command = argv.shift&.to_sym
|
297
|
+
|
298
|
+
begin
|
299
|
+
create_sub_parser&.parse!(argv)
|
300
|
+
rescue OptionParser::ParseError => e
|
301
|
+
warn "uplot: #{e.message}"
|
302
|
+
exit 1 if YouPlot.run_as_executable?
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|