1
# datacolumn.rb: a class holding a 'column' of data
2
# copyright (c) 2009-2011 by Vincent Fourmond
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.
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).
14
require 'Dobjects/Dvector'
15
require 'ctioga2/utils'
17
# This module contains all the classes used by ctioga
20
Version::register_svn_info('$Revision: 229 $', '$Date: 2011-01-17 17:34:57 +0100 (Mon, 17 Jan 2011) $')
24
# This class holds one column, possibly with error bars.
26
# \todo a way to concatenate two DataColumns
28
# \todo a way to easily access the by "lines"
31
# A Dvector holding ``real'' values
34
# A Dvector holding minimal values
35
attr_accessor :min_values
37
# A Dvector holding maximal values
38
attr_accessor :max_values
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)
46
def initialize(values, min = nil, max = nil)
52
# Creates a DataColumn object
53
def self.create(number, with_errors = false)
54
a = Dobjects::Dvector.new(number, NaN::NaN)
56
b = Dobjects::Dvector.new(number, NaN::NaN)
57
c = Dobjects::Dvector.new(number, NaN::NaN)
62
return self.new(a, b, c)
66
# Yields all the vectors in turn to apply a given
74
# Sorts the values according to the index vector given.
75
def reindex(idx_vector)
78
# Code should be written in C on the dvector side.
80
# Or we could use Function.sort, though this is not very
81
# elegant nor efficient. (but it would be memory-efficient,
84
w = Dobjects::Dvector.new(idx_vector.size) do |i|
91
# Whether there are error bars.
93
return (@min_values && @max_values)
96
# Column names. _base_ is used as a base for the names. If
97
# _expand_ is on, always return all the names.
98
def column_names(base, expand = false)
99
if expand || has_errors?
100
return [base, "#{base}min", "#{base}max"]
106
# Values at the given index.
108
# If _with_errors_ is false, only [value] is returned.
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)
117
return [@values[i], @min_values[i], @max_values[i]]
120
return [@values[i], nil, nil]
122
return [@values[i], @values[i], @values[i]]
127
# Vectors: all values if there are error bars, or only the
128
# #value one if there isn't.
131
return [@values, @min_values, @max_values]
137
# Returns the number of elements.
142
# Sets the values at the given index
143
def set_values_at(i, value, min = nil, max = nil)
148
@max_vaklues[i] = max
152
# Appends the given values at the end of the DataColumn
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)
159
# Creates dummy errors (ie, min_values = max_values = values) if
160
# the datacolumn does not currently have one.
161
def ensure_has_errors
163
@min_values = @values.dup
164
@max_values = @values.dup
168
# Concatenates with another DataColumn, making sure the errors
169
# and such are not lost.
171
# If there are error bars, wew make sure we concatenate all of them
172
if has_errors? || column.has_errors?
173
self.ensure_has_errors
174
column.ensure_has_errors
175
@min_values.concat(column.min_values)
176
@max_values.concat(column.max_values)
178
@values.concat(column.values)
181
# Only keeps every _n_ points in the DataColumn
191
new_values = Dobjects::Dvector.new
199
new_vects << new_values
204
set_vectors(new_vects)
207
ColumnSpecsRE = /|min|max|err/i
209
# This function sets the value of the DataColumn object
210
# according to a hash: _spec_ => _vector_. _spec_ can be any of:
211
# * 'value', 'values' or '' : the #values
214
# * 'err' : absolute error: min is value - error, max is value +
218
@values = spec['value'] || spec['values'] ||
221
raise "Need a 'value' specification"
223
for k in ['value', 'values', '']
233
@min_values = @values - s[key]
234
@max_values = @values + s[key]
236
raise "Unkown key: #{key}"
242
# Creates and returns a DataColumn object according to the
243
# _spec_. See #from_hash for more information.
244
def self.from_hash(spec)
245
a = DataColumn.new(nil)
250
# Returns the minimum value of all vectors held in this column
253
for v in [@min_values, @max_values]
256
if m1 < m # This also works if m1 is NaN
264
# Returns the maximum value of all vectors held in this column
267
for v in [@min_values, @max_values]
270
if m1 > m # This also works if m1 is NaN
278
def convolve!(kernel, middle = nil)
279
middle ||= kernel.size/2
280
# We smooth everything, stupidly?
282
v.replace(v.convolve(kernel,middle)) if v
288
# All the vectors held by the DataColumn
290
return [@values, @min_values, @max_values]
293
# Sets the vectors to the given list, as might have been
294
# returned by #all_vectors
295
def set_vectors(vectors)
296
@values, @min_values, @max_values = *vectors