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 +276 -0
- data/gemspec +19 -0
- data/lib/iconPlot.rb +68 -0
- data/lib/icon_plot.ncl +653 -0
- data/lib/icon_plot_lib.ncl +1687 -0
- data/test/test_iconPlot.rb +33 -0
- metadata +52 -0
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
|