ctioga2 0.13.1 → 0.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog +26 -0
  3. data/bin/ct2-make-movie +4 -1
  4. data/bin/ctioga2 +1 -1
  5. data/lib/ctioga2/commands/commands.rb +2 -0
  6. data/lib/ctioga2/commands/doc/doc.rb +1 -1
  7. data/lib/ctioga2/commands/doc/documentation-commands.rb +38 -0
  8. data/lib/ctioga2/commands/doc/html.rb +84 -0
  9. data/lib/ctioga2/commands/general-commands.rb +20 -1
  10. data/lib/ctioga2/commands/general-functions.rb +26 -0
  11. data/lib/ctioga2/commands/general-types.rb +1 -0
  12. data/lib/ctioga2/commands/instruction.rb +61 -0
  13. data/lib/ctioga2/commands/interpreter.rb +12 -2
  14. data/lib/ctioga2/data/datacolumn.rb +38 -0
  15. data/lib/ctioga2/data/dataset.rb +6 -5
  16. data/lib/ctioga2/data/filters.rb +12 -5
  17. data/lib/ctioga2/data/stack.rb +105 -22
  18. data/lib/ctioga2/graphics/elements.rb +1 -1
  19. data/lib/ctioga2/graphics/elements/curve2d.rb +1 -1
  20. data/lib/ctioga2/graphics/elements/element.rb +29 -10
  21. data/lib/ctioga2/graphics/elements/primitive.rb +26 -2
  22. data/lib/ctioga2/graphics/elements/subplot.rb +7 -1
  23. data/lib/ctioga2/graphics/generator.rb +1 -2
  24. data/lib/ctioga2/graphics/legends/area.rb +3 -0
  25. data/lib/ctioga2/graphics/root.rb +18 -2
  26. data/lib/ctioga2/graphics/styles/curve.rb +6 -0
  27. data/lib/ctioga2/graphics/styles/drawable.rb +4 -0
  28. data/lib/ctioga2/graphics/styles/factory.rb +4 -5
  29. data/lib/ctioga2/graphics/styles/plot-types.rb +22 -7
  30. data/lib/ctioga2/graphics/subplot-commands.rb +2 -4
  31. data/lib/ctioga2/graphics/types.rb +17 -0
  32. data/lib/ctioga2/graphics/types/boundaries.rb +10 -0
  33. data/lib/ctioga2/graphics/types/boxes.rb +18 -0
  34. data/lib/ctioga2/graphics/types/dimensions.rb +4 -0
  35. data/lib/ctioga2/graphics/types/grid.rb +98 -4
  36. data/lib/ctioga2/graphics/types/point.rb +9 -0
  37. data/lib/ctioga2/metabuilder/types/lists.rb +1 -1
  38. data/lib/ctioga2/metabuilder/types/styles.rb +5 -3
  39. data/lib/ctioga2/plotmaker.rb +28 -5
  40. data/lib/ctioga2/postprocess.rb +28 -0
  41. data/lib/ctioga2/ruby.rb +7 -0
  42. data/lib/ctioga2/utils.rb +45 -0
  43. data/lib/ctioga2/version.rb +2 -2
  44. metadata +4 -3
@@ -133,7 +133,13 @@ module CTioga2
133
133
  end
134
134
  for k, b in bounds
135
135
  if ! b.valid?
136
- error { "Invalid computed range, you probably have only empty datasets" }
136
+ if b.nan?
137
+ error { "Invalid computed range, you have NaNs in your data (missing data ?)" }
138
+ elsif b.infinite?
139
+ error { "Infinite computed range, you have infinite numbers in your data" }
140
+ else
141
+ error { "Invalid computed range, you probably have only empty datasets" }
142
+ end
137
143
  bounds[k] = Types::SimpleRange.new(0.0,1.0)
138
144
  end
139
145
  end
@@ -88,8 +88,7 @@ module CTioga2
88
88
  old_opts = options.dup
89
89
  # Now, we trim options unrelated to the plotting
