ctioga2 0.8 → 0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/Changelog +15 -0
- data/bin/ct2-make-movie +253 -0
- data/lib/ctioga2/commands/doc/doc.rb +4 -0
- data/lib/ctioga2/commands/doc/documentation-commands.rb +23 -8
- data/lib/ctioga2/commands/doc/html.rb +111 -60
- data/lib/ctioga2/commands/doc/markup.rb +2 -2
- data/lib/ctioga2/commands/function.rb +90 -0
- data/lib/ctioga2/commands/general-commands.rb +12 -0
- data/lib/ctioga2/commands/general-functions.rb +106 -0
- data/lib/ctioga2/commands/general-types.rb +8 -3
- data/lib/ctioga2/commands/interpreter.rb +11 -0
- data/lib/ctioga2/commands/parsers/file.rb +7 -5
- data/lib/ctioga2/commands/strings.rb +25 -4
- data/lib/ctioga2/commands/variables.rb +5 -1
- data/lib/ctioga2/data/point.rb +12 -4
- data/lib/ctioga2/graphics/elements/curve2d.rb +13 -2
- data/lib/ctioga2/graphics/elements/subplot.rb +13 -1
- data/lib/ctioga2/graphics/styles/axes.rb +12 -2
- data/lib/ctioga2/graphics/styles/map-axes.rb +1 -1
- data/lib/ctioga2/graphics/styles/plot.rb +48 -6
- data/lib/ctioga2/graphics/styles/texts.rb +9 -1
- data/lib/ctioga2/graphics/styles/ticks.rb +34 -0
- data/lib/ctioga2/graphics/subplot-commands.rb +35 -0
- data/lib/ctioga2/graphics/types.rb +30 -4
- data/lib/ctioga2/graphics/types/boxes.rb +13 -0
- data/lib/ctioga2/graphics/types/dimensions.rb +7 -0
- data/lib/ctioga2/plotmaker.rb +2 -0
- data/lib/ctioga2/postprocess.rb +15 -2
- data/lib/ctioga2/utils.rb +120 -0
- data/lib/ctioga2/version.rb +2 -2
- metadata +5 -2
@@ -54,9 +54,12 @@ module CTioga2
|
|
54
54
|
|
55
55
|
@subframe = nil # Automatic by default.
|
56
56
|
|
57
|
+
@prev_subframe = nil
|
58
|
+
|
57
59
|
@style = style || Styles::PlotStyle.new
|
58
60
|
|
59
61
|
@user_boundaries = {}
|
62
|
+
|
60
63
|
end
|
61
64
|
|
62
65
|
# Returns the boundaries that apply for the given _curve_ --
|
@@ -87,7 +90,16 @@ module CTioga2
|
|
87
90
|
end
|
88
91
|
|
89
92
|
def actual_subframe(t)
|
90
|
-
|
93
|
+
if @subframe
|
94
|
+
return @subframe
|
95
|
+
else
|
96
|
+
if @prev_subframe
|
97
|
+
@style.compute_margins(t, @prev_subframe)
|
98
|
+
else
|
99
|
+
@prev_subframe = @style.estimate_margins(t)
|
100
|
+
return @prev_subframe
|
101
|
+
end
|
102
|
+
end
|
91
103
|
end
|
92
104
|
|
93
105
|
# In general, subplot's boundaries do not count for the parent
|
@@ -81,6 +81,7 @@ module CTioga2
|
|
81
81
|
# * a transform is set
|
82
82
|
# * ticks are set
|
83
83
|
|
84
|
+
@@text_size_index = 0
|
84
85
|
|
85
86
|
# Creates a new AxisStyle object at the given location with
|
86
87
|
# the given style.
|
@@ -94,6 +95,9 @@ module CTioga2
|
|
94
95
|
@log = false
|
95
96
|
@ticks_side = {}
|
96
97
|
@ticks = AxisTicks.new
|
98
|
+
|
99
|
+
@index = @@text_size_index
|
100
|
+
@@text_size_index += 1
|
97
101
|
end
|
98
102
|
|
99
103
|
# Draws the axis within the current plot. Boundaries are the
|
@@ -105,7 +109,9 @@ module CTioga2
|
|
105
109
|
# where it should be...
|
106
110
|
# * non-linear axes (or linear, for that matter, but with
|
107
111
|
# a transformation)
|
108
|
-
|
112
|
+
#
|
113
|
+
# _watcher_ is a TextSizeWatcher object.
|
114
|
+
def draw_axis(t, watcher = nil)
|
109
115
|
spec = get_axis_specification(t)
|
110
116
|
|
111
117
|
info = t.axis_information(spec)
|
@@ -129,7 +135,11 @@ minor_tick_length minor_tick_width)
|
|
129
135
|
t.show_axis(spec)
|
130
136
|
@axis_label.loc = @location
|
131
137
|
default = vertical? ? 'ylabel' : 'xlabel'
|
132
|
-
@
|
138
|
+
nm = "axis-label#{@index}"
|
139
|
+
@axis_label.draw(t, default, nm)
|
140
|
+
if watcher
|
141
|
+
watcher.watch(nm)
|
142
|
+
end
|
133
143
|
end
|
134
144
|
|
135
145
|
# Sets the current boundaries of the _t_ object to the _range_
|
@@ -76,6 +76,12 @@ module CTioga2
|
|
76
76
|
# mode. A Dimension.
|
77
77
|
attr_accessor :padding
|
78
78
|
|
79
|
+
# Mode for auto-adjust
|
80
|
+
attr_accessor :text_auto_adjust
|
81
|
+
|
82
|
+
|
83
|
+
@@current_index = 0
|
84
|
+
|
79
85
|
def initialize
|
80
86
|
# Default style for the plots.
|
81
87
|
@axes = {}
|
@@ -110,8 +116,20 @@ module CTioga2
|
|
110
116
|
@background =
|
111
117
|
StyleSheet.style_for(BackgroundStyle, 'background')
|
112
118
|
|
113
|
-
# A padding of
|
114
|
-
@padding = Types::Dimension.new(:bp,
|
119
|
+
# A padding of 6bp ? Why ?? Why not ?
|
120
|
+
@padding = Types::Dimension.new(:bp, 6)
|
121
|
+
|
122
|
+
|
123
|
+
|
124
|
+
@text_size_index = @@current_index
|
125
|
+
@@current_index += 1
|
126
|
+
|
127
|
+
# Automatic adjustment of text sizes...
|
128
|
+
@text_sizes = TextSizeWatcher.new
|
129
|
+
@text_sizes.watch("title-#{@text_size_index}")
|
130
|
+
|
131
|
+
@text_auto_adjust = :both
|
132
|
+
|
115
133
|
end
|
116
134
|
|
117
135
|
# Apply (destructively) the current transformations to the
|
@@ -120,7 +138,6 @@ module CTioga2
|
|
120
138
|
@transforms.transform_2d!(dataset)
|
121
139
|
end
|
122
140
|
|
123
|
-
|
124
141
|
# Whether to use log scale for the given axis.
|
125
142
|
#
|
126
143
|
# Now the question is: how should that affect user-defined
|
@@ -235,7 +252,7 @@ module CTioga2
|
|
235
252
|
t.context do
|
236
253
|
begin
|
237
254
|
axis.set_bounds_for_axis(t, bounds[which])
|
238
|
-
axis.draw_axis(t)
|
255
|
+
axis.draw_axis(t, @text_sizes)
|
239
256
|
rescue Exception => e
|
240
257
|
error { "Impossible to draw axis #{which}: #{e.message}" }
|
241
258
|
debug { "Full message: #{e.inspect}\n#{e.backtrace.join("\n")}" }
|
@@ -243,7 +260,7 @@ module CTioga2
|
|
243
260
|
end
|
244
261
|
end
|
245
262
|
# We draw the title last
|
246
|
-
title.draw(t, 'title')
|
263
|
+
title.draw(t, 'title', "title-#{@text_size_index}")
|
247
264
|
end
|
248
265
|
|
249
266
|
# Draws all axes background lines for the plot.
|
@@ -302,6 +319,31 @@ module CTioga2
|
|
302
319
|
return box
|
303
320
|
end
|
304
321
|
|
322
|
+
# Computes the margins based on the text information.
|
323
|
+
#
|
324
|
+
# This is very different from the one above, since this one
|
325
|
+
# relies on measured texts to get it right !
|
326
|
+
def compute_margins(t, prev_margins)
|
327
|
+
margins = estimate_margins(t)
|
328
|
+
if @text_auto_adjust == :old
|
329
|
+
return margins
|
330
|
+
else
|
331
|
+
pad = if @padding
|
332
|
+
@padding.to_bp(t)
|
333
|
+
else
|
334
|
+
4
|
335
|
+
end
|
336
|
+
nm = @text_sizes.update_margins(t, prev_margins, pad)
|
337
|
+
|
338
|
+
# We include the old margins, unless we have the :measure
|
339
|
+
# text adjust mode
|
340
|
+
if @text_auto_adjust != :measure
|
341
|
+
nm.expand_to!(t, margins)
|
342
|
+
end
|
343
|
+
return nm
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
305
347
|
protected
|
306
348
|
|
307
349
|
# Takes a string and returns a Symbol suitable for use with
|
@@ -394,7 +436,7 @@ EOH
|
|
394
436
|
[:left, :right, :top, :bottom].each do |loc|
|
395
437
|
style = AxisStyle.current_axis_style(plotmaker, loc)
|
396
438
|
style.decoration = Tioga::FigureConstants::AXIS_HIDDEN
|
397
|
-
style.axis_label.text =
|
439
|
+
style.axis_label.text = false
|
398
440
|
end
|
399
441
|
end
|
400
442
|
ClearAxesCommand.
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# texts.rb: style for textual objects
|
2
|
-
# copyright (c) 2009 by Vincent Fourmond
|
2
|
+
# copyright (c) 2009, 2010, 2012, 2013, 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
|
@@ -47,6 +47,9 @@ module CTioga2
|
|
47
47
|
# The horizontal alignment
|
48
48
|
typed_attribute :justification, 'justification'
|
49
49
|
|
50
|
+
# A text width
|
51
|
+
typed_attribute :text_width, "text"
|
52
|
+
|
50
53
|
# Draw the _text_ at the given location with the given style.
|
51
54
|
# If _y_ is _nil_, then _x_or_loc_ is taken to be a location
|
52
55
|
# (see FigureMaker#show_text).
|
@@ -81,6 +84,7 @@ module CTioga2
|
|
81
84
|
dim = dict['scale']
|
82
85
|
dict['scale'] = dim.to_dy(t)
|
83
86
|
end
|
87
|
+
dict.delete('text_width')
|
84
88
|
return dict
|
85
89
|
end
|
86
90
|
|
@@ -89,6 +93,10 @@ module CTioga2
|
|
89
93
|
# Prepares the dictionnary for use with show_text
|
90
94
|
def prepare_show_text_dict(t, text, x_or_loc, y = nil, measure = nil)
|
91
95
|
dict = self.hash_for_tioga(t)
|
96
|
+
if @text_width
|
97
|
+
text = "\\parbox{#{@text_width}}{#{text}}"
|
98
|
+
end
|
99
|
+
|
92
100
|
dict['text'] = text
|
93
101
|
|
94
102
|
if y
|
@@ -48,8 +48,22 @@ module CTioga2
|
|
48
48
|
# @todo make it possible to provide a function to generate that ?
|
49
49
|
typed_attribute :major, 'float-list'
|
50
50
|
|
51
|
+
# Separation between major ticks. Overriden by the major list
|
52
|
+
typed_attribute :major_delta, "float"
|
53
|
+
|
54
|
+
# Approximate number of major ticks
|
55
|
+
typed_attribute :major_number, "integer"
|
56
|
+
|
51
57
|
# The list of the position of minor ticks
|
52
58
|
typed_attribute :minor, 'float-list'
|
59
|
+
|
60
|
+
# Separation between minor ticks
|
61
|
+
typed_attribute :minor_delta, "float"
|
62
|
+
|
63
|
+
# Number of minor ticks between major ticks
|
64
|
+
typed_attribute :minor_number, "integer"
|
65
|
+
|
66
|
+
|
53
67
|
|
54
68
|
# The list of labels
|
55
69
|
typed_attribute :labels, 'text-list'
|
@@ -71,15 +85,35 @@ module CTioga2
|
|
71
85
|
end
|
72
86
|
fmt = @format
|
73
87
|
|
88
|
+
# beginning or end of the axis. Not specifically x
|
89
|
+
xl, xr = * (if info['vertical']
|
90
|
+
[info['y0'], info['y1']]
|
91
|
+
else
|
92
|
+
[info['x0'], info['x1']]
|
93
|
+
end)
|
94
|
+
|
95
|
+
if xl > xr
|
96
|
+
xl, xr = xr, xl
|
97
|
+
end
|
98
|
+
|
74
99
|
if @major
|
75
100
|
ret['minor_ticks'] = Dobjects::Dvector.new
|
76
101
|
ret['major_ticks'] = Dobjects::Dvector.new(@major)
|
77
102
|
|
78
103
|
fmt ||= "$%g$"
|
104
|
+
elsif @major_delta || @major_number
|
105
|
+
delta = @major_delta || Utils::closest_subdivision(( (xr - xl)/@major_number))
|
106
|
+
ret['major_ticks'] = Utils::integer_subdivisions(xl, xr,
|
107
|
+
delta)
|
108
|
+
fmt ||= "$%g$"
|
79
109
|
end
|
80
110
|
|
81
111
|
if @minor
|
82
112
|
ret['minor_ticks'] = Dobjects::Dvector.new(@minor)
|
113
|
+
elsif @minor_delta || delta
|
114
|
+
dt = @minor_delta || delta/((@minor_number || 3)+1)
|
115
|
+
ret['minor_ticks'] = Utils::integer_subdivisions(xl, xr,
|
116
|
+
dt)
|
83
117
|
end
|
84
118
|
|
85
119
|
fmt_last = @format_last || fmt
|
@@ -57,6 +57,41 @@ When the {command: frame-margins} is set to automatic, ctioga2 leaves
|
|
57
57
|
that much space around the plot on the sides where there are no labels.
|
58
58
|
EOH
|
59
59
|
|
60
|
+
|
61
|
+
TARE = {
|
62
|
+
/^\s*old/i => :old,
|
63
|
+
/^\s*both/i => :both,
|
64
|
+
/^\s*measure/i => :measure,
|
65
|
+
}
|
66
|
+
|
67
|
+
TEType =
|
68
|
+
CmdType.new('text-adjust-mode',
|
69
|
+
{:type => :re_list,
|
70
|
+
:list => TARE}, <<EOD)
|
71
|
+
Mode for text size adjustment
|
72
|
+
* @old@ for the old style heuristics
|
73
|
+
* @both@ for both the old style heuristics and the measures, taking
|
74
|
+
whichever of those is the biggest
|
75
|
+
* @measure@ for only measured text size (but watch out for axis ticks !)
|
76
|
+
EOD
|
77
|
+
|
78
|
+
|
79
|
+
TAACommand =
|
80
|
+
Cmd.new("text-adjust-mode",nil,"--text-adjust-mode",
|
81
|
+
[
|
82
|
+
CmdArg.new('text-adjust-mode'),
|
83
|
+
]) do |plotmaker, tf|
|
84
|
+
|
85
|
+
Styles::PlotStyle.current_plot_style(plotmaker).text_auto_adjust = tf
|
86
|
+
end
|
87
|
+
|
88
|
+
TAACommand.describe('Enables or disables the automatic detection of text size',
|
89
|
+
<<EOH, SubplotsGroup)
|
90
|
+
When this is on (the default), @ctioga2@ tries to be smart about the
|
91
|
+
size of the text bits around the plot. However, this can be bothersome
|
92
|
+
at times, so you can disable that with this command.
|
93
|
+
EOH
|
94
|
+
|
60
95
|
|
61
96
|
InsetCommand =
|
62
97
|
Cmd.new("inset",nil,"--inset",
|
@@ -176,7 +176,27 @@ EOD
|
|
176
176
|
AlignedPointType =
|
177
177
|
CmdType.new('aligned-point', {:type => :aligned_point,
|
178
178
|
:default => :frame}, <<EOD)
|
179
|
-
A point together with alignment specifications
|
179
|
+
A point together with alignment specifications, used to place some
|
180
|
+
elements such as legends for instance, that require alignment information.
|
181
|
+
|
182
|
+
The first two letters represent the alignment:
|
183
|
+
|
184
|
+
* @t@ for top
|
185
|
+
* @b@ for bottom
|
186
|
+
* @c@ for center
|
187
|
+
* @l@ for left and
|
188
|
+
* @r@ for right
|
189
|
+
|
190
|
+
These letters can optionally be followed by the exact location of the
|
191
|
+
point in frame coordinates. If not provided, a reasonable default
|
192
|
+
value is chosen.
|
193
|
+
|
194
|
+
Examples:
|
195
|
+
|
196
|
+
* @tl@ is a point at the top left of the frame aligned to the top
|
197
|
+
and left;
|
198
|
+
* @cl:0.1,0.6@ is vertically centered and aligned to the left, and
|
199
|
+
positioned 10% from the left and 60% from the bottom.
|
180
200
|
EOD
|
181
201
|
|
182
202
|
FrameMarginsType =
|
@@ -250,10 +270,16 @@ EOD
|
|
250
270
|
|
251
271
|
BoxType =
|
252
272
|
CmdType.new('box', :box, <<EOD)
|
253
|
-
The specification for a box, such as an inset.
|
254
|
-
|
273
|
+
The specification for a box, such as an inset. It can be a grid
|
274
|
+
specification, such as @grid:0,1@. For this to work, a grid must have
|
275
|
+
been setup beforehand using {command: setup-grid}.
|
276
|
+
|
277
|
+
It can also be an {type: aligned-point} together with a width and
|
278
|
+
optionally a height in frame coordinates, such as:
|
255
279
|
|
256
|
-
@
|
280
|
+
* @cc:0.3@: a box in the center of size 30% width and 30% height;
|
281
|
+
* @bl:0.1,0.2:0.7,0.2@ a box starting from the point at 10% from the left
|
282
|
+
and 20% from the bottom, with a width of 70% and a height of 20%.
|
257
283
|
EOD
|
258
284
|
|
259
285
|
# Coordinate transformations
|
@@ -91,6 +91,19 @@ module CTioga2
|
|
91
91
|
return [@left, @right, @top, @bottom]
|
92
92
|
end
|
93
93
|
|
94
|
+
# Augments the margins so that they also encompass those given
|
95
|
+
# in other. Based on the current interpretation of the
|
96
|
+
# measures as bp.
|
97
|
+
def expand_to!(t, other)
|
98
|
+
for w in %w(left right top bottom)
|
99
|
+
mine = self.send(w)
|
100
|
+
theirs = other.send(w)
|
101
|
+
if mine.to_bp(t) < theirs.to_bp(t)
|
102
|
+
self.send("#{w}=", theirs)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
94
107
|
end
|
95
108
|
|
96
109
|
# A box defined by an AlignedPoint and two dimensions
|
@@ -81,6 +81,13 @@ module CTioga2
|
|
81
81
|
return fig/t.default_text_height_dy
|
82
82
|
end
|
83
83
|
|
84
|
+
# Converts the dimension into big points
|
85
|
+
def to_bp(t, orientation = nil)
|
86
|
+
orientation ||= @orientation
|
87
|
+
return t.send("convert_figure_to_output_d#{orientation}",
|
88
|
+
to_figure(t, orientation)) / 10.0
|
89
|
+
end
|
90
|
+
|
84
91
|
# Converts the Dimension to the *frame* coordinates of the
|
85
92
|
# *current* frame in _t_.
|
86
93
|
def to_frame(t, orientation = nil)
|
data/lib/ctioga2/plotmaker.rb
CHANGED
@@ -752,6 +752,7 @@ EOH
|
|
752
752
|
{
|
753
753
|
'oversampling' => CmdArg.new('float'),
|
754
754
|
'scale' => CmdArg.new('float'),
|
755
|
+
'pdftoppm' => CmdArg.new('boolean'),
|
755
756
|
}) do |plotmaker,res, opts|
|
756
757
|
if res =~ /^\s*(\d+)\s*x\s*(\d+)\s*$/
|
757
758
|
size = [$1.to_i, $2.to_i]
|
@@ -761,6 +762,7 @@ EOH
|
|
761
762
|
end
|
762
763
|
scale = opts['scale'] || 1
|
763
764
|
plotmaker.postprocess.png_scale = scale
|
765
|
+
plotmaker.postprocess.png_pdftoppm = opts['pdftoppm']
|
764
766
|
page_size = size.map { |n| (n/(1.0 *scale)).to_s + "bp" }.join('x')
|
765
767
|
plotmaker.root_object.set_page_size(page_size)
|
766
768
|
else
|
data/lib/ctioga2/postprocess.rb
CHANGED
@@ -43,6 +43,13 @@ module CTioga2
|
|
43
43
|
# Are we converting to EPS using pdftops ?
|
44
44
|
attr_accessor :eps
|
45
45
|
|
46
|
+
|
47
|
+
# @todo Maybe all the PNG stuff should be it is own class ?
|
48
|
+
|
49
|
+
# If on, we use pdftoppm rather than imagemagick (gs, used by
|
50
|
+
# pdftoppm is much slower than pdftoppm)
|
51
|
+
attr_accessor :png_pdftoppm
|
52
|
+
|
46
53
|
# PNG resolution
|
47
54
|
attr_accessor :png_res
|
48
55
|
|
@@ -62,6 +69,7 @@ module CTioga2
|
|
62
69
|
@png_res = nil
|
63
70
|
@png_oversampling = 2
|
64
71
|
@png_scale = 1
|
72
|
+
@png_pdftoppm = false
|
65
73
|
|
66
74
|
@processed_files = []
|
67
75
|
end
|
@@ -114,9 +122,14 @@ module CTioga2
|
|
114
122
|
|
115
123
|
# Converts to PNG if applicable
|
116
124
|
if @png_res
|
117
|
-
|
125
|
+
tbase = file.sub(/(\.pdf)?$/,'')
|
118
126
|
info { "Converting #{file} to PNG" }
|
119
|
-
|
127
|
+
|
128
|
+
if @png_pdftoppm
|
129
|
+
spawn "pdftoppm -singlefile -png -r #{(@png_scale * 72).to_i} #{file} #{tbase}"
|
130
|
+
else
|
131
|
+
spawn "convert -density #{(@png_oversampling * @png_scale * 72).to_i} #{file} -resize #{@png_res.join('x')} #{tbase}.png"
|
132
|
+
end
|
120
133
|
end
|
121
134
|
|
122
135
|
# View produced PDF or PNG files...
|