tb 0.8 → 0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/README +14 -7
  3. data/bin/tb +3 -3
  4. data/lib/tb.rb +3 -3
  5. data/lib/tb/basic.rb +34 -34
  6. data/lib/tb/catreader.rb +3 -3
  7. data/lib/tb/cmd_cat.rb +5 -5
  8. data/lib/tb/cmd_consecutive.rb +4 -4
  9. data/lib/tb/cmd_crop.rb +4 -4
  10. data/lib/tb/cmd_cross.rb +3 -3
  11. data/lib/tb/cmd_cut.rb +3 -3
  12. data/lib/tb/cmd_git.rb +3 -3
  13. data/lib/tb/cmd_grep.rb +3 -3
  14. data/lib/tb/cmd_group.rb +3 -3
  15. data/lib/tb/cmd_gsub.rb +3 -3
  16. data/lib/tb/cmd_help.rb +3 -3
  17. data/lib/tb/cmd_join.rb +3 -3
  18. data/lib/tb/cmd_ls.rb +3 -3
  19. data/lib/tb/cmd_melt.rb +3 -3
  20. data/lib/tb/cmd_mheader.rb +3 -3
  21. data/lib/tb/cmd_nest.rb +3 -3
  22. data/lib/tb/cmd_newfield.rb +17 -7
  23. data/lib/tb/cmd_rename.rb +3 -3
  24. data/lib/tb/cmd_shape.rb +3 -3
  25. data/lib/tb/cmd_sort.rb +3 -3
  26. data/lib/tb/cmd_svn.rb +3 -3
  27. data/lib/tb/cmd_tar.rb +3 -3
  28. data/lib/tb/cmd_to_csv.rb +4 -4
  29. data/lib/tb/cmd_to_json.rb +3 -3
  30. data/lib/tb/cmd_to_ltsv.rb +4 -4
  31. data/lib/tb/cmd_to_pnm.rb +3 -3
  32. data/lib/tb/cmd_to_pp.rb +3 -3
  33. data/lib/tb/cmd_to_tsv.rb +4 -4
  34. data/lib/tb/cmd_to_yaml.rb +3 -3
  35. data/lib/tb/cmd_unmelt.rb +3 -3
  36. data/lib/tb/cmd_unnest.rb +5 -4
  37. data/lib/tb/cmdmain.rb +3 -3
  38. data/lib/tb/cmdtop.rb +3 -3
  39. data/lib/tb/cmdutil.rb +3 -3
  40. data/lib/tb/csv.rb +10 -4
  41. data/lib/tb/customcmp.rb +3 -3
  42. data/lib/tb/customeq.rb +3 -3
  43. data/lib/tb/enumerable.rb +3 -3
  44. data/lib/tb/enumerator.rb +3 -3
  45. data/lib/tb/ex_enumerable.rb +2 -2
  46. data/lib/tb/ex_enumerator.rb +4 -4
  47. data/lib/tb/fieldset.rb +3 -3
  48. data/lib/tb/fileenumerator.rb +6 -6
  49. data/lib/tb/func.rb +3 -3
  50. data/lib/tb/json.rb +3 -3
  51. data/lib/tb/ltsv.rb +32 -7
  52. data/lib/tb/pnm.rb +3 -3
  53. data/lib/tb/reader.rb +3 -3
  54. data/lib/tb/record.rb +3 -3
  55. data/lib/tb/revcmp.rb +3 -3
  56. data/lib/tb/ropen.rb +23 -23
  57. data/lib/tb/search.rb +7 -7
  58. data/lib/tb/tsv.rb +3 -3
  59. data/lib/tb/zipper.rb +3 -3
  60. data/sample/excel2csv +36 -36
  61. data/sample/poi-xls2csv.rb +78 -78
  62. data/sample/poi-xls2csv.sh +3 -3
  63. data/sample/tbplot +214 -112
  64. data/test/test_basic.rb +4 -4
  65. data/test/test_cmd_newfield.rb +17 -3
  66. data/test/test_ex_enumerable.rb +18 -18
  67. data/test/test_ltsv.rb +8 -0
  68. metadata +5 -5
