tb 0.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. data/README +62 -50
  2. data/bin/tb +22 -18
  3. data/lib/tb.rb +35 -19
  4. data/lib/tb/basic.rb +85 -86
  5. data/lib/tb/catreader.rb +33 -116
  6. data/lib/tb/cmd_cat.rb +31 -27
  7. data/lib/tb/cmd_consecutive.rb +45 -35
  8. data/lib/tb/cmd_crop.rb +86 -52
  9. data/lib/tb/cmd_cross.rb +113 -71
  10. data/lib/tb/cmd_cut.rb +49 -44
  11. data/lib/tb/cmd_git_log.rb +193 -0
  12. data/lib/tb/cmd_grep.rb +43 -32
  13. data/lib/tb/cmd_group.rb +63 -39
  14. data/lib/tb/cmd_gsub.rb +53 -43
  15. data/lib/tb/cmd_help.rb +51 -24
  16. data/lib/tb/cmd_join.rb +32 -35
  17. data/lib/tb/cmd_ls.rb +233 -205
  18. data/lib/tb/cmd_mheader.rb +47 -37
  19. data/lib/tb/cmd_nest.rb +94 -0
  20. data/lib/tb/cmd_newfield.rb +29 -33
  21. data/lib/tb/cmd_rename.rb +40 -32
  22. data/lib/tb/cmd_shape.rb +31 -24
  23. data/lib/tb/cmd_sort.rb +46 -25
  24. data/lib/tb/cmd_svn_log.rb +47 -28
  25. data/lib/tb/cmd_tar_tvf.rb +447 -0
  26. data/lib/tb/cmd_to_csv.rb +60 -0
  27. data/lib/tb/cmd_to_json.rb +60 -0
  28. data/lib/tb/cmd_to_pnm.rb +48 -0
  29. data/lib/tb/cmd_to_pp.rb +71 -0
  30. data/lib/tb/cmd_to_tsv.rb +48 -0
  31. data/lib/tb/cmd_to_yaml.rb +52 -0
  32. data/lib/tb/cmd_unnest.rb +118 -0
  33. data/lib/tb/cmdmain.rb +24 -20
  34. data/lib/tb/cmdtop.rb +33 -25
  35. data/lib/tb/cmdutil.rb +26 -66
  36. data/lib/tb/csv.rb +46 -34
  37. data/lib/tb/enum.rb +294 -0
  38. data/lib/tb/enumerable.rb +198 -7
  39. data/lib/tb/enumerator.rb +73 -0
  40. data/lib/tb/fieldset.rb +27 -19
  41. data/lib/tb/fileenumerator.rb +365 -0
  42. data/lib/tb/json.rb +50 -0
  43. data/lib/tb/pager.rb +6 -6
  44. data/lib/tb/pairs.rb +227 -0
  45. data/lib/tb/pnm.rb +23 -22
  46. data/lib/tb/reader.rb +52 -49
  47. data/lib/tb/record.rb +48 -19
  48. data/lib/tb/revcmp.rb +38 -0
  49. data/lib/tb/ropen.rb +74 -57
  50. data/lib/tb/search.rb +25 -21
  51. data/lib/tb/tsv.rb +31 -34
  52. data/sample/excel2csv +24 -20
  53. data/sample/poi-xls2csv.rb +24 -20
  54. data/sample/poi-xls2csv.sh +22 -18
  55. data/sample/tbplot +185 -127
  56. data/test-all-cov.rb +3 -3
  57. data/test-all.rb +1 -1
  58. data/test/test_basic.rb +26 -10
  59. data/test/test_catreader.rb +7 -6
  60. data/test/test_cmd_cat.rb +32 -0
  61. data/test/test_cmd_consecutive.rb +10 -0
  62. data/test/test_cmd_crop.rb +4 -4
  63. data/test/test_cmd_cross.rb +16 -4
  64. data/test/test_cmd_git_log.rb +46 -0
  65. data/test/test_cmd_help.rb +17 -12
  66. data/test/test_cmd_join.rb +21 -1
  67. data/test/test_cmd_ls.rb +3 -4
  68. data/test/test_cmd_mheader.rb +17 -11
  69. data/test/test_cmd_nest.rb +49 -0
  70. data/test/test_cmd_sort.rb +15 -0
  71. data/test/test_cmd_tar_tvf.rb +281 -0
  72. data/test/{test_cmd_csv.rb → test_cmd_to_csv.rb} +35 -21
  73. data/test/{test_cmd_json.rb → test_cmd_to_json.rb} +31 -3
  74. data/test/{test_cmd_pnm.rb → test_cmd_to_pnm.rb} +2 -2
  75. data/test/{test_cmd_pp.rb → test_cmd_to_pp.rb} +4 -4
  76. data/test/{test_cmd_tsv.rb → test_cmd_to_tsv.rb} +4 -4
  77. data/test/{test_cmd_yaml.rb → test_cmd_to_yaml.rb} +3 -3
  78. data/test/test_cmd_unnest.rb +89 -0
  79. data/test/test_cmdtty.rb +19 -13
  80. data/test/test_enumerable.rb +83 -1
  81. data/test/test_fileenumerator.rb +265 -0
  82. data/test/test_json.rb +15 -0
  83. data/test/test_pager.rb +3 -4
  84. data/test/test_pairs.rb +122 -0
  85. data/test/test_pnm.rb +24 -24
  86. data/test/test_reader.rb +35 -13
  87. data/test/test_revcmp.rb +10 -0
  88. data/test/test_tbenum.rb +173 -0
  89. metadata +51 -23
  90. data/lib/tb/cmd_csv.rb +0 -42
  91. data/lib/tb/cmd_json.rb +0 -60
  92. data/lib/tb/cmd_pnm.rb +0 -43
  93. data/lib/tb/cmd_pp.rb +0 -70
  94. data/lib/tb/cmd_tsv.rb +0 -43
  95. data/lib/tb/cmd_yaml.rb +0 -47
