1
# subplot.rb: a subplot
2
# copyright (c) 2006, 2007, 2008, 2009 by Vincent Fourmond
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.
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).
14
require 'ctioga2/utils'
19
Version::register_svn_info('$Revision: 196 $', '$Date: 2010-11-25 20:15:32 +0100 (Thu, 25 Nov 2010) $')
25
# A subplot. It features:
26
# * inclusion of curves
28
# * a way to set/get its figure boundaries.
29
class Subplot < Container
31
# Various stylistic aspects of the plot, as a
32
# Styles::PlotStyle object.
35
# User-specified boundaries. It is a hash axis -> SimpleRange,
36
# where the axis is a valid return value of PlotStyle#get_axis_key
37
attr_accessor :user_boundaries
39
# Computed boundaries. It also is a hash axis -> SimpleRange,
40
# just as #user_boundaries. Its value is not defined as long
41
# as #real_do hasn't been entered into.
42
attr_accessor :computed_boundaries
44
def initialize(parent, root, style)
47
@subframe = Types::MarginsBox.new("2.8dy", "2.8dy",
50
@subframe = nil # Automatic by default.
52
@style = style || Styles::PlotStyle.new
57
# Returns the boundaries that apply for the given _curve_ --
58
# it reads the curve's axes. #compute_boundaries must have
59
# been called beforehand, which means that it will only work
60
# from within #real_do.
62
# \todo This should not only apply to curves, but to any
63
# object. That also means that there should be a way to
64
# specify axes for them too.
65
def get_el_boundaries(el)
66
return get_given_boundaries(* el.location.get_axis_keys(style))
69
# Returns the boundaries of the *default* axes. Plotting
70
# functions may safely assume that they are drawn using these
71
# boundaries, unless they asked for being drawn onto different
74
return get_given_boundaries(style.xaxis_location,
78
# Sets the user boundaries for the given (named) axis:
79
def set_user_boundaries(axis, bounds)
80
key = @style.get_axis_key(axis)
81
@user_boundaries[key] = Types::SimpleRange.new(bounds)
84
def actual_subframe(t)
85
return @subframe || @style.estimate_margins(t)
88
# In general, subplot's boundaries do not count for the parent
96
# Makes up a Boundaries object from two axes keys
97
def get_given_boundaries(horiz, vert)
98
if @computed_boundaries
99
return Types::Boundaries.from_ranges(@computed_boundaries[horiz],
100
@computed_boundaries[vert])
106
def compute_boundaries
108
bounds = get_elements_boundaries
109
if @style.plot_margin
111
b.apply_margin!(@style.plot_margin)
114
for k,b in @user_boundaries
115
bounds[k] ||= Types::SimpleRange.new(nil,nil)
116
bounds[k].override(b)
123
# Plots all the objects inside the plot.
125
# First thing, we setup the boundaries
126
@computed_boundaries = compute_boundaries
128
real_boundaries = get_boundaries
130
frames = actual_subframe(t)
132
# We wrap the call within a subplot
133
t.subplot(frames.to_frame_margins(t)) do
135
# Setup various aspects of the figure maker object.
136
@style.setup_figure_maker(t)
138
# Manually creating the plot:
139
t.set_bounds(real_boundaries.to_a)
141
# Drawing the background elements:
145
@style.background.draw_background(t)
147
@style.draw_all_background_lines(t)
149
for element in @elements
151
t.set_bounds(get_el_boundaries(element).to_a)
157
@style.draw_all_axes(t, @computed_boundaries)
159
# Now drawing legends:
161
a, b = @legend_area.partition_frame(t, self)
164
@legend_area.display_legend(t, self)
171
# Returns the boundaries of all the elements of this plot.
172
def get_elements_boundaries
175
if el.respond_to? :get_boundaries
176
if el.respond_to?(:count_boundaries?) && ! (el.count_boundaries?)
179
bounds = el.get_boundaries
180
xaxis, yaxis = *el.location.get_axis_keys(style)
182
## \todo see if there will ever be a need for a hash
186
boundaries[xaxis] ||= Types::SimpleRange.new(nil,nil)
187
boundaries[xaxis].extend(bounds.horizontal)
188
boundaries[yaxis] ||= Types::SimpleRange.new(nil,nil)
189
boundaries[yaxis].extend(bounds.vertical)