ctioga 1.11.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 (103) hide show
  1. data/COPYING +340 -0
  2. data/ctioga/bin/ctable +28 -0
  3. data/ctioga/bin/ctioga +37 -0
  4. data/ctioga/doc/ctable.1 +156 -0
  5. data/ctioga/doc/ctioga.1 +2363 -0
  6. data/ctioga/examples/README +46 -0
  7. data/ctioga/examples/ctioga.gnuplot +4 -0
  8. data/ctioga/examples/ctioga_within_tioga.rb +53 -0
  9. data/ctioga/examples/ctiogarc.rb +24 -0
  10. data/ctioga/examples/include_1.rb +15 -0
  11. data/ctioga/examples/noise.dat +100 -0
  12. data/ctioga/examples/noise.rb +13 -0
  13. data/ctioga/examples/trig.csv +100 -0
  14. data/ctioga/examples/trig.dat +100 -0
  15. data/ctioga/examples/trig.rb +14 -0
  16. data/ctioga/examples/trigh.dat +100 -0
  17. data/ctioga/examples/trigh.rb +10 -0
  18. data/ctioga/examples/tutorial +763 -0
  19. data/ctioga/examples/tutorial.sh +269 -0
  20. data/ctioga/tests/README +14 -0
  21. data/ctioga/tests/axes.sh +40 -0
  22. data/ctioga/tests/basic.sh +11 -0
  23. data/ctioga/tests/draw.sh +24 -0
  24. data/ctioga/tests/histograms.sh +14 -0
  25. data/ctioga/tests/insets.sh +41 -0
  26. data/ctioga/tests/layouts.sh +29 -0
  27. data/ctioga/tests/legends.sh +113 -0
  28. data/ctioga/tests/styles.sh +43 -0
  29. data/ctioga/tests/test_style.sh +8 -0
  30. data/ctioga/tests/tests.sh +24 -0
  31. data/ctioga/tests/text_backend.sh +83 -0
  32. data/ctioga/tests/tioga_defaults.rb +18 -0
  33. data/lib/CTioga/axes.rb +904 -0
  34. data/lib/CTioga/backends.rb +88 -0
  35. data/lib/CTioga/boundaries.rb +224 -0
  36. data/lib/CTioga/ctable.rb +134 -0
  37. data/lib/CTioga/curve_style.rb +246 -0
  38. data/lib/CTioga/debug.rb +199 -0
  39. data/lib/CTioga/dimension.rb +133 -0
  40. data/lib/CTioga/elements.rb +17 -0
  41. data/lib/CTioga/elements/base.rb +84 -0
  42. data/lib/CTioga/elements/containers.rb +578 -0
  43. data/lib/CTioga/elements/curves.rb +368 -0
  44. data/lib/CTioga/elements/tioga_primitives.rb +440 -0
  45. data/lib/CTioga/layout.rb +595 -0
  46. data/lib/CTioga/legends.rb +29 -0
  47. data/lib/CTioga/legends/cmdline.rb +187 -0
  48. data/lib/CTioga/legends/item.rb +164 -0
  49. data/lib/CTioga/legends/style.rb +257 -0
  50. data/lib/CTioga/log.rb +73 -0
  51. data/lib/CTioga/movingarrays.rb +131 -0
  52. data/lib/CTioga/partition.rb +271 -0
  53. data/lib/CTioga/plot_style.rb +230 -0
  54. data/lib/CTioga/plotmaker.rb +1677 -0
  55. data/lib/CTioga/shortcuts.rb +69 -0
  56. data/lib/CTioga/structures.rb +82 -0
  57. data/lib/CTioga/styles.rb +140 -0
  58. data/lib/CTioga/themes.rb +581 -0
  59. data/lib/CTioga/themes/classical.rb +82 -0
  60. data/lib/CTioga/themes/demo.rb +63 -0
  61. data/lib/CTioga/themes/fits.rb +91 -0
  62. data/lib/CTioga/themes/mono.rb +33 -0
  63. data/lib/CTioga/tioga.rb +32 -0
  64. data/lib/CTioga/utils.rb +173 -0
  65. data/lib/MetaBuilder/Parameters/dates.rb +38 -0
  66. data/lib/MetaBuilder/Parameters/lists.rb +132 -0
  67. data/lib/MetaBuilder/Parameters/numbers.rb +69 -0
  68. data/lib/MetaBuilder/Parameters/strings.rb +86 -0
  69. data/lib/MetaBuilder/Parameters/styles.rb +75 -0
  70. data/lib/MetaBuilder/Qt4/Parameters/dates.rb +51 -0
  71. data/lib/MetaBuilder/Qt4/Parameters/numbers.rb +65 -0
  72. data/lib/MetaBuilder/Qt4/Parameters/strings.rb +106 -0
  73. data/lib/MetaBuilder/Qt4/parameter.rb +172 -0
  74. data/lib/MetaBuilder/Qt4/parameters.rb +9 -0
  75. data/lib/MetaBuilder/descriptions.rb +603 -0
  76. data/lib/MetaBuilder/factory.rb +101 -0
  77. data/lib/MetaBuilder/group.rb +57 -0
  78. data/lib/MetaBuilder/metabuilder.rb +10 -0
  79. data/lib/MetaBuilder/parameter.rb +374 -0
  80. data/lib/MetaBuilder/parameters.rb +11 -0
  81. data/lib/MetaBuilder/qt4.rb +8 -0
  82. data/lib/SciYAG/Backends/backend.rb +379 -0
  83. data/lib/SciYAG/Backends/binner.rb +168 -0
  84. data/lib/SciYAG/Backends/cache.rb +102 -0
  85. data/lib/SciYAG/Backends/dataset.rb +158 -0
  86. data/lib/SciYAG/Backends/descriptions.rb +469 -0
  87. data/lib/SciYAG/Backends/filters.rb +25 -0
  88. data/lib/SciYAG/Backends/filters/average.rb +134 -0
  89. data/lib/SciYAG/Backends/filters/cumulate.rb +37 -0
  90. data/lib/SciYAG/Backends/filters/filter.rb +70 -0
  91. data/lib/SciYAG/Backends/filters/norm.rb +39 -0
  92. data/lib/SciYAG/Backends/filters/smooth.rb +63 -0
  93. data/lib/SciYAG/Backends/filters/sort.rb +43 -0
  94. data/lib/SciYAG/Backends/filters/strip.rb +34 -0
  95. data/lib/SciYAG/Backends/filters/trim.rb +64 -0
  96. data/lib/SciYAG/Backends/gnuplot.rb +131 -0
  97. data/lib/SciYAG/Backends/math.rb +108 -0
  98. data/lib/SciYAG/Backends/mdb.rb +462 -0
  99. data/lib/SciYAG/Backends/multitext.rb +96 -0
  100. data/lib/SciYAG/Backends/source.rb +64 -0
  101. data/lib/SciYAG/Backends/text.rb +339 -0
  102. data/lib/SciYAG/backends.rb +16 -0
  103. metadata +191 -0