90
90
  options.delete_if { |k,v|
91
- ! Graphics::Styles::
92
- CurveStyleFactory::PlotCommandOptions.key?(k)
91
+ ! Graphics::Styles::CurveStyleFactory::PlotCommandOptions.key?(k)
93
92
  }
94
93
 
95
94
  begin
@@ -79,6 +79,9 @@ module CTioga2
79
79
  #
80
80
  def display_legend(t, container)
81
81
  items = container.legend_storage.harvest_contents
82
+ if self.hidden
83
+ return # Not doing anything
84
+ end
82
85
  t.context do
83
86
 
84
87
  ## @todo These two commands should join LegendStyle
@@ -137,11 +137,27 @@ module CTioga2
137
137
  #
138
138
  # For the sake of convenience, returns the newly created
139
139
  # Elements::Subplot
140
- def subplot(opts)
140
+ def subplot(opts, box = nil)
141
141
  if ! @current_container
142
142
  enter_subobject(Elements::Container.new(nil, self, {}))
143
143
  end
144
- subplot = Elements::Subplot.new(@current_container, self, opts)
144
+
145
+ o = opts.dup
146
+ o["class"] ||= []
147
+
148
+ # We add automatic classes from the box
149
+ #
150
+ # Most of the time empty, for sure.
151
+ if box
152
+ o["class"] += box.classes
153
+ end
154
+
155
+ subplot = Elements::Subplot.new(@current_container, self, o)
156
+
157
+ if box
158
+ subplot.subframe = box
159
+ end
160
+
145
161
  enter_subobject(subplot)
146
162
  return subplot
147
163
  end
@@ -91,6 +91,12 @@ module CTioga2
91
91
  # A colormap for markers (only for XYZ data)
92
92
  typed_attribute :marker_color_map, 'colormap'
93
93
 
94
+ # A colormap for the line of markers (only for XYZ data)
95
+ typed_attribute :marker_line_color_map, 'colormap'
96
+
97
+ # A colormap for the fill color of markers (only for XYZ data)
98
+ typed_attribute :marker_fill_color_map, 'colormap'
99
+
94
100
  # If this is specified when choosing the marker scale as a
95
101
  # function of a given Z value, then the original Z segment is
96
102
  # mapped to min_scale -> scale.
@@ -50,10 +50,14 @@ module CTioga2
50
50
  class StrokeStyle < LineStyle
51
51
  # The color
52
52
  typed_attribute :color, 'color-or-false'
53
+
54
+ # The line cap
55
+ typed_attribute :cap, 'line-cap'
53
56
 
54
57
  # Sets the stroke style to a FigureMaker object, _t_.
55
58
  def set_stroke_style(t)
56
59
  t.stroke_color = @color if @color
60
+ t.line_cap = @cap if @cap
57
61
  super
58
62
  end
59
63
 
@@ -353,6 +353,8 @@ module CTioga2
353
353
 
354
354
  simple_parameter 'line_style', 'line style', Sets::LineStyleSets
355
355
 
356
+ simple_parameter 'line_cap', 'line cap', nil
357
+
356
358
  # Markers
357
359
  simple_parameter 'marker', 'marker', Sets::MarkerSets, '-m'
358
360
 
@@ -409,12 +411,9 @@ module CTioga2
409
411
 
410
412
  simple_parameter 'zaxis', "name for the Z axis"
411
413
 
412
- ## @todo For xy-parametric, there should be a way to specify
413
- ## to which z value the maps apply (ie lines = y2, marker =
414
- ## y3...). Although for readability, it is probably better
415
- ## to avoid that...
416
414
  simple_parameter 'marker_color_map', 'color map for markers'
417
-
415
+ simple_parameter 'marker_line_color_map', 'color map for the lines of markers'
416
+ simple_parameter 'marker_fill_color_map', 'color map for the lines of markers'
418
417
  simple_parameter 'split_on_nan', 'split on NaN'
419
418
 
420
419
 
@@ -1,3 +1,4 @@
1
+ # coding: utf-8
1
2
  # contour.rb: the style of a contour plot
2
3
  # copyright (c) 2009 by Vincent Fourmond
3
4
 
