ctioga2 0.6.1 → 0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,123 @@
1
+ # contour.rb: the style of a contour plot
2
+ # copyright (c) 2009 by Vincent Fourmond
3
+
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details (in the COPYING file).
13
+
14
+ require 'ctioga2/utils'
15
+ require 'ctioga2/log'
16
+
17
+
18
+ # This module contains all the classes used by ctioga
19
+ module CTioga2
20
+
21
+ Version::register_svn_info('$Revision$', '$Date$')
22
+
23
+ module Graphics
24
+
25
+ module Styles
26
+
27
+ StyleAspectRE = {
28
+ /^marker[_-]color$/i => :marker_color,
29
+ /^marker[_-](size|scale)$/i => :marker_scale,
30
+ }
31
+
32
+ StyleAspect =
33
+ CmdType.new('style-aspect', {:type => :re_list,
34
+ :list => StyleAspectRE}, <<EOD)
35
+
36
+ This type designs which aspect of the style of a
37
+ {command: xy-parametric} plot is controlled by a certain Z value.
38
+ It can take the following values:
39
+ * @marker_color@: the color for the markers
40
+ * @marker_size@/@marker_scale@: the size of the markers
41
+ EOD
42
+
43
+ # This class defines how the Z values are converted into
44
+ # stylistic information
45
+ class ParametricPlotStyle < BasicStyle
46
+
47
+ # What is the z1 axis
48
+ typed_attribute :z1, 'style-aspect'
49
+
50
+ # What is the z2 axis
51
+ typed_attribute :z2, 'style-aspect'
52
+
53
+ def initialize
54
+ @z1 = :marker_color
55
+ end
56
+
57
+ def prepare
58
+ @reversed = {}
59
+
60
+ 2.times do |i|
61
+ val = self.send("z#{i+1}")
62
+ if val
63
+ @reversed[val] = i
64
+ end
65
+ end
66
+ end
67
+
68
+ # Returns the marker style for the given Z values.
69
+ #
70
+ # This will only work if #prepare has been called first !
71
+ def marker_style(curve_style, zvalue, zmin, zmax)
72
+
73
+ style = curve_style.marker.dup
74
+
75
+ if @reversed[:marker_scale]
76
+ idx = @reversed[:marker_scale]
77
+ if idx < zvalue.size
78
+ max_scale = curve_style.marker.scale || 1.0
79
+
80
+ ## @todo Later on, when a min_marker_scale is provided,
81
+ ## then the scale will be constrained between the min
82
+ ## and max. For now, it is simply proportionnal to the
83
+ ## absolute value of the largest.
84
+ min_scale = curve_style.marker_min_scale
85
+
86
+ zm = zmin[idx]
87
+ zM = zmax[idx]
88
+
89
+ mm = zM.abs
90
+ m2 = zm.abs
91
+ mm = m2 if m2 > mm
92
+
93
+ z = zvalue[idx]
94
+
95
+ style.scale = if min_scale
96
+ min_scale + (max_scale - min_scale) *
97
+ (z - zm)/(zM - zm)
98
+ else
99
+ zvalue[idx].abs/mm * max_scale
100
+ end
101
+ end
102
+
103
+ end
104
+
105
+ if @reversed[:marker_color]
106
+ idx = @reversed[:marker_color]
107
+ if idx < zvalue.size
108
+ style.color = curve_style.marker_color_map.z_color(zvalue[idx],
109
+ zmin[idx],
110
+ zmax[idx])
111
+ end
112
+ end
113
+
114
+ return style
115
+
116
+ end
117
+
118
+ end
119
+ end
120
+
121
+ end
122
+ end
123
+
@@ -19,7 +19,7 @@ require 'ctioga2/graphics/coordinates'
19
19
  # This module contains all the classes used by ctioga
20
20
  module CTioga2
21
21
 
22
- Version::register_svn_info('$Revision: 488 $', '$Date: 2013-09-03 00:31:36 +0200 (Tue, 03 Sep 2013) $')
22
+ Version::register_svn_info('$Revision: 521 $', '$Date: 2013-09-21 18:55:05 +0200 (Sat, 21 Sep 2013) $')
23
23
 