@@ -3,11 +3,11 @@
3
3
  # sample/poi-xls2csv.rb - XLS to CSV convert using Apache POI with JRuby.
4
4
  #
5
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
8
  # modification, are permitted provided that the following conditions
9
9
  # are met:
10
- #
10
+ #
11
11
  # 1. Redistributions of source code must retain the above copyright
12
12
  # notice, this list of conditions and the following disclaimer.
13
13
  # 2. Redistributions in binary form must reproduce the above
@@ -17,7 +17,7 @@
17
17
  # 3. The name of the author may not be used to endorse or promote
18
18
  # products derived from this software without specific prior
19
19
  # written permission.
20
- #
20
+ #
21
21
  # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
22
22
  # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
23
  # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -85,7 +85,7 @@ def convert_single_cell(cell)
85
85
  ExcelDateStylesHash[style.getDataFormat]
86
86
  d = cell.getDateCellValue
87
87
  val = "%d-%02d-%02d %02d:%02d:%02d" % [
88
- d.getYear+1900, d.getMonth+1, d.getDate, d.getHours, d.getMinutes, d.getSeconds
88
+ d.getYear+1900, d.getMonth+1, d.getDate, d.getHours, d.getMinutes, d.getSeconds
89
89
  ]
90
90
  val = val + ":date" if $opt_type
91
91
  else
@@ -119,9 +119,9 @@ def convert_cell(sheet, merged, row, x, y)
119
119
  topleft_cell = sheet.getRow(y1).getCell(x1)
120
120
  if $opt_mergecells == 'topleft'
121
121
  if x == x1 && y == y1
122
- val = convert_single_cell(topleft_cell)
122
+ val = convert_single_cell(topleft_cell)
123
123
  else
124
- val = nil
124
+ val = nil
125
125
  end
126
126
  else
127
127
  val = convert_single_cell(topleft_cell)
@@ -146,7 +146,7 @@ def get_merged_regions(sheet)
146
146
  rid = [x1, y1, x2, y2]
147
147
  y1.upto(y2) {|y|
148
148
  x1.upto(x2) {|x|
149
- merged[[x,y]] = rid
149
+ merged[[x,y]] = rid
150
150
  }
151
151
  }
152
152
  }
@@ -205,66 +205,66 @@ def convert_horizontal_borders(sheet, merged, upper_y, min_firstcol)
205
205
  left_x = right_x - 1
206
206
  upper_line = lower_line = left_line = right_line = false
207
207
  if upper_row
