ctioga2 0.12 → 0.13
Sign up to get free protection for your applications and to get access to all the features.
- 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
|