ctioga2 0.13.1 → 0.14

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.
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)