@@ -0,0 +1,11 @@
1
+ # parameters.rb: A file grouping all the require necessary to have a
2
+ # working parameter system.
3
+ # This file is copyright 2006 by Vincent Fourmond, but you can do whatever
4
+ # you want with it.
5
+
6
+ require 'MetaBuilder/parameter'
7
+ require 'MetaBuilder/Parameters/numbers'
8
+ require 'MetaBuilder/Parameters/strings'
9
+ require 'MetaBuilder/Parameters/lists'
10
+ require 'MetaBuilder/Parameters/styles'
11
+ require 'MetaBuilder/Parameters/dates'
@@ -0,0 +1,8 @@
1
+ # qt4.rb: Use this file to include Qt support for parameters in an
2
+ # application.
3
+
4
+ # This file is copyright 2006 by Vincent Fourmond, but you can do whatever
5
+ # you want with it.
6
+
7
+ require 'MetaBuilder/Qt4/parameters'
8
+
@@ -0,0 +1,379 @@
1
+ # backend.rb : The base of the arcitecture of the Backends
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
+ # Filters and descriptions
19
+ require 'MetaBuilder/metabuilder'
20
+ require 'SciYAG/Backends/descriptions'
21
+ require 'SciYAG/Backends/filters'
22
+ require 'SciYAG/Backends/dataset'
23
+ require 'SciYAG/Backends/cache'
24
+
25
+ # Document-class: SciYAG
26
+ # The SciYAG module contains all the classes related to Backend and Filter.
27
+ # It will also contain additionnal features in a not-so-distant future.
28
+ module SciYAG
29
+
30
+ module Backends
31
+
32
+ # A simple class to describe a backend. See the
33
+ # Descriptions::Description
34
+ class BackendDescription < MetaBuilder::Description
35
+ # The backend's banner.
36
+ def banner(instance)
37
+ "Backend '#{instance.long_name}'"
38
+ end
39
+
40
+ # Creates a new backend and optionnally registers it
41
+ def initialize(cls, name, long_name, desc, register = true)
42
+ super(cls, name, long_name, desc)
43
+ if register
44
+ Backend.register_class(self)
45
+ end
46
+ end
47
+ end
48
+
49
+
50
+ # This class provides the infrastructure for accessing data sets. It
51
+ # shouldn't be used directly, but rather subclassed and reimplemented.
52
+ # The aim of this class is to provide any software which is interested
53
+ # to retrive data from some source with a consistent way to do so,
54
+ # independent the kind of source accessed.
55
+ #
56
+ # Subclasses should:
57
+ # * provide a consistent method for creating themselves,
58
+ # with as much information as necessary, including options and default
59
+ # parameters. Actually, their initialize function should take no value
60
+ # bu on the other side, the BackendDescription associated with it
61
+ # should make it easy to set all the parameters necessary to
62
+ # get one set of data.
63
+ # * provide a way to fill an OptionParser with their own parameters
64
+ # * provide a way to retrieve the data via named 'sets' (either 2D or 3D
65
+ # data, depending on the subclass)
66
+ # * provide a way to obtain all meta-informations on one dataset,
67
+ # such as the date, the meaning of the columns (if any), and so on.
68
+ # * provide a way to know which named sets are available, or at least
69
+ # a subset (or nothing if we don't know a thing).
70
+ # * wether the actual reading of the data is done at initialization time
71
+ # or at query time is left to the implementor ;-) !
72
+
73
+ class Backend
74
+
75
+ # Import the main description functions into the appropriate
76
+ # namespaces
77
+ extend MetaBuilder::DescriptionExtend
78
+ include MetaBuilder::DescriptionInclude
79
+
80
+ # Backend is a factory, but no autoregistering is made.
81
+ create_factory false
82
+
83
+ # Sets up a few things, such as the filters.
84
+ def initialize()
85
+ @xy_filters = []
86
+ @xy_filters_apply = false
87
+
88
+ @xyz_filters = []
89
+ @xyz_filters_apply = false
90
+
91
+ # If set, uses this set as a baseline for all the others.
92
+ @base_line = ""
93
+ @base_line_cache = false
94
+
95
+ # Filters are classes that have one method apply, which takes a
96
+ # pair/triplet of vectors and return the same number of stuff,
97
+ # modified or not.
98
+
99
+
100
+ # We create a cache by default. Doesn't take up much space anyway:
101
+ @cache = Cache.new
102
+ end
103
+
104
+ def push_xy_filter(f)
105
+ @xy_filters << f
106
+ @xy_filters_apply = true
107
+ end
108
+
109
+ # Removes a filter from the top
110
+ def pop_xy_filter
111
+ return @xy_filters.pop
112
+ end
113
+
114
+ # Removes all filters on the list.
115
+ def clear_xy_filters
116
+ @xy_filters = []
117
+ @xy_filters_apply = false
118
+ end
119
+
120
+
121
+ # Creates a description object with the given texts and associates
122
+ # it with the class. It is necessary to have this statement
123
+ # *before* any parameter declaration. If you don't set any description,
124
+ # you will not be able to benefit from the plugin system.
125
+ # To be used in Backend subclasses, simply this way:
126
+ #
127
+ # describe "biniou", "Biniou backend", "A backend to deal with Binious"
128
+ #
129
+ def Backend.describe(name, longname, desc, register = true)
130
+ d = BackendDescription.new(self, name, longname, desc, register)
131
+ set_description(d)
132
+ end
133
+
134
+ # Returns a hash containing the description of all available backends
135
+ def Backend.list_backends
136
+ return factory_description_hash
137
+ end
138
+
139
+ def Backend.list_descriptions
140
+ warn "Backend.list_descriptions should not be used, use Backend.list_backends instead"
141
+ list_backends
142
+ end
143
+
144
+ describe 'backend', 'The base class for backends', <<EOD, false
145
+ This is the base class for backends. It should never be used directly.
146
+ EOD
147
+
148
+ # A hook to set a baseline:
149
+ param_reader :base_line=, :base_line, "baseline", "Base line",
150
+ {:type => :string, }, "Sets a baseline for subsequent data sets"
151
+
152
+
153
+ def base_line=(str)
154
+ if str =~ /^no$/ or str.empty?
155
+ @base_line = ""
156
+ else
157
+ @base_line = expand_sets(str)[0]
158
+ # Fill the cache.
159
+ ary = query_xy_data(@base_line)
160
+ @base_line_cache = if ary.is_a?(Array)
161
+ ary[0]
162
+ else
163
+ ary
164
+ end
165
+ end
166
+ end
167
+
168
+ # This function should return a hash containing all meta-information
169
+ # available about the given set. The hash can contain elements such as:
170
+ #
171
+ # <tt>:date</tt>:: the date at which the set was recorded
172
+ # <tt>:x_legend</tt>:: legend of the X axis
173
+ # <tt>:x_unit</tt>:: unit of the X axis
174
+ # (and the same kind for Y and Z axis)
175
+ #
176
+ # Of course, this list is not limitative; you are encouraged at any rate
177
+ # to add as much metadata as possible. Later on, I'll provide a method
178
+ # to register metadata types.
179
+
180
+ def meta_data(set)
181
+ warn "No metadata implementation for backend " +
182
+ "#{description.name}"
183
+ end
184
+
185
+ # Returns true if the backend can provide data for the given set.
186
+ def has_set?(set)
187
+ return false
188
+ end
189
+
190
+ alias set? has_set?
191
+
192
+ # Returns :xy or :xyz depending on the kind of the given set.
193
+ def set_type(set)
194
+ raise "Shouldn't be called for the base class"
195
+ end
196
+
197
+ # This function must be redefined by children who provide
198
+ # 2D datasets. This function must return either:
199
+ # * a Function alone, representing the 2D data of the set
200
+ # * or an Array, whose first element is a Function and whose
201
+ # second element is an array containing metadata about the
202
+ # dataset.
203
+ def query_xy_data(set)
204
+ raise "query_xy_data must be redefined by children !"
205
+ end
206
+
207
+ # Used by other classes to query for the Backends data. This may
208
+ # include processing with data filters. Please note that the
209
+ # query_xy_data functions *must* return a Dobjects::Function.
210
+ # The return value *must* be modifiable without consequences to
211
+ # the backend.
212
+ def xy_data(set)
213
+ retval = query_xy_data(set)
214
+ if retval.is_a?(Array)
215
+ ary,errors,meta = *retval
216
+ else
217
+ ary = retval
218
+ errors = {}
219
+ meta = {}
220
+ end
221
+ if (not @base_line.empty?) and @base_line_cache
222
+ ary.y.sub!(@base_line_cache.y)
223
+ end
224
+ # Now, this is the fun part: we create the Dataset object
225
+ dataset = DataSet2D.new(self, ary, errors, meta)
226
+ # apply the filters if necessary
227
+ if @xy_filters_apply
228
+ for filter in @xy_filters
229
+ filter.apply!(dataset)
230
+ end
231
+ end
232
+ return dataset
233
+ end
234
+
235
+ # Returns the XYZ data for the given set
236
+ def xyz_data(set)
237
+ ary = query_xyz_data(set)
238
+ # apply the filters if necessary
239
+ if @xyz_filters_apply
240
+ for filter in @xyz_filters
241
+ ary = filter.apply(ary)
242
+ end
243
+ end
244
+ return ary
245
+ end
246
+
247
+
248
+ # When converting a user input into a set, a program should
249
+ # *always* use this function, unless it has really good reasons for
250
+ # that.
251
+ #
252
+ # The default implementation is to expand 2##4 to 2, 3, 4. Can be
253
+ # useful even for mathematical stuff.
254
+ #
255
+ # Another thing is recognised and expanded:
256
+ # #<2<i*2>,5> runs the code i*2 with the values from 2 to 5 and
257
+ # returns the result. The code in the middle is a Ruby block, and therefore
258
+ # should be valid !
259
+ #
260
+ # A third expansion is now available:
261
+ # #<a = 2<a * sin(x)>10> will expand into 2*sin(x) , 3*sin(x) ... 10*sin(x)
262
+ # it is different than the previous in the sense that the code in the
263
+ # middle is not a Ruby code, but a mere string, which means there won't be
264
+ # compilation problems.
265
+ #
266
+ # Unless your backend can't accomodate for that, all redefinitions
267
+ # of this function should check for their specific signatures
268
+ # first and call this function if they fail. This way, they
269
+ # will profit from improvements in this code while keeping
270
+ # old stuff working.
271
+ def expand_sets(spec)
272
+ if m = /(\d+)##(\d+)/.match(spec)
273
+ debug "Using expansion rule #1"
274
+ a = m[1].to_i
275
+ b = m[2].to_i
276
+ ret = []
277
+ a.upto(b) do |i|
278
+ ret << m.pre_match + i.to_s + m.post_match
279
+ end
280
+ return ret
281
+ elsif m = /\#<(\d+)<(.*?)>(\d+)>/.match(spec)
282
+ debug "Using expansion rule #2"
283
+ from = m[1].to_i
284
+ to = m[3].to_i
285
+ debug "Ruby code used for expansion: {|i| #{m[2]} }"
286
+ code = eval "proc {|i| #{m[2]} }"
287
+ ret = []
288
+ from.upto(to) do |i|
289
+ ret << m.pre_match + code.call(i).to_s + m.post_match
290
+ end
291
+ return ret
292
+ elsif m = /\#<\s*(\w+)\s*=\s*(\d+)\s*<(.*?)>\s*(\d+)\s*>/.match(spec)
293
+ debug "Using expansion rule #3"
294
+ var = m[1]
295
+ from = m[2].to_i
296
+ to = m[4].to_i
297
+ # Then we replace all occurences of the variable
298
+ literal = '"' + m[3].gsub(/\b#{var}\b/, '#{' + var + '}') + '"'
299
+ debug "Ruby code used for expansion: {|#{var}| #{literal} }"
300
+ code = eval "proc {|#{var}| #{literal} }"
301
+ ret = []
302
+ from.upto(to) do |i|
303
+ ret << m.pre_match + code.call(i).to_s + m.post_match
304
+ end
305
+ return ret
306
+ end
307
+ # Fallback
308
+ return [spec]
309
+ rescue Exception => ex
310
+ # In case something went wrong in the eval.
311
+ warn "An error occured during expansion of '#{spec}': #{ex.message}"
312
+ debug "Error backtrace: #{ex.backtrace.join "\n"}"
313
+ warn "Ignoring, but you're nearly garanteed something will "+
314
+ "fail later on"
315
+ return [spec]
316
+ end
317
+
318
+ # Some backends have a pretty good idea of the sets available for use.
319
+ # Some really don't. You can choose to reimplement this function if
320
+ # you can provide a useful list of sets for your backend. This list
321
+ # doesn't need to be exhaustive (and is most unlikely to be). It can
322
+ # also return something that would need further expansion using
323
+ # expand_sets.
324
+ def sets_available
325
+ return []
326
+ end
327
+
328
+ # Gets a cached entry or generate it and cache it. See Cache#cache
329
+ # for more details. The cache's meta_data is constructed as following:
330
+ # * the current state of the backend is taken
331
+ # * keys inside _exclude_ are removed.
332
+ # * _supp_info_ is added
333
+ def get_cached_entry(name, exclude = [], supp_info = {}, &code)
334
+ state = save_state
335
+ for k in exclude
336
+ state.delete(k)
337
+ end
338
+ state.merge!(supp_info)
339
+ return @cache.get_cache(name, state, &code)
340
+ end
341
+
342
+ # Returns the default state of the named backend,
343
+ # or nil if it wasn't found.
344
+ def self.default_state(name)
345
+ desc = factory_description_hash[name]
346
+ if desc
347
+ return desc.default_state
348
+ else
349
+ return nil
350
+ end
351
+ end
352
+
353
+ @@log = nil
354
+
355
+ # Set the logger for Backends
356
+ def self.logger= (logger)
357
+ @@log = logger
358
+ end
359
+
360
+ # Facilities for logging: we forward all functions that look
361
+ # like logging facility to the @@log class variable, if that
362
+ # one responds to it.
363
+ methods = %w(warn info debug error fatal)
364
+ for meth in methods
365
+ eval <<"EOE"
366
+ def #{meth}(*args)
367
+ if @@log.respond_to? :#{meth}
368
+ @@log.#{meth}(*args)
369
+ end
370
+ end
371
+ EOE
372
+ end
373
+
374
+ # ruby.el really isn't happy with this one
375
+ private *methods.map {|t| t.to_sym}
376
+
377
+ end
378
+ end
379
+ end
@@ -0,0 +1,168 @@
1
+ # binner.rb : a binning backend to make histograms
2
+ # Copyright (C) 2008 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
+
19
+
20
+ require 'SciYAG/Backends/backend'
21
+ require 'Dobjects/Dvector'
22
+ require 'Dobjects/Function'
23
+
24
+ module SciYAG
25
+
26
+ module Backends
27
+
28
+ class BinnerBackend < Backend
29
+
30
+ include Dobjects
31
+
32
+ describe 'binner', 'Automatic binner', <<EOD
33
+ Reads 1D data and bins them, giving the average position of the
34
+ bin and counts.
35
+ EOD
36
+
37
+
38
+ param_accessor :number, 'number', "Number of bins", :integer,
39
+ "Number of bins"
40
+
41
+ param_accessor :x_range, 'xrange', "X Range", :float_range,
42
+ "X range (a:b)"
43
+
44
+ param_accessor :normalize, 'norm', "Normalize", :boolean,
45
+ "Whether to divide by the total"
46
+
47
+ param_accessor :bin_size, 'bin', "Step size", :float,
48
+ "The bin size"
49
+
50
+
51
+ def initialize
52
+ @number = 20
53
+ @skip = 0
54
+ @separator = /\s+/
55
+ @default_column_spec = "1"
56
+
57
+ @x_range = false
58
+ @normalize = false
59
+
60
+ @bin_size = false
61
+
62
+ super()
63
+
64
+ @cache = {}
65
+ end
66
+
67
+
68
+ # Reads data from a file. If needed, extract the file from the set
69
+ # specification.
70
+ def read_file(file)
71
+ if file =~ /(.*)@.*/
72
+ file = $1
73
+ end
74
+ name = file # As file will be modified.
75
+ if ! @cache.key?(file) # Read the file if it is not cached.
76
+ if file == "-"
77
+ file = $stdin
78
+ elsif file =~ /(.*?)\|\s*$/
79
+ file = IO.popen($1)
80
+ end
81
+ fancy_read_options = {'index_col' => true,
82
+ 'skip_first' => @skip,
83
+ 'sep' => @separator
84
+ }
85
+ debug "Fancy read '#{file}', options #{fancy_read_options.inspect}"
86
+ @cache[name] = Dvector.fancy_read(file, nil, fancy_read_options)
87
+ end
88
+ return @cache[name]
89
+ end
90
+
91
+
92
+ # This is called by the architecture to get the data. It splits
93
+ # the set name into filename@cols, reads the file if necessary and
94
+ # calls get_data
95
+ def query_xy_data(set)
96
+ if set =~ /(.*)@(.*)/
97
+ col_spec = $2
98
+ file = $1
99
+ else
100
+ col_spec = @default_column_spec
101
+ file = set
102
+ end
103
+ if file.length > 0
104
+ @current_data = read_file(file)
105
+ @current = file
106
+ end
107
+ x,y = get_data(col_spec)
108
+ return Function.new(x,y)
109
+ end
110
+
111
+ # Reads the data using the columns specification, provided that
112
+ # the appropriate fle has already been loaded into @current. For now
113
+ # no single sanity check.
114
+ def get_data(col_spec)
115
+ if col_spec =~ /\$/ # There is a formula in the specification
116
+ formula = col_spec.gsub(/\$(\d+)/, 'column[\1]')
117
+ debug "Using formula '#{formula}'"
118
+ data = Dvector.
119
+ compute_formula(formula,
120
+ @current_data,[])
121
+ else
122
+ data = @current_data[col_spec.to_i].dup
123
+ end
124
+
125
+ # Now, data is a single Dvector of numbers. We want to bin it:
126
+ if @x_range
127
+ min = @x_range.first
128
+ max = @x_range.last
129
+ else
130
+ min = data.min
131
+ max = data.max
132
+ end
133
+
134
+
135
+ if @bin_size
136
+ delta = @bin_size
137
+ nb_bins = (((max - min).abs)/@bin_size).ceil.to_i + 1
138
+ else
139
+ nb_bins = @number
140
+ delta = (max - min)/(nb_bins - 1)
141
+ end
142
+
143
+ # We create a X Dvector:
144
+ x_values = Dvector.new(nb_bins)
145
+ y_values = Dvector.new(nb_bins)
146
+ nb_bins.times do |i|
147
+ x_values[i] = min + delta * i
148
+ y_values[i] = 0
149
+ end
150
+
151
+ # Now, we bin it:
152
+ for val in data
153
+ i = ((val - min)/delta).round
154
+ y_values[i] += 1
155
+ end
156
+
157
+ if @normalize
158
+ y_values /= data.size
159
+ end
160
+
161
+ return [x_values, y_values]
162
+ end
163
+
164
+ end
165
+
166
+ end
167
+
168
+ end