Class: CTioga2::Graphics::Styles::PlotStyle

Inherits:
Object
  • Object
show all
Includes:
Log, Tioga::FigureConstants
Defined in:
lib/ctioga2/graphics/styles/plot.rb

Overview

The style of a Elements::Subplot object.

todo it should hold

  • labels

  • axes and edges (in a clean way !)

  • ticks

  • background (uniform fill + watermark if applicable + possibly a picture .?)

This class is way too complex and needs too much flexibility to be handled by a subclass of BasicStyle. However, all substyles should be.

Constant Summary collapse

@@current_index =
0

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Log

context, counts, debug, error, fatal, #format_exception, #identify, info, init_logger, log_to, logger, set_level, #spawn, warn

Constructor Details

#initialize(plt) ⇒ PlotStyle

Returns a new instance of PlotStyle.



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/ctioga2/graphics/styles/plot.rb', line 94

def initialize(plt)
  # Default style for the plots.
  @target_plot = plt

  @axes = {}
  for ax in [:left, :right, :top, :bottom] 
    
    cls = [ax.to_s]
    cls << if (ax == :bottom or ax == :top)
             'x'
           else
             'y'
           end
    dec = if (ax == :bottom or ax == :left)
            AXIS_WITH_TICKS_AND_NUMERIC_LABELS
          else
            AXIS_WITH_TICKS_ONLY
          end
    label = nil
    if ax == :bottom
      label = '$x$'
    elsif ax == :left
      label = '$y$'
    end
    
    axis = Elements::AxisElement.new
    axis.setup_style(@target_plot, {'class' => cls})
    axis.initialize_style(ax, dec, label)
    @axes[ax] = axis
  end

  @xaxis_location = :bottom
  @yaxis_location = :left

  @title = Elements::TitleElement.new(@target_plot, {})

  @plot_margin = nil

  @transforms = CoordinateTransforms.new

  @background = Elements::BackgroundElement.new(@target_plot, {})

  # A padding of 6bp ? Why ?? Why not ?
  @padding = Types::Dimension.new(:bp, 6)


  
  @text_size_index = @@current_index
  @@current_index += 1

  # Automatic adjustment of text sizes...
  @text_sizes = TextSizeWatcher.new
  @text_sizes.watch("title-#{@text_size_index}")

  @text_auto_adjust = :both

end

Instance Attribute Details

#axesObject

The various sides of the plot. A hash location -> AxisStyle.



46
47
48
# File 'lib/ctioga2/graphics/styles/plot.rb', line 46

def axes
  @axes
end

#backgroundObject

Style of the background of the plot



66
67
68
# File 'lib/ctioga2/graphics/styles/plot.rb', line 66

def background
  @background
end

#frame_real_sizeObject

If not nil, then the boundaries are computed from the real dimensions of the plot frame, using the given number as a conversion factor from postscript points.



86
87
88
# File 'lib/ctioga2/graphics/styles/plot.rb', line 86

def frame_real_size
  @frame_real_size
end

#lines_scaleObject

Scale of the lines of the plot. The plot is wrapped in a t.rescale_lines call.



70
71
72
# File 'lib/ctioga2/graphics/styles/plot.rb', line 70

def lines_scale
  @lines_scale
end

#paddingObject

A padding around the box when automatic spacing is in auto mode. A Dimension.



78
79
80
# File 'lib/ctioga2/graphics/styles/plot.rb', line 78

def padding
  @padding
end

#plot_marginObject

A margin to be left around the data points



58
59
60
# File 'lib/ctioga2/graphics/styles/plot.rb', line 58

def plot_margin
  @plot_margin
end

#target_plotObject

The target plot (ie the parent of all the small elements)



90
91
92
# File 'lib/ctioga2/graphics/styles/plot.rb', line 90

def target_plot
  @target_plot
end

#text_auto_adjustObject

Mode for auto-adjust



81
82
83
# File 'lib/ctioga2/graphics/styles/plot.rb', line 81

def text_auto_adjust
  @text_auto_adjust
end

#text_scaleObject

Scale of the text of the plot. The plot is wrapped in a t.rescale_text call.



74
75
76
# File 'lib/ctioga2/graphics/styles/plot.rb', line 74

def text_scale
  @text_scale
end

#titleObject

The title of the plot



55
56
57
# File 'lib/ctioga2/graphics/styles/plot.rb', line 55

