ctioga2 0.4 → 0.5
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/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 =
|