ctioga2 0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +339 -0
- data/Changelog +6 -0
- data/bin/ctioga2 +26 -0
- data/lib/ctioga2/commands/arguments.rb +58 -0
- data/lib/ctioga2/commands/commands.rb +258 -0
- data/lib/ctioga2/commands/doc/doc.rb +118 -0
- data/lib/ctioga2/commands/doc/documentation-commands.rb +119 -0
- data/lib/ctioga2/commands/doc/help.rb +95 -0
- data/lib/ctioga2/commands/doc/html.rb +230 -0
- data/lib/ctioga2/commands/doc/introspection.rb +211 -0
- data/lib/ctioga2/commands/doc/man.rb +279 -0
- data/lib/ctioga2/commands/doc/markup.rb +359 -0
- data/lib/ctioga2/commands/general-commands.rb +119 -0
- data/lib/ctioga2/commands/general-types.rb +118 -0
- data/lib/ctioga2/commands/groups.rb +73 -0
- data/lib/ctioga2/commands/interpreter.rb +257 -0
- data/lib/ctioga2/commands/parsers/command-line.rb +187 -0
- data/lib/ctioga2/commands/parsers/file.rb +186 -0
- data/lib/ctioga2/commands/strings.rb +303 -0
- data/lib/ctioga2/commands/type.rb +100 -0
- data/lib/ctioga2/commands/variables.rb +101 -0
- data/lib/ctioga2/data/backends/backend.rb +260 -0
- data/lib/ctioga2/data/backends/backends.rb +39 -0
- data/lib/ctioga2/data/backends/backends/gnuplot.rb +140 -0
- data/lib/ctioga2/data/backends/backends/math.rb +121 -0
- data/lib/ctioga2/data/backends/backends/text.rb +335 -0
- data/lib/ctioga2/data/backends/description.rb +405 -0
- data/lib/ctioga2/data/backends/factory.rb +73 -0
- data/lib/ctioga2/data/backends/parameter.rb +109 -0
- data/lib/ctioga2/data/datacolumn.rb +245 -0
- data/lib/ctioga2/data/dataset.rb +233 -0
- data/lib/ctioga2/data/filters.rb +131 -0
- data/lib/ctioga2/data/merge.rb +43 -0
- data/lib/ctioga2/data/point.rb +72 -0
- data/lib/ctioga2/data/stack.rb +294 -0
- data/lib/ctioga2/graphics/coordinates.rb +73 -0
- data/lib/ctioga2/graphics/elements.rb +111 -0
- data/lib/ctioga2/graphics/elements/containers.rb +111 -0
- data/lib/ctioga2/graphics/elements/curve2d.rb +155 -0
- data/lib/ctioga2/graphics/elements/element.rb +90 -0
- data/lib/ctioga2/graphics/elements/primitive.rb +256 -0
- data/lib/ctioga2/graphics/elements/subplot.rb +140 -0
- data/lib/ctioga2/graphics/generator.rb +68 -0
- data/lib/ctioga2/graphics/legends.rb +108 -0
- data/lib/ctioga2/graphics/legends/area.rb +199 -0
- data/lib/ctioga2/graphics/legends/items.rb +183 -0
- data/lib/ctioga2/graphics/legends/provider.rb +58 -0
- data/lib/ctioga2/graphics/legends/storage.rb +65 -0
- data/lib/ctioga2/graphics/root.rb +209 -0
- data/lib/ctioga2/graphics/styles.rb +30 -0
- data/lib/ctioga2/graphics/styles/axes.rb +247 -0
- data/lib/ctioga2/graphics/styles/background.rb +122 -0
- data/lib/ctioga2/graphics/styles/base.rb +115 -0
- data/lib/ctioga2/graphics/styles/carrays.rb +53 -0
- data/lib/ctioga2/graphics/styles/curve.rb +101 -0
- data/lib/ctioga2/graphics/styles/drawable.rb +87 -0
- data/lib/ctioga2/graphics/styles/factory.rb +351 -0
- data/lib/ctioga2/graphics/styles/legend.rb +63 -0
- data/lib/ctioga2/graphics/styles/plot.rb +410 -0
- data/lib/ctioga2/graphics/styles/sets.rb +64 -0
- data/lib/ctioga2/graphics/styles/texts.rb +277 -0
- data/lib/ctioga2/graphics/subplot-commands.rb +141 -0
- data/lib/ctioga2/graphics/types.rb +188 -0
- data/lib/ctioga2/graphics/types/bijection.rb +79 -0
- data/lib/ctioga2/graphics/types/boundaries.rb +170 -0
- data/lib/ctioga2/graphics/types/boxes.rb +157 -0
- data/lib/ctioga2/graphics/types/dimensions.rb +157 -0
- data/lib/ctioga2/graphics/types/point.rb +247 -0
- data/lib/ctioga2/log.rb +97 -0
- data/lib/ctioga2/metabuilder/type.rb +316 -0
- data/lib/ctioga2/metabuilder/types.rb +39 -0
- data/lib/ctioga2/metabuilder/types/coordinates.rb +124 -0
- data/lib/ctioga2/metabuilder/types/dates.rb +43 -0
- data/lib/ctioga2/metabuilder/types/lists.rb +188 -0
- data/lib/ctioga2/metabuilder/types/numbers.rb +97 -0
- data/lib/ctioga2/metabuilder/types/strings.rb +93 -0
- data/lib/ctioga2/metabuilder/types/styles.rb +178 -0
- data/lib/ctioga2/plotmaker.rb +677 -0
- data/lib/ctioga2/postprocess.rb +115 -0
- data/lib/ctioga2/utils.rb +120 -0
- data/setup.rb +1586 -0
- 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
|
+
|