@@ -2,29 +2,33 @@
2
2
 
3
3
  # sample/poi-xls2csv.rb - XLS to CSV convert using Apache POI with JRuby.
4
4
  #
5
- # Copyright (C) 2011 Tanaka Akira <akr@fsij.org>
5
+ # Copyright (C) 2011-2012 Tanaka Akira <akr@fsij.org>
6
6
  #
7
7
  # Redistribution and use in source and binary forms, with or without
8
- # modification, are permitted provided that the following conditions are met:
8
+ # modification, are permitted provided that the following conditions
9
+ # are met:
9
10
  #
10
- # 1. Redistributions of source code must retain the above copyright notice, this
11
- # list of conditions and the following disclaimer.
12
- # 2. Redistributions in binary form must reproduce the above copyright notice,
13
- # this list of conditions and the following disclaimer in the documentation
14
- # and/or other materials provided with the distribution.
15
- # 3. The name of the author may not be used to endorse or promote products
16
- # derived from this software without specific prior written permission.
11
+ # 1. Redistributions of source code must retain the above copyright
12
+ # notice, this list of conditions and the following disclaimer.
13
+ # 2. Redistributions in binary form must reproduce the above
14
+ # copyright notice, this list of conditions and the following
15
+ # disclaimer in the documentation and/or other materials provided
16
+ # with the distribution.
17
+ # 3. The name of the author may not be used to endorse or promote
18
+ # products derived from this software without specific prior
19
+ # written permission.
17
20
  #
18
- # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
19
- # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20
- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
21
- # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
23
- # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
- # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
- # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26
- # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
27
- # OF SUCH DAMAGE.
21
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
22
+ # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
25
+ # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27
+ # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31
+ # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
32
 
29
33
  $KCODE = 'u'
30
34
 
@@ -382,7 +386,7 @@ def convert_book(filename, input, csvgen)
382
386
  end
383
387
  end
384
388
 
