ctioga2 0.10.1 → 0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/Changelog +18 -0
  3. data/bin/ctioga2 +28 -0
  4. data/lib/ctioga2/commands/commands.rb +1 -0
  5. data/lib/ctioga2/commands/doc/documentation-commands.rb +13 -0
  6. data/lib/ctioga2/commands/doc/help.rb +3 -2
  7. data/lib/ctioga2/commands/doc/html.rb +48 -0
  8. data/lib/ctioga2/commands/doc/introspection.rb +2 -2
  9. data/lib/ctioga2/commands/general-types.rb +10 -0
  10. data/lib/ctioga2/commands/parsers/file.rb +23 -2
  11. data/lib/ctioga2/data/backends/backends.rb +1 -2
  12. data/lib/ctioga2/data/backends/backends/smath.rb +129 -0
  13. data/lib/ctioga2/data/backends/backends/text.rb +1 -0
  14. data/lib/ctioga2/data/dataset.rb +1 -1
  15. data/lib/ctioga2/data/stack.rb +13 -3
  16. data/lib/ctioga2/graphics/elements.rb +2 -0
  17. data/lib/ctioga2/graphics/elements/containers.rb +3 -1
  18. data/lib/ctioga2/graphics/elements/element.rb +194 -5
  19. data/lib/ctioga2/graphics/elements/gradient-region.rb +5 -2
  20. data/lib/ctioga2/graphics/elements/histogram.rb +7 -2
  21. data/lib/ctioga2/graphics/elements/plot-elements.rb +88 -0
  22. data/lib/ctioga2/graphics/elements/primitive.rb +28 -12
  23. data/lib/ctioga2/graphics/elements/region.rb +6 -1
  24. data/lib/ctioga2/graphics/elements/style-lists.rb +2 -2
  25. data/lib/ctioga2/graphics/elements/subplot.rb +3 -3
  26. data/lib/ctioga2/graphics/elements/tangent.rb +5 -8
  27. data/lib/ctioga2/graphics/generator.rb +10 -0
  28. data/lib/ctioga2/graphics/geometry.rb +96 -0
  29. data/lib/ctioga2/graphics/legends.rb +4 -2
  30. data/lib/ctioga2/graphics/legends/area.rb +12 -4
  31. data/lib/ctioga2/graphics/root.rb +16 -14
  32. data/lib/ctioga2/graphics/styles.rb +5 -2
  33. data/lib/ctioga2/graphics/styles/arrows.rb +5 -0
  34. data/lib/ctioga2/graphics/styles/axes.rb +1 -1
  35. data/lib/ctioga2/graphics/styles/base.rb +95 -14
  36. data/lib/ctioga2/graphics/styles/curve.rb +8 -0
  37. data/lib/ctioga2/graphics/styles/drawable.rb +35 -48
  38. data/lib/ctioga2/graphics/styles/factory.rb +23 -23
  39. data/lib/ctioga2/graphics/styles/fill.rb +268 -0
  40. data/lib/ctioga2/graphics/styles/plot.rb +90 -46
  41. data/lib/ctioga2/graphics/styles/sets.rb +3 -0
  42. data/lib/ctioga2/graphics/styles/{sheet.rb → styles.rb} +70 -160
  43. data/lib/ctioga2/graphics/styles/stylesheet.rb +355 -0
  44. data/lib/ctioga2/graphics/styles/texts.rb +4 -2
  45. data/lib/ctioga2/graphics/styles/ticks.rb +44 -4
  46. data/lib/ctioga2/graphics/subplot-commands.rb +84 -9
  47. data/lib/ctioga2/graphics/types.rb +1 -1
  48. data/lib/ctioga2/graphics/types/dimensions.rb +40 -0
  49. data/lib/ctioga2/graphics/types/grid.rb +21 -5
  50. data/lib/ctioga2/graphics/types/point.rb +2 -1
  51. data/lib/ctioga2/log.rb +5 -1
  52. data/lib/ctioga2/metabuilder/types/styles.rb +11 -7
  53. data/lib/ctioga2/plotmaker.rb +2 -0
  54. data/lib/ctioga2/utils.rb +21 -6
  55. data/lib/ctioga2/version.rb +2 -2
  56. metadata +105 -108
