ctioga2 0.4 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/Changelog +16 -0
  2. data/lib/ctioga2/commands/arguments.rb +5 -2
  3. data/lib/ctioga2/commands/commands.rb +45 -13
  4. data/lib/ctioga2/commands/context.rb +9 -1
  5. data/lib/ctioga2/commands/doc/help.rb +2 -2
  6. data/lib/ctioga2/commands/doc/html.rb +8 -8
  7. data/lib/ctioga2/commands/doc/introspection.rb +7 -5
  8. data/lib/ctioga2/commands/parsers/file.rb +123 -120
  9. data/lib/ctioga2/commands/parsers/old-file.rb +191 -0
  10. data/lib/ctioga2/commands/strings.rb +2 -2
  11. data/lib/ctioga2/data/datacolumn.rb +5 -2
  12. data/lib/ctioga2/data/dataset.rb +3 -13
  13. data/lib/ctioga2/data/indexed-dtable.rb +43 -11
  14. data/lib/ctioga2/data/stack.rb +65 -8
  15. data/lib/ctioga2/graphics/elements.rb +2 -1
  16. data/lib/ctioga2/graphics/elements/containers.rb +22 -3
  17. data/lib/ctioga2/graphics/elements/primitive.rb +5 -5
  18. data/lib/ctioga2/graphics/elements/xyz-contour.rb +123 -0
  19. data/lib/ctioga2/graphics/generator.rb +31 -5
  20. data/lib/ctioga2/graphics/legends.rb +44 -3
  21. data/lib/ctioga2/graphics/legends/area.rb +28 -9
  22. data/lib/ctioga2/graphics/legends/items.rb +34 -23
  23. data/lib/ctioga2/graphics/legends/multicols.rb +132 -0
  24. data/lib/ctioga2/graphics/styles.rb +3 -1
  25. data/lib/ctioga2/graphics/styles/axes.rb +10 -4
  26. data/lib/ctioga2/graphics/styles/base.rb +65 -11
  27. data/lib/ctioga2/graphics/styles/colormap.rb +2 -1
  28. data/lib/ctioga2/graphics/styles/contour.rb +141 -0
  29. data/lib/ctioga2/graphics/styles/curve.rb +49 -67
  30. data/lib/ctioga2/graphics/styles/drawable.rb +17 -8
  31. data/lib/ctioga2/graphics/styles/factory.rb +79 -38
  32. data/lib/ctioga2/graphics/styles/legend.rb +49 -6
  33. data/lib/ctioga2/graphics/styles/plot.rb +10 -9
  34. data/lib/ctioga2/graphics/styles/sheet.rb +11 -11
  35. data/lib/ctioga2/graphics/styles/texts.rb +38 -9
  36. data/lib/ctioga2/graphics/types.rb +20 -1
  37. data/lib/ctioga2/graphics/types/dimensions.rb +7 -1
  38. data/lib/ctioga2/metabuilder/types/lists.rb +4 -4
  39. data/lib/ctioga2/metabuilder/types/numbers.rb +3 -3
  40. data/lib/ctioga2/metabuilder/types/styles.rb +2 -2
  41. data/lib/ctioga2/plotmaker.rb +12 -1
  42. data/lib/ctioga2/utils.rb +27 -3
  43. 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: 2 $', '$Date: 2009-04-25 14:03:30 +0200 (Sat, 25 Apr 2009) $')
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: 229 $', '$Date: 2011-01-17 17:34:57 +0100 (Mon, 17 Jan 2011) $')
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
@@ -18,7 +18,7 @@ require 'ctioga2/data/indexed-dtable'
18
18
 
19
19
  module CTioga2
20
20
 
21
- Version::register_svn_info('$Revision: 304 $', '$Date: 2012-01-03 15:06:33 +0100 (Tue, 03 Jan 2012) $')
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
- dtable = indexed_table
397
- x,y,gaps = *dtable.make_contour(level)
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: 181 $', '$Date: 2010-10-27 15:18:35 +0200 (Wed, 27 Oct 2010) $')
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
- # Returns a [xs, ys, gaps] triplet suitable for use with
118
- # t.append_points_with_gaps_to_path to show the given level.
117
+ # Makes a contour using the given level.
119
118
  #
120
- # @todo add algorithm choice too
121
- def make_contour(level)
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
- xs, ys = *Tioga::FigureMaker.make_contour('data' => @table,
125
- 'xs' => @x_values,
126
- 'ys' => @y_values,
127
- 'gaps' => gaps,
128
- 'level' => level)
129
- return [xs, ys, gaps]
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
@@ -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: 367 $', '$Date: 2012-12-28 16:14:52 +0100 (Fri, 28 Dec 2012) $')
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
- return @stack[spec]
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
- return @named_datasets[spec]
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
- return stored_dataset(spec)
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 {cmd: xyz-map} or
413
- {cmd: xy-parametric}.
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 =