ctioga2 0.0 → 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Changelog +25 -1
- data/lib/ctioga2/commands/commands.rb +13 -2
- data/lib/ctioga2/commands/doc/doc.rb +13 -17
- data/lib/ctioga2/commands/doc/documentation-commands.rb +14 -1
- data/lib/ctioga2/commands/doc/help.rb +136 -25
- data/lib/ctioga2/commands/doc/html.rb +56 -4
- data/lib/ctioga2/commands/doc/introspection.rb +45 -9
- data/lib/ctioga2/commands/doc/man.rb +7 -5
- data/lib/ctioga2/commands/doc/markup.rb +39 -12
- data/lib/ctioga2/commands/doc/wordwrap.rb +70 -0
- data/lib/ctioga2/commands/general-commands.rb +7 -4
- data/lib/ctioga2/commands/general-types.rb +27 -12
- data/lib/ctioga2/commands/interpreter.rb +2 -2
- data/lib/ctioga2/commands/parsers/command-line.rb +9 -5
- data/lib/ctioga2/commands/parsers/file.rb +5 -3
- data/lib/ctioga2/commands/type.rb +10 -3
- data/lib/ctioga2/commands/variables.rb +2 -2
- data/lib/ctioga2/data/backends/backend.rb +17 -15
- data/lib/ctioga2/data/backends/backends.rb +2 -2
- data/lib/ctioga2/data/backends/backends/gnuplot.rb +20 -5
- data/lib/ctioga2/data/backends/backends/math.rb +2 -2
- data/lib/ctioga2/data/backends/backends/text.rb +112 -17
- data/lib/ctioga2/data/backends/description.rb +10 -11
- data/lib/ctioga2/data/datacolumn.rb +73 -14
- data/lib/ctioga2/data/dataset.rb +305 -9
- data/lib/ctioga2/data/filters.rb +49 -1
- data/lib/ctioga2/data/indexed-dtable.rb +137 -0
- data/lib/ctioga2/data/point.rb +98 -7
- data/lib/ctioga2/data/stack.rb +98 -21
- data/lib/ctioga2/graphics/coordinates.rb +19 -2
- data/lib/ctioga2/graphics/elements.rb +12 -2
- data/lib/ctioga2/graphics/elements/containers.rb +14 -2
- data/lib/ctioga2/graphics/elements/contour.rb +67 -0
- data/lib/ctioga2/graphics/elements/curve2d.rb +103 -42
- data/lib/ctioga2/graphics/elements/element.rb +12 -2
- data/lib/ctioga2/graphics/elements/gradient-region.rb +94 -0
- data/lib/ctioga2/graphics/elements/parametric2d.rb +172 -0
- data/lib/ctioga2/graphics/elements/primitive.rb +37 -21
- data/lib/ctioga2/graphics/elements/region.rb +143 -0
- data/lib/ctioga2/graphics/elements/subplot.rb +92 -32
- data/lib/ctioga2/graphics/elements/tangent.rb +99 -0
- data/lib/ctioga2/graphics/elements/xyz-map.rb +126 -0
- data/lib/ctioga2/graphics/generator.rb +91 -6
- data/lib/ctioga2/graphics/legends.rb +26 -21
- data/lib/ctioga2/graphics/legends/area.rb +8 -8
- data/lib/ctioga2/graphics/legends/items.rb +5 -5
- data/lib/ctioga2/graphics/legends/storage.rb +4 -2
- data/lib/ctioga2/graphics/root.rb +24 -2
- data/lib/ctioga2/graphics/styles.rb +8 -0
- data/lib/ctioga2/graphics/styles/axes.rb +49 -23
- data/lib/ctioga2/graphics/styles/base.rb +2 -2
- data/lib/ctioga2/graphics/styles/carrays.rb +9 -2
- data/lib/ctioga2/graphics/styles/colormap.rb +272 -0
- data/lib/ctioga2/graphics/styles/curve.rb +64 -4
- data/lib/ctioga2/graphics/styles/drawable.rb +68 -9
- data/lib/ctioga2/graphics/styles/errorbar.rb +73 -0
- data/lib/ctioga2/graphics/styles/factory.rb +133 -17
- data/lib/ctioga2/graphics/styles/gradients.rb +60 -0
- data/lib/ctioga2/graphics/styles/location.rb +64 -0
- data/lib/ctioga2/graphics/styles/map-axes.rb +164 -0
- data/lib/ctioga2/graphics/styles/plot.rb +165 -62
- data/lib/ctioga2/graphics/styles/sets.rb +14 -1
- data/lib/ctioga2/graphics/styles/texts.rb +44 -34
- data/lib/ctioga2/graphics/subplot-commands.rb +94 -6
- data/lib/ctioga2/graphics/types.rb +113 -35
- data/lib/ctioga2/graphics/types/bijection.rb +3 -3
- data/lib/ctioga2/graphics/types/boundaries.rb +120 -1
- data/lib/ctioga2/graphics/types/dimensions.rb +8 -1
- data/lib/ctioga2/graphics/types/grid.rb +196 -0
- data/lib/ctioga2/graphics/types/location.rb +228 -0
- data/lib/ctioga2/graphics/types/point.rb +2 -2
- data/lib/ctioga2/log.rb +18 -18
- data/lib/ctioga2/metabuilder/type.rb +15 -3
- data/lib/ctioga2/metabuilder/types.rb +2 -2
- data/lib/ctioga2/metabuilder/types/coordinates.rb +13 -1
- data/lib/ctioga2/metabuilder/types/data.rb +50 -0
- data/lib/ctioga2/metabuilder/types/generic.rb +60 -0
- data/lib/ctioga2/metabuilder/types/lists.rb +53 -16
- data/lib/ctioga2/metabuilder/types/styles.rb +26 -45
- data/lib/ctioga2/plotmaker.rb +91 -20
- data/lib/ctioga2/postprocess.rb +8 -8
- data/lib/ctioga2/utils.rb +23 -4
- metadata +107 -75
- data/lib/ctioga2/data/merge.rb +0 -43
@@ -22,7 +22,7 @@ require 'ctioga2/commands/groups'
|
|
22
22
|
|
23
23
|
module CTioga2
|
24
24
|
|
25
|
-
Version::register_svn_info('$Revision:
|
25
|
+
Version::register_svn_info('$Revision: 155 $', '$Date: 2010-06-21 21:41:32 +0200 (Mon, 21 Jun 2010) $')
|
26
26
|
|
27
27
|
|
28
28
|
module Data
|
@@ -73,10 +73,10 @@ module CTioga2
|
|
73
73
|
# create objects at run-time, the classes used by describe
|
74
74
|
# *should not need any parameter for #initialize*.
|
75
75
|
#
|
76
|
-
#
|
76
|
+
# \todo add functions to prepare commands to set the various
|
77
77
|
# parameters
|
78
78
|
#
|
79
|
-
#
|
79
|
+
# \todo write the parameters stuff again...
|
80
80
|
class BackendDescription
|
81
81
|
# The Class to instantiate.
|
82
82
|
attr_accessor :object_class
|
@@ -149,16 +149,16 @@ module CTioga2
|
|
149
149
|
# In addition, this function creates a group to store Backend
|
150
150
|
# commands.
|
151
151
|
#
|
152
|
-
#
|
152
|
+
# \todo finish this !!!
|
153
153
|
def create_backend_commands
|
154
154
|
group = CmdGroup.
|
155
155
|
new("backend-#{@name}",
|
156
156
|
"The '#{@name}' backend: #{@long_name}",
|
157
157
|
"The commands in this group drive the "+
|
158
|
-
"behaviour of the #{@
|
159
|
-
|
158
|
+
"behaviour of the {backend: #{@name}} backend;\n" +
|
159
|
+
"see its documentation for more information",
|
160
160
|
DefaultBackendGroupPriority)
|
161
|
-
|
161
|
+
|
162
162
|
backend_options = {}
|
163
163
|
|
164
164
|
# Again, each is needed for scoping problems.
|
@@ -175,9 +175,8 @@ module CTioga2
|
|
175
175
|
backend_options[param.name] = arg.dup
|
176
176
|
end
|
177
177
|
|
178
|
-
# TODO: add option parsing
|
179
178
|
Cmd.new("#{@name}", nil, "--#{@name}", [],
|
180
|
-
backend_options, "Selects the '#{@name}' backend",
|
179
|
+
backend_options, "Selects the '{backend: #{@name}}' backend",
|
181
180
|
nil, group) do |plotmaker, options|
|
182
181
|
plotmaker.data_stack.backend_factory.set_current_backend(@name)
|
183
182
|
for k,v in options
|
@@ -390,11 +389,11 @@ module CTioga2
|
|
390
389
|
if parents_params.key?(n)
|
391
390
|
description.add_param(parents_params[n])
|
392
391
|
else
|
393
|
-
warn "Param #{n} not found"
|
392
|
+
warn { "Param #{n} not found" }
|
394
393
|
end
|
395
394
|
end
|
396
395
|
else
|
397
|
-
warn "The parent class has no description"
|
396
|
+
warn { "The parent class has no description" }
|
398
397
|
end
|
399
398
|
end
|
400
399
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# datacolumn.rb: a class holding a 'column' of data
|
2
|
-
# copyright (c) 2009 by Vincent Fourmond
|
2
|
+
# copyright (c) 2009-2011 by Vincent Fourmond
|
3
3
|
|
4
4
|
# This program is free software; you can redistribute it and/or modify
|
5
5
|
# it under the terms of the GNU General Public License as published by
|
@@ -17,15 +17,15 @@ require 'ctioga2/utils'
|
|
17
17
|
# This module contains all the classes used by ctioga
|
18
18
|
module CTioga2
|
19
19
|
|
20
|
-
Version::register_svn_info('$Revision:
|
20
|
+
Version::register_svn_info('$Revision: 229 $', '$Date: 2011-01-17 17:34:57 +0100 (Mon, 17 Jan 2011) $')
|
21
21
|
|
22
22
|
module Data
|
23
23
|
|
24
24
|
# This class holds one column, possibly with error bars.
|
25
25
|
#
|
26
|
-
#
|
26
|
+
# \todo a way to concatenate two DataColumns
|
27
27
|
#
|
28
|
-
#
|
28
|
+
# \todo a way to easily access the by "lines"
|
29
29
|
class DataColumn
|
30
30
|
|
31
31
|
# A Dvector holding ``real'' values
|
@@ -37,11 +37,11 @@ module CTioga2
|
|
37
37
|
# A Dvector holding maximal values
|
38
38
|
attr_accessor :max_values
|
39
39
|
|
40
|
-
#
|
40
|
+
# \todo a method that resembles the code in the old text backend
|
41
41
|
# to set errors according to a speficication (relative,
|
42
42
|
# absolute, already max/min)
|
43
43
|
|
44
|
-
#
|
44
|
+
# \todo a dup !
|
45
45
|
|
46
46
|
def initialize(values, min = nil, max = nil)
|
47
47
|
@values = values
|
@@ -49,6 +49,19 @@ module CTioga2
|
|
49
49
|
@max_values = max
|
50
50
|
end
|
51
51
|
|
52
|
+
# Creates a DataColumn object
|
53
|
+
def self.create(number, with_errors = false)
|
54
|
+
a = Dobjects::Dvector.new(number, NaN::NaN)
|
55
|
+
if with_errors
|
56
|
+
b = Dobjects::Dvector.new(number, NaN::NaN)
|
57
|
+
c = Dobjects::Dvector.new(number, NaN::NaN)
|
58
|
+
else
|
59
|
+
b = nil
|
60
|
+
c = nil
|
61
|
+
end
|
62
|
+
return self.new(a, b, c)
|
63
|
+
end
|
64
|
+
|
52
65
|
|
53
66
|
# Yields all the vectors in turn to apply a given
|
54
67
|
# transformation.
|
@@ -90,26 +103,59 @@ module CTioga2
|
|
90
103
|
end
|
91
104
|
end
|
92
105
|
|
93
|
-
# Values
|
94
|
-
#
|
95
|
-
#
|
96
|
-
|
106
|
+
# Values at the given index.
|
107
|
+
#
|
108
|
+
# If _with_errors_ is false, only [value] is returned.
|
109
|
+
#
|
110
|
+
# If _with_errors_ is true, then, non-existent values are
|
111
|
+
# expanded to _nil_ if _expand_nil_ is true or to value if not.
|
112
|
+
def values_at(i, with_errors = false, expand_nil = true)
|
113
|
+
if ! with_errors
|
114
|
+
return [@values[i]]
|
115
|
+
end
|
97
116
|
if has_errors?
|
98
117
|
return [@values[i], @min_values[i], @max_values[i]]
|
99
118
|
else
|
100
|
-
if
|
101
|
-
return [@values[i],
|
119
|
+
if expand_nil
|
120
|
+
return [@values[i], nil, nil]
|
102
121
|
else
|
103
|
-
return [@values[i]]
|
122
|
+
return [@values[i], @values[i], @values[i]]
|
104
123
|
end
|
105
124
|
end
|
106
125
|
end
|
107
126
|
|
127
|
+
# Vectors: all values if there are error bars, or only the
|
128
|
+
# #value one if there isn't.
|
129
|
+
def vectors
|
130
|
+
if has_errors?
|
131
|
+
return [@values, @min_values, @max_values]
|
132
|
+
else
|
133
|
+
return [@values]
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
108
137
|
# Returns the number of elements.
|
109
138
|
def size
|
110
139
|
return @values.size
|
111
140
|
end
|
112
141
|
|
142
|
+
# Sets the values at the given index
|
143
|
+
def set_values_at(i, value, min = nil, max = nil)
|
144
|
+
@values[i] = value
|
145
|
+
if min && max
|
146
|
+
ensure_has_errors
|
147
|
+
@min_values[i] = min
|
148
|
+
@max_vaklues[i] = max
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Appends the given values at the end of the DataColumn
|
153
|
+
#
|
154
|
+
# @todo This isn't very efficient. Does it really matter ?
|
155
|
+
def push_values(value, min=nil, max=nil)
|
156
|
+
set_values_at(@values.size, value, min, max)
|
157
|
+
end
|
158
|
+
|
113
159
|
# Creates dummy errors (ie, min_values = max_values = values) if
|
114
160
|
# the datacolumn does not currently have one.
|
115
161
|
def ensure_has_errors
|
@@ -158,13 +204,15 @@ module CTioga2
|
|
158
204
|
set_vectors(new_vects)
|
159
205
|
end
|
160
206
|
|
161
|
-
ColumnSpecsRE = /|min|max/i
|
207
|
+
ColumnSpecsRE = /|min|max|err/i
|
162
208
|
|
163
209
|
# This function sets the value of the DataColumn object
|
164
210
|
# according to a hash: _spec_ => _vector_. _spec_ can be any of:
|
165
211
|
# * 'value', 'values' or '' : the #values
|
166
212
|
# * 'min' : #min
|
167
213
|
# * 'max' : #max
|
214
|
+
# * 'err' : absolute error: min is value - error, max is value +
|
215
|
+
# error
|
168
216
|
def from_hash(spec)
|
169
217
|
s = spec.dup
|
170
218
|
@values = spec['value'] || spec['values'] ||
|
@@ -181,6 +229,9 @@ module CTioga2
|
|
181
229
|
@min_values = s[key]
|
182
230
|
when /^max$/i
|
183
231
|
@max_values = s[key]
|
232
|
+
when /^err$/i
|
233
|
+
@min_values = @values - s[key]
|
234
|
+
@max_values = @values + s[key]
|
184
235
|
else
|
185
236
|
raise "Unkown key: #{key}"
|
186
237
|
end
|
@@ -223,6 +274,14 @@ module CTioga2
|
|
223
274
|
end
|
224
275
|
return m
|
225
276
|
end
|
277
|
+
|
278
|
+
def convolve!(kernel, middle = nil)
|
279
|
+
middle ||= kernel.size/2
|
280
|
+
# We smooth everything, stupidly?
|
281
|
+
for v in all_vectors
|
282
|
+
v.replace(v.convolve(kernel,middle)) if v
|
283
|
+
end
|
284
|
+
end
|
226
285
|
|
227
286
|
protected
|
228
287
|
|
data/lib/ctioga2/data/dataset.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# dataset.rb: a class holding *one* dataset
|
2
|
-
# copyright (c) 2009 by Vincent Fourmond
|
2
|
+
# copyright (c) 2009-2011 by Vincent Fourmond
|
3
3
|
|
4
4
|
# This program is free software; you can redistribute it and/or modify
|
5
5
|
# it under the terms of the GNU General Public License as published by
|
@@ -13,13 +13,14 @@
|
|
13
13
|
|
14
14
|
require 'ctioga2/utils'
|
15
15
|
require 'ctioga2/data/datacolumn'
|
16
|
+
require 'ctioga2/data/indexed-dtable'
|
16
17
|
|
17
18
|
module CTioga2
|
18
19
|
|
19
|
-
Version::register_svn_info('$Revision:
|
20
|
+
Version::register_svn_info('$Revision: 233 $', '$Date: 2011-01-20 10:26:42 +0100 (Thu, 20 Jan 2011) $')
|
20
21
|
|
21
22
|
|
22
|
-
#
|
23
|
+
# \todo now, port the backend infrastructure...
|
23
24
|
|
24
25
|
# This module holds all the code that deals with manipulation and
|
25
26
|
# acquisition of data of any sort.
|
@@ -53,6 +54,18 @@ module CTioga2
|
|
53
54
|
@x = columns[0]
|
54
55
|
@ys = columns[1..-1]
|
55
56
|
@name = name
|
57
|
+
|
58
|
+
# Cache for the indexed dtable
|
59
|
+
@indexed_dtable = nil
|
60
|
+
end
|
61
|
+
|
62
|
+
# Creates a
|
63
|
+
def self.create(name, number)
|
64
|
+
cols = []
|
65
|
+
number.times do
|
66
|
+
cols << Dobjects::Dvector.new()
|
67
|
+
end
|
68
|
+
return self.new(name, cols)
|
56
69
|
end
|
57
70
|
|
58
71
|
# Creates a new Dataset from a specification. This function
|
@@ -111,6 +124,11 @@ module CTioga2
|
|
111
124
|
return @ys[1]
|
112
125
|
end
|
113
126
|
|
127
|
+
# Returns true if X or Y columns have errors
|
128
|
+
def has_xy_errors?
|
129
|
+
return self.y.has_errors? || self.x.has_errors?
|
130
|
+
end
|
131
|
+
|
114
132
|
# Sorts all columns according to X values
|
115
133
|
def sort!
|
116
134
|
idx_vector = Dobjects::Dvector.new(@x.values.size) do |i|
|
@@ -134,12 +152,13 @@ module CTioga2
|
|
134
152
|
return retval
|
135
153
|
end
|
136
154
|
|
137
|
-
# Iterates over all the values of the Dataset
|
138
|
-
|
155
|
+
# Iterates over all the values of the Dataset. Values of
|
156
|
+
# optional arguments are those of DataColumn::values_at.
|
157
|
+
def each_values(with_errors = false, expand_nil = true)
|
139
158
|
@x.size.times do |i|
|
140
|
-
v = @x.values_at(i)
|
159
|
+
v = @x.values_at(i,with_errors, expand_nil)
|
141
160
|
for y in @ys
|
142
|
-
v += y.values_at(i)
|
161
|
+
v += y.values_at(i,with_errors, expand_nil)
|
143
162
|
end
|
144
163
|
yield i, *v
|
145
164
|
end
|
@@ -169,6 +188,25 @@ module CTioga2
|
|
169
188
|
end
|
170
189
|
end
|
171
190
|
|
191
|
+
# Appends the given values (as yielded by each_values(true)) to
|
192
|
+
# the stack. Elements of _values_ laying after the last
|
193
|
+
# DataColumn in the Dataset are simply ignored. Giving less than
|
194
|
+
# there should be will give interesting results.
|
195
|
+
def push_values(*values)
|
196
|
+
@x.push_values(*(values[0..2]))
|
197
|
+
@ys.size.times do |i|
|
198
|
+
@ys[i].push_values(*(values.slice(3*(i+1),3)))
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# Almost the same thing as #push_values, but when you don't care
|
203
|
+
# about the min/max things.
|
204
|
+
def push_only_values(values)
|
205
|
+
@x.push_values(values[0])
|
206
|
+
@ys.size.times do |i|
|
207
|
+
@ys[i].push_values(values[i+1])
|
208
|
+
end
|
209
|
+
end
|
172
210
|
|
173
211
|
# Modifies the dataset to only keep the data for which the block
|
174
212
|
# returns true. The block should take the following arguments,
|
@@ -198,7 +236,7 @@ module CTioga2
|
|
198
236
|
end
|
199
237
|
|
200
238
|
# Same as #select!, but you give it a text formula instead of a
|
201
|
-
# block. It
|
239
|
+
# block. It internally calls #select!, by the way ;-)...
|
202
240
|
def select_formula!(formula)
|
203
241
|
names = @x.column_names('x', true)
|
204
242
|
names.concat(@x.column_names('y', true))
|
@@ -216,7 +254,260 @@ module CTioga2
|
|
216
254
|
select!(&block)
|
217
255
|
end
|
218
256
|
|
219
|
-
#
|
257
|
+
# \todo a dup !
|
258
|
+
|
259
|
+
# Average all the non-X values of successive data points that
|
260
|
+
# have the same X values. It is a naive version that also
|
261
|
+
# averages the error columns.
|
262
|
+
def average_duplicates!
|
263
|
+
last_x = nil
|
264
|
+
last_x_first_idx = 0
|
265
|
+
xv = @x.values
|
266
|
+
i = 0
|
267
|
+
vectors = all_vectors
|
268
|
+
while i < xv.size
|
269
|
+
x = xv[i]
|
270
|
+
if ((last_x == x) && (i != (xv.size - 1)))
|
271
|
+
# Do nothing
|
272
|
+
else
|
273
|
+
if last_x_first_idx < (i - 1) ||
|
274
|
+
((last_x == x) && (i == (xv.size - 1)))
|
275
|
+
if i == (xv.size - 1)
|
276
|
+
e = i
|
277
|
+
else
|
278
|
+
e = i-1
|
279
|
+
end # The end of the slice.
|
280
|
+
|
281
|
+
## \todo In real, to do this properly, one would
|
282
|
+
# have to write a proper function in DataColumn that
|
283
|
+
# does averaging over certain indices possibly more
|
284
|
+
# cleverly than the current way to do.
|
285
|
+
for v in vectors
|
286
|
+
subv = v[last_x_first_idx..e]
|
287
|
+
ave = subv.sum/subv.size
|
288
|
+
v.slice!(last_x_first_idx+1, e - last_x_first_idx)
|
289
|
+
v[last_x_first_idx] = ave
|
290
|
+
end
|
291
|
+
i -= e - last_x_first_idx
|
292
|
+
end
|
293
|
+
last_x = x
|
294
|
+
last_x_first_idx = i
|
295
|
+
end
|
296
|
+
i += 1
|
297
|
+
end
|
298
|
+
|
299
|
+
end
|
300
|
+
|
301
|
+
|
302
|
+
# Returns an IndexedDTable representing the XYZ
|
303
|
+
# data. Information about errors are not included.
|
304
|
+
#
|
305
|
+
# @todo For performance, this will have to be turned into a real
|
306
|
+
# Dtable or Dvector class function. This function is just going
|
307
|
+
# to be *bad* ;-)
|
308
|
+
#
|
309
|
+
# @todo The cache should be invalidated when the contents of the
|
310
|
+
# Dataset changes (but that will be *real* hard !)
|
311
|
+
def indexed_table
|
312
|
+
if @indexed_dtable
|
313
|
+
return @indexed_dtable
|
314
|
+
end
|
315
|
+
# We convert the index into three x,y and z arrays
|
316
|
+
x = @x.values.dup
|
317
|
+
y = @ys[0].values.dup
|
318
|
+
z = @ys[1].values.dup
|
319
|
+
|
320
|
+
xvals = x.sort.uniq
|
321
|
+
yvals = y.sort.uniq
|
322
|
+
|
323
|
+
# Now building reverse hashes to speed up the conversion:
|
324
|
+
x_index = {}
|
325
|
+
i = 0
|
326
|
+
xvals.each do |v|
|
327
|
+
x_index[v] = i
|
328
|
+
i += 1
|
329
|
+
end
|
330
|
+
|
331
|
+
y_index = {}
|
332
|
+
i = 0
|
333
|
+
yvals.each do |v|
|
334
|
+
y_index[v] = i
|
335
|
+
i += 1
|
336
|
+
end
|
337
|
+
|
338
|
+
table = Dobjects::Dtable.new(xvals.size, yvals.size)
|
339
|
+
# We initialize all the values to NaN
|
340
|
+
table.set(0.0/0.0)
|
341
|
+
|
342
|
+
x.each_index do |i|
|
343
|
+
ix = x_index[x[i]]
|
344
|
+
iy = y_index[y[i]]
|
345
|
+
# Y first !
|
346
|
+
table[iy, ix] = z[i]
|
347
|
+
end
|
348
|
+
@indexed_dtable = IndexedDTable.new(xvals, yvals, table)
|
349
|
+
return @indexed_dtable
|
350
|
+
end
|
351
|
+
|
352
|
+
# Returns a x,y Function
|
353
|
+
def make_contour(level)
|
354
|
+
dtable = indexed_table
|
355
|
+
x,y,gaps = *dtable.make_contour(level)
|
356
|
+
n = 0.0/0.0
|
357
|
+
gaps.sort.reverse.each do |i|
|
358
|
+
x.insert(i-1,n)
|
359
|
+
y.insert(i-1,n)
|
360
|
+
end
|
361
|
+
return Dobjects::Function.new(x,y)
|
362
|
+
end
|
363
|
+
|
364
|
+
# Smooths the data using a naive gaussian-like convolution (but
|
365
|
+
# not exactly). Not for use for reliable data filtering.
|
366
|
+
def naive_smooth!(number)
|
367
|
+
kernel = Dobjects::Dvector.new(number) { |i|
|
368
|
+
Utils.cnk(number,i)
|
369
|
+
}
|
370
|
+
mid = number - number/2 - 1
|
371
|
+
for y in @ys
|
372
|
+
y.convolve!(kernel, mid)
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
# Returns a hash of Datasets indexed on the values of the
|
377
|
+
# columns _cols_. Datasets contain the same number of columns.
|
378
|
+
def index_on_cols(cols = [2])
|
379
|
+
# Transform column number into index in the each_values call
|
380
|
+
cols.map! do |i|
|
381
|
+
i*3
|
382
|
+
end
|
383
|
+
|
384
|
+
datasets = {}
|
385
|
+
self.each_values(true) do |i,*values|
|
386
|
+
signature = cols.map do |i|
|
387
|
+
values[i]
|
388
|
+
end
|
389
|
+
datasets[signature] ||= Dataset.create(name, self.size)
|
390
|
+
datasets[signature].push_values(*values)
|
391
|
+
end
|
392
|
+
return datasets
|
393
|
+
end
|
394
|
+
|
395
|
+
|
396
|
+
# Massive linear regressions over all X and Y values
|
397
|
+
# corresponding to a unique set of all the other Y2... Yn
|
398
|
+
# values.
|
399
|
+
#
|
400
|
+
# Returns the [coeffs, lines]
|
401
|
+
#
|
402
|
+
# @todo Have the possibility to elaborate on the regression side
|
403
|
+
# (in particular force b to 0)
|
404
|
+
def reglin(options = {})
|
405
|
+
cols = []
|
406
|
+
2.upto(self.size-1) do |i|
|
407
|
+
cols << i
|
408
|
+
end
|
409
|
+
datasets = index_on_cols(cols)
|
410
|
+
|
411
|
+
# Create two new datasets:
|
412
|
+
# * one that collects the keys and a,b
|
413
|
+
# * another that collects the keys and x1,y1, x2y2
|
414
|
+
coeffs = Dataset.create("coefficients", self.size)
|
415
|
+
lines = Dataset.create("lines", self.size)
|
416
|
+
|
417
|
+
for k,v in datasets
|
418
|
+
f = Dobjects::Function.new(v.x.values, v.y.values)
|
419
|
+
if options['linear'] # Fit to y = a*x
|
420
|
+
d = f.x.dup
|
421
|
+
d.mul!(f.x)
|
422
|
+
sxx = d.sum
|
423
|
+
d.replace(f.x)
|
424
|
+
d.mul!(f.y)
|
425
|
+
sxy = d.sum
|
426
|
+
a = sxy/sxx
|
427
|
+
coeffs.push_only_values(k + [a,0])
|
428
|
+
lines.push_only_values(k + [f.x.min, a * f.x.min])
|
429
|
+
lines.push_only_values(k + [f.x.max, a * f.x.max])
|
430
|
+
else
|
431
|
+
a,b = f.reglin
|
432
|
+
coeffs.push_only_values(k + [a, b])
|
433
|
+
lines.push_only_values(k + [f.x.min, b + a * f.x.min])
|
434
|
+
lines.push_only_values(k + [f.x.max, b + a * f.x.max])
|
435
|
+
end
|
436
|
+
|
437
|
+
end
|
438
|
+
|
439
|
+
return [coeffs, lines]
|
440
|
+
end
|
441
|
+
|
442
|
+
# Merges one or more other data sets into this one; one or more
|
443
|
+
# columns are designated as "master" columns and their values
|
444
|
+
# must match in all datasets. Extra columns are simply appended,
|
445
|
+
# in the order in which the datasets are given
|
446
|
+
#
|
447
|
+
# Comparisons between the values are made in abritrary precision
|
448
|
+
# unless precision is given, in which case values only have to
|
449
|
+
# match to this given number of digits.
|
450
|
+
#
|
451
|
+
# @todo update column names.
|
452
|
+
#
|
453
|
+
# @todo write provisions for column names, actually ;-)...
|
454
|
+
def merge_datasets_in(datasets, columns = [0], precision = nil)
|
455
|
+
# First thing, the data precision block:
|
456
|
+
|
457
|
+
prec = if precision then
|
458
|
+
proc do |x|
|
459
|
+
("%.#{@precision}g" % x) # This does not need to be a Float
|
460
|
+
end
|
461
|
+
else
|
462
|
+
proc {|x| x} # For exact comparisons
|
463
|
+
end
|
464
|
+
|
465
|
+
# First, we build an index of the master columns of the first
|
466
|
+
# dataset.
|
467
|
+
|
468
|
+
hash = {}
|
469
|
+
self.each_values(false) do |i, *cols|
|
470
|
+
signature = columns.map {|j|
|
471
|
+
prec.call(cols[j])
|
472
|
+
}
|
473
|
+
hash[signature] = i
|
474
|
+
end
|
475
|
+
|
476
|
+
remove_indices = columns.sort.reverse
|
477
|
+
|
478
|
+
for set in datasets
|
479
|
+
old_columns = set.all_columns
|
480
|
+
for i in remove_indices
|
481
|
+
old_columns.slice!(i)
|
482
|
+
end
|
483
|
+
|
484
|
+
# Now, we got rid of the master columns, we add the given
|
485
|
+
# number of columns
|
486
|
+
|
487
|
+
new_columns = []
|
488
|
+
old_columns.each do |c|
|
489
|
+
new_columns << DataColumn.create(@x.size, c.has_errors?)
|
490
|
+
end
|
491
|
+
|
492
|
+
set.each_values(false) do |i, *cols|
|
493
|
+
signature = columns.map {|j|
|
494
|
+
prec.call(cols[j])
|
495
|
+
}
|
496
|
+
idx = hash[signature]
|
497
|
+
if idx
|
498
|
+
old_columns.each_index { |j|
|
499
|
+
new_columns[j].
|
500
|
+
set_values_at(idx,
|
501
|
+
* old_columns[j].values_at(i, true, true))
|
502
|
+
}
|
503
|
+
else
|
504
|
+
# Data points are lost
|
505
|
+
end
|
506
|
+
end
|
507
|
+
@ys.concat(new_columns)
|
508
|
+
end
|
509
|
+
|
510
|
+
end
|
220
511
|
|
221
512
|
protected
|
222
513
|
|
@@ -224,6 +515,11 @@ module CTioga2
|
|
224
515
|
def all_columns
|
225
516
|
return [@x, *@ys]
|
226
517
|
end
|
518
|
+
|
519
|
+
# Returns all Dvectors of the columns one by one.
|
520
|
+
def all_vectors
|
521
|
+
return all_columns.map {|x| x.vectors}.flatten(1)
|
522
|
+
end
|
227
523
|
|
228
524
|
end
|
229
525
|
|