@@ -15,6 +15,7 @@ require 'ctioga2/utils'
15
15
  require 'ctioga2/log'
16
16
 
17
17
  require 'ctioga2/graphics/coordinates'
18
+ require 'ctioga2/graphics/elements/element'
18
19
 
19
20
  # This module contains all the classes used by ctioga
20
21
  module CTioga2
@@ -85,40 +86,52 @@ module CTioga2
85
86
  attr_accessor :frame_real_size
86
87
 
87
88
 
89
+ # The target plot (ie the parent of all the small elements)
90
+ attr_accessor :target_plot
91
+
88
92
  @@current_index = 0
89
93
 
90
- def initialize
94
+ def initialize(plt)
91
95
  # Default style for the plots.
96
+ @target_plot = plt
97
+
92
98
  @axes = {}
93
- @axes[:left] =
94
- StyleSheet.style_for(AxisStyle, 'left', :left,
95
- AXIS_WITH_TICKS_AND_NUMERIC_LABELS,
96
- '$y$')
97
- @axes[:bottom] =
98
- StyleSheet.style_for(AxisStyle, 'bottom', :bottom,
99
- AXIS_WITH_TICKS_AND_NUMERIC_LABELS,
100
- '$x$')
101
-
102
- @axes[:right] =
103
- StyleSheet.style_for(AxisStyle, 'right', :right,
104
- AXIS_WITH_TICKS_ONLY)
105
- @axes[:top] =
106
- StyleSheet.style_for(AxisStyle, 'top', :top,
107
- AXIS_WITH_TICKS_ONLY)
99
+ for ax in [:left, :right, :top, :bottom]
100
+
101
+ cls = [ax.to_s]
102
+ cls << if (ax == :bottom or ax == :top)
103
+ 'x'
104
+ else
105
+ 'y'
106
+ end
107
+ dec = if (ax == :bottom or ax == :left)
108
+ AXIS_WITH_TICKS_AND_NUMERIC_LABELS
109
+ else
110
+ AXIS_WITH_TICKS_ONLY
111
+ end
112
+ label = nil
113
+ if ax == :bottom
114
+ label = '$x$'
115
+ elsif ax == :left
116
+ label = '$y$'
117
+ end
118
+
119
+ axis = Elements::AxisElement.new
120
+ axis.setup_style(@target_plot, {'class' => cls})
121
+ axis.initialize_style(ax, dec, label)
122
+ @axes[ax] = axis
123
+ end
108
124
 
109
125
  @xaxis_location = :bottom
110
126
  @yaxis_location = :left
111
127
 
112
- @title =
113
- StyleSheet.style_for(TextLabel, 'title',
114
- nil,
115
- Types::PlotLocation.new(:top))
128
+ @title = Elements::TitleElement.new(@target_plot, {})
129
+
116
130
  @plot_margin = nil
117
131
 
118
132
  @transforms = CoordinateTransforms.new
119
133
 
120
- @background =
121
- StyleSheet.style_for(BackgroundStyle, 'background')
134
+ @background = Elements::BackgroundElement.new(@target_plot, {})
122
135
 
123
136
  # A padding of 6bp ? Why ?? Why not ?
124
137
  @padding = Types::Dimension.new(:bp, 6)
@@ -152,12 +165,12 @@ module CTioga2
152
165
  def set_log_scale(which, val)
153
166
  case which
154
167
  when :x
155
- @axes[:top].log = val
156
- @axes[:bottom].log = val
168
+ @axes[:top].style.log = val
169
+ @axes[:bottom].style.log = val
157
170
  @transforms.x_log = val
158
171
  when :y
159
- @axes[:left].log = val
160
- @axes[:right].log = val
172
+ @axes[:left].style.log = val
173
+ @axes[:right].style.log = val
161
174
  @transforms.y_log = val
162
175
  else
163
176
  raise "Unknown axis: #{which.inspect}"
@@ -186,12 +199,12 @@ module CTioga2
186
199
  # \todo Maybe x2 and y2 could be provided to signify "the side
187
200
  # which isn't the default" ?
188
201
  def get_axis_style(name)
189
- style = @axes[get_axis_key(name)]
190
- if ! style
202
+ axis = @axes[get_axis_key(name)]
203
+ if ! axis
191
204
  ## @todo Type-safe exception here
