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.
- checksums.yaml +4 -4
- data/README +14 -7
- data/bin/tb +3 -3
- data/lib/tb.rb +3 -3
- data/lib/tb/basic.rb +34 -34
- data/lib/tb/catreader.rb +3 -3
- data/lib/tb/cmd_cat.rb +5 -5
- data/lib/tb/cmd_consecutive.rb +4 -4
- data/lib/tb/cmd_crop.rb +4 -4
- data/lib/tb/cmd_cross.rb +3 -3
- data/lib/tb/cmd_cut.rb +3 -3
- data/lib/tb/cmd_git.rb +3 -3
- data/lib/tb/cmd_grep.rb +3 -3
- data/lib/tb/cmd_group.rb +3 -3
- data/lib/tb/cmd_gsub.rb +3 -3
- data/lib/tb/cmd_help.rb +3 -3
- data/lib/tb/cmd_join.rb +3 -3
- data/lib/tb/cmd_ls.rb +3 -3
- data/lib/tb/cmd_melt.rb +3 -3
- data/lib/tb/cmd_mheader.rb +3 -3
- data/lib/tb/cmd_nest.rb +3 -3
- data/lib/tb/cmd_newfield.rb +17 -7
- data/lib/tb/cmd_rename.rb +3 -3
- data/lib/tb/cmd_shape.rb +3 -3
- data/lib/tb/cmd_sort.rb +3 -3
- data/lib/tb/cmd_svn.rb +3 -3
- data/lib/tb/cmd_tar.rb +3 -3
- data/lib/tb/cmd_to_csv.rb +4 -4
- data/lib/tb/cmd_to_json.rb +3 -3
- data/lib/tb/cmd_to_ltsv.rb +4 -4
- data/lib/tb/cmd_to_pnm.rb +3 -3
- data/lib/tb/cmd_to_pp.rb +3 -3
- data/lib/tb/cmd_to_tsv.rb +4 -4
- data/lib/tb/cmd_to_yaml.rb +3 -3
- data/lib/tb/cmd_unmelt.rb +3 -3
- data/lib/tb/cmd_unnest.rb +5 -4
- data/lib/tb/cmdmain.rb +3 -3
- data/lib/tb/cmdtop.rb +3 -3
- data/lib/tb/cmdutil.rb +3 -3
- data/lib/tb/csv.rb +10 -4
- data/lib/tb/customcmp.rb +3 -3
- data/lib/tb/customeq.rb +3 -3
- data/lib/tb/enumerable.rb +3 -3
- data/lib/tb/enumerator.rb +3 -3
- data/lib/tb/ex_enumerable.rb +2 -2
- data/lib/tb/ex_enumerator.rb +4 -4
- data/lib/tb/fieldset.rb +3 -3
- data/lib/tb/fileenumerator.rb +6 -6
- data/lib/tb/func.rb +3 -3
- data/lib/tb/json.rb +3 -3
- data/lib/tb/ltsv.rb +32 -7
- data/lib/tb/pnm.rb +3 -3
- data/lib/tb/reader.rb +3 -3
- data/lib/tb/record.rb +3 -3
- data/lib/tb/revcmp.rb +3 -3
- data/lib/tb/ropen.rb +23 -23
- data/lib/tb/search.rb +7 -7
- data/lib/tb/tsv.rb +3 -3
- data/lib/tb/zipper.rb +3 -3
- data/sample/excel2csv +36 -36
- data/sample/poi-xls2csv.rb +78 -78
- data/sample/poi-xls2csv.sh +3 -3
- data/sample/tbplot +214 -112
- data/test/test_basic.rb +4 -4
- data/test/test_cmd_newfield.rb +17 -3
- data/test/test_ex_enumerable.rb +18 -18
- data/test/test_ltsv.rb +8 -0
- metadata +5 -5
data/sample/poi-xls2csv.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
122
|
+
val = convert_single_cell(topleft_cell)
|
123
123
|
else
|
124
|
-
|
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
|
-
|
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
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
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
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
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
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
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
|
data/sample/poi-xls2csv.sh
CHANGED
@@ -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
|
data/sample/tbplot
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
#
|
3
|
-
# Copyright (C) 2011-
|
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 [
|
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+
|
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 =
|
116
|
+
@numeric_min = @numeric_max = v
|
77
117
|
else
|
78
|
-
@numeric_min =
|
79
|
-
@numeric_max =
|
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("
|
176
|
+
# AxisScale.new("log(fieldname)")
|
127
177
|
def initialize(desc)
|
128
178
|
@desc = desc
|
129
|
-
if /\
|
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
|
187
|
+
attr_reader :desc, :field
|
188
|
+
attr_accessor :logscale
|
138
189
|
end
|
139
190
|
|
140
|
-
|
141
|
-
|
142
|
-
$shape_field
|
143
|
-
$
|
144
|
-
$
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
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
|
-
|
174
|
-
r = Tb::CatReader.open(argv)
|
230
|
+
r = Tb.open_reader(table_filename).to_fileenumerator
|
175
231
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
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
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
$x_field
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
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 << " #{
|
396
|
+
title << " #{shape_value.to_s}"
|
310
397
|
end
|
311
398
|
if color_value
|
312
|
-
title << " #{
|
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
|
-
|
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
|
-
|
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)
|