ctioga2 0.0 → 0.1
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.
- 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
|
|