208
- if !merged[[left_x, upper_y]] || !merged[[right_x, upper_y]] ||
209
- merged[[left_x, upper_y]] != merged[[right_x, upper_y]]
210
- if !upper_line && upper_cellrange.include?(left_x) &&
211
- (upperleft_cell = upper_row.getCell(left_x)) &&
212
- upperleft_cell.getCellStyle.getBorderRight != Java::HSSFCellStyle::BORDER_NONE
213
- upper_line = true
214
- end
215
- if !upper_line && upper_cellrange.include?(right_x) &&
216
- (upperright_cell = upper_row.getCell(right_x)) &&
217
- upperright_cell.getCellStyle.getBorderLeft != Java::HSSFCellStyle::BORDER_NONE
218
- upper_line = true
219
- end
220
- end
221
- if !merged[[left_x, upper_y]] || !merged[[left_x, lower_y]] ||
222
- merged[[left_x, upper_y]] != merged[[left_x, lower_y]]
223
- if !left_line && upper_cellrange.include?(left_x) &&
224
- (upperleft_cell = upper_row.getCell(left_x)) &&
225
- upperleft_cell.getCellStyle.getBorderBottom != Java::HSSFCellStyle::BORDER_NONE
226
- left_line = true
227
- end
228
- end
229
- if !merged[[right_x, upper_y]] || !merged[[right_x, lower_y]] ||
230
- merged[[right_x, upper_y]] != merged[[right_x, lower_y]]
231
- if !right_line && upper_cellrange.include?(right_x) &&
232
- (upperright_cell = upper_row.getCell(right_x)) &&
233
- upperright_cell.getCellStyle.getBorderBottom != Java::HSSFCellStyle::BORDER_NONE
234
- right_line = true
235
- end
236
- end
208
+ if !merged[[left_x, upper_y]] || !merged[[right_x, upper_y]] ||
209
+ merged[[left_x, upper_y]] != merged[[right_x, upper_y]]
210
+ if !upper_line && upper_cellrange.include?(left_x) &&
211
+ (upperleft_cell = upper_row.getCell(left_x)) &&
212
+ upperleft_cell.getCellStyle.getBorderRight != Java::HSSFCellStyle::BORDER_NONE
213
+ upper_line = true
214
+ end
215
+ if !upper_line && upper_cellrange.include?(right_x) &&
216
+ (upperright_cell = upper_row.getCell(right_x)) &&
217
+ upperright_cell.getCellStyle.getBorderLeft != Java::HSSFCellStyle::BORDER_NONE
218
+ upper_line = true
219
+ end
220
+ end
221
+ if !merged[[left_x, upper_y]] || !merged[[left_x, lower_y]] ||
222
+ merged[[left_x, upper_y]] != merged[[left_x, lower_y]]
223
+ if !left_line && upper_cellrange.include?(left_x) &&
224
+ (upperleft_cell = upper_row.getCell(left_x)) &&
225
+ upperleft_cell.getCellStyle.getBorderBottom != Java::HSSFCellStyle::BORDER_NONE
226
+ left_line = true
227
+ end
228
+ end
229
+ if !merged[[right_x, upper_y]] || !merged[[right_x, lower_y]] ||
230
+ merged[[right_x, upper_y]] != merged[[right_x, lower_y]]
231
+ if !right_line && upper_cellrange.include?(right_x) &&
232
+ (upperright_cell = upper_row.getCell(right_x)) &&
233
+ upperright_cell.getCellStyle.getBorderBottom != Java::HSSFCellStyle::BORDER_NONE
234
+ right_line = true
235
+ end
236
+ end
237
237
  end
238
238
  if lower_row
239
- if !merged[[left_x, lower_y]] || !merged[[right_x, lower_y]] ||
240
- merged[[left_x, lower_y]] != merged[[right_x, lower_y]]
241
- if !lower_line && lower_cellrange.include?(left_x) &&
242
- (lowerleft_cell = lower_row.getCell(left_x)) &&
243
- lowerleft_cell.getCellStyle.getBorderRight != Java::HSSFCellStyle::BORDER_NONE
244
- lower_line = true
245
- end
246
- if !lower_line && lower_cellrange.include?(right_x) &&
247
- (lowerright_cell = lower_row.getCell(right_x)) &&
248
- lowerright_cell.getCellStyle.getBorderLeft != Java::HSSFCellStyle::BORDER_NONE
249
- lower_line = true
250
- end
251
- end
252
- if !merged[[left_x, upper_y]] || !merged[[left_x, lower_y]] ||
253
- merged[[left_x, upper_y]] != merged[[left_x, lower_y]]
254
- if !left_line && lower_cellrange.include?(left_x) &&
255
- (lowerleft_cell = lower_row.getCell(left_x)) &&
256
- lowerleft_cell.getCellStyle.getBorderTop != Java::HSSFCellStyle::BORDER_NONE
257
- left_line = true
258
- end
259
- end
260
- if !merged[[right_x, upper_y]] || !merged[[right_x, lower_y]] ||
261
- merged[[right_x, upper_y]] != merged[[right_x, lower_y]]
262
- if !right_line && lower_cellrange.include?(right_x) &&
263
- (lowerright_cell = lower_row.getCell(right_x)) &&
264
- lowerright_cell.getCellStyle.getBorderTop != Java::HSSFCellStyle::BORDER_NONE
265
- right_line = true
266
- end
267
- end
239
+ if !merged[[left_x, lower_y]] || !merged[[right_x, lower_y]] ||
240
+ merged[[left_x, lower_y]] != merged[[right_x, lower_y]]
241
+ if !lower_line && lower_cellrange.include?(left_x) &&
242
+ (lowerleft_cell = lower_row.getCell(left_x)) &&
243
+ lowerleft_cell.getCellStyle.getBorderRight != Java::HSSFCellStyle::BORDER_NONE
244
+ lower_line = true
245
+ end
246
+ if !lower_line && lower_cellrange.include?(right_x) &&
247
+ (lowerright_cell = lower_row.getCell(right_x)) &&
248
+ lowerright_cell.getCellStyle.getBorderLeft != Java::HSSFCellStyle::BORDER_NONE
249
+ lower_line = true
250
+ end
251
+ end
252
+ if !merged[[left_x, upper_y]] || !merged[[left_x, lower_y]] ||
253
+ merged[[left_x, upper_y]] != merged[[left_x, lower_y]]
254
+ if !left_line && lower_cellrange.include?(left_x) &&
255
+ (lowerleft_cell = lower_row.getCell(left_x)) &&
256
+ lowerleft_cell.getCellStyle.getBorderTop != Java::HSSFCellStyle::BORDER_NONE
257
+ left_line = true
258
+ end
259
+ end
260
+ if !merged[[right_x, upper_y]] || !merged[[right_x, lower_y]] ||
261
+ merged[[right_x, upper_y]] != merged[[right_x, lower_y]]
262
+ if !right_line && lower_cellrange.include?(right_x) &&
263
+ (lowerright_cell = lower_row.getCell(right_x)) &&
264
+ lowerright_cell.getCellStyle.getBorderTop != Java::HSSFCellStyle::BORDER_NONE
265
+ right_line = true
266
+ end
267
+ end
268
268
  end
