ctioga2 0.12 → 0.13
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.
- checksums.yaml +4 -4
- data/Changelog +12 -0
- data/lib/ctioga2/commands/doc/doc.rb +34 -0
- data/lib/ctioga2/commands/doc/help.rb +3 -0
- data/lib/ctioga2/commands/doc/html.rb +1 -1
- data/lib/ctioga2/commands/doc/man.rb +1 -1
- data/lib/ctioga2/commands/doc/markup.rb +6 -0
- data/lib/ctioga2/commands/general-commands.rb +13 -0
- data/lib/ctioga2/commands/interpreter.rb +1 -1
- data/lib/ctioga2/commands/parsers/file.rb +9 -2
- data/lib/ctioga2/commands/parsers/old-file.rb +1 -1
- data/lib/ctioga2/data/backends/backends/gnuplot.rb +1 -1
- data/lib/ctioga2/data/backends/backends/text.rb +2 -25
- data/lib/ctioga2/data/datacolumn.rb +34 -0
- data/lib/ctioga2/data/dataset.rb +11 -13
- data/lib/ctioga2/data/filters.rb +24 -5
- data/lib/ctioga2/data/stack.rb +3 -2
- data/lib/ctioga2/graphics/elements.rb +7 -0
- data/lib/ctioga2/graphics/elements/histogram.rb +22 -1
- data/lib/ctioga2/graphics/elements/subplot.rb +11 -3
- data/lib/ctioga2/graphics/legends/area.rb +2 -2
- data/lib/ctioga2/graphics/legends/items.rb +2 -2
- data/lib/ctioga2/graphics/styles/background.rb +1 -1
- data/lib/ctioga2/graphics/styles/image.rb +1 -0
- data/lib/ctioga2/graphics/styles/plot-types.rb +19 -0
- data/lib/ctioga2/graphics/styles/plot.rb +2 -2
- data/lib/ctioga2/graphics/styles/styles.rb +1 -1
- data/lib/ctioga2/graphics/styles/texts.rb +5 -2
- data/lib/ctioga2/graphics/subplot-commands.rb +1 -1
- data/lib/ctioga2/graphics/types/boundaries.rb +7 -0
- data/lib/ctioga2/graphics/types/dimensions.rb +2 -2
- data/lib/ctioga2/graphics/types/grid.rb +5 -0
- data/lib/ctioga2/graphics/types/point.rb +2 -2
- data/lib/ctioga2/plotmaker.rb +46 -2
- data/lib/ctioga2/ruby.rb +1 -1
- data/lib/ctioga2/utils.rb +100 -7
- data/lib/ctioga2/version.rb +2 -2
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c0bb20ba501e3fd5bda7270ed5ef5330e0dd27c1
|
4
|
+
data.tar.gz: 67b4272430de8d90aa5b539fb7ac6d8c21a9e111
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 108ec5f7a5549506ba8ca7472949bbffae2d8fe4180cf1eff08bf0722a86a971ab3375a8a4594defa94e2a5e289e81909d7a6d0f8f7f0096e7a3708bab334d10
|
7
|
+
data.tar.gz: fec86d2c4348f8c9862f419e1c4ba4aa0b00fd81801134ac2c6b6fe75012815cc8966f3417e6f6bcfc1f4ad94e958f72aa5b225cb76f3d1d2921303d6b3c3a28
|
data/Changelog
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
ctioga2 (0.13)
|
2
|
+
|
3
|
+
* Change the stroke width when using draw-marker
|
4
|
+
* Customizable outut PDF resolution
|
5
|
+
* Can now get the standard deviation as error bars using avg-dup-last
|
6
|
+
* Handling of histograms with 'holes' in X values (closes: SF issue #1)
|
7
|
+
* Various improvements in the emacs mode, including contextual help
|
8
|
+
* Automatic generation of dependencies (makefile format)
|
9
|
+
* Many bug fixes
|
10
|
+
|
11
|
+
-- Vincent <vincent.fourmond@9online.fr> Thu 11 Jun 23:01:19 CEST 2015
|
12
|
+
|
1
13
|
ctioga2 (0.12)
|
2
14
|
|
3
15
|
* The xyz-map plot type now handles correctly inhomogeneous grids (so long
|
@@ -90,6 +90,40 @@ module CTioga2
|
|
90
90
|
print_commandline_options(*self.documented_commands)
|
91
91
|
end
|
92
92
|
|
93
|
+
# Displays help on a given command
|
94
|
+
def display_help_on(cmd, options)
|
95
|
+
if ! cmd.is_a? Command
|
96
|
+
cd = Interpreter::commands[cmd]
|
97
|
+
raise "Unkown command '#{cmd}'" unless cd
|
98
|
+
cmd = cd
|
99
|
+
end
|
100
|
+
puts text_doc(cmd)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Returns a string that represents a plain text documentation
|
104
|
+
def text_doc(cmd, options = {})
|
105
|
+
|
106
|
+
size ||= 80
|
107
|
+
|
108
|
+
str = "Synopsis: "
|
109
|
+
str << cmd.name
|
110
|
+
for arg in cmd.arguments
|
111
|
+
str << " #{arg.type.name}"
|
112
|
+
end
|
113
|
+
|
114
|
+
os = ""
|
115
|
+
for k,v in cmd.optional_arguments
|
116
|
+
os << " /#{k}=#{v.type.name}"
|
117
|
+
end
|
118
|
+
s2 = WordWrapper.wrap(os, size-4) # 4 for the spaces
|
119
|
+
str << "\nOptions: #{s2.join("\n ")}"
|
120
|
+
shrt = MarkedUpText.new(self, cmd.short_description).to_s
|
121
|
+
mup = MarkedUpText.new(self, cmd.long_description).to_s
|
122
|
+
s2 = WordWrapper.wrap(mup.to_s, size)
|
123
|
+
return "#{cmd.name} -- #{shrt}\n#{str}\n#{s2.join("\n")}"
|
124
|
+
end
|
125
|
+
|
126
|
+
|
93
127
|
protected
|
94
128
|
|
95
129
|
|
@@ -140,6 +140,9 @@ module CTioga2
|
|
140
140
|
# Formats one entry of the commands
|
141
141
|
def format_one_entry(cmd)
|
142
142
|
sh, long, desc = cmd.option_strings
|
143
|
+
|
144
|
+
# Hmmm...
|
145
|
+
# desc = MarkedUpText.new(@doc, desc).to_s
|
143
146
|
|
144
147
|
str = "#{leading_spaces}%2s%1s %-#{@options_column_width}s" %
|
145
148
|
[ sh, (sh ? "," : " "), long]
|
@@ -144,7 +144,7 @@ module CTioga2
|
|
144
144
|
ln.gsub!(/<a[^>]+>(.*?)<\/a>/) { || $1 }
|
145
145
|
str += "<pre class='#{s[:cls]}'><a href='#{k}'>#{ln}</a></pre>\n"
|
146
146
|
end
|
147
|
-
out.puts "<h5 id='
|
147
|
+
out.puts "<h5 id='snippets-h5-#{cmd.name}' onclick='toggleExamples(this);'>Examples...</h5>\n<div id='snippets-#{cmd.name}' class='snippets'>#{str}</div>"
|
148
148
|
end
|
149
149
|
end
|
150
150
|
end
|
@@ -42,7 +42,20 @@ module CTioga2
|
|
42
42
|
Prints helps about short and long options available when run from the
|
43
43
|
command-line.
|
44
44
|
EOH
|
45
|
+
|
46
|
+
# Display help on the command-line
|
47
|
+
HelpOnCommand =
|
48
|
+
Cmd.new("help-on", nil,
|
49
|
+
"--help-on", [CmdArg.new('text') ]) do |plotmaker, cmd, options|
|
50
|
+
plotmaker.interpreter.doc.display_help_on(cmd, options)
|
51
|
+
exit
|
52
|
+
end
|
45
53
|
|
54
|
+
HelpOnCommand.describe("Prints help text about the given command",
|
55
|
+
<<EOH, GeneralGroup)
|
56
|
+
Prints help about the given command
|
57
|
+
EOH
|
58
|
+
|
46
59
|
# Prints the version of ctioga2 used
|
47
60
|
PrintVersion = Cmd.new("version", '-V', "--version", []) do |plotmaker|
|
48
61
|
puts "This is ctioga2 version #{CTioga2::Version::version}"
|
@@ -44,7 +44,7 @@ module CTioga2
|
|
44
44
|
|
45
45
|
# Runs a command file targeting the given _interpreter_.
|
46
46
|
def run_command_file(file, interpreter)
|
47
|
-
f = open(file)
|
47
|
+
f = Utils::open(file)
|
48
48
|
parse_io_object(f, interpreter)
|
49
49
|
end
|
50
50
|
|
@@ -208,8 +208,15 @@ module CTioga2
|
|
208
208
|
end
|
209
209
|
else
|
210
210
|
nxt = all_args.shift
|
211
|
+
if ! nxt
|
212
|
+
fatal { "Missing option text for option '#{o}'"}
|
213
|
+
end
|
211
214
|
if nxt =~ /^\s*=\s*$/
|
212
|
-
|
215
|
+
nxt = all_args.shift
|
216
|
+
if ! nxt
|
217
|
+
fatal { "Missing option text for option '#{o}'"}
|
218
|
+
end
|
219
|
+
opts[o] = nxt
|
213
220
|
else
|
214
221
|
opts[o] = nxt.gsub(/^\s*=/,'')
|
215
222
|
end
|
@@ -78,7 +78,7 @@ EOD
|
|
78
78
|
date = File::mtime(filename)
|
79
79
|
# Get it from the cache !
|
80
80
|
debug { "Running gnuplot on file #{filename}" }
|
81
|
-
f =
|
81
|
+
f = Utils::open(filename)
|
82
82
|
# We open a bidirectionnal connection to gnuplot:
|
83
83
|
gnuplot = IO.popen("gnuplot", "r+")
|
84
84
|
output = ""
|
@@ -39,15 +39,6 @@ module CTioga2
|
|
39
39
|
|
40
40
|
class TextBackend < Backend
|
41
41
|
|
42
|
-
# A constant holding a relation extension -> command to
|
43
|
-
# decompress (to be fed to sprintf with the filename as argument)
|
44
|
-
UNCOMPRESSORS = {
|
45
|
-
".gz" => "gunzip -c %s",
|
46
|
-
".bz2" => "bunzip2 -c %s",
|
47
|
-
".lzma" => "unlzma -c %s",
|
48
|
-
".lz" => "unlzma -c %s",
|
49
|
-
".xz" => "unxz -c %s",
|
50
|
-
}
|
51
42
|
|
52
43
|
include Dobjects
|
53
44
|
|
@@ -171,23 +162,9 @@ EOD
|
|
171
162
|
return $stdin
|
172
163
|
elsif file =~ /(.*?)\|\s*$/ # A pipe
|
173
164
|
return IO.popen($1)
|
174
|
-
|
175
|
-
|
176
|
-
for ext,method in UNCOMPRESSORS
|
177
|
-
if File.readable? "#{file}#{ext}"
|
178
|
-
info { "Using compressed file #{file}#{ext} in stead of #{file}" }
|
179
|
-
return IO.popen(method % "#{file}#{ext}")
|
180
|
-
end
|
181
|
-
end
|
182
|
-
else
|
183
|
-
for ext, method in UNCOMPRESSORS
|
184
|
-
if file =~ /#{ext}$/
|
185
|
-
info { "Taking file #{file} as a compressed file" }
|
186
|
-
return IO.popen(method % file)
|
187
|
-
end
|
188
|
-
end
|
165
|
+
else
|
166
|
+
return Utils::open(file)
|
189
167
|
end
|
190
|
-
return File::open(file)
|
191
168
|
end
|
192
169
|
|
193
170
|
# A line is invalid if it is blank or starts
|
@@ -283,6 +283,40 @@ module CTioga2
|
|
283
283
|
v.replace(v.convolve(kernel,middle)) if v
|
284
284
|
end
|
285
285
|
end
|
286
|
+
|
287
|
+
# Resize all the columns to the given size.
|
288
|
+
def resize!(new_size)
|
289
|
+
for v in all_vectors
|
290
|
+
v.resize(new_size) if v
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
# Averages over the given indices, and puts the result at the
|
295
|
+
# target index.
|
296
|
+
#
|
297
|
+
# Different averaging modes are available.
|
298
|
+
def average_over(istart, iend, itgt, mode = :avg)
|
299
|
+
case mode
|
300
|
+
when :avg
|
301
|
+
# Stupidly average over all the values
|
302
|
+
for v in all_vectors
|
303
|
+
if v
|
304
|
+
av = Utils::average_vector(v, istart, iend)
|
305
|
+
v[itgt] = av[0]
|
306
|
+
end
|
307
|
+
end
|
308
|
+
when :stddev
|
309
|
+
# Ignore errors, and set them from the standard deviation
|
310
|
+
@min_values ||= @values.dup
|
311
|
+
@max_values ||= @values.dup
|
312
|
+
|
313
|
+
av = Utils::average_vector(@values, istart, iend, 2)
|
314
|
+
@values[itgt] = av[0]
|
315
|
+
stddev = (av[1] - av[0]**2)**0.5
|
316
|
+
@min_values[itgt] = av[0] - stddev
|
317
|
+
@max_values[itgt] = av[0] + stddev
|
318
|
+
end
|
319
|
+
end
|
286
320
|
|
287
321
|
protected
|
288
322
|
|
data/lib/ctioga2/data/dataset.rb
CHANGED
@@ -269,18 +269,19 @@ module CTioga2
|
|
269
269
|
# Average all the non-X values of successive data points that
|
270
270
|
# have the same X values. It is a naive version that also
|
271
271
|
# averages the error columns.
|
272
|
-
def average_duplicates!
|
272
|
+
def average_duplicates!(mode = :avg)
|
273
273
|
last_x = nil
|
274
274
|
last_x_first_idx = 0
|
275
275
|
xv = @x.values
|
276
276
|
i = 0
|
277
277
|
vectors = all_vectors
|
278
|
+
nb_x = 0
|
278
279
|
while i < xv.size
|
279
280
|
x = xv[i]
|
280
281
|
if ((last_x == x) && (i != (xv.size - 1)))
|
281
282
|
# Do nothing
|
282
283
|
else
|
283
|
-
if last_x_first_idx
|
284
|
+
if last_x_first_idx <= (i - 1) ||
|
284
285
|
((last_x == x) && (i == (xv.size - 1)))
|
285
286
|
if i == (xv.size - 1)
|
286
287
|
e = i
|
@@ -288,24 +289,21 @@ module CTioga2
|
|
288
289
|
e = i-1
|
289
290
|
end # The end of the slice.
|
290
291
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
for v in vectors
|
296
|
-
subv = v[last_x_first_idx..e]
|
297
|
-
ave = subv.sum/subv.size
|
298
|
-
v.slice!(last_x_first_idx+1, e - last_x_first_idx)
|
299
|
-
v[last_x_first_idx] = ave
|
292
|
+
# Now, we delegate to the columns the task of averaging.
|
293
|
+
@x.average_over(last_x_first_idx, e, nb_x, :avg)
|
294
|
+
for c in @ys
|
295
|
+
c.average_over(last_x_first_idx, e, nb_x, mode)
|
300
296
|
end
|
301
|
-
|
297
|
+
nb_x += 1
|
302
298
|
end
|
303
299
|
last_x = x
|
304
300
|
last_x_first_idx = i
|
305
301
|
end
|
306
302
|
i += 1
|
307
303
|
end
|
308
|
-
|
304
|
+
for c in all_columns
|
305
|
+
c.resize!(nb_x)
|
306
|
+
end
|
309
307
|
end
|
310
308
|
|
311
309
|
# Applies formulas to values. Formulas are like text-backend
|
data/lib/ctioga2/data/filters.rb
CHANGED
@@ -123,10 +123,30 @@ Install the {command: cherry-pick-last} command as a dataset hook (see
|
|
123
123
|
false for subsequent datasets will be removed.
|
124
124
|
EOH
|
125
125
|
|
126
|
+
AVGDupModeRE = {
|
127
|
+
/naive|avg|average/i => :avg,
|
128
|
+
/stddev/i => :stddev,
|
129
|
+
}
|
130
|
+
|
131
|
+
AVGDupMode =
|
132
|
+
CmdType.new('average-mode',
|
133
|
+
{:type => :re_list,
|
134
|
+
:list => AVGDupModeRE}, <<EOD)
|
135
|
+
How the {command: avg-dup-last} command :
|
136
|
+
|
137
|
+
* @naive@ or @average@ (the default) treats all columns (values and
|
138
|
+
error bars) the same way, and average everythin
|
139
|
+
* @stddev@ ignores the original errors, and sets the new errors to the
|
140
|
+
standard deviation of the values
|
141
|
+
EOD
|
142
|
+
|
143
|
+
|
144
|
+
|
126
145
|
AverageDupOperation =
|
127
146
|
Cmd.new("avg-dup-last", nil, "--avg-dup-last",
|
128
|
-
[], {}) do |plotmaker|
|
129
|
-
|
147
|
+
[], {'mode' => CmdArg.new('average-mode')}) do |plotmaker, opts|
|
148
|
+
mode = opts['mode'] || :avg
|
149
|
+
plotmaker.data_stack.last.average_duplicates!(mode)
|
130
150
|
end
|
131
151
|
|
132
152
|
AverageDupOperation.describe("Average successive elements with identical X values",
|
@@ -135,9 +155,8 @@ Averages successive points with identical X values. This algorithm is
|
|
135
155
|
naive with respect to the min/max values and averages them just as
|
136
156
|
well, whereas one might expect something more clever.
|
137
157
|
|
138
|
-
To average over
|
139
|
-
dataset, you
|
140
|
-
|
158
|
+
To average over all X values when they are not successive in the
|
159
|
+
dataset, you should use {command: sort-last} first.
|
141
160
|
EOH
|
142
161
|
|
143
162
|
AverageDupFilter =
|
data/lib/ctioga2/data/stack.rb
CHANGED
@@ -78,8 +78,8 @@ module CTioga2
|
|
78
78
|
end
|
79
79
|
|
80
80
|
csv.describe("reads CSV files",
|
81
|
-
|
82
|
-
Now parse the following data files as CSV.
|
81
|
+
<<"EOH", "backend-text")
|
82
|
+
Now parse the following data files as CSV. Equivalent to
|
83
83
|
|
84
84
|
# text /separator=/[,;]/
|
85
85
|
EOH
|
@@ -373,6 +373,7 @@ EOH
|
|
373
373
|
}) do |plotmaker,opts|
|
374
374
|
ds = plotmaker.data_stack.specified_dataset(opts)
|
375
375
|
if opts['save']
|
376
|
+
# Writing
|
376
377
|
out = open(opts['save'], 'w')
|
377
378
|
else
|
378
379
|
out = STDOUT
|
@@ -69,6 +69,13 @@ EOH
|
|
69
69
|
cmd.describe("Sets the #{x.to_s.upcase} range",
|
70
70
|
<<EOH, PlotCoordinatesGroup)
|
71
71
|
Sets the range of the #{x.to_s.upcase} coordinates.
|
72
|
+
|
73
|
+
*Important note:* when the axis is in log range (using
|
74
|
+
{command: #{x.to_s.upcase}log}), the numbers you give are not the or
|
75
|
+
{command: ylog} values, but their @log10@, so that to
|
76
|
+
display #{x.to_s.upcase} values from @1e-2@ to @1e3@, use:
|
77
|
+
|
78
|
+
# #{x.to_s}yrange -2:3
|
72
79
|
EOH
|
73
80
|
CoordinateRelatedCommands << cmd
|
74
81
|
|
@@ -193,6 +193,25 @@ module CTioga2
|
|
193
193
|
return parent.gp_cache[:histograms]
|
194
194
|
end
|
195
195
|
|
196
|
+
# Computes the number of histograms to be displayed in total
|
197
|
+
# -- or, at least, the total number of slots.
|
198
|
+
def compute_hist_number(x_values)
|
199
|
+
case @histogram_style.compute_dx
|
200
|
+
when nil, false
|
201
|
+
return x_values.size
|
202
|
+
when :mindx
|
203
|
+
xv = Dvector.new(x_values.to_a.sort)
|
204
|
+
x1 = xv[0..-2]
|
205
|
+
x2 = xv[1..-1]
|
206
|
+
x2.sub!(x1)
|
207
|
+
x2.abs!
|
208
|
+
subs = (xv.max - xv.min)/(x2.min)
|
209
|
+
return subs.round+1
|
210
|
+
else
|
211
|
+
raise "Invalid compute-dx type: #{@histogram_style.compute_dx}"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
196
215
|
# Returns the cached metrics of all the histograms,
|
197
216
|
# recomputing it in the process.
|
198
217
|
def get_cached_metrics(t)
|
@@ -228,7 +247,9 @@ module CTioga2
|
|
228
247
|
# values (which means in particular that they won't be
|
229
248
|
# positioned at the exact X value, but that's already the
|
230
249
|
# case anyway).
|
231
|
-
|
250
|
+
number = compute_hist_number(x_values)
|
251
|
+
|
252
|
+
width = (x_values.max - x_values.min)/(number - 1).to_f
|
232
253
|
if width.nan? || width == 0.0
|
233
254
|
# Only 1 X value, we use a width of 1
|
234
255
|
# ??
|
@@ -131,6 +131,12 @@ module CTioga2
|
|
131
131
|
bounds[k] ||= Types::SimpleRange.new(nil,nil)
|
132
132
|
bounds[k].override(b)
|
133
133
|
end
|
134
|
+
for k, b in bounds
|
135
|
+
if ! b.valid?
|
136
|
+
error { "Invalid computed range, you probably have only empty datasets" }
|
137
|
+
bounds[k] = Types::SimpleRange.new(0.0,1.0)
|
138
|
+
end
|
139
|
+
end
|
134
140
|
return bounds
|
135
141
|
end
|
136
142
|
|
@@ -158,6 +164,7 @@ module CTioga2
|
|
158
164
|
def real_do(t)
|
159
165
|
# First thing, we setup the boundaries
|
160
166
|
@computed_boundaries = compute_boundaries
|
167
|
+
p @computed_boundaries
|
161
168
|
|
162
169
|
real_boundaries = get_boundaries
|
163
170
|
|
@@ -176,15 +183,16 @@ module CTioga2
|
|
176
183
|
dx = t.convert_figure_to_output_dx(1.0)
|
177
184
|
dy = t.convert_figure_to_output_dy(1.0)
|
178
185
|
|
179
|
-
frm = [0.0, dx
|
180
|
-
-dy
|
186
|
+
frm = [0.0, dx/(@style.frame_real_size * t.scaling_factor),
|
187
|
+
-dy/(@style.frame_real_size * t.scaling_factor), 0.0]
|
181
188
|
@computed_boundaries = {
|
182
189
|
:bottom => Types::SimpleRange.new(frm[0], frm[1]),
|
183
190
|
:left => Types::SimpleRange.new(frm[2], frm[3]),
|
184
191
|
}
|
185
192
|
t.set_bounds(frm)
|
186
193
|
else
|
187
|
-
|
194
|
+
bnds = real_boundaries.to_a
|
195
|
+
t.set_bounds(bnds)
|
188
196
|
end
|
189
197
|
|
190
198
|
# First, gather up all elements by depth
|
@@ -148,10 +148,10 @@ module CTioga2
|
|
148
148
|
w, h = size(t, container)
|
149
149
|
case @legend_type
|
150
150
|
when :left, :right
|
151
|
-
return [width + t.convert_figure_to_output_dx(w)/
|
151
|
+
return [width + t.convert_figure_to_output_dx(w)/t.scaling_factor,
|
152
152
|
height]
|
153
153
|
when :top, :bottom
|
154
|
-
return [width, height + t.convert_figure_to_output_dy(h)/
|
154
|
+
return [width, height + t.convert_figure_to_output_dy(h)/t.scaling_factor]
|
155
155
|
when :inside
|
156
156
|
return [width, height]
|
157
157
|
end
|
@@ -78,9 +78,9 @@ module CTioga2
|
|
78
78
|
info = t.get_text_size(legend_name)
|
79
79
|
|
80
80
|
if info.key? 'width'
|
81
|
-
width += t.convert_output_to_figure_dx(
|
81
|
+
width += t.convert_output_to_figure_dx(t.scaling_factor*info['width'])
|
82
82
|
|
83
|
-
h = t.convert_output_to_figure_dy(
|
83
|
+
h = t.convert_output_to_figure_dy(t.scaling_factor*info['height'])
|
84
84
|
if h > height
|
85
85
|
height = h
|
86
86
|
end
|
@@ -95,7 +95,7 @@ EOD
|
|
95
95
|
Cmd.new('background', nil, '--background',
|
96
96
|
[ CmdArg.new('color-or-false') ]) do |plotmaker, color|
|
97
97
|
PlotStyle.current_plot_style(plotmaker).
|
98
|
-
background.background_color = color
|
98
|
+
background.style.background_color = color
|
99
99
|
end
|
100
100
|
|
101
101
|
BackgroundColorCmd.describe("Background color for the plot",
|
@@ -137,6 +137,21 @@ How to specify that histograms should be stacked. Can be:
|
|
137
137
|
* next, in which case the following histograms get stacked on a new slot
|
138
138
|
EOD
|
139
139
|
|
140
|
+
ComputeDxRE = {
|
141
|
+
/^no(ne)?$/i => false,
|
142
|
+
/^min(dx)?$/i => :mindx,
|
143
|
+
}
|
144
|
+
|
145
|
+
ComputeDx =
|
146
|
+
CmdType.new('compute-dx', {:type => :re_list,
|
147
|
+
:list => ComputeDxRE}, <<EOD)
|
148
|
+
This controls how the histograms treats unevenly spaced X values:
|
149
|
+
* @none@: ignores the problem, and treats the points as if they were all
|
150
|
+
evenly spaced
|
151
|
+
* @min@, @mindx@: considers that all slots have the size of the
|
152
|
+
smallest variation of X values
|
153
|
+
EOD
|
154
|
+
|
140
155
|
|
141
156
|
# This class defines various informations about the look of
|
142
157
|
# histograms.
|
@@ -151,6 +166,10 @@ EOD
|
|
151
166
|
# Specs for cumulative
|
152
167
|
typed_attribute :cumulative, 'cumulative-histograms'
|
153
168
|
|
169
|
+
# Whether one should assume evenly spaced X points or be more
|
170
|
+
# clever.
|
171
|
+
typed_attribute :compute_dx, 'compute-dx'
|
172
|
+
|
154
173
|
def set_from_hash(hash, name = "%s")
|
155
174
|
super
|
156
175
|
|
@@ -82,7 +82,7 @@ module CTioga2
|
|
82
82
|
|
83
83
|
# If not nil, then the boundaries are computed from the real
|
84
84
|
# dimensions of the plot frame, using the given number as a
|
85
|
-
# conversion factor from
|
85
|
+
# conversion factor from postscript points.
|
86
86
|
attr_accessor :frame_real_size
|
87
87
|
|
88
88
|
|
@@ -478,7 +478,7 @@ EOH
|
|
478
478
|
if u =~ /([\d.]+)?\s*(cm|in|bp|pt|mm)/
|
479
479
|
nb = $1 ? $1.to_f : 1.0
|
480
480
|
un = $2
|
481
|
-
style.frame_real_size =
|
481
|
+
style.frame_real_size = nb *
|
482
482
|
Types::Dimension::DimensionConversion.fetch(un)
|
483
483
|
else
|
484
484
|
raise 'Invalid unit'
|
@@ -245,8 +245,9 @@ module CTioga2
|
|
245
245
|
|
246
246
|
|
247
247
|
# The style for a string marker. Hmmm, this is somewhat
|
248
|
-
# redundant with
|
249
|
-
#
|
248
|
+
# redundant with MarkerStyle and I don't like that.
|
249
|
+
#
|
250
|
+
# Worse than that, it's not the same options !
|
250
251
|
class MarkerStringStyle < BasicStyle
|
251
252
|
|
252
253
|
# The angle of the text
|
@@ -272,6 +273,8 @@ module CTioga2
|
|
272
273
|
typed_attribute :stroke_color, 'color-or-false'
|
273
274
|
typed_attribute :fill_color, 'color-or-false'
|
274
275
|
|
276
|
+
typed_attribute :stroke_width, 'float'
|
277
|
+
|
275
278
|
|
276
279
|
# A number between 1 to 14 -- a PDF font
|
277
280
|
typed_attribute :font, "pdf-font"
|
@@ -117,7 +117,7 @@ EOH
|
|
117
117
|
Cmd.new("root-plot",nil,"--root-plot",
|
118
118
|
[
|
119
119
|
], Elements::TiogaElement::StyleBaseOptions) do |plotmaker, opts|
|
120
|
-
Log::debug { "
|
120
|
+
Log::debug { "Explicitly starting the root plot, options #{opts.inspect}" }
|
121
121
|
opts['id'] ||= 'root'
|
122
122
|
plotmaker.root_object.
|
123
123
|
enter_subobject(Elements::Subplot.new(nil,plotmaker.root_object, opts))
|
@@ -44,6 +44,13 @@ module CTioga2
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
+
# Checks if the range is valid, that is both elements are
|
48
|
+
# finite numbers
|
49
|
+
def valid?
|
50
|
+
return (Utils::finite_number?(@first) and
|
51
|
+
Utils::finite_number?(@last))
|
52
|
+
end
|
53
|
+
|
47
54
|
# Minimum value
|
48
55
|
def min
|
49
56
|
@first < @last ? @first : @last
|
@@ -134,7 +134,7 @@ module CTioga2
|
|
134
134
|
|
135
135
|
case @type
|
136
136
|
when :bp
|
137
|
-
return t.send("convert_output_to_figure_d#{orientation}", @value) *
|
137
|
+
return t.send("convert_output_to_figure_d#{orientation}", @value) * t.scaling_factor
|
138
138
|
when :dy
|
139
139
|
return t.send("default_text_height_d#{orientation}") * @value
|
140
140
|
when :frame
|
@@ -158,7 +158,7 @@ module CTioga2
|
|
158
158
|
def to_bp(t, orientation = nil)
|
159
159
|
orientation ||= @orientation
|
160
160
|
return t.send("convert_figure_to_output_d#{orientation}",
|
161
|
-
to_figure(t, orientation)) /
|
161
|
+
to_figure(t, orientation)) / t.scaling_factor
|
162
162
|
end
|
163
163
|
|
164
164
|
# Converts the Dimension to the *frame* coordinates of the
|
@@ -131,6 +131,11 @@ module CTioga2
|
|
131
131
|
@hscales, @vscales = nup.split(/\s*x\s*/).map { |x|
|
132
132
|
x.split(/\s*,\s*/).map { |y| y.to_f }
|
133
133
|
}
|
134
|
+
if @hscales.size == 1
|
135
|
+
@hscales = [1] * @hscales[0].to_i
|
136
|
+
elsif @vscales.size == 1
|
137
|
+
@vscales = [1] * @vscales[0].to_i
|
138
|
+
end
|
134
139
|
@nup = [@hscales.size, @vscales.size]
|
135
140
|
else
|
136
141
|
@nup = nup.split(/\s*x\s*/).map { |s| s.to_i }
|
@@ -128,8 +128,8 @@ module CTioga2
|
|
128
128
|
xl, yt = @tl.to_figure_xy(t)
|
129
129
|
xr, yb = @br.to_figure_xy(t)
|
130
130
|
|
131
|
-
return [t.convert_figure_to_output_dx(xr - xl) *
|
132
|
-
t.convert_figure_to_output_dy(yb - yt) *
|
131
|
+
return [t.convert_figure_to_output_dx(xr - xl) * t.scaling_factor,
|
132
|
+
t.convert_figure_to_output_dy(yb - yt) * t.scaling_factor]
|
133
133
|
end
|
134
134
|
|
135
135
|
# Returns an array of [ul, ll, lr] coordinates. If an aspect
|
data/lib/ctioga2/plotmaker.rb
CHANGED
@@ -226,6 +226,12 @@ module CTioga2
|
|
226
226
|
# errors. Useful on windows, where the windows closes before one
|
227
227
|
# has a chance to see anything.
|
228
228
|
attr_accessor :pause_on_errors
|
229
|
+
|
230
|
+
# If not empty, a Makefile file where the dependencies are written out
|
231
|
+
attr_accessor :makefile_dependencies
|
232
|
+
|
233
|
+
# The resolution of the PDF file
|
234
|
+
attr_accessor :pdf_resolution
|
229
235
|
|
230
236
|
|
231
237
|
# The first instance of PlotMaker created
|
@@ -368,7 +374,7 @@ module CTioga2
|
|
368
374
|
end
|
369
375
|
|
370
376
|
# We always cd into the target directory for creading the
|
371
|
-
|
377
|
+
Utils::chdir(path.dirname) do
|
372
378
|
fn = path.basename.to_s
|
373
379
|
|
374
380
|
efn = fn.gsub(/[.\s]/) do |x|
|
@@ -405,6 +411,14 @@ module CTioga2
|
|
405
411
|
|
406
412
|
file = path.to_s + ".pdf"
|
407
413
|
|
414
|
+
if @makefile_dependencies
|
415
|
+
File.open(@makefile_dependencies, "w") do |f|
|
416
|
+
deps = Utils::used_files.values
|
417
|
+
# TODO: handle spaces
|
418
|
+
f.puts "#{file}: #{deps.join(" ")}"
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
408
422
|
# Feed it
|
409
423
|
@postprocess.process_file(file, last)
|
410
424
|
return file
|
@@ -451,7 +465,7 @@ module CTioga2
|
|
451
465
|
|
452
466
|
# Creates a new FigureMaker object and returns it
|
453
467
|
def create_figure_maker
|
454
|
-
t = Tioga::FigureMaker.new
|
468
|
+
t = Tioga::FigureMaker.new(@pdf_resolution || 100)
|
455
469
|
t.tex_preamble += @latex_preamble
|
456
470
|
t.autocleanup = @cleanup
|
457
471
|
|
@@ -624,6 +638,25 @@ EOD
|
|
624
638
|
<<EOH, OutputSetupGroup)
|
625
639
|
Sets the size of the output PDF file, in real units. Takes arguments in the
|
626
640
|
form of 12cm x 3in (spaces can be omitted).
|
641
|
+
EOH
|
642
|
+
|
643
|
+
ResolutionCommand =
|
644
|
+
Cmd.new("resolution", false,"--resolution",
|
645
|
+
[ CmdArg.new('float') ],
|
646
|
+
) do |plotmaker, size, options|
|
647
|
+
plotmaker.pdf_resolution = size
|
648
|
+
end
|
649
|
+
|
650
|
+
ResolutionCommand.describe('Sets the output resolution',
|
651
|
+
<<EOH, OutputSetupGroup)
|
652
|
+
By default, ctioga2 has a resolution of 1/100th of a postscript
|
653
|
+
point. This is clearly enough for most tasks, but you can increase it
|
654
|
+
should you need, or decrease it to generate possibly a little more
|
655
|
+
jaggy but less large PDF files.
|
656
|
+
|
657
|
+
The number given is the number of output points per postscript point.
|
658
|
+
|
659
|
+
Better change that at the beginning of the plot.
|
627
660
|
EOH
|
628
661
|
|
629
662
|
CleanupCommand =
|
@@ -816,6 +849,17 @@ want any information to leak.
|
|
816
849
|
Please note that this will not log the values of the CTIOGA2_PRE and
|
817
850
|
CTIOGA2_POST variables, so you might still get a different output if
|
818
851
|
you make heavy use of those.
|
852
|
+
EOH
|
853
|
+
|
854
|
+
DepsCommand =
|
855
|
+
Cmd.new("dependencies",nil,"--dependencies",
|
856
|
+
[CmdArg.new('file') ]) do |plotmaker,val|
|
857
|
+
plotmaker.makefile_dependencies = val
|
858
|
+
end
|
859
|
+
|
860
|
+
DepsCommand.describe('Save dependencies',
|
861
|
+
<<EOH, OutputSetupGroup)
|
862
|
+
Saves the dependencies as a Makefike into the given file name.
|
819
863
|
EOH
|
820
864
|
|
821
865
|
end
|
data/lib/ctioga2/ruby.rb
CHANGED
data/lib/ctioga2/utils.rb
CHANGED
@@ -59,6 +59,11 @@ module CTioga2
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
+
# Returns true if the argument is a finite number
|
63
|
+
def self.finite_number?(flt)
|
64
|
+
return (flt.is_a?(Numeric) and flt.to_f.finite?)
|
65
|
+
end
|
66
|
+
|
62
67
|
# Converts a number to a float while trying to stay as lenient as
|
63
68
|
# possible
|
64
69
|
def self.txt_to_float(txt)
|
@@ -160,6 +165,24 @@ module CTioga2
|
|
160
165
|
end
|
161
166
|
end
|
162
167
|
|
168
|
+
# Returns the nth first modes
|
169
|
+
def self.average_vector(vect, istart, iend, n = 1)
|
170
|
+
rv = [0] * n
|
171
|
+
nb = 0
|
172
|
+
istart.upto(iend) do |i|
|
173
|
+
v = 1
|
174
|
+
y = vect[i]
|
175
|
+
n.times do |j|
|
176
|
+
v *= y
|
177
|
+
rv[j] += v
|
178
|
+
end
|
179
|
+
nb += 1
|
180
|
+
end
|
181
|
+
|
182
|
+
return rv.map do |v|
|
183
|
+
v/nb
|
184
|
+
end
|
185
|
+
end
|
163
186
|
|
164
187
|
# Groups the given strings by prefixes
|
165
188
|
|
@@ -176,6 +199,76 @@ module CTioga2
|
|
176
199
|
return sets_by_prefix
|
177
200
|
end
|
178
201
|
|
202
|
+
# An instrumentized version of Dir::chdir
|
203
|
+
def self.chdir(dir, &blk)
|
204
|
+
@current_dirs ||= []
|
205
|
+
@current_dirs << Pathname.new(dir)
|
206
|
+
Dir::chdir(dir, &blk)
|
207
|
+
@current_dirs.pop
|
208
|
+
end
|
209
|
+
|
210
|
+
# A constant holding a relation extension -> command to decompress
|
211
|
+
# (to be fed to sprintf with the filename as argument)
|
212
|
+
UNCOMPRESSORS = {
|
213
|
+
".gz" => "gunzip -c %s",
|
214
|
+
".bz2" => "bunzip2 -c %s",
|
215
|
+
".lzma" => "unlzma -c %s",
|
216
|
+
".lz" => "unlzma -c %s",
|
217
|
+
".xz" => "unxz -c %s",
|
218
|
+
}
|
219
|
+
|
220
|
+
# This opens a file for reading, keeping track of the opened files
|
221
|
+
# and possibly transparently decompressing files when
|
222
|
+
# applicable. Returns the file object, or runs the given block
|
223
|
+
# with it, closing the file at the end.
|
224
|
+
def self.open(file)
|
225
|
+
if not File.readable?(file)
|
226
|
+
# Try to find a compressed version
|
227
|
+
for ext,method in UNCOMPRESSORS
|
228
|
+
if File.readable? "#{file}#{ext}"
|
229
|
+
info { "Using compressed file #{file}#{ext} in stead of #{file}" }
|
230
|
+
ff = "#{file}#{ext}"
|
231
|
+
handle = IO.popen(method % ff)
|
232
|
+
break
|
233
|
+
end
|
234
|
+
end
|
235
|
+
else
|
236
|
+
for ext, method in UNCOMPRESSORS
|
237
|
+
if file =~ /#{ext}$/
|
238
|
+
info { "Taking file #{file} as a compressed file" }
|
239
|
+
ff = file
|
240
|
+
handle = IO.popen(method % file)
|
241
|
+
break
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
if ! handle
|
246
|
+
ff = file
|
247
|
+
handle = File::open(file)
|
248
|
+
end
|
249
|
+
|
250
|
+
# Unwrap directory
|
251
|
+
@used_files ||= {}
|
252
|
+
|
253
|
+
@current_dirs ||= []
|
254
|
+
rf = (@current_dirs + [file]).inject :+
|
255
|
+
rff = (@current_dirs + [ff]).inject :+
|
256
|
+
# The files referenced
|
257
|
+
@used_files[rf] = rff
|
258
|
+
if block_given?
|
259
|
+
yield handle
|
260
|
+
handle.close
|
261
|
+
else
|
262
|
+
return handle
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
|
267
|
+
# Returns the list of files that were read by ctioga2
|
268
|
+
def self.used_files()
|
269
|
+
return @used_files || {}
|
270
|
+
end
|
271
|
+
|
179
272
|
|
180
273
|
|
181
274
|
NaturalSubdivisions = [1.0, 2.0, 5.0, 10.0]
|
@@ -470,8 +563,7 @@ module CTioga2
|
|
470
563
|
# Watched text names
|
471
564
|
attr_accessor :watched_names
|
472
565
|
|
473
|
-
# A left, bottom, right, up bounding box (
|
474
|
-
# divided by 10)
|
566
|
+
# A left, bottom, right, up bounding box (postscript points)
|
475
567
|
attr_accessor :bb
|
476
568
|
|
477
569
|
def initialize
|
@@ -497,11 +589,11 @@ module CTioga2
|
|
497
589
|
return margins
|
498
590
|
end
|
499
591
|
left, top, right, bottom = *margins.to_frame_coordinates(t)
|
500
|
-
|
501
|
-
xl =
|
502
|
-
xr =
|
503
|
-
yt =
|
504
|
-
yb =
|
592
|
+
scl = 1/t.scaling_factor
|
593
|
+
xl = scl * t.convert_page_to_output_x(t.convert_frame_to_page_x(left))
|
594
|
+
xr = scl * t.convert_page_to_output_x(t.convert_frame_to_page_x(right))
|
595
|
+
yt = scl * t.convert_page_to_output_y(t.convert_frame_to_page_y(top))
|
596
|
+
yb = scl * t.convert_page_to_output_y(t.convert_frame_to_page_y(bottom))
|
505
597
|
|
506
598
|
vals = [ xl - @bb[0], @bb[2] - xr, @bb[3] - yt, yb - @bb[1]].map do |x|
|
507
599
|
x += padding
|
@@ -605,6 +697,7 @@ class Hash
|
|
605
697
|
end
|
606
698
|
|
607
699
|
|
700
|
+
|
608
701
|
class String
|
609
702
|
# Splits a string into substrings at the given regexp, but only if
|
610
703
|
# the splitting occurs at top-level with respect to parentheses.
|
data/lib/ctioga2/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ctioga2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.13'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vincent Fourmond <vincent.fourmond@9online.fr>
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-06-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tioga
|
@@ -16,20 +16,20 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1.
|
19
|
+
version: '1.19'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1.
|
26
|
+
version: '1.19'
|
27
27
|
description: |
|
28
28
|
ctioga2 is a command-driven plotting program that produces
|
29
29
|
high quality PDF files. It can be used both from the command-line
|
30
30
|
and using command files (at the same time).
|
31
31
|
|
32
|
-
It is based on Tioga (http://tioga.
|
32
|
+
It is based on Tioga (http://tioga.sourceforge.net).
|
33
33
|
email: vincent.fourmond@9online.fr
|
34
34
|
executables:
|
35
35
|
- ctioga2
|