tioga 1.4
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/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
|