269
269
  if upper_line && lower_line && !left_line && !right_line
270
270
  joint = '|'
@@ -283,19 +283,19 @@ def convert_horizontal_borders(sheet, merged, upper_y, min_firstcol)
283
283
  hborder = nil
284
284
  cell_x = min_firstcol + i / 2
285
285
  if !merged[[cell_x, upper_y]] || !merged[[cell_x, lower_y]] ||
286
- merged[[cell_x, upper_y]] != merged[[cell_x, lower_y]]
287
- if !hborder && upper_row && upper_cellrange.include?(cell_x) &&
288
- (upper_cell = upper_row.getCell(cell_x)) &&
289
- upper_cell.getCellStyle.getBorderBottom != Java::HSSFCellStyle::BORDER_NONE
290
- hborder = '-'
291
- hborder = hborder + ":#{bordertype(upper_cell.getCellStyle.getBorderBottom)}" if $opt_type
292
- end
293
- if !hborder && lower_row && lower_cellrange.include?(cell_x) &&
294
- (lower_cell = lower_row.getCell(cell_x)) &&
295
- lower_cell.getCellStyle.getBorderTop != Java::HSSFCellStyle::BORDER_NONE
296
- hborder = '-'
297
- hborder = hborder + ":#{bordertype(lower_cell.getCellStyle.getBorderTop)}" if $opt_type
298
- end
286
+ merged[[cell_x, upper_y]] != merged[[cell_x, lower_y]]
287
+ if !hborder && upper_row && upper_cellrange.include?(cell_x) &&
288
+ (upper_cell = upper_row.getCell(cell_x)) &&
289
+ upper_cell.getCellStyle.getBorderBottom != Java::HSSFCellStyle::BORDER_NONE
290
+ hborder = '-'
291
+ hborder = hborder + ":#{bordertype(upper_cell.getCellStyle.getBorderBottom)}" if $opt_type
292
+ end
293
+ if !hborder && lower_row && lower_cellrange.include?(cell_x) &&
294
+ (lower_cell = lower_row.getCell(cell_x)) &&
295
+ lower_cell.getCellStyle.getBorderTop != Java::HSSFCellStyle::BORDER_NONE
296
+ hborder = '-'
297
+ hborder = hborder + ":#{bordertype(lower_cell.getCellStyle.getBorderTop)}" if $opt_type
298
+ end
299
299
  end
300
300
  #hborder ||= ' '
