ctioga2 0.4 → 0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/Changelog +16 -0
- data/lib/ctioga2/commands/arguments.rb +5 -2
- data/lib/ctioga2/commands/commands.rb +45 -13
- data/lib/ctioga2/commands/context.rb +9 -1
- data/lib/ctioga2/commands/doc/help.rb +2 -2
- data/lib/ctioga2/commands/doc/html.rb +8 -8
- data/lib/ctioga2/commands/doc/introspection.rb +7 -5
- data/lib/ctioga2/commands/parsers/file.rb +123 -120
- data/lib/ctioga2/commands/parsers/old-file.rb +191 -0
- data/lib/ctioga2/commands/strings.rb +2 -2
- data/lib/ctioga2/data/datacolumn.rb +5 -2
- data/lib/ctioga2/data/dataset.rb +3 -13
- data/lib/ctioga2/data/indexed-dtable.rb +43 -11
- data/lib/ctioga2/data/stack.rb +65 -8
- data/lib/ctioga2/graphics/elements.rb +2 -1
- data/lib/ctioga2/graphics/elements/containers.rb +22 -3
- data/lib/ctioga2/graphics/elements/primitive.rb +5 -5
- data/lib/ctioga2/graphics/elements/xyz-contour.rb +123 -0
- data/lib/ctioga2/graphics/generator.rb +31 -5
- data/lib/ctioga2/graphics/legends.rb +44 -3
- data/lib/ctioga2/graphics/legends/area.rb +28 -9
- data/lib/ctioga2/graphics/legends/items.rb +34 -23
- data/lib/ctioga2/graphics/legends/multicols.rb +132 -0
- data/lib/ctioga2/graphics/styles.rb +3 -1
- data/lib/ctioga2/graphics/styles/axes.rb +10 -4
- data/lib/ctioga2/graphics/styles/base.rb +65 -11
- data/lib/ctioga2/graphics/styles/colormap.rb +2 -1
- data/lib/ctioga2/graphics/styles/contour.rb +141 -0
- data/lib/ctioga2/graphics/styles/curve.rb +49 -67
- data/lib/ctioga2/graphics/styles/drawable.rb +17 -8
- data/lib/ctioga2/graphics/styles/factory.rb +79 -38
- data/lib/ctioga2/graphics/styles/legend.rb +49 -6
- data/lib/ctioga2/graphics/styles/plot.rb +10 -9
- data/lib/ctioga2/graphics/styles/sheet.rb +11 -11
- data/lib/ctioga2/graphics/styles/texts.rb +38 -9
- data/lib/ctioga2/graphics/types.rb +20 -1
- data/lib/ctioga2/graphics/types/dimensions.rb +7 -1
- data/lib/ctioga2/metabuilder/types/lists.rb +4 -4
- data/lib/ctioga2/metabuilder/types/numbers.rb +3 -3
- data/lib/ctioga2/metabuilder/types/styles.rb +2 -2
- data/lib/ctioga2/plotmaker.rb +12 -1
- data/lib/ctioga2/utils.rb +27 -3
- metadata +8 -4
@@ -0,0 +1,191 @@
|
|
1
|
+
# old-file.rb: a file parser for ctioga2
|
2
|
+
# copyright (c) 2009, 2013 by 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 (in the COPYING file).
|
13
|
+
|
14
|
+
require 'stringio'
|
15
|
+
require 'ctioga2/utils'
|
16
|
+
require 'ctioga2/log'
|
17
|
+
require 'ctioga2/commands/commands'
|
18
|
+
require 'ctioga2/commands/strings'
|
19
|
+
|
20
|
+
module CTioga2
|
21
|
+
|
22
|
+
Version::register_svn_info('$Revision: 392 $', '$Date: 2013-06-23 01:05:02 +0200 (Sun, 23 Jun 2013) $')
|
23
|
+
|
24
|
+
module Commands
|
25
|
+
|
26
|
+
module Parsers
|
27
|
+
|
28
|
+
# Raised when EOF is encountered during a symbol parsing
|
29
|
+
class UnterminatedSymbol < Exception
|
30
|
+
end
|
31
|
+
|
32
|
+
# Unexepected character.
|
33
|
+
class UnexpectedCharacter < Exception
|
34
|
+
end
|
35
|
+
|
36
|
+
# Syntax error
|
37
|
+
class ParserSyntaxError < Exception
|
38
|
+
end
|
39
|
+
|
40
|
+
# This class is in charge of parsing a "old style" command file.
|
41
|
+
class OldFileParser
|
42
|
+
|
43
|
+
include Log
|
44
|
+
|
45
|
+
# Runs a command file targeting the given _interpreter_.
|
46
|
+
def self.run_command_file(file, interpreter)
|
47
|
+
OldFileParser.new.run_command_file(file, interpreter)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Runs the given command strings
|
51
|
+
def self.run_commands(strings, interpreter)
|
52
|
+
OldFileParser.new.run_commands(strings, interpreter)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Runs a command file targeting the given _interpreter_.
|
56
|
+
def run_command_file(file, interpreter)
|
57
|
+
f = open(file)
|
58
|
+
parse_io_object(f, interpreter)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Runs the given command strings
|
62
|
+
def run_commands(strings, interpreter)
|
63
|
+
io = StringIO.new(strings)
|
64
|
+
parse_io_object(io, interpreter)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Parses a given _io_ object, sending commands/variable
|
68
|
+
# definitions to the given _interpreter_.
|
69
|
+
def parse_io_object(io, interpreter)
|
70
|
+
# The process is simple: we look for symbols and
|
71
|
+
# corresponding syntax element: parentheses or assignments
|
72
|
+
|
73
|
+
## @todo It would be really great if assignments could be
|
74
|
+
## made conditional (a bit like in makefiles)
|
75
|
+
while(1)
|
76
|
+
symbol = up_to_next_symbol(io)
|
77
|
+
break if not symbol
|
78
|
+
|
79
|
+
while(1)
|
80
|
+
c = io.getc
|
81
|
+
if ! c # EOF
|
82
|
+
raise ParserSyntaxError, "Expecting something after symbol #{symbol}"
|
83
|
+
end
|
84
|
+
ch = c.chr
|
85
|
+
if ch =~ /\s/ # blank...
|
86
|
+
next
|
87
|
+
elsif ch == '(' # beginning of a function call
|
88
|
+
# Parse string:
|
89
|
+
str = InterpreterString.parse_until_unquoted(io,")")
|
90
|
+
# Now, we need to split str.
|
91
|
+
args = str.expand_and_split(/\s*,\s*/, interpreter)
|
92
|
+
|
93
|
+
cmd = interpreter.get_command(symbol)
|
94
|
+
real_args = args.slice!(0, cmd.argument_number)
|
95
|
+
# And now the options:
|
96
|
+
options = {}
|
97
|
+
|
98
|
+
# Problem: the space on the right of the = sign is
|
99
|
+
# *significant*.
|
100
|
+
for o in args
|
101
|
+
if o =~ /^\s*\/?([\w-]+)\s*=(.*)/
|
102
|
+
if cmd.has_option? $1
|
103
|
+
options[$1] = $2
|
104
|
+
else
|
105
|
+
error {
|
106
|
+
"Command #{cmd.name} does not take option #{$1}"
|
107
|
+
}
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
interpreter.context.parsing_file(symbol, io) # Missing line number
|
113
|
+
interpreter.run_command(cmd, real_args, options)
|
114
|
+
io.getc # Slurp up the )
|
115
|
+
break
|
116
|
+
elsif ch == ':' # Assignment
|
117
|
+
c = io.getc
|
118
|
+
if ! c # EOF
|
119
|
+
raise ParserSyntaxError, "Expecting = after :"
|
120
|
+
end
|
121
|
+
ch = c.chr
|
122
|
+
if ch != '='
|
123
|
+
raise ParserSyntaxError, "Expecting = after :"
|
124
|
+
end
|
125
|
+
str = InterpreterString.parse_until_unquoted(io,"\n", false)
|
126
|
+
interpreter.variables.define_variable(symbol, str,
|
127
|
+
interpreter)
|
128
|
+
break
|
129
|
+
elsif ch == '='
|
130
|
+
str = InterpreterString.parse_until_unquoted(io,"\n", false)
|
131
|
+
interpreter.variables.define_variable(symbol, str, nil)
|
132
|
+
break
|
133
|
+
else
|
134
|
+
raise UnexpectedCharacter, "Did not expect #{ch} after #{symbol}"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
protected
|
141
|
+
|
142
|
+
SYMBOL_CHAR_REGEX = /[a-zA-Z0-9_-]/
|
143
|
+
|
144
|
+
# Parses the _io_ stream up to and including the next
|
145
|
+
# symbol. Only white space or comments may be found on the
|
146
|
+
# way. This function returns the symbol.
|
147
|
+
#
|
148
|
+
# Symbols are composed of the alphabet SYMBOL_CHAR_REGEX.
|
149
|
+
def up_to_next_symbol(io)
|
150
|
+
|
151
|
+
symbol = nil # As long as no symbol as been started
|
152
|
+
# it will stay nil.
|
153
|
+
while(1)
|
154
|
+
c = io.getc
|
155
|
+
if ! c # EOF
|
156
|
+
if symbol
|
157
|
+
raise UnterminatedSymbol, "EOF reached during symbol parsing"
|
158
|
+
else
|
159
|
+
# File is finished and we didn't meet any symbol.
|
160
|
+
# Nothing to do !
|
161
|
+
return nil
|
162
|
+
end
|
163
|
+
end
|
164
|
+
ch = c.chr
|
165
|
+
if symbol # We have started
|
166
|
+
if ch =~ SYMBOL_CHAR_REGEX
|
167
|
+
symbol += ch
|
168
|
+
else
|
169
|
+
io.ungetc(c)
|
170
|
+
return symbol
|
171
|
+
end
|
172
|
+
else
|
173
|
+
if ch =~ SYMBOL_CHAR_REGEX
|
174
|
+
symbol = ch
|
175
|
+
elsif ch =~ /\s/
|
176
|
+
# Nothing
|
177
|
+
elsif ch == '#'
|
178
|
+
io.gets
|
179
|
+
else
|
180
|
+
raise UnexpectedCharacter, "Unexpected character: #{ch}, when looking for a symbol"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
@@ -16,7 +16,7 @@ require 'stringio' # For debugging purposes
|
|
16
16
|
|
17
17
|
module CTioga2
|
18
18
|
|
19
|
-
Version::register_svn_info('$Revision:
|
19
|
+
Version::register_svn_info('$Revision: 400 $', '$Date: 2013-08-19 17:29:57 +0200 (Mon, 19 Aug 2013) $')
|
20
20
|
|
21
21
|
module Commands
|
22
22
|
|
@@ -256,7 +256,7 @@ module CTioga2
|
|
256
256
|
cur_str += value
|
257
257
|
when :unquoted
|
258
258
|
tmp = value.split(re, -1)
|
259
|
-
cur_str += tmp[0]
|
259
|
+
cur_str += tmp[0] if tmp.size > 0
|
260
260
|
# Push splitted stuff here:
|
261
261
|
while tmp.size > 1
|
262
262
|
retval << cur_str
|
@@ -17,7 +17,7 @@ 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: 402 $', '$Date: 2013-08-19 17:30:02 +0200 (Mon, 19 Aug 2013) $')
|
21
21
|
|
22
22
|
module Data
|
23
23
|
|
@@ -204,7 +204,7 @@ module CTioga2
|
|
204
204
|
set_vectors(new_vects)
|
205
205
|
end
|
206
206
|
|
207
|
-
ColumnSpecsRE = /|min|max|err/i
|
207
|
+
ColumnSpecsRE = /|min|max|err|rerr/i
|
208
208
|
|
209
209
|
# This function sets the value of the DataColumn object
|
210
210
|
# according to a hash: _spec_ => _vector_. _spec_ can be any of:
|
@@ -232,6 +232,9 @@ module CTioga2
|
|
232
232
|
when /^err$/i
|
233
233
|
@min_values = @values - s[key]
|
234
234
|
@max_values = @values + s[key]
|
235
|
+
when /^rerr$/i
|
236
|
+
@min_values = @values *(1 - s[key])
|
237
|
+
@max_values = @values *(1 + s[key])
|
235
238
|
else
|
236
239
|
raise "Unkown key: #{key}"
|
237
240
|
end
|
data/lib/ctioga2/data/dataset.rb
CHANGED
@@ -18,7 +18,7 @@ require 'ctioga2/data/indexed-dtable'
|
|
18
18
|
|
19
19
|
module CTioga2
|
20
20
|
|
21
|
-
Version::register_svn_info('$Revision:
|
21
|
+
Version::register_svn_info('$Revision: 406 $', '$Date: 2013-08-22 21:23:44 +0200 (Thu, 22 Aug 2013) $')
|
22
22
|
|
23
23
|
|
24
24
|
# \todo now, port the backend infrastructure...
|
@@ -393,18 +393,8 @@ module CTioga2
|
|
393
393
|
#
|
394
394
|
# @todo add algorithm
|
395
395
|
def make_contour(level)
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
# We remove any gap corresponding to the element size,
|
400
|
-
# meaningless.
|
401
|
-
gaps -= [x.size]
|
402
|
-
n = 0.0/0.0
|
403
|
-
gaps.sort.reverse.each do |i|
|
404
|
-
x.insert(i,n)
|
405
|
-
y.insert(i,n)
|
406
|
-
end
|
407
|
-
return Dobjects::Function.new(x,y)
|
396
|
+
table = indexed_table
|
397
|
+
return table.make_contour(level, {'ret' => 'func'} )
|
408
398
|
end
|
409
399
|
|
410
400
|
# Smooths the data using a naive gaussian-like convolution (but
|
@@ -15,7 +15,7 @@ require 'ctioga2/utils'
|
|
15
15
|
|
16
16
|
module CTioga2
|
17
17
|
|
18
|
-
Version::register_svn_info('$Revision:
|
18
|
+
Version::register_svn_info('$Revision: 406 $', '$Date: 2013-08-22 21:23:44 +0200 (Thu, 22 Aug 2013) $')
|
19
19
|
|
20
20
|
|
21
21
|
module Data
|
@@ -114,19 +114,51 @@ module CTioga2
|
|
114
114
|
return @y_values.size
|
115
115
|
end
|
116
116
|
|
117
|
-
#
|
118
|
-
# t.append_points_with_gaps_to_path to show the given level.
|
117
|
+
# Makes a contour using the given level.
|
119
118
|
#
|
120
|
-
#
|
121
|
-
|
119
|
+
# Depending on the value of opts['ret'], what is returned is:
|
120
|
+
# * if 'xyg', [xs, ys, gaps] triplet suitable for use with
|
121
|
+
# t.append_points_with_gaps_to_path to show the
|
122
|
+
# given level (default)
|
123
|
+
# * if 'func', a single function with nans inserted
|
124
|
+
# at the position of the gaps
|
125
|
+
# * if 'funcs', a function for each of the "continuous" segments
|
126
|
+
#
|
127
|
+
# Anything else in opts is given directly to make_contour
|
128
|
+
def make_contour(level, opts = {})
|
122
129
|
gaps = []
|
123
130
|
# Requires Tioga r598
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
131
|
+
opts = {'data' => @table,
|
132
|
+
'xs' => @x_values,
|
133
|
+
'ys' => @y_values,
|
134
|
+
'gaps' => gaps,
|
135
|
+
'level' => level
|
136
|
+
}.update(opts)
|
137
|
+
|
138
|
+
ret = opts['ret'] || 'xyg'
|
139
|
+
|
140
|
+
opts.delete('ret')
|
141
|
+
xs, ys = *Tioga::FigureMaker.make_contour(opts)
|
142
|
+
|
143
|
+
if ret == 'xyg'
|
144
|
+
return [xs, ys, gaps]
|
145
|
+
end
|
146
|
+
|
147
|
+
gaps = opts['gaps'].dup
|
148
|
+
|
149
|
+
gaps -= [xs.size]
|
150
|
+
n = 0.0/0.0
|
151
|
+
gaps.sort.reverse.each do |i|
|
152
|
+
xs.insert(i,n)
|
153
|
+
ys.insert(i,n)
|
154
|
+
end
|
155
|
+
|
156
|
+
fnc = Dobjects::Function.new(xs,ys)
|
157
|
+
if ret == 'func'
|
158
|
+
return fnc
|
159
|
+
else
|
160
|
+
return fnc.split_on_nan(:x)
|
161
|
+
end
|
130
162
|
end
|
131
163
|
|
132
164
|
end
|
data/lib/ctioga2/data/stack.rb
CHANGED
@@ -25,7 +25,7 @@ require 'ctioga2/data/filters'
|
|
25
25
|
# This module contains all the classes used by ctioga
|
26
26
|
module CTioga2
|
27
27
|
|
28
|
-
Version::register_svn_info('$Revision:
|
28
|
+
Version::register_svn_info('$Revision: 390 $', '$Date: 2013-03-13 11:36:47 +0100 (Wed, 13 Mar 2013) $')
|
29
29
|
|
30
30
|
|
31
31
|
module Data
|
@@ -121,28 +121,54 @@ module CTioga2
|
|
121
121
|
# Returns the stored dataset, either using its index in the
|
122
122
|
# stack, or its name in the dataset.
|
123
123
|
def stored_dataset(spec)
|
124
|
+
return dataset_xref(spec)[0]
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
# Returns the [dataset, index, name] of the given dataset
|
129
|
+
def dataset_xref(spec)
|
130
|
+
ds = nil
|
131
|
+
index = nil
|
132
|
+
name = nil
|
124
133
|
if spec.is_a? Numeric or spec =~ /^\s*-?\d+\s*$/
|
125
134
|
spec = spec.to_i
|
126
|
-
|
135
|
+
index = spec
|
136
|
+
name = nil
|
137
|
+
ds = @stack[index]
|
138
|
+
for k,v in @named_datasets
|
139
|
+
if v == ds
|
140
|
+
name = k
|
141
|
+
end
|
142
|
+
end
|
127
143
|
else
|
128
144
|
if @named_datasets.key? spec
|
129
|
-
|
145
|
+
name = spec
|
146
|
+
ds = @named_datasets[spec]
|
147
|
+
i = 0
|
148
|
+
for d in @stack
|
149
|
+
if d == ds
|
150
|
+
index = i
|
151
|
+
end
|
152
|
+
i += 1
|
153
|
+
end
|
130
154
|
else
|
131
155
|
raise "Unkown named dataset from the stack: '#{spec}'"
|
132
156
|
end
|
133
157
|
end
|
158
|
+
return [ds, index, name]
|
134
159
|
end
|
135
160
|
|
136
161
|
# Gets a dataset from the given _options_ hash. If a 'which' key
|
137
162
|
# is present, it is used as an argument for #stored_dataset;
|
138
163
|
# else, -1 is used.
|
139
|
-
def specified_dataset(options)
|
164
|
+
def specified_dataset(options, full = false)
|
140
165
|
spec = if options && options['which']
|
141
166
|
options['which']
|
142
167
|
else
|
143
168
|
-1
|
144
169
|
end
|
145
|
-
|
170
|
+
xr = dataset_xref(spec)
|
171
|
+
return (full ? xr : xr[0])
|
146
172
|
end
|
147
173
|
|
148
174
|
# Adds a Dataset object onto the stack, running hooks if
|
@@ -250,11 +276,25 @@ module CTioga2
|
|
250
276
|
|
251
277
|
pref = sprintf("#%-2d %-3d:", i, - @stack.size + i)
|
252
278
|
|
253
|
-
STDERR.puts " * #{pref} #{ds.name} -- #{ds.ys.size + 1} columns #{name}"
|
279
|
+
STDERR.puts " * #{pref} #{ds.name} -- #{ds.ys.size + 1} columns, #{ds.x.size} points #{name}"
|
254
280
|
i += 1
|
255
281
|
end
|
256
282
|
end
|
257
283
|
|
284
|
+
# Drops the dataset corresponding to the given spec from the
|
285
|
+
# stack
|
286
|
+
def drop_from_stack(spec)
|
287
|
+
xr = dataset_xref(spec)
|
288
|
+
if xr[1] # But that should always be the case ?
|
289
|
+
@stack.delete_at(xr[1])
|
290
|
+
else
|
291
|
+
warn { "For some reason, dataset '#{spec}' is not in the stack !"}
|
292
|
+
end
|
293
|
+
if xr[2]
|
294
|
+
@named_datasets.delete(xr[2])
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
258
298
|
|
259
299
|
end
|
260
300
|
|
@@ -332,6 +372,23 @@ EOH
|
|
332
372
|
<<EOH, DataStackGroup)
|
333
373
|
Prints to standard output data contained in the last dataset pushed
|
334
374
|
onto the stack, or the given stored dataset if the which option is given.
|
375
|
+
EOH
|
376
|
+
|
377
|
+
|
378
|
+
DropCommand =
|
379
|
+
Cmd.new("drop", nil, "--drop",
|
380
|
+
[CmdArg.new('stored-dataset')], { }) do |plotmaker,spec,opts|
|
381
|
+
plotmaker.data_stack.drop_from_stack(spec)
|
382
|
+
end
|
383
|
+
|
384
|
+
DropCommand.describe("Drops the given dataset from the stack",
|
385
|
+
<<EOH, DataStackGroup)
|
386
|
+
Removes the given dataset from the stack.
|
387
|
+
|
388
|
+
Can become useful when dealing with large datasets, some of which are
|
389
|
+
only used as intermediates for {command: apply-formula} or
|
390
|
+
{command: compute-contour}, for instance.
|
391
|
+
|
335
392
|
EOH
|
336
393
|
|
337
394
|
ConcatLastCommand =
|
@@ -409,8 +466,8 @@ default the one before the last) into the last one. Data points that
|
|
409
466
|
have no corresponding X value in the current dataset are simply
|
410
467
|
ignored.
|
411
468
|
|
412
|
-
This can be used to build 3D datasets for {
|
413
|
-
{
|
469
|
+
This can be used to build 3D datasets for {command: xyz-map} or
|
470
|
+
{command: xy-parametric}.
|
414
471
|
EOH
|
415
472
|
|
416
473
|
XYReglinCommand =
|