@@ -24,6 +25,8 @@ module CTioga2
24
25
 
25
26
  StyleAspectRE = {
26
27
  /^marker[_-]color$/i => :marker_color,
28
+ /^marker[_-]fill[_-]color$/i => :marker_fill_color,
29
+ /^marker[_-]line[_-]color$/i => :marker_line_color,
27
30
  /^marker[_-](size|scale)$/i => :marker_scale,
28
31
  }
29
32
 
@@ -48,6 +51,12 @@ EOD
48
51
  # What is the z2 axis
49
52
  typed_attribute :z2, 'style-aspect'
50
53
 
54
+ # What is the z3 axis
55
+ typed_attribute :z3, 'style-aspect'
56
+
57
+ # What is the z4 axis
58
+ typed_attribute :z4, 'style-aspect'
59
+
51
60
  def initialize
52
61
  @z1 = :marker_color
53
62
  end
@@ -55,7 +64,7 @@ EOD
55
64
  def prepare
56
65
  @reversed = {}
57
66
 
58
- 2.times do |i|
67
+ 4.times do |i|
59
68
  val = self.send("z#{i+1}")
60
69
  if val
61
70
  @reversed[val] = i
@@ -106,12 +115,18 @@ EOD
106
115
 
107
116
  end
108
117
 
109
- if @reversed[:marker_color]
110
- idx = @reversed[:marker_color]
111
- if idx < zvalue.size
112
- style.color = curve_style.marker_color_map.z_color(zvalue[idx],
113
- zmin[idx],
114
- zmax[idx])
118
+ for bs in [:color, :line_color, :fill_color]
119
+ stl = "marker_#{bs}".to_sym
120
+ if @reversed[stl]
121
+ idx = @reversed[stl]
122
+ if idx < zvalue.size
123
+ map = curve_style.send("#{stl}_map")
124
+ if map
125
+ style.send("#{bs}=",map.z_color(zvalue[idx],
126
+ zmin[idx],
127
+ zmax[idx]))
128
+ end
129
+ end
115
130
  end
116
131
  end
117
132
 
@@ -135,8 +135,7 @@ EOD
135
135
  CmdArg.new('box'),
136
136
  ], Elements::TiogaElement::StyleBaseOptions) do |plotmaker, box, opts|
137
137
  Log::debug { "Starting a subplot with specs #{box.inspect}" }
138
- subplot = plotmaker.root_object.subplot(opts)
139
- subplot.subframe = box
138
+ subplot = plotmaker.root_object.subplot(opts, box)
140
139
  end
141
140
 
142
141
  InsetCommand.describe('Begins a new inset',
@@ -153,8 +152,7 @@ EOD
153
152
  CmdArg.new('box'),
154
153
  ], Elements::TiogaElement::StyleBaseOptions) do |plotmaker, box,opts|
155
154
  plotmaker.root_object.leave_subobject
156
- subplot = plotmaker.root_object.subplot(opts)
157
- subplot.subframe = box
155
+ subplot = plotmaker.root_object.subplot(opts, box)
158
156
  end
159
157
 