301
301
  ary << hborder
@@ -3,11 +3,11 @@
3
3
  # sample/poi-xls2csv.sh - script to run sample/poi-xls2csv.rb
4
4
  #
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
8
  # modification, are permitted provided that the following conditions
9
9
  # are met:
10
- #
10
+ #
11
11
  # 1. Redistributions of source code must retain the above copyright
12
12
  # notice, this list of conditions and the following disclaimer.
13
13
  # 2. Redistributions in binary form must reproduce the above
@@ -17,7 +17,7 @@
17
17
  # 3. The name of the author may not be used to endorse or promote
18
18
  # products derived from this software without specific prior
19
19
  # written permission.
20
- #
20
+ #
21
21
  # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
22
22
  # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
23
  # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env ruby
2
2
  #
3
- # Copyright (C) 2011-2012 Tanaka Akira <akr@fsij.org>
4
- #
3
+ # Copyright (C) 2011-2013 Tanaka Akira <akr@fsij.org>
4
+ #
5
5
  # Redistribution and use in source and binary forms, with or without
6
6
  # modification, are permitted provided that the following conditions
7
7
  # are met:
8
- #
8
+ #
9
9
  # 1. Redistributions of source code must retain the above copyright
10
10
  # notice, this list of conditions and the following disclaimer.
11
11
  # 2. Redistributions in binary form must reproduce the above
@@ -15,7 +15,7 @@
15
15
  # 3. The name of the author may not be used to endorse or promote
16
16
  # products derived from this software without specific prior
17
17
  # written permission.
18
- #
18
+ #
19
19
  # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
20
20
  # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
21
  # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -31,12 +31,51 @@
31
31
  # plot a graph using gnuplot.
32
32
 
33
33
  # usage:
34
- # tbplot [-x field,...] [-y field,...] [--shape field] [--color field] [--size field] [--facet-x field] [--facet-y field] filename
35
-
36
- $:.unshift '/home/akr/ruby/tb/lib'
34
+ # tbplot [options] table-filename [image-filename]
37
35
 
38
36
  require 'tb/cmdtop'
39
37
 
38
+ $x_field = nil
39
+ $y_field = nil
40
+ $shape_field = nil
41
+ $color_field = nil
42
+ $size_field = nil
43
+ $facet_x_field = nil
44
+ $facet_y_field = nil
45
+ $max_size = nil
46
+ $logx = nil
47
+ $logy = nil
48
+ $prompt = nil
49
+ $gnuplot_terminal = nil
50
+
51
+ def process_options(argv)
52
+ op = OptionParser.new
53
+ op.def_option('-x FIELD,...', 'x-fields') {|f| $x_field = split_field_list_argument(f).map {|ff| AxisScale.new(ff) } }
54
+ op.def_option('-y FIELD,...', 'y-fields') {|f| $y_field = split_field_list_argument(f).map {|ff| AxisScale.new(ff) } }
55
+ op.def_option('--shape=FIELD', 'shape-field') {|f| $shape_field = f }
56
+ op.def_option('--color=FIELD', 'color-field') {|f| $color_field = f }
57
+ op.def_option('--size=FIELD', 'size-field') {|f| $size_field = f }
58
+ op.def_option('--facet-x=FIELD', 'facet-x-field') {|f| $facet_x_field = f }
59
+ op.def_option('--facet-y=FIELD', 'facet-y-field') {|f| $facet_y_field = f }
60
+ op.def_option('--shapecolor=FIELD', 'shape-field and color-field') {|f| $shape_field = $color_field = f }
61
+ op.def_option('--max-size=MAX-SIZE', 'maximum point size') {|v| $max_size = v.to_f }
62
+ op.def_option('--loglog', 'use full log scale') {|v| $logx = $logy = true }
63
+ op.def_option('--logx', 'use log scale for x-axis') {|v| $logx = true }
64
+ op.def_option('--logy', 'use log scale for y-axis') {|v| $logy = true }
65
+ op.def_option('--prompt', 'enter gnuplot interactive mode') {|v| $prompt = true }
66
+ op.def_option('--gnuplot-terminal=TERMINAL', 'gnuplot terminal. e.g. "png size 500,500"') {|v| $gnuplot_terminal = v }
67
+
68
+ op.parse!(argv)
69
+
70
+ if !$max_size
71
+ if $size_field
72
+ $max_size = 100.0
73
+ else
74
+ $max_size = 1.0
75
+ end
76
+ end
77
+ end
78
+
40
79
  def gnuplot_escape_string(string)