192
205
  raise "Unkown named axis: '#{name}'"
193
206
  else
194
- return style
207
+ return axis.style
195
208
  end
196
209
  end
197
210
 
@@ -206,9 +219,9 @@ module CTioga2
206
219
  end
207
220
  end
208
221
 
209
- def set_axis_style(name, style)
222
+ def set_axis(name, axis)
210
223
  key = get_axis_key(name)
211
- @axes[key] = style
224
+ @axes[key] = axis
212
225
  end
213
226
 
214
227
 
@@ -223,7 +236,7 @@ module CTioga2
223
236
  # ticks are implied.
224
237
  def get_label_style(location)
225
238
  if location =~ /^\s*title\s*$/
226
- return @title
239
+ return @title.style
227
240
  end
228
241
  location =~ /^\s*(.*?)(?:_(ticks?|label))?\s*$/i
229
242
  which = $2
@@ -255,22 +268,22 @@ module CTioga2
255
268
  for which, axis in @axes
256
269
  t.context do
257
270
  begin
258
- axis.set_bounds_for_axis(t, bounds[which])
259
- axis.draw_axis(t, @text_sizes)
271
+ axis.style.set_bounds_for_axis(t, bounds[which])
272
+ axis.style.draw_axis(t, @text_sizes)
260
273
  rescue Exception => e
261
274
  error { "Impossible to draw axis #{which}: #{e.message}" }
262
- debug { "Full message: #{e.inspect}\n#{e.backtrace.join("\n")}" }
275
+ info { "Full message: #{e.inspect}\n#{e.backtrace.join("\n")}" }
263
276
  end
264
277
  end
265
278
  end
266
279
  # We draw the title last
267
- title.draw(t, 'title', "title-#{@text_size_index}")
280
+ title.style.draw(t, 'title', "title-#{@text_size_index}")
268
281
  end
269
282
 
270
283
  # Draws all axes background lines for the plot.
271
284
  def draw_all_background_lines(t)
272
285
  for which, axis in @axes
273
- axis.draw_background_lines(t)
286
+ axis.style.draw_background_lines(t)
274
287
  end
275
288
  end
276
289
 
@@ -305,10 +318,10 @@ module CTioga2
305
318
  def estimate_margins(t)
306
319
  margins = [:left, :right, :top, :bottom].map do |side|
307
320
  exts = axes_for_side(side).map do |ax|
308
- ax.extension(t,self)
321
+ ax.style.extension(t, self)
309
322
  end
310
- if @title.loc.is_side?(side)
311
- exts << @title.label_extension(t, 'title', @title.loc) *
323
+ if @title.style.loc.is_side?(side)
324
+ exts << @title.style.label_extension(t, 'title', @title.style.loc) *
312
325
  (@text_scale || 1)
313
326
  end
314
327
  Types::Dimension.new(:dy, exts.max || 0)
@@ -374,7 +387,7 @@ module CTioga2
374
387
  def axes_for_side(side)
375
388
  ret = []
376
389
  for k,v in @axes
377
- ret << v if v.location.is_side?(side)
390
+ ret << v if v.style.location.is_side?(side)
378
391
  end
379
392
  return ret
380
393
  end
@@ -548,6 +561,35 @@ EOH
548
561
  Sets the color of the background lines for the given axis.
549
562
  EOH
550
563
 
564
+ BackgroundGridCommand =
565
+ Cmd.new('background-grid', nil, '--background-grid',
566
+ [
567
+ CmdArg.new('color-or-false')
568
+ ],
569
+ StrokeStyle.options_hash().without('color')
570
+ ) do |plotmaker, color, options|
571
+ for which in [:left, :bottom]
572
+ axis = AxisStyle.current_axis_style(plotmaker, which)
573
+ if color
574
+ style = {'color' => color}
575
+ style.merge!(options)
576
+ if axis.background_lines
577
+ axis.background_lines.set_from_hash(style)
578
+ else
579
+ axis.background_lines = StrokeStyle.from_hash(style)
580
+ end
581
+ else
582
+ axis.background_lines = false
583
+ end
584
+ end
585
+ end
586
+
587
+ BackgroundGridCommand.
588
+ describe("Sets the color of the background lines",
589
+ <<"EOH", AxisGroup)
590
+ Shortcut to set the color for the left and bottom axes
591
+ EOH
592
+
551
593
 
