youplot 0.3.0 → 0.3.5

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