41
80
  string = string.dup.force_encoding("ascii-8bit") if string.respond_to? :force_encoding
42
81
  '"' + string.gsub(/[^A-Za-z]/) {|c| sprintf("\\%03o", c.ord) } + '"'
@@ -70,14 +109,25 @@ class ValueChecker
70
109
  @numeric_min = val if val < @numeric_min
71
110
  @numeric_max = val if @numeric_max < val
72
111
  end
73
- elsif /\A\s*-?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?\s*\z/ =~ val
112
+ elsif /\A\s*-?(\d+)\s*\z/ =~ val
113
+ v = val.to_i
74
114
  @numeric += 1
75
115
  if @numeric == 1
76
- @numeric_min = @numeric_max = val
116
+ @numeric_min = @numeric_max = v
77
117
  else
78
- @numeric_min = val if val < @numeric_min
79
- @numeric_max = val if @numeric_max < val
118
+ @numeric_min = v if v < @numeric_min
119
+ @numeric_max = v if @numeric_max < v
80
120
  end
121
+ elsif /\A\s*-?(\d+\.\d*|\.\d+)([eE][-+]?\d+)?\s*\z/ =~ val
122
+ v = val.to_f
123
+ @numeric += 1
124
+ if @numeric == 1
125
+ @numeric_min = @numeric_max = v
126
+ else
127
+ @numeric_min = v if v < @numeric_min
128
+ @numeric_max = v if @numeric_max < v
129
+ end
130
+
81
131
  elsif /\A\s*-?\d+-\d\d(-\d\d(T\d\d(:\d\d(:\d\d(\.\d+)?(Z|[+-]\d\d:?\d\d)?)?)?)?)?\s*\z/ =~ val ||
82
132
  /\A\s*-?\d+\d\d\d\dT\d\d(\d\d(\d\d(\.\d+)?(Z|[+-]\d\d:?\d\d)?)?)?\s*\z/ =~ val
83
133
  @time += 1
@@ -123,10 +173,10 @@ class AxisScale
123
173
  # create an AxisScale object.
124
174
  #
125
175
  # AxisScale.new("fieldname")
126
- # AxisScale.new("logscale(fieldname)")
176
+ # AxisScale.new("log(fieldname)")
127
177
  def initialize(desc)
128
178
  @desc = desc
129
- if /\Alogscale\((.*)\)\z/ =~ desc
179
+ if /\Alog\((.*)\)\z/ =~ desc
130
180
  @field = $1
131
181
  @logscale = true
132
182
  else
@@ -134,117 +184,144 @@ class AxisScale
134
184
  @logscale = false
135
185
  end
136
186
  end
137
- attr_reader :desc, :field, :logscale
187
+ attr_reader :desc, :field
188
+ attr_accessor :logscale
138
189
  end
139
190
 
140
- $x_field = nil
141
- $y_field = nil
142
- $shape_field = nil
143
- $color_field = nil
144
- $size_field = nil
145
- $facet_x_field = nil
146
- $facet_y_field = nil
147
- $max_size = nil
148
-
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 }
160
-
161
- op.parse!(argv)
162
-
163
- if !$max_size
164
- if $size_field
165
- $max_size = 100.0
166
- else
167
- $max_size = 1.0
191
+ def bind_fields(header0, checkers)
192
+ header = header0.dup
193
+ fields = [$shape_field, $color_field, $size_field, $facet_x_field, $facet_y_field]
194
+ fields.concat $x_field.map {|as| as.field } if $x_field
195
+ fields.concat $y_field.map {|as| as.field } if $y_field
196
+ fields.each {|f|
197
+ if f && !header.include?(f)
198
+ err("field not found: #{f.inspect}")
199
+ end
200
+ }
201
+ header -= fields.compact
202
+ if !$x_field
203
+ if header.empty?
204
+ err("x-field not found")
205
+ end
206
+ $x_field = [AxisScale.new(header.shift)]
207
+ end
208
+ if !$y_field
209
+ if header.empty?
210
+ err("y-field not found")
168
211
  end