552
594
  %w{x y}.each do |axis|
553
595
  labelcmd = Cmd.new("#{axis}label", "-#{axis}",
@@ -651,11 +693,13 @@ EOH
651
693
  Cmd.new('new-zaxis', nil, '--new-zaxis',
652
694
  [
653
695
  CmdArg.new('text')
654
- ],ZAxisStyle) do |plotmaker, name, options|
655
- axis = Styles::MapAxisStyle.new
656
- PlotStyle.current_plot_style(plotmaker).
657
- set_axis_style(name, axis)
658
- axis.set_from_hash(options)
696
+ ], ZAxisStyle.merge(Elements::TiogaElement::StyleBaseOptions)
697
+ ) do |plotmaker, name, options|
698
+
699
+ cps = PlotStyle.current_plot_style(plotmaker)
700
+ axis = Elements::MapAxisElement.new(cps.target_plot, options)
701
+ cps.set_axis(name, axis)
702
+ axis.style.set_from_hash(options)
659
703
  end
660
704
 
661
705
  NewZAxisCommand.
@@ -91,6 +91,9 @@ module CTioga2
91
91
  MarkerSets[k] = lst
92
92
  end
93
93
 
94
+ MarkerSets["alternate"] = MarkerSets["default"].
95
+ zip(MarkerSets["open"]).flatten(1)
96
+
94
97
  LineWidthSets = {
95
98
  'default' => [1.0]
96
99
  }
@@ -1,5 +1,5 @@
1
- # sheet.rb: handling of style sheets
2
- # copyright (c) 2012 by Vincent Fourmond
1
+ # styles.rb: commands for setting styles
2
+ # copyright (c) 2014 by Vincent Fourmond
3
3
 
4
4
  # This program is free software; you can redistribute it and/or modify
5
5
  # it under the terms of the GNU General Public License as published by
@@ -23,181 +23,42 @@ module CTioga2
23
23
 
24
24
  module Styles
25
25
 