160
158
  NextInsetCommand.describe('Ends the previous inset and begins a new one',
@@ -102,6 +102,23 @@ a series of comma-separated numbers which are the length of the
102
102
  strokes and gaps, or @no@, @none@ or @off@ to mean no line.
103
103
  EOD
104
104
 
105
+ LineCapType =
106
+ CmdType.new('line-cap', {
107
+ :type => :list,
108
+ :list => {},
109
+ :shortcuts => {
110
+ 'butt' => Tioga::FigureConstants::LINE_CAP_BUTT,
111
+ 'round' => Tioga::FigureConstants::LINE_CAP_ROUND,
112
+ 'square' => Tioga::FigureConstants::LINE_CAP_SQUARE,
113
+ }
114
+ }, <<EOD)
115
+ A line cap style, i.e. how the line extends beyond its last point.
116
+ Available choices:
117
+ * @round@ (extends as a half circle default)
118
+ * @butt@ (does not extend at all)
119
+ * @square@ (extends as a half square)
120
+ EOD
121
+
105
122
  MarkerType =
106
123
  CmdType.new('marker', {
107
124
  :type => :tioga_marker,
@@ -51,6 +51,16 @@ module CTioga2
51
51
  Utils::finite_number?(@last))
52
52
  end
53
53
 
54
+ def nan?
55
+ return (Utils::nan_number?(@first) or
56
+ Utils::nan_number?(@last))
57
+ end
58
+
59
+ def infinite?
60
+ return (Utils::infinite_number?(@first) or
61
+ Utils::infinite_number?(@last))
62
+ end
63
+
54
64
  # Minimum value
55
65
  def min
56
66
  @first < @last ? @first : @last
@@ -44,6 +44,24 @@ module CTioga2
44
44
  xl, yt, xr, yb = self.to_frame_coordinates(t)
45
45
  return [xl, 1 - xr, 1 - yt, yb]
46
46
  end
47
+
48
+ # Runs the block within the context of the box.
49
+ def within_frames(t, frame_coords = true)
50
+ t.context do
51
+ t.subfigure(self.to_frame_margins(t)) do
52
+ if frame_coords
53
+ t.set_bounds([0, 1, 1, 0])
54
+ end
55
+ yield
56
+ end
57
+ end
58
+ end
59
+
60
+ # The classes enumerated here get added to the class list of
61
+ # the subwindow
62
+ def classes
63
+ return []
64
+ end
47
65
 
48
66
  end
49
67
 
@@ -77,6 +77,10 @@ module CTioga2
77
77
  return Dimension.new(@type, -@value, @orientation)
78
78
  end
79
79
 
80
+ def *(fct)
81
+ return Dimension.new(@type, @value*fct, @orientation)
82
+ end
83
+
80
84
  # Returns a dimension corresponding to the distance.
81
85
  def self.get_distance(t, dx, dy)
82
86
  dx = make_dimension(dx, :x).to_bp(t)
@@ -31,7 +31,7 @@ module CTioga2
31
31
 
32
32
  OptionHashRE = /([\w-]+)\s*=\s*([^,]+),?\s*/
33
33
 
34
- GridBoxRE = /^\s*grid:(\d+(?:-\d+)?)\s*,\s*(\d+(?:-\d+)?)(?:,(#{OptionHashRE}+))?\s*$/
34
+ GridBoxRE = /^\s*grid:(?:(\d+(?:-\d+)?)\s*,\s*(\d+(?:-\d+)?)|(next))(?:,(#{OptionHashRE}+))?\s*$/
35
35
 
36
36
  # This hash helps to convert from a hash-based representation
37
37
  # of frame coordinates to the array-based one.
@@ -44,11 +44,31 @@ module CTioga2
44
44
  'yb' => 3
45
45
  }
46
46
 
47
+ # The position of the element in the grid (arrays [left,right]
48
+ # or [top, bottom])
49
+ attr_accessor :x,:y
50
+
47
51
  def self.from_text(txt)
48
52
  if txt =~ GridBoxRE
49
- return GridBox.new(GridLayout.current_grid, $1, $2,
50
- $3) # The latter being to remove
51
- # the initial comma
53
+ if $3 # next
54
+ x = 0
55
+ y = 0
56
+ grd = GridLayout.current_grid
57
+ lastel = grd.elements.last
58
+ if lastel
59
+ x = lastel.x.max + 1
60
+ y = lastel.y.max
61
+ if x >= grd.xsize
62
+ x = 0
63
+ y += 1
64
+ end
65
+ end
66
+ return GridBox.new(grd, x, y, $4)
67
+ else
68
+ return GridBox.new(GridLayout.current_grid, $1, $2,
69
+ $4) # The latter being to remove
70
+ # the initial comma
71
+ end
52
72
  else
53
73
  raise "#{txt} is not a grid box."
54
74
  end
@@ -63,6 +83,19 @@ module CTioga2
63
83
  return [str.to_i, str.to_i]
64
84
  end
65
85
  end
86
+
87
+ # Returns false if the position given by @x and @y are within
88
+ # the grid
89
+ def within_grid?
90
+ if @x.min < 0 || @x.max >= @grid.xsize
91
+ return false
92
+ end
93
+ if @y.min < 0 || @y.max >= @grid.ysize
94
+ return false
95
+ end
96
+ return true
97
+ end
98
+
66
99
 
67
100
  def initialize(grid, x, y, options = {})
68
101
  if options.is_a? String
@@ -83,6 +116,12 @@ module CTioga2
83
116
  @x = parse_range(x).sort
84
117
  @y = parse_range(y).sort
85
118
  @overrides = options || {}
119
+
120
+ if ! within_grid?
121
+ raise "Grid element #{x},#{y} is outside grid boundaries (#{@grid.xsize}x#{@grid.ysize})"
122
+ end
123
+
124
+ @grid.elements << self
86
125
  end
87
126
 
88
127
  def to_frame_coordinates(t)
@@ -99,6 +138,48 @@ module CTioga2
99
138
  end
100
139
  return a
101
140
  end
141
+
142
+ def classes
143
+ rv = []
144
+ hsh = {
145
+ 'left' => @x.min == 0,
146
+ 'right' => @x.max + 1 == @grid.xsize,
147
+ 'top' => @y.min == 0,
148
+ 'bottom' => @y.max + 1 == @grid.ysize
149
+ }
150
+ for k, v in hsh
151
+ if v
152
+ rv << "grid-#{k}"
153
+ else
154
+ rv << "grid-non-#{k}"
155
+ end
156
+ end
157
+
158
+ xv = nil
159
+ yv = nil
160
+ if @x.min == @x.max
161
+ xv = @x.min
162
+ rv << "grid-column-#{xv}"
163
+ if xv.even?
164
+ rv << "grid-even-column"
165
+ else
166
+ rv << "grid-odd-column"
167
+ end
168
+ end
169
+ if @y.min == @y.max
170
+ yv = @y.min
171
+ rv << "grid-row-#{yv}"
172
+ if yv.even?
173
+ rv << "grid-even-row"
174
+ else
175
+ rv << "grid-odd-row"
176
+ end
177
+ end
178
+ if xv && yv
179
+ rv << "grid-#{xv}-#{yv}"
180
+ end
181
+ return rv
182
+ end
102
183
  end
103
184
 
104
185
  # This class provides a grid-like layout through the use of a grid
@@ -125,6 +206,9 @@ module CTioga2
125
206
  # Vertical scales
126
207
  attr_accessor :vscales
127
208
 
209
+ # The GridBox objects we've seen so far
210
+ attr_accessor :elements
211
+
128
212
  def initialize(nup = "2x2")
129
213
  if nup.respond_to?(:split)
130
214
  if nup =~ /,/
@@ -156,6 +240,8 @@ module CTioga2
156
240
 
157
241
  @hscales ||= [1] * @nup[0]
158
242
  @vscales ||= [1] * @nup[1]
243
+
244
+ @elements = []
159
245
  end
160
246
 
161
247
  # The grid currently in use.
@@ -169,6 +255,14 @@ module CTioga2
169
255
  return @current_grid
170
256
  end
171
257
 
258
+ def xsize
259
+ return @hscales.size
260
+ end
261
+
262
+ def ysize
263
+ return @vscales.size
264
+ end
265
+
172
266
  # Compute the frame coordinates fo the x,y element of the
173
267
  # grid. They are numbered from the top,left element.
174
268
  def frame_coordinates(t, x, y)
@@ -216,6 +216,15 @@ module CTioga2
216
216
  @valign = valign
217
217
  end
218
218
 
219
+ def self.from_point(pt, halign = :center, valign = :center)
220
+ a = AlignedPoint.new
221
+ a.x = pt.x
222
+ a.y = pt.y
223
+ a.halign = halign
224
+ a.valign = valign
225
+ return a
226
+ end
227
+
219
228
  # Returns frame coordinates corresponding to the point, the
220
229
  # alignment and the given size in figure coordinates
221
230
  def to_frame_coordinates(t, width, height)