212
+ $y_field = [AxisScale.new(header.shift)]
169
213
  end
214
+ if !$shape_field && !$color_field && !header.empty?
215
+ $shape_field = $color_field = header.shift
216
+ end
217
+ if $logx
218
+ $x_field.each {|axis| axis.logscale = true }
219
+ end
220
+ if $logy
221
+ $y_field.each {|axis| axis.logscale = true }
222
+ end
223
+ uniq_fields = [$shape_field, $color_field, $size_field, $facet_x_field, $facet_y_field].compact.uniq
224
+ end
170
225
 
226
+ def input_table(table_filename)
171
227
  tmps = {}
228
+ checkers = {}
172
229
 
173
- argv = ARGV.empty? ? ['-'] : ARGV
174
- r = Tb::CatReader.open(argv)
230
+ r = Tb.open_reader(table_filename).to_fileenumerator
175
231
 
176
- checkers = {}
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
232
+ r.use {
233
+ r.with_header {|header|
234
+ header.each {|f|
235
+ checkers[f] ||= ValueChecker.new
236
+ }
237
+ }.each {|pairs|
238
+ pairs.each {|f, v|
239
+ checkers[f].check(v)
240
+ }
187
241
  }
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)]
194
- end
195
- if !$y_field
196
- if header.empty?
197
- err("y-field not found")
198
- end
199
- $y_field = [AxisScale.new(header.shift)]
200
- end
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])
242
+
243
+ uniq_fields = nil
244
+ r.with_header {|header0|
245
+ uniq_fields = bind_fields(header0, checkers)
246
+ }.each {|pairs|
247
+ $x_field.each {|x_scale|
248
+ x_field = x_scale.field
249
+ $y_field.each {|y_scale|
250
+ y_field = y_scale.field
251
+ next if uniq_fields.any? {|f| pairs[f].nil? }
252
+ next if pairs[x_field].nil?
253
+ vs = {}
254
+ vs[x_field] = checkers[x_field].check(pairs[x_field])
255
+ vs[y_field] = checkers[y_field].check(pairs[y_field])
256
+ uniq_fields.each {|f|
257
+ vs[f] = checkers[f].check(pairs[f])
258
+ }
259
+ x = vs[x_field]
260
+ y = vs[y_field]
261
+
262
+ size = 1
263
+ if $shape_field
264
+ shape = vs[$shape_field]
265
+ end
266
+ if $color_field
267
+ color = vs[$color_field]
268
+ end
269
+ if $size_field
270
+ size = vs[$size_field]
271
+ end
272
+ if $facet_x_field
273
+ facet_x = vs[$facet_x_field]
274
+ end
275
+ if $facet_y_field
276
+ facet_y = vs[$facet_y_field]
277
+ end
278
+ key1 = [facet_x, facet_y, x_scale, y_scale]
279
+ key2 = [shape, color]
280
+ tmps[key1] ||= {}
281
+ tmps[key1][key2] ||= Tempfile.new('tbplot')
282
+ tmps[key1][key2].puts "#{x} #{y} #{size}"
217
283
  }
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
284
  }
243
285
  }
244
286
  }
287
+ return checkers, tmps
288
+ end
245
289
 
290
+ def output_gnuplot(checkers, tmps, table_filename, image_filename)
246
291
  tmps.each {|k1, h| h.each {|k2, v| v.close } }
247
292
  gnuplot_command = ''
