ctioga2 0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. data/COPYING +339 -0
  2. data/Changelog +6 -0
  3. data/bin/ctioga2 +26 -0
  4. data/lib/ctioga2/commands/arguments.rb +58 -0
  5. data/lib/ctioga2/commands/commands.rb +258 -0
  6. data/lib/ctioga2/commands/doc/doc.rb +118 -0
  7. data/lib/ctioga2/commands/doc/documentation-commands.rb +119 -0
  8. data/lib/ctioga2/commands/doc/help.rb +95 -0
  9. data/lib/ctioga2/commands/doc/html.rb +230 -0
  10. data/lib/ctioga2/commands/doc/introspection.rb +211 -0
  11. data/lib/ctioga2/commands/doc/man.rb +279 -0
  12. data/lib/ctioga2/commands/doc/markup.rb +359 -0
  13. data/lib/ctioga2/commands/general-commands.rb +119 -0
  14. data/lib/ctioga2/commands/general-types.rb +118 -0
  15. data/lib/ctioga2/commands/groups.rb +73 -0
  16. data/lib/ctioga2/commands/interpreter.rb +257 -0
  17. data/lib/ctioga2/commands/parsers/command-line.rb +187 -0
  18. data/lib/ctioga2/commands/parsers/file.rb +186 -0
  19. data/lib/ctioga2/commands/strings.rb +303 -0
  20. data/lib/ctioga2/commands/type.rb +100 -0
  21. data/lib/ctioga2/commands/variables.rb +101 -0
  22. data/lib/ctioga2/data/backends/backend.rb +260 -0
  23. data/lib/ctioga2/data/backends/backends.rb +39 -0
  24. data/lib/ctioga2/data/backends/backends/gnuplot.rb +140 -0
  25. data/lib/ctioga2/data/backends/backends/math.rb +121 -0
  26. data/lib/ctioga2/data/backends/backends/text.rb +335 -0
  27. data/lib/ctioga2/data/backends/description.rb +405 -0
  28. data/lib/ctioga2/data/backends/factory.rb +73 -0
  29. data/lib/ctioga2/data/backends/parameter.rb +109 -0
  30. data/lib/ctioga2/data/datacolumn.rb +245 -0
  31. data/lib/ctioga2/data/dataset.rb +233 -0
  32. data/lib/ctioga2/data/filters.rb +131 -0
  33. data/lib/ctioga2/data/merge.rb +43 -0
  34. data/lib/ctioga2/data/point.rb +72 -0
  35. data/lib/ctioga2/data/stack.rb +294 -0
  36. data/lib/ctioga2/graphics/coordinates.rb +73 -0
  37. data/lib/ctioga2/graphics/elements.rb +111 -0
  38. data/lib/ctioga2/graphics/elements/containers.rb +111 -0
  39. data/lib/ctioga2/graphics/elements/curve2d.rb +155 -0
  40. data/lib/ctioga2/graphics/elements/element.rb +90 -0
  41. data/lib/ctioga2/graphics/elements/primitive.rb +256 -0
  42. data/lib/ctioga2/graphics/elements/subplot.rb +140 -0
  43. data/lib/ctioga2/graphics/generator.rb +68 -0
  44. data/lib/ctioga2/graphics/legends.rb +108 -0
  45. data/lib/ctioga2/graphics/legends/area.rb +199 -0
  46. data/lib/ctioga2/graphics/legends/items.rb +183 -0
  47. data/lib/ctioga2/graphics/legends/provider.rb +58 -0
  48. data/lib/ctioga2/graphics/legends/storage.rb +65 -0
  49. data/lib/ctioga2/graphics/root.rb +209 -0
  50. data/lib/ctioga2/graphics/styles.rb +30 -0
  51. data/lib/ctioga2/graphics/styles/axes.rb +247 -0
  52. data/lib/ctioga2/graphics/styles/background.rb +122 -0
  53. data/lib/ctioga2/graphics/styles/base.rb +115 -0
  54. data/lib/ctioga2/graphics/styles/carrays.rb +53 -0
  55. data/lib/ctioga2/graphics/styles/curve.rb +101 -0
  56. data/lib/ctioga2/graphics/styles/drawable.rb +87 -0
  57. data/lib/ctioga2/graphics/styles/factory.rb +351 -0
  58. data/lib/ctioga2/graphics/styles/legend.rb +63 -0
  59. data/lib/ctioga2/graphics/styles/plot.rb +410 -0
  60. data/lib/ctioga2/graphics/styles/sets.rb +64 -0
  61. data/lib/ctioga2/graphics/styles/texts.rb +277 -0
  62. data/lib/ctioga2/graphics/subplot-commands.rb +141 -0
  63. data/lib/ctioga2/graphics/types.rb +188 -0
  64. data/lib/ctioga2/graphics/types/bijection.rb +79 -0
  65. data/lib/ctioga2/graphics/types/boundaries.rb +170 -0
  66. data/lib/ctioga2/graphics/types/boxes.rb +157 -0
  67. data/lib/ctioga2/graphics/types/dimensions.rb +157 -0
  68. data/lib/ctioga2/graphics/types/point.rb +247 -0
  69. data/lib/ctioga2/log.rb +97 -0
  70. data/lib/ctioga2/metabuilder/type.rb +316 -0
  71. data/lib/ctioga2/metabuilder/types.rb +39 -0
  72. data/lib/ctioga2/metabuilder/types/coordinates.rb +124 -0
  73. data/lib/ctioga2/metabuilder/types/dates.rb +43 -0
  74. data/lib/ctioga2/metabuilder/types/lists.rb +188 -0
  75. data/lib/ctioga2/metabuilder/types/numbers.rb +97 -0
  76. data/lib/ctioga2/metabuilder/types/strings.rb +93 -0
  77. data/lib/ctioga2/metabuilder/types/styles.rb +178 -0
  78. data/lib/ctioga2/plotmaker.rb +677 -0
  79. data/lib/ctioga2/postprocess.rb +115 -0
  80. data/lib/ctioga2/utils.rb +120 -0
  81. data/setup.rb +1586 -0
  82. metadata +144 -0
