ctioga2 0.0
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/COPYING +339 -0
- data/Changelog +6 -0
- data/bin/ctioga2 +26 -0
- data/lib/ctioga2/commands/arguments.rb +58 -0
- data/lib/ctioga2/commands/commands.rb +258 -0
- data/lib/ctioga2/commands/doc/doc.rb +118 -0
- data/lib/ctioga2/commands/doc/documentation-commands.rb +119 -0
- data/lib/ctioga2/commands/doc/help.rb +95 -0
- data/lib/ctioga2/commands/doc/html.rb +230 -0
- data/lib/ctioga2/commands/doc/introspection.rb +211 -0
- data/lib/ctioga2/commands/doc/man.rb +279 -0
- data/lib/ctioga2/commands/doc/markup.rb +359 -0
- data/lib/ctioga2/commands/general-commands.rb +119 -0
- data/lib/ctioga2/commands/general-types.rb +118 -0
- data/lib/ctioga2/commands/groups.rb +73 -0
- data/lib/ctioga2/commands/interpreter.rb +257 -0
- data/lib/ctioga2/commands/parsers/command-line.rb +187 -0
- data/lib/ctioga2/commands/parsers/file.rb +186 -0
- data/lib/ctioga2/commands/strings.rb +303 -0
- data/lib/ctioga2/commands/type.rb +100 -0
- data/lib/ctioga2/commands/variables.rb +101 -0
- data/lib/ctioga2/data/backends/backend.rb +260 -0
- data/lib/ctioga2/data/backends/backends.rb +39 -0
- data/lib/ctioga2/data/backends/backends/gnuplot.rb +140 -0
- data/lib/ctioga2/data/backends/backends/math.rb +121 -0
- data/lib/ctioga2/data/backends/backends/text.rb +335 -0
- data/lib/ctioga2/data/backends/description.rb +405 -0
- data/lib/ctioga2/data/backends/factory.rb +73 -0
- data/lib/ctioga2/data/backends/parameter.rb +109 -0
- data/lib/ctioga2/data/datacolumn.rb +245 -0
- data/lib/ctioga2/data/dataset.rb +233 -0
- data/lib/ctioga2/data/filters.rb +131 -0
- data/lib/ctioga2/data/merge.rb +43 -0
- data/lib/ctioga2/data/point.rb +72 -0
- data/lib/ctioga2/data/stack.rb +294 -0
- data/lib/ctioga2/graphics/coordinates.rb +73 -0
- data/lib/ctioga2/graphics/elements.rb +111 -0
- data/lib/ctioga2/graphics/elements/containers.rb +111 -0
- data/lib/ctioga2/graphics/elements/curve2d.rb +155 -0
- data/lib/ctioga2/graphics/elements/element.rb +90 -0
- data/lib/ctioga2/graphics/elements/primitive.rb +256 -0
- data/lib/ctioga2/graphics/elements/subplot.rb +140 -0
- data/lib/ctioga2/graphics/generator.rb +68 -0
- data/lib/ctioga2/graphics/legends.rb +108 -0
- data/lib/ctioga2/graphics/legends/area.rb +199 -0
- data/lib/ctioga2/graphics/legends/items.rb +183 -0
- data/lib/ctioga2/graphics/legends/provider.rb +58 -0
- data/lib/ctioga2/graphics/legends/storage.rb +65 -0
- data/lib/ctioga2/graphics/root.rb +209 -0
- data/lib/ctioga2/graphics/styles.rb +30 -0
- data/lib/ctioga2/graphics/styles/axes.rb +247 -0
- data/lib/ctioga2/graphics/styles/background.rb +122 -0
- data/lib/ctioga2/graphics/styles/base.rb +115 -0
- data/lib/ctioga2/graphics/styles/carrays.rb +53 -0
- data/lib/ctioga2/graphics/styles/curve.rb +101 -0
- data/lib/ctioga2/graphics/styles/drawable.rb +87 -0
- data/lib/ctioga2/graphics/styles/factory.rb +351 -0
- data/lib/ctioga2/graphics/styles/legend.rb +63 -0
- data/lib/ctioga2/graphics/styles/plot.rb +410 -0
- data/lib/ctioga2/graphics/styles/sets.rb +64 -0
- data/lib/ctioga2/graphics/styles/texts.rb +277 -0
- data/lib/ctioga2/graphics/subplot-commands.rb +141 -0
- data/lib/ctioga2/graphics/types.rb +188 -0
- data/lib/ctioga2/graphics/types/bijection.rb +79 -0
- data/lib/ctioga2/graphics/types/boundaries.rb +170 -0
- data/lib/ctioga2/graphics/types/boxes.rb +157 -0
- data/lib/ctioga2/graphics/types/dimensions.rb +157 -0
- data/lib/ctioga2/graphics/types/point.rb +247 -0
- data/lib/ctioga2/log.rb +97 -0
- data/lib/ctioga2/metabuilder/type.rb +316 -0
- data/lib/ctioga2/metabuilder/types.rb +39 -0
- data/lib/ctioga2/metabuilder/types/coordinates.rb +124 -0
- data/lib/ctioga2/metabuilder/types/dates.rb +43 -0
- data/lib/ctioga2/metabuilder/types/lists.rb +188 -0
- data/lib/ctioga2/metabuilder/types/numbers.rb +97 -0
- data/lib/ctioga2/metabuilder/types/strings.rb +93 -0
- data/lib/ctioga2/metabuilder/types/styles.rb +178 -0
- data/lib/ctioga2/plotmaker.rb +677 -0
- data/lib/ctioga2/postprocess.rb +115 -0
- data/lib/ctioga2/utils.rb +120 -0
- data/setup.rb +1586 -0
- metadata +144 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# backends.rb: all the backends
|
|
2
|
+
|
|
3
|
+
# This program is free software; you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
|
5
|
+
# the Free Software Foundation; either version 2 of the License, or
|
|
6
|
+
# (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful, but
|
|
9
|
+
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
11
|
+
# General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with this program; if not, write to the Free Software
|
|
15
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
|
|
16
|
+
# USA
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
require 'ctioga2/data/backends/backend'
|
|
20
|
+
|
|
21
|
+
# We try to look for all files under a ctioga2/metabuilder/types
|
|
22
|
+
# directory anywhere on the $: path
|
|
23
|
+
|
|
24
|
+
files = []
|
|
25
|
+
for dir in $:
|
|
26
|
+
Dir[dir + '/ctioga2/data/backends/backends/**/*'].each do |f|
|
|
27
|
+
f =~ /ctioga2\/data\/backends\/backends\/(.*)\.[^.]+$/
|
|
28
|
+
files << $1
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
for file in files.uniq
|
|
33
|
+
begin
|
|
34
|
+
require "ctioga2/data/backends/backends/#{file}"
|
|
35
|
+
rescue Exception => e
|
|
36
|
+
warn "There was a problem trying to load 'ctioga2/data/backends/backends/#{file}': "
|
|
37
|
+
warn "#{e.inspect}"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# gnuplot.rb: a backend to extract plots from gnuplot's files
|
|
2
|
+
# Copyright (C) 2007,2009 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 'Dobjects/Dvector'
|
|
21
|
+
require 'Dobjects/Function'
|
|
22
|
+
|
|
23
|
+
# To feed data to fancyread
|
|
24
|
+
require 'stringio'
|
|
25
|
+
|
|
26
|
+
module CTioga2
|
|
27
|
+
|
|
28
|
+
Version::register_svn_info('$Revision: 61 $', '$Date: 2009-05-29 01:00:56 +0200 (Fri, 29 May 2009) $')
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
module Data
|
|
32
|
+
|
|
33
|
+
module Backends
|
|
34
|
+
|
|
35
|
+
class GnuplotBackend < Backend
|
|
36
|
+
|
|
37
|
+
include Dobjects
|
|
38
|
+
include Log
|
|
39
|
+
|
|
40
|
+
describe 'gnuplot', 'Gnuplot files', <<EOD
|
|
41
|
+
This backend hijacks gnuplot files to make extract data which they plot.
|
|
42
|
+
No information is taken about the style !
|
|
43
|
+
EOD
|
|
44
|
+
|
|
45
|
+
param_accessor :variables_overrides, 'vars',
|
|
46
|
+
"Variable overrides", 'text', <<EOD
|
|
47
|
+
A colon-separated override of local variables, such as a=1;b=3;c=5
|
|
48
|
+
EOD
|
|
49
|
+
|
|
50
|
+
param_accessor :range, 'range',
|
|
51
|
+
"Plotting X range", 'float-range',
|
|
52
|
+
"The plotting X range, such as 0:2"
|
|
53
|
+
|
|
54
|
+
# This is called by the architecture to get the data. It splits
|
|
55
|
+
# the set name into filename@cols, reads the file if necessary and
|
|
56
|
+
# calls get_data
|
|
57
|
+
def query_dataset(set)
|
|
58
|
+
set =~ /^(.*?)(?:@(\d+))?(?::(.*))?$/
|
|
59
|
+
filename = $1
|
|
60
|
+
if $2
|
|
61
|
+
number = $2.to_i - 1
|
|
62
|
+
else
|
|
63
|
+
number = 0
|
|
64
|
+
end
|
|
65
|
+
if $3
|
|
66
|
+
overrides = "#{@variable_overrides};#{$3}"
|
|
67
|
+
else
|
|
68
|
+
overrides = @variable_overrides
|
|
69
|
+
end
|
|
70
|
+
plots = run_gnuplot(filename, overrides)
|
|
71
|
+
return Dataset.new(set,plots[number])
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Runs gnuplot on the file, and returns all datasets found
|
|
75
|
+
# inside it.
|
|
76
|
+
def run_gnuplot(filename, overrides = @variables_overrides)
|
|
77
|
+
date = File::mtime(filename)
|
|
78
|
+
# Get it from the cache !
|
|
79
|
+
debug "Running gnuplot on file #{filename}"
|
|
80
|
+
f = File.open(filename)
|
|
81
|
+
# We open a bidirectionnal connection to gnuplot:
|
|
82
|
+
gnuplot = IO.popen("gnuplot", "r+")
|
|
83
|
+
output = ""
|
|
84
|
+
gnuplot.puts "set term table"
|
|
85
|
+
for line in f
|
|
86
|
+
next if line =~ /set\s+term/
|
|
87
|
+
if overrides and line =~ /plot\s+/
|
|
88
|
+
debug "Found a plot, inserting variable overrides: #{overrides}"
|
|
89
|
+
line.gsub!(/plot\s+/, "#{overrides};plot ")
|
|
90
|
+
end
|
|
91
|
+
if @range and line =~ /plot\s+/
|
|
92
|
+
debug "Found a plot, inserting range: #{@range}"
|
|
93
|
+
line.gsub!(/plot\s+(\[[^\]]+\])?/,
|
|
94
|
+
"plot [#{@range}]")
|
|
95
|
+
end
|
|
96
|
+
gnuplot.print line
|
|
97
|
+
gnuplot.flush
|
|
98
|
+
output += slurp(gnuplot)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Output a "\n" in the end.
|
|
102
|
+
|
|
103
|
+
gnuplot.puts ""
|
|
104
|
+
gnuplot.flush
|
|
105
|
+
gnuplot.close_write
|
|
106
|
+
# Then we get all that is remaining:
|
|
107
|
+
output += gnuplot.read
|
|
108
|
+
gnuplot.close
|
|
109
|
+
|
|
110
|
+
# Now, interaction with gnuplot is finished, and we want to
|
|
111
|
+
# parse that:
|
|
112
|
+
outputs = output.split("\n\n")
|
|
113
|
+
plots = []
|
|
114
|
+
for data in outputs
|
|
115
|
+
plots << Dvector.fancy_read(StringIO.new(data), [0,1])
|
|
116
|
+
end
|
|
117
|
+
# This block evaluates to plots:
|
|
118
|
+
return plots
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Gets all data from the given file until it blocks, and returns it.
|
|
122
|
+
def slurp(f, size = 10240)
|
|
123
|
+
str = ""
|
|
124
|
+
begin
|
|
125
|
+
while IO::select([f],[],[],0)
|
|
126
|
+
ret = f.readpartial(size)
|
|
127
|
+
if ret.empty?
|
|
128
|
+
return str
|
|
129
|
+
end
|
|
130
|
+
str << ret
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
return str
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# math.rb :the Math backend: data based on mathematical formulas.
|
|
2
|
+
# Copyright (C) 2006 - 2009 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
|
+
require 'Dobjects/Dvector'
|
|
20
|
+
require 'Dobjects/Function'
|
|
21
|
+
|
|
22
|
+
module CTioga2
|
|
23
|
+
|
|
24
|
+
Version::register_svn_info('$Revision: 17 $', '$Date: 2009-04-28 22:22:22 +0200 (Tue, 28 Apr 2009) $')
|
|
25
|
+
|
|
26
|
+
module Data
|
|
27
|
+
|
|
28
|
+
module Backends
|
|
29
|
+
|
|
30
|
+
class MathBackend < Backend
|
|
31
|
+
|
|
32
|
+
include Dobjects
|
|
33
|
+
include Math
|
|
34
|
+
|
|
35
|
+
describe 'math', 'Mathematical functions', <<EOD
|
|
36
|
+
This backend returns computations of mathematical formulas.
|
|
37
|
+
EOD
|
|
38
|
+
|
|
39
|
+
# TODO: make provisions for 3-D datasets. Ideas: x(t):y(t):z(t)
|
|
40
|
+
# for parametric plots ? (possibly x(t):y1(t):y2(t):...:yn(t)) ?
|
|
41
|
+
|
|
42
|
+
param_accessor :samples, 'samples', "Samples", 'integer',
|
|
43
|
+
"The number of points"
|
|
44
|
+
param_accessor :x_range, 'xrange', "X Range", 'float-range',
|
|
45
|
+
"X range (a:b)"
|
|
46
|
+
param_accessor :t_range, 'trange', "T Range", 'float-range',
|
|
47
|
+
"T range (a:b) (parametric plot)"
|
|
48
|
+
|
|
49
|
+
param_accessor :log, 'log', "Logarithmic scale", 'boolean',
|
|
50
|
+
"Space samples logarithmically"
|
|
51
|
+
|
|
52
|
+
def initialize
|
|
53
|
+
super()
|
|
54
|
+
@samples = 100
|
|
55
|
+
@x_range = -10.0..10.0
|
|
56
|
+
@t_range = -10.0..10.0
|
|
57
|
+
@log = false
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# This is called by the architecture to get the data. It first
|
|
61
|
+
# splits the set name into func@range.
|
|
62
|
+
def query_dataset(set)
|
|
63
|
+
if set =~ /(.*)@(.*)/
|
|
64
|
+
set = $1
|
|
65
|
+
range = $2
|
|
66
|
+
end
|
|
67
|
+
name = "math: #{set}"
|
|
68
|
+
if set =~ /:/ # parametric
|
|
69
|
+
if range
|
|
70
|
+
set_param_from_string(:t_range, range)
|
|
71
|
+
end
|
|
72
|
+
varname = "t"
|
|
73
|
+
values = make_dvector(@t_range, @samples, @log)
|
|
74
|
+
else
|
|
75
|
+
if range
|
|
76
|
+
set_param_from_string(:x_range, range)
|
|
77
|
+
end
|
|
78
|
+
varname = "x"
|
|
79
|
+
values = make_dvector(@x_range, @samples, @log)
|
|
80
|
+
set = "x:#{set}"
|
|
81
|
+
end
|
|
82
|
+
return Dataset.dataset_from_spec(name, set) do |b|
|
|
83
|
+
get_data_column(b, varname, values)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
protected
|
|
89
|
+
|
|
90
|
+
# Turns a Range and a number of points into a Dvector
|
|
91
|
+
def make_dvector(range, nb_points, log = @log)
|
|
92
|
+
n = nb_points -1
|
|
93
|
+
a = Dvector.new(nb_points) { |i|
|
|
94
|
+
i.to_f/(n.to_f)
|
|
95
|
+
}
|
|
96
|
+
# a is in [0:1] inclusive...
|
|
97
|
+
if log
|
|
98
|
+
delta = range.last/range.first
|
|
99
|
+
# delta is positive necessarily
|
|
100
|
+
a *= delta.log
|
|
101
|
+
a.exp!
|
|
102
|
+
a *= range.first
|
|
103
|
+
else
|
|
104
|
+
delta = range.last - range.first
|
|
105
|
+
a *= delta
|
|
106
|
+
a += range.first
|
|
107
|
+
end
|
|
108
|
+
return a
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Uses compute_formula to get data from
|
|
112
|
+
def get_data_column(column, variable, values)
|
|
113
|
+
column.gsub!(/\b#{variable}\b/, "(column[0])")
|
|
114
|
+
Dvector.compute_formula(column, [values])
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
# text.rb : A simple backend to deal with basic text files.
|
|
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
|
+
|
|
19
|
+
|
|
20
|
+
require 'Dobjects/Dvector'
|
|
21
|
+
require 'Dobjects/Function'
|
|
22
|
+
|
|
23
|
+
# For separated sets
|
|
24
|
+
require 'stringio'
|
|
25
|
+
|
|
26
|
+
module CTioga2
|
|
27
|
+
|
|
28
|
+
Version::register_svn_info('$Revision: 17 $', '$Date: 2009-04-28 22:22:22 +0200 (Tue, 28 Apr 2009) $')
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
module Data
|
|
32
|
+
|
|
33
|
+
# A module for easy use of NaN in operations
|
|
34
|
+
module NaN
|
|
35
|
+
NaN = 0.0/0.0
|
|
36
|
+
def nan
|
|
37
|
+
return NaN
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
module Backends
|
|
42
|
+
|
|
43
|
+
class TextBackend < Backend
|
|
44
|
+
|
|
45
|
+
# A constant holding a relation extension -> command to
|
|
46
|
+
# decompress (to be fed to sprintf with the filename as argument)
|
|
47
|
+
UNCOMPRESSORS = {
|
|
48
|
+
".gz" => "gunzip -c %s",
|
|
49
|
+
".bz2" => "bunzip2 -c %s",
|
|
50
|
+
".lzma" => "unlzma -c %s",
|
|
51
|
+
".lz" => "unlzma -c %s",
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
include Dobjects
|
|
55
|
+
|
|
56
|
+
describe 'text', 'Text format', <<EOD
|
|
57
|
+
This backend can read text files in a format close to the one understood
|
|
58
|
+
by gnuplot and the like.
|
|
59
|
+
EOD
|
|
60
|
+
|
|
61
|
+
# Inherit the baseline handling, can be useful !
|
|
62
|
+
# inherit_parameters :base_line
|
|
63
|
+
|
|
64
|
+
param_accessor :skip, 'skip', "Skip lines", 'integer',
|
|
65
|
+
"Number of lines to be skipped at the beginning of the file"
|
|
66
|
+
|
|
67
|
+
param_accessor :default_column_spec, 'col',
|
|
68
|
+
"Default column specification", 'text',
|
|
69
|
+
"Which columns to use when the @1:2 syntax is not used"
|
|
70
|
+
|
|
71
|
+
param_accessor :split, 'split', "Split into subsets", 'boolean',
|
|
72
|
+
"If true, splits files into subsets on blank/non number lines"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
param_accessor :separator, 'separator', "Data columns separator",
|
|
76
|
+
'regexp',
|
|
77
|
+
"The columns separator. Defaults to /\s+/"
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# param_accessor :select, 'select', "Select lines", {:type => :string},
|
|
81
|
+
# "Skips line where the code returns false"
|
|
82
|
+
|
|
83
|
+
def initialize
|
|
84
|
+
@dummy = nil
|
|
85
|
+
@current = nil
|
|
86
|
+
# Current is the name of the last file used. Necessary for '' specs.
|
|
87
|
+
@current_data = nil # The data of the last file used.
|
|
88
|
+
@skip = 0
|
|
89
|
+
@included_modules = [NaN] # to make sure we give them to
|
|
90
|
+
# Dvector.compute_formula
|
|
91
|
+
@default_column_spec = "1:2"
|
|
92
|
+
|
|
93
|
+
@separator = /\s+/
|
|
94
|
+
|
|
95
|
+
# We don't split data by default.
|
|
96
|
+
@split = false
|
|
97
|
+
|
|
98
|
+
super()
|
|
99
|
+
|
|
100
|
+
# Override Backend's cache - for now.
|
|
101
|
+
@cache = {} # A cache file_name -> data
|
|
102
|
+
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def extend(mod)
|
|
106
|
+
super
|
|
107
|
+
@included_modules << mod
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Expands specifications into few sets. This function will separate the
|
|
111
|
+
# set into a file spec and a col spec. Within the col spec, the 2##6
|
|
112
|
+
# keyword is used to expand to 2,3,4,5,6. 2## followed by a non-digit
|
|
113
|
+
# expands to 2,...,last column in the file. For now, the expansions
|
|
114
|
+
# stops on the first occurence found, and the second form doesn't
|
|
115
|
+
# work yet. But soon...
|
|
116
|
+
def expand_sets(spec)
|
|
117
|
+
if m = /(\d+)##(\D|$)/.match(spec)
|
|
118
|
+
a = m[1].to_i
|
|
119
|
+
trail = m[2]
|
|
120
|
+
b = read_file(spec)
|
|
121
|
+
b = (b.length - 1)
|
|
122
|
+
ret = []
|
|
123
|
+
a.upto(b) do |i|
|
|
124
|
+
ret << m.pre_match + i.to_s + trail + m.post_match
|
|
125
|
+
end
|
|
126
|
+
return ret
|
|
127
|
+
else
|
|
128
|
+
return super
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
protected
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
# Returns a IO object suitable to acquire data from it for
|
|
137
|
+
# the given _file_, which can be one of the following:
|
|
138
|
+
# * a real file name
|
|
139
|
+
# * a compressed file name
|
|
140
|
+
# * a pipe command.
|
|
141
|
+
def get_io_object(file)
|
|
142
|
+
if file == "-"
|
|
143
|
+
return $stdin
|
|
144
|
+
elsif file =~ /(.*?)\|\s*$/ # A pipe
|
|
145
|
+
return IO.popen($1)
|
|
146
|
+
elsif not File.readable?(file)
|
|
147
|
+
# Try to find a compressed version
|
|
148
|
+
for ext,method in UNCOMPRESSORS
|
|
149
|
+
if File.readable? "#{file}#{ext}"
|
|
150
|
+
info "Using compressed file #{file}#{ext} in stead of #{file}"
|
|
151
|
+
return IO.popen(method % "#{file}#{ext}")
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
else
|
|
155
|
+
for ext, method in UNCOMPRESSORS
|
|
156
|
+
if file =~ /#{ext}$/
|
|
157
|
+
info "Taking file #{file} as a compressed file"
|
|
158
|
+
return IO.popen(method % file)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
return File::open(file)
|
|
162
|
+
end
|
|
163
|
+
error "Could not open #{file}"
|
|
164
|
+
return nil
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# A line is invalid if it is blank or starts
|
|
168
|
+
# neither with a digit nor +, - or .
|
|
169
|
+
#
|
|
170
|
+
# Maybe to be improved later.
|
|
171
|
+
InvalidLineRE = /^\s*$|^\s*[^\d+.\s-]+/
|
|
172
|
+
|
|
173
|
+
# Returns a string corresponding to the given _set_ of the
|
|
174
|
+
# given _io_ object.
|
|
175
|
+
#
|
|
176
|
+
# Sets are 1-based.
|
|
177
|
+
def get_set_string(io, set)
|
|
178
|
+
cur_set = 1
|
|
179
|
+
last_line_is_invalid = true
|
|
180
|
+
str = ""
|
|
181
|
+
line_number = 0
|
|
182
|
+
while line = io.gets
|
|
183
|
+
line_number += 1
|
|
184
|
+
if line =~ InvalidLineRE
|
|
185
|
+
debug "Found invalid line at #{line_number}"
|
|
186
|
+
if ! last_line_is_invalid
|
|
187
|
+
# We begin a new set.
|
|
188
|
+
cur_set += 1
|
|
189
|
+
debug "Found set #{cur_set} at line #{line_number}"
|
|
190
|
+
if(cur_set > set)
|
|
191
|
+
return str
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
last_line_is_invalid = true
|
|
195
|
+
else
|
|
196
|
+
last_line_is_invalid = false
|
|
197
|
+
if cur_set == set
|
|
198
|
+
str += line
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
return str
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Returns an IO object corresponding to the given file.
|
|
206
|
+
def get_io_set(file)
|
|
207
|
+
if not @split
|
|
208
|
+
return get_io_object(file)
|
|
209
|
+
else
|
|
210
|
+
file =~ /(.*?)(?:#(\d+))?$/; # ; to make ruby-mode indent correctly.
|
|
211
|
+
filename = $1
|
|
212
|
+
if $2
|
|
213
|
+
set = $2.to_i
|
|
214
|
+
else
|
|
215
|
+
set = 1
|
|
216
|
+
end
|
|
217
|
+
debug "Trying to get set #{set} from file '#{filename}'"
|
|
218
|
+
str = get_set_string(get_io_object(filename), set)
|
|
219
|
+
return StringIO.new(str)
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# Reads data from a file. If needed, extract the file from the
|
|
224
|
+
# columns specification.
|
|
225
|
+
#
|
|
226
|
+
# TODO: the cache really should include things such as time of
|
|
227
|
+
# last modification and various parameters that influence the
|
|
228
|
+
# reading of the file.
|
|
229
|
+
def read_file(file)
|
|
230
|
+
if file =~ /(.*)@.*/
|
|
231
|
+
file = $1
|
|
232
|
+
end
|
|
233
|
+
name = file # As file will be modified.
|
|
234
|
+
if ! @cache.key?(file) # Read the file if it is not cached.
|
|
235
|
+
fancy_read_options = {'index_col' => true,
|
|
236
|
+
'skip_first' => @skip,
|
|
237
|
+
'sep' => @separator
|
|
238
|
+
}
|
|
239
|
+
io_set = get_io_set(file)
|
|
240
|
+
debug "Fancy read '#{file}', options #{fancy_read_options.inspect}"
|
|
241
|
+
@cache[name] = Dvector.fancy_read(io_set, nil, fancy_read_options)
|
|
242
|
+
end
|
|
243
|
+
return @cache[name]
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
# This is called by the architecture to get the data. It
|
|
248
|
+
# splits the set name into filename@cols, reads the file if
|
|
249
|
+
# necessary and calls get_data
|
|
250
|
+
def query_dataset(set)
|
|
251
|
+
if set =~ /(.*)@(.*)/
|
|
252
|
+
col_spec = $2
|
|
253
|
+
file = $1
|
|
254
|
+
else
|
|
255
|
+
col_spec = @default_column_spec
|
|
256
|
+
file = set
|
|
257
|
+
end
|
|
258
|
+
if file.length > 0
|
|
259
|
+
@current_data = read_file(file)
|
|
260
|
+
@current = file
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
# Wether we need or not to compute formulas:
|
|
264
|
+
if col_spec =~ /\$/
|
|
265
|
+
compute_formulas = true
|
|
266
|
+
else
|
|
267
|
+
compute_formulas = false
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
return Dataset.dataset_from_spec(set, col_spec) do |col|
|
|
271
|
+
get_data_column(col, compute_formulas)
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# Gets the data corresponding to the given column. If
|
|
276
|
+
# _compute_formulas_ is true, the column specification is
|
|
277
|
+
# taken to be a formula (in the spirit of gnuplot's)
|
|
278
|
+
def get_data_column(column, compute_formulas = false)
|
|
279
|
+
if compute_formulas
|
|
280
|
+
formula = column.gsub(/\$(\d+)/, 'column[\1]')
|
|
281
|
+
debug "Using formula #{formula} for column spec: #{column}"
|
|
282
|
+
return Dvector.compute_formula(formula,
|
|
283
|
+
@current_data,
|
|
284
|
+
@included_modules)
|
|
285
|
+
else
|
|
286
|
+
return @current_data[column.to_i].dup
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# # Turns a target => values specification into something usable as
|
|
291
|
+
# # error bars, that is :xmin, :xmax and the like hashes. The rules
|
|
292
|
+
# # are the following:
|
|
293
|
+
# # * ?min/?max are passed on directly;
|
|
294
|
+
# # * ?e(abs) are transformed into ?min = ? - ?eabs, ?max = ? + ?eabs
|
|
295
|
+
# # * ?eu(p/?ed(own) are transformed respectively into ? +/- ?...
|
|
296
|
+
# # * ?er(el) become ?min = ?*(1 - ?erel, ?max = ?(1 + ?erel)
|
|
297
|
+
# # * ?erup/?erdown follow the same pattern...
|
|
298
|
+
# def compute_error_bars(values)
|
|
299
|
+
# target = {}
|
|
300
|
+
# for key in values.keys
|
|
301
|
+
# case key.to_s
|
|
302
|
+
# when /^[xy](min|max)?$/
|
|
303
|
+
# target[key] = values[key].dup # Just to make sure.
|
|
304
|
+
# when /^(.)e(a(bs?)?)?$/
|
|
305
|
+
# target["#{$1}min".to_sym] = values[$1.to_sym] - values[key]
|
|
306
|
+
# target["#{$1}max".to_sym] = values[$1.to_sym] + values[key]
|
|
307
|
+
# when /^(.)eu(p)?$/
|
|
308
|
+
# target["#{$1}max".to_sym] = values[$1.to_sym] + values[key]
|
|
309
|
+
# when /^(.)ed(o(wn?)?)?$/
|
|
310
|
+
# target["#{$1}min".to_sym] = values[$1.to_sym] - values[key]
|
|
311
|
+
# when /^(.)er(el?)?$/
|
|
312
|
+
# target["#{$1}min".to_sym] = values[$1.to_sym] *
|
|
313
|
+
# (values[key].neg + 1)
|
|
314
|
+
# target["#{$1}max".to_sym] = values[$1.to_sym] *
|
|
315
|
+
# (values[key] + 1)
|
|
316
|
+
# when /^(.)erd(o(wn?)?)?$/
|
|
317
|
+
# target["#{$1}min".to_sym] = values[$1.to_sym] *
|
|
318
|
+
# (values[key].neg + 1)
|
|
319
|
+
# when /^(.)erup?$/
|
|
320
|
+
# target["#{$1}max".to_sym] = values[$1.to_sym] *
|
|
321
|
+
# (values[key] + 1)
|
|
322
|
+
# else
|
|
323
|
+
# warn "Somehow, the target specification #{key} " +
|
|
324
|
+
# "didn't make it through"
|
|
325
|
+
# end
|
|
326
|
+
# end
|
|
327
|
+
# return target
|
|
328
|
+
# end
|
|
329
|
+
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
end
|
|
335
|
+
end
|