24
24
  module Graphics
25
25
 
@@ -355,13 +355,27 @@ EOH
355
355
 
356
356
  end
357
357
 
358
+ asco = AxisStyleOptions.dup
359
+ asco['also-axes'] = CmdArg.new('axis')
360
+
358
361
  AxisStyleCommand =
359
362
  Cmd.new("axis-style",nil,"--axis-style",
360
363
  [
361
364
  CmdArg.new('axis'),
362
- ], AxisStyleOptions) do |plotmaker, which, opts|
363
- style = AxisStyle.current_axis_style(plotmaker, which)
364
- style.set_from_hash(opts)
365
+ ], asco) do |plotmaker, which, opts|
366
+ axes = [which]
367
+ if opts['also-axes']
368
+ axes += opts['also-axes'].split(/\s*,\s*/)
369
+ end
370
+
371
+ for w in axes
372
+ begin
373
+ style = AxisStyle.current_axis_style(plotmaker, w)
374
+ style.set_from_hash(opts)
375
+ rescue Exception => e
376
+ error {"Error while setting style of axis: #{w} -- #{e}"}
377
+ end
378
+ end
365
379
  end
366
380
  AxisStyleCommand.
367
381
  describe("Sets the style of the given axis",
@@ -370,6 +384,10 @@ This command can be used to set various aspects of the style of the
370
384
  given axis, through its various options, which are documented in more details
371
385
  in the {command: define-axis-style} command -- excepted for the @ticks@ bit
372
386
  which are documented in the {command: ticks} command.
387
+
388
+ If the option @also-axes@ is specified, the style is also applied to
389
+ the comma-separated list of axes it contains.
390
+
373
391
  EOH
374
392
 
375
393
  ClearAxesCommand =
@@ -26,7 +26,7 @@ require 'ctioga2/graphics/types/grid'
26
26
  # This module contains all the classes used by ctioga
27
27
  module CTioga2
28
28
 
29
- Version::register_svn_info('$Revision: 466 $', '$Date: 2013-08-31 13:10:38 +0200 (Sat, 31 Aug 2013) $')
29
+ Version::register_svn_info('$Revision: 523 $', '$Date: 2013-09-22 15:31:16 +0200 (Sun, 22 Sep 2013) $')
30
30
 
31
31
  module Graphics
32
32
 
@@ -49,6 +49,7 @@ module CTioga2
49
49
 
50
50
  ColorType = CmdType.new('color', {
51
51
  :type => :tioga_color,
52
+ :namespace => Tioga::ColorConstants,
52
53
  }, <<EOD)
53
54
  A color. It can take three forms:
54
55
  * a named color, see
@@ -61,9 +62,10 @@ EOD
61
62
  ColorOrFalseType =
62
63
  CmdType.new('color-or-false', {
63
64
  :type => :tioga_color,
65
+ :namespace => Tioga::ColorConstants,
64
66
  :shortcuts => {'none' => false }
65
67
  }, <<EOD)
66
- A {type: color}, or false to say that nothing should be drawn.
68
+ A {type: color}, or none to say that nothing should be drawn.
67
69
  EOD
68
70
 
69
71
 
data/lib/ctioga2/log.rb CHANGED
@@ -16,7 +16,7 @@ require 'logger'
16
16
 
17
17
  module CTioga2
18
18
 
19
- Version::register_svn_info('$Revision: 497 $', '$Date: 2013-09-04 22:07:55 +0200 (Wed, 04 Sep 2013) $')
19
+ Version::register_svn_info('$Revision: 522 $', '$Date: 2013-09-22 12:02:48 +0200 (Sun, 22 Sep 2013) $')
20
20
 
21
21
  # This module should be included (or extended) by every class that
22
22
  # need logging/debugging facilities.
@@ -101,7 +101,10 @@ module CTioga2
101
101
 
102
102
  # A logged replacement for system
103
103
  def spawn(cmd, priority = :info)
104
- retval = system(cmd)
104
+ if cmd.is_a? String
105
+ cmd = [cmd]
106
+ end
107
+ retval = system(*cmd)
105
108
  self.send(priority) { "Spawned #{cmd} -> " +
106
109
  if retval
107
110
  "success"
@@ -20,7 +20,7 @@ require 'ctioga2/utils'
20
20
 
21
21
  module CTioga2
22
22
 
23
- Version::register_svn_info('$Revision: 151 $', '$Date: 2010-06-19 23:45:20 +0200 (Sat, 19 Jun 2010) $')
23
+ Version::register_svn_info('$Revision: 523 $', '$Date: 2013-09-22 15:31:16 +0200 (Sun, 22 Sep 2013) $')
24
24
 
25
25
 
26
26
  # The MetaBuilder module contains a framework to perform
@@ -104,6 +104,13 @@ module CTioga2
104
104
  # passed through without further modification.
105
105
  attr_accessor :passthrough
106
106
 
107
+ # An array of module whose constants can be used "as such"
108
+ attr_accessor :namespace
109
+
110
+ # When a :namespace option is provided, this hash provides a
111
+ # lookup 'lowercase name' => constant value.
112
+ attr_accessor :namespace_lookup
113
+
107
114
  # A default constructor. It should be safe to use it directly for
108
115
  # children, unless something more specific is needed. Any descendent
109
116
  # should *always* register _type_ as @type - or, even better, call
@@ -128,6 +135,7 @@ module CTioga2
128
135
 
129
136
  end
130
137
 
138
+
131
139
  # This class function actually registers the current type
132
140
  # to the Type ancestor. _name_ should be a symbol.
133
141
  # Moreover, if the second argument is provided, it automatically
@@ -200,11 +208,12 @@ module CTioga2
200
208
  end
201
209
  end
202
210
  end
211
+
203
212
  # Then, constants lookup.
204
213
  if @type.key?(:namespace)
205
214
  begin
206
215
  return stt_run_hook(lookup_const(string))
207
- rescue Exception
216
+ rescue IncorrectInput
208
217
  end
209
218
  end
210
219
  return stt_run_hook(string_to_type_internal(string))
@@ -276,17 +285,32 @@ module CTioga2
276
285
 
277
286
  protected
278
287
 
288
+ def build_namespace_lookup
289
+ if @type[:namespace]
290
+ @namespace = [@type[:namespace]].flatten
291
+
292
+ @namespace_lookup = {}
293
+ for m in @namespace
294
+ for c in m.constants
295
+ @namespace_lookup[c.to_s.downcase] = m.const_get(c)
296
+ end
297
+ end
298
+ end
299
+
300
+ end
301
+
279
302
  # Looks for the value as a constant specified in the :namespace
280
303
  # modules. Raises IncorrectInput if not found.
281
304
  def lookup_const(str)
282
- for mod in [@type[:namespace]].flatten
283
- begin
284
- return mod.const_get(str)
285
- rescue
286
- # Nothing, we still look up
287
- end
305
+ str = str.downcase
306
+ if @type[:namespace] && (! @namespace_lookup)
307
+ build_namespace_lookup
308
+ end
309
+ if @namespace_lookup.key? str
310
+ return @namespace_lookup[str]
311
+ else
312
+ raise IncorrectInput, "Constant #{str} not found"
288
313
  end
289
- raise IncorrectInput, "Constant #{str} not found"
290
314
  end
291
315
 
292
316
  # The internal function for converting type to a string. Used by
@@ -158,7 +158,7 @@ require 'ctioga2/postprocess'
158
158
  # displays of rate constants vs potentials)
159
159
  module CTioga2
160
160
 
161
- Version::register_svn_info('$Revision: 508 $', '$Date: 2013-09-09 22:13:14 +0200 (Mon, 09 Sep 2013) $')
161
+ Version::register_svn_info('$Revision: 522 $', '$Date: 2013-09-22 12:02:48 +0200 (Sun, 22 Sep 2013) $')
162
162
 
163
163
  # This class is the core of ctioga. It parses the command-line arguments,
164
164
  # reads all necessary files and plots graphs. Most of its functionality
@@ -700,12 +700,18 @@ EOH
700
700
 
701
701
  XpdfViewerCommand =
702
702
  Cmd.new("xpdf",'-X',"--xpdf", [ ]) do |plotmaker|
703
- plotmaker.postprocess.viewer = "xpdf -z page"
703
+ plotmaker.postprocess.viewer = :auto
704
704
  end
705
705
 
706
706
  XpdfViewerCommand.describe('Uses xpdf to view the produced PDF files',
707
707
  <<EOH, OutputSetupGroup)
708
708
  Uses xpdf to view the PDF files produced by ctioga2.
709
+
710
+ If xpdf is not found, then it tries to guess which viewers are available:
711
+ * on windows, it uses the system file associations to open the PDF file
712
+ * on mac, it uses the open command
713
+ * on linux, it tries, mime-open, and if that is missing, falls back to
714
+ commonly available PDF viewers.
709
715
  EOH
710
716
 
711
717
  OpenViewerCommand =
@@ -17,7 +17,7 @@ require 'ctioga2/log'
17
17
 
18
18
  module CTioga2
19
19
 
20
- Version::register_svn_info('$Revision: 155 $', '$Date: 2010-06-21 21:41:32 +0200 (Mon, 21 Jun 2010) $')
20
+ Version::register_svn_info('$Revision: 522 $', '$Date: 2013-09-22 12:02:48 +0200 (Sun, 22 Sep 2013) $')
21
21
 
22
22
  # What happens to generated PDF files ?
23
23
  #
@@ -69,6 +69,33 @@ module CTioga2
69
69
  end
70
70
 
71
71
 
72
+ # Try to open the file with xpdf, or fallback to system defaults
73
+ def view_pdf(pdf)
74
+ if Utils.which("xpdf")
75
+ spawn(["xpdf", "-z", "page", pdf])
76
+ else
77
+ case Utils.os
78
+ when :windows
79
+ # Use start
80
+ spawn(["start", "/B", pdf])
81
+ when :macosx
82
+ spawn(["open", pdf])
83
+ else
84
+ for w in %w{evince gv mimeopen}
85
+ if Utils.which(w)
86
+ if w == "mimeopen"
87
+ spawn(["mimeopen", "-n", pdf])
88
+ else
89
+ spawn([w, pdf])
90
+ end
91
+ break
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+
72
99
  # Process the given _file_. If _last_ is true, things that should
73
100
  # only happen last happen.
74
101
  def process_file(file, last = false)
@@ -96,15 +123,19 @@ module CTioga2
96
123
 
97
124
  # View produced PDF or PNG files...
98
125
  if (last || @view_all) && @viewer
99
- if @png_res
100
- cmd = "display #{target}"
101
- elsif @viewer =~ /%s/
102
- cmd = @viewer % file
126
+ if @viewer == :auto
127
+ view_pdf(file)
103
128
  else
104
- cmd = "#{@viewer} #{file}"
129
+ if @png_res
130
+ cmd = "display #{target}"
131
+ elsif @viewer =~ /%s/
132
+ cmd = @viewer % file
133
+ else
134
+ cmd = "#{@viewer} #{file}"
135
+ end
136
+ info { "Spawning the viewer as requested for #{file}" }
137
+ spawn(cmd)
105
138
  end
106
- info { "Spawning the viewer as requested for #{file}" }
107
- spawn(cmd)
108
139
  end
109
140
  end
110
141
 
data/lib/ctioga2/utils.rb CHANGED
@@ -11,6 +11,9 @@
11
11
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
12
  # GNU General Public License for more details (in the COPYING file).
13
13
 
14
+ # For platform detection
15
+ require 'rbconfig'
16
+
14
17
  module CTioga2
15
18
 
16
19
  # An exception to raise upon to-be-implemented-one-day features
@@ -35,7 +38,7 @@ module CTioga2
35
38
  # arguments and have the Date and Revision svn:keyword:. Use this
36
39
  # way:
37
40
  #
38
- # Version::register_svn_info('$Revision: 508 $', '$Date: 2013-09-09 22:13:14 +0200 (Mon, 09 Sep 2013) $')
41
+ # Version::register_svn_info('$Revision: 532 $', '$Date: 2013-09-29 12:13:33 +0200 (Sun, 29 Sep 2013) $')
39
42
  #
40
43
  # To set the correct properties, the following command-line can be
41
44
  # used:
@@ -75,7 +78,7 @@ module CTioga2
75
78
  }
76
79
 
77
80
  # The position of the URL, used for getting the version
78
- SVN_URL = '$HeadURL: svn+ssh://rubyforge.org/var/svn/ctioga2/releases/ctioga2-0.6.1/lib/ctioga2/utils.rb $'
81
+ SVN_URL = '$HeadURL: svn+ssh://rubyforge.org/var/svn/ctioga2/releases/ctioga2-0.7/lib/ctioga2/utils.rb $'
79
82
 
80
83
  # The version of ctioga2
81
84
  CTIOGA_VERSION = if SVN_URL =~ /releases\/ctioga2-([^\/]+)/
@@ -84,7 +87,7 @@ module CTioga2
84
87
  "SVN version"
85
88
  end
86
89
 
87
- register_svn_info('$Revision: 508 $', '$Date: 2013-09-09 22:13:14 +0200 (Mon, 09 Sep 2013) $')
90
+ register_svn_info('$Revision: 532 $', '$Date: 2013-09-29 12:13:33 +0200 (Sun, 29 Sep 2013) $')
88
91
 
89
92
  end
90
93
 
@@ -254,6 +257,93 @@ module CTioga2
254
257
  end
255
258
  return file # But that will fail later on.
256
259
  end
260
+
261
+
262
+
263
+ # Cross-platform way of finding an executable in the $PATH.
264
+ #
265
+ # This is adapted from
266
+ # http://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby
267
+ def self.which(cmd)
268
+ return nil unless cmd
269
+ exts = ['']
270
+ if ENV['PATHEXT']
271
+ exts += ENV['PATHEXT'].split(';')
272
+ end
273
+
274
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
275
+ exts.each { |ext|
276
+ exe = File.join(path, "#{cmd}#{ext}")
277
+ return exe if File.executable? exe
278
+ }
279
+ end
280
+ return nil
281
+ end
282
+
283
+
284
+ # Reliable OS detection, coming from:
285
+ #
286
+ # http://stackoverflow.com/questions/11784109/detecting-operating-systems-in-ruby
287
+ def self.os
288
+ host_os = RbConfig::CONFIG['host_os']
289
+ case host_os
290
+ when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
291
+ :windows
292
+ when /darwin|mac os/
293
+ :macosx
294
+ when /linux/
295
+ :linux
296
+ when /solaris|bsd/
297
+ :unix
298
+ else
299
+ warn {"Unknown os: #{host_os.inspect}"}
300
+ :unknown
301
+ end
302
+ end
303
+
304
+
305
+ # Cluster a series of objects by the values returned by the given
306
+ # funcall. It returns an array of arrays where the elements are in
307
+ # the same order, and in each sub-array, the functions all return
308
+ # the same value
309
+ #
310
+ # @todo with block too ?
311
+ def self.cluster_by_value(list, funcall)
312
+ if list.size == 0
313
+ return []
314
+ end
315
+ ret = [ [list[0]] ]
316
+ cur = ret[0]
317
+ last = cur.first.send(funcall)
318
+
319
+ for o in list[1..-1]
320
+ val = o.send(funcall)
321
+ if last == val
322
+ cur << o
323
+ else
324
+ cur = [o]
325
+ ret << cur
326
+ last = val
327
+ end
328
+ end
329
+
330
+ return ret
331
+ end
332
+
333
+
334
+ # Returns a hash value -> [elements] in which the elements are in
335
+ # the same order
336
+ def self.sort_by_value(list, funcall)
337
+ ret = {}
338
+
339
+ for el in list
340
+ val = el.send(funcall)
341
+ ret[val] ||= []
342
+
343
+ ret[val] << el
344
+ end
345
+ return ret
346
+ end
257
347
  end
258
348
 
259
349