26
- # This is a style sheet, is a storage place for style
27
- # objects. It has two related functions:
28
- # * first, store the user-specified preferences
29
- # * second, provide the appropriate default style for any given
30
- # object, most probably at construction time (although that
31
- # may get hard some times)
32
- #
33
- # The style are cascading and scoped. A scope should begin in
34
- # each plot.
35
- #
36
- # Cascades happen in two ways:
37
- #
38
- # * more specific styles inherit from less specific (axis ->
39
- # yaxis -> left)
40
- # * children style inherit from parent style
41
- class StyleSheet
42
-
43
- # The parent of the style sheet, or nil if this is the top one.
44
- attr_accessor :parent
45
-
46
- # The styles, in form of a style class -> style name -> style
47
- # object nested hash
48
- #
49
- # The style object is actually a hash ready to be fed to the
50
- # BasicStyle#set_from_hash
51
- attr_accessor :own_styles
52
-
53
- def initialize(par = nil)
54
- @parent = par
55
- @own_styles = {}
56
- end
57
-
58
- # This hash contains the parent style for each of the style
59
- # listed in
60
- #
61
- # Keyed by class -> style name -> parent name
62
- @style_parent = {}
63
-
64
- # Sets the parent for the given style
65
- def self.set_parent(cls, style, parent)
66
- @style_parent[cls] ||= {}
67
- @style_parent[cls][style] = parent
68
- end
69
-
70
- # Returns the parent style for the style (or _nil_ should the
71
- # style have no parent)
72
- #
73
- # All styles (but base) derive from the corresponding "base"
74
- # style.
75
- def self.get_parent(cls, style)
76
- @style_parent[cls] ||= {}
77
- stl = @style_parent[cls][style]
78
- if (! stl) and (! (style == 'base'))
79
- return 'base'
80
- end
81
- return stl
82
- end
83
-
84
- set_parent AxisStyle, "x", "base"
85
- set_parent AxisStyle, "y", "base"
86
-
87
- set_parent AxisStyle, "bottom", "x"
88
- set_parent AxisStyle, "top", "x"
89
- set_parent AxisStyle, "left", "y"
90
- set_parent AxisStyle, "right", "y"
91
-
92
-
93
- # This returns the style we have in this object for the given
94
- # name. Inner cascading should take place (ie object
95
- # hierarchy, but not scope hierarchy).
96
- #
97
- # This returns a hash that can be modified.
98
- def own_style_hash_for(cls, name)
99
- p = self.class.get_parent(cls, name)
100
- base = {}
101
- if p
102
- base = own_style_hash_for(cls, p)
103
- end
104
- @own_styles[cls] ||= {}
105
- style = @own_styles[cls][name]
106
- if ! style
107
- return base
108
- end
109
- style = style.dup
110
- style.merge!(base) { |key, v1, v2| v1 }
111
- return style
112
- end
113
-
114
- # The style for the given name, including all cascading
115
- def get_style_hash_for(cls, name)
116
- ps = {}
117
- if @parent
118
- ps = @parent.get_style_hash_for(cls, name);
119
- end
120
- style = own_style_hash_for(cls, name)
121
- style.merge!(ps) { |key, v1, v2| v1 }
122
- return style
123
- end
124
-
125
-
126
-
127
- # The current sheet
128
- @sheet = StyleSheet.new
129
-
130
- # Returns a suitable style object for the given style name, or
131
- # crashes if the name isn't known.
132
- #
133
- # Additional arguments are passed to the constructor
134
- def self.style_for(cls, name, *args)
135
- a = cls.new(*args)
136
- a.set_from_hash(@sheet.get_style_hash_for(cls, name))
137
- return a
138
- end
139
-
140
- def self.enter_scope()
141
- @sheet = StyleSheet.new(@sheet)
142
- end
143
-
144
- def self.leave_scope()
145
- if @sheet.parent
146
- @sheet = @sheet.parent
147
- else
148
- warn { "Trying to leave top-level stylesheet scope" }
149
- end
150
- end
151
-
152
- def self.current_sheet()
153
- return @sheet
154
- end
155
-
156
-
157
- # Updates the style sheet concerning the _what_ of class _cls_
158
- # with the given values
159
- def self.update_style(cls, what, values)
160
- StyleSheet.current_sheet.own_styles[cls] ||= {}
161
- StyleSheet.current_sheet.own_styles[cls][what] ||= {}
162
- StyleSheet.current_sheet.own_styles[cls][what].merge!(values)
163
- end
164
-
165
- end
166
-
167
26
  StyleSheetGroup = CmdGroup.new('style-sheets',
168
27
  "Default styles",
169
28
  <<EOD, 40)
170
29
  Commands for defining default styles.
171
30
 
172
- All commands take the name of the style to redefine. Different styles
173
- live in a different name space, so there is no risk naming an @axis@ and
174
- a @text@ style with the same name. All styles for a given type inherit from
175
- the style name @base@.
31
+ All commands take the selector of the style to be defined. It is a
32
+ CSS-like selector, relying on #id and .class, and using
33
+ #parentality. Therefore, defining a style for @.insets #stuff@ will
34
+ define it for an object named @stuff@, but only if it is contained
35
+ within another one that has a @.insets@ class.
176
36
 
177
37
  ctioga2 does not support changing a style after its use. It may
178
38
  affect only the following objects or all the ones that were created
179
39
  from the beginning, depending on the context. For safety, only define
180
40
  style before issueing any graphics command.
181
41
 
182
- ctioga2 may support at a later time loading style files, but that is
183
- not the case for now.
184
-
185
42
  EOD
186
43
  # We create the commands programmatically
187
44
  kinds = [
188
45
  ['axis', AxisStyle, 'axis'],
189
46
  ['background', BackgroundStyle, 'plot background'],
47
+ ['curve', CurveStyle, 'plot background'],
190
48
  ['title', TextLabel, 'plot title'],
191
49
  ['text', FullTextStyle, 'text'],
192
50
  ['marker', MarkerStringStyle, 'marker'],
51
+ ['legend', LegendStorageStyle, 'legend'],
193
52
  ['box', BoxStyle, 'boxes'],
194
53
  ['arrow', ArrowStyle, 'arrows'],
195
54
  ['image', ImageStyle, 'image'],
196
- ['line', StrokeStyle, 'lines']
55
+ ['line', StrokeStyle, 'lines'],
56
+ ['oriented-line', OrientedLineStyle, 'oriented lines']
197
57
  ]
