tb 0.8 → 0.9

Sign up to get free protection for your applications and to get access to all the features.
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)