def title
  @title
end

#transformsObject

TODO:

they should be axis-specific.

Coordinate tranforms



63
64
65
# File 'lib/ctioga2/graphics/styles/plot.rb', line 63

def transforms
  @transforms
end

#xaxis_locationObject

The default location of the X axis (well, mainly, the X label)



49
50
51
# File 'lib/ctioga2/graphics/styles/plot.rb', line 49

def xaxis_location
  @xaxis_location
end

#yaxis_locationObject

The default location of the Y axis (well, mainly, the Y label)



52
53
54
# File 'lib/ctioga2/graphics/styles/plot.rb', line 52

def yaxis_location
  @yaxis_location
end

Class Method Details

.current_plot_style(plotmaker) ⇒ Object

Returns the PlotStyle object of the current plot



309
310
311
# File 'lib/ctioga2/graphics/styles/plot.rb', line 309

def self.current_plot_style(plotmaker)
  return plotmaker.root_object.current_plot.style
end

Instance Method Details

#apply_transforms!(dataset) ⇒ Object

Apply (destructively) the current transformations to the given dataset



154
155
156
# File 'lib/ctioga2/graphics/styles/plot.rb', line 154

def apply_transforms!(dataset)
  @transforms.transform_2d!(dataset)
end

#clear_axesObject

Clear all axes



340
341
342
343
344
345
346
# File 'lib/ctioga2/graphics/styles/plot.rb', line 340

def clear_axes()
  [:left, :right, :top, :bottom].each do |loc|
    style = get_axis_style(loc)
    style.decoration = Tioga::FigureConstants::AXIS_HIDDEN
    style.axis_label.text = false
  end
end

#compute_margins(t, prev_margins) ⇒ Object

Computes the margins based on the text information.

This is very different from the one above, since this one relies on measured texts to get it right !



352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
# File 'lib/ctioga2/graphics/styles/plot.rb', line 352

def compute_margins(t, prev_margins)
  margins = estimate_margins(t)
  if @text_auto_adjust == :old
    return margins
  else
    pad = if @padding
            @padding.to_bp(t)
          else
            4
          end
    nm =  @text_sizes.update_margins(t, prev_margins, pad)

    # We include the old margins, unless we have the :measure
    # text adjust mode
    if @text_auto_adjust != :measure
      nm.expand_to!(t, margins)
    end
    return nm
  end
end

#deep_copyObject

Returns a deep copy of self, with all references stripped.



304
305
306
# File 'lib/ctioga2/graphics/styles/plot.rb', line 304

def deep_copy
  return Marshal.load(Marshal.dump(self))
end

#draw_all_axes(t, bounds) ⇒ Object

Draws all axes for the plot. The bounds argument is that computed by Subplot#compute_boundaries; it is there to ensure that the axes know whether they have their own coordinate system or if they just follow what’s around.



267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/ctioga2/graphics/styles/plot.rb', line 267

def draw_all_axes(t, bounds)
  for which, axis in @axes
    t.context do
      begin
        axis.style.set_bounds_for_axis(t, bounds[which])
        axis.style.draw_axis(t, @text_sizes)
      rescue Exception => e
        error { "Impossible to draw axis #{which}: #{e.message}" }
        info { "Full message: #{e.inspect}\n#{e.backtrace.join("\n")}" }
      end
    end
  end
  # We draw the title last
  title.style.draw(t, 'title', "title-#{@text_size_index}")
end

#draw_all_background_lines(t) ⇒ Object

Draws all axes background lines for the plot.



284
285
286
287
288
# File 'lib/ctioga2/graphics/styles/plot.rb', line 284

def draw_all_background_lines(t)
  for which, axis in @axes
    axis.style.draw_background_lines(t)
  end
end

#estimate_margins(t) ⇒ Object

Estimate the margins of the plot whose style this object controls. These margins are used when the plot margins are in automatic mode.

Returns a Types::MarginsBox



318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
# File 'lib/ctioga2/graphics/styles/plot.rb', line 318

def estimate_margins(t)
  margins = [:left, :right, :top, :bottom].map do |side|
    exts = axes_for_side(side).map do |ax|
      ax.style.extension(t, self)
    end
    if @title.style.loc.is_side?(side)
      exts << @title.style.label_extension(t, 'title', @title.style.loc) * 
        (@text_scale || 1)
    end
    Types::Dimension.new(:dy, exts.max || 0)
  end

  box = Types::MarginsBox.new(*margins)
  if @padding
    for dim in box.margins
      dim.replace_if_bigger(t, @padding)
    end
  end
  return box
