iconPlot 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/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