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.
Files changed (84) hide show
  1. data/Changelog +25 -1
  2. data/lib/ctioga2/commands/commands.rb +13 -2
  3. data/lib/ctioga2/commands/doc/doc.rb +13 -17
  4. data/lib/ctioga2/commands/doc/documentation-commands.rb +14 -1
  5. data/lib/ctioga2/commands/doc/help.rb +136 -25
  6. data/lib/ctioga2/commands/doc/html.rb +56 -4
  7. data/lib/ctioga2/commands/doc/introspection.rb +45 -9
  8. data/lib/ctioga2/commands/doc/man.rb +7 -5
  9. data/lib/ctioga2/commands/doc/markup.rb +39 -12
  10. data/lib/ctioga2/commands/doc/wordwrap.rb +70 -0
  11. data/lib/ctioga2/commands/general-commands.rb +7 -4
  12. data/lib/ctioga2/commands/general-types.rb +27 -12
  13. data/lib/ctioga2/commands/interpreter.rb +2 -2
  14. data/lib/ctioga2/commands/parsers/command-line.rb +9 -5
  15. data/lib/ctioga2/commands/parsers/file.rb +5 -3
  16. data/lib/ctioga2/commands/type.rb +10 -3
  17. data/lib/ctioga2/commands/variables.rb +2 -2
  18. data/lib/ctioga2/data/backends/backend.rb +17 -15
  19. data/lib/ctioga2/data/backends/backends.rb +2 -2
  20. data/lib/ctioga2/data/backends/backends/gnuplot.rb +20 -5
  21. data/lib/ctioga2/data/backends/backends/math.rb +2 -2
  22. data/lib/ctioga2/data/backends/backends/text.rb +112 -17
  23. data/lib/ctioga2/data/backends/description.rb +10 -11
  24. data/lib/ctioga2/data/datacolumn.rb +73 -14
  25. data/lib/ctioga2/data/dataset.rb +305 -9
  26. data/lib/ctioga2/data/filters.rb +49 -1
  27. data/lib/ctioga2/data/indexed-dtable.rb +137 -0
  28. data/lib/ctioga2/data/point.rb +98 -7
  29. data/lib/ctioga2/data/stack.rb +98 -21
  30. data/lib/ctioga2/graphics/coordinates.rb +19 -2
  31. data/lib/ctioga2/graphics/elements.rb +12 -2
  32. data/lib/ctioga2/graphics/elements/containers.rb +14 -2
  33. data/lib/ctioga2/graphics/elements/contour.rb +67 -0
  34. data/lib/ctioga2/graphics/elements/curve2d.rb +103 -42
  35. data/lib/ctioga2/graphics/elements/element.rb +12 -2
  36. data/lib/ctioga2/graphics/elements/gradient-region.rb +94 -0
  37. data/lib/ctioga2/graphics/elements/parametric2d.rb +172 -0
  38. data/lib/ctioga2/graphics/elements/primitive.rb +37 -21
  39. data/lib/ctioga2/graphics/elements/region.rb +143 -0
  40. data/lib/ctioga2/graphics/elements/subplot.rb +92 -32
  41. data/lib/ctioga2/graphics/elements/tangent.rb +99 -0
  42. data/lib/ctioga2/graphics/elements/xyz-map.rb +126 -0
  43. data/lib/ctioga2/graphics/generator.rb +91 -6
  44. data/lib/ctioga2/graphics/legends.rb +26 -21
  45. data/lib/ctioga2/graphics/legends/area.rb +8 -8
  46. data/lib/ctioga2/graphics/legends/items.rb +5 -5
  47. data/lib/ctioga2/graphics/legends/storage.rb +4 -2
  48. data/lib/ctioga2/graphics/root.rb +24 -2
  49. data/lib/ctioga2/graphics/styles.rb +8 -0
  50. data/lib/ctioga2/graphics/styles/axes.rb +49 -23
  51. data/lib/ctioga2/graphics/styles/base.rb +2 -2
  52. data/lib/ctioga2/graphics/styles/carrays.rb +9 -2
  53. data/lib/ctioga2/graphics/styles/colormap.rb +272 -0
  54. data/lib/ctioga2/graphics/styles/curve.rb +64 -4
  55. data/lib/ctioga2/graphics/styles/drawable.rb +68 -9
  56. data/lib/ctioga2/graphics/styles/errorbar.rb +73 -0
  57. data/lib/ctioga2/graphics/styles/factory.rb +133 -17
  58. data/lib/ctioga2/graphics/styles/gradients.rb +60 -0
  59. data/lib/ctioga2/graphics/styles/location.rb +64 -0
  60. data/lib/ctioga2/graphics/styles/map-axes.rb +164 -0
  61. data/lib/ctioga2/graphics/styles/plot.rb +165 -62
  62. data/lib/ctioga2/graphics/styles/sets.rb +14 -1
  63. data/lib/ctioga2/graphics/styles/texts.rb +44 -34
  64. data/lib/ctioga2/graphics/subplot-commands.rb +94 -6
  65. data/lib/ctioga2/graphics/types.rb +113 -35
  66. data/lib/ctioga2/graphics/types/bijection.rb +3 -3
  67. data/lib/ctioga2/graphics/types/boundaries.rb +120 -1
  68. data/lib/ctioga2/graphics/types/dimensions.rb +8 -1
  69. data/lib/ctioga2/graphics/types/grid.rb +196 -0
  70. data/lib/ctioga2/graphics/types/location.rb +228 -0
  71. data/lib/ctioga2/graphics/types/point.rb +2 -2
  72. data/lib/ctioga2/log.rb +18 -18
  73. data/lib/ctioga2/metabuilder/type.rb +15 -3
  74. data/lib/ctioga2/metabuilder/types.rb +2 -2
  75. data/lib/ctioga2/metabuilder/types/coordinates.rb +13 -1
  76. data/lib/ctioga2/metabuilder/types/data.rb +50 -0
  77. data/lib/ctioga2/metabuilder/types/generic.rb +60 -0
  78. data/lib/ctioga2/metabuilder/types/lists.rb +53 -16
  79. data/lib/ctioga2/metabuilder/types/styles.rb +26 -45
  80. data/lib/ctioga2/plotmaker.rb +91 -20
  81. data/lib/ctioga2/postprocess.rb +8 -8
  82. data/lib/ctioga2/utils.rb +23 -4
  83. metadata +107 -75
  84. 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: 59 $', '$Date: 2009-05-28 23:15:50 +0200 (Thu, 28 May 2009) $')
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
- # TODO: add functions to prepare commands to set the various
76
+ # \todo add functions to prepare commands to set the various
77
77
  # parameters
78
78
  #
79
- # TODO: write the parameters stuff again...
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
- # TODO: finish this !!!
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 #{@long_name} backend.\n" +
159
- @description,
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: 81 $', '$Date: 2009-06-11 21:14:59 +0200 (Thu, 11 Jun 2009) $')
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
- # TODO: a way to concatenate two DataColumns
26
+ # \todo a way to concatenate two DataColumns
27
27
  #
28
- # TODO: a way to easily access the by "lines"
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
- # TODO: a method that resembles the code in the old text backend
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
- # TODO: a dup !
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, [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)
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 expand
101
- return [@values[i], @values[i], @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
 
@@ -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: 81 $', '$Date: 2009-06-11 21:14:59 +0200 (Thu, 11 Jun 2009) $')
20
+ Version::register_svn_info('$Revision: 233 $', '$Date: 2011-01-20 10:26:42 +0100 (Thu, 20 Jan 2011) $')
20
21
 
21
22
 
22
- # TODO: now, port the backend infrastructure...
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
- def each_values
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 internall calls #select!, by the way ;-)...
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
- # TODO: a dup !
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