end

#get_axis_key(name) ⇒ Object

Returns the key corresponding to the named axis. See #get_axis_style for more information; though ultimately the latter is using this function.



214
215
216
217
218
219
220
# File 'lib/ctioga2/graphics/styles/plot.rb', line 214

def get_axis_key(name)
  if name =~ /^\s*([xy])(?:axis)?\s*$/i
    return self.send("#{$1.downcase}axis_location")
  else
    return clean_axis_name(name)
  end
end

#get_axis_style(name) ⇒ Object

Returns the AxisStyle corresponding to the named axis. name can be:

  • one of the named axes (ie, by default: top, left, right, bottom). All names are stripped from spaces around, and downcased (see #clean_axis_name). Can be also user-defined axes.

  • x(axis)?/y(axis)?, which returns the default object for the given location

todo Maybe x2 and y2 could be provided to signify “the side which isn’t the default” ?



201
202
203
204
205
206
207
208
209
# File 'lib/ctioga2/graphics/styles/plot.rb', line 201

def get_axis_style(name)
  axis = @axes[get_axis_key(name)]
  if ! axis
    ## @todo Type-safe exception here
    raise "Unkown named axis: '#{name}'"
  else
    return axis.style
  end
end

#get_label_style(location) ⇒ Object

Returns a BaseTextStyle or similar for the given location. The location is of the form:

axis_name(_(ticks?|label))

or

title

If neither label nor ticks is specified in the first form, ticks are implied.



237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/ctioga2/graphics/styles/plot.rb', line 237

def get_label_style(location)
  if location =~ /^\s*title\s*$/
    return @title.style
  end
  location =~ /^\s*(.*?)(?:_(ticks?|label))?\s*$/i
  which = $2
  axis = get_axis_style($1)
  if which =~ /label/
    return axis.axis_label
  else
    return axis.tick_label_style
  end
end

#set_axis(name, axis) ⇒ Object



222
223
224
225
# File 'lib/ctioga2/graphics/styles/plot.rb', line 222

def set_axis(name, axis)
  key = get_axis_key(name)
  @axes[key] = axis
end

#set_default_axis(which, name) ⇒ Object

Sets the axis which should be used for subsequent objects (for which no axis is specified) for the given plot



182
183
184
185
# File 'lib/ctioga2/graphics/styles/plot.rb', line 182

def set_default_axis(which, name)
  axis = get_axis_key(name)
  self.send("#{which}axis_location=", axis)
end

#set_label_style(which, hash, text = nil) ⇒ Object

Sets the style of the given label. Sets the text as well, if text is not nil



253
254
255
256
257
258
259
260
# File 'lib/ctioga2/graphics/styles/plot.rb', line 253

def set_label_style(which, hash, text = nil)
  style = get_label_style(which)
  hash = hash.merge({'text' => text}) unless text.nil?
  if hash.key?('text') and ! style.is_a?(TextLabel)
    CTioga2::Log::warn {"Text property of label #{which} was set, but this has no meaning: tick labels can't be set this way. Did you mean to use \"#{which}_label\"" + " instead ?" }
  end
  style.set_from_hash(hash)
end

#set_log_scale(which, val) ⇒ Object

Whether to use log scale for the given axis.

Now the question is: how should that affect user-defined axes ? It should not.

todo This really should move to Axis when transformations are handled correctly.



165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/ctioga2/graphics/styles/plot.rb', line 165

def set_log_scale(which, val)
  case which
  when :x
    @axes[:top].style.log = val
    @axes[:bottom].style.log = val
    @transforms.x_log = val
  when :y
    @axes[:left].style.log = val
    @axes[:right].style.log = val
    @transforms.y_log = val
  else
    raise "Unknown axis: #{which.inspect}"
  end
end

#setup_figure_maker(t) ⇒ Object

Sets up the FigureMaker object for the plot. To be called just after the outermost context call for the concerned plot.



293
294
295
296
297
298
299
300
# File 'lib/ctioga2/graphics/styles/plot.rb', line 293

def setup_figure_maker(t)
  if @lines_scale
    t.rescale_lines(@lines_scale)
  end
  if @text_scale
    t.rescale_text(@text_scale)
  end
end