198
58
 
199
59
  StyleSheetCommands = {}
200
60
  StyleSheetPredefinedNames = {}
61
+ AllStyleKeys = []
201
62
 
202
63
  kinds.each do |k|
203
64
  name, cls, desc = *k
@@ -209,15 +70,41 @@ EOD
209
70
  CmdArg.new('text'),
210
71
  ],
211
72
  cls.options_hash
212
- ) do |plotmaker, what, opts|
213
- StyleSheet.update_style(cls, what, opts)
73
+ ) do |plotmaker, xpath, opts|
74
+ StyleSheet.style_sheet.update_style(xpath, opts, name)
214
75
  end
215
76
  StyleSheetCommands[name].
216
77
  describe("Sets the default style for the given #{desc}.",
217
78
  <<"EOH", StyleSheetGroup)
218
79
  Sets the default style for the named #{desc}.
219
80
  EOH
81
+ AllStyleKeys.concat(cls.options_hash.keys)
220
82
  end
83
+
84
+ AllStyleKeys.uniq!
85
+ AllStyleKeys.sort!
86
+
87
+ AllStyleOptions = {}
88
+ for k in AllStyleKeys
89
+ AllStyleOptions[k] = CmdArg.new('text')
90
+ end
91
+
92
+ GenericStyleCommand =
93
+ Cmd.new("define-style",nil,
94
+ "--define-style",
95
+ [
96
+ CmdArg.new('text'),
97
+ ],
98
+ AllStyleOptions
99
+ ) do |plotmaker, xpath, opts|
100
+ StyleSheet.style_sheet.update_style(xpath, opts)
101
+ end
102
+ GenericStyleCommand.
103
+ describe("Defines style for the given xpath",
104
+ <<"EOH", StyleSheetGroup)
105
+ ...
106
+ EOH
107
+
221
108
 
222
109
  StyleSheetCommands['line'].long_description = <<EOD
223
110
  Sets the default style for lines. All line styles descend from the
@@ -230,15 +117,19 @@ Meaning of the style parameters:
230
117
  * @style@: the line style, see {type: line-style}
231
118
  * @width@: the line width (in points)
232
119
 
233
- > --define-line-style base /color=Pink
120
+ > --define-line-style * /color=Pink
234
121
 
235
122
  makes all lines pink (unless overriden by the /color option to
236
123
  {command: draw-line}), while
237
124
 
238
- > --define-line-style line-pink /color=Pink
125
+ > --define-line-style .pink /color=Pink
239
126
 
240
- only affect those to which the /base-style=line-pink style option
127
+ only affect those to which the /class=pink style option
241
128
  was given.
129
+ EOD
130
+
131
+ StyleSheetCommands['legend'].long_description = <<EOD
132
+ Sets the style for legends.
242
133
  EOD
243
134
 
244
135
  StyleSheetCommands['arrow'].long_description = <<EOD
@@ -352,10 +243,29 @@ EOD
352
243
 
353
244
  # Here, a few defaults styles
354
245
 
355
- StyleSheet.update_style(TextLabel, 'title', {
356
- 'text_width' =>
357
- Types::Dimension.new(:frame, 1.0, :x)
358
- })
246
+ StyleSheet.style_sheet.
247
+ update_style('title', {
248
+ 'text_width' =>
249
+ Types::Dimension.new(:frame, 1.0, :x)
250
+ })
251
+
252
+ LoadStyleCommand =
253
+ Cmd.new("load-style", nil,
254
+ "--load-style",
255
+ [
256
+ CmdArg.new('file'),
257
+ ], {}
258
+ ) do |plotmaker, file|
259
+ File.open(file) do |f|
260
+ str = f.read
261
+ StyleSheet.style_sheet.update_from_string(str)
262
+ end
263
+ end
264
+ LoadStyleCommand.
265
+ describe("Load a style file",
266
+ <<"EOH", StyleSheetGroup)
267
+ ...
268
+ EOH
359
269
  end
360
270
  end
361
271
  end