@@ -0,0 +1,109 @@
1
+ # parameter.rb : A class to describe a parameter
2
+ # Copyright (C) 2006 Vincent Fourmond
3
+
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software
16
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ require 'ctioga2/utils'
19
+
20
+ require 'ctioga2/metabuilder/type'
21
+
22
+ module CTioga2
23
+
24
+ Version::register_svn_info('$Revision: 17 $', '$Date: 2009-04-28 22:22:22 +0200 (Tue, 28 Apr 2009) $')
25
+
26
+ module Data
27
+
28
+ module Backends
29
+
30
+ # A parameter describes a way of storing some information into an
31
+ # instance of an object. No type checking is done on the target object
32
+ # when the actual reading/writing is done. However, the type checking
33
+ # is done upstream by the Description system.
34
+ #
35
+ # A Parameter consists of several things:
36
+ #
37
+ # * a #name, to identify it in a unique fashion;
38
+ # * a #type, used to convert to and from String and for user
39
+ # interaction in general;
40
+ # * some explanative text, used to inform the user: #long_name and
41
+ # #description
42
+ # * two symbols that are used to gain read and write access of the
43
+ # parameter on the target object.
44
+ #
45
+ # The Parameter class can be used to maintain a set of
46
+ # meta-informations about types in a given object.
47
+ class Parameter
48
+
49
+ # The short name of the parameter
50
+ attr_accessor :name
51
+
52
+ # The long name of the parameter, to be translated
53
+ attr_accessor :long_name
54
+
55
+ # The function names that should be used to set the symbol and
56
+ # retrieve it's current value. The corresponding functions should
57
+ # read or return a string, and writer(reader) should be a noop.
58
+ attr_accessor :reader_symbol, :writer_symbol
59
+
60
+ # The (text) description of the parameter
61
+ attr_accessor :description
62
+
63
+ # The actual Commands::CommandType of the parameter
64
+ attr_accessor :type
65
+
66
+ # Creates a new Parameter with the given symbols. Remember that
67
+ # if you don't intend to use #get, #get_raw, #set and #set_raw,
68
+ # you don't need to pass meaningful values to _writer_symbol_ and
69
+ # _reader_symbol_.
70
+ def initialize(name, writer_symbol,
71
+ reader_symbol,
72
+ long_name, type,
73
+ description)
74
+ @name = name
75
+ @writer_symbol = writer_symbol
76
+ @reader_symbol = reader_symbol
77
+ @description = description
78
+ @long_name = long_name
79
+ @type = Commands::CommandType::get_type(type)
80
+ end
81
+
82
+
83
+ # Sets directly the target parameter, without type conversion
84
+ def set_value(target, val)
85
+ target.send(@writer_symbol, val)
86
+ end
87
+
88
+ # Uses the #writer_symbol of the _target_ to set the value of the
89
+ # parameter to the one converted from the String _str_
90
+ def set_from_string(target, str)
91
+ set_value(target, string_to_type(str))
92
+ end
93
+
94
+
95
+ # Aquires the value from the backend, and returns it in the
96
+ # form of a string
97
+ def get_string(target)
98
+ return type_to_string(get_value(target))
99
+ end
100
+
101
+ # Aquires the value from the backend, and returns it.
102
+ def get_value(target)
103
+ target.send(@reader_symbol)
104
+ end
105
+
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,245 @@
1
+ # datacolumn.rb: a class holding a 'column' of data
2
+ # copyright (c) 2009 by Vincent Fourmond
3
+
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details (in the COPYING file).
13
+
14
+ require 'Dobjects/Dvector'
15
+ require 'ctioga2/utils'
16
+
17
+ # This module contains all the classes used by ctioga
18
+ module CTioga2
19
+
20
+ Version::register_svn_info('$Revision: 81 $', '$Date: 2009-06-11 21:14:59 +0200 (Thu, 11 Jun 2009) $')
21
+
22
+ module Data
23
+
24
+ # This class holds one column, possibly with error bars.
25
+ #
26
+ # TODO: a way to concatenate two DataColumns
27
+ #
28
+ # TODO: a way to easily access the by "lines"
29
+ class DataColumn
30
+
31
+ # A Dvector holding ``real'' values
32
+ attr_accessor :values
33
+
34
+ # A Dvector holding minimal values
35
+ attr_accessor :min_values
36
+
37
+ # A Dvector holding maximal values
38
+ attr_accessor :max_values
39
+
40
+ # TODO: a method that resembles the code in the old text backend
41
+ # to set errors according to a speficication (relative,
42
+ # absolute, already max/min)
43
+
44
+ # TODO: a dup !
45
+
46
+ def initialize(values, min = nil, max = nil)
47
+ @values = values
48
+ @min_values = min
49
+ @max_values = max
50
+ end
51
+
52
+
53
+ # Yields all the vectors in turn to apply a given
54
+ # transformation.
55
+ def apply
56
+ for v in all_vectors
57
+ yield v if v
58
+ end
59
+ end
60
+
61
+ # Sorts the values according to the index vector given.
62
+ def reindex(idx_vector)
63
+ for v in all_vectors
64
+ # This is slow !
65
+ # Code should be written in C on the dvector side.
66
+ #
67
+ # Or we could use Function.sort, though this is not very
68
+ # elegant nor efficient. (but it would be memory-efficient,
69
+ # though).
70
+ next unless v
71
+ w = Dobjects::Dvector.new(idx_vector.size) do |i|
72
+ v[idx_vector[i]]
73
+ end
74
+ v.replace(w)
75
+ end
76
+ end
77
+
78
+ # Whether there are error bars.
79
+ def has_errors?
80
+ return (@min_values && @max_values)
81
+ end
82
+
83
+ # Column names. _base_ is used as a base for the names. If
84
+ # _expand_ is on, always return all the names.
85
+ def column_names(base, expand = false)
86
+ if expand || has_errors?
87
+ return [base, "#{base}min", "#{base}max"]
88
+ else
89
+ return [base]
90
+ end
91
+ end
92
+
93
+ # Values, [value, min, max], at the given index. If #min and
94
+ # #max are nil only [value] is returned -- unless _expand_ is
95
+ # set, in which case we make up a default value for min and max.
96
+ def values_at(i, expand = false)
97
+ if has_errors?
98
+ return [@values[i], @min_values[i], @max_values[i]]
99
+ else
100
+ if expand
101
+ return [@values[i], @values[i], @values[i]]
102
+ else
103
+ return [@values[i]]
104
+ end
105
+ end
106
+ end
107
+
108
+ # Returns the number of elements.
109
+ def size
110
+ return @values.size
111
+ end
112
+
113
+ # Creates dummy errors (ie, min_values = max_values = values) if
114
+ # the datacolumn does not currently have one.
115
+ def ensure_has_errors
116
+ if ! has_errors?
117
+ @min_values = @values.dup
118
+ @max_values = @values.dup
119
+ end
120
+ end
121
+
122
+ # Concatenates with another DataColumn, making sure the errors
123
+ # and such are not lost.
124
+ def <<(column)
125
+ # If there are error bars, wew make sure we concatenate all of them
126
+ if has_errors? || column.has_errors?
127
+ self.ensure_has_errors
128
+ column.ensure_has_errors
129
+ @min_values.concat(column.min_values)
130
+ @max_values.concat(column.max_values)
131
+ end
132
+ @values.concat(column.values)
133
+ end
134
+
135
+ # Only keeps every _n_ points in the DataColumn
136
+ def trim!(nb)
137
+ nb = nb.to_i
138
+ if nb < 2
139
+ return
140
+ end
141
+
142
+ new_vects = []
143
+ for v in all_vectors
144
+ if v
145
+ new_values = Dobjects::Dvector.new
146
+ i = 0
147
+ for val in v
148
+ if (i % nb) == 0
149
+ new_values << val
150
+ end
151
+ i+=1
152
+ end
153
+ new_vects << new_values
154
+ else
155
+ new_vects << nil
156
+ end
157
+ end
158
+ set_vectors(new_vects)
159
+ end
160
+
161
+ ColumnSpecsRE = /|min|max/i
162
+
163
+ # This function sets the value of the DataColumn object
164
+ # according to a hash: _spec_ => _vector_. _spec_ can be any of:
165
+ # * 'value', 'values' or '' : the #values
166
+ # * 'min' : #min
167
+ # * 'max' : #max
168
+ def from_hash(spec)
169
+ s = spec.dup
170
+ @values = spec['value'] || spec['values'] ||
171
+ spec['']
172
+ if ! @values
173
+ raise "Need a 'value' specification"
174
+ end
175
+ for k in ['value', 'values', '']
176
+ s.delete(k)
177
+ end
178
+ for key in s.keys
179
+ case key
180
+ when /^min$/i
181
+ @min_values = s[key]
182
+ when /^max$/i
183
+ @max_values = s[key]
184
+ else
185
+ raise "Unkown key: #{key}"
186
+ end
187
+ end
188
+ end
189
+
190
+
191
+ # Creates and returns a DataColumn object according to the
192
+ # _spec_. See #from_hash for more information.
193
+ def self.from_hash(spec)
194
+ a = DataColumn.new(nil)
195
+ a.from_hash(spec)
196
+ return a
197
+ end
198
+
199
+ # Returns the minimum value of all vectors held in this column
200
+ def min
201
+ m = @values.min
202
+ for v in [@min_values, @max_values]
203
+ if v
204
+ m1 = v.min
205
+ if m1 < m # This also works if m1 is NaN
206
+ m = m1
207
+ end
208
+ end
209
+ end
210
+ return m
211
+ end
212
+
213
+ # Returns the maximum value of all vectors held in this column
214
+ def max
215
+ m = @values.max
216
+ for v in [@min_values, @max_values]
217
+ if v
218
+ m1 = v.max
219
+ if m1 > m # This also works if m1 is NaN
220
+ m = m1
221
+ end
222
+ end
223
+ end
224
+ return m
225
+ end
226
+
227
+ protected
228
+
229
+ # All the vectors held by the DataColumn
230
+ def all_vectors
231
+ return [@values, @min_values, @max_values]
232
+ end
233
+
234
+ # Sets the vectors to the given list, as might have been
235
+ # returned by #all_vectors
236
+ def set_vectors(vectors)
237
+ @values, @min_values, @max_values = *vectors
238
+ end
239
+
240
+ end
241
+
242
+ end
243
+
244
+ end
245
+
@@ -0,0 +1,233 @@
1
+ # dataset.rb: a class holding *one* dataset
2
+ # copyright (c) 2009 by Vincent Fourmond
3
+
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details (in the COPYING file).
13
+
14
+ require 'ctioga2/utils'
15
+ require 'ctioga2/data/datacolumn'
16
+
17
+ module CTioga2
18
+
19
+ Version::register_svn_info('$Revision: 81 $', '$Date: 2009-06-11 21:14:59 +0200 (Thu, 11 Jun 2009) $')
20
+
21
+
22
+ # TODO: now, port the backend infrastructure...
23
+
24
+ # This module holds all the code that deals with manipulation and
25
+ # acquisition of data of any sort.
26
+ module Data
27
+
28
+ # This is the central class of the data manipulation in ctioga.
29
+ # It is a series of 'Y' DataColumn indexed on a unique 'X'
30
+ # DataColumn. This can be used to represent multiple XY data sets,
31
+ # but also XYZ and even more complex data. The actual
32
+ # signification of the various 'Y' columns are left to the user.
33
+ class Dataset
34
+
35
+ # The X DataColumn
36
+ attr_accessor :x
37
+
38
+ # All Y DataColumn (an Array of DataColumn)
39
+ attr_accessor :ys
40
+
41
+ # The name of the Dataset, such as one that could be used in a
42
+ # legend (like for the --auto-legend option of ctioga).
43
+ attr_accessor :name
44
+
45
+ # Creates a new Dataset object with the given data columns
46
+ # (Dvector or DataColumn). #x is the first one
47
+ def initialize(name, columns)
48
+ columns.each_index do |i|
49
+ if columns[i].is_a? Dobjects::Dvector
50
+ columns[i] = DataColumn.new(columns[i])
51
+ end
52
+ end
53
+ @x = columns[0]
54
+ @ys = columns[1..-1]
55
+ @name = name
56
+ end
57
+
58
+ # Creates a new Dataset from a specification. This function
59
+ # parses a specification in the form of:
60
+ # * a:b{:c}+
61
+ # * spec=a{:spec2=b}+
62
+ #
63
+ # It yields each of the unprocessed text, not necessarily in the
64
+ # order they were read, and expects a Dvector as a return value.
65
+ #
66
+ # It then builds a suitable Dataset object with these values,
67
+ # and returns it.
68
+ #
69
+ # It is *strongly* *recommended* to use this function for
70
+ # reimplementations of Backends::Backend#query_dataset.
71
+ def self.dataset_from_spec(name, spec)
72
+ specs = []
73
+ i = 0
74
+ for s in spec.split(/:/)
75
+ if s =~ /^(x|y\d*|z)(#{DataColumn::ColumnSpecsRE})=(.*)/i
76
+ which, mod, s = $1.downcase,($2 && $2.downcase) || "value",$3
77
+
78
+ case which
79
+ when /x/
80
+ idx = 0
81
+ when /y(\d+)?/
82
+ if $1
83
+ idx = $1.to_i
84
+ else
85
+ idx = 1
86
+ end
87
+ when /z/
88
+ idx = 2
89
+ end
90
+ specs[idx] ||= {}
91
+ specs[idx][mod] = yield s
92
+ else
93
+ specs[i] = {"value" => yield(s)}
94
+ end
95
+ i += 1
96
+ end
97
+ columns = []
98
+ for s in specs
99
+ columns << DataColumn.from_hash(s)
100
+ end
101
+ return Dataset.new(name, columns)
102
+ end
103
+
104
+ # The main Y column (ie, the first one)
105
+ def y
106
+ return @ys[0]
107
+ end
108
+
109
+ # The Z column, if applicable
110
+ def z
111
+ return @ys[1]
112
+ end
113
+
114
+ # Sorts all columns according to X values
115
+ def sort!
116
+ idx_vector = Dobjects::Dvector.new(@x.values.size) do |i|
117
+ i
118
+ end
119
+ f = Dobjects::Function.new(@x.values.dup, idx_vector)
120
+ f.sort
121
+ # Now, idx_vector contains the indices that make X values
122
+ # sorted.
123
+ for col in all_columns
124
+ col.reindex(idx_vector)
125
+ end
126
+ end
127
+
128
+ # Returns an array with Column names.
129
+ def column_names
130
+ retval = @x.column_names("x")
131
+ @ys.each_index do |i|
132
+ retval += @ys[i].column_names("y#{i+1}")
133
+ end
134
+ return retval
135
+ end
136
+
137
+ # Iterates over all the values of the Dataset
138
+ def each_values
139
+ @x.size.times do |i|
140
+ v = @x.values_at(i)
141
+ for y in @ys
142
+ v += y.values_at(i)
143
+ end
144
+ yield i, *v
145
+ end
146
+ end
147
+
148
+ # The overall number of columns
149
+ def size
150
+ return 1 + @ys.size
151
+ end
152
+
153
+ # Concatenates another Dataset to this one
154
+ def <<(dataset)
155
+ if dataset.size != self.size
156
+ raise "Can't concatenate datasets that don't have the same number of columns: #{self.size} vs #{dataset.size}"
157
+ end
158
+ @x << dataset.x
159
+ @ys.size.times do |i|
160
+ @ys[i] << dataset.ys[i]
161
+ end
162
+ end
163
+
164
+
165
+ # Trims all data columns. See DataColumn#trim!
166
+ def trim!(nb)
167
+ for col in all_columns
168
+ col.trim!(nb)
169
+ end
170
+ end
171
+
172
+
173
+ # Modifies the dataset to only keep the data for which the block
174
+ # returns true. The block should take the following arguments,
175
+ # in order:
176
+ #
177
+ # _x_, _xmin_, _xmax_, _y_, _ymin_, _ymax_, _y1_, _y1min_, _y1max_,
178
+ # _z_, _zmin_, _zmax_, _y2_, _y2min_, _y2max_, _y3_, _y3min_, _y3max_
179
+ #
180
+ def select!(&block)
181
+ target = []
182
+ @x.size.times do |i|
183
+ args = @x.values_at(i, true)
184
+ args.concat(@ys[0].values_at(i, true) * 2)
185
+ if @ys[1]
186
+ args.concat(@ys[1].values_at(i, true) * 2)
187
+ for yvect in @ys[2..-1]
188
+ args.concat(yvect.values_at(i, true))
189
+ end
190
+ end
191
+ if block.call(*args)
192
+ target << i
193
+ end
194
+ end
195
+ for col in all_columns
196
+ col.reindex(target)
197
+ end
198
+ end
199
+
200
+ # Same as #select!, but you give it a text formula instead of a
201
+ # block. It internall calls #select!, by the way ;-)...
202
+ def select_formula!(formula)
203
+ names = @x.column_names('x', true)
204
+ names.concat(@x.column_names('y', true))
205
+ names.concat(@x.column_names('y1', true))
206
+ if @ys[1]
207
+ names.concat(@x.column_names('z', true))
208
+ names.concat(@x.column_names('y2', true))
209
+ i = 3
210
+ for yvect in @ys[2..-1]
211
+ names.concat(@x.column_names("y#{i}", true))
212
+ i += 1
213
+ end
214
+ end
215
+ block = eval("proc do |#{names.join(',')}|\n#{formula}\nend")
216
+ select!(&block)
217
+ end
218
+
219
+ # TODO: a dup !
220
+
221
+ protected
222
+
223
+ # Returns all DataColumn objects held by this Dataset
224
+ def all_columns
225
+ return [@x, *@ys]
226
+ end
227
+
228
+ end
229
+
230
+ end
231
+
232
+ end
233
+