tioga 1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Tioga_README +372 -0
- data/lgpl.txt +504 -0
- data/split/Dtable/defs.h +33 -0
- data/split/Dtable/dtable.c +1928 -0
- data/split/Dtable/dtable_intern.h +144 -0
- data/split/Dtable/dvector.h +61 -0
- data/split/Dtable/extconf.rb +4 -0
- data/split/Dtable/include/dtable.h +35 -0
- data/split/Dtable/lib/Dtable_extras.rb +90 -0
- data/split/Dtable/namespace.h +47 -0
- data/split/Dtable/safe_double.h +104 -0
- data/split/Dtable/symbols.c +92 -0
- data/split/Dtable/symbols.h +52 -0
- data/split/Dvector/defs.h +33 -0
- data/split/Dvector/dvector.c +5486 -0
- data/split/Dvector/dvector_intern.h +142 -0
- data/split/Dvector/extconf.rb +4 -0
- data/split/Dvector/include/dvector.h +61 -0
- data/split/Dvector/lib/Dvector_extras.rb +328 -0
- data/split/Dvector/lib/Numeric_extras.rb +134 -0
- data/split/Dvector/namespace.h +47 -0
- data/split/Dvector/safe_double.h +104 -0
- data/split/Dvector/symbols.c +92 -0
- data/split/Dvector/symbols.h +52 -0
- data/split/Flate/defs.h +33 -0
- data/split/Flate/extconf.rb +19 -0
- data/split/Flate/flate.c +156 -0
- data/split/Flate/flate_intern.h +97 -0
- data/split/Flate/include/flate.h +98 -0
- data/split/Flate/namespace.h +47 -0
- data/split/Flate/safe_double.h +104 -0
- data/split/Flate/symbols.c +92 -0
- data/split/Flate/symbols.h +52 -0
- data/split/Function/defs.h +33 -0
- data/split/Function/dvector.h +61 -0
- data/split/Function/extconf.rb +4 -0
- data/split/Function/function.c +988 -0
- data/split/Function/joint_qsort.c +258 -0
- data/split/Function/lib/Function_extras.rb +44 -0
- data/split/Function/namespace.h +47 -0
- data/split/Function/safe_double.h +104 -0
- data/split/Function/symbols.c +92 -0
- data/split/Function/symbols.h +52 -0
- data/split/Tioga/axes.c +774 -0
- data/split/Tioga/defs.h +33 -0
- data/split/Tioga/dtable.h +35 -0
- data/split/Tioga/dvector.h +61 -0
- data/split/Tioga/extconf.rb +4 -0
- data/split/Tioga/figures.c +672 -0
- data/split/Tioga/figures.h +855 -0
- data/split/Tioga/flate.h +98 -0
- data/split/Tioga/init.c +524 -0
- data/split/Tioga/lib/Arcs_and_Circles.rb +64 -0
- data/split/Tioga/lib/ColorConstants.rb +274 -0
- data/split/Tioga/lib/Colorbars.rb +10 -0
- data/split/Tioga/lib/Colormaps.rb +105 -0
- data/split/Tioga/lib/Coordinate_Conversions.rb +194 -0
- data/split/Tioga/lib/Creating_Paths.rb +94 -0
- data/split/Tioga/lib/Doc.rb +91 -0
- data/split/Tioga/lib/Executive.rb +515 -0
- data/split/Tioga/lib/FigMkr.rb +2224 -0
- data/split/Tioga/lib/FigureConstants.rb +125 -0
- data/split/Tioga/lib/Figures_and_Plots.rb +268 -0
- data/split/Tioga/lib/Images.rb +278 -0
- data/split/Tioga/lib/Legends.rb +190 -0
- data/split/Tioga/lib/MarkerConstants.rb +122 -0
- data/split/Tioga/lib/Markers.rb +129 -0
- data/split/Tioga/lib/Page_Frame_Bounds.rb +567 -0
- data/split/Tioga/lib/Rectangles.rb +94 -0
- data/split/Tioga/lib/Shading.rb +100 -0
- data/split/Tioga/lib/Special_Paths.rb +307 -0
- data/split/Tioga/lib/Strokes.rb +129 -0
- data/split/Tioga/lib/TeX_Text.rb +454 -0
- data/split/Tioga/lib/TexPreamble.rb +358 -0
- data/split/Tioga/lib/Titles_and_Labels.rb +306 -0
- data/split/Tioga/lib/Transparency.rb +89 -0
- data/split/Tioga/lib/Using_Paths.rb +164 -0
- data/split/Tioga/lib/Utils.rb +74 -0
- data/split/Tioga/lib/X_and_Y_Axes.rb +749 -0
- data/split/Tioga/lib/irb_tioga.rb +122 -0
- data/split/Tioga/lib/tioga.rb +1 -0
- data/split/Tioga/lib/tioga_ui.rb +5 -0
- data/split/Tioga/lib/tioga_ui_cmds.rb +793 -0
- data/split/Tioga/makers.c +989 -0
- data/split/Tioga/mk_tioga_sty.rb +53 -0
- data/split/Tioga/namespace.h +47 -0
- data/split/Tioga/pdf_font_dicts.c +18253 -0
- data/split/Tioga/pdfcolor.c +486 -0
- data/split/Tioga/pdfcoords.c +505 -0
- data/split/Tioga/pdffile.c +342 -0
- data/split/Tioga/pdfimage.c +536 -0
- data/split/Tioga/pdfpath.c +914 -0
- data/split/Tioga/pdfs.h +229 -0
- data/split/Tioga/pdftext.c +443 -0
- data/split/Tioga/safe_double.h +104 -0
- data/split/Tioga/symbols.c +92 -0
- data/split/Tioga/symbols.h +52 -0
- data/split/Tioga/texout.c +380 -0
- data/split/defs.h +33 -0
- data/split/extconf.rb +107 -0
- data/split/mkmf2.rb +1612 -0
- data/split/namespace.h +47 -0
- data/split/safe_double.h +104 -0
- data/split/scripts/tioga +4 -0
- data/split/symbols.c +92 -0
- data/split/symbols.h +52 -0
- data/tests/dtable_test.data +6 -0
- data/tests/dvector_read_test.data +1 -0
- data/tests/dvector_test.data +101 -0
- data/tests/tc_Dtable.rb +221 -0
- data/tests/tc_Dvector.rb +791 -0
- data/tests/tc_FMkr.rb +162 -0
- data/tests/tc_Flate.rb +45 -0
- data/tests/tc_Function.rb +111 -0
- data/tests/ts_Tioga.rb +38 -0
- metadata +163 -0
@@ -0,0 +1,2224 @@
|
|
1
|
+
# FigMkr.rb
|
2
|
+
|
3
|
+
=begin
|
4
|
+
Copyright (C) 2005, 2006 Bill Paxton
|
5
|
+
|
6
|
+
This file is part of Tioga.
|
7
|
+
|
8
|
+
Tioga is free software; you can redistribute it and/or modify
|
9
|
+
it under the terms of the GNU General Library Public License as published
|
10
|
+
by the Free Software Foundation; either version 2 of the License, or
|
11
|
+
(at your option) any later version.
|
12
|
+
|
13
|
+
Tioga is distributed in the hope that it will be useful,
|
14
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
GNU Library General Public License for more details.
|
17
|
+
|
18
|
+
You should have received a copy of the GNU Library General Public License
|
19
|
+
along with Tioga; if not, write to the Free Software
|
20
|
+
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
21
|
+
=end
|
22
|
+
|
23
|
+
require 'Tioga/FigureConstants.rb'
|
24
|
+
|
25
|
+
module Tioga
|
26
|
+
class FigureMaker
|
27
|
+
|
28
|
+
include FigureConstants
|
29
|
+
|
30
|
+
@@default_figure_maker = nil
|
31
|
+
@@which_pdflatex = nil
|
32
|
+
@@initialized = false # set true by the C code when first make a figure
|
33
|
+
|
34
|
+
|
35
|
+
# The tag used for cvs export
|
36
|
+
CVS_TAG = "rel_1_4" # now manually cheating...
|
37
|
+
|
38
|
+
# Version now uses the CVS_TAG to create the version number. CVS_TAG should
|
39
|
+
# look like 'rel_1_1_0' for the 1.1.0 release.
|
40
|
+
def FigureMaker.version
|
41
|
+
CVS_TAG =~ /\D+(.*?)\s*\$?$/
|
42
|
+
version = $1.tr("-_", "..")
|
43
|
+
if version.length > 0
|
44
|
+
return version
|
45
|
+
else
|
46
|
+
return "SNV $Revision: 313 $" # Can't do better than that.
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def FigureMaker.default
|
51
|
+
@@default_figure_maker = FigureMaker.new if @@default_figure_maker == nil
|
52
|
+
@@default_figure_maker
|
53
|
+
end
|
54
|
+
|
55
|
+
def FigureMaker.default=(fm)
|
56
|
+
@@default_figure_maker = fm
|
57
|
+
end
|
58
|
+
|
59
|
+
def FigureMaker.pdflatex
|
60
|
+
@@which_pdflatex = 'pdflatex' if @@which_pdflatex == nil
|
61
|
+
@@which_pdflatex
|
62
|
+
end
|
63
|
+
|
64
|
+
def FigureMaker.pdflatex=(s)
|
65
|
+
@@which_pdflatex = s
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
def FigureMaker.make_name_lookup_hash(ary)
|
70
|
+
dict = Hash.new
|
71
|
+
ary.each { |name| dict[name] = true }
|
72
|
+
return dict
|
73
|
+
end
|
74
|
+
|
75
|
+
attr_accessor :style_filename
|
76
|
+
|
77
|
+
attr_accessor :legend_info
|
78
|
+
|
79
|
+
attr_reader :num_figures
|
80
|
+
|
81
|
+
attr_reader :figure_names
|
82
|
+
|
83
|
+
attr_reader :figure_pdfs
|
84
|
+
|
85
|
+
attr_reader :run_dir
|
86
|
+
|
87
|
+
attr_accessor :save_dir
|
88
|
+
|
89
|
+
attr_accessor :quiet_mode
|
90
|
+
|
91
|
+
attr_accessor :legend_defaults
|
92
|
+
|
93
|
+
attr_accessor :marker_defaults
|
94
|
+
|
95
|
+
attr_accessor :tex_preamble
|
96
|
+
|
97
|
+
attr_accessor :xaxis_numeric_label_tex
|
98
|
+
attr_accessor :yaxis_numeric_label_tex
|
99
|
+
|
100
|
+
attr_accessor :tex_fontsize
|
101
|
+
attr_accessor :tex_fontfamily
|
102
|
+
attr_accessor :tex_fontseries
|
103
|
+
attr_accessor :tex_fontshape
|
104
|
+
|
105
|
+
attr_accessor :default_page_width
|
106
|
+
attr_accessor :default_page_height
|
107
|
+
attr_accessor :default_frame_left
|
108
|
+
attr_accessor :default_frame_right
|
109
|
+
attr_accessor :default_frame_top
|
110
|
+
attr_accessor :default_frame_bottom
|
111
|
+
|
112
|
+
attr_accessor :num_error_lines
|
113
|
+
|
114
|
+
# Whether or not to create +save_dir+ if it doesn't exist
|
115
|
+
attr_accessor :create_save_dir
|
116
|
+
|
117
|
+
# Whether or not do do automatic cleanup of the files
|
118
|
+
attr_accessor :autocleanup
|
119
|
+
|
120
|
+
# Whether or not do do multithreading for parallel pdflatex calls
|
121
|
+
attr_accessor :multithreads_okay_for_tioga
|
122
|
+
|
123
|
+
|
124
|
+
|
125
|
+
# old preview attributes -- to be removed later
|
126
|
+
|
127
|
+
attr_accessor :model_number
|
128
|
+
attr_accessor :add_model_number
|
129
|
+
attr_accessor :need_to_reload_data
|
130
|
+
attr_accessor :auto_refresh_filename
|
131
|
+
|
132
|
+
#attr_accessor :tex_preview_documentclass
|
133
|
+
#attr_accessor :tex_preview_pagestyle
|
134
|
+
#attr_accessor :tex_preview_tiogafigure_command
|
135
|
+
attr_accessor :tex_xoffset
|
136
|
+
attr_accessor :tex_yoffset
|
137
|
+
|
138
|
+
#attr_accessor :tex_preview_paper_width
|
139
|
+
#attr_accessor :tex_preview_paper_height
|
140
|
+
#attr_accessor :tex_preview_hoffset
|
141
|
+
#attr_accessor :tex_preview_voffset
|
142
|
+
#attr_accessor :tex_preview_figure_width
|
143
|
+
#attr_accessor :tex_preview_figure_height
|
144
|
+
#attr_accessor :tex_preview_minwhitespace
|
145
|
+
#attr_accessor :tex_preview_fullpage
|
146
|
+
|
147
|
+
|
148
|
+
def reset_figures # set the state to default values
|
149
|
+
@figure_commands = []
|
150
|
+
@num_figures = 0
|
151
|
+
@create_save_dir = true # creates +save_dir+ by default
|
152
|
+
|
153
|
+
@name = nil
|
154
|
+
@auto_refresh_filename = nil
|
155
|
+
@figure_names = [ ]
|
156
|
+
@figure_pdfs = [ ]
|
157
|
+
@legend_info = [ ]
|
158
|
+
@run_dir = Dir.getwd
|
159
|
+
@save_dir = nil
|
160
|
+
@quiet_mode = false
|
161
|
+
@model_number = -1
|
162
|
+
@need_to_reload_data = true
|
163
|
+
@add_model_number = false
|
164
|
+
@tex_preview_documentclass = 'article'
|
165
|
+
@tex_preamble = '% start of preamble.
|
166
|
+
\usepackage[dvipsnames,usenames]{color} % need this for text colors
|
167
|
+
'
|
168
|
+
# \usepackage[pdftex]{geometry} % need this for setting page size for preview
|
169
|
+
# This has been commented out as it's place lie in the texout.c, for
|
170
|
+
# it's parameters to be set properly...
|
171
|
+
@tex_preview_pagestyle = 'empty'
|
172
|
+
@default_page_width = 72*5 # in big-points (1/72 inch)
|
173
|
+
@default_page_height = 72*5 # in big-points (1/72 inch)
|
174
|
+
|
175
|
+
@default_frame_left = 0.15 # as fraction of width from left edge
|
176
|
+
@default_frame_right = 0.85 # as fraction of width from left edge
|
177
|
+
@default_frame_top = 0.85 # as fraction of width from bottom edge
|
178
|
+
@default_frame_bottom = 0.15 # as fraction of width from bottom edge
|
179
|
+
|
180
|
+
@xaxis_numeric_label_tex = '$#1$'
|
181
|
+
@yaxis_numeric_label_tex = '$#1$'
|
182
|
+
|
183
|
+
@tex_preview_fullpage = true
|
184
|
+
@tex_preview_minwhitespace = nil # use default
|
185
|
+
|
186
|
+
@tex_preview_tiogafigure_command = 'tiogafigurescaledtofit'
|
187
|
+
@tex_preview_figure_width = '\paperwidth - 2in'
|
188
|
+
@tex_preview_figure_height = '\paperheight - 2in'
|
189
|
+
|
190
|
+
@num_error_lines = 10
|
191
|
+
|
192
|
+
@tex_xoffset = 0
|
193
|
+
@tex_yoffset = 0
|
194
|
+
|
195
|
+
@tex_preview_hoffset = '1in'
|
196
|
+
@tex_preview_voffset = '1in'
|
197
|
+
|
198
|
+
@tex_fontsize = '10.0'
|
199
|
+
@tex_fontfamily = 'rmdefault'
|
200
|
+
@tex_fontseries = 'mddefault'
|
201
|
+
@tex_fontshape = 'updefault'
|
202
|
+
|
203
|
+
@legend_defaults = {
|
204
|
+
'legend_top_margin' => 0.03,
|
205
|
+
'legend_bottom_margin' => 0.03,
|
206
|
+
'legend_left_margin' => 0.83,
|
207
|
+
'legend_right_margin' => 0.0,
|
208
|
+
'plot_top_margin' => 0.0,
|
209
|
+
'plot_bottom_margin' => 0.0,
|
210
|
+
'plot_left_margin' => 0.0,
|
211
|
+
'plot_right_margin' => 0.18,
|
212
|
+
'plot_scale' => 1,
|
213
|
+
'legend_scale' => 1 }
|
214
|
+
|
215
|
+
@marker_defaults = {
|
216
|
+
'fill_color' => Black,
|
217
|
+
'stroke_color' => Black,
|
218
|
+
'scale' => 1,
|
219
|
+
'angle' => 0,
|
220
|
+
'justification' => CENTERED,
|
221
|
+
'alignment' => ALIGNED_AT_MIDHEIGHT,
|
222
|
+
'horizontal_scale' => 1.0,
|
223
|
+
'vertical_scale' => 1.0,
|
224
|
+
'italic_angle' => 0.0,
|
225
|
+
'ascent_angle' => 0.0 }
|
226
|
+
|
227
|
+
@eval_command = nil
|
228
|
+
|
229
|
+
@enter_show_plot_function = nil
|
230
|
+
@exit_show_plot_function = nil
|
231
|
+
|
232
|
+
@enter_subfigure_function = nil
|
233
|
+
@exit_subfigure_function = nil
|
234
|
+
|
235
|
+
@enter_subplot_function = nil
|
236
|
+
@exit_subplot_function = nil
|
237
|
+
|
238
|
+
@enter_context_function = nil
|
239
|
+
@exit_context_function = nil
|
240
|
+
|
241
|
+
@enter_page_function = lambda { default_enter_page_function }
|
242
|
+
@exit_page_function = nil
|
243
|
+
|
244
|
+
@tex_preview_paper_width = '297mm'
|
245
|
+
@tex_preview_paper_height = '210mm'
|
246
|
+
|
247
|
+
@plot_box_command = lambda { show_plot_box }
|
248
|
+
|
249
|
+
# Automatic cleanup of by default
|
250
|
+
@autocleanup = true
|
251
|
+
|
252
|
+
# multithreads by default
|
253
|
+
@multithreads_okay_for_tioga = true
|
254
|
+
|
255
|
+
end
|
256
|
+
|
257
|
+
def initialize
|
258
|
+
reset_figures
|
259
|
+
end
|
260
|
+
|
261
|
+
|
262
|
+
def reset_state
|
263
|
+
reset_figures
|
264
|
+
end
|
265
|
+
|
266
|
+
|
267
|
+
def tex_xaxis_numeric_label
|
268
|
+
self.xaxis_numeric_label_tex
|
269
|
+
end
|
270
|
+
|
271
|
+
def tex_xaxis_numeric_label=(str)
|
272
|
+
self.xaxis_numeric_label_tex = str
|
273
|
+
end
|
274
|
+
|
275
|
+
|
276
|
+
def tex_yaxis_numeric_label
|
277
|
+
self.yaxis_numeric_label_tex
|
278
|
+
end
|
279
|
+
|
280
|
+
def tex_yaxis_numeric_label=(str)
|
281
|
+
self.yaxis_numeric_label_tex = str
|
282
|
+
end
|
283
|
+
|
284
|
+
|
285
|
+
def default_line_scale=(s)
|
286
|
+
self.rescale_lines(s)
|
287
|
+
end
|
288
|
+
|
289
|
+
def default_enter_page_function
|
290
|
+
page_setup(self.default_page_width,self.default_page_height)
|
291
|
+
set_frame_sides(self.default_frame_left,self.default_frame_right,
|
292
|
+
self.default_frame_top,self.default_frame_bottom)
|
293
|
+
end
|
294
|
+
|
295
|
+
def set_default_font_size(size, update_preview_size_string = true)
|
296
|
+
private_set_default_font_size(size)
|
297
|
+
return unless update_preview_size_string == true
|
298
|
+
@tex_preview_fontsize = sprintf("%0.2fbp", size)
|
299
|
+
end
|
300
|
+
|
301
|
+
def page_setup(width,height) # in big-points (1/72 inch)
|
302
|
+
set_device_pagesize(width*10-1, height*10-1)
|
303
|
+
@tex_preview_figure_width = width.to_s + 'bp'
|
304
|
+
@tex_preview_figure_height = height.to_s + 'bp'
|
305
|
+
@tex_preview_paper_height = "#{height}bp"
|
306
|
+
@tex_preview_paper_width = "#{width}bp"
|
307
|
+
@tex_preview_tiogafigure_command = 'tiogafigureshow'
|
308
|
+
@tex_preview_fullpage = false
|
309
|
+
@tex_xoffset = 0
|
310
|
+
@tex_yoffset = 0
|
311
|
+
@tex_preview_hoffset = '0in'
|
312
|
+
@tex_preview_voffset = '0in'
|
313
|
+
set_frame_sides(0,1,1,0)
|
314
|
+
set_bounds(
|
315
|
+
'left_boundary' => 0, 'right_boundary' => 1,
|
316
|
+
'top_boundary' => 1, 'bottom_boundary' => 0)
|
317
|
+
self.update_bbox(0,0)
|
318
|
+
self.update_bbox(0,1)
|
319
|
+
self.update_bbox(1,0)
|
320
|
+
self.update_bbox(1,1)
|
321
|
+
end
|
322
|
+
|
323
|
+
def tex_preview_preamble # for backward compatibility
|
324
|
+
self.tex_preamble
|
325
|
+
end
|
326
|
+
|
327
|
+
def tex_preview_preamble=(str)
|
328
|
+
self.tex_preamble = str
|
329
|
+
end
|
330
|
+
|
331
|
+
def figure_name(num)
|
332
|
+
@figure_names[num]
|
333
|
+
end
|
334
|
+
|
335
|
+
def figure_pdf(name)
|
336
|
+
if name.kind_of?(Integer)
|
337
|
+
num = name
|
338
|
+
name = @figure_names[num]
|
339
|
+
else
|
340
|
+
num = @figure_names.index(name)
|
341
|
+
end
|
342
|
+
return nil if num == nil
|
343
|
+
@figure_pdfs[num]
|
344
|
+
end
|
345
|
+
|
346
|
+
def line_color
|
347
|
+
self.stroke_color
|
348
|
+
end
|
349
|
+
|
350
|
+
def line_color=(color)
|
351
|
+
self.stroke_color=(color)
|
352
|
+
end
|
353
|
+
|
354
|
+
def stroke_width
|
355
|
+
self.line_width
|
356
|
+
end
|
357
|
+
|
358
|
+
def stroke_width=(width)
|
359
|
+
self.line_width=(width)
|
360
|
+
end
|
361
|
+
|
362
|
+
|
363
|
+
def opacity_for_stroke
|
364
|
+
self.stroke_opacity
|
365
|
+
end
|
366
|
+
|
367
|
+
def opacity_for_stroke=(frac)
|
368
|
+
self.stroke_opacity=(frac)
|
369
|
+
end
|
370
|
+
|
371
|
+
def opacity_for_fill
|
372
|
+
self.fill_opacity
|
373
|
+
end
|
374
|
+
|
375
|
+
def opacity_for_fill=(frac)
|
376
|
+
self.fill_opacity=(frac)
|
377
|
+
end
|
378
|
+
|
379
|
+
|
380
|
+
def transparency_for_stroke
|
381
|
+
1.0 - self.stroke_opacity
|
382
|
+
end
|
383
|
+
|
384
|
+
def transparency_for_stroke=(frac)
|
385
|
+
self.stroke_opacity=(1.0 - frac)
|
386
|
+
end
|
387
|
+
|
388
|
+
def transparency_for_fill
|
389
|
+
1.0 - self.fill_opacity
|
390
|
+
end
|
391
|
+
|
392
|
+
def transparency_for_fill=(frac)
|
393
|
+
self.fill_opacity=(1.0 - frac)
|
394
|
+
end
|
395
|
+
|
396
|
+
|
397
|
+
def fill_transparency
|
398
|
+
self.transparency_for_fill
|
399
|
+
end
|
400
|
+
|
401
|
+
def fill_transparency=(frac)
|
402
|
+
self.transparency_for_fill = frac
|
403
|
+
end
|
404
|
+
|
405
|
+
def stroke_transparency
|
406
|
+
self.transparency_for_stroke
|
407
|
+
end
|
408
|
+
|
409
|
+
def stroke_transparency=(frac)
|
410
|
+
self.transparency_for_stroke = frac
|
411
|
+
end
|
412
|
+
|
413
|
+
|
414
|
+
def title_visible=(bool)
|
415
|
+
if bool != false
|
416
|
+
raise "Sorry: can only set 'title_visible' to false."
|
417
|
+
end
|
418
|
+
self.no_title
|
419
|
+
end
|
420
|
+
|
421
|
+
def xlabel_visible=(bool)
|
422
|
+
if bool != false
|
423
|
+
raise "Sorry: can only set 'xlabel_visible' to false."
|
424
|
+
end
|
425
|
+
self.no_xlabel
|
426
|
+
end
|
427
|
+
|
428
|
+
def ylabel_visible=(bool)
|
429
|
+
if bool != false
|
430
|
+
raise "Sorry: can only set 'ylabel_visible' to false."
|
431
|
+
end
|
432
|
+
self.no_ylabel
|
433
|
+
end
|
434
|
+
|
435
|
+
def xaxis_visible=(bool)
|
436
|
+
if bool != false
|
437
|
+
raise "Sorry: can only set 'xaxis_visible' to false."
|
438
|
+
end
|
439
|
+
self.no_xaxis
|
440
|
+
end
|
441
|
+
|
442
|
+
def yaxis_visible=(bool)
|
443
|
+
if bool != false
|
444
|
+
raise "Sorry: can only set 'yaxis_visible' to false."
|
445
|
+
end
|
446
|
+
self.no_yaxis
|
447
|
+
end
|
448
|
+
|
449
|
+
def left_edge_visible=(bool)
|
450
|
+
if bool != false
|
451
|
+
raise "Sorry: can only set 'left_edge_visible' to false."
|
452
|
+
end
|
453
|
+
self.no_left_edge
|
454
|
+
end
|
455
|
+
|
456
|
+
def right_edge_visible=(bool)
|
457
|
+
if bool != false
|
458
|
+
raise "Sorry: can only set 'right_edge_visible' to false."
|
459
|
+
end
|
460
|
+
self.no_right_edge
|
461
|
+
end
|
462
|
+
|
463
|
+
def top_edge_visible=(bool)
|
464
|
+
if bool != false
|
465
|
+
raise "Sorry: can only set 'top_edge_visible' to false."
|
466
|
+
end
|
467
|
+
self.no_top_edge
|
468
|
+
end
|
469
|
+
|
470
|
+
def bottom_edge_visible=(bool)
|
471
|
+
if bool != false
|
472
|
+
raise "Sorry: can only set 'bottom_edge_visible' to false."
|
473
|
+
end
|
474
|
+
self.no_bottom_edge
|
475
|
+
end
|
476
|
+
|
477
|
+
Required = '!required!'.to_sym
|
478
|
+
|
479
|
+
# A helper function to prepare a default hash for a function, and to check
|
480
|
+
# for extraneous or missing arguments. It takes two arguments:
|
481
|
+
# * _dict_, the user-provided dictionnary to check and complete
|
482
|
+
# * _specs_, a hash representing the valid arguments and their default
|
483
|
+
# value.
|
484
|
+
# Symbols in the _specs_ hash have special meanings:
|
485
|
+
# * a normal symbol means: call self.symbol to get the default value. If
|
486
|
+
# this call fails with a MethodMissing error, the symbol is returned.
|
487
|
+
# * a '->stuff'.to_sym symbol means: copy the value from the value
|
488
|
+
# associated with the key 'stuff'.
|
489
|
+
# * a '!required!' symbol means that if the key is missing from
|
490
|
+
# the original, raise an exception. (use the Required consant for that)
|
491
|
+
#
|
492
|
+
# You should find a few examples in the constants of this class...
|
493
|
+
#
|
494
|
+
# This function modifies _dict_ in place !
|
495
|
+
def prepare_argument_hash(spec, dict, strict = true)
|
496
|
+
for key in dict.keys
|
497
|
+
if (not spec.key?(key)) and strict
|
498
|
+
warn "Unkown key #{key} for #{caller.first}, information removed"
|
499
|
+
dict.delete(key)
|
500
|
+
end
|
501
|
+
end
|
502
|
+
for key in spec.keys
|
503
|
+
dict[key] = argument_value(spec, dict, key)
|
504
|
+
end
|
505
|
+
return dict
|
506
|
+
end
|
507
|
+
|
508
|
+
# Returns the value associated with the given key. Default value is
|
509
|
+
# returned in case the key is missing from the _dict_ hash. See
|
510
|
+
def argument_value(spec, dict, key)
|
511
|
+
return dict[key] if dict.key?(key)
|
512
|
+
raise "Unknown key asked for" unless spec.key?(key)
|
513
|
+
default = spec[key]
|
514
|
+
return default unless default.is_a?(::Symbol)
|
515
|
+
if default.to_s =~ /^->(.*)/ # Special symbol:
|
516
|
+
# return the value of the pointed key
|
517
|
+
return argument_value(spec, dict, $1)
|
518
|
+
elsif default == Required
|
519
|
+
raise "Required key #{key} is missing from #{dict.inspect}"
|
520
|
+
end
|
521
|
+
begin
|
522
|
+
return self.send(default)
|
523
|
+
rescue NoMethodError
|
524
|
+
return default
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
@@keys_for_save_legend_info = FigureMaker.make_name_lookup_hash(['text', 'dy',
|
529
|
+
'line_color', 'stroke_color', 'line_width', 'stroke_width',
|
530
|
+
'line_cap', 'line_type', 'marker', 'marker_color', 'marker_scale', 'marker_dict' ])
|
531
|
+
|
532
|
+
Save_legend_info_args = {
|
533
|
+
'text' => nil,
|
534
|
+
'dy' => :legend_text_dy,
|
535
|
+
'line_color' => :line_color,
|
536
|
+
'line_width' => :line_width,
|
537
|
+
'line_cap' => :line_cap,
|
538
|
+
'line_type' => :line_type,
|
539
|
+
'stroke_color' => nil,
|
540
|
+
'stroke_width' => nil,
|
541
|
+
'marker' => nil,
|
542
|
+
'marker_dict' => nil, # use again #prepare_argument_hash ?
|
543
|
+
'marker_color' => nil,
|
544
|
+
'marker_scale' => nil,
|
545
|
+
}
|
546
|
+
|
547
|
+
def save_legend_info(arg)
|
548
|
+
if arg.kind_of?String
|
549
|
+
dict = { 'text' => arg }
|
550
|
+
else
|
551
|
+
dict = arg
|
552
|
+
end
|
553
|
+
prepare_argument_hash(Save_legend_info_args, dict)
|
554
|
+
if dict['marker_dict'] == nil
|
555
|
+
dict['marker'] = false if dict['marker'] == nil
|
556
|
+
dict['marker_color'] = self.line_color if dict['marker_color'] == nil
|
557
|
+
dict['marker_scale'] = 0.5 if dict['marker_scale'] == nil
|
558
|
+
end
|
559
|
+
@legend_info << dict
|
560
|
+
end
|
561
|
+
|
562
|
+
def show_legend
|
563
|
+
char_dx = self.default_text_height_dx
|
564
|
+
char_dy = self.default_text_height_dy
|
565
|
+
line_ht_x = char_dx * self.legend_scale
|
566
|
+
line_ht_y = char_dy * self.legend_scale
|
567
|
+
x = self.legend_text_xstart*line_ht_x
|
568
|
+
ltw = self.legend_text_width
|
569
|
+
if ltw < 0
|
570
|
+
if @pr_margin == 0
|
571
|
+
ltw = 1
|
572
|
+
else
|
573
|
+
ltw = 7
|
574
|
+
end
|
575
|
+
end
|
576
|
+
xright = x + ltw*line_ht_x
|
577
|
+
y = 1.0 - self.legend_text_ystart*line_ht_y
|
578
|
+
update_bbox(xright, y)
|
579
|
+
dy = -self.legend_text_dy*line_ht_y
|
580
|
+
line_x0 = self.legend_line_x0*line_ht_x
|
581
|
+
line_x1 = self.legend_line_x1*line_ht_x
|
582
|
+
line_dy = self.legend_line_dy*line_ht_y
|
583
|
+
self.label_left_margin = self.label_right_margin = self.label_top_margin = self.label_bottom_margin = -1e99
|
584
|
+
@legend_info.each do |dict|
|
585
|
+
text = dict['text']
|
586
|
+
if text != nil
|
587
|
+
show_text('text' => text,
|
588
|
+
'x' => x, 'y' => y, 'scale' => self.legend_scale,
|
589
|
+
'justification' => self.legend_justification,
|
590
|
+
'alignment' => self.legend_alignment)
|
591
|
+
end
|
592
|
+
line_width = dict['line_width']
|
593
|
+
if line_width >= 0
|
594
|
+
self.line_color = dict['line_color']
|
595
|
+
self.line_width = dict['line_width']
|
596
|
+
self.line_cap = dict['line_cap']
|
597
|
+
self.line_type = dict['line_type']
|
598
|
+
stroke_line(line_x0, y+line_dy, line_x1, y+line_dy)
|
599
|
+
end
|
600
|
+
# place any marker right in the middle of the line
|
601
|
+
if dict['marker_dict'] != nil
|
602
|
+
marker_dict = dict['marker_dict']
|
603
|
+
marker_dict['x'] = 0.5*(line_x0 + line_x1)
|
604
|
+
marker_dict['y'] = y+line_dy
|
605
|
+
show_marker(marker_dict)
|
606
|
+
elsif dict['marker']
|
607
|
+
show_marker( 'x' => 0.5*(line_x0 + line_x1),
|
608
|
+
'y' => (y+line_dy),
|
609
|
+
'marker' => dict['marker'],
|
610
|
+
'color' => dict['marker_color'],
|
611
|
+
'scale' => dict['marker_scale'])
|
612
|
+
end
|
613
|
+
dy = dict['dy']; dy = 1 if dy == nil
|
614
|
+
y -= line_ht_y * dy
|
615
|
+
end
|
616
|
+
end
|
617
|
+
|
618
|
+
def legend_height
|
619
|
+
height = 0.0
|
620
|
+
@legend_info.each { |dict| height += dict['dy'] }
|
621
|
+
return height
|
622
|
+
end
|
623
|
+
|
624
|
+
def reset_legend_info
|
625
|
+
@legend_info = [ ]
|
626
|
+
end
|
627
|
+
|
628
|
+
def save_legend_separator(dy)
|
629
|
+
save_legend_info('dy' => dy, 'line_width' => -1)
|
630
|
+
end
|
631
|
+
|
632
|
+
def do_box_labels(title, xlabel, ylabel)
|
633
|
+
if title != nil
|
634
|
+
show_title(title); no_title
|
635
|
+
end
|
636
|
+
if xlabel != nil
|
637
|
+
show_xlabel(xlabel); no_xlabel
|
638
|
+
end
|
639
|
+
if ylabel != nil
|
640
|
+
show_ylabel(ylabel); no_ylabel
|
641
|
+
end
|
642
|
+
end
|
643
|
+
|
644
|
+
def set_aspect_ratio_relative_to_frame(width_to_height)
|
645
|
+
if width_to_height >= 1
|
646
|
+
margin = (1 - 1.0/width_to_height) * 0.5
|
647
|
+
set_subframe('top_margin' => margin, 'bottom_margin' => margin)
|
648
|
+
else
|
649
|
+
margin = (1 - width_to_height) * 0.5
|
650
|
+
set_subframe('left_margin' => margin, 'right_margin' => margin)
|
651
|
+
end
|
652
|
+
end
|
653
|
+
|
654
|
+
def set_physical_aspect_ratio(width_to_height)
|
655
|
+
wd = convert_frame_to_page_dx(1)
|
656
|
+
ht = convert_frame_to_page_dy(1)
|
657
|
+
set_aspect_ratio_relative_to_frame(width_to_height * ht / wd)
|
658
|
+
end
|
659
|
+
|
660
|
+
def set_aspect_ratio(width_to_height)
|
661
|
+
set_physical_aspect_ratio(width_to_height)
|
662
|
+
end
|
663
|
+
|
664
|
+
def set_landscape
|
665
|
+
set_aspect_ratio(11.0/8.5)
|
666
|
+
end
|
667
|
+
|
668
|
+
def landscape
|
669
|
+
set_landscape
|
670
|
+
end
|
671
|
+
|
672
|
+
def set_portrait
|
673
|
+
set_aspect_ratio(8.5/11.0)
|
674
|
+
end
|
675
|
+
|
676
|
+
def portrait
|
677
|
+
set_portrait
|
678
|
+
end
|
679
|
+
|
680
|
+
@@keys_for_set_subframe = FigureMaker.make_name_lookup_hash(['margins',
|
681
|
+
'left_margin', 'right_margin', 'top_margin', 'bottom_margin',
|
682
|
+
'left', 'right', 'plot_left_margin', 'top', 'bottom' ])
|
683
|
+
def set_subframe(dict=nil)
|
684
|
+
return if dict == nil
|
685
|
+
if dict.kind_of?Array and dict.size == 4
|
686
|
+
left = dict[0]
|
687
|
+
right = dict[1]
|
688
|
+
top = dict[2]
|
689
|
+
bottom = dict[3]
|
690
|
+
else
|
691
|
+
check_dict(dict, @@keys_for_set_subframe, 'set_subframe')
|
692
|
+
if (margins = dict['margins']) != nil and margins.kind_of?Array and margins.size == 4
|
693
|
+
left = margins[0]
|
694
|
+
right = margins[1]
|
695
|
+
top = margins[2]
|
696
|
+
bottom = margins[3]
|
697
|
+
else
|
698
|
+
left = alt_names(dict, 'left_margin', 'left')
|
699
|
+
right = alt_names(dict, 'right_margin', 'right')
|
700
|
+
top = alt_names(dict, 'top_margin', 'top')
|
701
|
+
bottom = alt_names(dict, 'bottom_margin', 'bottom')
|
702
|
+
end
|
703
|
+
end
|
704
|
+
left = 0 if left == nil
|
705
|
+
right = 0 if right == nil
|
706
|
+
top = 0 if top == nil
|
707
|
+
bottom = 0 if bottom == nil
|
708
|
+
private_set_subframe(left, right, top, bottom)
|
709
|
+
end
|
710
|
+
|
711
|
+
@@keys_for_set_bounds = FigureMaker.make_name_lookup_hash([
|
712
|
+
'bounds_left', 'bounds_right', 'bounds_top', 'bounds_bottom',
|
713
|
+
'left_boundary', 'right_boundary', 'top_boundary', 'bottom_boundary', 'boundaries' ])
|
714
|
+
def set_bounds(dict=nil)
|
715
|
+
return if dict == nil
|
716
|
+
if dict.kind_of?Array and dict.size == 4
|
717
|
+
left = dict[0]
|
718
|
+
right = dict[1]
|
719
|
+
top = dict[2]
|
720
|
+
bottom = dict[3]
|
721
|
+
else
|
722
|
+
check_dict(dict, @@keys_for_set_bounds, 'set_bounds')
|
723
|
+
if (boundaries = dict['boundaries']) != nil and boundaries.kind_of?Array and boundaries.size == 4
|
724
|
+
left = boundaries[0]
|
725
|
+
right = boundaries[1]
|
726
|
+
top = boundaries[2]
|
727
|
+
bottom = boundaries[3]
|
728
|
+
else
|
729
|
+
left = complain_if_missing_numeric_arg(dict,'bounds_left','left_boundary','set_bounds')
|
730
|
+
right = complain_if_missing_numeric_arg(dict,'bounds_right','right_boundary','set_bounds')
|
731
|
+
top = complain_if_missing_numeric_arg(dict,'bounds_top','top_boundary','set_bounds')
|
732
|
+
bottom = complain_if_missing_numeric_arg(dict,'bounds_bottom','bottom_boundary','set_bounds')
|
733
|
+
end
|
734
|
+
end
|
735
|
+
private_set_bounds(left, right, top, bottom)
|
736
|
+
end
|
737
|
+
|
738
|
+
|
739
|
+
def trace_cmd_no_arg(entry_function, exit_function, &cmd)
|
740
|
+
|
741
|
+
unless entry_function == nil
|
742
|
+
begin
|
743
|
+
entry_function.call
|
744
|
+
rescue Exception => er
|
745
|
+
report_error(er, nil)
|
746
|
+
end
|
747
|
+
end
|
748
|
+
|
749
|
+
result = cmd.call
|
750
|
+
|
751
|
+
unless exit_function == nil
|
752
|
+
begin
|
753
|
+
exit_function.call
|
754
|
+
rescue Exception => er
|
755
|
+
report_error(er, nil)
|
756
|
+
end
|
757
|
+
end
|
758
|
+
|
759
|
+
return result
|
760
|
+
|
761
|
+
end
|
762
|
+
|
763
|
+
|
764
|
+
def trace_cmd_one_arg(entry_function, exit_function, arg, &cmd)
|
765
|
+
|
766
|
+
unless entry_function == nil
|
767
|
+
begin
|
768
|
+
entry_function.call(arg)
|
769
|
+
rescue Exception => er
|
770
|
+
report_error(er, nil)
|
771
|
+
end
|
772
|
+
end
|
773
|
+
|
774
|
+
result = cmd.call
|
775
|
+
|
776
|
+
unless exit_function == nil
|
777
|
+
begin
|
778
|
+
exit_function.call(arg)
|
779
|
+
rescue Exception => er
|
780
|
+
report_error(er, nil)
|
781
|
+
end
|
782
|
+
end
|
783
|
+
|
784
|
+
return result
|
785
|
+
|
786
|
+
end
|
787
|
+
|
788
|
+
|
789
|
+
def show_plot(bounds=nil,&cmd)
|
790
|
+
trace_cmd_one_arg(@enter_show_plot_function, @exit_show_plot_function, bounds) {
|
791
|
+
set_bounds(bounds)
|
792
|
+
context { clip_to_frame; cmd.call }
|
793
|
+
show_plot_box
|
794
|
+
}
|
795
|
+
end
|
796
|
+
|
797
|
+
def subfigure(margins=nil,&cmd)
|
798
|
+
trace_cmd_one_arg(@enter_subfigure_function, @exit_subfigure_function, margins) {
|
799
|
+
context { doing_subfigure; set_subframe(margins); cmd.call }
|
800
|
+
}
|
801
|
+
end
|
802
|
+
|
803
|
+
def root_plot
|
804
|
+
return ! self.in_subplot
|
805
|
+
end
|
806
|
+
|
807
|
+
def in_subfigure
|
808
|
+
return ! self.root_figure
|
809
|
+
end
|
810
|
+
|
811
|
+
def subplot(margins=nil,&cmd)
|
812
|
+
trace_cmd_one_arg(@enter_subplot_function, @exit_subplot_function, margins) {
|
813
|
+
reset_legend_info
|
814
|
+
context { doing_subplot; set_subframe(margins); cmd.call }
|
815
|
+
}
|
816
|
+
end
|
817
|
+
|
818
|
+
|
819
|
+
@@keys_for_column_margins = FigureMaker.make_name_lookup_hash([
|
820
|
+
'left_margin', 'right_margin', 'column_margin', 'column',
|
821
|
+
'first_column', 'last_column', 'num_columns' ])
|
822
|
+
def column_margins(dict)
|
823
|
+
check_dict(dict, @@keys_for_column_margins, 'column_margins')
|
824
|
+
left_margin = get_if_given_else_default(dict, 'left_margin', 0)
|
825
|
+
right_margin = get_if_given_else_default(dict, 'right_margin', 0)
|
826
|
+
num_columns = dict['num_columns']
|
827
|
+
first_column = dict['first_column']
|
828
|
+
last_column = dict['last_column']
|
829
|
+
column_margin = dict['column_margin']
|
830
|
+
column = dict['column']
|
831
|
+
if column != nil
|
832
|
+
first_column = last_column = column
|
833
|
+
end
|
834
|
+
first_column = 1 if first_column == nil
|
835
|
+
last_column = first_column if last_column == nil
|
836
|
+
first_column -= 1; last_column -= 1 # switch to 0 for left column instead of 1
|
837
|
+
num_columns = last_column + 1 if num_columns == nil
|
838
|
+
column_margin = 0 if column_margin == nil
|
839
|
+
columns_after = num_columns - last_column - 1
|
840
|
+
columns_before = first_column
|
841
|
+
column_width = (1.0 - (left_margin + right_margin + column_margin * (num_columns-1))) / num_columns
|
842
|
+
left_margin = left_margin + columns_before * (column_width + column_margin)
|
843
|
+
right_margin = right_margin + columns_after * (column_width + column_margin)
|
844
|
+
return { 'left_margin' => left_margin, 'right_margin' => right_margin }
|
845
|
+
end
|
846
|
+
|
847
|
+
@@keys_for_row_margins = FigureMaker.make_name_lookup_hash([
|
848
|
+
'top_margin', 'bottom_margin', 'row_margin', 'row',
|
849
|
+
'first_row', 'last_row', 'num_rows' ])
|
850
|
+
def row_margins(dict)
|
851
|
+
check_dict(dict, @@keys_for_row_margins, 'row_margins')
|
852
|
+
top_margin = get_if_given_else_default(dict, 'top_margin', 0)
|
853
|
+
bottom_margin = get_if_given_else_default(dict, 'bottom_margin', 0)
|
854
|
+
num_rows = dict['num_rows']
|
855
|
+
first_row = dict['first_row']
|
856
|
+
last_row = dict['last_row']
|
857
|
+
row_margin = dict['row_margin']
|
858
|
+
row = dict['row']
|
859
|
+
if row != nil
|
860
|
+
first_row = last_row = row
|
861
|
+
end
|
862
|
+
first_row = 1 if first_row == nil
|
863
|
+
last_row = first_row if last_row == nil
|
864
|
+
first_row -= 1; last_row -= 1 # switch to 0 for top row instead of 1
|
865
|
+
num_rows = last_row + 1 if num_rows == nil
|
866
|
+
row_margin = 0 if row_margin == nil
|
867
|
+
rows_below = num_rows - last_row - 1
|
868
|
+
rows_above = first_row
|
869
|
+
row_width = (1.0 - (top_margin + bottom_margin + row_margin * (num_rows-1))) / num_rows
|
870
|
+
top_margin = top_margin + rows_above * (row_width + row_margin)
|
871
|
+
bottom_margin = bottom_margin + rows_below * (row_width + row_margin)
|
872
|
+
return { 'top_margin' => top_margin, 'bottom_margin' => bottom_margin }
|
873
|
+
end
|
874
|
+
|
875
|
+
|
876
|
+
def context(&cmd)
|
877
|
+
trace_cmd_no_arg(@enter_context_function, @exit_context_function) {
|
878
|
+
private_context(cmd) }
|
879
|
+
end
|
880
|
+
|
881
|
+
|
882
|
+
def rescale(factor)
|
883
|
+
rescale_text(factor)
|
884
|
+
rescale_lines(factor)
|
885
|
+
end
|
886
|
+
|
887
|
+
def show_plot_box
|
888
|
+
show_xaxis
|
889
|
+
show_yaxis
|
890
|
+
show_edges
|
891
|
+
show_title
|
892
|
+
show_xlabel
|
893
|
+
show_ylabel
|
894
|
+
end
|
895
|
+
|
896
|
+
def show_xaxis
|
897
|
+
show_axis(self.xaxis_loc) if self.xaxis_visible
|
898
|
+
end
|
899
|
+
|
900
|
+
def show_yaxis
|
901
|
+
show_axis(self.yaxis_loc) if self.yaxis_visible
|
902
|
+
end
|
903
|
+
|
904
|
+
def show_edges
|
905
|
+
show_top_edge
|
906
|
+
show_bottom_edge
|
907
|
+
show_left_edge
|
908
|
+
show_right_edge
|
909
|
+
end
|
910
|
+
|
911
|
+
def show_top_edge
|
912
|
+
show_edge(TOP) if self.top_edge_visible && self.xaxis_loc != TOP
|
913
|
+
end
|
914
|
+
|
915
|
+
def show_bottom_edge
|
916
|
+
show_edge(BOTTOM) if self.bottom_edge_visible && self.xaxis_loc != BOTTOM
|
917
|
+
end
|
918
|
+
|
919
|
+
def show_left_edge
|
920
|
+
show_edge(LEFT) if self.left_edge_visible && self.yaxis_loc != LEFT
|
921
|
+
end
|
922
|
+
|
923
|
+
def show_right_edge
|
924
|
+
show_edge(RIGHT) if self.right_edge_visible && self.yaxis_loc != RIGHT
|
925
|
+
end
|
926
|
+
|
927
|
+
def show_title(text = nil)
|
928
|
+
text = self.title if text == nil
|
929
|
+
if (self.title_visible && text != nil)
|
930
|
+
show_text('text' => text,
|
931
|
+
'side' => self.title_side, 'position' => self.title_position,
|
932
|
+
'scale' => self.title_scale, 'shift' => self.title_shift,
|
933
|
+
'angle' => self.title_angle, 'alignment' => self.title_alignment,
|
934
|
+
'justification' => self.title_justification,
|
935
|
+
'color' => self.title_color)
|
936
|
+
end
|
937
|
+
end
|
938
|
+
|
939
|
+
def show_xlabel(text = nil)
|
940
|
+
text = self.xlabel if text == nil
|
941
|
+
if (self.xlabel_visible && text != nil)
|
942
|
+
angle = self.xlabel_angle
|
943
|
+
side = self.xlabel_side
|
944
|
+
shift = self.xlabel_shift
|
945
|
+
shift -= 0.5 if (side == TOP && angle == 0)
|
946
|
+
show_text('text' => text,
|
947
|
+
'side' => side, 'position' => self.xlabel_position,
|
948
|
+
'scale' => self.xlabel_scale, 'shift' => shift,
|
949
|
+
'angle' => angle, 'alignment' => self.xlabel_alignment,
|
950
|
+
'justification' => self.xlabel_justification,
|
951
|
+
'color' => self.xlabel_color)
|
952
|
+
end
|
953
|
+
end
|
954
|
+
|
955
|
+
def show_ylabel(text = nil)
|
956
|
+
text = self.ylabel if text == nil
|
957
|
+
if (self.ylabel_visible && text != nil)
|
958
|
+
angle = self.ylabel_angle
|
959
|
+
side = self.ylabel_side
|
960
|
+
shift = self.ylabel_shift
|
961
|
+
shift += 0.5 if (side == RIGHT && angle == 0)
|
962
|
+
show_text('text' => text,
|
963
|
+
'side' => side, 'position' => self.ylabel_position,
|
964
|
+
'scale' => self.ylabel_scale, 'shift' => shift,
|
965
|
+
'angle' => angle, 'alignment' => self.ylabel_alignment,
|
966
|
+
'justification' => self.ylabel_justification,
|
967
|
+
'color' => self.ylabel_color)
|
968
|
+
end
|
969
|
+
end
|
970
|
+
|
971
|
+
@@keys_for_show_plot_with_legend = FigureMaker.make_name_lookup_hash([
|
972
|
+
'legend_top_margin', 'legend_bottom_margin', 'legend_left_margin', 'legend_right_margin',
|
973
|
+
'plot_top_margin', 'plot_bottom_margin', 'plot_left_margin', 'plot_right_margin',
|
974
|
+
'plot_scale', 'legend_scale' ])
|
975
|
+
def show_plot_with_legend(dict=nil, &cmd)
|
976
|
+
check_dict(dict, @@keys_for_show_plot_with_legend, 'show_plot_with_legend') if dict != nil
|
977
|
+
legend_top_margin = get_if_given_else_use_default_dict(dict, 'legend_top_margin', @legend_defaults)
|
978
|
+
legend_bottom_margin = get_if_given_else_use_default_dict(dict, 'legend_bottom_margin', @legend_defaults)
|
979
|
+
legend_left_margin = get_if_given_else_use_default_dict(dict, 'legend_left_margin', @legend_defaults)
|
980
|
+
legend_right_margin = get_if_given_else_use_default_dict(dict, 'legend_right_margin', @legend_defaults)
|
981
|
+
legend_scale = get_if_given_else_use_default_dict(dict, 'legend_scale', @legend_defaults)
|
982
|
+
plot_top_margin = get_if_given_else_use_default_dict(dict, 'plot_top_margin', @legend_defaults)
|
983
|
+
plot_bottom_margin = get_if_given_else_use_default_dict(dict, 'plot_bottom_margin', @legend_defaults)
|
984
|
+
plot_left_margin = get_if_given_else_use_default_dict(dict, 'plot_left_margin', @legend_defaults)
|
985
|
+
plot_right_margin = get_if_given_else_use_default_dict(dict, 'plot_right_margin', @legend_defaults)
|
986
|
+
plot_scale = get_if_given_else_use_default_dict(dict, 'plot_scale', @legend_defaults)
|
987
|
+
reset_legend_info
|
988
|
+
rescale(plot_scale)
|
989
|
+
subplot([plot_left_margin, plot_right_margin, plot_top_margin, plot_bottom_margin]) { cmd.call }
|
990
|
+
set_subframe([legend_left_margin, legend_right_margin, legend_top_margin, legend_bottom_margin])
|
991
|
+
rescale(legend_scale) # note that legend_scale is an addition to the plot_scale, not a replacement
|
992
|
+
@pr_margin = plot_right_margin
|
993
|
+
show_legend
|
994
|
+
end
|
995
|
+
|
996
|
+
def append_points_with_gaps_to_path(xs, ys, gaps, close_subpaths = false)
|
997
|
+
private_append_points_with_gaps_to_path(xs, ys, gaps, close_subpaths)
|
998
|
+
end
|
999
|
+
|
1000
|
+
def show_polyline(xs, ys, color = nil, legend = nil, type = nil, gaps = nil, close_subpaths = nil)
|
1001
|
+
context do
|
1002
|
+
self.line_type = type if type != nil
|
1003
|
+
self.stroke_color = color if color != nil
|
1004
|
+
append_points_with_gaps_to_path(xs, ys, gaps, close_subpaths)
|
1005
|
+
stroke
|
1006
|
+
save_legend_info(legend) if legend != nil
|
1007
|
+
end
|
1008
|
+
end
|
1009
|
+
|
1010
|
+
def stroke_polyline(xs, ys, color = nil, legend = nil, type = nil, gaps = nil, close_subpaths = nil)
|
1011
|
+
show_polyline(xs, ys, color, legend, type, gaps, close_subpaths)
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
def show_contour(xs, ys, gaps = nil, color = nil, type = nil, legend = nil)
|
1015
|
+
show_polyline(xs, ys, color, legend, type, gaps, false)
|
1016
|
+
end
|
1017
|
+
|
1018
|
+
@@keys_for_make_contour = FigureMaker.make_name_lookup_hash([
|
1019
|
+
'dest_xs', 'dest_ys', 'z_level', 'z', 'level', 'xs', 'ys', 'gaps', 'zs', 'data', 'legit', 'method'])
|
1020
|
+
def make_contour(dict)
|
1021
|
+
check_dict(dict, @@keys_for_make_contour, 'make_contour')
|
1022
|
+
z_level = dict['z_level']
|
1023
|
+
if z_level == nil
|
1024
|
+
z_level = complain_if_missing_numeric_arg(dict, 'z', 'level', 'make_contour')
|
1025
|
+
end
|
1026
|
+
dest_xs = get_dvec(dict, 'dest_xs', 'make_contour')
|
1027
|
+
dest_ys = get_dvec(dict, 'dest_ys', 'make_contour')
|
1028
|
+
xs = get_dvec(dict, 'xs', 'make_contour')
|
1029
|
+
ys = get_dvec(dict, 'ys', 'make_contour')
|
1030
|
+
gaps = dict['gaps']
|
1031
|
+
if (!(gaps.kind_of? Array))
|
1032
|
+
raise "Sorry: 'gaps' for 'make_contour' must be an Array"
|
1033
|
+
end
|
1034
|
+
zs = alt_names(dict, 'zs', 'data')
|
1035
|
+
if (!(zs.kind_of? Dtable))
|
1036
|
+
raise "Sorry: 'zs' for 'make_contour' must be a Dtable"
|
1037
|
+
end
|
1038
|
+
dest_xs.clear; dest_ys.clear; gaps.clear
|
1039
|
+
|
1040
|
+
legit = dict['legit']
|
1041
|
+
if legit == nil
|
1042
|
+
legit = Dtable.new(xs.length,ys.length).set(1.0)
|
1043
|
+
elsif (!(legit.kind_of? Dtable))
|
1044
|
+
raise "Sorry: 'legit' for 'make_contour' must be a Dtable -- nonzero means legitimate value in corresponding entry in zs"
|
1045
|
+
end
|
1046
|
+
|
1047
|
+
method = dict['method']
|
1048
|
+
use_conrec = (method == 'conrec' or method == 'CONREC')? 1 : 0
|
1049
|
+
private_make_contour(dest_xs, dest_ys, gaps, xs, ys, zs, z_level, legit, use_conrec)
|
1050
|
+
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
@@keys_for_make_steps = FigureMaker.make_name_lookup_hash([
|
1054
|
+
'xfirst', 'x_first', 'yfirst', 'y_first', 'xlast', 'x_last', 'ylast', 'y_last',
|
1055
|
+
'xs', 'ys', 'dest_xs', 'dest_ys'])
|
1056
|
+
def make_steps(dict)
|
1057
|
+
check_dict(dict, @@keys_for_make_steps, 'make_steps')
|
1058
|
+
xfirst = complain_if_missing_numeric_arg(dict, 'xfirst', 'x_first', 'make_steps')
|
1059
|
+
yfirst = complain_if_missing_numeric_arg(dict, 'yfirst', 'y_first', 'make_steps')
|
1060
|
+
xlast = complain_if_missing_numeric_arg(dict, 'xlast', 'x_last', 'make_steps')
|
1061
|
+
ylast = complain_if_missing_numeric_arg(dict, 'ylast', 'y_last', 'make_steps')
|
1062
|
+
dest_xs = get_dvec(dict, 'dest_xs', 'make_steps')
|
1063
|
+
dest_ys = get_dvec(dict, 'dest_ys', 'make_steps')
|
1064
|
+
xs = get_dvec(dict, 'xs', 'make_steps')
|
1065
|
+
ys = get_dvec(dict, 'ys', 'make_steps')
|
1066
|
+
private_make_steps(dest_xs, dest_ys, xs, ys, xfirst, yfirst, xlast, ylast)
|
1067
|
+
end
|
1068
|
+
|
1069
|
+
@@keys_for_make_curves = FigureMaker.make_name_lookup_hash([
|
1070
|
+
'start_slope', 'end_slope', 'xs', 'ys', 'sample_xs', 'result_ys'])
|
1071
|
+
def make_spline_interpolated_points(dict)
|
1072
|
+
check_dict(dict, @@keys_for_make_curves, 'make_spline_interpolated_points')
|
1073
|
+
start_slope = dict['start_slope']
|
1074
|
+
end_slope = dict['end_slope']
|
1075
|
+
sample_xs = get_dvec(dict, 'sample_xs', 'make_spline_interpolated_points')
|
1076
|
+
result_ys = get_dvec(dict, 'result_ys', 'make_spline_interpolated_points')
|
1077
|
+
xs = get_dvec(dict, 'xs', 'make_spline_interpolated_points')
|
1078
|
+
ys = get_dvec(dict, 'ys', 'make_spline_interpolated_points')
|
1079
|
+
private_make_spline_interpolated_points(sample_xs, result_ys, xs, ys, start_slope, end_slope)
|
1080
|
+
end
|
1081
|
+
|
1082
|
+
@@keys_for_make_interpolant = FigureMaker.make_name_lookup_hash([
|
1083
|
+
'start_slope', 'end_slope', 'xs', 'ys'])
|
1084
|
+
def make_interpolant(dict)
|
1085
|
+
check_dict(dict, @@keys_for_make_interpolant, 'make_smoothed')
|
1086
|
+
start_slope = dict['start_slope']
|
1087
|
+
end_slope = dict['end_slope']
|
1088
|
+
xs = get_dvec(dict, 'xs', 'make_interpolant')
|
1089
|
+
ys = get_dvec(dict, 'ys', 'make_interpolant')
|
1090
|
+
return Dvector.create_spline_interpolant(xs, ys,
|
1091
|
+
(start_slope != nil), start_slope, (end_slope != nil), end_slope)
|
1092
|
+
end
|
1093
|
+
|
1094
|
+
def append_interpolant_to_path(interp)
|
1095
|
+
x_s = interp[0]; y_s = interp[1]; a_s = interp[2]; b_s = interp[3]; c_s = interp[4]
|
1096
|
+
ctrl = Dvector.new
|
1097
|
+
move_to_point(x_s[0], y_s[0]);
|
1098
|
+
(x_s.size - 1).times do |i|
|
1099
|
+
x0 = x_s[i]; delta_x = x_s[i+1] - x0
|
1100
|
+
ctrl.make_bezier_control_points_for_cubic_in_x(x0, y_s[i], delta_x, a_s[i], b_s[i], c_s[i])
|
1101
|
+
append_curve_to_path(ctrl[0], ctrl[1], ctrl[2], ctrl[3], ctrl[4], ctrl[5])
|
1102
|
+
end
|
1103
|
+
end
|
1104
|
+
|
1105
|
+
@@keys_for_show_error_bars = FigureMaker.make_name_lookup_hash(['x', 'y', 'dx', 'dy',
|
1106
|
+
'dx_plus', 'dx_minus', 'dy_plus', 'dy_minus', 'color', 'end_cap', 'line_width'])
|
1107
|
+
def show_error_bars(dict)
|
1108
|
+
check_dict(dict, @@keys_for_show_error_bars, 'show_error_bars')
|
1109
|
+
x = dict['x']
|
1110
|
+
y = dict['y']
|
1111
|
+
if (x == nil || y == nil)
|
1112
|
+
raise "Sorry: Must give both 'x' and 'y' for show_error_bar."
|
1113
|
+
end
|
1114
|
+
dx = dict['dx']
|
1115
|
+
dx_plus = get_if_given_else_default(dict, 'dx_plus', dx)
|
1116
|
+
dx_minus = get_if_given_else_default(dict, 'dx_minus', dx)
|
1117
|
+
dy = dict['dy']
|
1118
|
+
dy_plus = get_if_given_else_default(dict, 'dy_plus', dy)
|
1119
|
+
dy_minus = get_if_given_else_default(dict, 'dy_minus', dy)
|
1120
|
+
if (dx_plus == nil || dx_minus == nil || dy_plus == nil || dy_minus == nil)
|
1121
|
+
raise "Sorry: Must give both 'dx' and 'dy' error ranges for show_error_bar."
|
1122
|
+
end
|
1123
|
+
end_cap = get_if_given_else_default(dict, 'end_cap', 0.15) # end_cap length in default text heights
|
1124
|
+
x_end_cap = end_cap * self.default_text_height_dy
|
1125
|
+
y_end_cap = end_cap * self.default_text_height_dx
|
1126
|
+
line_width = get_if_given_else_default(dict, 'line_width', 1)
|
1127
|
+
prev_line_width = self.line_width
|
1128
|
+
self.line_width = line_width if prev_line_width != line_width
|
1129
|
+
color = get_if_given_else_default(dict, 'color', Black)
|
1130
|
+
prev_color = self.stroke_color
|
1131
|
+
self.stroke_color = color if prev_color != color
|
1132
|
+
# vertical error (dy)
|
1133
|
+
if (dy_plus != 0 || dy_minus != 0)
|
1134
|
+
stroke_line(x, y+dy_plus, x, y-dy_minus)
|
1135
|
+
stroke_line(x-y_end_cap, y+dy_plus, x+y_end_cap, y+dy_plus)
|
1136
|
+
stroke_line(x-y_end_cap, y-dy_minus, x+y_end_cap, y-dy_minus)
|
1137
|
+
end
|
1138
|
+
# horizontal error (dx)
|
1139
|
+
if (dx_plus != 0 || dx_minus != 0)
|
1140
|
+
stroke_line(x+dx_plus, y, x-dx_minus, y)
|
1141
|
+
stroke_line(x+dx_plus, y-x_end_cap, x+dx_plus, y+x_end_cap)
|
1142
|
+
stroke_line(x-dx_minus, y-x_end_cap, x-dx_minus, y+x_end_cap)
|
1143
|
+
end
|
1144
|
+
self.line_width = prev_line_width if prev_line_width != line_width
|
1145
|
+
self.stroke_color = prev_color if prev_color != color
|
1146
|
+
end
|
1147
|
+
|
1148
|
+
@@keys_for_show_arrow = FigureMaker.make_name_lookup_hash([
|
1149
|
+
'x_head', 'y_head', 'x_tail', 'y_tail', 'head', 'tail',
|
1150
|
+
'color', 'head_color', 'tail_color', 'line_color',
|
1151
|
+
'line_style',
|
1152
|
+
'head_marker', 'tail_marker', 'line_width',
|
1153
|
+
'head_angle', 'head_just', 'tail_just', 'tail_angle',
|
1154
|
+
'head_scale', 'tail_scale'])
|
1155
|
+
|
1156
|
+
# TODO: add linestyle capacities to arrows.
|
1157
|
+
def show_arrow(dict)
|
1158
|
+
check_dict(dict, @@keys_for_show_arrow, 'show_arrow')
|
1159
|
+
if check_pair(head = dict['head'], 'head', 'show_arrow')
|
1160
|
+
x_head = head[0]
|
1161
|
+
y_head = head[1]
|
1162
|
+
else
|
1163
|
+
x_head = dict['x_head']
|
1164
|
+
y_head = dict['y_head']
|
1165
|
+
end
|
1166
|
+
if (x_head == nil || y_head == nil)
|
1167
|
+
raise "Sorry: Must give both 'x_head' and 'y_head' for show_arrow."
|
1168
|
+
end
|
1169
|
+
if check_pair(tail = dict['tail'], 'tail', 'show_arrow')
|
1170
|
+
x_tail = tail[0]
|
1171
|
+
y_tail = tail[1]
|
1172
|
+
else
|
1173
|
+
x_tail = dict['x_tail']
|
1174
|
+
y_tail = dict['y_tail']
|
1175
|
+
end
|
1176
|
+
if (x_tail == nil || y_tail == nil)
|
1177
|
+
raise "Sorry: Must give both 'x_tail' and 'y_tail' for show_arrow."
|
1178
|
+
end
|
1179
|
+
color = get_if_given_else_default(dict, 'color', Black)
|
1180
|
+
head_color = get_if_given_else_default(dict, 'head_color', color)
|
1181
|
+
tail_color = get_if_given_else_default(dict, 'tail_color', color)
|
1182
|
+
head_angle = get_if_given_else_default(dict, 'head_angle', 0)
|
1183
|
+
tail_angle = get_if_given_else_default(dict, 'tail_angle', -180)
|
1184
|
+
line_color = get_if_given_else_default(dict, 'line_color', color)
|
1185
|
+
head_marker = get_if_given_else_default(dict, 'head_marker', Arrowhead)
|
1186
|
+
tail_marker = get_if_given_else_default(dict, 'tail_marker', BarThin)
|
1187
|
+
line_width = get_if_given_else_default(dict, 'line_width', 1)
|
1188
|
+
head_scale = dict['head_scale']
|
1189
|
+
head_scale = @marker_defaults['scale'] if head_scale == nil
|
1190
|
+
tail_scale = dict['tail_scale']
|
1191
|
+
|
1192
|
+
# Automatic detection of marker justification
|
1193
|
+
dict['tail_just'] ||= if tail_marker == Arrowhead || tail_marker == ArrowheadOpen
|
1194
|
+
RIGHT_JUSTIFIED
|
1195
|
+
else
|
1196
|
+
CENTERED
|
1197
|
+
end
|
1198
|
+
|
1199
|
+
dict['head_just'] ||= if head_marker == Arrowhead || head_marker == ArrowheadOpen
|
1200
|
+
RIGHT_JUSTIFIED
|
1201
|
+
else
|
1202
|
+
CENTERED
|
1203
|
+
end
|
1204
|
+
|
1205
|
+
prev_line_cap = self.line_cap
|
1206
|
+
self.line_cap = LINE_CAP_BUTT if prev_line_cap != LINE_CAP_BUTT
|
1207
|
+
prev_line_width = self.line_width
|
1208
|
+
self.line_width = line_width if prev_line_width != line_width
|
1209
|
+
prev_stroke_color = self.stroke_color
|
1210
|
+
self.stroke_color = line_color if line_color != prev_stroke_color
|
1211
|
+
prev_line_type = self.line_type
|
1212
|
+
if dict['line_style']
|
1213
|
+
self.line_type = dict['line_style']
|
1214
|
+
end
|
1215
|
+
dx = x_head - x_tail
|
1216
|
+
dy = y_head - y_tail
|
1217
|
+
pg_dx = convert_figure_to_output_dx(dx)
|
1218
|
+
pg_dy = convert_figure_to_output_dy(dy)
|
1219
|
+
len = (pg_dx*pg_dx + pg_dy*pg_dy).sqrt
|
1220
|
+
chsz = convert_figure_to_output_dx(default_text_height_dx) * head_scale
|
1221
|
+
chsz = -chsz if chsz < 0
|
1222
|
+
|
1223
|
+
tail_frac = if dict['tail_just'] == RIGHT_JUSTIFIED
|
1224
|
+
0.5 * chsz/len
|
1225
|
+
else
|
1226
|
+
0.0
|
1227
|
+
end
|
1228
|
+
head_frac = if dict['head_just'] == RIGHT_JUSTIFIED
|
1229
|
+
(len - 0.5 * chsz)/len
|
1230
|
+
else
|
1231
|
+
1.0
|
1232
|
+
end
|
1233
|
+
if head_frac < tail_frac # Pretty uncommon, I guess
|
1234
|
+
head_frac = tail_frac = 0.5 # We put everything in the middle, then
|
1235
|
+
end
|
1236
|
+
|
1237
|
+
# Don't actually stroke the line if line_width is null. Can be used
|
1238
|
+
# to draw only the markers.
|
1239
|
+
stroke_line(x_tail + tail_frac*dx, y_tail + tail_frac*dy,
|
1240
|
+
x_tail + head_frac*dx, y_tail + head_frac*dy) if line_width > 0
|
1241
|
+
angle = convert_to_degrees(dx, dy)
|
1242
|
+
if head_marker != 'None'
|
1243
|
+
show_marker('marker' => head_marker, 'point' => [x_head, y_head], 'color' => head_color,
|
1244
|
+
'justification' => dict['head_just'], 'angle'=> (angle + head_angle), 'scale' => head_scale)
|
1245
|
+
end
|
1246
|
+
if tail_marker != 'None'
|
1247
|
+
if tail_marker == Arrowhead || tail_marker == ArrowheadOpen
|
1248
|
+
just = RIGHT_JUSTIFIED
|
1249
|
+
else
|
1250
|
+
just = CENTERED
|
1251
|
+
end
|
1252
|
+
show_marker('marker' => tail_marker, 'point' => [x_tail, y_tail], 'color' => tail_color,
|
1253
|
+
'angle'=> (angle + tail_angle), 'scale' => tail_scale, 'justification' => dict['tail_just'])
|
1254
|
+
end
|
1255
|
+
self.line_cap = prev_line_cap if prev_line_cap != LINE_CAP_BUTT
|
1256
|
+
self.line_width = prev_line_width if prev_line_width != line_width
|
1257
|
+
self.stroke_color = prev_stroke_color if prev_stroke_color != line_color
|
1258
|
+
self.line_type = prev_line_type
|
1259
|
+
end
|
1260
|
+
|
1261
|
+
@@keys_for_axial_shading = FigureMaker.make_name_lookup_hash(['extend_start', 'extend_end',
|
1262
|
+
'x_start', 'y_start', 'start', 'start_point', 'x_end', 'y_end', 'end', 'end_point', 'colormap', 'color_map'])
|
1263
|
+
def axial_shading(dict)
|
1264
|
+
check_dict(dict, @@keys_for_axial_shading, 'axial_shading')
|
1265
|
+
x_start = y_start = nil
|
1266
|
+
start = alt_names(dict, 'start', 'start_point')
|
1267
|
+
if check_pair(start, 'start', 'axial_shading')
|
1268
|
+
x_start = start[0]; y_start = start[1];
|
1269
|
+
end
|
1270
|
+
x_start = dict['x_start'] if x_start == nil
|
1271
|
+
y_start = dict['y_start'] if y_start == nil
|
1272
|
+
if (x_start == nil || y_start == nil)
|
1273
|
+
raise "Sorry: Must give both 'x_start' and 'y_start' for axial_shading."
|
1274
|
+
end
|
1275
|
+
x_end = y_end = nil
|
1276
|
+
endpt = alt_names(dict, 'end', 'end_point')
|
1277
|
+
if check_pair(endpt, 'end', 'axial_shading')
|
1278
|
+
x_end = endpt[0]; y_end= endpt[1];
|
1279
|
+
end
|
1280
|
+
x_end = dict['x_end'] if x_end == nil
|
1281
|
+
y_end = dict['y_end'] if y_end == nil
|
1282
|
+
if (x_end == nil || y_end == nil)
|
1283
|
+
raise "Sorry: Must give both 'x_end' and 'y_end' for axial_shading."
|
1284
|
+
end
|
1285
|
+
colormap = alt_names(dict, 'colormap', 'color_map')
|
1286
|
+
extend_start = dict['extend_start']
|
1287
|
+
extend_end = dict['extend_end']
|
1288
|
+
private_axial_shading(x_start, y_start, x_end, y_end, colormap, extend_start, extend_end)
|
1289
|
+
end
|
1290
|
+
|
1291
|
+
@@keys_for_radial_shading = FigureMaker.make_name_lookup_hash(['extend_start', 'extend_end',
|
1292
|
+
'x_start', 'y_start', 'radius_start', 'start_radius', 'start', 'start_circle',
|
1293
|
+
'x_end', 'y_end', 'radius_start', 'end_radius', 'end', 'end_circle',
|
1294
|
+
'colormap', 'color_map', 'x_hat', 'y_hat', 'xhat', 'yhat'])
|
1295
|
+
def radial_shading(dict)
|
1296
|
+
check_dict(dict, @@keys_for_radial_shading, 'radial_shading')
|
1297
|
+
start_circle = alt_names(dict, 'start_circle', 'start')
|
1298
|
+
end_circle = alt_names(dict, 'end_circle', 'end')
|
1299
|
+
colormap = alt_names(dict, 'colormap', 'color_map')
|
1300
|
+
x_hat = alt_names(dict, 'x_hat', 'xhat')
|
1301
|
+
x_hat = [1, 0] if x_hat == nil
|
1302
|
+
y_hat = alt_names(dict, 'y_hat', 'yhat')
|
1303
|
+
y_hat = [0, 1] if y_hat == nil
|
1304
|
+
origin = dict['origin']
|
1305
|
+
origin = [0, 0] if origin == nil
|
1306
|
+
extend_start = dict['extend_start']
|
1307
|
+
extend_end = dict['extend_end']
|
1308
|
+
private_radial_shading(start_circle[0], start_circle[1], start_circle[2],
|
1309
|
+
end_circle[0], end_circle[1], end_circle[2], colormap,
|
1310
|
+
x_hat[0], y_hat[0], x_hat[1], y_hat[1],
|
1311
|
+
extend_start, extend_end)
|
1312
|
+
end
|
1313
|
+
|
1314
|
+
@@keys_for_show_image = FigureMaker.make_name_lookup_hash([
|
1315
|
+
'll', 'lr', 'ul', 'w', 'width', 'height', 'h',
|
1316
|
+
'opacity_mask', 'stencil_mask',
|
1317
|
+
'jpg', 'JPG', 'jpeg', 'JPEG', 'interpolate', 'data', 'value_mask',
|
1318
|
+
'color_space', 'color_map', 'colormap'])
|
1319
|
+
def show_image(dict)
|
1320
|
+
internal_show_image(dict, false)
|
1321
|
+
end
|
1322
|
+
|
1323
|
+
@@keys_for_create_colormap = FigureMaker.make_name_lookup_hash(['length', 'points', 'Rs', 'Gs', 'Bs', 'Hs', 'Ls', 'Ss'])
|
1324
|
+
def create_colormap(dict)
|
1325
|
+
check_dict(dict, @@keys_for_create_colormap, 'create_colormap')
|
1326
|
+
length = dict['length']
|
1327
|
+
length = 256 if length == nil
|
1328
|
+
if !(length >= 2 && length <= 256)
|
1329
|
+
raise "Sorry: dictionary for create color map must have 'length' between 2 and 256"
|
1330
|
+
end
|
1331
|
+
points = dict['points']
|
1332
|
+
if points == nil
|
1333
|
+
raise "Sorry: dictionary for create color map must have 'points' set to a vector of increasing locations from 0.0 to 1.0"
|
1334
|
+
end
|
1335
|
+
c1s = dict['Rs']
|
1336
|
+
c2s = dict['Gs']
|
1337
|
+
c3s = dict['Bs']
|
1338
|
+
if c1s != nil && c2s != nil && c3s != nil
|
1339
|
+
rgb_flag = true
|
1340
|
+
else
|
1341
|
+
c1s = dict['Hs']
|
1342
|
+
c2s = dict['Ls']
|
1343
|
+
c3s = dict['Ss']
|
1344
|
+
if c1s == nil || c2s == nil || c3s == nil
|
1345
|
+
raise "Sorry: dictionary for create color map must have 'Rs', 'Gs', and 'Bs', or 'Hs', 'Ls', and 'Ss'."
|
1346
|
+
end
|
1347
|
+
rgb_flag = false
|
1348
|
+
end
|
1349
|
+
private_create_colormap(rgb_flag, length, points, c1s, c2s, c3s)
|
1350
|
+
end
|
1351
|
+
|
1352
|
+
def intense_colormap
|
1353
|
+
if @intense_colormap == nil
|
1354
|
+
@intense_colormap = create_colormap(
|
1355
|
+
'points' => [0.0, 0.44, 0.50, 0.50, 0.56, 1.0],
|
1356
|
+
'Hs' => [240, 240, 240, 0, 0, 0],
|
1357
|
+
'Ls' => [0.5, 0.90, 0.99, 0.99, 0.90, 0.5],
|
1358
|
+
'Ss' => [1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
|
1359
|
+
)
|
1360
|
+
end
|
1361
|
+
@intense_colormap
|
1362
|
+
end
|
1363
|
+
|
1364
|
+
def mellow_colormap
|
1365
|
+
if @mellow_colormap == nil
|
1366
|
+
@mellow_colormap = create_colormap(
|
1367
|
+
'points' => [0.0, 0.44, 0.50, 0.50, 0.56, 1.0],
|
1368
|
+
'Hs' => [240, 240, 240, 0, 0, 0],
|
1369
|
+
'Ls' => [0.5, 0.90, 0.99, 0.99, 0.90, 0.5],
|
1370
|
+
'Ss' => [0.5, 1.0, 1.0, 1.0, 1.0, 0.5]
|
1371
|
+
)
|
1372
|
+
end
|
1373
|
+
@mellow_colormap
|
1374
|
+
end
|
1375
|
+
|
1376
|
+
def rainbow_colormap
|
1377
|
+
if @rainbow_colormap == nil
|
1378
|
+
@rainbow_colormap = create_colormap(
|
1379
|
+
'points' => [0.00, 0.27, 0.46, 0.73, 1.00], # distorted to reduce size of green
|
1380
|
+
# modified for debugging purposes...
|
1381
|
+
'Hs' => (Dvector[0.0, 1.0, 2.0, 3.0, 4.0]*90.0 - 20.0)*(340.0/360.0) + 10.0,
|
1382
|
+
'Ls' => [ 0.5, 0.5, 0.5, 0.5, 0.5],
|
1383
|
+
'Ss' => [ 1.0, 1.0, 1.0, 1.0, 1.0]
|
1384
|
+
)
|
1385
|
+
end
|
1386
|
+
@rainbow_colormap
|
1387
|
+
end
|
1388
|
+
|
1389
|
+
@@keys_for_create_gradient_colormap = FigureMaker.make_name_lookup_hash([
|
1390
|
+
'hue', 'starting_H', 'ending_H',
|
1391
|
+
'lightness', 'starting_L', 'ending_L', 'saturation', 'starting_S', 'ending_S'])
|
1392
|
+
def create_gradient_colormap(dict)
|
1393
|
+
check_dict(dict, @@keys_for_create_gradient_colormap, 'create_gradient_colormap')
|
1394
|
+
hue = get_if_given_else_default(dict, 'hue', 0)
|
1395
|
+
starting_H = get_if_given_else_default(dict, 'starting_H', hue)
|
1396
|
+
ending_H = get_if_given_else_default(dict, 'ending_H', hue)
|
1397
|
+
lightness = get_if_given_else_default(dict, 'lightness', 0.5)
|
1398
|
+
starting_L = get_if_given_else_default(dict, 'starting_L', lightness)
|
1399
|
+
ending_L = get_if_given_else_default(dict, 'ending_L', lightness)
|
1400
|
+
saturation = get_if_given_else_default(dict, 'saturation', 0.5)
|
1401
|
+
starting_S = get_if_given_else_default(dict, 'starting_S', saturation)
|
1402
|
+
ending_S = get_if_given_else_default(dict, 'ending_S', saturation)
|
1403
|
+
create_colormap(
|
1404
|
+
'points' => [0.00, 1.00],
|
1405
|
+
'Hs' => [starting_H, ending_H],
|
1406
|
+
'Ls' => [starting_L, ending_L],
|
1407
|
+
'Ss' => [starting_S, ending_S]
|
1408
|
+
)
|
1409
|
+
end
|
1410
|
+
|
1411
|
+
@@keys_for_create_image_data = FigureMaker.make_name_lookup_hash([
|
1412
|
+
'first_row', 'last_row', 'first_column', 'last_column',
|
1413
|
+
'min_value', 'max_value', 'max_code', 'if_below_range', 'if_above_range', 'masking'])
|
1414
|
+
def create_image_data(data, dict)
|
1415
|
+
check_dict(dict, @@keys_for_create_image_data, 'create_image_data')
|
1416
|
+
first_row = dict['first_row']
|
1417
|
+
last_row = dict['last_row']
|
1418
|
+
first_column = dict['first_column']
|
1419
|
+
last_column = dict['last_column']
|
1420
|
+
min_value = dict['min_value']
|
1421
|
+
max_value = dict['max_value']
|
1422
|
+
max_code = dict['max_code']
|
1423
|
+
if_below_range = dict['if_below_range']
|
1424
|
+
if_above_range = dict['if_above_range']
|
1425
|
+
first_row = 0 if first_row == nil
|
1426
|
+
last_row = -1 if last_row == nil
|
1427
|
+
first_column = 0 if first_column == nil
|
1428
|
+
last_column = -1 if last_column == nil
|
1429
|
+
min_value = data.min if min_value == nil
|
1430
|
+
max_value = data.max if max_value == nil
|
1431
|
+
max_code = 255 if max_code == nil
|
1432
|
+
if_below_range = 0 if if_below_range == nil
|
1433
|
+
if_above_range = max_code if if_above_range == nil
|
1434
|
+
if dict['masking'] == true
|
1435
|
+
max_code = 254; if_below_range = if_above_range = 255
|
1436
|
+
end
|
1437
|
+
return private_create_image_data(data, first_row, last_row, first_column, last_column,
|
1438
|
+
min_value, max_value, max_code, if_below_range, if_above_range);
|
1439
|
+
end
|
1440
|
+
|
1441
|
+
@@keys_for_create_monochrome_image_data = FigureMaker.make_name_lookup_hash([
|
1442
|
+
'first_row', 'last_row', 'first_column', 'last_column', 'boundary', 'reverse'])
|
1443
|
+
def create_monochrome_image_data(data, dict)
|
1444
|
+
check_dict(dict, @@keys_for_create_monochrome_image_data, 'create_monochrome_image_data')
|
1445
|
+
first_row = dict['first_row']
|
1446
|
+
last_row = dict['last_row']
|
1447
|
+
first_column = dict['first_column']
|
1448
|
+
last_column = dict['last_column']
|
1449
|
+
boundary = dict['boundary']
|
1450
|
+
reverse = dict['reverse']
|
1451
|
+
first_row = 0 if first_row == nil
|
1452
|
+
last_row = -1 if last_row == nil
|
1453
|
+
first_column = 0 if first_column == nil
|
1454
|
+
last_column = -1 if last_column == nil
|
1455
|
+
boundary = 0 if boundary == nil
|
1456
|
+
reverse = false if reverse == nil
|
1457
|
+
return private_create_monochrome_image_data(data, first_row, last_row, first_column, last_column,
|
1458
|
+
boundary, reverse);
|
1459
|
+
end
|
1460
|
+
|
1461
|
+
@@keys_for_show_marker = FigureMaker.make_name_lookup_hash([
|
1462
|
+
'marker', 'x', 'y', 'at', 'point', 'Xs', 'Ys', 'xs', 'ys', 'mode', 'rendering_mode',
|
1463
|
+
'angle', 'scale', 'font', 'string', 'text', 'color', 'fill_color', 'stroke_color', 'stroke_width',
|
1464
|
+
'horizontal_scale', 'vertical_scale', 'italic_angle', 'ascent_angle', 'alignment', 'justification'])
|
1465
|
+
def show_marker(dict)
|
1466
|
+
check_dict(dict, @@keys_for_show_marker, 'show_marker')
|
1467
|
+
marker = dict['marker']
|
1468
|
+
x = y = nil
|
1469
|
+
at = alt_names(dict, 'at', 'point')
|
1470
|
+
if check_pair(at, 'at', 'show_text')
|
1471
|
+
x = at[0]; y = at[1];
|
1472
|
+
end
|
1473
|
+
x = dict['x'] if x == nil
|
1474
|
+
y = dict['y'] if y == nil
|
1475
|
+
xs = alt_names(dict, 'Xs', 'xs')
|
1476
|
+
ys = alt_names(dict, 'Ys', 'ys')
|
1477
|
+
if ((xs != nil && ys == nil) || (ys != nil && xs == nil))
|
1478
|
+
raise "Sorry: Must supply both xs and ys for show_marker"
|
1479
|
+
end
|
1480
|
+
if (xs != nil && ys != nil && xs.size != ys.size)
|
1481
|
+
raise "Sorry: Must equal length xs and ys for show_marker"
|
1482
|
+
end
|
1483
|
+
color = dict['color']
|
1484
|
+
if color == nil
|
1485
|
+
fill_color = get_if_given_else_use_default_dict(dict, 'fill_color', @marker_defaults)
|
1486
|
+
stroke_color = get_if_given_else_use_default_dict(dict, 'stroke_color', @marker_defaults)
|
1487
|
+
else
|
1488
|
+
fill_color = stroke_color = color
|
1489
|
+
end
|
1490
|
+
font = dict['font']
|
1491
|
+
mode = alt_names(dict, 'mode', 'rendering_mode')
|
1492
|
+
string = alt_names(dict, 'string', 'text')
|
1493
|
+
if (marker == nil && string == nil)
|
1494
|
+
raise "Sorry: Must give either 'marker' or 'string' for show_marker"
|
1495
|
+
end
|
1496
|
+
if (marker != nil && string != nil)
|
1497
|
+
raise "Sorry: Must give either 'marker' or 'string' for show_marker, but not both"
|
1498
|
+
end
|
1499
|
+
if (marker == nil)
|
1500
|
+
glyph = stroke_width = nil
|
1501
|
+
else
|
1502
|
+
if !(marker.kind_of?Array) && marker.size >= 2 && marker.size <= 3
|
1503
|
+
raise "Sorry: 'marker' for show_marker must be array of [font_number, char_code] or [font_number, char_code, rendering_mode]"
|
1504
|
+
end
|
1505
|
+
font = marker[0]
|
1506
|
+
glyph = marker[1]
|
1507
|
+
if marker.size == 3
|
1508
|
+
mode = STROKE if mode == nil
|
1509
|
+
stroke_width = marker[2]
|
1510
|
+
else
|
1511
|
+
mode = FILL if mode == nil
|
1512
|
+
stroke_width = nil
|
1513
|
+
end
|
1514
|
+
end
|
1515
|
+
mode = FILL if mode == nil
|
1516
|
+
font = Times_Roman if (font == nil && string != nil)
|
1517
|
+
if (font != nil && !(font.kind_of? Integer))
|
1518
|
+
raise "Sorry: 'font' for show_marker must be an integer font number (see FigureConstants list)"
|
1519
|
+
end
|
1520
|
+
stroke_width = get_if_given_else_default(dict, 'stroke_width', stroke_width)
|
1521
|
+
angle = get_if_given_else_use_default_dict(dict, 'angle', @marker_defaults)
|
1522
|
+
scale = get_if_given_else_use_default_dict(dict, 'scale', @marker_defaults)
|
1523
|
+
just = get_if_given_else_use_default_dict(dict, 'justification', @marker_defaults)
|
1524
|
+
align = get_if_given_else_use_default_dict(dict, 'alignment', @marker_defaults)
|
1525
|
+
h_scale = get_if_given_else_use_default_dict(dict, 'horizontal_scale', @marker_defaults)
|
1526
|
+
v_scale = get_if_given_else_use_default_dict(dict, 'vertical_scale', @marker_defaults)
|
1527
|
+
it_angle = get_if_given_else_use_default_dict(dict, 'italic_angle', @marker_defaults)
|
1528
|
+
ascent_angle = get_if_given_else_use_default_dict(dict, 'ascent_angle', @marker_defaults)
|
1529
|
+
glyph = 0 if glyph == nil
|
1530
|
+
int_args = glyph*100000 + font*1000 + mode*100 + align*10 + just
|
1531
|
+
# Ruby limits us to 15 args, so pack some small integers together
|
1532
|
+
private_show_marker(int_args, stroke_width, string, x, y, xs, ys,
|
1533
|
+
h_scale, v_scale, scale, it_angle, ascent_angle, angle, fill_color, stroke_color)
|
1534
|
+
end
|
1535
|
+
|
1536
|
+
def show_label(dict)
|
1537
|
+
at = alt_names(dict, 'at', 'point')
|
1538
|
+
if check_pair(at, 'at', 'show_text')
|
1539
|
+
xloc = at[0]
|
1540
|
+
yloc = at[1]
|
1541
|
+
else
|
1542
|
+
xloc = dict['x']
|
1543
|
+
yloc = dict['y']
|
1544
|
+
end
|
1545
|
+
if (xloc == nil || yloc == nil)
|
1546
|
+
raise "Sorry: Must supply 'at', 'point', or 'x' and 'y' for show_label"
|
1547
|
+
end
|
1548
|
+
return if !check_label_clip(xloc, yloc)
|
1549
|
+
show_text(dict)
|
1550
|
+
end
|
1551
|
+
|
1552
|
+
@@keys_for_show_text = FigureMaker.make_name_lookup_hash([
|
1553
|
+
'text', 'side', 'loc', 'position', 'pos', 'x', 'y',
|
1554
|
+
'shift', 'scale', 'color', 'angle', 'alignment', 'justification', 'at', 'point'])
|
1555
|
+
def show_text(dict)
|
1556
|
+
check_dict(dict, @@keys_for_show_text, 'show_text')
|
1557
|
+
text = dict['text']
|
1558
|
+
if text == nil
|
1559
|
+
raise "Sorry: Must supply 'text' entry in dictionary for show_text"
|
1560
|
+
end
|
1561
|
+
scale = get_if_given_else_default(dict, 'scale', 1)
|
1562
|
+
color = dict['color'] # color is [r,g,b] array. this adds \textcolor[rgb]{r,g,b}{...}
|
1563
|
+
if color != nil
|
1564
|
+
if !color.kind_of?Array
|
1565
|
+
raise "Sorry: 'color' must be array of [r,g,b] intensities for show_text (#{color})"
|
1566
|
+
end
|
1567
|
+
r = color[0]; g = color[1]; b = color[2];
|
1568
|
+
if (!(r.kind_of? Numeric) || !(g.kind_of? Numeric) || !(b.kind_of? Numeric) )
|
1569
|
+
raise "Sorry: 'color' must be array of [r,g,b] intensities for show_text"
|
1570
|
+
end
|
1571
|
+
text = sprintf("\\textcolor[rgb]{%0.2f,%0.2f,%0.2f}{%s}", r, g, b, text)
|
1572
|
+
end
|
1573
|
+
just = get_if_given_else_default(dict, 'justification', self.justification)
|
1574
|
+
align = get_if_given_else_default(dict, 'alignment', self.alignment)
|
1575
|
+
angle = get_if_given_else_default(dict, 'angle', 0)
|
1576
|
+
loc = alt_names(dict, 'loc', 'side')
|
1577
|
+
if (loc == nil)
|
1578
|
+
at = alt_names(dict, 'at', 'point')
|
1579
|
+
if check_pair(at, 'at', 'show_text')
|
1580
|
+
xloc = at[0]
|
1581
|
+
yloc = at[1]
|
1582
|
+
else
|
1583
|
+
xloc = dict['x']
|
1584
|
+
yloc = dict['y']
|
1585
|
+
end
|
1586
|
+
if (xloc == nil || yloc == nil)
|
1587
|
+
raise "Sorry: Must supply a location for show_text"
|
1588
|
+
end
|
1589
|
+
show_rotated_label(text, xloc, yloc, scale, angle, just, align)
|
1590
|
+
return
|
1591
|
+
end
|
1592
|
+
position = alt_names(dict, 'position', 'pos')
|
1593
|
+
position = 0.5 if position == nil
|
1594
|
+
shift = dict['shift']
|
1595
|
+
if loc == LEFT
|
1596
|
+
shift = self.text_shift_on_left if shift == nil
|
1597
|
+
elsif loc == RIGHT
|
1598
|
+
shift = self.text_shift_on_right if shift == nil
|
1599
|
+
elsif loc == TOP
|
1600
|
+
shift = self.text_shift_on_top if shift == nil
|
1601
|
+
elsif loc == BOTTOM
|
1602
|
+
shift = self.text_shift_on_bottom if shift == nil
|
1603
|
+
else
|
1604
|
+
if (loc == AT_X_ORIGIN)
|
1605
|
+
shift = self.text_shift_from_x_origin if shift == nil
|
1606
|
+
xloc = shift*self.char_height_dx
|
1607
|
+
yloc = convert_frame_to_figure_y(position)
|
1608
|
+
return
|
1609
|
+
elsif (loc == AT_Y_ORIGIN)
|
1610
|
+
shift = self.text_shift_from_y_origin if shift == nil
|
1611
|
+
yloc = shift*self.char_height_dy
|
1612
|
+
xloc = convert_frame_to_figure_x(position)
|
1613
|
+
else
|
1614
|
+
raise "Sorry: 'loc' must be LEFT, RIGHT, TOP, BOTTOM, AT_X_ORIGIN, or AT_Y_ORIGIN for show_text"
|
1615
|
+
end
|
1616
|
+
show_rotated_label(text, xloc, yloc, scale, angle, just, align)
|
1617
|
+
return
|
1618
|
+
end
|
1619
|
+
show_rotated_text(text, loc, shift, position, scale, angle, just, align)
|
1620
|
+
end
|
1621
|
+
|
1622
|
+
|
1623
|
+
def reset_eval_function
|
1624
|
+
@eval_command = nil
|
1625
|
+
end
|
1626
|
+
|
1627
|
+
def def_eval_function(&cmd)
|
1628
|
+
if cmd == nil
|
1629
|
+
raise "Sorry: must provide a command block for def_eval"
|
1630
|
+
end
|
1631
|
+
@eval_command = cmd
|
1632
|
+
end
|
1633
|
+
|
1634
|
+
|
1635
|
+
|
1636
|
+
def def_enter_page_function(&cmd)
|
1637
|
+
if cmd == nil
|
1638
|
+
raise "Sorry: must provide a command block for def_enter_page_function"
|
1639
|
+
end
|
1640
|
+
@enter_page_function = cmd
|
1641
|
+
end
|
1642
|
+
|
1643
|
+
def reset_enter_page_function
|
1644
|
+
@enter_page_function = nil
|
1645
|
+
end
|
1646
|
+
|
1647
|
+
def def_exit_page_function(&cmd)
|
1648
|
+
if cmd == nil
|
1649
|
+
raise "Sorry: must provide a command block for def_exit_page_function"
|
1650
|
+
end
|
1651
|
+
@exit_page_function = cmd
|
1652
|
+
end
|
1653
|
+
|
1654
|
+
def reset_exit_page_function
|
1655
|
+
@exit_page_function = nil
|
1656
|
+
end
|
1657
|
+
|
1658
|
+
|
1659
|
+
|
1660
|
+
def def_enter_show_plot_function(&cmd)
|
1661
|
+
if cmd == nil
|
1662
|
+
raise "Sorry: must provide a command block for def_enter_show_plot_function"
|
1663
|
+
end
|
1664
|
+
@enter_show_plot_function = cmd
|
1665
|
+
end
|
1666
|
+
|
1667
|
+
def reset_enter_show_plot_function
|
1668
|
+
@enter_show_plot_function = nil
|
1669
|
+
end
|
1670
|
+
|
1671
|
+
def def_exit_show_plot_function(&cmd)
|
1672
|
+
if cmd == nil
|
1673
|
+
raise "Sorry: must provide a command block for def_exit_show_plot_function"
|
1674
|
+
end
|
1675
|
+
@exit_show_plot_function = cmd
|
1676
|
+
end
|
1677
|
+
|
1678
|
+
def reset_exit_show_plot_function
|
1679
|
+
@exit_show_plot_function = nil
|
1680
|
+
end
|
1681
|
+
|
1682
|
+
|
1683
|
+
|
1684
|
+
def def_enter_subfigure_function(&cmd)
|
1685
|
+
if cmd == nil
|
1686
|
+
raise "Sorry: must provide a command block for def_enter_subfigure_function"
|
1687
|
+
end
|
1688
|
+
@enter_subfigure_function = cmd
|
1689
|
+
end
|
1690
|
+
|
1691
|
+
def reset_enter_subfigure_function
|
1692
|
+
@enter_subfigure_function = nil
|
1693
|
+
end
|
1694
|
+
|
1695
|
+
def def_exit_subfigure_function(&cmd)
|
1696
|
+
if cmd == nil
|
1697
|
+
raise "Sorry: must provide a command block for def_exit_subfigure_function"
|
1698
|
+
end
|
1699
|
+
@exit_subfigure_function = cmd
|
1700
|
+
end
|
1701
|
+
|
1702
|
+
def reset_exit_subfigure_function
|
1703
|
+
@exit_subfigure_function = nil
|
1704
|
+
end
|
1705
|
+
|
1706
|
+
|
1707
|
+
def def_enter_subplot_function(&cmd)
|
1708
|
+
if cmd == nil
|
1709
|
+
raise "Sorry: must provide a command block for def_enter_subplot_function"
|
1710
|
+
end
|
1711
|
+
@enter_subplot_function = cmd
|
1712
|
+
end
|
1713
|
+
|
1714
|
+
def reset_enter_subplot_function
|
1715
|
+
@enter_subplot_function = nil
|
1716
|
+
end
|
1717
|
+
|
1718
|
+
def def_exit_subplot_function(&cmd)
|
1719
|
+
if cmd == nil
|
1720
|
+
raise "Sorry: must provide a command block for def_exit_subplot_function"
|
1721
|
+
end
|
1722
|
+
@exit_subplot_function = cmd
|
1723
|
+
end
|
1724
|
+
|
1725
|
+
def reset_exit_subplot_function
|
1726
|
+
@exit_subplot_function = nil
|
1727
|
+
end
|
1728
|
+
|
1729
|
+
|
1730
|
+
def def_enter_context_function(&cmd)
|
1731
|
+
if cmd == nil
|
1732
|
+
raise "Sorry: must provide a command block for def_enter_context_function"
|
1733
|
+
end
|
1734
|
+
@enter_context_function = cmd
|
1735
|
+
end
|
1736
|
+
|
1737
|
+
def reset_enter_context_function
|
1738
|
+
@enter_subplot_context = nil
|
1739
|
+
end
|
1740
|
+
|
1741
|
+
def def_exit_context_function(&cmd)
|
1742
|
+
if cmd == nil
|
1743
|
+
raise "Sorry: must provide a command block for def_exit_context_function"
|
1744
|
+
end
|
1745
|
+
@exit_context_function = cmd
|
1746
|
+
end
|
1747
|
+
|
1748
|
+
def reset_exit_context_function
|
1749
|
+
@exit_subplot_context = nil
|
1750
|
+
end
|
1751
|
+
|
1752
|
+
|
1753
|
+
def eval_function(string)
|
1754
|
+
result = string
|
1755
|
+
if @eval_command == nil
|
1756
|
+
begin
|
1757
|
+
result = eval(string)
|
1758
|
+
rescue Exception => er
|
1759
|
+
report_error(er, nil)
|
1760
|
+
end
|
1761
|
+
else
|
1762
|
+
begin
|
1763
|
+
result = @eval_command.call(string)
|
1764
|
+
rescue Exception => er
|
1765
|
+
report_error(er, nil)
|
1766
|
+
end
|
1767
|
+
end
|
1768
|
+
return result
|
1769
|
+
end
|
1770
|
+
|
1771
|
+
def def_figure(name, &cmd)
|
1772
|
+
name = name.split(' ').join('_') # replace blanks by underscores since names must be okay for shell
|
1773
|
+
if cmd == nil
|
1774
|
+
raise "Sorry: must provide a command block for def_figure"
|
1775
|
+
end
|
1776
|
+
if (num = @figure_names.index(name)) == nil
|
1777
|
+
@figure_names << name
|
1778
|
+
num = @figure_names.index(name)
|
1779
|
+
@num_figures = @figure_names.length
|
1780
|
+
end
|
1781
|
+
@figure_commands[num] = cmd
|
1782
|
+
return cmd
|
1783
|
+
end
|
1784
|
+
|
1785
|
+
def figure_index(name)
|
1786
|
+
return @figure_names.index(name)
|
1787
|
+
end
|
1788
|
+
|
1789
|
+
def make_figure(num)
|
1790
|
+
make_pdf(num)
|
1791
|
+
end
|
1792
|
+
|
1793
|
+
|
1794
|
+
def make_preview_pdf(num) # old name
|
1795
|
+
make_pdf(num)
|
1796
|
+
end
|
1797
|
+
|
1798
|
+
|
1799
|
+
def make_pdf(num) # returns pdf name if successful, false if failed.
|
1800
|
+
num = get_num_for_pdf(num)
|
1801
|
+
result = start_making_pdf(num)
|
1802
|
+
return unless result
|
1803
|
+
return @figure_pdfs[num] = finish_making_pdf(@figure_names[num])
|
1804
|
+
end
|
1805
|
+
|
1806
|
+
|
1807
|
+
def require_pdf(num)
|
1808
|
+
num = get_num_for_pdf(num)
|
1809
|
+
make_pdf(num) if @figure_pdfs[num] == nil
|
1810
|
+
return @figure_pdfs[num]
|
1811
|
+
end
|
1812
|
+
|
1813
|
+
|
1814
|
+
def require_all(fignums=nil, report=false, always_make=false)
|
1815
|
+
fignums = Array.new(@figure_names.length) {|i| i} if fignums == nil
|
1816
|
+
nums = []
|
1817
|
+
fignums.each do |num|
|
1818
|
+
if always_make || (@figure_pdfs[num] == nil)
|
1819
|
+
result = start_making_pdf(num)
|
1820
|
+
if result
|
1821
|
+
report_number_and_name(num,@figure_names[num]) if report
|
1822
|
+
nums << num
|
1823
|
+
else
|
1824
|
+
puts 'ERROR: Failed to make pdf for ' + @figure_names[num]
|
1825
|
+
end
|
1826
|
+
end
|
1827
|
+
end
|
1828
|
+
finish_making_pdfs(nums,report)
|
1829
|
+
return true
|
1830
|
+
end
|
1831
|
+
|
1832
|
+
|
1833
|
+
def make_all(fignums=nil, report=false)
|
1834
|
+
require_all(fignums, report, true)
|
1835
|
+
end
|
1836
|
+
|
1837
|
+
|
1838
|
+
def make_portfolio_pdf(name, fignums=nil, report=false)
|
1839
|
+
make_portfolio(name,fignums,report)
|
1840
|
+
end
|
1841
|
+
|
1842
|
+
|
1843
|
+
def make_portfolio(name, fignums=nil, report=false)
|
1844
|
+
require_all(fignums,report)
|
1845
|
+
private_make_portfolio(name, fignums, @figure_names)
|
1846
|
+
finish_making_pdf(name)
|
1847
|
+
end
|
1848
|
+
|
1849
|
+
|
1850
|
+
|
1851
|
+
|
1852
|
+
|
1853
|
+
|
1854
|
+
private
|
1855
|
+
|
1856
|
+
|
1857
|
+
def report_number_and_name(num,name)
|
1858
|
+
if num < 10
|
1859
|
+
puts ' ' + num.to_s + ' ' + name
|
1860
|
+
elsif num < 100
|
1861
|
+
puts ' ' + num.to_s + ' ' + name
|
1862
|
+
else
|
1863
|
+
puts num.to_s + ' ' + name
|
1864
|
+
end
|
1865
|
+
end
|
1866
|
+
|
1867
|
+
|
1868
|
+
def get_num_for_pdf(num)
|
1869
|
+
num = @figure_names.index(num) unless num.kind_of?(Integer)
|
1870
|
+
ensure_safe_save_dir
|
1871
|
+
num = num.to_i
|
1872
|
+
num_figures = @figure_names.size
|
1873
|
+
num += num_figures if num < 0
|
1874
|
+
if ((num < 0) or (num >= num_figures))
|
1875
|
+
puts "Sorry: number must be between 0 and #{num_figures-1}"
|
1876
|
+
num = nil
|
1877
|
+
end
|
1878
|
+
return num
|
1879
|
+
end
|
1880
|
+
|
1881
|
+
|
1882
|
+
def start_making_pdf(num) # returns true if successful, false if failed.
|
1883
|
+
num = get_num_for_pdf(num)
|
1884
|
+
if num == nil
|
1885
|
+
result = false
|
1886
|
+
else
|
1887
|
+
name = @figure_names[num]
|
1888
|
+
begin
|
1889
|
+
result = create_figure_temp_files(num)
|
1890
|
+
name = get_save_filename(name)
|
1891
|
+
rescue Exception => er
|
1892
|
+
report_error(er, "ERROR: make failed for #{name}")
|
1893
|
+
result = false
|
1894
|
+
end
|
1895
|
+
end
|
1896
|
+
return result
|
1897
|
+
end
|
1898
|
+
|
1899
|
+
|
1900
|
+
def create_figure_temp_files(name) # returns true if successful, false if failed.
|
1901
|
+
if name.kind_of?(Integer)
|
1902
|
+
num = name
|
1903
|
+
name = @figure_names[num]
|
1904
|
+
else
|
1905
|
+
num = @figure_names.index(name)
|
1906
|
+
end
|
1907
|
+
return false if num == nil
|
1908
|
+
cmd = @figure_commands[num]
|
1909
|
+
return false unless cmd.kind_of?(Proc)
|
1910
|
+
begin
|
1911
|
+
reset_legend_info
|
1912
|
+
result = private_make(name, cmd)
|
1913
|
+
return result
|
1914
|
+
rescue Exception => er
|
1915
|
+
report_error(er, "ERROR while executing command: #{cmd}")
|
1916
|
+
end
|
1917
|
+
return false
|
1918
|
+
end
|
1919
|
+
|
1920
|
+
|
1921
|
+
def finish_making_pdfs(fignums,report)
|
1922
|
+
if @multithreads_okay_for_tioga # run separate threads for the pdflatex processing
|
1923
|
+
threads = []
|
1924
|
+
fignums.each do |num|
|
1925
|
+
threads << Thread.new(num) { |i| finish_1_pdf(i,report) }
|
1926
|
+
end
|
1927
|
+
threads.each {|thr| thr.join}
|
1928
|
+
else
|
1929
|
+
fignums.each {|num| finish_1_pdf(num,report)}
|
1930
|
+
end
|
1931
|
+
return true
|
1932
|
+
end
|
1933
|
+
|
1934
|
+
|
1935
|
+
def finish_1_pdf(num,report)
|
1936
|
+
pdfname = finish_making_pdf(@figure_names[num])
|
1937
|
+
if pdfname != false
|
1938
|
+
@figure_pdfs[num] = pdfname
|
1939
|
+
report_number_and_name(num,pdfname) if report
|
1940
|
+
else
|
1941
|
+
puts 'ERROR: pdflatex failed to make pdf for ' + @figure_names[num]
|
1942
|
+
end
|
1943
|
+
end
|
1944
|
+
|
1945
|
+
|
1946
|
+
def finish_making_pdf(name) # returns pdfname if succeeds, false if fails.
|
1947
|
+
pdflatex = FigureMaker.pdflatex
|
1948
|
+
quiet = @quiet_mode
|
1949
|
+
run_directory = @run_dir
|
1950
|
+
if (@save_dir == nil)
|
1951
|
+
syscmd = "#{pdflatex} -interaction nonstopmode #{name}.tex > pdflatex.log 2>&1"
|
1952
|
+
else
|
1953
|
+
syscmd = "cd #{@save_dir}; #{pdflatex} -interaction nonstopmode #{name}.tex > pdflatex.log 2>&1"
|
1954
|
+
end
|
1955
|
+
result = system(syscmd)
|
1956
|
+
if !result
|
1957
|
+
if (@save_dir == nil)
|
1958
|
+
logname = "pdflatex.log"
|
1959
|
+
else
|
1960
|
+
logname = "#{@save_dir}/pdflatex.log"
|
1961
|
+
end
|
1962
|
+
puts "ERROR: #{pdflatex} failed."
|
1963
|
+
file = File.open(logname)
|
1964
|
+
if file == nil
|
1965
|
+
puts "cannot open #{logname}"
|
1966
|
+
else
|
1967
|
+
reporting = false; linecount = 0
|
1968
|
+
file.each_line do |line|
|
1969
|
+
firstchar = line[0..0]
|
1970
|
+
comparison = (firstchar <=> '!')
|
1971
|
+
reporting = true if comparison == 0
|
1972
|
+
if reporting
|
1973
|
+
puts line
|
1974
|
+
linecount = linecount + 1
|
1975
|
+
break if linecount == @num_error_lines
|
1976
|
+
end
|
1977
|
+
end
|
1978
|
+
file.close
|
1979
|
+
end
|
1980
|
+
end
|
1981
|
+
if result
|
1982
|
+
pdfname = name
|
1983
|
+
logname = "pdflatex.log"
|
1984
|
+
files = %w(.tex .out .aux .log _figure.pdf _figure.txt).map do |suffix|
|
1985
|
+
pdfname + suffix
|
1986
|
+
end
|
1987
|
+
files << logname
|
1988
|
+
files << "color_names.aux"
|
1989
|
+
if @save_dir # prepend directory specification
|
1990
|
+
files.map! do |f|
|
1991
|
+
"#{@save_dir}/#{f}"
|
1992
|
+
end
|
1993
|
+
end
|
1994
|
+
begin
|
1995
|
+
if @autocleanup
|
1996
|
+
files.each do |f|
|
1997
|
+
begin
|
1998
|
+
File.delete(f)
|
1999
|
+
rescue
|
2000
|
+
end
|
2001
|
+
end
|
2002
|
+
end
|
2003
|
+
end
|
2004
|
+
pdfname = "#{@save_dir}/#{pdfname}" if @save_dir != nil
|
2005
|
+
pdfname = "#{run_directory}/#{pdfname}" if run_directory != nil && pdfname[0..0] != '/'
|
2006
|
+
pdfname += ".pdf"
|
2007
|
+
return pdfname
|
2008
|
+
end
|
2009
|
+
return false
|
2010
|
+
end
|
2011
|
+
|
2012
|
+
def internal_show_image(dict, is_mask)
|
2013
|
+
check_dict(dict, @@keys_for_show_image, 'show_image')
|
2014
|
+
ll = dict['ll']; lr = dict['lr']; ul = dict['ul']
|
2015
|
+
w = alt_names(dict, 'w', 'width')
|
2016
|
+
h = alt_names(dict, 'h', 'height')
|
2017
|
+
opacity_mask = alt_names(dict, 'opacity_mask', 'stencil_mask')
|
2018
|
+
if opacity_mask != nil
|
2019
|
+
mask_xo_num = internal_show_image(opacity_mask, true)
|
2020
|
+
else
|
2021
|
+
mask_xo_num = 0
|
2022
|
+
end
|
2023
|
+
filename = alt_names(dict, 'jpg', 'JPG')
|
2024
|
+
filename = dict['jpeg'] if filename == nil
|
2025
|
+
filename = dict['JPEG'] if filename == nil
|
2026
|
+
if filename != nil
|
2027
|
+
return private_show_jpg(filename, w, h, [ll[0], ll[1], lr[0], lr[1], ul[0], ul[1]], mask_xo_num)
|
2028
|
+
end
|
2029
|
+
interpolate = get_if_given_else_default(dict, 'interpolate', true)
|
2030
|
+
data = dict['data']
|
2031
|
+
value_mask = dict['value_mask']
|
2032
|
+
color_space = alt_names(dict, 'color_space', 'colormap')
|
2033
|
+
color_space = dict['color_map'] if color_space == nil
|
2034
|
+
if color_space == nil
|
2035
|
+
raise "Sorry: must specify 'color_space' for the image"
|
2036
|
+
end
|
2037
|
+
if color_space == 'MONO' || color_space == 'mono'
|
2038
|
+
raise "Sorry: monochrome image must not itself have a mask" unless mask_xo_num == 0
|
2039
|
+
reversed = get_if_given_else_default(dict, 'reversed', false)
|
2040
|
+
xo_obj = private_show_monochrome_image(ll[0], ll[1], lr[0], lr[1], ul[0], ul[1],
|
2041
|
+
interpolate, reversed, w, h, data, ((is_mask)? -1 : 0))
|
2042
|
+
return is_mask ? xo_obj : self
|
2043
|
+
end
|
2044
|
+
if color_space == 'GRAY' || color_space == 'gray' || color_space == 'GREY' || color_space == 'grey'
|
2045
|
+
if is_mask
|
2046
|
+
raise("Sorry: mask must not itself have a mask") unless mask_xo_num == 0
|
2047
|
+
mask_xo_num = -1
|
2048
|
+
end
|
2049
|
+
xo_obj = private_show_grayscale_image(ll[0], ll[1], lr[0], lr[1], ul[0], ul[1],
|
2050
|
+
interpolate, w, h, data, mask_xo_num)
|
2051
|
+
return is_mask ? xo_obj : self
|
2052
|
+
end
|
2053
|
+
if is_mask
|
2054
|
+
raise "Sorry: mask image must have 'color_space' set to 'gray' or 'mono'"
|
2055
|
+
end
|
2056
|
+
if color_space == 'RGB' || color_space == 'rgb'
|
2057
|
+
private_show_rgb_image(ll[0], ll[1], lr[0], lr[1], ul[0], ul[1], interpolate, w, h, data, mask_xo_num)
|
2058
|
+
return self
|
2059
|
+
end
|
2060
|
+
if color_space == 'CMYK' || color_space == 'cmyk'
|
2061
|
+
private_show_cmyk_image(ll[0], ll[1], lr[0], lr[1], ul[0], ul[1], interpolate, w, h, data, mask_xo_num)
|
2062
|
+
return self
|
2063
|
+
end
|
2064
|
+
if value_mask == nil
|
2065
|
+
value_mask_min = value_mask_max = 256
|
2066
|
+
elsif value_mask.kind_of?Integer
|
2067
|
+
value_mask_min = value_mask_max = value_mask
|
2068
|
+
else
|
2069
|
+
value_mask_min = value_mask[0];
|
2070
|
+
value_mask_max = value_mask[1];
|
2071
|
+
end
|
2072
|
+
private_show_image(
|
2073
|
+
ll[0], ll[1], lr[0], lr[1], ul[0], ul[1], interpolate,
|
2074
|
+
w, h, data, value_mask_min, value_mask_max, color_space[0], color_space[1], mask_xo_num)
|
2075
|
+
return self
|
2076
|
+
end
|
2077
|
+
|
2078
|
+
def report_error(er, msg)
|
2079
|
+
if msg != nil
|
2080
|
+
puts msg
|
2081
|
+
puts ""
|
2082
|
+
end
|
2083
|
+
puts " " + "#{er.message}" + " [version: " + FigureMaker.version + "]"
|
2084
|
+
line_count = 0
|
2085
|
+
show_count = 0
|
2086
|
+
past_callers_routines = false
|
2087
|
+
in_callers_routines = false
|
2088
|
+
er.backtrace.each do |line|
|
2089
|
+
if (line.include?('Tioga/FigMkr.rb')) || (line.include?('Tioga/tioga_ui.rb'))
|
2090
|
+
if in_callers_routines
|
2091
|
+
past_callers_routines = true
|
2092
|
+
in_callers_routines = false
|
2093
|
+
end
|
2094
|
+
else
|
2095
|
+
in_callers_routines = true
|
2096
|
+
end
|
2097
|
+
if (show_count < @num_error_lines) and in_callers_routines
|
2098
|
+
puts " " + line
|
2099
|
+
show_count = show_count + 1
|
2100
|
+
end
|
2101
|
+
line_count = line_count + 1
|
2102
|
+
end
|
2103
|
+
end
|
2104
|
+
|
2105
|
+
|
2106
|
+
def make_page(cmd) # the C implementation uses this to call the page function for the figure
|
2107
|
+
entry_function = @enter_page_function
|
2108
|
+
exit_function = @exit_page_function
|
2109
|
+
unless entry_function == nil
|
2110
|
+
begin
|
2111
|
+
entry_result = entry_function.call
|
2112
|
+
rescue Exception => er
|
2113
|
+
report_error(er, nil)
|
2114
|
+
end
|
2115
|
+
end
|
2116
|
+
result = do_cmd(cmd)
|
2117
|
+
unless result == false or exit_function == nil
|
2118
|
+
begin
|
2119
|
+
exit_result = exit_function.call
|
2120
|
+
rescue Exception => er
|
2121
|
+
report_error(er, nil)
|
2122
|
+
end
|
2123
|
+
end
|
2124
|
+
return result
|
2125
|
+
end
|
2126
|
+
|
2127
|
+
|
2128
|
+
def do_cmd(cmd) # the C implementation uses this to call Ruby commands
|
2129
|
+
begin
|
2130
|
+
cmd.call
|
2131
|
+
return true
|
2132
|
+
rescue Exception => er
|
2133
|
+
report_error(er, nil)
|
2134
|
+
end
|
2135
|
+
return false
|
2136
|
+
end
|
2137
|
+
|
2138
|
+
def check_dict(dict,names,str)
|
2139
|
+
dict.each_key do |name|
|
2140
|
+
if names[name] == nil
|
2141
|
+
raise "Sorry: Invalid dictionary key for #{str} (#{name})."
|
2142
|
+
end
|
2143
|
+
end
|
2144
|
+
end
|
2145
|
+
|
2146
|
+
def set_if_given(name, dict)
|
2147
|
+
val = dict[name]
|
2148
|
+
return if val == nil
|
2149
|
+
eval "self." + name + " = val"
|
2150
|
+
end
|
2151
|
+
|
2152
|
+
def alt_names(dict, name1, name2)
|
2153
|
+
val = dict[name1]
|
2154
|
+
val = dict[name2] if val == nil
|
2155
|
+
return val
|
2156
|
+
end
|
2157
|
+
|
2158
|
+
def get_if_given_else_use_default_dict(dict, name, default_dict)
|
2159
|
+
if dict != nil
|
2160
|
+
val = dict[name]
|
2161
|
+
return val if val != nil
|
2162
|
+
end
|
2163
|
+
val = default_dict[name]
|
2164
|
+
if val == nil
|
2165
|
+
raise "Sorry: failed to find value for '#{name}' in the defaults dictionary."
|
2166
|
+
end
|
2167
|
+
return val
|
2168
|
+
end
|
2169
|
+
|
2170
|
+
def get_if_given_else_default(dict, name, default)
|
2171
|
+
return default if dict == nil
|
2172
|
+
val = dict[name]
|
2173
|
+
return val if val != nil
|
2174
|
+
return default
|
2175
|
+
end
|
2176
|
+
|
2177
|
+
def complain_if_missing_numeric_arg(dict, name, alt_name, who_called)
|
2178
|
+
val = dict[name]
|
2179
|
+
val = dict[alt_name] if val == nil
|
2180
|
+
if val == nil
|
2181
|
+
raise "Sorry: Must supply '#{name}' in call to '#{who_called}'"
|
2182
|
+
end
|
2183
|
+
if !(val.kind_of?Numeric)
|
2184
|
+
raise "Sorry: Must supply numeric value for '#{name}' in call to '#{who_called}'"
|
2185
|
+
end
|
2186
|
+
return val
|
2187
|
+
end
|
2188
|
+
|
2189
|
+
def check_pair(ary, name, who_called)
|
2190
|
+
return false if ary == nil
|
2191
|
+
if !(ary.kind_of?(Array) || ary.kind_of?(Dvector)) and ary.size == 2
|
2192
|
+
raise "Sorry: '#{name}' must be array [x,y] for #{who_called}."
|
2193
|
+
end
|
2194
|
+
return true
|
2195
|
+
end
|
2196
|
+
|
2197
|
+
def get_dvec(dict, name, who_called)
|
2198
|
+
val = dict[name]
|
2199
|
+
if val == nil || !(val.kind_of? Dvector)
|
2200
|
+
raise "Sorry: '#{name}' must be a Dvector for '#{who_called}'"
|
2201
|
+
end
|
2202
|
+
return val
|
2203
|
+
end
|
2204
|
+
|
2205
|
+
# We make sure that save_dir exists and is a directory, creating it
|
2206
|
+
# if necessary.
|
2207
|
+
def ensure_safe_save_dir
|
2208
|
+
if @save_dir
|
2209
|
+
if File.exists?(@save_dir)
|
2210
|
+
raise "save_dir (#{@save_dir}) exists and is not a directory" unless File.directory?(@save_dir)
|
2211
|
+
else
|
2212
|
+
# we create the directory if possible
|
2213
|
+
if @create_save_dir
|
2214
|
+
Dir.mkdir @save_dir
|
2215
|
+
else
|
2216
|
+
raise "save_dir (#{@save_dir}) doesn't exist " +
|
2217
|
+
" and I was told not to create it"
|
2218
|
+
end
|
2219
|
+
end
|
2220
|
+
end
|
2221
|
+
end
|
2222
|
+
|
2223
|
+
end # class FigureMaker
|
2224
|
+
end # module Tioga
|