293
+
294
+ if image_filename
295
+ if $gnuplot_terminal
296
+ gnuplot_command << "set term #{$gnuplot_terminal}\n"
297
+ else
298
+ case image_filename
299
+ when /\.png\z/
300
+ gnuplot_command << "set term png\n"
301
+ when /\.eps\z/
302
+ gnuplot_command << "set term epscairo\n"
303
+ when /\.ps\z/
304
+ gnuplot_command << "set term postscript\n"
305
+ when /\.pdf\z/
306
+ gnuplot_command << "set term pdfcairo\n"
307
+ when /\.svg\z/
308
+ gnuplot_command << "set term svg\n"
309
+ when /\.jpeg\z|\.jpg\z/
310
+ gnuplot_command << "set term jpeg\n"
311
+ else
312
+ err("unknown image filename extension: #{image_filename.inspect}")
313
+ end
314
+ end
315
+ gnuplot_command << "set output #{gnuplot_escape_string image_filename}\n"
316
+ else
317
+ if $gnuplot_terminal
318
+ gnuplot_command << "set term #{$gnuplot_terminal}\n"
319
+ end
320
+ end
321
+
322
+ whole_title = File.basename(table_filename).sub(/\.(csv|json|ltsv|tsv)\z/, '')
323
+ gnuplot_command << "set title #{gnuplot_escape_string(whole_title)}\n"
324
+
248
325
  gnuplot_command << 'set timefmt "%Y-%m-%dT%H:%M:%SZ"' << "\n"
249
326
  use_multiplot = false
250
327
  if $facet_x_field || $facet_y_field || 1 < $x_field.length || 1 < $y_field.length
@@ -277,6 +354,16 @@ def main_body(argv)
277
354
  gnuplot_command << "set pointsize #{pointsize}\n"
278
355
  end
279
356
 
357
+ gnuplot_command << "set key outside\n"
358
+ #gnuplot_command << "unset key\n"
359
+ key_title = []
360
+ key_title << $shape_field if $shape_field
361
+ key_title << $color_field if $color_field
362
+ if !key_title.empty?
363
+ key_title = key_title.uniq.join(' ')
364
+ gnuplot_command << "set key title #{gnuplot_escape_string(key_title)}\n"
365
+ end
366
+
280
367
  if use_multiplot
281
368
  x_graphindex = 0.0
282
369
  if $facet_x_field
@@ -306,11 +393,12 @@ def main_body(argv)
306
393
  gnuplot_command << ' using 1:2:3 '
307
394
  title = []
308
395
  if shape_value
309
- title << " #{$shape_field}=#{shape_value.to_s}"
396
+ title << " #{shape_value.to_s}"
310
397
  end
311
398
  if color_value
312
- title << " #{$color_field}=#{color_value.to_s}"
399
+ title << " #{color_value.to_s}"
313
400
  end
401
+
314
402
  title = title.uniq.join(' ')
315
403
  gnuplot_command << ' title ' << gnuplot_escape_string(title)
316
404
  gnuplot_command << ' with points'
@@ -332,14 +420,28 @@ def main_body(argv)
332
420
  if use_multiplot
333
421
  gnuplot_command << "unset multiplot\n"
334
422
  end
335
- gnuplot_command << "pause mouse any\n"
423
+ if !image_filename && !$prompt
424
+ gnuplot_command << "pause mouse any\n"
425
+ end
336
426
  tmp_gnuplot_command = Tempfile.new(['tbplot', '.gp'])
337
427
  tmp_gnuplot_command << gnuplot_command
338
428
  tmp_gnuplot_command.close
339
429
  #puts gnuplot_command; sleep 100
340
- system('gnuplot', tmp_gnuplot_command.path)
430
+ args = ['gnuplot', tmp_gnuplot_command.path]
431
+ if $prompt
432
+ args << '-' # enter interactive mode.
433
+ end
434
+ system(*args)
341
435
  end
342
436
 
437
+ def main_body(argv)
438
+ process_options(argv)
439
+ argv = ['-'] if argv.empty?
440
+ table_filename = argv.shift
441
+ image_filename = argv.shift
442
+ checkers, tmps = input_table(table_filename)
443
+ output_gnuplot(checkers, tmps, table_filename, image_filename)
444
+ end
343
445
 
344
446
  def main(argv)
345
447
  main_body(argv)