385
- Tb.csv_stream_output(STDOUT) {|csvgen|
389
+ Tb.csv_stream_output($stdout) {|csvgen|
386
390
  argv = ARGV.empty? ? ['-'] : ARGV
387
391
  argv.each {|filename|
388
392
  if filename == '-'
@@ -5,26 +5,30 @@
5
5
  # Copyright (C) 2011 Tanaka Akira <akr@fsij.org>
6
6
  #
7
7
  # Redistribution and use in source and binary forms, with or without
8
- # modification, are permitted provided that the following conditions are met:
8
+ # modification, are permitted provided that the following conditions
9
+ # are met:
9
10
  #
10
- # 1. Redistributions of source code must retain the above copyright notice, this
11
- # list of conditions and the following disclaimer.
12
- # 2. Redistributions in binary form must reproduce the above copyright notice,
13
- # this list of conditions and the following disclaimer in the documentation
14
- # and/or other materials provided with the distribution.
15
- # 3. The name of the author may not be used to endorse or promote products
16
- # derived from this software without specific prior written permission.
11
+ # 1. Redistributions of source code must retain the above copyright
12
+ # notice, this list of conditions and the following disclaimer.
13
+ # 2. Redistributions in binary form must reproduce the above
14
+ # copyright notice, this list of conditions and the following
15
+ # disclaimer in the documentation and/or other materials provided
16
+ # with the distribution.
17
+ # 3. The name of the author may not be used to endorse or promote
18
+ # products derived from this software without specific prior
19
+ # written permission.
17
20
  #
18
- # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
19
- # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20
- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
21
- # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
23
- # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
- # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
- # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26
- # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
27
- # OF SUCH DAMAGE.
21
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
22
+ # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
25
+ # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27
+ # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31
+ # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
32
 
29
33
  # Ubuntu libjakarta-poi-java package installs /usr/share/java/jakarta-poi.jar.
30
34
 
data/sample/tbplot CHANGED
@@ -1,45 +1,41 @@
1
1
  #!/usr/bin/env ruby
2
2
  #
3
- # Copyright (C) 2011 Tanaka Akira <akr@fsij.org>
3
+ # Copyright (C) 2011-2012 Tanaka Akira <akr@fsij.org>
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without
6
- # modification, are permitted provided that the following conditions are met:
6
+ # modification, are permitted provided that the following conditions
7
+ # are met:
7
8
  #
8
- # 1. Redistributions of source code must retain the above copyright notice, this
9
- # list of conditions and the following disclaimer.
10
- # 2. Redistributions in binary form must reproduce the above copyright notice,
11
- # this list of conditions and the following disclaimer in the documentation
12
- # and/or other materials provided with the distribution.
13
- # 3. The name of the author may not be used to endorse or promote products
14
- # derived from this software without specific prior written permission.
9
+ # 1. Redistributions of source code must retain the above copyright
10
+ # notice, this list of conditions and the following disclaimer.
11
+ # 2. Redistributions in binary form must reproduce the above
12
+ # copyright notice, this list of conditions and the following
13
+ # disclaimer in the documentation and/or other materials provided
14
+ # with the distribution.
15
+ # 3. The name of the author may not be used to endorse or promote
16
+ # products derived from this software without specific prior
17
+ # written permission.
15
18
  #
16
- # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17
- # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18
- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19
- # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20
- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21
- # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22
- # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23
- # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24
- # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
25
- # OF SUCH DAMAGE.
19
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
20
+ # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23
+ # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
25
+ # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
28
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29
+ # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
30
 
27
31
  # plot a graph using gnuplot.
28
32
 
29
33
  # usage:
30
- # tbplot [-x field] [-y field] [--shape field] [--color field] [--size field] [--facet-x field] [--facet-y field] filename
34
+ # tbplot [-x field,...] [-y field,...] [--shape field] [--color field] [--size field] [--facet-x field] [--facet-y field] filename
31
35
 
32
36
  $:.unshift '/home/akr/ruby/tb/lib'
33
37
 
34
- require 'optparse'
35
- require 'tempfile'
36
- require 'time'
37
- require 'tb'
38
-
39
- def err(msg)
40
- STDERR.puts msg
41
- exit false
42
- end
38
+ require 'tb/cmdtop'
43
39
 
44
40
  def gnuplot_escape_string(string)
45
41
  string = string.dup.force_encoding("ascii-8bit") if string.respond_to? :force_encoding
@@ -123,6 +119,24 @@ class ValueChecker
123
119
  end
124
120
  end
125
121
 
122
+ class AxisScale
123
+ # create an AxisScale object.
124
+ #
125
+ # AxisScale.new("fieldname")
126
+ # AxisScale.new("logscale(fieldname)")
127
+ def initialize(desc)
128
+ @desc = desc
129
+ if /\Alogscale\((.*)\)\z/ =~ desc
130
+ @field = $1
131
+ @logscale = true
132
+ else
133
+ @field = desc
134
+ @logscale = false
135
+ end
136
+ end
137
+ attr_reader :desc, :field, :logscale
138
+ end
139
+
126
140
  $x_field = nil
127
141
  $y_field = nil
128
142
  $shape_field = nil
@@ -132,117 +146,150 @@ $facet_x_field = nil
132
146
  $facet_y_field = nil
133
147
  $max_size = nil
134
148
 
135
- op = OptionParser.new
136
- op.def_option('-x FIELD', 'x-field') {|f| $x_field = f }
137
- op.def_option('-y FIELD', 'y-field') {|f| $y_field = f }
138
- op.def_option('--shape=FIELD', 'shape-field') {|f| $shape_field = f }
139
- op.def_option('--color=FIELD', 'color-field') {|f| $color_field = f }
140
- op.def_option('--size=FIELD', 'size-field') {|f| $size_field = f }
141
- op.def_option('--facet-x=FIELD', 'facet-x-field') {|f| $facet_x_field = f }
142
- op.def_option('--facet-y=FIELD', 'facet-y-field') {|f| $facet_y_field = f }
143
- op.def_option('--shapecolor=FIELD', 'shape-field and color-field') {|f| $shape_field = $color_field = f }
144
- op.def_option('--max-size=MAX-SIZE', 'maximum point size') {|v| $max_size = v.to_f }
149
+ def main_body(argv)
150
+ op = OptionParser.new
151
+ op.def_option('-x FIELD,...', 'x-fields') {|f| $x_field = split_field_list_argument(f).map {|ff| AxisScale.new(ff) } }
152
+ op.def_option('-y FIELD,...', 'y-fields') {|f| $y_field = split_field_list_argument(f).map {|ff| AxisScale.new(ff) } }
153
+ op.def_option('--shape=FIELD', 'shape-field') {|f| $shape_field = f }
154
+ op.def_option('--color=FIELD', 'color-field') {|f| $color_field = f }
155
+ op.def_option('--size=FIELD', 'size-field') {|f| $size_field = f }
156
+ op.def_option('--facet-x=FIELD', 'facet-x-field') {|f| $facet_x_field = f }
157
+ op.def_option('--facet-y=FIELD', 'facet-y-field') {|f| $facet_y_field = f }
158
+ op.def_option('--shapecolor=FIELD', 'shape-field and color-field') {|f| $shape_field = $color_field = f }
159
+ op.def_option('--max-size=MAX-SIZE', 'maximum point size') {|v| $max_size = v.to_f }
145
160
 
146
- op.parse!(ARGV)
161
+ op.parse!(argv)
147
162
 
148
- if !$max_size
149
- if $size_field
150
- $max_size = 100.0
151
- else
152
- $max_size = 1.0
163
+ if !$max_size
164
+ if $size_field
165
+ $max_size = 100.0
166
+ else
167
+ $max_size = 1.0
168
+ end
153
169
  end
154
- end
155
170
 
156
- tmps = {}
171
+ tmps = {}
172
+
173
+ argv = ARGV.empty? ? ['-'] : ARGV
174
+ r = Tb::CatReader.open(argv)
157
175
 
158
- argv = ARGV.empty? ? ['-'] : ARGV
159
- Tb::CatReader.open(argv) {|r|
160
- header0 = r.header
161
- header = header0.dup
162
- [$x_field, $y_field, $shape_field, $color_field, $size_field, $facet_x_field, $facet_y_field].each {|f|
163
- if f && !header.include?(f)
164
- err("field not found: #{f.inspect}")
165
- end
166
- }
167
- header -= [$x_field, $y_field, $shape_field, $color_field, $size_field, $facet_x_field, $facet_y_field].compact
168
- if !$x_field
169
- if header.empty?
170
- err("x-field not found")
171
- end
172
- $x_field = header.shift
173
- end
174
- if !$y_field
175
- if header.empty?
176
- err("y-field not found")
177
- end
178
- $y_field = header.shift
179
- end
180
176
  checkers = {}
181
- uniq_fields = [$x_field, $y_field, $shape_field, $color_field, $size_field, $facet_x_field, $facet_y_field].compact.uniq
182
- r.each {|ary|
183
- next if uniq_fields.any? {|f| ary[r.index_from_field(f)].nil? }
184
- vs = {}
185
- uniq_fields.each {|f|
186
- v = ary[r.index_from_field(f)]
187
- checkers[f] ||= ValueChecker.new
188
- vs[f] = checkers[f].check(v)
177
+ uniq_fields = nil
178
+ r.with_header {|header0|
179
+ header = header0.dup
180
+ fields = [$shape_field, $color_field, $size_field, $facet_x_field, $facet_y_field]
181
+ fields.concat $x_field.map {|as| as.field } if $x_field
182
+ fields.concat $y_field.map {|as| as.field } if $y_field
183
+ fields.each {|f|
184
+ if f && !header.include?(f)
185
+ err("field not found: #{f.inspect}")
186
+ end
189
187
  }
190
- x = vs[$x_field]
191
- y = vs[$y_field]
192
-
193
- shape_value = color_value = nil
194
- size = 1
195
- facet_x_field = facet_y_field = nil
196
- if $shape_field
197
- shape = vs[$shape_field]
198
- end
199
- if $color_field
200
- color = vs[$color_field]
201
- end
202
- if $size_field
203
- size = vs[$size_field]
204
- end
205
- if $facet_x_field
206
- facet_x = vs[$facet_x_field]
188
+ header -= fields.compact
189
+ if !$x_field
190
+ if header.empty?
191
+ err("x-field not found")
192
+ end
193
+ $x_field = [AxisScale.new(header.shift)]
207
194
  end
208
- if $facet_y_field
209
- facet_y = vs[$facet_y_field]
195
+ if !$y_field
196
+ if header.empty?
197
+ err("y-field not found")
198
+ end
199
+ $y_field = [AxisScale.new(header.shift)]
210
200
  end
211
- key1 = [facet_x, facet_y]
212
- key2 = [shape, color]
213
- tmps[key1] ||= {}
214
- tmps[key1][key2] ||= Tempfile.new('tbplot')
215
- tmps[key1][key2].puts "#{x} #{y} #{size}"
201
+ uniq_fields = [$shape_field, $color_field, $size_field, $facet_x_field, $facet_y_field].compact.uniq
202
+ }.each {|pairs|
203
+ $x_field.each {|x_scale|
204
+ x_field = x_scale.field
205
+ $y_field.each {|y_scale|
206
+ y_field = y_scale.field
207
+ next if uniq_fields.any? {|f| pairs[f].nil? }
208
+ next if pairs[x_field].nil?
209
+ vs = {}
210
+ checkers[x_field] ||= ValueChecker.new
211
+ vs[x_field] = checkers[x_field].check(pairs[x_field])
212
+ checkers[y_field] ||= ValueChecker.new
213
+ vs[y_field] = checkers[y_field].check(pairs[y_field])
214
+ uniq_fields.each {|f|
215
+ checkers[f] ||= ValueChecker.new
216
+ vs[f] = checkers[f].check(pairs[f])
217
+ }
218
+ x = vs[x_field]
219
+ y = vs[y_field]
220
+
221
+ size = 1
222
+ if $shape_field
223
+ shape = vs[$shape_field]
224
+ end
225
+ if $color_field
226
+ color = vs[$color_field]
227
+ end
228
+ if $size_field
229
+ size = vs[$size_field]
230
+ end
231
+ if $facet_x_field
232
+ facet_x = vs[$facet_x_field]
233
+ end
234
+ if $facet_y_field
235
+ facet_y = vs[$facet_y_field]
236
+ end
237
+ key1 = [facet_x, facet_y, x_scale, y_scale]
238
+ key2 = [shape, color]
239
+ tmps[key1] ||= {}
240
+ tmps[key1][key2] ||= Tempfile.new('tbplot')
241
+ tmps[key1][key2].puts "#{x} #{y} #{size}"
242
+ }
243
+ }
216
244
  }
245
+
217
246
  tmps.each {|k1, h| h.each {|k2, v| v.close } }
218
247
  gnuplot_command = ''
219
- if 0 < checkers[$x_field].time || 0 < checkers[$y_field].time
220
- gnuplot_command << 'set timefmt "%Y-%m-%dT%H:%M:%SZ"' << "\n"
221
- end
222
- if 0 < checkers[$x_field].time
223
- gnuplot_command << "set xdata time\n"
224
- gnuplot_command << "set format x #{gnuplot_escape_string(checkers[$x_field].tic_format)}\n"
225
- end
226
- if 0 < checkers[$y_field].time
227
- gnuplot_command << "set ydata time\n"
228
- gnuplot_command << "set format y #{gnuplot_escape_string(checkers[$y_field].tic_format)}\n"
229
- end
230
- gnuplot_command << "set xlabel #{gnuplot_escape_string($x_field)}\n"
231
- gnuplot_command << "set ylabel #{gnuplot_escape_string($y_field)}\n"
232
- if $size_field
233
- pointsize = $max_size / checkers[$size_field].numeric_max
234
- gnuplot_command << "set pointsize #{pointsize}\n"
235
- end
236
- if $facet_x_field || $facet_y_field
237
- xsize = $facet_x_field ? 1.0 / checkers[$facet_x_field].values.size : 1.0
238
- ysize = $facet_y_field ? 1.0 / checkers[$facet_y_field].values.size : 1.0
248
+ gnuplot_command << 'set timefmt "%Y-%m-%dT%H:%M:%SZ"' << "\n"
249
+ use_multiplot = false
250
+ if $facet_x_field || $facet_y_field || 1 < $x_field.length || 1 < $y_field.length
251
+ use_multiplot = true
252
+ x_numgraph = ($facet_x_field ? checkers[$facet_x_field].values.size : 1) * $x_field.length
253
+ y_numgraph = ($facet_y_field ? checkers[$facet_y_field].values.size : 1) * $y_field.length
254
+ xsize = 1.0 / x_numgraph
255
+ ysize = 1.0 / y_numgraph
239
256
  gnuplot_command << "set multiplot\n"
240
257
  gnuplot_command << "set size #{xsize},#{ysize}\n"
241
258
  end
242
- tmps.each {|(facet_x, facet_y), h|
243
- if $facet_x_field || $facet_y_field
244
- xorigin = $facet_x_field ? (checkers[$facet_x_field].categorical_index(facet_x)-1.0)/checkers[$facet_x_field].values.size : 0
245
- yorigin = $facet_y_field ? 1.0-(checkers[$facet_y_field].categorical_index(facet_y)-0.0)/checkers[$facet_y_field].values.size : 0
259
+
260
+ tmps.each {|(facet_x, facet_y, x_scale, y_scale), h|
261
+ x_field = x_scale.field
262
+ y_field = y_scale.field
263
+ gnuplot_command << (x_scale.logscale ? "set" : "unset") << " logscale x\n"
264
+ gnuplot_command << (y_scale.logscale ? "set" : "unset") << " logscale y\n"
265
+ if 0 < checkers[x_field].time
266
+ gnuplot_command << "set xdata time\n"
267
+ gnuplot_command << "set format x #{gnuplot_escape_string(checkers[x_field].tic_format)}\n"
268
+ end
269
+ if 0 < checkers[y_field].time
270
+ gnuplot_command << "set ydata time\n"
271
+ gnuplot_command << "set format y #{gnuplot_escape_string(checkers[y_field].tic_format)}\n"
272
+ end
273
+ gnuplot_command << "set xlabel #{gnuplot_escape_string(x_field)}\n"
274
+ gnuplot_command << "set ylabel #{gnuplot_escape_string(y_field)}\n"
275
+ if $size_field
276
+ pointsize = $max_size / checkers[$size_field].numeric_max
277
+ gnuplot_command << "set pointsize #{pointsize}\n"
278
+ end
279
+
280
+ if use_multiplot
281
+ x_graphindex = 0.0
282
+ if $facet_x_field
283
+ x_graphindex += (checkers[$facet_x_field].categorical_index(facet_x)-1) * $x_field.length
284
+ end
285
+ x_graphindex += $x_field.index(x_scale)
286
+ xorigin = x_graphindex / x_numgraph
287
+ y_graphindex = 0.0
288
+ if $facet_y_field
289
+ y_graphindex += (checkers[$facet_y_field].categorical_index(facet_y)-1) * $y_field.length
290
+ end
291
+ y_graphindex += $y_field.index(y_scale)
292
+ yorigin = (y_numgraph - y_graphindex - 1) / y_numgraph
246
293
  gnuplot_command << "set origin #{xorigin},#{yorigin}\n"
247
294
  end
248
295
  gnuplot_command << 'plot '
@@ -282,12 +329,23 @@ Tb::CatReader.open(argv) {|r|
282
329
  }
283
330
  gnuplot_command << "\n"
284
331
  }
285
- if $facet_x_field || $facet_y_field
332
+ if use_multiplot
286
333
  gnuplot_command << "unset multiplot\n"
287
334
  end
288
335
  gnuplot_command << "pause mouse any\n"
289
336
  tmp_gnuplot_command = Tempfile.new(['tbplot', '.gp'])
290
337
  tmp_gnuplot_command << gnuplot_command
291
338
  tmp_gnuplot_command.close
339
+ #puts gnuplot_command; sleep 100
292
340
  system('gnuplot', tmp_gnuplot_command.path)
293
- }
341
+ end
342
+
343
+
344
+ def main(argv)
345
+ main_body(argv)
346
+ rescue SystemExit
347
+ $stderr.puts $!.message if $!.message != 'exit'
348
+ raise
349
+ end
350
+
351
+ main(ARGV)