iconPlot 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/contrib/nclsh ADDED
@@ -0,0 +1,276 @@
1
+ #! /usr/bin/env perl
2
+
3
+ =head1 NAME
4
+
5
+ =encoding utf8
6
+
7
+ nclsh - Wrapper for NCL interpreter providing simplified passing of parameters
8
+
9
+ =head1 SYNOPSIS
10
+
11
+ B<nclsh> [I<FILE>] [I<OPTION>]... [I<ARG>]...
12
+
13
+ =head1 DESCRIPTION
14
+
15
+ This is a replacement for calling the NCAR Command Language (NCL) directly
16
+ whenever you need to pass command line arguments to NCL without twisting your
17
+ fingers into a knot.
18
+
19
+ It simply translates the parameters into a form recognized by NCL, and then
20
+ runs the B<ncl> command as configured on your system.
21
+ Within nclsh, ncl is run with the '-n' option,
22
+ i.e. print output is not prefixed by element indices.
23
+
24
+ =head2 Parameter translation
25
+
26
+ Any command line parameter is parsed and put into NCL syntax according to
27
+ these rules:
28
+
29
+ =over
30
+
31
+ =item *
32
+ Parameters beginning with '+', '-' or '--' are options.
33
+
34
+ =item *
35
+ Options that are continued with '=' take the remainder of the parameter as
36
+ value
37
+
38
+ =item *
39
+ Values may be scalar or arrays; array elements are separated by ',' or ':'.
40
+
41
+ =item *
42
+ Values are of type boolean ('True' or 'False', case-insensitive), numeric,
43
+ or string.
44
+
45
+ =item *
46
+ Options without value are taken to be boolean. Prefix '+' assigns 'False',
47
+ prefix '-' or '--' assigns 'True'.
48
+
49
+ =item *
50
+ If an option without value begins with '-no' or '--no', and the option name
51
+ is longer than 2 characters, the leading 'no' is stripped from the option,
52
+ and its value becomes 'False'.
53
+
54
+ =item *
55
+ The first non-option parameter is taken to be the NCL script file name. Its
56
+ treatment is described below
57
+
58
+ =item *
59
+ Any remaining non-option parameters are assigned to a string array option
60
+ named 'ARGS'. Therefore, 'ARGS' is not a valid option name for user options.
61
+ If there are no such parameters, 'ARGS' is undefined.
62
+
63
+ =item *
64
+ All options are passed to NCL as variable assignment. Variable name is the
65
+ option name without the '+', '-', '--', or 'no' prefixes. Scalar values are
66
+ assigned as NCL scalar, array values with NCL array syntax. All non-numeric
67
+ and non-boolean values are surrounded by NCL's string quote '"'.
68
+
69
+ =item *
70
+ For array assignments, all elements must have the same type. So, if elements
71
+ are not recognized to be all numeric or all boolean, all elements in that
72
+ array are interpreted as strings and quoted.
73
+
74
+ =back
75
+
76
+ Also note that, when calling nclsh, the usual shell restrictions apply when
77
+ you want to embed white space or meta-characters into your string values.
78
+
79
+ =head2 Examples
80
+
81
+ nclsh -format=pdf -> ncl format="pdf"
82
+ nclsh --format=pdf -> ncl format="pdf"
83
+ nclsh +format=pdf -> ncl format="pdf"
84
+ nclsh -values=12,34.56,78e9 -> ncl values=(/12,34.56,78e9/)
85
+ nclsh -variables=slp:sst -> ncl variables=(/"slp","sst"/)
86
+ nclsh -verbose -> ncl verbose=True
87
+ nclsh +verbose -> ncl verbose=False
88
+ nclsh -noverbose -> ncl verbose=False
89
+
90
+ I<Please note:>
91
+
92
+ nclsh -no -> ncl no=True
93
+ nclsh +no -> ncl no=False
94
+ nclsh +noverbose -> ncl noverbose=False
95
+ nclsh -values=12,True,78e9 -> ncl values=(/"12","True","78e9"/)
96
+
97
+ =head2 Script file
98
+
99
+ If a NCL script name has been recognized in the parameter list, nclsh checks
100
+ if the first line of this file contains the she-bang (#!) sequence.
101
+ If this is the case, the whole script is copied to a temporary file with the
102
+ first line commented out by NCLs comment character ';'.
103
+ This allows using nclsh as command script interpreter. The recommended way to
104
+ do this is heading your NCL script with the following line:
105
+
106
+ #! /usr/bin/env nclsh
107
+
108
+ Note that, in this case, any error message refers to the temp file name
109
+ instead of the original script file name. However this should make no
110
+ difference when using line numbers as only the first line is altered and
111
+ no lines are deleted or added.
112
+
113
+ =head1 SEE ALSO
114
+
115
+ The NCL website L<http://www.ncl.ucar.edu/>, providing all you ever wanted to know
116
+ about NCL, and possibly more.
117
+
118
+ =head1 AUTHOR
119
+
120
+ Written by Karl-Hermann Wieners, but ultimately inspired by Ralf Müller.
121
+
122
+ =head1 COPYRIGHT
123
+
124
+ Copyright (c) 2012 Max-Planck-Institut für Meteorologie, Hamburg, Germany
125
+
126
+ Copying and distribution of this file, with or without modification,
127
+ are permitted in any medium without royalty provided the copyright
128
+ notice and this notice are preserved. This file is offered as-is,
129
+ without any warranty.
130
+
131
+ =cut
132
+
133
+ #
134
+ # $Id: nclsh 216 2012-02-17 20:38:10Z m221078 $
135
+ #
136
+
137
+ use warnings;
138
+ use strict;
139
+
140
+ # Routines for generating safe temp files.
141
+ use File::Temp qw(tempfile);
142
+
143
+ my @args = (); # Non-option arguments (file names etc.)
144
+ my %opts = (); # Options and their values
145
+
146
+ my @params = (); # Parameter list for NCL call
147
+ my $file; # NCL script file name
148
+
149
+ # Parse command line and store results in @args and %opts
150
+
151
+ for my $arg (@ARGV) {
152
+ if($arg =~ /^(\+|--?)(\w+)(=(.*))?$/) {
153
+ # Anything looking like an option is handled here.
154
+ # $1 is option prefix, $2 is the option name, $4 are assigned values.
155
+ # $3 is the optional value assignment (= and values)
156
+
157
+ # Special option name ARGS is reserved for passing non-option args.
158
+ $2 ne 'ARGS' or die("Sorry: option name ARGS is reserved and may not be used!\n");
159
+
160
+ if(defined($3)) {
161
+ # If a value is assigned to the option, store it in %opts.
162
+ # Make sure that lists (separated by : or ,) are split.
163
+ my @vals = split(/[,:]/, $4, -1);
164
+ $opts{$2} = \@vals;
165
+ }
166
+ else {
167
+ # Options w/o assignment are taken to be Boolean.
168
+ if($1 eq '+') {
169
+ # Prefix + switches off named option
170
+ $opts{$2} = [ 'False' ];
171
+ }
172
+ elsif(length($2) > 2 && substr($2, 0, 2) eq 'no') {
173
+ # Prefixes --no... and -no... also denote switched off options.
174
+ # Option name is set by removing leading 'no' from name.
175
+ # Bare '-no' is taken as is, i.e. switched on with name 'no'.
176
+ $opts{substr($2, 2)} = [ 'False' ];
177
+ }
178
+ else {
179
+ # All other cases denote options that are switched on.
180
+ $opts{$2} = [ 'True' ];
181
+ }
182
+ }
183
+ }
184
+ else {
185
+ # Non-option i.e non-prefixed arguments are handled here.
186
+
187
+ if(defined($file)) {
188
+ # All except the first argument are put into the ARGS list
189
+ push(@args, $arg);
190
+ }
191
+ else {
192
+ # First non-option argument is taken to be the script file
193
+ $file = $arg;
194
+ }
195
+ }
196
+ }
197
+
198
+ # Transform options and arguments to NCL style
199
+
200
+ # Transform options to be stored in NCL parameter list
201
+ while(my ($key, $val) = each(%opts)) {
202
+ my @vals = @$val;
203
+
204
+ # All non-numeric and non-boolean values are considered strings.
205
+ # If one element in the value list is a string, all are stringified.
206
+ my $is_boolean = ! grep(!/^(true|false)$/i, @vals);
207
+ my $is_numeric = ! $is_boolean &&
208
+ ! grep(!/^[+-]?(\d+|\d+\.\d*|\d*\.\d+)([ed][-+]?\d+)?$/i, @vals);
209
+ my $is_string = ! $is_numeric && ! $is_boolean;
210
+
211
+ # Add quotes to string values.
212
+ if($is_string) {
213
+ @vals = map { '"'.$_.'"' } @vals;
214
+ }
215
+
216
+ # Capitalize booleans properly
217
+ if($is_boolean) {
218
+ @vals = map { uc(substr($_,0,1)).lc(substr($_,1)) } @vals;
219
+ }
220
+
221
+ # Store values into parameter list with option name as variable id.
222
+ if(@vals == 1) {
223
+ # Single value options are stored as scalar value.
224
+ push(@params, $key.'='.$vals[0]);
225
+ }
226
+ else {
227
+ # Multi-valued options are passed as array.
228
+ push(@params, $key.'=(/'.join(',', @vals).'/)');
229
+ }
230
+ }
231
+
232
+ # Transform non-option args. These are all put into a string array named ARGS.
233
+ if(@args) {
234
+ push(@params, 'ARGS=(/'.join(',', map { '"'.$_.'"' } @args).'/)');
235
+ }
236
+
237
+ # Handle the script file
238
+
239
+ if(defined($file)) {
240
+ # Check if first line contains she-bang.
241
+ # If so, copy contents to a temporary file, disabling first line.
242
+ # This allows using nclsh as script interpreter, but changes error messages
243
+ # to contain the temp file name instead of the script file name.
244
+
245
+ open(my $file_handle, '<', $file) or die("Sorry: cannot open file: $!\n");
246
+ if(defined($_ = <$file_handle>) && /^#!/) {
247
+ # First line is she-bang line.
248
+
249
+ # Temp file should be removed at exit.
250
+ my($temp_handle, $temp_name) = tempfile(UNLINK=>1);
251
+ # Comment out she-bang line for temp file
252
+ s/^/\;/;
253
+ print $temp_handle ($_);
254
+ # Copy remaining lines into temp file
255
+ while(<$file_handle>) {
256
+ print $temp_handle ($_);
257
+ }
258
+ push(@params, $temp_name);
259
+ }
260
+ else {
261
+ push(@params, $file);
262
+ }
263
+ close($file_handle);
264
+ }
265
+
266
+ # Add option for non-verbose printing within NCL.
267
+ unshift(@params, '-n');
268
+
269
+ # @todo Provide debugging output on demand
270
+ # while(my ($key, $val) = each(@params)) {
271
+ # print("$key: '$val'\n");
272
+ # }
273
+
274
+ # Must use system (not exec) to have temp file removed at exit
275
+ system('ncl', @params);
276
+
data/gemspec ADDED
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ $:.unshift File.join(File.dirname(__FILE__),"..","lib")
3
+
4
+ spec = Gem::Specification.new do |s|
5
+ s.name = "iconPlot"
6
+ s.version = '0.0.1'
7
+ s.platform = Gem::Platform::RUBY
8
+ s.files = ["lib/iconPlot.rb"] + ["gemspec"] + ["contrib/nclsh"] + Dir.glob("lib/*ncl")
9
+ s.test_file = "test/test_iconPlot.rb"
10
+ s.description = "Plot with ncl via Ruby: requires NCL 6.* and CDO 1.5.*"
11
+ s.summary = "Plot ICON output with ncl via Ruby"
12
+ s.author = "Ralf Mueller"
13
+ s.email = "stark.dreamdetective@gmail.com"
14
+ s.homepage = "https://github.com/Try2Code/iconPlot"
15
+ s.license = "GPLv2"
16
+ s.required_ruby_version = ">= 1.8"
17
+ end
18
+
19
+ # vim:ft=ruby
data/lib/iconPlot.rb ADDED
@@ -0,0 +1,68 @@
1
+ require 'fileutils'
2
+
3
+ class IconPlot < Struct.new(:caller,:plotter,:libdir,:otype,:display,:cdo,:debug)
4
+ def IconPlot.gemPath
5
+ gemSearcher = Gem::GemPathSearcher.new
6
+ gemspec = gemSearcher.find('iconPlot')
7
+ gemspec.gem_dir
8
+ end
9
+ def initialize(*args)
10
+ super(*args)
11
+
12
+ gempath = IconPlot.gemPath
13
+ defaults = {
14
+ :caller => [gempath,'contrib','nclsh'].join(File::SEPARATOR),
15
+ :plotter => [gempath,'lib','icon_plot.ncl'].join(File::SEPARATOR),
16
+ :libdir => [gempath,'lib'].join(File::SEPARATOR),
17
+ :otype => 'png',
18
+ :display => 'sxiv',
19
+ :cdo => ENV['CDO'].nil? ? 'cdo' : ENV['CDO'],
20
+ :debug => false
21
+ }
22
+ self.each_pair {|k,v| self[k] = defaults[k] if v.nil? }
23
+ end
24
+ def plot(ifile,ofile,varname,vartype='scalar',opts=[])
25
+ unless File.exists?(ifile)
26
+ warn "Input file #{ifile} dows NOT exist!"
27
+ exit
28
+ end
29
+ varIdent = case vartype
30
+ when 'scalar' then "-varName=#{varname}"
31
+ when 'vector' then "-vecVars=#{varname.split(' ').join(',')}"
32
+ when 'scatter' then "-plotMode=scatter -vecVars#{varname.split(' ').join(',')}"
33
+ else
34
+ warn "Wrong variable type #{vartype}"
35
+ exit
36
+ end
37
+
38
+ opts[:tStrg] =ofile
39
+
40
+ cmd = [self.caller,self.plotter].join(' ')
41
+ cmd << " -altLibDir=#{self.libdir} #{varIdent} -iFile=#{ifile} -oFile=#{ofile} -oType=#{self.otype} -isIcon -DEBUG"
42
+ opts.each {|k,v| cmd << " -"<< [k,v].join('=') }
43
+ puts cmd if self.debug
44
+ out = IO.popen(cmd).read
45
+ puts out if self.debug
46
+
47
+ return [FileUtils.pwd,"#{ofile}.#{self.otype}"].join(File::SEPARATOR)
48
+ end
49
+ def scalarPlot(ifile,ofile,varname,opts={})
50
+ plot(ifile,ofile,varname,'scalar',opts)
51
+ end
52
+ def vectorPlot(ifile,ofile,varname,opts={})
53
+ plot(ifile,ofile,varname,'vector',opts)
54
+ end
55
+
56
+ def del(file)
57
+ FileUtils.rm(file) if File.exists?(file)
58
+ end
59
+ def show(*files)
60
+ files.flatten.each {|file| IO.popen("#{self.display} #{file} &") }
61
+ end
62
+ def defaultPlot(ifile,ofile,opts={})
63
+ show(scalarPlot(ifile,ofile,DEFAULT_VARNAME,opts))
64
+ end
65
+ def showVector(ifile,ofile,vars,opts={})
66
+ show(vectorPlot(ifile,ofile,vars,opts))
67
+ end
68
+ end