ctioga2 0.8 → 0.9
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.
- 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...
|