From a07d3c4cd485d99a180161f849317acac2a899e1 Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Fri, 11 Sep 2015 13:09:51 -0700 Subject: [PATCH 001/191] Display plots are now preserved, instead of constantly being thrown out --- Packages/vcs/Lib/Canvas.py | 29 +++++++++++++++++++++-------- Packages/vcs/Lib/VTKPlots.py | 8 ++++---- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/Packages/vcs/Lib/Canvas.py b/Packages/vcs/Lib/Canvas.py index 7f066aec8..cf4edd2d4 100644 --- a/Packages/vcs/Lib/Canvas.py +++ b/Packages/vcs/Lib/Canvas.py @@ -2374,7 +2374,7 @@ Options::: 'xbounds', 'ybounds', 'xname', 'yname', 'xunits', 'yunits', 'xweights', 'yweights', 'comment1', 'comment2', 'comment3', 'comment4', 'hms', 'long_name', 'zaxis', 'zarray', 'zname', 'zunits', 'taxis', 'tarray', 'tname', 'tunits', 'waxis', 'warray', - 'wname', 'wunits', 'bg', 'ratio', 'donotstoredisplay', 'render'] + 'wname', 'wunits', 'bg', 'ratio', 'donotstoredisplay', 'render', "display_name"] # def replot(self): # """ Clears and plots with last used plot arguments @@ -3584,14 +3584,18 @@ Options::: "unknown taylordiagram graphic method: %s" % arglist[4]) t.plot(arglist[0], canvas=self, template=arglist[2], **keyargs) - nm, src = self.check_name_source(None, "default", "display") - dn = displayplot.Dp(nm) + + dname = keyargs.get("display_name") + if dname is not None: + dn = vcs.elements["display"][dname] + else: + nm, src = self.check_name_source(None, "default", "display") + dn = displayplot.Dp(nm) dn.template = arglist[2] dn.g_type = arglist[3] dn.g_name = arglist[4] dn.array = arglist[:2] dn.extradisplays = t.displays -# dn.array=arglist[0] for p in slab_changed_attributes.keys(): tmp = slab_changed_attributes[p] if tmp == (None, None): @@ -3838,9 +3842,13 @@ Options::: else: returned_kargs = self.backend.plot(*arglist, **keyargs) if not keyargs.get("donotstoredisplay", False): - nm, src = self.check_name_source( - None, "default", "display") - dn = displayplot.Dp(nm) + dname = keyargs.get("display_name") + if dname is not None: + dn = vcs.elements['display'][dname] + else: + nm, src = self.check_name_source( + None, "default", "display") + dn = displayplot.Dp(nm) dn.template = arglist[2] dn.g_type = arglist[3] dn.g_name = arglist[4] @@ -3990,6 +3998,10 @@ Options::: self.configurator.stop_animating() self.animate_info = [] self.animate.update_animate_display_list() + + preserve_display = kargs.get("preserve_display", False) + if "preserve_display" in kargs: + del kargs["preserve_display"] self.backend.clear(*args, **kargs) for nm in self.display_names: # Lets look at elements created by dispaly production @@ -4004,7 +4016,8 @@ Options::: for k in new_elts[e]: if k in vcs.elements[e].keys(): del(vcs.elements[e][k]) - del(vcs.elements["display"][nm]) + if not preserve_display: + del(vcs.elements["display"][nm]) self.display_names = [] return diff --git a/Packages/vcs/Lib/VTKPlots.py b/Packages/vcs/Lib/VTKPlots.py index eb923f0c4..db6f45d97 100644 --- a/Packages/vcs/Lib/VTKPlots.py +++ b/Packages/vcs/Lib/VTKPlots.py @@ -232,15 +232,15 @@ class VTKVCSBackend(object): parg.append(d.g_type) parg.append(d.g_name) plots_args.append(parg) + key = {"display_name": dnm} if d.ratio is not None: - key_args.append({"ratio": d.ratio}) - else: - key_args.append({}) + key["ratio"] = d.ratio + key_args.append(key) # Have to pull out the UI layer so it doesn't get borked by the clear self.hideGUI() - self.canvas.clear(render=False) + self.canvas.clear(render=False, preserve_display=True) for i, pargs in enumerate(plots_args): self.canvas.plot(*pargs, render=False, **key_args[i]) -- GitLab From 10e92c09f824d91719a15e1bf2093e21904f605b Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Tue, 26 Jan 2016 14:52:54 -0800 Subject: [PATCH 002/191] Made VCSAddon be a new-style object --- Packages/vcsaddons/Lib/core.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Packages/vcsaddons/Lib/core.py b/Packages/vcsaddons/Lib/core.py index 38932c486..b12bf627d 100644 --- a/Packages/vcsaddons/Lib/core.py +++ b/Packages/vcsaddons/Lib/core.py @@ -1,7 +1,7 @@ import vcsaddons,vcs import numpy -class VCSaddon: +class VCSaddon(object): def __init__(self,name=None,source='default',x=None,template=None): self._saves={} self.g_nslabs=1 @@ -139,14 +139,14 @@ class VCSaddon: self._saves={} - def getgm(self,name): + def getgm(self,source="default"): gm = None for nm in vcsaddons.gms[self.g_name].keys(): - if name == nm: + if source == nm: return vcsaddons.gms[self.g_name][nm] if gm is None: - raise "Could not find graphic method %s named: %s" % (self.g_type, name) + raise "Could not find graphic method %s named: %s" % (self.g_type, source) def creategm(self,name,source='default'): return self.__init__(name,source=source,x=self.x,template=self.template) -- GitLab From ffe9cff7445b9d94f5c35021aec22f7d67b9b6d2 Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Tue, 26 Jan 2016 14:53:32 -0800 Subject: [PATCH 003/191] Flake8'd --- Packages/vcsaddons/Lib/histograms.py | 95 ++++++++++++++-------------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/Packages/vcsaddons/Lib/histograms.py b/Packages/vcsaddons/Lib/histograms.py index 6e974f2a6..f51a1500b 100644 --- a/Packages/vcsaddons/Lib/histograms.py +++ b/Packages/vcsaddons/Lib/histograms.py @@ -1,31 +1,35 @@ from core import VCSaddon -import cdms2,MV2,vcs,vcsaddons +import cdms2 +import MV2 +import vcs +import vcsaddons + class Ghg(VCSaddon): - def __init__(self,name=None,source='default',x=None,template = None): - self.g_name='Ghg' - self.g_type='histogram' - VCSaddon.__init__(self,name,source,x,template) + + def __init__(self, name=None, source='default', x=None, template=None): + self.g_name = 'Ghg' + self.g_type = 'histogram' + VCSaddon.__init__(self, name, source, x, template) if source == 'default': - self.fillareastyles = ['solid',] - self.fillareaindices = [1,] - self.fillareacolors = [252,] - self.line = ['solid',] - self.linewidth=[1.0,] - self.linecolors=[241,] + self.fillareastyles = ['solid'] + self.fillareaindices = [1] + self.fillareacolors = [252] + self.line = ['solid'] + self.linewidth = [1.0] + self.linecolors = [241] else: gm = vcsaddons.gms[self.g_name][source] - self.fillareastyle= gm.fillareastyles + self.fillareastyle = gm.fillareastyles self.fillareaindices = gm.fillareaindices self.fillareacolors = gm.fillareacolors self.line = gm.line self.linewidth = gm.linewidth self.linecolors = gm.linecolors - def list(self): print '---------- Histogram (Ghg) member (attribute) listings ----------' - print 'Canvas Mode = ',self.x.mode + print 'Canvas Mode = ', self.x.mode VCSaddon.list(self) print 'fillareastyles = ', self.fillareastyles print 'fillareaindices = ', self.fillareaindices @@ -33,26 +37,25 @@ class Ghg(VCSaddon): print 'line = ', self.line print 'linewidth = ', self.linewidth print 'linecolors = ', self.linecolors - - - def plot(self,data,template = None, bg=0, x=None): + + def plot(self, data, template=None, bg=0, x=None): if x is None: x = self.x if template is None: template = self.template - elif isinstance(template,str): + elif isinstance(template, str): template = x.gettemplate(template) elif not vcs.istemplate(template): raise "Error did not know what to do with template: %s" % template - - if not isinstance(data,cdms2.tvariable.TransientVariable): - mode= cdms2.getAutoBounds() + + if not isinstance(data, cdms2.tvariable.TransientVariable): + mode = cdms2.getAutoBounds() cdms2.setAutoBounds("on") data = MV2.array(data) data.getAxis(-1).getBounds() cdms2.setAutoBounds(mode) - while data.rank()>1: + while data.rank() > 1: data = data[0] # ok now we have a good x and a good data @@ -61,26 +64,27 @@ class Ghg(VCSaddon): # create the primitive fill = x.createfillarea() line = x.createline() - fill.viewport = [template.data.x1,template.data.x2,template.data.y1,template.data.y2] - line.viewport = [template.data.x1,template.data.x2,template.data.y1,template.data.y2] + fill.viewport = [ + template.data.x1, template.data.x2, template.data.y1, template.data.y2] + line.viewport = [ + template.data.x1, template.data.x2, template.data.y1, template.data.y2] axb = data.getAxis(0).getBounds() - xmn,xmx = vcs.minmax(axb) - ymn,ymx = vcs.minmax(data) - - xmn,xmx,ymn,ymx = self.prep_plot(xmn,xmx,ymn,ymx) - - fill.worldcoordinate=[xmn,xmx,ymn,ymx] - line.worldcoordinate=[xmn,xmx,ymn,ymx] - - styles =[] + xmn, xmx = vcs.minmax(axb) + ymn, ymx = vcs.minmax(data) + + xmn, xmx, ymn, ymx = self.prep_plot(xmn, xmx, ymn, ymx) + + fill.worldcoordinate = [xmn, xmx, ymn, ymx] + line.worldcoordinate = [xmn, xmx, ymn, ymx] + + styles = [] cols = [] indices = [] lt = [] - lw =[] + lw = [] lc = [] xs = [] ys = [] - for i in range(nbars): if i < len(self.fillareastyles): @@ -96,21 +100,20 @@ class Ghg(VCSaddon): else: indices.append(self.fillareaindices[-1]) if i < len(self.line): - lt.append( self.line[i]) + lt.append(self.line[i]) else: lt.append(self.line[-1]) if i < len(self.linewidth): - lw.append( self.linewidth[i]) + lw.append(self.linewidth[i]) else: lw.append(self.linewidth[-1]) if i < len(self.line): - lc.append( self.linecolors[i]) + lc.append(self.linecolors[i]) else: lc.append(self.linecolors[-1]) - - xs.append( [axb[i][0],axb[i][1],axb[i][1],axb[i][0],axb[i][0]]) - ys.append( [0,0,data[i],data[i],0]) + xs.append([axb[i][0], axb[i][1], axb[i][1], axb[i][0], axb[i][0]]) + ys.append([0, 0, data[i], data[i], 0]) fill.style = styles fill.x = xs @@ -123,13 +126,13 @@ class Ghg(VCSaddon): line.type = lt line.width = lw line.color = lc - + fill.list() displays = [] - displays.append(x.plot(fill,bg=bg)) - displays.append(x.plot(line,bg=bg)) + displays.append(x.plot(fill, bg=bg)) + displays.append(x.plot(line, bg=bg)) - x.worldcoordinate = fill.worldcoordinate - dsp = template.plot(data,self,bg=bg) + x.worldcoordinate = fill.worldcoordinate + dsp = template.plot(data, self, bg=bg) for d in dsp: displays.append(d) -- GitLab From 26031e3a24b17a54f5dc6f62d2112f00cbf10148 Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Fri, 5 Feb 2016 08:47:54 -0800 Subject: [PATCH 004/191] Made histogram work and display variance; needs to be cleaned up --- Packages/vcsaddons/Lib/core.py | 6 + Packages/vcsaddons/Lib/histograms.py | 161 ++++++++++++++++++--------- 2 files changed, 115 insertions(+), 52 deletions(-) diff --git a/Packages/vcsaddons/Lib/core.py b/Packages/vcsaddons/Lib/core.py index b12bf627d..c39667bb8 100644 --- a/Packages/vcsaddons/Lib/core.py +++ b/Packages/vcsaddons/Lib/core.py @@ -38,6 +38,7 @@ class VCSaddon(object): self.datawc_x2=1.e20 self.datawc_y1=1.e20 self.datawc_y2=1.e20 + self.colormap="default" self.xmtics1='*' self.xmtics2='*' self.ymtics1='*' @@ -48,6 +49,8 @@ class VCSaddon(object): self.yticlabels2='*' self.xaxisconvert= 'linear' self.yaxisconvert= 'linear' + self.color_1 = 16 + self.color_2 = 239 self.legend = None self.projection='linear' else: @@ -58,6 +61,7 @@ class VCSaddon(object): self.datawc_x2=gm.datawc_x2 self.datawc_y1=gm.datawc_y1 self.datawc_y2=gm.datawc_x2 + self.colormap=gm.colormap self.xmtics1=gm.xmtics1 self.xmtics2=gm.xmtics2 self.ymtics1=gm.ymtics1 @@ -68,6 +72,8 @@ class VCSaddon(object): self.yticlabels2=gm.yticlabels2 self.xaxisconvert=gm.xaxisconvert self.yaxisconvert= gm.yaxisconvert + self.color_1 = gm.color_1 + self.color_2 = gm.color_2 self.legend = gm.legend self.projection=gm.projection self.name = name diff --git a/Packages/vcsaddons/Lib/histograms.py b/Packages/vcsaddons/Lib/histograms.py index f51a1500b..69c575615 100644 --- a/Packages/vcsaddons/Lib/histograms.py +++ b/Packages/vcsaddons/Lib/histograms.py @@ -1,6 +1,7 @@ from core import VCSaddon import cdms2 import MV2 +import numpy import vcs import vcsaddons @@ -12,20 +13,22 @@ class Ghg(VCSaddon): self.g_type = 'histogram' VCSaddon.__init__(self, name, source, x, template) if source == 'default': - self.fillareastyles = ['solid'] - self.fillareaindices = [1] - self.fillareacolors = [252] - self.line = ['solid'] - self.linewidth = [1.0] - self.linecolors = [241] + self.line = [] + self.linewidth = [] + self.linecolors = [] + self.fillareastyles = [] + self.fillareaindices = [] + self.fillareacolors = [] + self.bins = [] else: gm = vcsaddons.gms[self.g_name][source] - self.fillareastyle = gm.fillareastyles - self.fillareaindices = gm.fillareaindices - self.fillareacolors = gm.fillareacolors self.line = gm.line self.linewidth = gm.linewidth self.linecolors = gm.linecolors + self.fillareastyles = gm.fillareastyles + self.fillareaindices = gm.fillareaindices + self.fillareacolors = gm.fillareacolors + self.bins = gm.bins def list(self): print '---------- Histogram (Ghg) member (attribute) listings ----------' @@ -37,6 +40,7 @@ class Ghg(VCSaddon): print 'line = ', self.line print 'linewidth = ', self.linewidth print 'linecolors = ', self.linecolors + print 'bins = ', self.bins def plot(self, data, template=None, bg=0, x=None): if x is None: @@ -46,20 +50,34 @@ class Ghg(VCSaddon): elif isinstance(template, str): template = x.gettemplate(template) elif not vcs.istemplate(template): - raise "Error did not know what to do with template: %s" % template - - if not isinstance(data, cdms2.tvariable.TransientVariable): - mode = cdms2.getAutoBounds() - cdms2.setAutoBounds("on") - data = MV2.array(data) - data.getAxis(-1).getBounds() - cdms2.setAutoBounds(mode) + raise ValueError("Error did not know what to do with template: %s" % template) - while data.rank() > 1: - data = data[0] + # We'll just flatten the data... if they want to be more precise, should pass in more precise data + data = data.flatten().asma() # ok now we have a good x and a good data - nbars = len(data) + if not self.bins: + self.bins = vcs.utils.mkscale(*vcs.minmax(data)) + + data_bins = numpy.digitize(data, self.bins) - 1 + binned = [data[data_bins==i] for i in range(len(self.bins))] + + means = [] + stds = [] + + max_possible_deviance = 0 + + for ind, databin in enumerate(binned): + means.append(databin.mean()) + stds.append(databin.std()) + if len(self.bins) > ind + 1: + max_possible_deviance = max(means[ind] - self.bins[ind], self.bins[ind + 1] - means[ind], max_possible_deviance) + else: + max_possible_deviance = max(means[ind] - self.bins[ind], max_possible_deviance) + + color_values = [std / max_possible_deviance for std in stds] + y_values, _ = numpy.histogram(data, self.bins) + nbars = len(self.bins) - 1 # create the primitive fill = x.createfillarea() @@ -68,9 +86,9 @@ class Ghg(VCSaddon): template.data.x1, template.data.x2, template.data.y1, template.data.y2] line.viewport = [ template.data.x1, template.data.x2, template.data.y1, template.data.y2] - axb = data.getAxis(0).getBounds() - xmn, xmx = vcs.minmax(axb) - ymn, ymx = vcs.minmax(data) + + xmn, xmx = vcs.minmax(self.bins) + ymn, ymx = 0, len(data) xmn, xmx, ymn, ymx = self.prep_plot(xmn, xmx, ymn, ymx) @@ -86,34 +104,67 @@ class Ghg(VCSaddon): xs = [] ys = [] - for i in range(nbars): - if i < len(self.fillareastyles): - styles.append(self.fillareastyles[i]) - else: - styles.append(self.fillareastyles[-1]) - if i < len(self.fillareacolors): - cols.append(self.fillareacolors[i]) - else: - cols.append(self.fillareacolors[-1]) - if i < len(self.fillareaindices): - indices.append(self.fillareaindices[i]) - else: - indices.append(self.fillareaindices[-1]) - if i < len(self.line): - lt.append(self.line[i]) - else: - lt.append(self.line[-1]) - if i < len(self.linewidth): - lw.append(self.linewidth[i]) - else: - lw.append(self.linewidth[-1]) - if i < len(self.line): - lc.append(self.linecolors[i]) - else: - lc.append(self.linecolors[-1]) + levels = [.1 * i for i in range(11)] - xs.append([axb[i][0], axb[i][1], axb[i][1], axb[i][0], axb[i][0]]) - ys.append([0, 0, data[i], data[i], 0]) + # Extend fillarea and line attrs to levels + if self.fillareastyles: + while len(self.fillareastyles) < len(levels): + self.fillareastyles.append(self.fillareastyles[-1]) + else: + self.fillareastyles = ["solid"] * len(levels) + + if self.fillareacolors: + while len(self.fillareacolors) < len(levels): + self.fillareacolors.append(self.fillareacolors[-1]) + else: + for lev in levels: + self.fillareacolors.append(int((self.color_2 - self.color_1) * lev) + self.color_1) + + if self.fillareaindices: + while len(self.fillareaindices) < len(levels): + self.fillareaindices.append(self.fillareaindices[-1]) + else: + self.fillareaindices = [1] * len(levels) + + if self.line: + while len(self.line) < len(levels): + self.line.append(self.line[-1]) + else: + self.line = ["solid"] * len(levels) + + if self.linewidth: + while len(self.linewidth) < len(levels): + self.linewidth.append(self.linewidth[-1]) + else: + self.linewidth = [1] * len(levels) + + if self.linecolors: + while len(self.linecolors) < len(levels): + self.linecolors.append(self.linecolors[-1]) + else: + self.linecolors = ["black"] * len(levels) + + for i in range(nbars): + # Calculate level for bar + value = color_values[i] + for lev_ind in range(len(levels)): + if levels[lev_ind] > value: + if lev_ind > 0: + lev_ind -= 1 + break + else: + # Shouldn't ever get here since level 0 is 0 + assert False + + styles.append(self.fillareastyles[lev_ind]) + cols.append(self.fillareacolors[lev_ind]) + indices.append(self.fillareaindices[lev_ind]) + lt.append(self.line[lev_ind]) + lw.append(self.linewidth[lev_ind]) + lc.append(self.linecolors[lev_ind]) + + xs.append([self.bins[i], self.bins[i], self.bins[i + 1], self.bins[i + 1]]) + ys.append([0, y_values[i], y_values[i], 0]) fill.style = styles fill.x = xs @@ -121,20 +172,26 @@ class Ghg(VCSaddon): fill.style fill.index = indices fill.color = cols + fill.colormap = self.colormap line.x = xs line.y = ys line.type = lt line.width = lw line.color = lc - fill.list() displays = [] displays.append(x.plot(fill, bg=bg)) displays.append(x.plot(line, bg=bg)) x.worldcoordinate = fill.worldcoordinate - dsp = template.plot(data, self, bg=bg) + + x_axis = cdms2.createAxis(self.bins, id="x") + y_axis = cdms2.createAxis(vcs.mkscale(0, len(data)), id="y") + + dsp = template.plot(x, MV2.masked_array(data), self, bg=bg, X=x_axis, Y=y_axis) for d in dsp: displays.append(d) self.restore() + # Ugh, hack + x.backend.renWin.Render() return displays -- GitLab From 53f54dff490bd99b526ae96e49fc3ecc8362a9e5 Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Mon, 8 Feb 2016 10:12:14 -0800 Subject: [PATCH 005/191] Adjusted y scale --- Packages/vcsaddons/Lib/histograms.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Packages/vcsaddons/Lib/histograms.py b/Packages/vcsaddons/Lib/histograms.py index 69c575615..0b7d7de86 100644 --- a/Packages/vcsaddons/Lib/histograms.py +++ b/Packages/vcsaddons/Lib/histograms.py @@ -88,7 +88,8 @@ class Ghg(VCSaddon): template.data.x1, template.data.x2, template.data.y1, template.data.y2] xmn, xmx = vcs.minmax(self.bins) - ymn, ymx = 0, len(data) + # Make the y scale be slightly larger than the largest bar + ymn, ymx = 0, max(y_values) * 1.25 xmn, xmx, ymn, ymx = self.prep_plot(xmn, xmx, ymn, ymx) -- GitLab From 510230038dc751a8e6803964b6ab09a0e1d24e0e Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Tue, 9 Feb 2016 12:09:18 -0800 Subject: [PATCH 006/191] Fixed vcsaddons to use display plots correctly --- Packages/vcs/Lib/Canvas.py | 13 ++++++-- Packages/vcs/Lib/displayplot.py | 5 +++- Packages/vcsaddons/Lib/core.py | 44 +++++++++++++++++++++------- Packages/vcsaddons/Lib/histograms.py | 6 ++-- 4 files changed, 52 insertions(+), 16 deletions(-) diff --git a/Packages/vcs/Lib/Canvas.py b/Packages/vcs/Lib/Canvas.py index 48327f0c0..cbe877c8e 100644 --- a/Packages/vcs/Lib/Canvas.py +++ b/Packages/vcs/Lib/Canvas.py @@ -3518,9 +3518,14 @@ Options::: tp = "boxfill" elif tp in ("xvsy", "xyvsy", "yxvsx", "scatter"): tp = "1d" - gm = vcs.elements[tp][arglist[4]] + if tp in vcsaddons.gms: + gm = vcsaddons.gms[tp][arglist[4]] + arglist[3] = gm + else: + gm = vcs.elements[tp][arglist[4]] if hasattr(gm, "priority") and gm.priority == 0: return + p = self.getprojection(gm.projection) if p.type in round_projections and ( doratio == "0" or doratio[:4] == "auto"): @@ -3729,20 +3734,22 @@ Options::: del(keyargs["bg"]) if isinstance(arglist[3], vcsaddons.core.VCSaddon): if arglist[1] is None: - dn = arglist[3].plot( + dn = arglist[3].plot_internal( arglist[0], template=arglist[2], bg=bg, x=self, **keyargs) else: - dn = arglist[3].plot( + dn = arglist[3].plot_internal( arglist[0], arglist[1], template=arglist[2], bg=bg, x=self, **keyargs) + self.display_names.append(dn.name) + return dn else: returned_kargs = self.backend.plot(*arglist, **keyargs) if not keyargs.get("donotstoredisplay", False): diff --git a/Packages/vcs/Lib/displayplot.py b/Packages/vcs/Lib/displayplot.py index 1f00450ba..dd66fac1d 100755 --- a/Packages/vcs/Lib/displayplot.py +++ b/Packages/vcs/Lib/displayplot.py @@ -25,6 +25,7 @@ # import VCS_validation_functions import vcs +import vcsaddons class Dp(object): @@ -211,7 +212,7 @@ class Dp(object): def _setg_type(self, value): value = VCS_validation_functions.checkString(self, 'g_type', value) value = value.lower() - if value not in vcs.elements and value != "text": + if value not in vcs.elements and value != "text" and value not in vcsaddons.gms: raise ValueError( "invalid g_type '%s' must be one of: %s " % (value, vcs.elements.keys())) @@ -259,6 +260,7 @@ class Dp(object): self._g_name = "default" self._array = [] self._continents = 1 + self._continents_line = "default" self.ratio = None else: src = vcs.elements["display"][Dp_name_src] @@ -269,6 +271,7 @@ class Dp(object): self.g_type = src.g_type self.g_name = src.g_name self.continents = src.continents + self.continents_line = src.continents_line self.priority = src.priority self.ratio = src.ratio diff --git a/Packages/vcsaddons/Lib/core.py b/Packages/vcsaddons/Lib/core.py index c39667bb8..8421e247c 100644 --- a/Packages/vcsaddons/Lib/core.py +++ b/Packages/vcsaddons/Lib/core.py @@ -5,14 +5,14 @@ class VCSaddon(object): def __init__(self,name=None,source='default',x=None,template=None): self._saves={} self.g_nslabs=1 - if not self.g_name in vcsaddons.gms.keys(): - vcsaddons.gms[self.g_name]={} + if not self.g_type in vcsaddons.gms.keys(): + vcsaddons.gms[self.g_type]={} if name is None: cont = True while cont: num= numpy.random.randint(1000) - nm = 'Ghg_'+str(num) - if not nm in vcsaddons.gms[self.g_name].keys(): + nm = self.g_type + '_'+str(num) + if not nm in vcsaddons.gms[self.g_type].keys(): name = nm cont = False @@ -30,7 +30,7 @@ class VCSaddon(object): else: raise "Error did not know what to do with template: %s" % template - if name in vcsaddons.gms[self.g_name].keys(): + if name in vcsaddons.gms[self.g_type].keys(): raise "Error graphic method %s already exists" % name if source=='default': @@ -54,9 +54,9 @@ class VCSaddon(object): self.legend = None self.projection='linear' else: - gm = vcsaddons.gms[self.g_name].get(source,None) + gm = vcsaddons.gms[self.g_type].get(source,None) if gm is None: - raise "error could not find graphic method %s (of type %s)" % (source, self.g_name) + raise "error could not find graphic method %s (of type %s)" % (source, self.g_type) self.datawc_x1=gm.datawc_x1 self.datawc_x2=gm.datawc_x2 self.datawc_y1=gm.datawc_y1 @@ -77,7 +77,7 @@ class VCSaddon(object): self.legend = gm.legend self.projection=gm.projection self.name = name - vcsaddons.gms[self.g_name][name]=self + vcsaddons.gms[self.g_type][name]=self def list(self): @@ -128,6 +128,30 @@ class VCSaddon(object): setattr(self,axes+sec+n,vcs.mklabels(sc)) return xmn,xmx,ymn,ymx + def plot_internal(self, slab=None, slab2=None, template=None, bg=0, x=None, **kwargs): + """ + Used by vcs to properly build a display plot for this graphics method. + """ + if x is None: + x = self.x + + if slab2 is not None: + displays = self.plot(slab, slab2, template, bg, x, **kwargs) + else: + displays = self.plot(slab, template, bg, x, **kwargs) + + for display in displays: + # Remove the display from the canvas + if display.name in x.display_names: + x.display_names.remove(display.name) + nm, src = x.check_name_source(None, "default", "display") + display = vcs.displayplot.Dp(nm) + display.g_name = self.name + display.g_type = self.g_type + display.array = [slab, slab2] + return display + + def save(self,attribute = None): if attribute is not None: self._saves[attribute] = getattr(self,attribute) @@ -147,9 +171,9 @@ class VCSaddon(object): def getgm(self,source="default"): gm = None - for nm in vcsaddons.gms[self.g_name].keys(): + for nm in vcsaddons.gms[self.g_type].keys(): if source == nm: - return vcsaddons.gms[self.g_name][nm] + return vcsaddons.gms[self.g_type][nm] if gm is None: raise "Could not find graphic method %s named: %s" % (self.g_type, source) diff --git a/Packages/vcsaddons/Lib/histograms.py b/Packages/vcsaddons/Lib/histograms.py index 0b7d7de86..d0e41c4ed 100644 --- a/Packages/vcsaddons/Lib/histograms.py +++ b/Packages/vcsaddons/Lib/histograms.py @@ -42,7 +42,7 @@ class Ghg(VCSaddon): print 'linecolors = ', self.linecolors print 'bins = ', self.bins - def plot(self, data, template=None, bg=0, x=None): + def plot(self, data, template=None, bg=0, x=None, **kwargs): if x is None: x = self.x if template is None: @@ -190,9 +190,11 @@ class Ghg(VCSaddon): dsp = template.plot(x, MV2.masked_array(data), self, bg=bg, X=x_axis, Y=y_axis) for d in dsp: - displays.append(d) + if d is not None: + displays.append(d) self.restore() # Ugh, hack x.backend.renWin.Render() + print displays return displays -- GitLab From 577499883890dc9bd70c1924a3e53b011641e613 Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Wed, 10 Feb 2016 09:25:41 -0800 Subject: [PATCH 007/191] Added legend, removed print, fixed the attr lengths --- Packages/vcsaddons/Lib/histograms.py | 30 ++++++++++++++++------------ 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/Packages/vcsaddons/Lib/histograms.py b/Packages/vcsaddons/Lib/histograms.py index d0e41c4ed..bf314f246 100644 --- a/Packages/vcsaddons/Lib/histograms.py +++ b/Packages/vcsaddons/Lib/histograms.py @@ -109,41 +109,41 @@ class Ghg(VCSaddon): # Extend fillarea and line attrs to levels if self.fillareastyles: - while len(self.fillareastyles) < len(levels): + while len(self.fillareastyles) < (len(levels) - 1): self.fillareastyles.append(self.fillareastyles[-1]) else: - self.fillareastyles = ["solid"] * len(levels) + self.fillareastyles = ["solid"] * (len(levels) - 1) if self.fillareacolors: - while len(self.fillareacolors) < len(levels): + while len(self.fillareacolors) < (len(levels) - 1): self.fillareacolors.append(self.fillareacolors[-1]) else: - for lev in levels: + for lev in levels[:-1]: self.fillareacolors.append(int((self.color_2 - self.color_1) * lev) + self.color_1) if self.fillareaindices: - while len(self.fillareaindices) < len(levels): + while len(self.fillareaindices) < (len(levels) - 1): self.fillareaindices.append(self.fillareaindices[-1]) else: - self.fillareaindices = [1] * len(levels) + self.fillareaindices = [1] * (len(levels) - 1) if self.line: - while len(self.line) < len(levels): + while len(self.line) < (len(levels) - 1): self.line.append(self.line[-1]) else: - self.line = ["solid"] * len(levels) + self.line = ["solid"] * (len(levels) - 1) if self.linewidth: - while len(self.linewidth) < len(levels): + while len(self.linewidth) < (len(levels) - 1): self.linewidth.append(self.linewidth[-1]) else: - self.linewidth = [1] * len(levels) + self.linewidth = [1] * (len(levels) - 1) if self.linecolors: - while len(self.linecolors) < len(levels): + while len(self.linecolors) < (len(levels) - 1): self.linecolors.append(self.linecolors[-1]) else: - self.linecolors = ["black"] * len(levels) + self.linecolors = ["black"] * (len(levels) - 1) for i in range(nbars): # Calculate level for bar @@ -193,8 +193,12 @@ class Ghg(VCSaddon): if d is not None: displays.append(d) + dsp = template.drawColorBar(self.fillareacolors, levels, legend={0: "No Variance", .1:"", .2: "", .3:"", .4:"", .5:"", .6:"", .7:"", .8:"", .9:"", 1: "High Variance"}, x=x) + for d in dsp: + if d is not None: + displays.append(d) + self.restore() # Ugh, hack x.backend.renWin.Render() - print displays return displays -- GitLab From 3af99c72693cb37050c8b842206a8c9aaf308b8d Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Wed, 10 Feb 2016 12:37:42 -0800 Subject: [PATCH 008/191] Finishing touch-ups on histo --- Packages/vcs/Lib/vcs2vtk.py | 46 ++++++++++++++++++++++++++-- Packages/vcsaddons/Lib/histograms.py | 17 +++++----- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/Packages/vcs/Lib/vcs2vtk.py b/Packages/vcs/Lib/vcs2vtk.py index a7b178e89..a7ab029ab 100644 --- a/Packages/vcs/Lib/vcs2vtk.py +++ b/Packages/vcs/Lib/vcs2vtk.py @@ -1880,7 +1880,49 @@ def generateVectorArray(data1, data2, vtk_grid): def vtkIterate(iterator): iterator.InitTraversal() - obj = iterator.GetNextItem() + obj = iterator.GetNextItemAsObject() while obj is not None: yield obj - obj = iterator.GetNextItem() + obj = iterator.GetNextItemAsObject() + + +# transforms [v1,v2] and returns it +# such that it is in the same order +# and has the same middle interval as [gm1, gm2] +def switchAndTranslate(gm1, gm2, v1, v2, wrapModulo): + assert(v1 < v2) + # keep the same middle of the interval + if (wrapModulo): + gmMiddle = float(gm1 + gm2) / 2.0 + half = float(v2 - v1) / 2.0 + v1 = gmMiddle - half + v2 = gmMiddle + half + # if gm margins are increasing and dataset bounds are decreasing + # or the other way around switch them + if ((gm1 - gm2) * (v1 - v2) < 0): + v1, v2 = v2, v1 + return [v1, v2] + + +# TODO: Get rid of this funtion and pass instead: flip and central meridian +# This function can fail for gmbounds -89, -2 where databounds are 89, 0 +# (the cells in the margins have different sizes: 2 and 4) +# +# returns bounds with the same interval size as databounds +# but in the same order and with the same middle interval +# as gmbounds. The middle and the order are used for +# plotting. wrapModule has YWrap, XWrap in degrees, 0 means no wrap +def getBoundsForPlotting(gmbounds, databounds, wrapModulo): + """ Returns the same interval as databounds but it + matches the order and also it keeps the same center interval as gmbounds + So for instance if databounds is -40, 320 and gmbounds is -180, 180 + this function returns + """ + x1gm, x2gm, y1gm, y2gm = gmbounds[:4] + x1, x2, y1, y2 = databounds[:4] + assert (x1 < x2 and y1 < y2) + if not numpy.allclose([x1gm, x2gm], 1.e20): + x1, x2 = switchAndTranslate(x1gm, x2gm, x1, x2, wrapModulo[1] if wrapModulo else None) + if (isinstance(y1gm, numbers.Number) and not numpy.allclose([y1gm, y2gm], 1.e20)): + y1, y2 = switchAndTranslate(y1gm, y2gm, y1, y2, wrapModulo[0] if wrapModulo else None) + return [x1, x2, y1, y2] diff --git a/Packages/vcsaddons/Lib/histograms.py b/Packages/vcsaddons/Lib/histograms.py index bf314f246..3c2b4a033 100644 --- a/Packages/vcsaddons/Lib/histograms.py +++ b/Packages/vcsaddons/Lib/histograms.py @@ -76,7 +76,7 @@ class Ghg(VCSaddon): max_possible_deviance = max(means[ind] - self.bins[ind], max_possible_deviance) color_values = [std / max_possible_deviance for std in stds] - y_values, _ = numpy.histogram(data, self.bins) + y_values = [len(databin) for databin in binned] nbars = len(self.bins) - 1 # create the primitive @@ -91,7 +91,7 @@ class Ghg(VCSaddon): # Make the y scale be slightly larger than the largest bar ymn, ymx = 0, max(y_values) * 1.25 - xmn, xmx, ymn, ymx = self.prep_plot(xmn, xmx, ymn, ymx) + #xmn, xmx, ymn, ymx = self.prep_plot(xmn, xmx, ymn, ymx) fill.worldcoordinate = [xmn, xmx, ymn, ymx] line.worldcoordinate = [xmn, xmx, ymn, ymx] @@ -180,14 +180,12 @@ class Ghg(VCSaddon): line.width = lw line.color = lc displays = [] - displays.append(x.plot(fill, bg=bg)) - displays.append(x.plot(line, bg=bg)) - - x.worldcoordinate = fill.worldcoordinate x_axis = cdms2.createAxis(self.bins, id="x") y_axis = cdms2.createAxis(vcs.mkscale(0, len(data)), id="y") + displays.append(x.plot(fill, bg=bg, render=False)) + dsp = template.plot(x, MV2.masked_array(data), self, bg=bg, X=x_axis, Y=y_axis) for d in dsp: if d is not None: @@ -198,7 +196,10 @@ class Ghg(VCSaddon): if d is not None: displays.append(d) + + displays.append(x.plot(line, bg=bg)) + + x.worldcoordinate = fill.worldcoordinate + self.restore() - # Ugh, hack - x.backend.renWin.Render() return displays -- GitLab From 4c0e5d7862e5a8755a6188e0a49b0cccb1486220 Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Fri, 12 Feb 2016 08:11:11 -0800 Subject: [PATCH 009/191] Made the axis be labeled correctly --- Packages/vcsaddons/Lib/histograms.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Packages/vcsaddons/Lib/histograms.py b/Packages/vcsaddons/Lib/histograms.py index 3c2b4a033..60f866492 100644 --- a/Packages/vcsaddons/Lib/histograms.py +++ b/Packages/vcsaddons/Lib/histograms.py @@ -51,6 +51,16 @@ class Ghg(VCSaddon): template = x.gettemplate(template) elif not vcs.istemplate(template): raise ValueError("Error did not know what to do with template: %s" % template) + try: + data_name = data.title + except AttributeError: + try: + data_name = data.long_name + except AttributeError: + try: + data_name = data.id + data.units + except AttributeError: + data_name = data.id # We'll just flatten the data... if they want to be more precise, should pass in more precise data data = data.flatten().asma() @@ -181,12 +191,13 @@ class Ghg(VCSaddon): line.color = lc displays = [] - x_axis = cdms2.createAxis(self.bins, id="x") - y_axis = cdms2.createAxis(vcs.mkscale(0, len(data)), id="y") + x_axis = cdms2.createAxis(self.bins, id=data_name) + y_axis = cdms2.createAxis(vcs.mkscale(0, ymx), id="bin_size") displays.append(x.plot(fill, bg=bg, render=False)) - - dsp = template.plot(x, MV2.masked_array(data), self, bg=bg, X=x_axis, Y=y_axis) + arr = MV2.masked_array(y_values) + arr.setAxis(0, x_axis) + dsp = template.plot(x, arr, self, bg=bg, X=x_axis, Y=y_axis) for d in dsp: if d is not None: displays.append(d) @@ -196,7 +207,6 @@ class Ghg(VCSaddon): if d is not None: displays.append(d) - displays.append(x.plot(line, bg=bg)) x.worldcoordinate = fill.worldcoordinate -- GitLab From 1bb3806f83652635c3f8e44be937721ae1c22463 Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Fri, 25 Mar 2016 15:26:31 -0700 Subject: [PATCH 010/191] Fixes #1894 --- Packages/vcs/Lib/vcsvtk/boxfillpipeline.py | 4 ++-- Packages/vcs/Lib/vcsvtk/isofillpipeline.py | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Packages/vcs/Lib/vcsvtk/boxfillpipeline.py b/Packages/vcs/Lib/vcsvtk/boxfillpipeline.py index 64ad4f00c..54d9b8a60 100644 --- a/Packages/vcs/Lib/vcsvtk/boxfillpipeline.py +++ b/Packages/vcs/Lib/vcsvtk/boxfillpipeline.py @@ -52,7 +52,7 @@ class BoxfillPipeline(Pipeline2D): if numpy.allclose(self._gm.level_1, 1.e20) or \ numpy.allclose(self._gm.level_2, 1.e20): self._contourLevels = vcs.mkscale(self._scalarRange[0], - self._scalarRange[1]) + self._scalarRange[1], nc=min(nlev, 12)) if len(self._contourLevels) == 1: # constant value ? self._contourLevels = [self._contourLevels[0], self._contourLevels[0] + .00001] @@ -282,7 +282,7 @@ class BoxfillPipeline(Pipeline2D): # Colortable bit # make sure length match - numLevels = len(self._contourLevels) + numLevels = len(self._contourLevels) - 1 while len(self._contourColors) < numLevels: self._contourColors.append(self._contourColors[-1]) diff --git a/Packages/vcs/Lib/vcsvtk/isofillpipeline.py b/Packages/vcs/Lib/vcsvtk/isofillpipeline.py index 59b31272a..28c7ee469 100644 --- a/Packages/vcs/Lib/vcsvtk/isofillpipeline.py +++ b/Packages/vcs/Lib/vcsvtk/isofillpipeline.py @@ -46,11 +46,11 @@ class IsofillPipeline(Pipeline2D): def _plotInternal(self): """Overrides baseclass implementation.""" - prepedContours = self._prepContours() - tmpLevels = prepedContours["tmpLevels"] - tmpIndices = prepedContours["tmpIndices"] - tmpColors = prepedContours["tmpColors"] - tmpOpacities = prepedContours["tmpOpacities"] + preppedCountours = self._prepContours() + tmpLevels = preppedCountours["tmpLevels"] + tmpIndices = preppedCountours["tmpIndices"] + tmpColors = preppedCountours["tmpColors"] + tmpOpacities = preppedCountours["tmpOpacities"] style = self._gm.fillareastyle luts = [] -- GitLab From eb791bcfb6cfb01bb44f83a916ecd0da659fa862 Mon Sep 17 00:00:00 2001 From: Charles Doutriaux Date: Tue, 5 Apr 2016 09:37:12 -0700 Subject: [PATCH 011/191] fix #1907 --- CMake/cdat_modules/docutils_external.cmake | 2 +- CMake/cdat_modules/gdal_external.cmake | 4 +++- CMake/cdat_modules/spyder_external.cmake | 2 +- CMake/cdat_modules_extra/cdatmpi_configure_step.cmake.in | 1 + CMake/cmake_modules/pipinstaller.cmake | 2 ++ 5 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CMake/cdat_modules/docutils_external.cmake b/CMake/cdat_modules/docutils_external.cmake index ae62d3b59..8e419bd00 100644 --- a/CMake/cdat_modules/docutils_external.cmake +++ b/CMake/cdat_modules/docutils_external.cmake @@ -2,5 +2,5 @@ # and configure and build it set(nm docutils) - +set(OLD "") include(pipinstaller) diff --git a/CMake/cdat_modules/gdal_external.cmake b/CMake/cdat_modules/gdal_external.cmake index 6efa6ae11..33e4c8e60 100644 --- a/CMake/cdat_modules/gdal_external.cmake +++ b/CMake/cdat_modules/gdal_external.cmake @@ -17,7 +17,9 @@ ExternalProject_Add(gdal URL_MD5 ${GDAL_MD5} BUILD_IN_SOURCE 1 PATCH_COMMAND "" - CONFIGURE_COMMAND sh configure --prefix=${cdat_EXTERNALS} --with-hdf5=${cdat_EXTERNALS} --with-netcdf=${cdat_EXTERNALS} --with-curl=${cdat_EXTERNALS} --with-geos=${cdat_EXTERNALS}/bin/geos-config --with-python=${PYTHON_EXECUTABLE} --with-jpeg=no --with-libtiff=internal --without-jpeg12 --with-geotiff=internal + CONFIGURE_COMMAND ${CMAKE_COMMAND} -DINSTALL_DIR= -DWORKING_DIR= -DCONFIGURE_ARGS=${gdal_configure_args} -P ${cdat_CMAKE_BINARY_DIR}/${configure_file} + BUILD_COMMAND ${CMAKE_COMMAND} -Dmake=$(MAKE) -DWORKING_DIR= -P ${cdat_CMAKE_BINARY_DIR}/cdat_make_step.cmake + INSTALL_COMMAND ${CMAKE_COMMAND} -DWORKING_DIR= -P ${cdat_CMAKE_BINARY_DIR}/cdat_install_step.cmake DEPENDS "${gdal_deps}" ${ep_log_options} ) diff --git a/CMake/cdat_modules/spyder_external.cmake b/CMake/cdat_modules/spyder_external.cmake index 2f1b6631b..ef88a8338 100644 --- a/CMake/cdat_modules/spyder_external.cmake +++ b/CMake/cdat_modules/spyder_external.cmake @@ -2,6 +2,6 @@ # and configure and build it set (nm spyder) - +set(OLD "") include(pipinstaller) diff --git a/CMake/cdat_modules_extra/cdatmpi_configure_step.cmake.in b/CMake/cdat_modules_extra/cdatmpi_configure_step.cmake.in index 826b0e209..b8dd0172d 100644 --- a/CMake/cdat_modules_extra/cdatmpi_configure_step.cmake.in +++ b/CMake/cdat_modules_extra/cdatmpi_configure_step.cmake.in @@ -4,6 +4,7 @@ set(ENV{PKG_CONFIG} "@cdat_PKG_CONFIG_EXECUTABLE@") include(@cdat_CMAKE_BINARY_DIR@/cdat_common_environment.cmake) set(ENV{CC} mpicc) +set(ENV{CXX} mpicxx) message("CONFIGURE_ARGS IS ${CONFIGURE_ARGS}") message("LD_ARGS IS $ENV{@LIBRARY_PATH@}") diff --git a/CMake/cmake_modules/pipinstaller.cmake b/CMake/cmake_modules/pipinstaller.cmake index 09b797908..1060a0ca1 100644 --- a/CMake/cmake_modules/pipinstaller.cmake +++ b/CMake/cmake_modules/pipinstaller.cmake @@ -49,3 +49,5 @@ unset(GIT_CMD_STR ) unset(USR_ENVS) unset(USER_BUILD_EXT_OPTS) unset(USER_INSTALL_OPTIONS) +unset(OLDSTR) +unset(OLD) -- GitLab From 89a2ec9489a6f70ad5c9ef5ad6ddd0c0cede44ed Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Wed, 6 Apr 2016 10:59:41 -0700 Subject: [PATCH 012/191] Made change to make labels better match levels, added precision-based rounding to labels --- Packages/vcs/Lib/utils.py | 51 ++++++++++++++------ Packages/vcs/Lib/vcsvtk/boxfillpipeline.py | 12 +++-- testing/vcs/CMakeLists.txt | 6 ++- testing/vcs/test_fewer_colors_than_levels.py | 29 +++++++++++ 4 files changed, 76 insertions(+), 22 deletions(-) create mode 100644 testing/vcs/test_fewer_colors_than_levels.py diff --git a/Packages/vcs/Lib/utils.py b/Packages/vcs/Lib/utils.py index 2323200ae..91c2acc2d 100644 --- a/Packages/vcs/Lib/utils.py +++ b/Packages/vcs/Lib/utils.py @@ -937,7 +937,24 @@ def __split2contiguous(levels): return tmplevs -def mklabels(vals, output='dict'): +def guess_precision(num): + """ + Rough guesstimate of the precision of a number. Don't use this for actual science. + """ + if num == 0: + return 1 + idigleft = int(float(numpy.ma.floor(numpy.ma.log10(num)))) + 1 + aa = numpy.ma.power(10., -idigleft) + + while abs(round(aa * num) - aa * num) > .000001: + aa = aa * 10. + + total_digits = numpy.ma.floor(numpy.ma.log10(aa * numpy.ma.power(10., idigleft))) + + return max(total_digits, idigleft) + + +def mklabels(vals, output='dict', precision=None): ''' Function : mklabels @@ -957,6 +974,11 @@ def mklabels(vals, output='dict'): {2.0000000000000002e-05: '2E-5', 5.0000000000000002e-05: '5E-5'} >>> vcs.mklabels ( [.00002,.00005],output='list') ['2E-5', '5E-5'] + >>> a = vcs.mkevenlevels(0, 100, nlev=9) + >>> vcs.mklabels(a) + {0.0: ' 0.000000000000000', 11.11111111111111: ' 11.111111111111111', 22.22222222222222: ' 22.222222222222221', 33.33333333333333: ' 33.333333333333329', 44.44444444444444: ' 44.444444444444443', 55.55555555555556: ' 55.555555555555557', 66.66666666666666: ' 66.666666666666657', 77.77777777777777: ' 77.777777777777771', 88.88888888888889: ' 88.888888888888886', 100.0: '100.000000000000000'} + >>> vcs.mklabels(a, precision=4) + {0.0: ' 0.0', 11.11111111111111: ' 11.1', 22.22222222222222: ' 22.2', 33.33333333333333: ' 33.3', 44.44444444444444: ' 44.4', 55.55555555555556: ' 55.6', 66.66666666666666: ' 66.7', 77.77777777777777: ' 77.8', 88.88888888888889: ' 88.9', 100.0: '100.0'} ''' import string import numpy.ma @@ -995,21 +1017,18 @@ def mklabels(vals, output='dict'): amax = float(numpy.ma.maximum(vals)) # Number of digit on the left of decimal point idigleft = int(numpy.ma.floor(numpy.ma.log10(amax))) + 1 - # Now determine the number of significant figures - idig = 0 - for i in range(nvals): - aa = numpy.ma.power(10., -idigleft) - while abs(round(aa * vals[i]) - aa * vals[i]) > .000001: - aa = aa * 10. - idig = numpy.ma.maximum( - idig, - numpy.ma.floor( - numpy.ma.log10( - aa * - numpy.ma.power( - 10., - idigleft)))) - idig = int(idig) + + if precision is None: + # Now determine the number of significant figures + idig = 0 + for i in range(nvals): + aa = numpy.ma.power(10., -idigleft) + while abs(round(aa * vals[i]) - aa * vals[i]) > .000001: + aa = aa * 10. + idig = numpy.ma.maximum(idig, numpy.ma.floor(numpy.ma.log10(aa * numpy.ma.power(10., idigleft)))) + idig = int(idig) + else: + idig = int(precision) # Now does the writing part lbls = [] # First if we need an E format diff --git a/Packages/vcs/Lib/vcsvtk/boxfillpipeline.py b/Packages/vcs/Lib/vcsvtk/boxfillpipeline.py index 54d9b8a60..98f61794e 100644 --- a/Packages/vcs/Lib/vcsvtk/boxfillpipeline.py +++ b/Packages/vcs/Lib/vcsvtk/boxfillpipeline.py @@ -51,12 +51,13 @@ class BoxfillPipeline(Pipeline2D): nlev = (self._gm.color_2 - self._gm.color_1) + 1 if numpy.allclose(self._gm.level_1, 1.e20) or \ numpy.allclose(self._gm.level_2, 1.e20): - self._contourLevels = vcs.mkscale(self._scalarRange[0], - self._scalarRange[1], nc=min(nlev, 12)) + self._contourLevels = vcs.mkevenlevels(self._scalarRange[0], + self._scalarRange[1], nlev=min(nlev, 12)) if len(self._contourLevels) == 1: # constant value ? - self._contourLevels = [self._contourLevels[0], - self._contourLevels[0] + .00001] - self._contourLabels = vcs.mklabels(self._contourLevels) + self._contourLevels = [self._contourLevels[0], self._contourLevels[0] + .00001] + + max_precision = max(vcs.guess_precision(self._contourLevels[0]), vcs.guess_precision(self._contourLevels[-1])) + self._contourLabels = vcs.mklabels(self._contourLevels, precision=max_precision) dx = (self._contourLevels[-1] - self._contourLevels[0]) / nlev self._contourLevels = numpy.arange(self._contourLevels[0], self._contourLevels[-1] + dx, @@ -282,6 +283,7 @@ class BoxfillPipeline(Pipeline2D): # Colortable bit # make sure length match + print self._contourLevels numLevels = len(self._contourLevels) - 1 while len(self._contourColors) < numLevels: self._contourColors.append(self._contourColors[-1]) diff --git a/testing/vcs/CMakeLists.txt b/testing/vcs/CMakeLists.txt index 69df44d3e..2bb2cde28 100644 --- a/testing/vcs/CMakeLists.txt +++ b/testing/vcs/CMakeLists.txt @@ -928,7 +928,11 @@ cdat_add_test(vcs_test_configurator_resize ${cdat_SOURCE_DIR}/testing/vcs/test_vcs_configurator_resize.py ${BASELINE_DIR}/test_vcs_configurator_resize.png ) - +cdat_add_test(vcs_test_fewer_colors_than_levels + "${PYTHON_EXECUTABLE}" + ${cdat_SOURCE_DIR}/testing/vcs/test_fewer_colors_than_levels.py + ${BASELINE_DIR}/test_fewer_colors_than_levels.png +) cdat_add_test(vcs_test_colorpicker_appearance "${PYTHON_EXECUTABLE}" ${cdat_SOURCE_DIR}/testing/vcs/test_vcs_colorpicker_appearance.py diff --git a/testing/vcs/test_fewer_colors_than_levels.py b/testing/vcs/test_fewer_colors_than_levels.py new file mode 100644 index 000000000..2779d4b6d --- /dev/null +++ b/testing/vcs/test_fewer_colors_than_levels.py @@ -0,0 +1,29 @@ +import vcs,cdms2,sys,os + +baselineImage = sys.argv[1] + +pth = os.path.join(os.path.dirname(__file__),"..") +sys.path.append(pth) +import checkimage + +dataset = cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) +data = dataset("clt") + +canvas = vcs.init() +canvas.setantialiasing(0) +canvas.setbgoutputdimensions(1200, 1091, units="pixels") +canvas.drawlogooff() + +boxfill = canvas.createboxfill() + +boxfill.color_1 = 242 +boxfill.color_2 = 250 + +canvas.plot(data, boxfill, bg=1) + +testImage = os.path.abspath("test_fewer_colors_than_levels.png") +canvas.png(testImage) + +ret = checkimage.check_result_image(testImage, baselineImage, checkimage.defaultThreshold) + +sys.exit(ret) -- GitLab From a75310d17ac964828703dcf63635b9812c5bb75d Mon Sep 17 00:00:00 2001 From: Charles Doutriaux Date: Wed, 6 Apr 2016 11:34:34 -0700 Subject: [PATCH 013/191] Update spyder_external.cmake --- CMake/cdat_modules/spyder_external.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMake/cdat_modules/spyder_external.cmake b/CMake/cdat_modules/spyder_external.cmake index ef88a8338..dede73c00 100644 --- a/CMake/cdat_modules/spyder_external.cmake +++ b/CMake/cdat_modules/spyder_external.cmake @@ -2,6 +2,6 @@ # and configure and build it set (nm spyder) -set(OLD "") +set(OLD "OFF") include(pipinstaller) -- GitLab From ad2fe28dafab39e92273010beeeb0766c73337d2 Mon Sep 17 00:00:00 2001 From: Charles Doutriaux Date: Wed, 6 Apr 2016 11:34:58 -0700 Subject: [PATCH 014/191] Update docutils_external.cmake --- CMake/cdat_modules/docutils_external.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMake/cdat_modules/docutils_external.cmake b/CMake/cdat_modules/docutils_external.cmake index 8e419bd00..36bdaedb1 100644 --- a/CMake/cdat_modules/docutils_external.cmake +++ b/CMake/cdat_modules/docutils_external.cmake @@ -2,5 +2,5 @@ # and configure and build it set(nm docutils) -set(OLD "") +set(OLD "OFF") include(pipinstaller) -- GitLab From 6c7b637eff5f87bba2544f332642c4de30cdafd9 Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Tue, 12 Apr 2016 15:13:32 -0700 Subject: [PATCH 015/191] Added documentation of plot args, deprecated some old ones, removed broken ones --- Packages/vcs/vcs/Canvas.py | 51 ++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/Packages/vcs/vcs/Canvas.py b/Packages/vcs/vcs/Canvas.py index 1032dba3c..25f8e731d 100644 --- a/Packages/vcs/vcs/Canvas.py +++ b/Packages/vcs/vcs/Canvas.py @@ -2264,13 +2264,13 @@ Options::: # Set alias for the secondary drawtextcombined. drawtext = drawtextcombined - _plot_keywords_ = ['variable', 'grid', 'xaxis', 'yaxis', 'xrev', 'yrev', 'continents', 'xarray', 'yarray', - 'name', 'time', 'units', 'ymd', 'file_comment', - 'xbounds', 'ybounds', 'xname', 'yname', 'xunits', 'yunits', 'xweights', 'yweights', - 'comment1', 'comment2', 'comment3', 'comment4', 'hms', 'long_name', 'zaxis', - 'zarray', 'zname', 'zunits', 'taxis', 'tarray', 'tname', 'tunits', 'waxis', 'warray', - 'wname', 'wunits', 'bg', 'ratio', 'donotstoredisplay', 'render', 'continents_line', "display_name"] + _plot_keywords_ = ['variable', 'grid', 'xaxis', 'xarray', 'xrev', 'yaxis', 'yarray', 'yrev', 'continents', + 'xbounds', 'ybounds', 'zaxis', 'zarray', 'taxis', 'tarray', 'waxis', 'warray', 'bg', 'ratio', + 'donotstoredisplay', 'render', 'continents_line', "display_name"] + _deprecated_plot_keywords_ = ["time", "units", "file_comment", "xname", "yname", "zname", "tname", "wname", + "xunits", "yunits", "zunits", "tunits", "wunits", "comment1", "comment2", "comment3", + "comment4", "long_name"] # def replot(self): # """ Clears and plots with last used plot arguments # """ @@ -2317,28 +2317,10 @@ Options::: '3',3: y dim will be 3 times bigger than x dim (restricted to original tempalte.data area Adding a 't' at the end of the ratio, makes the tickmarks and boxes move along. - Variable attribute keys: - comment1 = string #Comment plotted above file_comment - comment2 = string #Comment plotted above comment1 - comment3 = string #Comment plotted above comment2 - comment4 = string #Comment plotted above comment4 - file_comment = string #Comment (defaults to file.comment) - hms = string (hh:mm:ss) #Hour, minute, second - long_name = string #Descriptive variable name - name = string #Variable name (defaults to var.id) - time = cdtime #instance (relative or absolute), - cdtime, reltime or abstime value - units = string #Variable units - ymd = string (yy/mm/dd) #Year, month, day - Dimension attribute keys (dimension length=n): [x|y|z|t|w]array = NumPy array of length n # x or y Dimension values [x|y|z|t|w]array = NumPy array of length n # x or y Dimension values [x|y]bounds = NumPy array of shape (n,2) # x or y Dimension boundaries - [x|y|z|t|w]name = string # x or y Dimension name - [x|y|z|t|w]units = string # x or y Dimension units - [x|y]weights = NumPy array of length n # x or y Dimension weights (used to - calculate area-weighted mean) CDMS object: [x|y|z|t|w]axis = CDMS axis object # x or y Axis @@ -2365,7 +2347,13 @@ Options::: # Values 6 through 11 signify the line type # defined by the files data_continent_other7 # through data_continent_other12. - + continents_line = vcs.getline("default") # VCS line object to define continent appearance + donotstoredisplay = True|False # Whether the displayplot object generated by this plot are stored + render = True|False # Whether to actually render the plot or not (useful for doing a + # bunch of plots in a row) + display_name = "__display_123" # VCS Display plot name (used to prevent duplicate display plots) + ratio = 1.5|"autot"|"auto" # Ratio of height/width for the plot; autot and auto will choose a + # "good" ratio for you. Graphics Output in Background Mode: bg = 0|1 # if ==1, create images in the background (Don't display the VCS Canvas) @@ -3526,11 +3514,14 @@ Options::: doratio == "0" or doratio[:4] == "auto"): doratio = "1t" for keyarg in keyargs.keys(): - if keyarg not in self.__class__._plot_keywords_ + \ - self.backend._plot_keywords: - warnings.warn( - 'Unrecognized vcs plot keyword: %s, assuming backend (%s) keyword' % - (keyarg, self.backend.type)) + if keyarg not in self.__class__._plot_keywords_ + self.backend._plot_keywords: + if keyarg in self.__class__._deprecated_plot_keywords_: + warnings.warn("Deprecation Warning: Keyword '%s' will be removed in the next version" + "of UV-CDAT." % keyarg) + else: + warnings.warn( + 'Unrecognized vcs plot keyword: %s, assuming backend (%s) keyword' % + (keyarg, self.backend.type)) if arglist[0] is not None or 'variable' in keyargs: arglist[0] = self._reconstruct_tv(arglist, keyargs) -- GitLab From a82437bfa57add72c02fce63ad3c3224c67d7e3a Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Tue, 12 Apr 2016 15:15:40 -0700 Subject: [PATCH 016/191] Added documentation to clear's preserve_display arg --- Packages/vcs/vcs/Canvas.py | 3 +++ Packages/vcs/vcs/VTKPlots.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Packages/vcs/vcs/Canvas.py b/Packages/vcs/vcs/Canvas.py index 25f8e731d..bd8c82310 100644 --- a/Packages/vcs/vcs/Canvas.py +++ b/Packages/vcs/vcs/Canvas.py @@ -3891,6 +3891,9 @@ Options::: a.plot(array,'default','isofill','quick') a.clear() + Internally, update() calls clear() to assist in removing plots. The preserve_display argument is used to + make sure that the display plots that are associated with the current canvas are not eliminated, and + are still able to be used to regenerate the plots. """ if self.animate.created(): self.animate.close() diff --git a/Packages/vcs/vcs/VTKPlots.py b/Packages/vcs/vcs/VTKPlots.py index d4a8241fa..4d870cd15 100644 --- a/Packages/vcs/vcs/VTKPlots.py +++ b/Packages/vcs/vcs/VTKPlots.py @@ -306,7 +306,7 @@ class VTKVCSBackend(object): key["continents_line"] = d.continents_line key_args.append(key) - # Have to pull out the UI layer so it doesn't get borked by the clear + # Have to pull out the UI layer so it doesn't get borked by the z self.hideGUI() if self.canvas.configurator is not None: -- GitLab From 88d77458579cf71437f4808b26547d1aa6dbda03 Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Fri, 15 Apr 2016 11:37:57 -0700 Subject: [PATCH 017/191] Fix bug in template's drawColorBox function that could prevent some labels from being drawn --- Packages/vcs/Lib/template.py | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/Packages/vcs/Lib/template.py b/Packages/vcs/Lib/template.py index 7d5869eee..2fd255525 100644 --- a/Packages/vcs/Lib/template.py +++ b/Packages/vcs/Lib/template.py @@ -1844,7 +1844,7 @@ class P(object): startlong]) # Now make sure we have a legend if isinstance(levels[0], list): - # Ok these are nono contiguous levels, we will use legend only if + # Ok these are non-contiguous levels, we will use legend only if # it's a perfect match for i, l in enumerate(levels): lt = l[0] @@ -1869,29 +1869,30 @@ class P(object): else: if legend is None: legend = vcs.mklabels(levels) + float_epsilon = numpy.finfo(float).eps if levels[0] < levels[1]: - ecompfunc = numpy.less_equal - compfunc = numpy.less + ecompfunc = lambda x, y: float_epsilon > x - y + compfunc = lambda x, y: -float_epsilon > x - y else: - ecompfunc = numpy.greater_equal - compfunc = numpy.greater + ecompfunc = lambda x, y: -float_epsilon < x - y + compfunc = lambda x, y: float_epsilon < x - y dlong = dD / (len(levels) - 1) + for l in legend.keys(): + # if legend key is between levels[0] and levels[-1] if not compfunc(l, levels[0]) and not compfunc(levels[-1], l): for i in range(len(levels) - 1): - if ecompfunc(levels[i], l) and ecompfunc( - l, levels[i + 1]): - # Ok we're between 2 levels, let's add the legend - # first let's figure out where to put it - loc = i * dlong # position at beginnig of level - # Adds the distance from beginnig of level box - loc += (l - levels[i]) / \ - (levels[i + 1] - levels[i]) * dlong - loc += startlong # Figures out the begining - # loc=((l-levels[0])/(levels[-1]-levels[0]))*dD+startlong - Ll.append([loc, loc]) + # if legend key is (inclusive) between levels[i] and levels[i+1] + if ecompfunc(levels[i], l) and ecompfunc(l, levels[i + 1]): + # first let's figure out where to put the legend label + location = i * dlong # position at beginning of level + # Adds the distance from beginning of level box + location += (l - levels[i]) / (levels[i + 1] - levels[i]) * dlong + location += startlong # Figures out the beginning + + Ll.append([location, location]) Sl.append([startshrt, startshrt + dshrt]) - Lt.append(loc) + Lt.append(location) St.append(startshrt + dshrt * 1.4) Tt.append(legend[l]) break -- GitLab From 5ab070a1b4b68eb7ccd94808638b1bfd7ed50784 Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Fri, 15 Apr 2016 11:38:36 -0700 Subject: [PATCH 018/191] Refactored legend/label logic to be in boxfill, fixed label generation, eliminated "guess_precision" --- Packages/vcs/Lib/boxfill.py | 44 ++++++++++++++++++++ Packages/vcs/Lib/utils.py | 44 +++++--------------- Packages/vcs/Lib/vcsvtk/boxfillpipeline.py | 47 +--------------------- 3 files changed, 56 insertions(+), 79 deletions(-) diff --git a/Packages/vcs/Lib/boxfill.py b/Packages/vcs/Lib/boxfill.py index 231b22839..76de13e04 100755 --- a/Packages/vcs/Lib/boxfill.py +++ b/Packages/vcs/Lib/boxfill.py @@ -24,6 +24,7 @@ import vcs import cdtime import VCS_validation_functions import xmldocs +import numpy import warnings @@ -734,6 +735,49 @@ class Gfb(object): self.yaxisconvert = yat xyscale.__doc__ = xmldocs.xyscaledoc + def getlevels(self, varmin, varmax): + if self.boxfill_type == "custom": + return self.levels + + if numpy.allclose(self.level_1, 1.e20) or \ + numpy.allclose(self.level_2, 1.e20): + low_end = varmin + high_end = varmax + else: + low_end = self.level_1 + high_end = self.level_2 + + if self.boxfill_type == "log10": + low_end = numpy.ma.log10(low_end) + high_end = numpy.ma.log10(high_end) + + nlev = float(self.color_2 - self.color_1 + 1) + scale = vcs.mkscale(low_end, high_end) + + low_end = scale[0] + high_end = scale[-1] + + dx = (high_end - low_end) / nlev + + contourLevels = numpy.arange(low_end, high_end + dx / 2., dx) + return contourLevels + + def getlegendlabels(self, levels): + if self.legend: + return self.legend + nlev = self.color_2 - self.color_1 + 1 + if nlev >= 12: + label_scale = vcs.mkscale(levels[0], levels[-1]) + return vcs.mklabels(label_scale) + else: + # Need to line up the levels and the labels, so we'll massage the label positions + dx = levels[1] - levels[0] + # Determine what decimal place we should round the label to to "see a difference" + round_pos = -1 * int(numpy.ma.log10(dx)) + round_values = [numpy.round(l, round_pos) for l in levels] + round_labels = vcs.mklabels(round_values, "list") + return {lev: label for lev, label in zip(levels, round_labels)} + ########################################################################### # # # List out boxfill graphics method members (attributes). # diff --git a/Packages/vcs/Lib/utils.py b/Packages/vcs/Lib/utils.py index 91c2acc2d..5550ae771 100644 --- a/Packages/vcs/Lib/utils.py +++ b/Packages/vcs/Lib/utils.py @@ -937,24 +937,7 @@ def __split2contiguous(levels): return tmplevs -def guess_precision(num): - """ - Rough guesstimate of the precision of a number. Don't use this for actual science. - """ - if num == 0: - return 1 - idigleft = int(float(numpy.ma.floor(numpy.ma.log10(num)))) + 1 - aa = numpy.ma.power(10., -idigleft) - - while abs(round(aa * num) - aa * num) > .000001: - aa = aa * 10. - - total_digits = numpy.ma.floor(numpy.ma.log10(aa * numpy.ma.power(10., idigleft))) - - return max(total_digits, idigleft) - - -def mklabels(vals, output='dict', precision=None): +def mklabels(vals, output='dict'): ''' Function : mklabels @@ -974,11 +957,6 @@ def mklabels(vals, output='dict', precision=None): {2.0000000000000002e-05: '2E-5', 5.0000000000000002e-05: '5E-5'} >>> vcs.mklabels ( [.00002,.00005],output='list') ['2E-5', '5E-5'] - >>> a = vcs.mkevenlevels(0, 100, nlev=9) - >>> vcs.mklabels(a) - {0.0: ' 0.000000000000000', 11.11111111111111: ' 11.111111111111111', 22.22222222222222: ' 22.222222222222221', 33.33333333333333: ' 33.333333333333329', 44.44444444444444: ' 44.444444444444443', 55.55555555555556: ' 55.555555555555557', 66.66666666666666: ' 66.666666666666657', 77.77777777777777: ' 77.777777777777771', 88.88888888888889: ' 88.888888888888886', 100.0: '100.000000000000000'} - >>> vcs.mklabels(a, precision=4) - {0.0: ' 0.0', 11.11111111111111: ' 11.1', 22.22222222222222: ' 22.2', 33.33333333333333: ' 33.3', 44.44444444444444: ' 44.4', 55.55555555555556: ' 55.6', 66.66666666666666: ' 66.7', 77.77777777777777: ' 77.8', 88.88888888888889: ' 88.9', 100.0: '100.0'} ''' import string import numpy.ma @@ -1018,17 +996,15 @@ def mklabels(vals, output='dict', precision=None): # Number of digit on the left of decimal point idigleft = int(numpy.ma.floor(numpy.ma.log10(amax))) + 1 - if precision is None: - # Now determine the number of significant figures - idig = 0 - for i in range(nvals): - aa = numpy.ma.power(10., -idigleft) - while abs(round(aa * vals[i]) - aa * vals[i]) > .000001: - aa = aa * 10. - idig = numpy.ma.maximum(idig, numpy.ma.floor(numpy.ma.log10(aa * numpy.ma.power(10., idigleft)))) - idig = int(idig) - else: - idig = int(precision) + # Now determine the number of significant figures + idig = 0 + for i in range(nvals): + aa = numpy.ma.power(10., -idigleft) + while abs(round(aa * vals[i]) - aa * vals[i]) > .000001: + aa = aa * 10. + idig = numpy.ma.maximum(idig, numpy.ma.floor(numpy.ma.log10(aa * numpy.ma.power(10., idigleft)))) + idig = int(idig) + # Now does the writing part lbls = [] # First if we need an E format diff --git a/Packages/vcs/Lib/vcsvtk/boxfillpipeline.py b/Packages/vcs/Lib/vcsvtk/boxfillpipeline.py index 98f61794e..a27c724cc 100644 --- a/Packages/vcs/Lib/vcsvtk/boxfillpipeline.py +++ b/Packages/vcs/Lib/vcsvtk/boxfillpipeline.py @@ -47,50 +47,8 @@ class BoxfillPipeline(Pipeline2D): def _updateContourLevelsAndColorsForBoxfill(self): """Set contour information for a standard boxfill.""" - # Compute levels - nlev = (self._gm.color_2 - self._gm.color_1) + 1 - if numpy.allclose(self._gm.level_1, 1.e20) or \ - numpy.allclose(self._gm.level_2, 1.e20): - self._contourLevels = vcs.mkevenlevels(self._scalarRange[0], - self._scalarRange[1], nlev=min(nlev, 12)) - if len(self._contourLevels) == 1: # constant value ? - self._contourLevels = [self._contourLevels[0], self._contourLevels[0] + .00001] - - max_precision = max(vcs.guess_precision(self._contourLevels[0]), vcs.guess_precision(self._contourLevels[-1])) - self._contourLabels = vcs.mklabels(self._contourLevels, precision=max_precision) - dx = (self._contourLevels[-1] - self._contourLevels[0]) / nlev - self._contourLevels = numpy.arange(self._contourLevels[0], - self._contourLevels[-1] + dx, - dx) - else: - if self._gm.boxfill_type == "log10": - levslbls = vcs.mkscale(numpy.ma.log10(self._gm.level_1), - numpy.ma.log10(self._gm.level_2)) - self._contourLevels = vcs.mkevenlevels( - numpy.ma.log10(self._gm.level_1), - numpy.ma.log10(self._gm.level_2), nlev=nlev) - else: - levslbls = vcs.mkscale(self._gm.level_1, self._gm.level_2) - self._contourLevels = vcs.mkevenlevels(self._gm.level_1, - self._gm.level_2, - nlev=nlev) - if len(self._contourLevels) > 25: - # Too many colors/levels need to prettyfy this for legend - self._contourLabels = vcs.mklabels(levslbls) - # Make sure extremes are in - legd2 = vcs.mklabels([self._contourLevels[0], - self._contourLevels[-1]]) - self._contourLabels.update(legd2) - else: - self._contourLabels = vcs.mklabels(self._contourLevels) - if self._gm.boxfill_type == "log10": - logLabels = {} - for key in self._contourLabels.keys(): - value = self._contourLabels[key] - newKey = float(numpy.ma.log10(value)) - logLabels[newKey] = value - self._contourLabels = logLabels - + self._contourLevels = self._gm.getlevels(self._scalarRange[0], self._scalarRange[1]) + self._contourLabels = self._gm.getlegendlabels(self._contourLevels) # Use consecutive colors: self._contourColors = range(self._gm.color_1, self._gm.color_2 + 1) @@ -283,7 +241,6 @@ class BoxfillPipeline(Pipeline2D): # Colortable bit # make sure length match - print self._contourLevels numLevels = len(self._contourLevels) - 1 while len(self._contourColors) < numLevels: self._contourColors.append(self._contourColors[-1]) -- GitLab From 602bba871669b09b6e4622ea18d35baafa62ce42 Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Mon, 18 Apr 2016 15:00:09 -0700 Subject: [PATCH 019/191] Tweaks to get tests to pass --- Packages/vcs/vcs/boxfill.py | 61 ++++++++++++++++++++++++++---------- Packages/vcs/vcs/template.py | 18 ++++++----- 2 files changed, 55 insertions(+), 24 deletions(-) diff --git a/Packages/vcs/vcs/boxfill.py b/Packages/vcs/vcs/boxfill.py index 76de13e04..e17145437 100755 --- a/Packages/vcs/vcs/boxfill.py +++ b/Packages/vcs/vcs/boxfill.py @@ -739,8 +739,12 @@ class Gfb(object): if self.boxfill_type == "custom": return self.levels + nlev = float(self.color_2 - self.color_1 + 1) + autolevels = False + if numpy.allclose(self.level_1, 1.e20) or \ numpy.allclose(self.level_2, 1.e20): + autolevels = True low_end = varmin high_end = varmax else: @@ -751,32 +755,57 @@ class Gfb(object): low_end = numpy.ma.log10(low_end) high_end = numpy.ma.log10(high_end) - nlev = float(self.color_2 - self.color_1 + 1) - scale = vcs.mkscale(low_end, high_end) - low_end = scale[0] - high_end = scale[-1] + if autolevels: + # Use nice values for the scale + scale = vcs.mkscale(low_end, high_end) + low_end = scale[0] + high_end = scale[-1] dx = (high_end - low_end) / nlev - contourLevels = numpy.arange(low_end, high_end + dx / 2., dx) + if dx == 0: + high_end += .00001 + return [low_end, high_end] + + contourLevels = numpy.arange(low_end, high_end + dx, dx) + return contourLevels def getlegendlabels(self, levels): if self.legend: return self.legend - nlev = self.color_2 - self.color_1 + 1 - if nlev >= 12: - label_scale = vcs.mkscale(levels[0], levels[-1]) - return vcs.mklabels(label_scale) + + if numpy.allclose(self.level_1, 1.e20) or \ + numpy.allclose(self.level_2, 1.e20): + autolevels = True + else: + autolevels = False + + if len(levels) > 12: + scale = vcs.mkscale(levels[0], levels[-1]) + if autolevels: + return vcs.mklabels(scale) + else: + # Create our own scale + dx = (self.level_2 - self.level_1) / float(len(scale)) + real_values = [self.level_1, self.level_2] + levels = numpy.arange(levels[0], levels[-1] + dx, dx) else: - # Need to line up the levels and the labels, so we'll massage the label positions - dx = levels[1] - levels[0] - # Determine what decimal place we should round the label to to "see a difference" - round_pos = -1 * int(numpy.ma.log10(dx)) - round_values = [numpy.round(l, round_pos) for l in levels] - round_labels = vcs.mklabels(round_values, "list") - return {lev: label for lev, label in zip(levels, round_labels)} + real_values = levels + + # Need to line up the levels and the labels, so we'll massage the label positions + max_round = 0 + for l in real_values: + round_pos = 0 + while numpy.round(l, round_pos) != l: + round_pos += 1 + max_round = max(max_round, round_pos) + + round_values = [numpy.round(l, round_pos) for l in levels] + round_labels = vcs.mklabels(round_values, "list") + + return {lev: label for lev, label in zip(levels, round_labels)} ########################################################################### # # diff --git a/Packages/vcs/vcs/template.py b/Packages/vcs/vcs/template.py index cb1c0217f..3eaac046b 100644 --- a/Packages/vcs/vcs/template.py +++ b/Packages/vcs/vcs/template.py @@ -1873,21 +1873,23 @@ class P(object): else: if legend is None: legend = vcs.mklabels(levels) - float_epsilon = numpy.finfo(float).eps + # We'll use the less precise float epsilon since this is just for labels + float_epsilon = numpy.finfo(numpy.float32).eps if levels[0] < levels[1]: - ecompfunc = lambda x, y: float_epsilon > x - y - compfunc = lambda x, y: -float_epsilon > x - y + # <= + comparison = lambda a, b: float_epsilon > a - b else: - ecompfunc = lambda x, y: -float_epsilon < x - y - compfunc = lambda x, y: float_epsilon < x - y + # >= + comparison = lambda a, b: -float_epsilon < a - b + + in_bounds = lambda x: comparison(levels[0], x) and comparison(x, levels[-1]) dlong = dD / (len(levels) - 1) for l in legend.keys(): - # if legend key is between levels[0] and levels[-1] - if not compfunc(l, levels[0]) and not compfunc(levels[-1], l): + if in_bounds(l): for i in range(len(levels) - 1): # if legend key is (inclusive) between levels[i] and levels[i+1] - if ecompfunc(levels[i], l) and ecompfunc(l, levels[i + 1]): + if comparison(levels[i], l) and comparison(l, levels[i + 1]): # first let's figure out where to put the legend label location = i * dlong # position at beginning of level # Adds the distance from beginning of level box -- GitLab From de21dafb8092fb258f0053edd9b732e806ff213a Mon Sep 17 00:00:00 2001 From: Charles Doutriaux Date: Tue, 19 Apr 2016 13:20:50 -0700 Subject: [PATCH 020/191] readme edits --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f79ed08fb..f1747bb98 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ uvcdat ====== [![build status](https://travis-ci.org/UV-CDAT/uvcdat.svg?branch=master)](https://travis-ci.org/UV-CDAT/uvcdat/builds) -[![stable version](http://img.shields.io/badge/stable version-2.4.0-brightgreen.svg)](https://github.com/UV-CDAT/uvcdat/releases/tag/2.4.0) +[![stable version](http://img.shields.io/badge/stable version-2.4.1-brightgreen.svg)](https://github.com/UV-CDAT/uvcdat/releases/tag/2.4.1) ![platforms](http://img.shields.io/badge/platforms-linux | osx-lightgrey.svg) -[![DOI](https://zenodo.org/badge/doi/10.5281/zenodo.45136.svg)](http://dx.doi.org/10.5281/zenodo.45136) +[![DOI](https://zenodo.org/badge/doi/10.5281/zenodo.50101.svg)](http://dx.doi.org/10.5281/zenodo.50101) Developed by partnering with ESGF and the community to create a larger problem-solving environment, UV-CDAT is an open source, easy-to-use application that links together disparate software subsystems and packages to form an integrated environment for analysis and visualization. This project seeks to advance climate science by fulfilling computational and diagnostic/visualization capabilities needed for DOE's climate research. @@ -13,4 +13,4 @@ Developing and Contributing ------ We'd love to get contributions from you! Please take a look at the [Contribution Documents](CONTRIBUTING.md) to see how to get your changes merged -in. \ No newline at end of file +in. -- GitLab From 585e4385fa2f517a580244b9cb3755b2ec8537ac Mon Sep 17 00:00:00 2001 From: Dan Lipsa Date: Wed, 20 Apr 2016 16:31:34 -0400 Subject: [PATCH 021/191] Allow unicode strings for subsetting. This is how they come from the web. --- Packages/cdms2/Lib/axis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/cdms2/Lib/axis.py b/Packages/cdms2/Lib/axis.py index df2778854..703c0e938 100644 --- a/Packages/cdms2/Lib/axis.py +++ b/Packages/cdms2/Lib/axis.py @@ -2250,7 +2250,7 @@ def axisMatches(axis, specification): 3. an axis object; will match if it is the same object as axis. """ - if isinstance(specification, types.StringType): + if isinstance(specification, basestring): s = string.lower(specification) s = s.strip() while s[0] == '(': -- GitLab From aa680fd6f24450f4157978745372cd266df839b0 Mon Sep 17 00:00:00 2001 From: Charles Doutriaux Date: Thu, 21 Apr 2016 22:45:35 -0700 Subject: [PATCH 022/191] Update README.md Adding badges for Conda --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index f1747bb98..5968858fe 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,9 @@ uvcdat ![platforms](http://img.shields.io/badge/platforms-linux | osx-lightgrey.svg) [![DOI](https://zenodo.org/badge/doi/10.5281/zenodo.50101.svg)](http://dx.doi.org/10.5281/zenodo.50101) +[![Anaconda-Server Badge](https://anaconda.org/uvcdat/uvcdat/badges/installer/conda.svg)](https://conda.anaconda.org/uvcdat) +[![Anaconda-Server Badge](https://anaconda.org/uvcdat/uvcdat/badges/downloads.svg)](https://anaconda.org/uvcdat/uvcdat) + Developed by partnering with ESGF and the community to create a larger problem-solving environment, UV-CDAT is an open source, easy-to-use application that links together disparate software subsystems and packages to form an integrated environment for analysis and visualization. This project seeks to advance climate science by fulfilling computational and diagnostic/visualization capabilities needed for DOE's climate research. Led by Lawrence Livermore National Laboratory (LLNL), the consortium consists of four DOE laboratories (Los Alamos, Lawrence Berkeley, LLNL, and Oak Ridge), two universities (University of Utah and the Polytechnic Institute of New York University), NASA, and two private companies (Kitware and tech-X) that will develop reusable software and workflow analysis and visualization applications for large-scale DOE climate modeling and measurements archives. The UV-CDAT concept is simple and flexible enough to interchange parts to expand for future DOE activities. -- GitLab From 6e372a536414695f0ecf32c240374efb063d6d1e Mon Sep 17 00:00:00 2001 From: McEnerney Date: Mon, 25 Apr 2016 10:20:54 -0700 Subject: [PATCH 023/191] change diags test 01 --- CMake/cdat_modules/uvcmetrics_pkg.cmake | 2 +- testing/metrics/diagtest01.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMake/cdat_modules/uvcmetrics_pkg.cmake b/CMake/cdat_modules/uvcmetrics_pkg.cmake index 7024a9580..2f8294042 100644 --- a/CMake/cdat_modules/uvcmetrics_pkg.cmake +++ b/CMake/cdat_modules/uvcmetrics_pkg.cmake @@ -6,7 +6,7 @@ set(UVCMETRICS_ZIP uvcmetrics-${UVCMETRICS_VERSION}.zip) #set(UVCMETRICS_SOURCE ${UVCMETRICS_URL}/${UVCMETRICS_ZIP}) set(UVCMETRICS_SOURCE ${GIT_PROTOCOL}github.com/UV-CDAT/uvcmetrics.git ) set(UVCMETRICS_MD5) -set(UVCMETRICS_BRANCH uvcdat-2.4.1) +set(UVCMETRICS_BRANCH master) if (NOT CDAT_BUILD_LEAN) add_cdat_package(UVCMETRICS "" "" ON) diff --git a/testing/metrics/diagtest01.py b/testing/metrics/diagtest01.py index b8cf415f0..09197a1e3 100755 --- a/testing/metrics/diagtest01.py +++ b/testing/metrics/diagtest01.py @@ -58,7 +58,7 @@ varid = 'T' vard = package.all_variables( filetable1, filetable2, sname ) var = vard[varid] -plot = sclass( [filetable1], [filetable2], varid, seasonid ) +plot = sclass( [filetable1], [filetable2], varid, seasonid, plotparms = { 'model':{}, 'obs':{}, 'diff':{} } ) res = plot.compute() if res is not None: if res.__class__.__name__ is 'uvc_composite_plotspec': -- GitLab From 99d489b10def142ad93aa1959c31d797cfa46896 Mon Sep 17 00:00:00 2001 From: Charles Doutriaux Date: Tue, 26 Apr 2016 08:53:03 -0700 Subject: [PATCH 024/191] cdscan removed use of old modules string and types --- Packages/cdms2/Script/cdscan | 84 ++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 43 deletions(-) diff --git a/Packages/cdms2/Script/cdscan b/Packages/cdms2/Script/cdscan index 59896b1b4..8914abbdd 100755 --- a/Packages/cdms2/Script/cdscan +++ b/Packages/cdms2/Script/cdscan @@ -7,11 +7,9 @@ from cdms2.grid import lookupArray from cdms2.axis import calendarToTag, tagToCalendar from cdms2.cdmsobj import CdFromObject,CdString,CdScalar,CdFloat,CdDouble,CdShort,CdInt,CdLong import numpy -import string import cdtime import os.path import copy -import types from cdms2 import cdmsNode import re @@ -258,7 +256,7 @@ def timeindex(value, units, basetime, delta, calendar): where t = reltime(value, units) and delu is the time interval (delta, delunits) (e.g., 1 month). """ - if string.find(units," as ")==-1: + if units.find(" as ")==-1: tval = cdtime.reltime(value, units) else: tval = cdtime.abstime(value, units) @@ -426,7 +424,7 @@ def disambig(name, dict, num, comparator, value): uniqname = '%s_%d'%(name,num) if dict.has_key(uniqname) and comparator(value, dict[uniqname]): trial_name = uniqname - for letter in string.lowercase: + for letter in 'abcdefghijklmnopqrstuvwxyz': uniqname = '%s_%s'%(trial_name,letter) if not dict.has_key(uniqname) or not comparator(value, dict[uniqname]): break @@ -448,7 +446,7 @@ def comparedomains(domain1, domain2): item2 = domain2[i] if type(item1)!=type(item2): return 1 - if type(item1)==types.StringType: + if isinstance(item1, basestring): return item1!=item2 elif compareaxes(item1, item2): return 1 @@ -486,14 +484,14 @@ def validateAttrs(node): if reqtype==CdFromObject: reqtype = parenttype if reqtype!=datatype and datatype==CdString and scaletype==CdScalar: - if reqtype in (CdFloat,CdDouble) and type(attval)!=types.FloatType: + if reqtype in (CdFloat,CdDouble) and not isinstance(attval, float): try: - attval = string.atof(attval) + attval = float(attval) except: if verbose: print >> sys.stderr, "Warning: %s=%s should be a float, id=%s"%(attname,attval,node.id), try: - attval = string.atoi(attval) + attval = int(attval) attval = float(attval) if verbose: print "(Recasting)" @@ -507,14 +505,14 @@ def validateAttrs(node): else: if verbose: print "" - elif reqtype in (CdShort,CdInt,CdLong) and type(attval)!=types.IntType: + elif reqtype in (CdShort,CdInt,CdLong) and not isinstance(attval, int): try: - attval = string.atoi(attval) + attval = int(attval) except: if verbose: print >> sys.stderr, "Warning: %s=%s should be an integer, id=%s"%(attname,attval,node.id), try: - attval = string.atof(attval) + attval = float(attval) attval = int(attval) if verbose: print "(Recasting)" @@ -530,7 +528,7 @@ def cloneWithLatCheck(axis): global notrimlat axisvals = origvals = axis[:] - if axis.isLatitude() and hasattr(axis,"units") and string.lower(axis.units[0:6])=="degree": + if axis.isLatitude() and hasattr(axis,"units") and axis.units[0:6].lower()=="degree": if notrimlat==0: axisvals = numpy.maximum(-90.0, numpy.minimum(90.0,axisvals)) if not numpy.ma.allclose(axisvals, origvals) and verbose: @@ -563,9 +561,9 @@ def addAttrs(fobj, eattrs): def setNodeDict(node, dict): for key in dict.keys(): value = dict[key] - if (isinstance(value, numpy.integer) or isinstance(value, types.IntType)): + if (isinstance(value, numpy.integer) or isinstance(value, int)): datatype = CdLong - elif (isinstance(value, numpy.floating) or isinstance(value, types.FloatType)): + elif (isinstance(value, numpy.floating) or isinstance(value, float)): datatype = CdDouble else: datatype = CdString @@ -696,7 +694,7 @@ def main(argv): if flag=='-a': aliasMapFile = arg elif flag=='-c': - calenkey = string.lower(arg) + calenkey = arg.lower() calendar = calendarMap[calenkey] overrideCalendar = 1 elif flag=='-d': @@ -717,7 +715,7 @@ def main(argv): elif flag=='--exclude': if arg[0]=='-': raise RuntimeError, "--exclude option requires an argument" - excludeList = string.split(arg,',') + excludeList = arg.split(',') elif flag=='--exclude-file': excludePattern = arg elif flag=='-f': @@ -732,7 +730,7 @@ def main(argv): sys.exit(0) elif flag=='-i': splitOnTime = 1 - referenceDelta = string.atof(arg) + referenceDelta = float(arg) timeIsLinear = 1 timeIsVector = None elif flag=='--ignore-open-error': @@ -740,7 +738,7 @@ def main(argv): elif flag=='--include': if arg[0]=='-': raise RuntimeError, "--include option requires an argument" - includeList = string.split(arg,',') + includeList = arg.split(',') elif flag=='--include-file': includePattern = arg elif flag=='-j': @@ -748,8 +746,8 @@ def main(argv): timeIsLinear = None elif flag=='-l': splitOnLevel = 1 - levelstr = string.split(arg,',') - levellist = map(string.atof, levelstr) + levelstr = arg.split(',') + levellist = map(float, levelstr) levels = numpy.array(levellist) levels = numpy.sort(levels) elif flag=='-m': @@ -771,19 +769,19 @@ def main(argv): timeid = arg args.append(('-e','%s.axis=T'%timeid)) # Add axis=T attribute elif flag=='--time-linear': - targlist = string.split(arg,',') - ttzero = string.atof(targlist[0]) - tdelta = string.atof(targlist[1]) - tunits = string.strip(targlist[2]) + targlist = arg.split(',') + ttzero = float(targlist[0]) + tdelta = float(targlist[1]) + tunits = targlist[2].strip() if len(targlist)==4: - tcalendar = string.strip(targlist[3]) + tcalendar = targlist[3].strip() else: tcalendar = None overrideTimeLinear = [ttzero,tdelta,tunits,tcalendar] elif flag=='--var-locate': if varLocate is None: varLocate = {} - vname, pattern = string.split(arg,',') + vname, pattern = arg.split(',') varLocate[vname]=pattern elif flag=='-x': writeToStdout = 0 @@ -806,7 +804,7 @@ def main(argv): # Ignore blank paths realargs = [] for arg in lastargs: - sarg = string.strip(arg) + sarg = arg.strip() if len(sarg)>0: realargs.append(sarg) lastargs = realargs @@ -816,7 +814,7 @@ def main(argv): dsetargs = [] for arg in lastargs: base, suffix = os.path.splitext(arg) - if string.lower(suffix) in ['.xml','.cdml']: + if suffix.lower() in ['.xml','.cdml']: dsetargs.append(arg) else: fileargs.append(arg) @@ -872,7 +870,7 @@ def main(argv): modelMap = {} modelDirs = [] for line in mfile.readlines(): - mdirec, model = string.split(line) + mdirec, model = line.split() modelMap[mdirec] = model modelDirs.append(mdirec) mfile.close() @@ -882,10 +880,10 @@ def main(argv): aliasMap = {} for line in afile.readlines(): if line[0] not in ["'",'"']: #" - varid, alias = string.split(line) + varid, alias = line.split() else: - dummy, varid, alias = string.split(line,line[0]) - alias = string.strip(alias) + dummy, varid, alias = line.split(line[0]) + alias = alias.strip() aliasMap[varid] = alias afile.close() @@ -983,7 +981,7 @@ def main(argv): boundsmap = {} # boundsmap : varid => timebounds_id boundsdict = {} # Same as vardict for time bounds for path in fileargs: - path = string.strip(path) + path = path.strip() # Check if the path is included if includePattern is not None: @@ -1021,7 +1019,7 @@ def main(argv): if mo is not None: suffixPattern = modelMap[direc] def gensuffix(m, mo=mo): - i = string.atoi(m.group(1)) + i = int(m.group(1)) return mo.group(i) varsuffix = re.sub(r'\\g<(\d)>', gensuffix, suffixPattern) break @@ -1191,7 +1189,7 @@ def main(argv): if verbose and not forecast: print 'Setting reference time units to', referenceTime if timeIsLinear is None and timeIsVector is None: - timeIsLinear = (string.lower(string.split(referenceTime)[0]) in ['hour','hours','minute','minutes','second','seconds']) + timeIsLinear = referenceTime.split()[0].lower() in ['hour','hours','minute','minutes','second','seconds'] if timeIsLinear and verbose: print 'Setting time representation to "linear"' #' if timeIsLinear and referenceDelta is None: @@ -1301,7 +1299,7 @@ def main(argv): if prevcal is not None and calendar != prevcal: sameCalendars = 0 prevcal = calendar - if string.find(units," as ")==-1: + if units.find(" as ")==-1: time0 = cdtime.reltime(values[0],units) else: time0 = cdtime.abstime(values[0],units) @@ -1319,7 +1317,7 @@ def main(argv): if prevcal is not None and calendar != prevcal: sameCalendars = 0 prevcal = calendar - if string.find(units," as ")==-1: + if units.find(" as ")==-1: time0 = cdtime.reltime(values[0],units) else: time0 = cdtime.abstime(values[0],units) @@ -1460,7 +1458,7 @@ def main(argv): domain, attributes, tcode = vardict[varname] for i in range(len(domain)): item = domain[i] - if type(item)==types.StringType and item==name: + if isinstance(item, basestring) and item==name: domain[i] = axisobj # Add bounds variables to vardict, varindex @@ -1479,7 +1477,7 @@ def main(argv): if reprVar in varids: varids.append(boundsname) tmpdom = boundsinfo[0] - if type(tmpdom[1])==types.StringType: + if isinstance(tmpdom[1], basestring): bndsobj = tmpdom[0] boundsdomain = (bndsobj, axisobj) else: @@ -1547,10 +1545,10 @@ def main(argv): # Generate the cdms_filemap attribute cdms_filemap = str(cdms_filemap_list) - cdms_filemap = string.replace(cdms_filemap, ' ', '') - cdms_filemap = string.replace(cdms_filemap, 'None', '-') - cdms_filemap = string.replace(cdms_filemap, '"', '') #" - cdms_filemap = string.replace(cdms_filemap, "'", '') + cdms_filemap = cdms_filemap.replace(' ', '') + cdms_filemap = cdms_filemap.replace('None', '-') + cdms_filemap = cdms_filemap.replace('"', '') + cdms_filemap = cdms_filemap.replace("'", '') # Dump to XML datasetnode = cdmsNode.DatasetNode(datasetid) -- GitLab From c9da8fbba9ae83414658ee040f63c41c0eef6f6c Mon Sep 17 00:00:00 2001 From: Charles Doutriaux Date: Tue, 26 Apr 2016 09:07:43 -0700 Subject: [PATCH 025/191] cleaned up avariable from using types or string module --- Packages/cdms2/Lib/avariable.py | 55 ++++++++++++++------------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/Packages/cdms2/Lib/avariable.py b/Packages/cdms2/Lib/avariable.py index dd2a2792d..bc20b8be5 100644 --- a/Packages/cdms2/Lib/avariable.py +++ b/Packages/cdms2/Lib/avariable.py @@ -3,8 +3,6 @@ "CDMS Variable objects, abstract interface" import numpy -import types -import string import re import warnings import cdmsNode @@ -404,7 +402,7 @@ class AbstractVariable(CdmsObj, Slab): if asarray==0 and isinstance(mv, numpy.ndarray): mv = mv[0] - if type(mv) is types.StringType and self.dtype.char not in ['?','c','O','S']: + if isinstance(mv, basestring) and self.dtype.char not in ['?','c','O','S']: mv = float(mv) return mv @@ -423,17 +421,16 @@ class AbstractVariable(CdmsObj, Slab): return selftype = self.typecode() - valuetype = type(value) - if valuetype is numpy.ndarray: + if isnstance(value, numpy.ndarray): value = value.astype(selftype).item() - elif isinstance(value, numpy.floating) or isinstance(value, numpy.integer): + elif isinstance(value, (numpy.floating, numpy.integer)): value = numpy.array([value], selftype) - elif valuetype in [types.FloatType, types.IntType, types.LongType, types.ComplexType]: + elif isinstance(value, (float, int, long, complex)): try: value = numpy.array([value], selftype) except: # Set fill value when ar[i:j] returns a masked value value = numpy.array([numpy.ma.default_fill_value(self)], selftype) - elif isinstance(value,(str,numpy.string_,numpy.str,numpy.string0,numpy.str_)) and selftype in ['?','c','O','S']: # '?' for Boolean and object + elif isinstance(value,(basestring,numpy.string_,numpy.str,numpy.string0,numpy.str_)) and selftype in ['?','c','O','S']: # '?' for Boolean and object pass else: raise CDMSError, 'Invalid missing value %s'%`value` @@ -1089,7 +1086,7 @@ avariable.regrid: We chose regridMethod = %s for you among the following choices if re.search('^regrid', regridTool, re.I): if keywords.has_key('diag') and \ - type(keywords['diag']) == types.DictType: + isinstance(keywords['diag'], dict): keywords['diag']['regridTool'] = 'regrid' # the original cdms2 regridder @@ -1206,7 +1203,7 @@ avariable.regrid: We chose regridMethod = %s for you among the following choices if specs[i] is Ellipsis: j = myrank - (nsupplied - (i+1)) else: - if isinstance(specs[i], types.IntType): + if isinstance(specs[i], int): singles.append(j) j = j + 1 i = i + 1 @@ -1227,15 +1224,15 @@ avariable.regrid: We chose regridMethod = %s for you among the following choices slicelist = [] for i in range(self.rank()): key = speclist[i] - if isinstance(key, types.IntType): # x[i] + if isinstance(key, int): # x[i] slicelist.append (slice(key,key+1)) - elif type(key) is types.SliceType: # x[i:j:k] + elif isinstance(key, slice): # x[i:j:k] slicelist.append(key) elif key is unspecified or key is None or key == ':': slicelist.append (slice(0, len(self.getAxis(i)))) elif key is Ellipsis: raise CDMSError, "Misuse of ellipsis in specification." - elif type(key) is types.TupleType: + elif sinstance(key, tuple): slicelist.append(slice(*key)) else: raise CDMSError, 'invalid index: %s'% str(key) @@ -1287,13 +1284,13 @@ avariable.regrid: We chose regridMethod = %s for you among the following choices for i in range(self.rank()): item = speclist[i] - if isinstance(item, types.SliceType): + if isinstance(item, slice): newitem = item elif item==':' or item is None or item is unspecified: axis = self.getAxis(i) newitem = slice(0,len(axis)) - elif isinstance(item, types.ListType) or \ - isinstance(item, types.TupleType): + elif isinstance(item, list) or \ + isinstance(item, tuple): axis = self.getAxis(i) if len(item)==2: # (start,end) indexInterval = axis.mapIntervalExt(item) @@ -1314,13 +1311,7 @@ avariable.regrid: We chose regridMethod = %s for you among the following choices if indexInterval is None: raise CDMSError, OutOfRange + str(item) newitem = slice(indexInterval[0],indexInterval[1],indexInterval[2]) - elif isinstance(item, numpy.floating) or \ - isinstance(item, types.FloatType) or \ - isinstance(item, numpy.integer) or \ - isinstance(item, types.IntType) or \ - isinstance(item, types.LongType) or \ - isinstance(item, types.StringType) or \ - type(item) in CdtimeTypes: + elif isinstance(item, (numpy.floating, float, numpy.integer, int, long, basestring)) or type(item) in CdtimeTypes: axis = self.getAxis(i) # # default is 'ccn' in axis.mapIntervalExt @@ -1397,10 +1388,10 @@ avariable.regrid: We chose regridMethod = %s for you among the following choices # numpy.ma overrides def __getitem__(self, key): - if type(key) is types.TupleType: + if isinstance(key, tuple): speclist = self._process_specs(key, {}) else: - if isinstance(key, types.IntType) and key>=len(self): + if isinstance(key, int) and key>=len(self): raise IndexError, "Index too large: %d"%key speclist = self._process_specs([key], {}) @@ -1509,7 +1500,7 @@ def orderparse (order): remaining axes. (name) meaning an axis whose id is name """ - if not isinstance(order, types.StringType): + if not isinstance(order, basestring): raise CDMSError, 'order arguments must be strings.' pos = 0 result=[] @@ -1523,8 +1514,8 @@ def orderparse (order): elif r == '...': r = Ellipsis elif len(r) == 1: - if r in string.digits: - r = string.atoi(r) + if r in '0123456789': + r = int(r) result.append(r) pos = m.end(0) @@ -1544,9 +1535,9 @@ def order2index (axes, order): remaining axes. (name) meaning an axis whose id is name """ - if isinstance(order, types.StringType): + if isinstance(order, basestring): result = orderparse(order) - elif isinstance(order, types.ListType): + elif isinstance(order, list): result = order else: raise CDMSError, 'order2index, order specified of bad type:' + str(type(order)) @@ -1557,7 +1548,7 @@ def order2index (axes, order): pos = 0 while j < len(result): item = result[j] - if isinstance(item, types.StringType): + if isinstance(item, basestring): if item == 't': spec = 'time' elif item == 'x': @@ -1581,7 +1572,7 @@ def order2index (axes, order): break else: raise CDMSError, 'No axis matching order spec %s' %str(item) - elif isinstance(item, types.IntType): + elif isinstance(item, int): if item in permutation: raise CDMSError, 'Duplicate item in order %s' % order if item >= n: -- GitLab From c9956674eb09da35755504d376765dd4f47630bb Mon Sep 17 00:00:00 2001 From: Charles Doutriaux Date: Tue, 26 Apr 2016 09:16:39 -0700 Subject: [PATCH 026/191] cleaned up cdmsobj from using types or string module --- Packages/cdms2/Lib/cdmsobj.py | 59 +++++++++++++++++------------------ 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/Packages/cdms2/Lib/cdmsobj.py b/Packages/cdms2/Lib/cdmsobj.py index 14c2d9bf0..b66cf7307 100644 --- a/Packages/cdms2/Lib/cdmsobj.py +++ b/Packages/cdms2/Lib/cdmsobj.py @@ -7,10 +7,7 @@ import cdtime import glob import os import re -import string import sys -import types -#import internattr # Data types @@ -204,7 +201,7 @@ def generateTime(matchobj,timespecs): if yrspec: pat,name,dimtype,pos = _specifierMap[yrspec] yrstr = matchobj.group(name) - iyr = string.atoi(yrstr) + iyr = int(yrstr) # Map 2-digit year to [1950,2049) if yrspec in ('%y','%ey'): @@ -220,23 +217,23 @@ def generateTime(matchobj,timespecs): elif mospec in ('%g','%eg'): imo = _monthMapLower[mostr] elif mospec in ('%m','%em','%n','%en'): - imo = string.atoi(mostr) + imo = int(mostr) if dyspec: pat,name,dimtype,pos = _specifierMap[dyspec] dystr = matchobj.group(name) - idy = string.atoi(dystr) + idy = int(dystr) if hrspec: pat,name,dimtype,pos = _specifierMap[hrspec] hrstr = matchobj.group(name) - ihr = string.atoi(hrstr) + ihr = int(hrstr) if mispec: pat,name,dimtype,pos = _specifierMap[mispec] mistr = matchobj.group(name) - imi = string.atoi(mistr) + imi = int(mistr) if sespec: pat,name,dimtype,pos = _specifierMap[sespec] sestr = matchobj.group(name) - ise = string.atoi(sestr) + ise = int(sestr) return cdtime.comptime(iyr,imo,idy,ihr,imi,ise) # Find all files in 'direc' which match 'template'. @@ -280,9 +277,9 @@ def matchingFiles(direc,template): if dimtypes['etime'] != [None,None,None,None,None,None]: matchnames[_etime] = generateTime(matchobj,dimtypes['etime']) if dimtypes['level'] is not None: - matchnames[_level] = string.atoi(matchobj.group('level')) + matchnames[_level] = int(matchobj.group('level')) if dimtypes['elevel'] is not None: - matchnames[_elevel] = string.atoi(matchobj.group('elevel')) + matchnames[_elevel] = int(matchobj.group('elevel')) matchfiles.append((candfile,matchnames)) return matchfiles @@ -300,22 +297,22 @@ def getTimeAsString(spec,time): elif spec in ('%S','%eS'): specstr = str(int(time.second)) elif spec in ('%Y','%eY'): - specstr = string.zfill(str(time.year),4) + specstr = str(time.year).zfill(4) elif spec in ('%d','%ed'): specstr = str(time.day) elif spec in ('%f','%ef'): - specstr = string.zfill(str(time.day),2) + specstr = str(time.day).zfill(2) elif spec in ('%g','%eg'): imo = time.month specstr = _monthListLower[imo-1] elif spec in ('%h','%eh'): - specstr = string.zfill(str(time.hour),2) + specstr = str(time.hour).zfill(2) elif spec in ('%m','%em'): specstr = str(time.month) elif spec in ('%n','%en'): - specstr = string.zfill(str(time.month),2) + specstr = str(time.month).zfill(2) elif spec in ('%y','%ey'): - specstr = string.zfill(str(time.year%100),2) + specstr = str(time.year%100).zfill(2) elif spec in ('%z','%ez'): specstr = getTimeAsString('%H',time)+'Z'+getTimeAsString('%Y',time)+getTimeAsString('%n',time)+getTimeAsString('%d',time) return specstr @@ -374,9 +371,9 @@ def getPathFromTemplate(template,matchnames): def searchPattern(objlist, pattern, attribute=None, tag=None): if tag is not None: - tag = string.lower(tag) + tag = tag.lower() regexp = re.compile(pattern) - if type(objlist) is not types.ListType: + if not isinstance(objlist, list): objlist = [objlist] returnlist = [] @@ -395,9 +392,9 @@ def searchPattern(objlist, pattern, attribute=None, tag=None): def matchPattern(objlist, pattern, attribute=None, tag=None): if tag is not None: - tag = string.lower(tag) + tag = tag.lower() regexp = re.compile(pattern) - if type(objlist) is not types.ListType: + if not isinstance(objlist, list): objlist = [objlist] returnlist = [] @@ -425,8 +422,8 @@ def matchPattern(objlist, pattern, attribute=None, tag=None): def searchPredicate(objlist, predicate, tag=None): if tag is not None: - tag = string.lower(tag) - if type(objlist) is not types.ListType: + tag = tag.lower() + if not isinstance(objlist, list): objlist = [objlist] returnlist = [] @@ -490,12 +487,12 @@ class CdmsObj (object): if reqtype!=datatype and datatype==CdString and scaletype==CdScalar: if reqtype in (CdFloat,CdDouble): try: - attval = string.atof(attval) + attval = float(attval) except: raise RuntimeError,"%s=%s must be a float"%(attname,attval) elif reqtype in (CdShort,CdInt,CdLong,CdInt64): try: - attval = string.atoi(attval) + attval = int(attval) except: raise RuntimeError,"%s=%s must be an integer"%(attname,attval) adict[attname] = attval @@ -519,12 +516,12 @@ class CdmsObj (object): """ if attname is None: for attval in self.attributes.values(): - if type(attval) is types.StringType and pattern.search(attval) is not None: + if isinstance(attval,basestring) and pattern.search(attval) is not None: return 1 return 0 elif self.attributes.has_key(attname): attval = self.attributes[attname] - return (type(attval) is types.StringType and pattern.search(attval) is not None) + return isinstance(attval,basestring) and pattern.search(attval) is not None else: return 0 @@ -549,12 +546,12 @@ class CdmsObj (object): """ if attname is None: for attval in self.attributes.values(): - if type(attval) is types.StringType and pattern.match(attval) is not None: + if isinstance(attval,basestring) and pattern.search(attval) is not None: return 1 return 0 elif self.attributes.has_key(attname): attval = self.attributes[attname] - return (type(attval) is types.StringType and pattern.match(attval) is not None) + return isinstance(attval,basestring) and pattern.search(attval) is not None else: return 0 @@ -573,7 +570,7 @@ class CdmsObj (object): result :: (list) (0) ::: """ - if tag is None or string.lower(tag)==self._node_.tag: + if tag is None or tag.lower()==self._node_.tag: if self.searchone(pattern,attribute): return [self] else: @@ -596,7 +593,7 @@ class CdmsObj (object): result :: (list) (0) ::: """ - if tag is None or string.lower(tag)==self._node_.tag: + if tag is None or tag.lower()==self._node_.tag: if self.matchone(pattern,attribute): return [self] else: @@ -619,7 +616,7 @@ class CdmsObj (object): result :: (list) (0) ::: """ - if tag is None or string.lower(tag)==self._node_.tag: + if tag is None or tag.lower()==self._node_.tag: try: if apply(predicate,(self,))==1: result = [self] -- GitLab From fb948093cd0f4d5eea14203c56fad2c707f1a019 Mon Sep 17 00:00:00 2001 From: Charles Doutriaux Date: Tue, 26 Apr 2016 09:40:16 -0700 Subject: [PATCH 027/191] cleaned up axis.py --- Packages/cdms2/Lib/axis.py | 92 +++++++++--------- Packages/cdms2/Lib/internattr.py | 157 ------------------------------- 2 files changed, 46 insertions(+), 203 deletions(-) delete mode 100644 Packages/cdms2/Lib/internattr.py diff --git a/Packages/cdms2/Lib/axis.py b/Packages/cdms2/Lib/axis.py index 703c0e938..458096c22 100644 --- a/Packages/cdms2/Lib/axis.py +++ b/Packages/cdms2/Lib/axis.py @@ -6,7 +6,7 @@ CDMS Axis objects """ _debug = 0 std_axis_attributes = ['name', 'units', 'length', 'values', 'bounds'] -import string, sys, types, copy +import sys, copy import numpy # import regrid2._regrid import cdmsNode @@ -22,13 +22,13 @@ class AliasList (UserList): def __init__(self, alist): UserList.__init__(self,alist) def __setitem__ (self, i, value): - self.data[i] = string.lower(value) + self.data[i] = value.lower() def __setslice(self, i, j, values): - self.data[i:j] = map(lambda x: string.lower(x), values) + self.data[i:j] = map(lambda x: x.lower(), values) def append(self, value): - self.data.append(string.lower(value)) + self.data.append(value.lower()) def extend(self, values): - self.data.extend(map(string.lower, values)) + self.data.extend(map("".lower, values)) level_aliases = AliasList(['plev']) longitude_aliases = AliasList([]) @@ -228,7 +228,7 @@ def mapLinearExt(axis, bounds, interval, indicator ='ccn', epsilon=None, stride= intersection is empty. """ - indicator = string.lower(indicator) + indicator = indicator.lower() length = len(axis) # Make the interval and search array non-decreasing @@ -615,7 +615,7 @@ class AbstractAxis(CdmsObj): self._doubledata_ = None def __str__ (self): - return string.join(self.listall(), "\n") + "\n" + return "\n".join(self.listall() + "\n" __repr__ = __str__ @@ -812,14 +812,14 @@ class AbstractAxis(CdmsObj): for val in self[:]: comptime=cdtime.reltime(val, self.units).tocomp(calendar) s=repr(comptime) - tt=string.split(s,' ') + tt=s.split(' ') - ttt=string.split(tt[0],'-') + ttt=tt[0].split('-') yr=int(ttt[0]) mo=int(ttt[1]) da=int(ttt[2]) - ttt=string.split(tt[1],':') + ttt=tt[1].split(':') hr=int(ttt[0]) dtg="%04d%02d%02d%02d"%(yr,mo,da,hr) result.append(dtg) @@ -974,7 +974,7 @@ class AbstractAxis(CdmsObj): # calendar. def getCalendar(self): if hasattr(self,'calendar'): - calendar = string.lower(self.calendar) + calendar = self.calendar.lower() else: calendar = None @@ -1009,7 +1009,7 @@ class AbstractAxis(CdmsObj): if self.isTime(): if type(value) in CdtimeTypes: value = value.torel(self.units, self.getCalendar()).value - elif type(value) is types.StringType and value not in [':',unspecified]: + elif isinstance(value, basestring) and value not in [':',unspecified]: cal = self.getCalendar() value = cdtime.s2c(value, cal).torel(self.units, cal).value return value @@ -1022,7 +1022,7 @@ class AbstractAxis(CdmsObj): # # mf 20010419 test if attribute is a string (non CF), set to 360.0 # - if(type(cycle) == types.StringType): + if isnstance(cycle, basestring): cycle = 360.0 else: cycle = 360.0 @@ -1106,7 +1106,7 @@ class AbstractAxis(CdmsObj): # check length of indicator if overridden by user # - indicator = string.lower(indicator) + indicator = indicator.lower() if len(indicator)==2: indicator += 'n' if( ( len(indicator) != 3 ) or @@ -1530,24 +1530,24 @@ class Axis(AbstractAxis): length = len(node) # Allow key of form (slice(i,j),) etc. - if type(key) is types.TupleType and len(key)==1: + if isinstance(key, tuple) and len(key)==1: key = key[0] - if isinstance(key, (types.IntType, numpy.int,numpy.int32)): # x[i] + if isinstance(key, (int, numpy.int,numpy.int32)): # x[i] if key>=length: raise IndexError, 'index out of bounds' else: # Don't generate the entire array (if linear) just for one value return node.data[key%length] - elif type(key) is types.SliceType: # x[i:j:k] + elif isinstance(key, slice): # x[i:j:k] if self._data_ is None: self._data_ = node.getData() return self._data_[key.start:key.stop:key.step] - elif type(key) is types.EllipsisType: # x[...] + elif isinstance(key, Ellipsis.__class__): # x[...] if self._data_ is None: self._data_ = node.getData() return self._data_ - elif type(key) is types.TupleType: + elif isinstance(key, tuple): raise IndexError,'axis is one-dimensional' else: raise IndexError,'index must be an integer: %s'%`key` @@ -1597,9 +1597,9 @@ class Axis(AbstractAxis): def getCalendar(self): if hasattr(self,'calendar'): - calendar = string.lower(self.calendar) + calendar = self.calendar.lower() elif self.parent is not None and hasattr(self.parent, 'calendar'): - calendar = string.lower(self.parent.calendar) + calendar = self.parent.calendar.lower() else: calendar = None @@ -1781,7 +1781,7 @@ class FileAxis(AbstractAxis): if obj is not None: for attname in self._obj_.__dict__.keys(): attval = getattr(self._obj_,attname) - if type(attval)!=types.BuiltinFunctionType: + if not callable(attval): self.__dict__[attname] = attval att = self.attributes att[attname]=attval @@ -1879,29 +1879,29 @@ class FileAxis(AbstractAxis): if (self._obj_ is not None) and (self.parent._mode_!='r') and not (hasattr(self.parent,'format') and self.parent.format=="DRS"): # For negative strides, get the equivalent slice with positive stride, # then reverse the result. - if (type(key) is types.SliceType) and (key.step is not None) and key.step<0: + if (isinstance(key, slice) and (key.step is not None) and key.step<0: posslice = reverseSlice(key,len(self)) result = apply(self._obj_.getitem, (posslice,)) return result[::-1] else: - if isinstance(key, types.IntType) and key>=len(self): + if isinstance(key, int) and key>=len(self): raise IndexError, 'Index out of bounds: %d'%key - if type(key) is not types.TupleType: + if isinstance(key, tuple): key = (key,) return apply(self._obj_.getitem, key) if self._data_ is None: self._data_ = self.getData() length = len(self._data_) - if isinstance(key, types.IntType): # x[i] + if isinstance(key, int): # x[i] if key>=length: raise IndexError, 'index out of bounds' else: return self._data_[key%length] - elif type(key) is types.SliceType: # x[i:j:k] + elif isinstance(key, slice): # x[i:j:k] return self._data_[key.start:key.stop:key.step] - elif type(key) is types.EllipsisType: # x[...] + elif isinstance(key, Ellipsis.__class__): # x[...] return self._data_ - elif type(key) is types.TupleType: + elif isinstance(key, tuple): raise IndexError,'axis is one-dimensional' else: raise IndexError,'index must be an integer or slice: %s'%`key` @@ -2027,9 +2027,9 @@ class FileAxis(AbstractAxis): def getCalendar(self): if hasattr(self,'calendar'): - calendar = string.lower(self.calendar) + calendar = self.calendar.lower() elif self.parent is not None and hasattr(self.parent, 'calendar'): - calendar = string.lower(self.parent.calendar) + calendar = self.parent.calendar.lower() else: calendar = None @@ -2126,15 +2126,15 @@ def axisMatchIndex (axes, specifications=None, omit=None, order=None): """ if specifications is None: speclist = axes - elif isinstance(specifications, types.StringType): + elif isinstance(specifications, basestring): speclist = [specifications] - elif isinstance(specifications, types.ListType): + elif isinstance(specifications, list): speclist = specifications - elif isinstance(specifications, types.TupleType): + elif isinstance(specifications, tuple): speclist=list(specifications) - elif isinstance(specifications, types.IntType): + elif isinstance(specifications, int): speclist = [specifications] - elif isinstance(specifications, types.FunctionType): + elif callable(specifications): speclist = [specifications] else: # to allow arange, etc. speclist = list(numpy.ma.filled(specifications)) @@ -2142,7 +2142,7 @@ def axisMatchIndex (axes, specifications=None, omit=None, order=None): candidates = [] for i in range(len(axes)): for s in speclist: - if isinstance(s, types.IntType): + if isinstance(s, int): r = (s == i) else: r = axisMatches(axes[i], s) @@ -2155,15 +2155,15 @@ def axisMatchIndex (axes, specifications=None, omit=None, order=None): if omit is None: omitlist = [] - elif isinstance(omit, types.StringType): + elif isinstance(omit, basestring): omitlist = [omit] - elif isinstance(omit, types.ListType): + elif isinstance(omit, list): omitlist = omit - elif isinstance(omit, types.TupleType): + elif isinstance(omit, tuple): omitlist=list(omit) - elif isinstance(omit, types.IntType): + elif isinstance(omit, int): omitlist = [omit] - elif isinstance(omit, types.FunctionType): + elif callable(omit): omitlist = [omit] elif isinstance(omit, AbstractAxis): omitlist = [omit] @@ -2171,7 +2171,7 @@ def axisMatchIndex (axes, specifications=None, omit=None, order=None): raise CDMSError, 'Unknown type of omit specifier.' for s in omitlist: - if isinstance(s, types.IntType): + if isinstance(s, int): for i in range(len(candidates)): if axes[candidates[i]] is axes[s]: del candidates[i] @@ -2251,13 +2251,13 @@ def axisMatches(axis, specification): 3. an axis object; will match if it is the same object as axis. """ if isinstance(specification, basestring): - s = string.lower(specification) + s = specification.lower() s = s.strip() while s[0] == '(': if s[-1] != ')': raise CDMSError, 'Malformed axis spec, ' + specification s = s[1:-1].strip() - if string.lower(axis.id) == s: + if axis.id.lower() == s: return 1 elif (s == 'time') or (s in time_aliases): return axis.isTime() @@ -2272,7 +2272,7 @@ def axisMatches(axis, specification): else: return 0 - elif isinstance(specification, types.FunctionType): + elif callable(specification): r = specification(axis) if r: return 1 diff --git a/Packages/cdms2/Lib/internattr.py b/Packages/cdms2/Lib/internattr.py deleted file mode 100644 index ff6ebeb0c..000000000 --- a/Packages/cdms2/Lib/internattr.py +++ /dev/null @@ -1,157 +0,0 @@ -"InternalAttributes (implmentation class for CDMS)" -import types -import PropertiedClasses -_PCLASS = PropertiedClasses.PropertiedClass -class AttributeDict: - """An attribute dictionary.""" - def __init__ (self, owner): - self._owner = owner - - def __getitem__ (self, name): - if self.has_key(name): - return self._owner.__dict__[name] - else: - raise KeyError, "%s instance has no external attribute %s" % \ - (self._owner.__class__.__name__, name) - - def __setitem__ (self, name, value): - if self._owner.is_internal_attribute(name): - raise RuntimeError, 'Cannot set internal name in external attribute dictionary.' - self._owner.__dict__[name] = value - - def clear (self): - self._owner.__dict__.clear() - - def get (self, name, default=None): - if self.has_key(name): - return self._owner.__dict__[name] - else: - return default - - def has_key(self, name): - d = self._owner.__dict__ - if d.has_key(name) and not self._owner.is_internal_attribute(name): - return 1 - else: - return 0 - - def items (self): - result = [] - for name, value in self._owner.__dict__.items(): - if self._owner.is_internal_attribute(name): continue - result.append((name, value)) - return result - - def keys (self): - result = [] - for name in self._owner.__dict__.keys(): - if self._owner.is_internal_attribute(name): continue - result.append(name) - return result - - def update(self, d): - for name, value in d.items(): - if self._owner.is_internal_attribute(name): - raise RuntimeError, "Cannot update attribute dict with internal name" - self._owner.__dict__[name] = value - - def values (self): - result = [] - for name, value in self._owner.__dict__.items(): - if self._owner.is_internal_attribute(name): continue - result.append(value) - return result - - def __repr__(self): - return 'AttributeDict (' + \ - repr(self._owner.__dict__) + \ - ')' - - def __str__(self): - return str(self._owner.__dict__) - -class InternalAttributesClass (_PCLASS): - def _getattributes (self, name): - """Return a dictionary-like object of the non-internal attributes.""" - return AttributeDict(self) - - def is_internal_attribute (self, name): - """is_internal_attribute(name) is true if name is internal.""" - if name[0] == '_' or name in self.__class__._internal: - return 1 - return 0 - - def replace_external_attributes(self, newAttributes): - """replace_external_attributes(newAttributes) - Replace the external attributes with dictionary newAttributes. - """ - if not isinstance(newAttributes, types.DictType) and \ - not isinstance(newAttributes, AttributeDict): - raise ValueError, "Argument must be a dictionary" - for n in self.__dict__.keys(): - if not self.is_internal_attribute(n): - del self.__dict__[n] - for n, v in newAttributes.items(): - self.__dict__[n] = v - -def initialize_internal_attributes (C): - "Prepare a class for life as a child of InternalAttributesClass." - if C.__dict__.has_key('_internal'): return - if not issubclass(C, InternalAttributesClass): - raise ValueError, 'Must be subclass of InternalAttributesClass' - PropertiedClasses.initialize_property_class (C) - C._internal = [] - for CP in C.__bases__: - if issubclass(CP, InternalAttributesClass): - initialize_internal_attributes(CP) - for name in CP._internal: - C._internal.append(name) - -def add_internal_attribute (C, *aname): - """add_internal_attribute (C, name, ...) - Make attributes name, ... internal in class C. - """ - initialize_internal_attributes(C) - for name in aname: - if not name in C._internal: - C._internal.append(name) - -PropertiedClasses.set_property(InternalAttributesClass, 'attributes', - InternalAttributesClass._getattributes, - nowrite=1, nodelete=1) - -if __name__ == '__main__': - class Test(InternalAttributesClass): - def __init__ (self): - self.node = None - self.parent = None - self.__dict__['ro'] = 1 - self.__hide = 3 - self._p = 4 - self.value = 1 - - PropertiedClasses.set_property(Test, 'ro', nowrite=1, nodelete=1) - add_internal_attribute(Test, 'node', 'parent', 'ro') - - t1 = Test() - assert t1.value == 1 - assert not t1.attributes.has_key('__hide') - assert not t1.attributes.has_key('_p') - assert t1._p == 4 - t1.value = 2 - assert t1.value == 2 - assert 'value' in t1.attributes.keys() - t1.b = t1.value + 1 - assert t1.b == 3 - assert t1.b == t1.attributes['b'] - t1.node = 'me' - t1.parent = 'dad' - assert t1.node == 'me' - assert 'node' not in t1.attributes.keys() - assert t1.ro == 1 - try: - t1.ro == 2 - except AttributeError: - pass - assert t1.ro == 1 - print "Test passed." -- GitLab From d40cb17afc176ecc96b35b563a36b8c27966812e Mon Sep 17 00:00:00 2001 From: Charles Doutriaux Date: Tue, 26 Apr 2016 09:51:59 -0700 Subject: [PATCH 028/191] cleaned up cdmsNode --- Packages/cdms2/Lib/cdmsNode.py | 48 +++++++++++++++------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/Packages/cdms2/Lib/cdmsNode.py b/Packages/cdms2/Lib/cdmsNode.py index 794e4ed3b..5d82a9526 100644 --- a/Packages/cdms2/Lib/cdmsNode.py +++ b/Packages/cdms2/Lib/cdmsNode.py @@ -9,9 +9,7 @@ from numpy import get_printoptions, set_printoptions, inf import CDML import cdtime import re -import string import sys -from types import * from error import CDMSError # Regular expressions @@ -309,9 +307,9 @@ class CdmsNode: if (validAttrs and (attname in validAttrs)) or (not validAttrs): (attval,datatype)=self.attribute[attname] # attvalstr = _Illegal.sub(mapIllegalToEntity,str(attval)) # Map illegal chars to entities - if type(attval)!=StringType: + if not isinstance(attval, basestring): attval = `attval` - attvalstr = string.strip(attval) + attvalstr = attval.strip() attvalstr = re.sub('\n','\n ',attvalstr) # Make sure continuation lines are preceded with a space if attvalstr=='': attvalstr = "none" fd.write("%s: %s\n"%(attname,attvalstr)) @@ -320,7 +318,7 @@ class CdmsNode: for attname in self.attribute.keys(): if validAttrs and (attname not in validAttrs): (attval,datatype)=self.attribute[attname] - if type(attval)!=StringType: + if not isinstance(attval, basestring): attval = `attval` attval = re.sub('\n','\n ',attval) # Make sure continuation lines are preceded with a space fd.write("attr: %s=%s\n"%(attname,attval)) @@ -332,7 +330,7 @@ class CdmsNode: # fd.write("value: %s"%(content,)) # Write user attributes - if type(userAttrs)==StringType: + if isinstance(userAttrs, basestring): newAttrs = [userAttrs] else: newAttrs = userAttrs @@ -356,7 +354,7 @@ class CdmsNode: for attname in self.attribute.keys(): if attname in validKeys: (atttype,default)=self.dtd[attname] - if type(atttype) is TupleType: + if isinstance(atttype,tuple): attval=self.getExternalAttr(attname) assert attval in atttype, 'Invalid attribute %s=%s must be in %s'%(attname,attval,`atttype`) elif atttype==CDML.Idref: @@ -426,7 +424,7 @@ class VariableNode(CdmsNode): # Create a variable. # If validate is true, validate immediately def __init__(self, id, datatype, domain): - assert type(datatype) is StringType, 'Invalid datatype: '+`datatype` + assert isinstance(datatype,basestring), 'Invalid datatype: '+`datatype` assert datatype in CdDatatypes, 'Invalid datatype: '+`datatype` CdmsNode.__init__(self,"variable",id) self.datatype = datatype @@ -456,8 +454,8 @@ class AxisNode(CdmsNode): # If datatype is None, assume values [0,1,..,length-1] # data is a numpy array, if specified def __init__(self, id, length, datatype=CdLong,data=None): - assert isinstance(length, IntType), 'Invalid length: '+`length` - assert type(datatype) is StringType, 'Invalid datatype: '+`datatype` + assert isinstance(length, int), 'Invalid length: '+`length` + assert isinstance(datatype, basestring), 'Invalid datatype: '+`datatype` assert datatype in CdDatatypes, 'Invalid datatype: '+`datatype` if data is not None: assert isinstance(data, numpy.ndarray), 'data must be a 1-D Numeric array' CdmsNode.__init__(self,"axis",id) @@ -492,7 +490,7 @@ class AxisNode(CdmsNode): numlist = [] for numstring in stringlist: if numstring=='': continue - numlist.append(string.atof(numstring)) + numlist.append(float(numstring)) if len(numlist)>0: # NB! len(zero-length array) causes IndexError on Linux! dataArray = numpy.array(numlist,numericType) @@ -506,7 +504,7 @@ class AxisNode(CdmsNode): numlist = [] for numstring in stringlist: if numstring=='': continue - numlist.append(string.atoi(numstring)) + numlist.append(int(numstring)) dataArray = numpy.array(numlist,numpy.int) if len(dataArray)>0: self.partition = dataArray @@ -722,13 +720,13 @@ class AxisNode(CdmsNode): # Linear data element class LinearDataNode(CdmsNode): - validStartTypes = [IntType,FloatType,type(cdtime.comptime(0)),type(cdtime.reltime(0,"hours"))] - validDeltaTypes = [IntType,FloatType,ListType] + validStartTypes = [int, float, type(cdtime.comptime(0)), type(cdtime.reltime(0,"hours"))] + validDeltaTypes = [int, float, list] def __init__(self, start, delta, length): assert isinstance(start, numpy.floating) or isinstance(start, numpy.integer) or (type(start) in self.validStartTypes), 'Invalid start argument: '+`start` assert isinstance(start, numpy.floating) or isinstance(start, numpy.integer) or (type(delta) in self.validDeltaTypes), 'Invalid delta argument: '+`delta` - assert isinstance(length, IntType), 'Invalid length argument: '+`length` + assert isinstance(length, int), 'Invalid length argument: '+`length` CdmsNode.__init__(self,"linear") self.delta = delta self.length = length @@ -932,12 +930,8 @@ class AttrNode(CdmsNode): def __init__(self, name, value=None): CdmsNode.__init__(self,"attr") - if not (isinstance(value,IntType) - or isinstance(value,numpy.integer) - or isinstance(value,FloatType) - or isinstance(value,numpy.floating) - or isinstance(value,StringType) - or isinstance(value,NoneType)): + if not (isinstance(value,(int, numpy.integer, float, numpy.floating, basestring)) \ + or value is None: raise CDMSError, 'Invalid attribute type: '+`value` self.name = name self.value = value @@ -954,11 +948,11 @@ class AttrNode(CdmsNode): def getDatatype(self): if self.datatype: return self.datatype - elif type(self.value) is StringType: + elif isinstance(self.value, basestring): return CdString - elif isinstance(self.value, FloatType) or isinstance(self.value,numpy.floating): + elif isinstance(self.value, (float,numpy.floating)): return CdDouble - elif isinstance(self.value, IntType) or isinstance(self.value,numpy.integer): + elif isinstance(self.value, (int, numpy.integer)): return CdLong else: raise CDMSError, 'Invalid attribute type: '+`self.value` @@ -970,18 +964,18 @@ class AttrNode(CdmsNode): # Returns ValueError if the conversion fails def setValueFromString(self,valString,datatype): val = None - if type(valString) is not StringType: + if not isinstance(valString, basestring): raise CDMSError, 'input value is not a string' if datatype == CdString: val=valString elif datatype in (CdShort,CdInt,CdLong): try: - val=string.atoi(valString) + val=int(valString) except ValueError: raise CDMSError, 'value is not an integer: '+valString elif datatype in (CdFloat,CdDouble): try: - val=string.atof(valString) + val=float(valString) except ValueError: raise CDMSError, 'value is not floating-point: '+valString self.value=val -- GitLab From bf68e04105ca4367cbd048732fa6ecd26b531732 Mon Sep 17 00:00:00 2001 From: Charles Doutriaux Date: Tue, 26 Apr 2016 09:54:00 -0700 Subject: [PATCH 029/191] cleaned up coord --- Packages/cdms2/Lib/coord.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Packages/cdms2/Lib/coord.py b/Packages/cdms2/Lib/coord.py index 6f7773fd1..8460485e6 100644 --- a/Packages/cdms2/Lib/coord.py +++ b/Packages/cdms2/Lib/coord.py @@ -10,8 +10,6 @@ import cdtime import copy import numpy #import internattr -import types -import string from cdmsobj import CdmsObj from axis import createAxis, TransientVirtualAxis from error import CDMSError @@ -118,7 +116,7 @@ class AbstractCoordinateAxis(CdmsObj): # calendar. def getCalendar(self): if hasattr(self,'calendar'): - calendar = string.lower(self.calendar) + calendar = self.calendar.lower() else: calendar = None @@ -147,7 +145,7 @@ class AbstractCoordinateAxis(CdmsObj): # Return true iff the axis is a level axis def isLevel(self): - id = string.lower(self.id) + id = self.id.lower() if (hasattr(self,'axis') and self.axis=='Z'): return 1 return ((id[0:3] == 'lev') or (id[0:5] == 'depth') or (id in level_aliases)) @@ -158,13 +156,13 @@ class AbstractCoordinateAxis(CdmsObj): # Return true iff the axis is a time axis def isTime(self): - id = string.lower(self.id) + id = self.id.lower() if (hasattr(self,'axis') and self.axis=='T'): return 1 return (id[0:4] == 'time') or (id in time_aliases) # Return true iff the axis is a forecast axis def isForecast(self): - id = string.lower(self.id) + id = self.id.lower() if (hasattr(self,'axis') and self.axis=='F'): return 1 return (id[0:6] == 'fctau0') or (id in forecast_aliases) -- GitLab From f570c2cf6112133f777fd6073769814c99b2b5e1 Mon Sep 17 00:00:00 2001 From: Charles Doutriaux Date: Tue, 26 Apr 2016 11:23:01 -0700 Subject: [PATCH 030/191] cleaned up all (most?) files --- Packages/cdms2/Lib/cudsinterface.py | 6 +++--- Packages/cdms2/Lib/database.py | 8 +++----- Packages/cdms2/Lib/dataset.py | 19 +++++++++---------- Packages/cdms2/Lib/fvariable.py | 1 - Packages/cdms2/Lib/grid.py | 5 ++--- Packages/cdms2/Lib/gsStaticVariable.py | 1 - Packages/cdms2/Lib/mvCdmsRegrid.py | 3 +-- Packages/cdms2/Lib/mvSphereMesh.py | 11 +++++------ Packages/cdms2/Lib/selectors.py | 4 ++-- Packages/cdms2/Lib/slabinterface.py | 6 +++--- Packages/cdms2/Lib/tvariable.py | 9 ++++----- Packages/cdms2/Lib/variable.py | 1 - 12 files changed, 32 insertions(+), 42 deletions(-) diff --git a/Packages/cdms2/Lib/cudsinterface.py b/Packages/cdms2/Lib/cudsinterface.py index c97f5fdef..4232bdf44 100644 --- a/Packages/cdms2/Lib/cudsinterface.py +++ b/Packages/cdms2/Lib/cudsinterface.py @@ -2,7 +2,7 @@ ## Further modified to be pure new numpy June 24th 2008 "Emulation of old cu package" -import string, types, sys +import sys from error import CDMSError from dataset import openDataset, createDataset from tvariable import createVariable @@ -215,7 +215,7 @@ class cuDataset(): if device is None: device=sys.stdout if vname is None: vname = self.default_variable_name alist = self.listall(vname, all=all) - device.write(string.join(alist, "\n")) + device.write("\n".join(alist)) device.write("\n") def dimensionobject (self, dname, vname=None): @@ -357,7 +357,7 @@ class cuDataset(): idim = ndims - (nargs - i - 1) i = i + 1 ne = 1 - elif type(x) == types.TupleType: + elif isinstance(x,tuple): cdms_args[idim] = x idim = idim + 1 i = i + 1 diff --git a/Packages/cdms2/Lib/database.py b/Packages/cdms2/Lib/database.py index 80f749fb4..ac8b0dc7a 100644 --- a/Packages/cdms2/Lib/database.py +++ b/Packages/cdms2/Lib/database.py @@ -7,9 +7,7 @@ import cdurlparse import copy import os import re -import string import sys -import types from CDMLParser import CDMLParser from cdmsobj import CdmsObj from dataset import Dataset @@ -205,7 +203,7 @@ class LDAPDatabase(AbstractDatabase): def normalizedn(self, dn): explodeddn = ldap.explode_dn(dn) - return string.join(explodeddn,',') + return ','.join(explodeddn) def cachecdml(self, name, cdml, datapath): normaldn = self.normalizedn(name) @@ -239,7 +237,7 @@ class LDAPDatabase(AbstractDatabase): # Get the parent dataset explodeddn = ldap.explode_dn(dn) - dsetdn = string.join(explodeddn[1:],',') # Dataset node is parent of variable + dsetdn = ','.join(explodeddn[1:]) # Dataset node is parent of variable dset = self.getDataset(dsetdn) rdn = explodeddn[0] matchobj = _Att.match(rdn) @@ -468,7 +466,7 @@ class LDAPSearchResult(AbstractSearchResult): """ if tag is not None: - tag = string.lower(tag) + tag = tag.lower() resultlist = [] for entry in self: diff --git a/Packages/cdms2/Lib/dataset.py b/Packages/cdms2/Lib/dataset.py index 977b1d8bb..6074615de 100644 --- a/Packages/cdms2/Lib/dataset.py +++ b/Packages/cdms2/Lib/dataset.py @@ -7,7 +7,6 @@ import Cdunif import numpy import cdmsNode import os, sys -import string import urllib import cdmsURLopener # Import after urllib, to handle errors import urlparse @@ -280,7 +279,7 @@ Output::: file :: (cdms2.dataset.CdmsFile) (0) file to read from ::: """ - uri = string.strip(uri) + uri = uri.strip() (scheme,netloc,path,parameters,query,fragment)=urlparse.urlparse(uri) if scheme in ('','file'): if netloc: @@ -417,7 +416,7 @@ def parseIndexList(text): for i in range(nindices): s = m.group(i+1) if s!='-': - result[i] = string.atoi(s) + result[i] = int(s) result[nindices] = m.group(nindices+1) return result, m.end() @@ -744,7 +743,7 @@ class Dataset(CdmsObj, cuDataset): def searchPattern(self,pattern,attribute,tag): resultlist = [] if tag is not None: - tag = string.lower(tag) + tag = tag.lower() if tag in ('dataset',None): if self.searchone(pattern,attribute)==1: resultlist = [self] @@ -769,7 +768,7 @@ class Dataset(CdmsObj, cuDataset): def matchPattern(self,pattern,attribute,tag): resultlist = [] if tag is not None: - tag = string.lower(tag) + tag = tag.lower() if tag in ('dataset',None): if self.matchone(pattern,attribute)==1: resultlist = [self] @@ -797,7 +796,7 @@ class Dataset(CdmsObj, cuDataset): def searchPredicate(self,predicate,tag): resultlist = [] if tag is not None: - tag = string.lower(tag) + tag = tag.lower() if tag in ('dataset',None): try: if apply(predicate,(self,))==1: @@ -1548,7 +1547,7 @@ class CdmsFile(CdmsObj, cuDataset): """ resultlist = [] if tag is not None: - tag = string.lower(tag) + tag = tag.lower() if tag in ('cdmsFile',None,'dataset'): if self.searchone(pattern,attribute)==1: resultlist = [self] @@ -1585,7 +1584,7 @@ class CdmsFile(CdmsObj, cuDataset): """ resultlist = [] if tag is not None: - tag = string.lower(tag) + tag = tag.lower() if tag in ('cdmsFile',None,'dataset'): if self.matchone(pattern,attribute)==1: resultlist = [self] @@ -1624,7 +1623,7 @@ class CdmsFile(CdmsObj, cuDataset): """ resultlist = [] if tag is not None: - tag = string.lower(tag) + tag = tag.lower() if tag in ('cdmsFile',None,'dataset'): try: if apply(predicate,(self,))==1: @@ -2017,7 +2016,7 @@ class CdmsFile(CdmsObj, cuDataset): def __repr__(self): filerep = `self._file_` - loc = string.find(filerep,"file") + loc = filerep.find("file") if loc==-1: loc=0 return ""%self._status_ diff --git a/Packages/cdms2/Lib/fvariable.py b/Packages/cdms2/Lib/fvariable.py index 4271e12c6..6ca32df15 100644 --- a/Packages/cdms2/Lib/fvariable.py +++ b/Packages/cdms2/Lib/fvariable.py @@ -4,7 +4,6 @@ "CDMS File-based variables." import numpy import typeconv -import types import re from cdmsobj import Max32int diff --git a/Packages/cdms2/Lib/grid.py b/Packages/cdms2/Lib/grid.py index f11ca1764..05fdf9b7c 100644 --- a/Packages/cdms2/Lib/grid.py +++ b/Packages/cdms2/Lib/grid.py @@ -2,7 +2,6 @@ ## Further modified to be pure new numpy June 24th 2008 """CDMS Grid objects""" -import types import re from error import CDMSError import numpy #, PropertiedClasses, internattr @@ -129,14 +128,14 @@ def setRegionSpecs(grid, coordSpec, coordType, resultSpec): if (coordSpec is None) or (coordSpec==':'): canonSpec = None - elif type(coordSpec) is types.TupleType: + elif isinstance(coordSpec, tuple): if len(coordSpec)==2: canonSpec = (coordSpec[0],coordSpec[1],'cc',None) elif len(coordSpec)==3: canonSpec = (coordSpec[0],coordSpec[1],coordSpec[2],None) elif len(coordSpec)!=4: raise CDMSError, 'Invalid coordinate specification: %s'%`coordSpec` - elif type(coordSpec) in [types.IntType, types.FloatType]: + elif isinstance(coordSpec, (int, float)): canonSpec = (coordSpec, coordSpec, 'cc', None) else: raise CDMSError, 'Invalid coordinate specification: %s'%`coordSpec` diff --git a/Packages/cdms2/Lib/gsStaticVariable.py b/Packages/cdms2/Lib/gsStaticVariable.py index 0332e1415..fdd740c86 100644 --- a/Packages/cdms2/Lib/gsStaticVariable.py +++ b/Packages/cdms2/Lib/gsStaticVariable.py @@ -9,7 +9,6 @@ No guarantee is provided whatsoever. Use at your own risk. import operator import cdms2 -import types from cdms2.error import CDMSError from cdms2.hgrid import AbstractCurveGrid, TransientCurveGrid, FileCurveGrid from cdms2.coord import TransientAxis2D, TransientVirtualAxis diff --git a/Packages/cdms2/Lib/mvCdmsRegrid.py b/Packages/cdms2/Lib/mvCdmsRegrid.py index 6cc0adf8a..5a1f34361 100644 --- a/Packages/cdms2/Lib/mvCdmsRegrid.py +++ b/Packages/cdms2/Lib/mvCdmsRegrid.py @@ -5,7 +5,6 @@ David Kindig and Alex Pletzer, Tech-X Corp. (2012) This code is provided with the hope that it will be useful. No guarantee is provided whatsoever. Use at your own risk. """ -import types import operator import re import numpy @@ -450,7 +449,7 @@ coordMin = %7.2f, boundMin = %7.2f, coordMax = %7.2f, boundMax = %7.2f attrs = {} for a in srcVar.attributes: v = srcVar.attributes[a] - if type(v) is types.StringType: + if isinstance(v, basestring): attrs[a] = v # if the missing value is present in the destination data, set diff --git a/Packages/cdms2/Lib/mvSphereMesh.py b/Packages/cdms2/Lib/mvSphereMesh.py index 2d4b7abad..7b95922e2 100644 --- a/Packages/cdms2/Lib/mvSphereMesh.py +++ b/Packages/cdms2/Lib/mvSphereMesh.py @@ -8,7 +8,6 @@ No guarantee is provided whatsoever. Use at your own risk. """ import numpy -from types import NoneType class SphereMesh: @@ -34,7 +33,7 @@ class SphereMesh: # compute the min/max of elevation, needed # for normalization - if type(elvs) != NoneType: + if elvs is not None: self.minElv = min(elvs[:]) self.maxElv = max(elvs[:]) if hasattr(elvs, 'positive'): @@ -44,7 +43,7 @@ class SphereMesh: # determine the dimensionality and # whether the grid is rectilinear for axis in lons, lats, elvs: - if type(axis) != NoneType: + if axis is not None: self.ndims += 1 if len(axis.shape) != 1: self.isRectilinear = False @@ -53,7 +52,7 @@ class SphereMesh: if self.isRectilinear: self.shape = [] for axis in lons, lats, elvs: - if type(axis) != NoneType: + if axis is not None: self.shape.append( len(axis) ) self.shape.reverse() @@ -63,7 +62,7 @@ class SphereMesh: # store lon, lat, elv as a curvilinear grid if self.isRectilinear: # apply tensore product of axes to generat curvilinear coordinates - if type(elvs) != NoneType: + if elvs is not None: self.elvs = numpy.outer(numpy.outer( numpy.ones(self.shape[:0], numpy.float32), elvs), numpy.ones(self.shape[0+1:], numpy.float32)).reshape(self.shape) else: @@ -77,7 +76,7 @@ class SphereMesh: # already in curvilinear form self.lons = lons[:] self.lats = lats[:] - if type(elvs) != NoneType: + if elvs is not None: self.elvs = elvs[:] else: self.elvs = numpy.zeros( self.shape, numpy.float32 ) diff --git a/Packages/cdms2/Lib/selectors.py b/Packages/cdms2/Lib/selectors.py index b2ee04bc6..f22443976 100644 --- a/Packages/cdms2/Lib/selectors.py +++ b/Packages/cdms2/Lib/selectors.py @@ -1,6 +1,6 @@ """Classes to support easy selection of climate data""" -import string, types, cdtime +import cdtime from axis import axisMatches from error import CDMSError from grid import AbstractRectGrid, defaultRegion, setRegionSpecs, LongitudeType, LatitudeType, TimeType, VerticalType @@ -393,7 +393,7 @@ def required(values): """Creates a selector that requires a certain axis to be present.""" if values is None: return all - if isinstance(values, types.StringType): + if isinstance(values, basestring): values = (values,) return Selector(requiredComponent(values)) diff --git a/Packages/cdms2/Lib/slabinterface.py b/Packages/cdms2/Lib/slabinterface.py index e08b49ea5..642aea131 100644 --- a/Packages/cdms2/Lib/slabinterface.py +++ b/Packages/cdms2/Lib/slabinterface.py @@ -3,7 +3,7 @@ "Read part of the old cu slab interface implemented over CDMS" import numpy -import string, types, sys +import sys from error import CDMSError from axis import std_axis_attributes import cdms2 as cdms @@ -143,7 +143,7 @@ class Slab: for nd in range(self.rank()): result.append('** Dimension ' + str(nd+1) + ' **') result = result + self.getAxis(nd).listall(1) - print string.join(result, '\n') + print '\n'.join(result) def listdimnames(self): "Return a list of the names of the dimensions." @@ -179,7 +179,7 @@ class Slab: def info(self, flag=None, device=None): "Write info about slab; include dimension values and weights if flag" if device is None: device = sys.stdout - device.write(string.join(self.listall(all=flag), "\n")) + device.write('\n'.join(self.listall(all=flag))) device.write("\n") def cdms_bounds2cu_bounds (b): diff --git a/Packages/cdms2/Lib/tvariable.py b/Packages/cdms2/Lib/tvariable.py index 27cab8156..7d9db8b9d 100644 --- a/Packages/cdms2/Lib/tvariable.py +++ b/Packages/cdms2/Lib/tvariable.py @@ -8,7 +8,6 @@ Contains also the write part of the old cu interface. """ import json import re -import types import typeconv import numpy from numpy import sctype2char @@ -166,7 +165,7 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): if dtype is None and typecode is not None: dtype = typeconv.convtypecode2(typecode) typecode = sctype2char(dtype) - if type(data) is types.TupleType: + if isinstance(data, tuple): data = list(data) AbstractVariable.__init__ (self) @@ -252,7 +251,7 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): if dtype is None and typecode is not None: dtype = typeconv.convtypecode2(typecode) typecode = sctype2char(dtype) - if type(data) is types.TupleType: + if isinstance(data, tuple): data = list(data) if isinstance(data, AbstractVariable): if not isinstance(data, TransientVariable): @@ -479,7 +478,7 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): raise CDMSError, "setdimattribute, dim out of bounds." d = self.getAxis(dim) if field == "name": - if not type(value) == types.StringType: + if not isinstance(value, basestring): raise CDMSError, "setdimattribute: name not a string" d.id = value @@ -492,7 +491,7 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): self.setAxis(dim, a) elif field == "units": - if not type(value) == types.StringType: + if not isinstance(value, basestring): raise CDMSError, "setdimattribute: units not a string" d.units = value diff --git a/Packages/cdms2/Lib/variable.py b/Packages/cdms2/Lib/variable.py index a1f3f7f7d..396dbdf06 100644 --- a/Packages/cdms2/Lib/variable.py +++ b/Packages/cdms2/Lib/variable.py @@ -11,7 +11,6 @@ import copy import os import string import sys -import types import cdmsobj from cdmsobj import CdmsObj, getPathFromTemplate, Max32int from avariable import AbstractVariable -- GitLab From 05e2675ee1e395a89b18dd6afa713e5d08535aa4 Mon Sep 17 00:00:00 2001 From: Charles Doutriaux Date: Tue, 26 Apr 2016 11:39:47 -0700 Subject: [PATCH 031/191] removed string odule wheen possible --- Packages/cdms2/Lib/CDMLParser.py | 15 +++++++-------- Packages/cdms2/Lib/cdxmllib.py | 1 - Packages/cdms2/Lib/convention.py | 27 +++++++++++++-------------- Packages/cdms2/Lib/gengrid.py | 9 ++++----- Packages/cdms2/Lib/hgrid.py | 9 ++++----- Packages/cdms2/Lib/variable.py | 5 ++--- 6 files changed, 30 insertions(+), 36 deletions(-) diff --git a/Packages/cdms2/Lib/CDMLParser.py b/Packages/cdms2/Lib/CDMLParser.py index 1ff9abc56..e741e44d2 100644 --- a/Packages/cdms2/Lib/CDMLParser.py +++ b/Packages/cdms2/Lib/CDMLParser.py @@ -6,7 +6,6 @@ from cdxmllib import XMLParser import CDML import re import cdmsNode -import string # Error constants InvalidAttribute = "Invalid attribute" @@ -52,7 +51,7 @@ class CDMLParser(XMLParser): if not matchObj: if self.verbose: print 'data:',data if self.root: - self.getCurrentNode().setContentFromString(string.strip(data)) + self.getCurrentNode().setContentFromString(data.strip()) def handle_cdata(self, data): if self.verbose: print 'cdata:', `data` @@ -125,7 +124,7 @@ class CDMLParser(XMLParser): datatype = attrs.get('datatype') if _Integer.match(length_s) is None: raise InvalidAttribute, 'length='+length_s - length = string.atoi(length_s) + length = int(length_s) axis = cdmsNode.AxisNode(id,length,datatype) partstring = attrs.get('partition') if partstring is not None: @@ -202,11 +201,11 @@ class CDMLParser(XMLParser): start_s = attrs.get('start') length_s = attrs.get('length') if start_s is not None: - start = string.atoi(start_s) + start = int(start_s) else: start = None if length_s is not None: - length = string.atoi(length_s) + length = int(length_s) else: length = None domElem = cdmsNode.DomElemNode(name,start,length) @@ -250,15 +249,15 @@ class CDMLParser(XMLParser): delta_s = attrs['delta'] length_s = attrs['length'] try: - start=string.atof(start_s) + start=float(start_s) except ValueError: raise InvalidAttribute, 'start='+start_s try: - delta=string.atof(delta_s) + delta=float(delta_s) except ValueError: raise InvalidAttribute, 'delta='+delta_s try: - length=string.atoi(length_s) + length=int(length_s) except ValueError: raise InvalidAttribute, 'length='+length_s linear = cdmsNode.LinearDataNode(start,delta,length) diff --git a/Packages/cdms2/Lib/cdxmllib.py b/Packages/cdms2/Lib/cdxmllib.py index baa0f6dfb..7c1aff308 100644 --- a/Packages/cdms2/Lib/cdxmllib.py +++ b/Packages/cdms2/Lib/cdxmllib.py @@ -3,7 +3,6 @@ # Author: Sjoerd Mullender. import re -import string # import warnings # warnings.warn("The xmllib module is obsolete. Use xml.sax instead.", diff --git a/Packages/cdms2/Lib/convention.py b/Packages/cdms2/Lib/convention.py index 4e8c9053e..0ed475877 100644 --- a/Packages/cdms2/Lib/convention.py +++ b/Packages/cdms2/Lib/convention.py @@ -1,6 +1,5 @@ """ metadata conventions """ -import string from error import CDMSError from UserList import UserList @@ -13,11 +12,11 @@ class AliasList (UserList): def __init__(self, alist): UserList.__init__(self,alist) def __setitem__ (self, i, value): - self.data[i] = string.lower(value) + self.data[i] = value.lower() def __setslice(self, i, j, values): - self.data[i:j] = map(lambda x: string.lower(x), values) + self.data[i:j] = map(lambda x: x.lower(), values) def append(self, value): - self.data.append(string.lower(value)) + self.data.append(value.lower()) level_aliases = AliasList(['plev']) longitude_aliases = AliasList([]) @@ -37,11 +36,11 @@ class AbstractConvention: raise CDMSError, MethodNotImplemented def axisIsLatitude(self, axis): - id = string.lower(axis.id) + id = axis.id.lower() return (id[0:3] == 'lat') or (id in latitude_aliases) def axisIsLongitude(self, axis): - id = string.lower(axis.id) + id = axis.id.lower() return (id[0:3] == 'lon') or (id in longitude_aliases) def getVarLatId(self, var, vardict=None): @@ -99,7 +98,7 @@ class CFConvention(COARDSConvention): coorddict = {} for var in vardict.values(): if hasattr(var, 'coordinates'): - coordnames = string.split(var.coordinates) + coordnames = var.coordinates.lower() for item in coordnames: # Don't include if already a 1D coordinate axis. if item in axiskeys: @@ -127,7 +126,7 @@ class CFConvention(COARDSConvention): for node in dsetdict.values(): coordnames = node.getExternalAttr('coordinates') if coordnames is not None: - coordnames = string.split(coordnames) + coordnames = coordnames.split() for item in coordnames: # Don't include if already a 1D coordinate axis. if dsetdict.has_key(item) and dsetdict[item].tag=='axis': @@ -149,7 +148,7 @@ class CFConvention(COARDSConvention): return (lat, nlat) if hasattr(var, 'coordinates'): - coordnames = string.split(var.coordinates) + coordnames = var.coordinates.split() for name in coordnames: coord = vardict.get(name) @@ -173,7 +172,7 @@ class CFConvention(COARDSConvention): return (lon, nlon) if hasattr(var, 'coordinates'): - coordnames = string.split(var.coordinates) + coordnames = var.coordinates.split() for name in coordnames: coord = vardict.get(name) @@ -191,9 +190,9 @@ class CFConvention(COARDSConvention): def axisIsLatitude(self, axis): if (hasattr(axis,'axis') and axis.axis=='Y'): return 1 - elif (hasattr(axis, 'units') and string.lower(axis.units) in ['degrees_north', 'degree_north', 'degree_n', 'degrees_n', 'degreen', 'degreesn']): + elif (hasattr(axis, 'units') and axis.units.lower() in ['degrees_north', 'degree_north', 'degree_n', 'degrees_n', 'degreen', 'degreesn']): return 1 - elif (hasattr(axis, 'standard_name') and string.lower(axis.standard_name)=='latitude'): + elif (hasattr(axis, 'standard_name') and axis.standard_name.lower()=='latitude'): return 1 else: return AbstractConvention.axisIsLatitude(self, axis) @@ -201,9 +200,9 @@ class CFConvention(COARDSConvention): def axisIsLongitude(self, axis): if (hasattr(axis,'axis') and axis.axis=='X'): return 1 - elif (hasattr(axis, 'units') and string.lower(axis.units) in ['degrees_east', 'degree_east', 'degree_e', 'degrees_e', 'degreee', 'degreese']): + elif (hasattr(axis, 'units') and axis.units.lower() in ['degrees_east', 'degree_east', 'degree_e', 'degrees_e', 'degreee', 'degreese']): return 1 - elif (hasattr(axis, 'standard_name') and string.lower(axis.standard_name)=='longitude'): + elif (hasattr(axis, 'standard_name') and axis.standard_name.lower()=='longitude'): return 1 else: return AbstractConvention.axisIsLongitude(self, axis) diff --git a/Packages/cdms2/Lib/gengrid.py b/Packages/cdms2/Lib/gengrid.py index 1204733bc..95e6d1871 100644 --- a/Packages/cdms2/Lib/gengrid.py +++ b/Packages/cdms2/Lib/gengrid.py @@ -338,7 +338,6 @@ def readScripGenericGrid(fileobj, dims, whichType, whichGrid): whichType is the type of file, either "grid" or "mapping" if whichType is "mapping", whichGrid is the choice of grid, either "source" or "destination" """ - import string from auxcoord import TransientAuxAxis1D from coord import TransientVirtualAxis @@ -400,7 +399,7 @@ def readScripGenericGrid(fileobj, dims, whichType, whichGrid): ni = dims[0] boundsshape = (ni, ncorners) - if hasattr(cornerLat, 'units') and string.lower(cornerLat.units)[0:6]=='radian': + if hasattr(cornerLat, 'units') and cornerLat.units.lower()[0:6]=='radian': cornerLat = (cornerLat*(180.0/numpy.pi)).reshape(boundsshape) cornerLon = (cornerLon*(180.0/numpy.pi)).reshape(boundsshape) @@ -415,21 +414,21 @@ def readScripGenericGrid(fileobj, dims, whichType, whichGrid): if vardict.has_key(gridCenterLatName): centerLat = fileobj(gridCenterLatName) - if hasattr(centerLat, "units") and string.lower(centerLat.units)=='radians': + if hasattr(centerLat, "units") and centerLat.units.lower()=='radians': centerLat *= (180.0/numpy.pi) else: centerLat = cornerLat[:,:,0] if vardict.has_key(gridCenterLonName): centerLon = fileobj(gridCenterLonName) - if hasattr(centerLon, "units") and string.lower(centerLon.units)=='radians': + if hasattr(centerLon, "units") and centerLon.units.lower()=='radians': centerLon *= (180.0/numpy.pi) else: centerLon = cornerLon[:,:,0] if hasattr(fileobj,titleName): gridid = getattr(fileobj, titleName) - gridid = string.replace(string.strip(gridid), ' ','_') + gridid = sgridid.strip().replace(' ','_') else: gridid="" diff --git a/Packages/cdms2/Lib/hgrid.py b/Packages/cdms2/Lib/hgrid.py index 56758ad72..1f53d3702 100644 --- a/Packages/cdms2/Lib/hgrid.py +++ b/Packages/cdms2/Lib/hgrid.py @@ -758,7 +758,6 @@ def readScripCurveGrid(fileobj, dims, whichType, whichGrid): whichType is the type of file, either "grid" or "mapping" if whichType is "mapping", whichGrid is the choice of grid, either "source" or "destination" """ - import string from coord import TransientAxis2D if 'S' in fileobj.variables.keys(): @@ -814,7 +813,7 @@ def readScripCurveGrid(fileobj, dims, whichType, whichGrid): nj = dims[0] gridshape = (ni, nj) boundsshape = (ni, nj, ncorners) - if hasattr(cornerLat, 'units') and string.lower(cornerLat.units)[0:6]=='radian': + if hasattr(cornerLat, 'units') and cornerLat.units.lower()[0:6]=='radian': cornerLat = (cornerLat*(180.0/numpy.pi)).reshape(boundsshape) cornerLon = (cornerLon*(180.0/numpy.pi)).reshape(boundsshape) else: @@ -835,7 +834,7 @@ def readScripCurveGrid(fileobj, dims, whichType, whichGrid): if vardict.has_key(gridCenterLatName): centerLat = fileobj(gridCenterLatName).reshape(gridshape) gclat = fileobj[gridCenterLatName] - if hasattr(gclat, "units") and string.lower(gclat.units)=='radians': + if hasattr(gclat, "units") and gclat.units.lower()=='radians': centerLat *= (180.0/numpy.pi) else: centerLat = cornerLat[:,:,0] @@ -843,14 +842,14 @@ def readScripCurveGrid(fileobj, dims, whichType, whichGrid): if vardict.has_key(gridCenterLonName): centerLon = fileobj(gridCenterLonName).reshape(gridshape) gclon = fileobj[gridCenterLonName] - if hasattr(gclon, "units") and string.lower(gclon.units)=='radians': + if hasattr(gclon, "units") and gclon.units.lower()=='radians': centerLon *= (180.0/numpy.pi) else: centerLon = cornerLon[:,:,0] if hasattr(fileobj,titleName): gridid = getattr(fileobj, titleName) - gridid = string.replace(string.strip(gridid), ' ','_') + gridid = gridid.strip().replace(' ','_') else: gridid="" diff --git a/Packages/cdms2/Lib/variable.py b/Packages/cdms2/Lib/variable.py index 396dbdf06..23650e3d8 100644 --- a/Packages/cdms2/Lib/variable.py +++ b/Packages/cdms2/Lib/variable.py @@ -9,7 +9,6 @@ import cdmsNode import cdtime import copy import os -import string import sys import cdmsobj from cdmsobj import CdmsObj, getPathFromTemplate, Max32int @@ -139,7 +138,7 @@ class DatasetVariable(AbstractVariable): raise CDMSError, InvalidGridElement + dename partlenstr = denode.getExternalAttr('partition_length') if partlenstr is not None: - truelen = string.atoi(partlenstr) + truelen = int(partlenstr) else: truelen = denode.length self.domain.append((domelem, denode.start, denode.length, truelen)) @@ -224,7 +223,7 @@ class DatasetVariable(AbstractVariable): else: # Use template method time0 = axis[interval[0]] time1 = axis[interval[1]-1] - isabs = (string.find(axis.units," as ")!=-1) + isabs = (axis.units.find(" as ")!=-1) if isabs: start = cdtime.abstime(time0,axis.units) end = cdtime.abstime(time1,axis.units) -- GitLab From 0bc3f4d47b9c21175d4cfa651640f92a4c6215d2 Mon Sep 17 00:00:00 2001 From: Dan Lipsa Date: Thu, 21 Apr 2016 11:52:28 -0400 Subject: [PATCH 032/191] ENH #1854: Tests will check for alternate baselines using basename_[1-9].ext Previously the pattern used was baseline.*\.ext --- testing/checkimage.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/testing/checkimage.py b/testing/checkimage.py index e0ad9db82..9871f3557 100644 --- a/testing/checkimage.py +++ b/testing/checkimage.py @@ -9,6 +9,7 @@ import numpy import vtk import os import os.path +import re import sys import logging @@ -40,13 +41,15 @@ def image_from_file(fname): print "Problem opening file '%s': %s"%(fname,err) return None +# find alternate baselines for fname of the form basename_d.ext +# where fname = basename.ext and d is a digit between 1 and 9 def find_alternates(fname): dirname = os.path.dirname(fname) prefix, ext = os.path.splitext(os.path.split(fname)[1]) files = os.listdir(dirname) results = [fname] for i in files: - if i.startswith(prefix) and i.endswith(ext) and i != prefix+ext: + if (re.match(prefix + '_[1-9]' + ext, i)): results.append(os.path.join(dirname, i)) return results -- GitLab From 2bc8a27233063bbca4c0c5ec23d8e3a4894cfd19 Mon Sep 17 00:00:00 2001 From: Charles Doutriaux Date: Tue, 26 Apr 2016 14:34:37 -0700 Subject: [PATCH 033/191] moved cdscan to lib dir so that we can import it --- Packages/cdms2/{Script/cdscan => Lib/cdscan.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Packages/cdms2/{Script/cdscan => Lib/cdscan.py} (100%) diff --git a/Packages/cdms2/Script/cdscan b/Packages/cdms2/Lib/cdscan.py similarity index 100% rename from Packages/cdms2/Script/cdscan rename to Packages/cdms2/Lib/cdscan.py -- GitLab From 50a55c122e0509915a91a7b525359dffc9475ba5 Mon Sep 17 00:00:00 2001 From: Charles Doutriaux Date: Tue, 26 Apr 2016 14:37:29 -0700 Subject: [PATCH 034/191] symlinked cdscan so that script is still installed --- Packages/cdms2/Script/cdscan | 1 + 1 file changed, 1 insertion(+) create mode 120000 Packages/cdms2/Script/cdscan diff --git a/Packages/cdms2/Script/cdscan b/Packages/cdms2/Script/cdscan new file mode 120000 index 000000000..11d1e0bf9 --- /dev/null +++ b/Packages/cdms2/Script/cdscan @@ -0,0 +1 @@ +../Lib/cdscan.py \ No newline at end of file -- GitLab From d5a9a226ca5fafb65e95fa793cf8144a349adbe3 Mon Sep 17 00:00:00 2001 From: Charles Doutriaux Date: Wed, 27 Apr 2016 08:46:49 -0700 Subject: [PATCH 035/191] Address @danlipsa comments --- Packages/cdms2/Lib/avariable.py | 4 ++-- Packages/cdms2/Lib/cdmsobj.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Packages/cdms2/Lib/avariable.py b/Packages/cdms2/Lib/avariable.py index bc20b8be5..db174105e 100644 --- a/Packages/cdms2/Lib/avariable.py +++ b/Packages/cdms2/Lib/avariable.py @@ -1232,7 +1232,7 @@ avariable.regrid: We chose regridMethod = %s for you among the following choices slicelist.append (slice(0, len(self.getAxis(i)))) elif key is Ellipsis: raise CDMSError, "Misuse of ellipsis in specification." - elif sinstance(key, tuple): + elif isinstance(key, tuple): slicelist.append(slice(*key)) else: raise CDMSError, 'invalid index: %s'% str(key) @@ -1514,7 +1514,7 @@ def orderparse (order): elif r == '...': r = Ellipsis elif len(r) == 1: - if r in '0123456789': + if r.isdigit(): r = int(r) result.append(r) pos = m.end(0) diff --git a/Packages/cdms2/Lib/cdmsobj.py b/Packages/cdms2/Lib/cdmsobj.py index b66cf7307..8fad6b3ab 100644 --- a/Packages/cdms2/Lib/cdmsobj.py +++ b/Packages/cdms2/Lib/cdmsobj.py @@ -546,12 +546,12 @@ class CdmsObj (object): """ if attname is None: for attval in self.attributes.values(): - if isinstance(attval,basestring) and pattern.search(attval) is not None: + if isinstance(attval,basestring) and pattern.match(attval) is not None: return 1 return 0 elif self.attributes.has_key(attname): attval = self.attributes[attname] - return isinstance(attval,basestring) and pattern.search(attval) is not None + return isinstance(attval,basestring) and pattern.match(attval) is not None else: return 0 -- GitLab From 6fc54c9a9537d0e4f47ab84a04bdad2c2ea486fa Mon Sep 17 00:00:00 2001 From: Charles Doutriaux Date: Wed, 27 Apr 2016 09:08:08 -0700 Subject: [PATCH 036/191] autopep8ed --- Packages/cdms2/Lib/CDML.py | 425 +++--- Packages/cdms2/Lib/CDMLParser.py | 180 ++- Packages/cdms2/Lib/MV2.py | 524 ++++--- Packages/cdms2/Lib/__init__.py | 62 +- Packages/cdms2/Lib/auxcoord.py | 80 +- Packages/cdms2/Lib/avariable.py | 962 +++++++------ Packages/cdms2/Lib/axis.py | 1827 +++++++++++++----------- Packages/cdms2/Lib/bindex.py | 41 +- Packages/cdms2/Lib/cache.py | 167 ++- Packages/cdms2/Lib/cdmsNode.py | 763 +++++----- Packages/cdms2/Lib/cdmsURLopener.py | 17 +- Packages/cdms2/Lib/cdmsobj.py | 438 +++--- Packages/cdms2/Lib/cdurllib.py | 72 +- Packages/cdms2/Lib/cdurlparse.py | 339 ++--- Packages/cdms2/Lib/cdxmllib.py | 249 ++-- Packages/cdms2/Lib/convention.py | 62 +- Packages/cdms2/Lib/coord.py | 201 +-- Packages/cdms2/Lib/cudsinterface.py | 182 +-- Packages/cdms2/Lib/database.py | 220 +-- Packages/cdms2/Lib/dataset.py | 1245 +++++++++------- Packages/cdms2/Lib/error.py | 4 +- Packages/cdms2/Lib/forecast.py | 226 +-- Packages/cdms2/Lib/fvariable.py | 137 +- Packages/cdms2/Lib/gengrid.py | 106 +- Packages/cdms2/Lib/grid.py | 385 ++--- Packages/cdms2/Lib/gsHost.py | 212 +-- Packages/cdms2/Lib/gsMosaic.py | 251 ++-- Packages/cdms2/Lib/gsStaticVariable.py | 107 +- Packages/cdms2/Lib/gsTimeVariable.py | 160 ++- Packages/cdms2/Lib/gui.py | 31 +- Packages/cdms2/Lib/hgrid.py | 247 ++-- Packages/cdms2/Lib/mvBaseWriter.py | 19 +- Packages/cdms2/Lib/mvCdmsRegrid.py | 26 +- Packages/cdms2/Lib/mvSphereMesh.py | 170 ++- Packages/cdms2/Lib/mvVTKSGWriter.py | 29 +- Packages/cdms2/Lib/mvVTKUGWriter.py | 47 +- Packages/cdms2/Lib/mvVsWriter.py | 36 +- Packages/cdms2/Lib/restApi.py | 965 +++++++------ Packages/cdms2/Lib/selectors.py | 286 ++-- Packages/cdms2/Lib/slabinterface.py | 130 +- Packages/cdms2/Lib/sliceut.py | 214 +-- Packages/cdms2/Lib/tvariable.py | 609 ++++---- Packages/cdms2/Lib/typeconv.py | 30 +- Packages/cdms2/Lib/variable.py | 345 ++--- Packages/cdms2/Lib/xlink.py | 10 +- 45 files changed, 7050 insertions(+), 5788 deletions(-) diff --git a/Packages/cdms2/Lib/CDML.py b/Packages/cdms2/Lib/CDML.py index 7a6c013f3..963f70ac6 100644 --- a/Packages/cdms2/Lib/CDML.py +++ b/Packages/cdms2/Lib/CDML.py @@ -37,6 +37,7 @@ CdArray = "Array" # Note: at some point, this should be created dynamically # from the XML DTD file. For now, it is built statically. + class CDML: cache = {} @@ -47,246 +48,254 @@ class CDML: self.extra = self.extraCache.get(uri) if not self.dtd: self.dtd = self.buildDTD(uri) - self.cache[uri]=self.dtd + self.cache[uri] = self.dtd self.extra = self.buildExtra(uri) - self.extraCache[uri]=self.extra + self.extraCache[uri] = self.extra - def buildDTD(self,uri): + def buildDTD(self, uri): dtd = {} dtd['attr'] = { - 'name': (Cdata,Required), - 'datatype': (("Char","Byte","Short","Int","Long","Int64","Float","Double","String"),Required), - } + 'name': (Cdata, Required), + 'datatype': + (("Char", "Byte", "Short", "Int", "Long", + "Int64", "Float", "Double", "String"), Required), + } dtd['axis'] = { - 'id': (Id,Required), - 'associate': (Idref,Implied), - 'axis': (("X","Y","Z","T"),Implied), - 'bounds': (Idref,Implied), - 'calendar': (Cdata,Implied), - 'comment': (Cdata,Implied), - 'component': (Cdata,Implied), - 'compress': (Cdata,Implied), - 'datatype': (("Char","Byte","Short","Int","Long","Int64","Float","Double","String"),Required), - 'expand': (Idref,Implied), - 'interval': (Cdata,Implied), - 'isvar': ( ("true","false"),"true"), - 'length': (Cdata,Required), - 'long_name': (Cdata,Implied), - 'modulo': (Cdata,Implied), - 'name_in_file': (Cdata,Implied), - 'partition': (Cdata,Implied), - 'partition_length': (Cdata,Implied), - 'positive': (("up","down"),Implied), - 'spacing': (("uniform","variable","disjoint"),Implied), - 'topology': (("linear","circular"),Implied), - 'weights': (Idref,Implied), - 'units': (Cdata,Required), - } + 'id': (Id, Required), + 'associate': (Idref, Implied), + 'axis': (("X", "Y", "Z", "T"), Implied), + 'bounds': (Idref, Implied), + 'calendar': (Cdata, Implied), + 'comment': (Cdata, Implied), + 'component': (Cdata, Implied), + 'compress': (Cdata, Implied), + 'datatype': + (("Char", "Byte", "Short", "Int", "Long", + "Int64", "Float", "Double", "String"), Required), + 'expand': (Idref, Implied), + 'interval': (Cdata, Implied), + 'isvar': (("true", "false"), "true"), + 'length': (Cdata, Required), + 'long_name': (Cdata, Implied), + 'modulo': (Cdata, Implied), + 'name_in_file': (Cdata, Implied), + 'partition': (Cdata, Implied), + 'partition_length': (Cdata, Implied), + 'positive': (("up", "down"), Implied), + 'spacing': (("uniform", "variable", "disjoint"), Implied), + 'topology': (("linear", "circular"), Implied), + 'weights': (Idref, Implied), + 'units': (Cdata, Required), + } dtd['component'] = { - 'name':(Idref,Required), - } + 'name': (Idref, Required), + } dtd['dataset'] = { - 'id': (Id,Required), - 'Conventions': (Cdata,Required), - 'appendices': (Cdata,Implied), - 'calendar': (Cdata,Implied), - 'cdms_filemap': (Cdata,Implied), - 'comment': (Cdata,Implied), - 'directory': (Cdata,Implied), - 'frequency': (Cdata,Implied), - 'history': (Cdata,Implied), - 'institution': (Cdata,Implied), - 'production': (Cdata,Implied), - 'project': (Cdata,Implied), - 'template': (Cdata,Implied), - } + 'id': (Id, Required), + 'Conventions': (Cdata, Required), + 'appendices': (Cdata, Implied), + 'calendar': (Cdata, Implied), + 'cdms_filemap': (Cdata, Implied), + 'comment': (Cdata, Implied), + 'directory': (Cdata, Implied), + 'frequency': (Cdata, Implied), + 'history': (Cdata, Implied), + 'institution': (Cdata, Implied), + 'production': (Cdata, Implied), + 'project': (Cdata, Implied), + 'template': (Cdata, Implied), + } dtd['doclink'] = { - 'id': (Id,Implied), - 'xml:link': (Cdata,(Fixed,"simple")), - 'href': (Cdata,Required), - 'role': (Cdata,Implied), - 'title': (Cdata,Implied), - 'show': (("embed","replace","new"),"replace"), - 'actuate': (("auto","user"),Implied), - 'behavior':(Cdata,Implied), - 'content-role': (Cdata,Implied), - 'content-title': (Cdata,Implied), - 'inline':(("true","false"),"true"), - } + 'id': (Id, Implied), + 'xml:link': (Cdata, (Fixed, "simple")), + 'href': (Cdata, Required), + 'role': (Cdata, Implied), + 'title': (Cdata, Implied), + 'show': (("embed", "replace", "new"), "replace"), + 'actuate': (("auto", "user"), Implied), + 'behavior': (Cdata, Implied), + 'content-role': (Cdata, Implied), + 'content-title': (Cdata, Implied), + 'inline': (("true", "false"), "true"), + } dtd['domain'] = {} dtd['domElem'] = { - 'name':(Idref,Required), - 'length':(Cdata,Implied), - 'partition_length':(Cdata,Implied), - 'start':(Cdata,Implied), - } + 'name': (Idref, Required), + 'length': (Cdata, Implied), + 'partition_length': (Cdata, Implied), + 'start': (Cdata, Implied), + } dtd['rectGrid'] = { - 'id': (Id,Required), - 'type':(("gaussian","uniform","equalarea","unknown"),"unknown"), - 'latitude':(Idref,Required), - 'longitude':(Idref,Required), - 'mask':(Idref,Implied), - 'order':(("xy","yx"),"yx"), - } + 'id': (Id, Required), + 'type': + (("gaussian", "uniform", "equalarea", "unknown"), "unknown"), + 'latitude': (Idref, Required), + 'longitude': (Idref, Required), + 'mask': (Idref, Implied), + 'order': (("xy", "yx"), "yx"), + } dtd['linear'] = { - 'delta': (Cdata,Required), - 'length': (Cdata,Required), - 'start': (Cdata,Required), - } + 'delta': (Cdata, Required), + 'length': (Cdata, Required), + 'start': (Cdata, Required), + } dtd['variable'] = { - 'id': (Id,Required), - 'add_offset': (Cdata,Implied), - 'associate': (Cdata,Implied), - 'axis': (Cdata,Implied), - 'comments': (Cdata,Implied), - 'datatype': (("Char","Byte","Short","Int","Long","Int64","Float","Double","String"),Required), - 'grid_name': (Cdata,Implied), - 'grid_type': (Cdata,Implied), - 'long_name': (Cdata,Implied), + 'id': (Id, Required), + 'add_offset': (Cdata, Implied), + 'associate': (Cdata, Implied), + 'axis': (Cdata, Implied), + 'comments': (Cdata, Implied), + 'datatype': + (("Char", "Byte", "Short", "Int", "Long", + "Int64", "Float", "Double", "String"), Required), + 'grid_name': (Cdata, Implied), + 'grid_type': (Cdata, Implied), + 'long_name': (Cdata, Implied), 'missing_value': (Cdata, Implied), - 'name_in_file': (Cdata,Implied), - 'scale_factor': (Cdata,Implied), - 'subgrid': (Cdata,Implied), - 'template': (Cdata,Implied), - 'units': (Cdata,Implied), - 'valid_max': (Cdata,Implied), - 'valid_min': (Cdata,Implied), - 'valid_range': (Cdata,Implied), - } + 'name_in_file': (Cdata, Implied), + 'scale_factor': (Cdata, Implied), + 'subgrid': (Cdata, Implied), + 'template': (Cdata, Implied), + 'units': (Cdata, Implied), + 'valid_max': (Cdata, Implied), + 'valid_min': (Cdata, Implied), + 'valid_range': (Cdata, Implied), + } dtd['xlink'] = { - 'id': (Id,Implied), - 'xml:link': (Cdata,(Fixed,"simple")), - 'href': (Cdata,Required), - 'role': (Cdata,Implied), - 'title': (Cdata,Implied), - 'show': (("embed","replace","new"),"embed"), - 'actuate': (("auto","user"),Implied), - 'behavior':(Cdata,Implied), - 'content-role': (("dataset","axis","grid","variable","object"),"object"), - 'content-title': (Cdata,Implied), - 'inline':(("true","false"),"true"), - } + 'id': (Id, Implied), + 'xml:link': (Cdata, (Fixed, "simple")), + 'href': (Cdata, Required), + 'role': (Cdata, Implied), + 'title': (Cdata, Implied), + 'show': (("embed", "replace", "new"), "embed"), + 'actuate': (("auto", "user"), Implied), + 'behavior': (Cdata, Implied), + 'content-role': + (("dataset", "axis", "grid", "variable", "object"), "object"), + 'content-title': (Cdata, Implied), + 'inline': (("true", "false"), "true"), + } return dtd # Extra datatype information not included in the formal DTD. - def buildExtra(self,uri): + def buildExtra(self, uri): extra = {} extra['attr'] = { - 'name': (CdScalar,CdString), - 'datatype': (CdScalar,CdString), - } + 'name': (CdScalar, CdString), + 'datatype': (CdScalar, CdString), + } extra['axis'] = { - 'id': (CdScalar,CdString), - 'associate': (CdScalar,CdString), - 'axis': (CdScalar,CdString), - 'bounds': (CdArray,CdFromObject), - 'calendar': (CdScalar,CdString), - 'comment': (CdScalar,CdString), - 'component': (CdScalar,CdString), - 'compress': (CdScalar,CdString), - 'datatype': (CdScalar,CdString), - 'expand': (CdScalar,CdString), - 'interval': (CdScalar,CdFromObject), - 'isvar': (CdScalar,CdString), - 'length': (CdScalar,CdInt), - 'long_name': (CdScalar,CdString), - 'modulo': (CdScalar,CdAny), - 'name_in_file': (CdScalar,CdString), - 'partition': (CdArray,CdInt), - 'partition_length': (CdScalar,CdInt), - 'positive': (CdScalar,CdString), - 'spacing': (CdScalar,CdFromObject), - 'topology': (CdScalar,CdString), - 'weights': (CdArray,CdDouble), - 'units': (CdScalar,CdString), - } + 'id': (CdScalar, CdString), + 'associate': (CdScalar, CdString), + 'axis': (CdScalar, CdString), + 'bounds': (CdArray, CdFromObject), + 'calendar': (CdScalar, CdString), + 'comment': (CdScalar, CdString), + 'component': (CdScalar, CdString), + 'compress': (CdScalar, CdString), + 'datatype': (CdScalar, CdString), + 'expand': (CdScalar, CdString), + 'interval': (CdScalar, CdFromObject), + 'isvar': (CdScalar, CdString), + 'length': (CdScalar, CdInt), + 'long_name': (CdScalar, CdString), + 'modulo': (CdScalar, CdAny), + 'name_in_file': (CdScalar, CdString), + 'partition': (CdArray, CdInt), + 'partition_length': (CdScalar, CdInt), + 'positive': (CdScalar, CdString), + 'spacing': (CdScalar, CdFromObject), + 'topology': (CdScalar, CdString), + 'weights': (CdArray, CdDouble), + 'units': (CdScalar, CdString), + } extra['component'] = { - 'name': (CdScalar,CdString), - } + 'name': (CdScalar, CdString), + } extra['dataset'] = { - 'id': (CdScalar,CdString), - 'Conventions': (CdScalar,CdString), - 'appendices': (CdScalar,CdString), - 'calendar': (CdScalar,CdString), - 'cdms_filemap': (CdScalar,CdString), - 'comment': (CdScalar,CdString), - 'directory': (CdScalar,CdString), - 'frequency': (CdScalar,CdString), - 'history': (CdScalar,CdString), - 'institution': (CdScalar,CdString), - 'production': (CdScalar,CdString), - 'project': (CdScalar,CdString), - 'template': (CdScalar,CdString), - } + 'id': (CdScalar, CdString), + 'Conventions': (CdScalar, CdString), + 'appendices': (CdScalar, CdString), + 'calendar': (CdScalar, CdString), + 'cdms_filemap': (CdScalar, CdString), + 'comment': (CdScalar, CdString), + 'directory': (CdScalar, CdString), + 'frequency': (CdScalar, CdString), + 'history': (CdScalar, CdString), + 'institution': (CdScalar, CdString), + 'production': (CdScalar, CdString), + 'project': (CdScalar, CdString), + 'template': (CdScalar, CdString), + } extra['doclink'] = { - 'id': (CdScalar,CdString), - 'xml:link': (CdScalar,CdString), - 'href': (CdScalar,CdString), - 'role': (CdScalar,CdString), - 'title': (CdScalar,CdString), - 'show': (CdScalar,CdString), - 'actuate': (CdScalar,CdString), - 'behavior': (CdScalar,CdString), - 'content-role': (CdScalar,CdString), - 'content-title': (CdScalar,CdString), - 'inline': (CdScalar,CdString), - } + 'id': (CdScalar, CdString), + 'xml:link': (CdScalar, CdString), + 'href': (CdScalar, CdString), + 'role': (CdScalar, CdString), + 'title': (CdScalar, CdString), + 'show': (CdScalar, CdString), + 'actuate': (CdScalar, CdString), + 'behavior': (CdScalar, CdString), + 'content-role': (CdScalar, CdString), + 'content-title': (CdScalar, CdString), + 'inline': (CdScalar, CdString), + } extra['domain'] = {} extra['domElem'] = { - 'name': (CdScalar,CdString), - 'length': (CdScalar,CdInt), - 'partition_length': (CdScalar,CdInt), - 'start': (CdScalar,CdInt), - } + 'name': (CdScalar, CdString), + 'length': (CdScalar, CdInt), + 'partition_length': (CdScalar, CdInt), + 'start': (CdScalar, CdInt), + } extra['rectGrid'] = { - 'id': (CdScalar,CdString), - 'type': (CdScalar,CdString), - 'latitude': (CdScalar,CdString), - 'longitude': (CdScalar,CdString), - 'mask': (CdScalar,CdString), - 'order': (CdScalar,CdString), - } + 'id': (CdScalar, CdString), + 'type': (CdScalar, CdString), + 'latitude': (CdScalar, CdString), + 'longitude': (CdScalar, CdString), + 'mask': (CdScalar, CdString), + 'order': (CdScalar, CdString), + } extra['linear'] = { - 'delta': (CdScalar,CdFromObject), - 'length': (CdScalar,CdInt), - 'start': (CdScalar,CdInt), - } + 'delta': (CdScalar, CdFromObject), + 'length': (CdScalar, CdInt), + 'start': (CdScalar, CdInt), + } extra['variable'] = { - 'id': (CdScalar,CdString), - 'add_offset': (CdScalar,CdDouble), - 'associate': (CdScalar,CdString), - 'axis': (CdScalar,CdString), - 'comments': (CdScalar,CdString), - 'datatype': (CdScalar,CdString), - 'grid_name': (CdScalar,CdString), - 'grid_type': (CdScalar,CdString), - 'long_name': (CdScalar,CdString), - 'missing_value': (CdScalar,CdFromObject), - 'name_in_file': (CdScalar,CdString), - 'scale_factor': (CdScalar,CdDouble), - 'subgrid': (CdScalar,CdString), - 'template': (CdScalar,CdString), - 'units': (CdScalar,CdString), - 'valid_max': (CdScalar,CdFromObject), - 'valid_min': (CdScalar,CdFromObject), - 'valid_range': (CdArray,CdFromObject), - } + 'id': (CdScalar, CdString), + 'add_offset': (CdScalar, CdDouble), + 'associate': (CdScalar, CdString), + 'axis': (CdScalar, CdString), + 'comments': (CdScalar, CdString), + 'datatype': (CdScalar, CdString), + 'grid_name': (CdScalar, CdString), + 'grid_type': (CdScalar, CdString), + 'long_name': (CdScalar, CdString), + 'missing_value': (CdScalar, CdFromObject), + 'name_in_file': (CdScalar, CdString), + 'scale_factor': (CdScalar, CdDouble), + 'subgrid': (CdScalar, CdString), + 'template': (CdScalar, CdString), + 'units': (CdScalar, CdString), + 'valid_max': (CdScalar, CdFromObject), + 'valid_min': (CdScalar, CdFromObject), + 'valid_range': (CdArray, CdFromObject), + } extra['xlink'] = { - 'id': (CdScalar,CdString), - 'xml:link': (CdScalar,CdString), - 'href': (CdScalar,CdString), - 'role': (CdScalar,CdString), - 'title': (CdScalar,CdString), - 'show': (CdScalar,CdString), - 'actuate': (CdScalar,CdString), - 'behavior': (CdScalar,CdString), - 'content-role': (CdScalar,CdString), - 'content-title': (CdScalar,CdString), - 'inline': (CdScalar,CdString), - } + 'id': (CdScalar, CdString), + 'xml:link': (CdScalar, CdString), + 'href': (CdScalar, CdString), + 'role': (CdScalar, CdString), + 'title': (CdScalar, CdString), + 'show': (CdScalar, CdString), + 'actuate': (CdScalar, CdString), + 'behavior': (CdScalar, CdString), + 'content-role': (CdScalar, CdString), + 'content-title': (CdScalar, CdString), + 'inline': (CdScalar, CdString), + } return extra -if __name__=='__main__': +if __name__ == '__main__': cdml = CDML() print cdml.extra cdml2 = CDML() diff --git a/Packages/cdms2/Lib/CDMLParser.py b/Packages/cdms2/Lib/CDMLParser.py index e741e44d2..6a88eda9c 100644 --- a/Packages/cdms2/Lib/CDMLParser.py +++ b/Packages/cdms2/Lib/CDMLParser.py @@ -2,10 +2,10 @@ Parse a CDML/XML file """ -from cdxmllib import XMLParser -import CDML +from .cdxmllib import XMLParser +from . import CDML import re -import cdmsNode +from . import cdmsNode # Error constants InvalidAttribute = "Invalid attribute" @@ -13,21 +13,23 @@ InvalidAttribute = "Invalid attribute" # Regular expressions _S = re.compile('[ \t\r\n]+$') _opS = '[ \t\r\n]*' -_Integer = re.compile(_opS+'[0-9]+$'+_opS) +_Integer = re.compile(_opS + '[0-9]+$' + _opS) + class CDMLParser(XMLParser): def __init__(self, verbose=0): - XMLParser.__init__(self) + XMLParser.__init__(self) self.root = None self.currentPath = [] # Current path, a stack self.dtd = CDML.CDML().dtd self.verbose = verbose # Push current node on the stack - def pushCurrentNode(self,node): + def pushCurrentNode(self, node): self.currentPath.append(node) - if not self.root: self.root = node + if not self.root: + self.root = node # Pop the current node off the stack def popCurrentNode(self): @@ -49,62 +51,67 @@ class CDMLParser(XMLParser): def handle_data(self, data): matchObj = _S.match(data) if not matchObj: - if self.verbose: print 'data:',data + if self.verbose: + print 'data:', data if self.root: self.getCurrentNode().setContentFromString(data.strip()) def handle_cdata(self, data): - if self.verbose: print 'cdata:', `data` + if self.verbose: + print 'cdata:', repr(data) def handle_proc(self, name, data): - if self.verbose: print 'processing:',name,`data` + if self.verbose: + print 'processing:', name, repr(data) def handle_special(self, data): - if self.verbose: print 'special:',`data` + if self.verbose: + print 'special:', repr(data) def handle_starttag(self, tag, method, attrs): - if self.dtd.has_key(tag): + if tag in self.dtd: # Check that attributes are valid - validDict = self.dtd[tag] + validDict = self.dtd[tag] validAttrs = validDict.keys() attrnames = attrs.keys() for attrname in attrnames: if attrname not in validAttrs: self.cdml_syntax_error(self.lineno, - 'unknown attribute %s of element %s' % - (attrname, tag)) + 'unknown attribute %s of element %s' % + (attrname, tag)) else: - (atttype,attdefault)=validDict[attrname] - if type(atttype)==type((0,)): + (atttype, attdefault) = validDict[attrname] + if isinstance(atttype, tuple): attrval = attrs[attrname] if attrval not in atttype: self.cdml_syntax_error(self.lineno, - 'invalid attribute value %s=%s of element %s, must be one of %s' % - (attrname,attrval,tag,atttype)) + 'invalid attribute value %s=%s of element %s, must be one of %s' % + (attrname, attrval, tag, atttype)) # Check that required attributes are present, # and add default values for attrname in validAttrs: - (atttype,attdefault)=validDict[attrname] - if attdefault==CDML.Required and attrname not in attrnames: + (atttype, attdefault) = validDict[attrname] + if attdefault == CDML.Required and attrname not in attrnames: self.cdml_syntax_error(self.lineno, - 'element %s requires an attribute %s' % - (tag,attrname)) - if type(attdefault)==type("") and attrname not in attrnames: - attrs[attrname]=attdefault - - method(attrs) + 'element %s requires an attribute %s' % + (tag, attrname)) + if isinstance(attdefault, basestring) and attrname not in attrnames: + attrs[attrname] = attdefault + + method(attrs) #------------------------------------------------------------------------ # CDML tags - def start_attr(self,attrs): - if self.verbose: print 'attr:',attrs + def start_attr(self, attrs): + if self.verbose: + print 'attr:', attrs name = attrs['name'] datatype = attrs['datatype'] - attr = cdmsNode.AttrNode(name,None) + attr = cdmsNode.AttrNode(name, None) attr.datatype = datatype self.pushCurrentNode(attr) @@ -112,33 +119,35 @@ class CDMLParser(XMLParser): def end_attr(self): attr = self.popCurrentNode() var = self.getCurrentNode() - attr.setValueFromString(attr.getContent(),attr.datatype) + attr.setValueFromString(attr.getContent(), attr.datatype) var.setExternalAttrFromAttr(attr) #------------------------------------------------------------------------ - def start_axis(self,attrs): - if self.verbose: print 'axis:',attrs + def start_axis(self, attrs): + if self.verbose: + print 'axis:', attrs id = attrs['id'] length_s = attrs['length'] datatype = attrs.get('datatype') if _Integer.match(length_s) is None: - raise InvalidAttribute, 'length='+length_s + raise InvalidAttribute('length=' + length_s) length = int(length_s) - axis = cdmsNode.AxisNode(id,length,datatype) + axis = cdmsNode.AxisNode(id, length, datatype) partstring = attrs.get('partition') if partstring is not None: axis.setPartitionFromString(partstring) axis.setExternalDict(attrs) - self.getCurrentNode().addId(id,axis) + self.getCurrentNode().addId(id, axis) self.pushCurrentNode(axis) - + def end_axis(self): self.popCurrentNode() #------------------------------------------------------------------------ def start_cdml(self, attrs): - if self.verbose: print 'cdml:',attrs + if self.verbose: + print 'cdml:', attrs def end_cdml(self): pass @@ -146,36 +155,40 @@ class CDMLParser(XMLParser): #------------------------------------------------------------------------ def start_component(self, attrs): - if self.verbose: print 'component:',attrs + if self.verbose: + print 'component:', attrs def end_component(self): pass #------------------------------------------------------------------------ def start_compoundAxis(self, attrs): - if self.verbose: print 'compoundAxis:',attrs + if self.verbose: + print 'compoundAxis:', attrs def end_compoundAxis(self): pass #------------------------------------------------------------------------ def start_data(self, attrs): - if self.verbose: print 'data:',attrs + if self.verbose: + print 'data:', attrs def end_data(self): pass #------------------------------------------------------------------------ - def start_dataset(self,attrs): - if self.verbose: print 'dataset:',attrs + def start_dataset(self, attrs): + if self.verbose: + print 'dataset:', attrs id = attrs['id'] dataset = cdmsNode.DatasetNode(id) dataset.setExternalDict(attrs) if self.root: - self.getCurrentNode().addId(id,dataset) + self.getCurrentNode().addId(id, dataset) self.pushCurrentNode(dataset) - + def end_dataset(self): dataset = self.popCurrentNode() dataset.validate() @@ -183,7 +196,8 @@ class CDMLParser(XMLParser): #------------------------------------------------------------------------ def start_doclink(self, attrs): - if self.verbose: print 'docLink:',attrs + if self.verbose: + print 'docLink:', attrs uri = attrs['href'] doclink = cdmsNode.DocLinkNode(uri) doclink.setExternalDict(attrs) @@ -196,7 +210,8 @@ class CDMLParser(XMLParser): #------------------------------------------------------------------------ def start_domElem(self, attrs): - if self.verbose: print 'domElem:',attrs + if self.verbose: + print 'domElem:', attrs name = attrs['name'] start_s = attrs.get('start') length_s = attrs.get('length') @@ -208,7 +223,7 @@ class CDMLParser(XMLParser): length = int(length_s) else: length = None - domElem = cdmsNode.DomElemNode(name,start,length) + domElem = cdmsNode.DomElemNode(name, start, length) domElem.setExternalDict(attrs) self.getCurrentNode().add(domElem) @@ -217,7 +232,8 @@ class CDMLParser(XMLParser): #------------------------------------------------------------------------ def start_domain(self, attrs): - if self.verbose: print 'domain:',attrs + if self.verbose: + print 'domain:', attrs domain = cdmsNode.DomainNode() self.getCurrentNode().setDomain(domain) self.pushCurrentNode(domain) @@ -227,40 +243,42 @@ class CDMLParser(XMLParser): #------------------------------------------------------------------------ - def start_rectGrid(self,attrs): - if self.verbose: print 'rectGrid:',attrs + def start_rectGrid(self, attrs): + if self.verbose: + print 'rectGrid:', attrs id = attrs['id'] gridtype = attrs['type'] latitude = attrs['latitude'] longitude = attrs['longitude'] - grid = cdmsNode.RectGridNode(id,latitude,longitude,gridtype) + grid = cdmsNode.RectGridNode(id, latitude, longitude, gridtype) grid.setExternalDict(attrs) - self.getCurrentNode().addId(id,grid) + self.getCurrentNode().addId(id, grid) self.pushCurrentNode(grid) - + def end_rectGrid(self): self.popCurrentNode() #------------------------------------------------------------------------ def start_linear(self, attrs): - if self.verbose: print 'linear:',attrs + if self.verbose: + print 'linear:', attrs start_s = attrs['start'] delta_s = attrs['delta'] length_s = attrs['length'] try: - start=float(start_s) + start = float(start_s) except ValueError: - raise InvalidAttribute, 'start='+start_s + raise InvalidAttribute('start=' + start_s) try: - delta=float(delta_s) + delta = float(delta_s) except ValueError: - raise InvalidAttribute, 'delta='+delta_s + raise InvalidAttribute('delta=' + delta_s) try: - length=int(length_s) + length = int(length_s) except ValueError: - raise InvalidAttribute, 'length='+length_s - linear = cdmsNode.LinearDataNode(start,delta,length) + raise InvalidAttribute('length=' + length_s) + linear = cdmsNode.LinearDataNode(start, delta, length) self.getCurrentNode().setLinearData(linear) def end_linear(self): @@ -268,28 +286,30 @@ class CDMLParser(XMLParser): #------------------------------------------------------------------------ - def start_variable(self,attrs): - if self.verbose: print 'variable:',attrs + def start_variable(self, attrs): + if self.verbose: + print 'variable:', attrs id = attrs['id'] datatype = attrs['datatype'] - variable = cdmsNode.VariableNode(id,datatype,None) + variable = cdmsNode.VariableNode(id, datatype, None) variable.setExternalDict(attrs) - self.getCurrentNode().addId(id,variable) + self.getCurrentNode().addId(id, variable) self.pushCurrentNode(variable) - + def end_variable(self): self.popCurrentNode() #------------------------------------------------------------------------ def start_xlink(self, attrs): - if self.verbose: print 'xlink:',attrs + if self.verbose: + print 'xlink:', attrs id = attrs['id'] uri = attrs['href'] contentRole = attrs['content-role'] - xlink = cdmsNode.XLinkNode(id,uri,contentRole) + xlink = cdmsNode.XLinkNode(id, uri, contentRole) xlink.setExternalDict(attrs) - self.getCurrentNode().addId(id,xlink) + self.getCurrentNode().addId(id, xlink) self.pushCurrentNode(xlink) def end_xlink(self): @@ -301,30 +321,33 @@ class CDMLParser(XMLParser): print 'error near line %d:' % lineno, message def unknown_starttag(self, tag, attrs): - if self.verbose: print '**'+tag+'**:',attrs + if self.verbose: + print '**' + tag + '**:', attrs def unknown_endtag(self, tag): pass def unknown_entityref(self, ref): - self.flush() - if self.verbose: print '*** unknown entity ref: &' + ref + ';' + self.flush() + if self.verbose: + print '*** unknown entity ref: &' + ref + ';' def unknown_charref(self, ref): - self.flush() - if self.verbose: print '*** unknown char ref: &#' + ref + ';' + self.flush() + if self.verbose: + print '*** unknown char ref: &#' + ref + ';' def close(self): - XMLParser.close(self) + XMLParser.close(self) if __name__ == '__main__': import sys - + sampfile = open(sys.argv[1]) text = sampfile.read() sampfile.close() - if len(sys.argv)==2: + if len(sys.argv) == 2: verbose = 0 else: verbose = 1 @@ -332,4 +355,3 @@ if __name__ == '__main__': p.feed(text) p.close() p.root.dump() - diff --git a/Packages/cdms2/Lib/MV2.py b/Packages/cdms2/Lib/MV2.py index b203bc6af..297cd7362 100644 --- a/Packages/cdms2/Lib/MV2.py +++ b/Packages/cdms2/Lib/MV2.py @@ -1,31 +1,31 @@ -## Automatically adapted for numpy.oldnumeric Aug 01, 2007 by -## Further modified to be pure new numpy June 24th 2008 +# Automatically adapted for numpy.oldnumeric Aug 01, 2007 by +# Further modified to be pure new numpy June 24th 2008 "CDMS Variable objects, MaskedArray interface" import numpy -import typeconv +from . import typeconv from numpy import character, float, float32, float64, int, int8, int16, int32 from numpy.ma import allclose, allequal, common_fill_value, compress, make_mask_none, dot, filled, \ - getmask, getmaskarray, identity, indices, innerproduct, masked, put, putmask, rank, ravel, \ + getmask, getmaskarray, identity, indices, innerproduct, masked, put, putmask, rank, ravel, \ set_fill_value, shape, size, isMA, isMaskedArray, is_mask, isarray, \ make_mask, make_mask_none, mask_or, nomask from numpy import sctype2char, get_printoptions, set_printoptions -from avariable import AbstractVariable, getNumericCompatibility -from tvariable import TransientVariable, asVariable -from grid import AbstractRectGrid -from error import CDMSError -#from numpy.ma import * -from axis import allclose as axisAllclose, TransientAxis, concatenate as axisConcatenate, take as axisTake - +from .avariable import AbstractVariable, getNumericCompatibility +from .tvariable import TransientVariable, asVariable +from .grid import AbstractRectGrid +from .error import CDMSError +# from numpy.ma import * +from .axis import allclose as axisAllclose, TransientAxis, concatenate as axisConcatenate, take as axisTake create_mask = make_mask_none e = numpy.e pi = numpy.pi -#NewAxis = numpy.oldnumeric.NewAxis +# NewAxis = numpy.oldnumeric.NewAxis newaxis = numpy.newaxis counter = 0 + def fill_value(ar): return ar.fill_value @@ -34,13 +34,14 @@ def _makeMaskedArg(x): """If x is a variable, turn it into a TransientVariable.""" if isinstance(x, AbstractVariable) and not isinstance(x, TransientVariable): return x.subSlice() - elif isinstance(x,TransientVariable): + elif isinstance(x, TransientVariable): return x else: return array(x) -def _extractMetadata(a, axes=None, attributes=None, id=None, omit=None, omitall=False): +def _extractMetadata( + a, axes=None, attributes=None, id=None, omit=None, omitall=False): """Extract axes, attributes, id from 'a', if arg is None.""" resultgrid = None if isinstance(a, AbstractVariable): @@ -52,7 +53,7 @@ def _extractMetadata(a, axes=None, attributes=None, id=None, omit=None, omitall= attributes = a.attributes if id is None: id = "variable_%i" % TransientVariable.variable_count - TransientVariable.variable_count+=1 + TransientVariable.variable_count += 1 # If the grid is rectilinear, don't return an explicit grid: it's implicitly defined # by the axes. @@ -60,13 +61,16 @@ def _extractMetadata(a, axes=None, attributes=None, id=None, omit=None, omitall= if (resultgrid is None) or (isinstance(resultgrid, AbstractRectGrid)) or (axes is None): resultgrid = None - # If the omitted axis was associated with the grid, the result will not be gridded. + # If the omitted axis was associated with the grid, the result will not + # be gridded. elif (omit is not None) and (resultgrid is not None) and (a.getAxis(omit) in resultgrid.getAxisList()): resultgrid = None return axes, attributes, id, resultgrid + class var_unary_operation: + def __init__(self, mafunc): """ var_unary_operation(mafunc) mafunc is an numpy.ma masked_unary_function. @@ -74,26 +78,31 @@ class var_unary_operation: self.mafunc = mafunc self.__doc__ = mafunc.__doc__ - def __call__ (self, a): + def __call__(self, a): axes, attributes, id, grid = _extractMetadata(a) maresult = self.mafunc(_makeMaskedArg(a)) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid) + class var_unary_operation_with_axis: + def __init__(self, mafunc): """ var_unary_operation(mafunc) mafunc is an numpy.ma masked_unary_function. """ self.mafunc = mafunc self.__doc__ = mafunc.__doc__ - def __call__ (self, a, axis=0): + + def __call__(self, a, axis=0): axis = _conv_axis_arg(axis) ta = _makeMaskedArg(a) maresult = self.mafunc(ta, axis=axis) - axes, attributes, id, grid = _extractMetadata(a, omit=axis, omitall=(axis is None)) + axes, attributes, id, grid = _extractMetadata( + a, omit=axis, omitall=(axis is None)) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid) -def commonDomain(a,b,omit=None): + +def commonDomain(a, b, omit=None): """commonDomain(a,b) tests that the domains of variables/arrays a and b are equal, and returns the common domain if equal, or None if not equal. The domains may differ in that one domain may have leading axes not common @@ -101,14 +110,15 @@ def commonDomain(a,b,omit=None): If is specified, as an integer i, skip comparison of the ith dimension and return None for the ith (common) dimension. """ - + if isinstance(b, AbstractVariable): bdom = b.getAxisList() else: bdom = None - return commonAxes(a,bdom,omit=omit) + return commonAxes(a, bdom, omit=omit) -def commonAxes(a,bdom,omit=None): + +def commonAxes(a, bdom, omit=None): """Helper function for commonDomain. 'a' is a variable or array, 'b' is an axislist or None. """ @@ -116,40 +126,40 @@ def commonAxes(a,bdom,omit=None): adom = a.getAxisList() arank = len(adom) brank = len(bdom) - if arank>brank: + if arank > brank: maxrank = arank minrank = brank else: maxrank = brank minrank = arank - diffrank = maxrank-minrank - if maxrank==arank: + diffrank = maxrank - minrank + if maxrank == arank: maxdom = adom else: maxdom = bdom - common = [None]*maxrank + common = [None] * maxrank if omit is None: iomit = None else: - iomit = omit-minrank + iomit = omit - minrank # Check shared dimensions, last to first for i in range(minrank): - j = -i-1 - if j==iomit: + j = -i - 1 + if j == iomit: continue aj = adom[j] bj = bdom[j] - if len(aj)!=len(bj): + if len(aj) != len(bj): return None - elif axisAllclose(aj,bj): + elif axisAllclose(aj, bj): common[j] = aj else: common[j] = TransientAxis(numpy.arange(len(aj))) # Copy leading (non-shared) axes for i in range(diffrank): - common[i]=maxdom[i] + common[i] = maxdom[i] return common elif isinstance(a, AbstractVariable): @@ -162,6 +172,7 @@ def commonAxes(a,bdom,omit=None): bdom[omit] = None return bdom + def commonGrid(a, b, axes): """commonGrid(a,b,axes) tests if the grids associated with variables a, b are equal, and consistent with the list of axes. If so, the common grid is returned, else None @@ -182,6 +193,7 @@ def commonGrid(a, b, axes): return commonGrid1(a, gb, axes) + def commonGrid1(a, gb, axes): """Helper function for commonGrid.""" if isinstance(a, AbstractVariable): @@ -210,7 +222,9 @@ def commonGrid1(a, gb, axes): return result + class var_binary_operation: + def __init__(self, mafunc): """ var_binary_operation(mafunc) mafunc is an numpy.ma masked_binary_function. @@ -218,29 +232,29 @@ class var_binary_operation: self.mafunc = mafunc self.__doc__ = mafunc.__doc__ - def __call__ (self, a, b): + def __call__(self, a, b): id = "variable_%i" % TransientVariable.variable_count - TransientVariable.variable_count+=1 - axes = commonDomain(a,b) - grid = commonGrid(a,b,axes) + TransientVariable.variable_count += 1 + axes = commonDomain(a, b) + grid = commonGrid(a, b, axes) ta = _makeMaskedArg(a) tb = _makeMaskedArg(b) - maresult = self.mafunc(ta,tb) - return TransientVariable(maresult, axes=axes, grid=grid,no_update_from=True,id=id) + maresult = self.mafunc(ta, tb) + return TransientVariable(maresult, axes=axes, grid=grid, no_update_from=True, id=id) - def reduce (self, target, axis=0): + def reduce(self, target, axis=0): ttarget = _makeMaskedArg(target) maresult = self.mafunc.reduce(ttarget, axis=axis) axes, attributes, id, grid = _extractMetadata(target, omit=axis) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid) - def accumulate (self, target, axis=0): + def accumulate(self, target, axis=0): ttarget = _makeMaskedArg(target) maresult = self.mafunc.accumulate(ttarget, axis=axis) axes, attributes, id, grid = _extractMetadata(target, omit=axis) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid) - - def outer (self, a, b): + + def outer(self, a, b): """Return the function applied to the outer product of a and b""" a1 = _makeMaskedArg(a) b1 = _makeMaskedArg(b) @@ -248,11 +262,13 @@ class var_binary_operation: return TransientVariable(maresult) -def compress(a,b): - __doc__=numpy.ma.__doc__ - import warnings - warnings.warn("arguments order for compress function has changed\nit is now: MV2.copmress(array,condition), if your code seems to not react or act wrong to a call to compress, please check this", Warning) - return TransientVariable(numpy.ma.compress(a,b),copy=1) +def compress(a, b): + __doc__ = numpy.ma.__doc__ + import warnings + warnings.warn( + "arguments order for compress function has changed\nit is now: MV2.copmress(array,condition), if your code seems to not react or act wrong to a call to compress, please check this", + Warning) + return TransientVariable(numpy.ma.compress(a, b), copy=1) sqrt = var_unary_operation(numpy.ma.sqrt) @@ -269,27 +285,31 @@ less_equal = var_binary_operation(numpy.ma.less_equal) greater_equal = var_binary_operation(numpy.ma.greater_equal) less = var_binary_operation(numpy.ma.less) greater = var_binary_operation(numpy.ma.greater) -def power (a, b, third=None): + + +def power(a, b, third=None): "a**b" ta = _makeMaskedArg(a) tb = _makeMaskedArg(b) - maresult = numpy.ma.power(ta,tb,third) + maresult = numpy.ma.power(ta, tb, third) axes, attributes, id, grid = _extractMetadata(a) return TransientVariable(maresult, axes=axes, attributes=attributes, grid=grid, id=id) -def left_shift (a, n): + +def left_shift(a, n): "Left shift n bits" ta = _makeMaskedArg(a) tb = _makeMaskedArg(n) - maresult = numpy.ma.left_shift(ta,numpy.ma.filled(tb)) + maresult = numpy.ma.left_shift(ta, numpy.ma.filled(tb)) axes, attributes, id, grid = _extractMetadata(a) return TransientVariable(maresult, axes=axes, attributes=attributes, grid=grid, id=id) -def right_shift (a, n): + +def right_shift(a, n): "Right shift n bits" ta = _makeMaskedArg(a) tb = _makeMaskedArg(n) - maresult = numpy.ma.right_shift(ta,numpy.ma.filled(tb)) + maresult = numpy.ma.right_shift(ta, numpy.ma.filled(tb)) axes, attributes, id, grid = _extractMetadata(a) return TransientVariable(maresult, axes=axes, attributes=attributes, grid=grid, id=id) @@ -300,27 +320,33 @@ def _convdtype(dtype, typecode): dtype = typeconv.convtypecode2(typecode) return dtype + def _conv_axis_arg(axis): "Handle backward compatibility with numpy for axis arg" if getNumericCompatibility() and axis is None: - axis=0 + axis = 0 return axis + def is_masked(x): "Is x a 0-D masked value?" - return isMaskedArray(x) and x.size==1 and x.ndim==0 and x.mask.item() + return isMaskedArray(x) and x.size == 1 and x.ndim == 0 and x.mask.item() + def is_floating(x): "Is x a scalar float, either python or numpy?" return (isinstance(x, numpy.floating) or isinstance(x, float)) + def is_integer(x): "Is x a scalar integer, either python or numpy?" return (isinstance(x, numpy.integer) or isinstance(x, int) or isinstance(x, long)) + def get_print_limit(): return get_printoptions()['threshold'] + def set_print_limit(limit=numpy.inf): set_printoptions(threshold=limit) @@ -369,75 +395,113 @@ bitwise_or = var_binary_operation(numpy.ma.bitwise_or) bitwise_xor = var_binary_operation(numpy.ma.bitwise_xor) -def count (a, axis = None): - "Count of the non-masked elements in a, or along a certain axis." +def count(a, axis=None): + "Count of the non-masked elements in a, or along a certain axis." if axis is None: - return numpy.ma.count(a,axis) + return numpy.ma.count(a, axis) else: ta = _makeMaskedArg(a) - maresult = numpy.ma.count(ta,axis) - axes, attributes, id, grid = _extractMetadata(a,omit=axis) - F=getattr(a,"fill_value",1.e20) + maresult = numpy.ma.count(ta, axis) + axes, attributes, id, grid = _extractMetadata(a, omit=axis) + F = getattr(a, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, grid=grid, id=id, fill_value=F) -def sum (a, axis = None, fill_value=0, dtype=None): + +def sum(a, axis=None, fill_value=0, dtype=None): "Sum of elements along a certain axis." axis = _conv_axis_arg(axis) ta = _makeMaskedArg(a) maresult = numpy.ma.sum(ta, axis, dtype=dtype) - axes, attributes, id, grid = _extractMetadata(a, omit=axis, omitall=(axis is None)) - F=getattr(a,"fill_value",1.e20) + axes, attributes, id, grid = _extractMetadata( + a, omit=axis, omitall=(axis is None)) + F = getattr(a, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, grid=grid, id=id, fill_value=F) -def product (a, axis = 0, dtype=None): + +def product(a, axis=0, dtype=None): "Product of elements along axis." ta = _makeMaskedArg(a) maresult = numpy.ma.product(ta, axis, dtype=dtype) axes, attributes, id, grid = _extractMetadata(a, omit=axis) - F=getattr(a,"fill_value",1.e20) + F = getattr(a, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, grid=grid, id=id, fill_value=F) -def average (a, axis=None, weights=None, returned=False): + +def average(a, axis=None, weights=None, returned=False): axis = _conv_axis_arg(axis) ta = _makeMaskedArg(a) maresult = numpy.ma.average(ta, axis, weights, returned) - axes, attributes, id, grid = _extractMetadata(a, omit=axis, omitall=(axis is None)) + axes, attributes, id, grid = _extractMetadata( + a, omit=axis, omitall=(axis is None)) if returned: - if isinstance(maresult,tuple): - maresult, wresult = maresult - else: - #ok it's masked constant need to return both things by hand - wresult = numpy.ma.masked - F=getattr(a,"fill_value",1.e20) - r1 = TransientVariable(maresult, axes=axes, attributes=attributes, grid=grid, id=id,no_update_from=True, fill_value=F) + if isinstance(maresult, tuple): + maresult, wresult = maresult + else: + # ok it's masked constant need to return both things by hand + wresult = numpy.ma.masked + F = getattr(a, "fill_value", 1.e20) + r1 = TransientVariable( + maresult, + axes=axes, + attributes=attributes, + grid=grid, + id=id, + no_update_from=True, + fill_value=F) if returned: - F=getattr(a,"fill_value",1.e20) - w1 = TransientVariable(wresult, axes=axes, grid=grid, id=id,no_update_from=True, fill_value=F) + F = getattr(a, "fill_value", 1.e20) + w1 = TransientVariable( + wresult, + axes=axes, + grid=grid, + id=id, + no_update_from=True, + fill_value=F) return r1, w1 else: return r1 average.__doc__ = numpy.ma.average.__doc__ -def max (a, axis=None): + +def max(a, axis=None): axis = _conv_axis_arg(axis) ta = _makeMaskedArg(a) maresult = numpy.ma.max(ta, axis) - axes, attributes, id, grid = _extractMetadata(a, omit=axis, omitall=(axis is None)) - F=getattr(a,"fill_value",1.e20) - r1 = TransientVariable(maresult, axes=axes, attributes=attributes, grid=grid, id=id,no_update_from=True, fill_value=F) + axes, attributes, id, grid = _extractMetadata( + a, omit=axis, omitall=(axis is None)) + F = getattr(a, "fill_value", 1.e20) + r1 = TransientVariable( + maresult, + axes=axes, + attributes=attributes, + grid=grid, + id=id, + no_update_from=True, + fill_value=F) return r1 max.__doc__ = numpy.ma.max.__doc__ -def min (a, axis=None): + + +def min(a, axis=None): axis = _conv_axis_arg(axis) ta = _makeMaskedArg(a) maresult = numpy.ma.min(ta, axis) - axes, attributes, id, grid = _extractMetadata(a, omit=axis, omitall=(axis is None)) - F=getattr(a,"fill_value",1.e20) - r1 = TransientVariable(maresult, axes=axes, attributes=attributes, grid=grid, id=id,no_update_from=True, fill_value=F) + axes, attributes, id, grid = _extractMetadata( + a, omit=axis, omitall=(axis is None)) + F = getattr(a, "fill_value", 1.e20) + r1 = TransientVariable( + maresult, + axes=axes, + attributes=attributes, + grid=grid, + id=id, + no_update_from=True, + fill_value=F) return r1 min.__doc__ = numpy.ma.min.__doc__ -def sort (a, axis=-1): + +def sort(a, axis=-1): ta = _makeMaskedArg(a) maresult = numpy.ma.sort(a.asma(), axis) axes, attributes, id, grid = _extractMetadata(a) @@ -445,11 +509,13 @@ def sort (a, axis=-1): if (grid is not None) and (sortaxis in grid.getAxisList()): grid = None axes[axis] = TransientAxis(numpy.arange(len(sortaxis))) - F=getattr(a,"fill_value",1.e20) + F = getattr(a, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, grid=grid, id=id, fill_value=F) -sort.__doc__ = numpy.ma.sort.__doc__ + "The sort axis is replaced with a dummy axis." +sort.__doc__ = numpy.ma.sort.__doc__ + \ + "The sort axis is replaced with a dummy axis." -def choose (indices, t): + +def choose(indices, t): """Returns an array shaped like indices containing elements chosen from t. If an element of t is the special element masked, any element @@ -458,35 +524,38 @@ def choose (indices, t): The result has only the default axes. """ maresult = numpy.ma.choose(indices, map(_makeMaskedArg, t)) - F=getattr(t,"fill_value",1.e20) + F = getattr(t, "fill_value", 1.e20) return TransientVariable(maresult, fill_value=F) -def where (condition, x, y): - "where(condition, x, y) is x where condition is true, y otherwise" -## axes = commonDomain(x,y) -## grid = commonGrid(x,y,axes) + +def where(condition, x, y): + "where(condition, x, y) is x where condition is true, y otherwise" +# axes = commonDomain(x,y) +# grid = commonGrid(x,y,axes) maresult = numpy.ma.where(condition, _makeMaskedArg(x), _makeMaskedArg(y)) axes, attributes, id, grid = _extractMetadata(condition) - F=getattr(x,"fill_value",1.e20) + F = getattr(x, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, grid=grid, id=id, fill_value=F) + def masked_where(condition, x, copy=1): - """Return x as an array masked where condition is true. + """Return x as an array masked where condition is true. Also masked where x or condition masked. """ tx = _makeMaskedArg(x) tcondition = _makeMaskedArg(condition) maresult = numpy.ma.masked_where(tcondition, tx, copy) axes, attributes, id, grid = _extractMetadata(x) - F=getattr(x,"fill_value",1.e20) + F = getattr(x, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid, fill_value=F) + def masked_greater(x, value): "masked_greater(x, value) = x masked where x > value" tx = _makeMaskedArg(x) maresult = numpy.ma.masked_greater(tx, value) axes, attributes, id, grid = _extractMetadata(x) - F=getattr(x,"fill_value",1.e20) + F = getattr(x, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid, fill_value=F) @@ -495,33 +564,37 @@ def masked_greater_equal(x, value): tx = _makeMaskedArg(x) maresult = numpy.ma.masked_greater_equal(tx, value) axes, attributes, id, grid = _extractMetadata(x) - F=getattr(x,"fill_value",1.e20) + F = getattr(x, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid, fill_value=F) + def masked_less(x, value): "masked_less(x, value) = x masked where x < value" tx = _makeMaskedArg(x) maresult = numpy.ma.masked_less(tx, value) axes, attributes, id, grid = _extractMetadata(x) - F=getattr(x,"fill_value",1.e20) + F = getattr(x, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid, fill_value=F) + def masked_less_equal(x, value): "masked_less_equal(x, value) = x masked where x <= value" tx = _makeMaskedArg(x) maresult = numpy.ma.masked_less_equal(tx, value) axes, attributes, id, grid = _extractMetadata(x) - F=getattr(x,"fill_value",1.e20) + F = getattr(x, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid, fill_value=F) + def masked_not_equal(x, value): "masked_not_equal(x, value) = x masked where x != value" tx = _makeMaskedArg(x) maresult = numpy.ma.masked_not_equal(tx, value) axes, attributes, id, grid = _extractMetadata(x) - F=getattr(x,"fill_value",1.e20) + F = getattr(x, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid, fill_value=F) + def masked_equal(x, value): """masked_equal(x, value) = x masked where x == value For floating point consider masked_values(x, value) instead. @@ -529,40 +602,43 @@ def masked_equal(x, value): tx = _makeMaskedArg(x) maresult = numpy.ma.masked_equal(tx, value) axes, attributes, id, grid = _extractMetadata(x) - F=getattr(x,"fill_value",1.e20) + F = getattr(x, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid, fill_value=F) + def masked_outside(x, v1, v2): "x with mask of all values of x that are outside [v1,v2]" tx = _makeMaskedArg(x) maresult = numpy.ma.masked_outside(tx, v1, v2) axes, attributes, id, grid = _extractMetadata(x) - F=getattr(x,"fill_value",1.e20) + F = getattr(x, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid, fill_value=F) + def masked_inside(x, v1, v2): "x with mask of all values of x that are inside [v1,v2]" tx = _makeMaskedArg(x) maresult = numpy.ma.masked_inside(tx, v1, v2) axes, attributes, id, grid = _extractMetadata(x) - F=getattr(x,"fill_value",1.e20) + F = getattr(x, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid, fill_value=F) -def concatenate (arrays, axis=0, axisid=None, axisattributes=None): + +def concatenate(arrays, axis=0, axisid=None, axisattributes=None): """Concatenate the arrays along the given axis. Give the extended axis the id and attributes provided - by default, those of the first array.""" tarrays = [_makeMaskedArg(a) for a in arrays] maresult = numpy.ma.concatenate(arrays, axis=axis) - if len(arrays)>1: + if len(arrays) > 1: varattributes = None varid = None - axes = commonDomain(tarrays[0],tarrays[1],omit=axis) + axes = commonDomain(tarrays[0], tarrays[1], omit=axis) grid = commonGrid(tarrays[0], tarrays[1], axes) - for i in range(len(arrays)-2): + for i in range(len(arrays) - 2): if axes is None: break - axes = commonAxes(tarrays[i+2],axes,omit=axis) + axes = commonAxes(tarrays[i + 2], axes, omit=axis) grid = commonGrid1(a, grid, axes) else: axes = tarrays[0].getAxisList() @@ -575,32 +651,37 @@ def concatenate (arrays, axis=0, axisid=None, axisattributes=None): if axes is not None: if axisid is None: axisid = tarrays[0].getAxis(axis).id - allunitsequal=True + allunitsequal = True try: - allunits=tarrays[0].getAxis(axis).units + allunits = tarrays[0].getAxis(axis).units except: - allunits=None + allunits = None for t in tarrays[1:]: try: - tunits=t.getAxis(axis).units + tunits = t.getAxis(axis).units except: - tunits=None - if tunits!=allunits: - allunitsequal=False + tunits = None + if tunits != allunits: + allunitsequal = False if allunitsequal: if axisattributes is None: axisattributes = tarrays[0].getAxis(axis).attributes - axes[axis] = axisConcatenate([t.getAxis(axis) for t in tarrays], axisid, axisattributes) + axes[axis] = axisConcatenate( + [t.getAxis(axis) for t in tarrays], + axisid, + axisattributes) - # If the grid doesn't match the axislist (e.g., catenation was on latitude) then omit it. + # If the grid doesn't match the axislist (e.g., catenation was on + # latitude) then omit it. if grid is not None: for item in grid.getAxisList(): if item not in axes: grid = None - F=getattr(arrays[0],"fill_value",1.e20) - return TransientVariable(maresult, axes=axes, attributes=varattributes,id=varid,grid=grid, fill_value=F) + F = getattr(arrays[0], "fill_value", 1.e20) + return TransientVariable(maresult, axes=axes, attributes=varattributes, id=varid, grid=grid, fill_value=F) + -def take (a, indices, axis=None): +def take(a, indices, axis=None): "take(a, indices, axis=None) returns selection of items from a." axis = _conv_axis_arg(axis) ta = _makeMaskedArg(a) @@ -608,15 +689,16 @@ def take (a, indices, axis=None): # ma compatibility interface has a bug maresult = numpy.ma.take(ta, indices, axis=axis) axes, attributes, id, grid = _extractMetadata(a, omitall=(axis is None)) - + # If the take is on a grid axis, omit the grid. if (grid is not None) and (axes[axis] in grid.getAxisList()): grid = None if axes is not None: axes[axis] = axisTake(axes[axis], indices) - F=getattr(a,"fill_value",1.e20) + F = getattr(a, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid, fill_value=F) + def transpose(a, axes=None): "transpose(a, axes=None) reorder dimensions per tuple axes" ta = _makeMaskedArg(a) @@ -628,49 +710,53 @@ def transpose(a, axes=None): newaxes = None if oldaxes is not None: newaxes = [oldaxes[i] for i in axes] - F=getattr(a,"fill_value",1.e20) + F = getattr(a, "fill_value", 1.e20) return TransientVariable(maresult, axes=newaxes, attributes=attributes, id=id, grid=grid, copy=1, fill_value=F) + class _minimum_operation: + "Object to calculate minima" - def __init__ (self): + + def __init__(self): """minimum(a, b) or minimum(a) In one argument case returns the scalar minimum. """ pass - def __call__ (self, a, b=None): + def __call__(self, a, b=None): "Execute the call behavior." a = _makeMaskedArg(a) if b is None: m = getmask(a) - if m is nomask: + if m is nomask: d = numpy.min(filled(a).ravel()) return d -## ac = a.compressed() -## if len(ac) == 0: -## return masked +# ac = a.compressed() +# if len(ac) == 0: +# return masked else: return numpy.ma.min(a) else: return where(less(a, b), a, b)[...] - - def reduce (self, target, axis=0): + + def reduce(self, target, axis=0): """Reduce target along the given axis.""" a = _makeMaskedArg(target) axes, attributes, id, grid = _extractMetadata(a, omit=axis) m = getmask(a) if m is nomask: t = filled(a) - result = masked_array (numpy.minimum.reduce (t, axis)) + result = masked_array(numpy.minimum.reduce(t, axis)) else: - t = numpy.minimum.reduce(filled(a, numpy.ma.minimum_fill_value(a)), axis) + t = numpy.minimum.reduce( + filled(a, numpy.ma.minimum_fill_value(a)), axis) m = numpy.logical_and.reduce(m, axis) result = masked_array(t, m, fill_value(a)) return TransientVariable(result, axes=axes, copy=0, - fill_value=fill_value(a), grid=grid, id=id) + fill_value=fill_value(a), grid=grid, id=id) - def outer (self, a, b): + def outer(self, a, b): "Return the function applied to the outer product of a and b." a = _makeMaskedArg(a) b = _makeMaskedArg(b) @@ -685,47 +771,51 @@ class _minimum_operation: d = numpy.minimum.outer(filled(a), filled(b)) return TransientVariable(d, mask=m, copy=0) -minimum = _minimum_operation () - +minimum = _minimum_operation() + + class _maximum_operation: + "Object to calculate maxima" - def __init__ (self): + + def __init__(self): """maximum(a, b) or maximum(a) In one argument case returns the scalar maximum. """ pass - def __call__ (self, a, b=None): + def __call__(self, a, b=None): "Execute the call behavior." a = _makeMaskedArg(a) if b is None: m = getmask(a) - if m is nomask: + if m is nomask: d = numpy.max(filled(a).ravel()) return d -## ac = a.compressed() -## if len(ac) == 0: -## return masked +# ac = a.compressed() +# if len(ac) == 0: +# return masked else: return numpy.ma.max(a) else: return where(greater(a, b), a, b)[...] - - def reduce (self, target, axis=0): + + def reduce(self, target, axis=0): """Reduce target along the given axis.""" axes, attributes, id, grid = _extractMetadata(target, omit=axis) a = _makeMaskedArg(target) m = getmask(a) if m is nomask: t = filled(a) - return masked_array (numpy.maximum.reduce (t, axis)) + return masked_array(numpy.maximum.reduce(t, axis)) else: - t = numpy.maximum.reduce(filled(a, numpy.ma.maximum_fill_value(a)), axis) + t = numpy.maximum.reduce( + filled(a, numpy.ma.maximum_fill_value(a)), axis) m = numpy.logical_and.reduce(m, axis) return TransientVariable(t, mask=m, fill_value=fill_value(a), - axes = axes, grid=grid, id=id) + axes=axes, grid=grid, id=id) - def outer (self, a, b): + def outer(self, a, b): "Return the function applied to the outer product of a and b." a = _makeMaskedArg(a) b = _makeMaskedArg(b) @@ -740,8 +830,9 @@ class _maximum_operation: d = numpy.maximum.outer(filled(a), filled(b)) return TransientVariable(d, mask=m) -maximum = _maximum_operation () - +maximum = _maximum_operation() + + def asarray(data, typecode=None, dtype=None): """asarray(data, typecode=None, dtype=None) is equivalent to array(data, dtype=None, copy=0) Returns data if dtype is None or data is a MaskedArray of the same dtype. @@ -751,10 +842,12 @@ def asarray(data, typecode=None, dtype=None): if isinstance(data, AbstractVariable) and (dtype is None or sctype2char(dtype) == data.dtype.char): return data else: - F=getattr(data,"fill_value",1.e20) + F = getattr(data, "fill_value", 1.e20) return TransientVariable(data, dtype=dtype, copy=0, fill_value=F) -def arrayrange(start, stop=None, step=1, typecode=None, axis=None, attributes=None, id=None, dtype=None): + +def arrayrange(start, stop=None, step=1, typecode=None, + axis=None, attributes=None, id=None, dtype=None): """Just like range() except it returns a variable whose type can be specfied by the keyword argument typecode. The axis of the result variable may be specified. """ @@ -767,15 +860,19 @@ def arrayrange(start, stop=None, step=1, typecode=None, axis=None, attributes=No arange = arrayrange -def zeros (shape, typecode=float, savespace=0, axes=None, attributes=None, id=None, grid=None, dtype=None): - """zeros(n, typecode=float, savespace=0, axes=None, attributes=None, id=None) = + +def zeros(shape, typecode=float, savespace=0, axes=None, + attributes=None, id=None, grid=None, dtype=None): + """zeros(n, typecode=float, savespace=0, axes=None, attributes=None, id=None) = an array of all zeros of the given length or shape.""" dtype = _convdtype(dtype, typecode) maresult = numpy.ma.zeros(shape, dtype=dtype) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid) - -def ones (shape, typecode=float, savespace=0, axes=None, attributes=None, id=None, grid=None, dtype=None): - """ones(n, typecode=float, savespace=0, axes=None, attributes=None, id=None) = + + +def ones(shape, typecode=float, savespace=0, axes=None, + attributes=None, id=None, grid=None, dtype=None): + """ones(n, typecode=float, savespace=0, axes=None, attributes=None, id=None) = an array of all ones of the given length or shape.""" dtype = _convdtype(dtype, typecode) maresult = numpy.ma.ones(shape, dtype=dtype) @@ -783,28 +880,31 @@ def ones (shape, typecode=float, savespace=0, axes=None, attributes=None, id=Non as_masked = numpy.ma.array + def outerproduct(a, b): """outerproduct(a,b) = {a[i]*b[j]}, has shape (len(a),len(b))""" - ta = asVariable(a,writeable=1) - tb = asVariable(b,writeable=1) - maresult = numpy.ma.outerproduct(ta,tb) - axes = (ta.getAxis(0),tb.getAxis(0)) - F=getattr(a,"fill_value",1.e20) + ta = asVariable(a, writeable=1) + tb = asVariable(b, writeable=1) + maresult = numpy.ma.outerproduct(ta, tb) + axes = (ta.getAxis(0), tb.getAxis(0)) + F = getattr(a, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, fill_value=F) -def argsort (x, axis = -1, fill_value=None): + +def argsort(x, axis=-1, fill_value=None): """Treating masked values as if they have the value fill_value, return sort indices for sorting along given axis. if fill_value is None, use fill_value(x) - """ + """ tx = _makeMaskedArg(x) - maresult = numpy.ma.argsort(tx,axis=axis,fill_value=fill_value) + maresult = numpy.ma.argsort(tx, axis=axis, fill_value=fill_value) axes, attributes, id, grid = _extractMetadata(x) - F=getattr(x,"fill_value",1.e20) + F = getattr(x, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid, fill_value=F) array = TransientVariable + def repeat(a, repeats, axis=None): """repeat elements of a repeats times along axis repeats is a sequence of length a.shape[axis] @@ -818,68 +918,85 @@ def repeat(a, repeats, axis=None): grid = None if axes is not None: axes[axis] = None - F=getattr(a,"fill_value",1.e20) + F = getattr(a, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid, no_update_from=True, fill_value=F) -def reshape (a, newshape, axes=None, attributes=None, id=None, grid=None): + +def reshape(a, newshape, axes=None, attributes=None, id=None, grid=None): ignore, attributes, id, ignore = _extractMetadata(a, axes, attributes, id) if axes is not None: axesshape = [len(item) for item in axes] - if axesshape!=list(newshape): - raise CDMSError, 'axes must be shaped %s'%`newshape` + if axesshape != list(newshape): + raise CDMSError('axes must be shaped %s' % repr(newshape)) ta = _makeMaskedArg(a) maresult = numpy.ma.reshape(ta, newshape) - F=getattr(a,"fill_value",1.e20) + F = getattr(a, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid, no_update_from=True, fill_value=F) -reshape.__doc__="numpy doc: %s\naxes/attributes/grid are applied onto the new variable" % numpy.reshape.__doc__ +reshape.__doc__ = "numpy doc: %s\naxes/attributes/grid are applied onto the new variable" % numpy.reshape.__doc__ + -def resize (a, new_shape, axes=None, attributes=None, id=None, grid=None): +def resize(a, new_shape, axes=None, attributes=None, id=None, grid=None): """resize(a, new_shape) returns a new array with the specified shape. The original array's total size can be any size.""" ignore, attributes, id, ignore = _extractMetadata(a, axes, attributes, id) if axes is not None: axesshape = [len(item) for item in axes] - if axesshape!=list(new_shape): - raise CDMSError, 'axes must be shaped %s'%`newshape` + if axesshape != list(new_shape): + raise CDMSError('axes must be shaped %s' % repr(newshape)) ta = _makeMaskedArg(a) maresult = numpy.ma.resize(ta, new_shape) - F=getattr(a,"fill_value",1.e20) + F = getattr(a, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid, fill_value=F) -def masked_array (a, mask=None, fill_value=None, axes=None, attributes=None, id=None): - """masked_array(a, mask=None) = + +def masked_array(a, mask=None, fill_value=None, + axes=None, attributes=None, id=None): + """masked_array(a, mask=None) = array(a, mask=mask, copy=0, fill_value=fill_value) Use fill_value(a) if None. """ - maresult = numpy.ma.masked_array(_makeMaskedArg(a), mask=mask, fill_value=fill_value) + maresult = numpy.ma.masked_array( + _makeMaskedArg(a), + mask=mask, + fill_value=fill_value) axes, attributes, id, grid = _extractMetadata(a, axes, attributes, id) - F=getattr(a,"fill_value",1.e20) + F = getattr(a, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid, fill_value=F) -def masked_values (data, value, rtol=1.e-5, atol=1.e-8, copy=1, - savespace=0, axes=None, attributes=None, id=None): + +def masked_values(data, value, rtol=1.e-5, atol=1.e-8, copy=1, + savespace=0, axes=None, attributes=None, id=None): """ masked_values(data, value, rtol=1.e-5, atol=1.e-8) Create a masked array; mask is None if possible. May share data values with original array, but not recommended. Masked where abs(data-value)<= atol + rtol * abs(value) """ - maresult = numpy.ma.masked_values(_makeMaskedArg(data), value, rtol=rtol, atol=atol, copy=copy) + maresult = numpy.ma.masked_values( + _makeMaskedArg(data), + value, + rtol=rtol, + atol=atol, + copy=copy) axes, attributes, id, grid = _extractMetadata(data, axes, attributes, id) - F=getattr(data,"fill_value",1.e20) + F = getattr(data, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid, fill_value=F) -def masked_object (data, value, copy=1, savespace=0, axes=None, attributes=None, id=None): + +def masked_object(data, value, copy=1, + savespace=0, axes=None, attributes=None, id=None): "Create array masked where exactly data equal to value" maresult = numpy.ma.masked_object(_makeMaskedArg(data), value, copy=copy) axes, attributes, id, grid = _extractMetadata(data, axes, attributes, id) - F=getattr(data,"fill_value",1.e20) + F = getattr(data, "fill_value", 1.e20) return TransientVariable(maresult, axes=axes, attributes=attributes, id=id, grid=grid, fill_value=F) - -def isMaskedVariable (x): + + +def isMaskedVariable(x): "Is x a masked variable, that is, an instance of AbstractVariable?" return isinstance(x, AbstractVariable) + def set_default_fill_value(value_type, value): """Set the default fill value for value_type to value. value_type is a string: 'real','complex','character','integer',or 'object'. @@ -896,24 +1013,23 @@ def set_default_fill_value(value_type, value): elif value_type == 'object': numpy.ma.default_object_fill_value = value -def fromfunction (f, dimensions): + +def fromfunction(f, dimensions): """Apply f to s to create an array as in numpy.""" return TransientVariable(numpy.ma.fromfunction(f, dimensions)) -def diagonal (a, offset = 0, axis1=0, axis2 = 1): - """diagonal(a, offset=0, axis1=0, axis2 = 1) returns the given + +def diagonal(a, offset=0, axis1=0, axis2=1): + """diagonal(a, offset=0, axis1=0, axis2 = 1) returns the given diagonals defined by the two dimensions of the array. """ - F=getattr(a,"fill_value",1.e20) - return TransientVariable(numpy.ma.diagonal(_makeMaskedArg(a), - offset, axis1, axis2), fill_value=F) + F = getattr(a, "fill_value", 1.e20) + return TransientVariable(numpy.ma.diagonal(_makeMaskedArg(a), + offset, axis1, axis2), fill_value=F) -def fromstring (s, t): + +def fromstring(s, t): """Construct a masked array from a string. Result will have no mask. t is a typecode. """ - return TransientArray(numpy.ma.fromstring(s,t)) - - - - + return TransientArray(numpy.ma.fromstring(s, t)) diff --git a/Packages/cdms2/Lib/__init__.py b/Packages/cdms2/Lib/__init__.py index 874601632..e3e53ff09 100644 --- a/Packages/cdms2/Lib/__init__.py +++ b/Packages/cdms2/Lib/__init__.py @@ -2,35 +2,35 @@ CDMS module-level API """ import cdat_info -cdat_info.pingPCMDIdb("cdat","cdms2") +cdat_info.pingPCMDIdb("cdat", "cdms2") -__all__ = ["cdmsobj", "axis", "coord", "grid", "hgrid", "avariable", \ -"sliceut", "error", "variable", "fvariable", "tvariable", "dataset", \ -"database", "cache", "selectors", "MV2", "convention", "bindex", \ -"auxcoord", "gengrid", "gsHost", "gsStaticVariable", "gsTimeVariable", \ -"mvBaseWriter", "mvSphereMesh", "mvVsWriter", "mvCdmsRegrid"] +__all__ = ["cdmsobj", "axis", "coord", "grid", "hgrid", "avariable", + "sliceut", "error", "variable", "fvariable", "tvariable", "dataset", + "database", "cache", "selectors", "MV2", "convention", "bindex", + "auxcoord", "gengrid", "gsHost", "gsStaticVariable", "gsTimeVariable", + "mvBaseWriter", "mvSphereMesh", "mvVsWriter", "mvCdmsRegrid"] # Errors -from error import CDMSError +from .error import CDMSError # CDMS datatypes -from cdmsobj import CdArray, CdChar, CdByte, CdDouble, CdFloat, CdFromObject, CdInt, CdLong, CdScalar, CdShort, CdString +from .cdmsobj import CdArray, CdChar, CdByte, CdDouble, CdFloat, CdFromObject, CdInt, CdLong, CdScalar, CdShort, CdString # Functions which operate on all objects or groups of objects -from cdmsobj import Unlimited, getPathFromTemplate, matchPattern, matchingFiles, searchPattern, searchPredicate, setDebugMode +from .cdmsobj import Unlimited, getPathFromTemplate, matchPattern, matchingFiles, searchPattern, searchPredicate, setDebugMode # Axis functions and classes -from axis import AbstractAxis, axisMatches, axisMatchAxis, axisMatchIndex -from axis import createAxis, createEqualAreaAxis, createGaussianAxis, createUniformLatitudeAxis, createUniformLongitudeAxis, setAutoBounds, getAutoBounds +from .axis import AbstractAxis, axisMatches, axisMatchAxis, axisMatchIndex +from .axis import createAxis, createEqualAreaAxis, createGaussianAxis, createUniformLatitudeAxis, createUniformLongitudeAxis, setAutoBounds, getAutoBounds # Grid functions -from grid import createGenericGrid, createGlobalMeanGrid, createRectGrid, createUniformGrid, createZonalGrid, setClassifyGrids, createGaussianGrid, writeScripGrid, isGrid +from .grid import createGenericGrid, createGlobalMeanGrid, createRectGrid, createUniformGrid, createZonalGrid, setClassifyGrids, createGaussianGrid, writeScripGrid, isGrid # Dataset functions -from dataset import createDataset, openDataset, useNetcdf3, \ - getNetcdfClassicFlag, getNetcdfShuffleFlag, getNetcdfDeflateFlag, getNetcdfDeflateLevelFlag,\ +from .dataset import createDataset, openDataset, useNetcdf3, \ + getNetcdfClassicFlag, getNetcdfShuffleFlag, getNetcdfDeflateFlag, getNetcdfDeflateLevelFlag,\ setNetcdfClassicFlag, setNetcdfShuffleFlag, setNetcdfDeflateFlag, setNetcdfDeflateLevelFlag,\ - setNetcdfUseNCSwitchModeFlag,getNetcdfUseNCSwitchModeFlag,\ + setNetcdfUseNCSwitchModeFlag, getNetcdfUseNCSwitchModeFlag,\ setCompressionWarnings,\ setNetcdf4Flag, getNetcdf4Flag,\ setNetcdfUseParallelFlag, getNetcdfUseParallelFlag, \ @@ -39,31 +39,31 @@ from dataset import createDataset, openDataset, useNetcdf3, \ open = openDataset # Database functions -from database import connect, Base, Onelevel, Subtree +from .database import connect, Base, Onelevel, Subtree -#Selectors -import selectors -from selectors import longitude, latitude, time, level, required, \ - longitudeslice, latitudeslice, levelslice, timeslice +# Selectors +from . import selectors +from .selectors import longitude, latitude, time, level, required, \ + longitudeslice, latitudeslice, levelslice, timeslice -from avariable import order2index, orderparse, setNumericCompatibility, getNumericCompatibility +from .avariable import order2index, orderparse, setNumericCompatibility, getNumericCompatibility # TV -from tvariable import asVariable, createVariable, isVariable +from .tvariable import asVariable, createVariable, isVariable -from mvSphereMesh import SphereMesh -from mvBaseWriter import BaseWriter -from mvVsWriter import VsWriter -from mvVTKSGWriter import VTKSGWriter -from mvVTKUGWriter import VTKUGWriter -from mvCdmsRegrid import CdmsRegrid +from .mvSphereMesh import SphereMesh +from .mvBaseWriter import BaseWriter +from .mvVsWriter import VsWriter +from .mvVTKSGWriter import VTKSGWriter +from .mvVTKUGWriter import VTKUGWriter +from .mvCdmsRegrid import CdmsRegrid # Gridspec is not installed by default so just pass on if it isn't installed try: - from gsStaticVariable import StaticFileVariable - from gsTimeVariable import TimeFileVariable + from .gsStaticVariable import StaticFileVariable + from .gsTimeVariable import TimeFileVariable except: pass -from restApi import esgfConnection,esgfDataset,FacetConnection +from .restApi import esgfConnection, esgfDataset, FacetConnection MV = MV2 diff --git a/Packages/cdms2/Lib/auxcoord.py b/Packages/cdms2/Lib/auxcoord.py index 24a97e8c3..334831dce 100644 --- a/Packages/cdms2/Lib/auxcoord.py +++ b/Packages/cdms2/Lib/auxcoord.py @@ -4,50 +4,66 @@ CDMS 1-D auxiliary coordinates. Note: In contrast to Axis objects (concrete classes subclassed from AbstractAxis), auxiliary coordinate variables are not monotonic in value, and do not share a name with the dimension. """ -## import internattr -from error import CDMSError -from coord import AbstractCoordinateAxis -from fvariable import FileVariable -from variable import DatasetVariable -from tvariable import TransientVariable -from avariable import AbstractVariable +# import internattr +from .error import CDMSError +from .coord import AbstractCoordinateAxis +from .fvariable import FileVariable +from .variable import DatasetVariable +from .tvariable import TransientVariable +from .avariable import AbstractVariable + class AbstractAuxAxis1D(AbstractCoordinateAxis): - def __init__ (self, parent=None, variableNode=None, bounds=None): - AbstractCoordinateAxis.__init__(self, parent, variableNode, bounds=bounds) + def __init__(self, parent=None, variableNode=None, bounds=None): + AbstractCoordinateAxis.__init__( + self, + parent, + variableNode, + bounds=bounds) - def clone (self, copyData=1): + def clone(self, copyData=1): """clone (self, copyData=1) Return a copy of self as a transient axis. If copyData is 1, make a separate copy of the data.""" - result = TransientAuxAxis1D(self[:], copy=copyData, axes=self.getAxisList(), attributes=self.attributes, bounds=self.getBounds()) + result = TransientAuxAxis1D( + self[:], + copy=copyData, + axes=self.getAxisList(), + attributes=self.attributes, + bounds=self.getBounds()) return result def setBounds(self, bounds): if bounds is not None: - if len(bounds.shape)!=2: - raise CDMSError, 'Bounds must have rank=2' - if bounds.shape[0:1]!=self.shape: - raise CDMSError, 'Bounds shape %s is inconsistent with axis shape %s'%(`bounds.shape`,`self.shape`) + if len(bounds.shape) != 2: + raise CDMSError('Bounds must have rank=2') + if bounds.shape[0:1] != self.shape: + raise CDMSError( + 'Bounds shape %s is inconsistent with axis shape %s' % + (repr(bounds.shape), repr(self.shape))) AbstractCoordinateAxis.setBounds(self, bounds) - def subSlice (self, *specs, **keys): + def subSlice(self, *specs, **keys): # Take a subslice, returning a TransientAuxAxis1D avar = AbstractVariable.subSlice(self, *specs, **keys) bounds = self.getBounds() if bounds is None: newbounds = None else: - newbounds = bounds[specs] # bounds can be a numarray or DatasetVariable + newbounds = bounds[ + specs] # bounds can be a numarray or DatasetVariable - # Note: disable axis copy to preserve identity of grid and variable domains - result = TransientAuxAxis1D(avar, bounds=newbounds, copyaxes=0) + # Note: disable axis copy to preserve identity of grid and variable + # domains + result = TransientAuxAxis1D(avar, bounds=newbounds, copyaxes=0) return result + class DatasetAuxAxis1D(AbstractAuxAxis1D, DatasetVariable): # Note: node is a VariableNode + def __init__(self, parent, id=None, variableNode=None, bounds=None): AbstractAuxAxis1D.__init__(self, parent, variableNode, bounds=bounds) DatasetVariable.__init__(self, parent, id, variableNode) @@ -55,11 +71,13 @@ class DatasetAuxAxis1D(AbstractAuxAxis1D, DatasetVariable): def __repr__(self): if self.parent is not None: - return ""%(self.id, self.parent.id, `self.shape`) + return "" % (self.id, self.parent.id, repr(self.shape)) else: - return ""%self.id + return "" % self.id + +# internattr.initialize_internal_attributes(DatasetAuxAxis1D) # Copy +# internal attrs from parents -## internattr.initialize_internal_attributes(DatasetAuxAxis1D) # Copy internal attrs from parents class FileAuxAxis1D(AbstractAuxAxis1D, FileVariable): @@ -70,15 +88,18 @@ class FileAuxAxis1D(AbstractAuxAxis1D, FileVariable): def __repr__(self): if self.parent is not None: - return ""%(self.id, self.parent.id, `self.shape`) + return "" % (self.id, self.parent.id, repr(self.shape)) else: - return ""%self.id + return "" % self.id + +# internattr.initialize_internal_attributes(FileAuxAxis1D) # Copy internal +# attrs from parents -## internattr.initialize_internal_attributes(FileAuxAxis1D) # Copy internal attrs from parents class TransientAuxAxis1D(AbstractAuxAxis1D, TransientVariable): - def __init__(self, data, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, + def __init__( + self, data, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, axes=None, attributes=None, id=None, copyaxes=1, bounds=None): """Create a transient, auxiliary 1-D axis. All arguments are as for TransientVariable. @@ -86,11 +107,12 @@ class TransientAuxAxis1D(AbstractAuxAxis1D, TransientVariable): nvert is the max number of vertices per cell. """ AbstractAuxAxis1D.__init__(self, None, None, bounds=bounds) - TransientVariable.__init__(self, data, typecode=typecode, copy=copy, savespace=savespace, + TransientVariable.__init__( + self, data, typecode=typecode, copy=copy, savespace=savespace, mask=mask, fill_value=fill_value, axes=axes, attributes=attributes, id=id, copyaxes=copyaxes) if axes is not None: self.setBounds(bounds) -## internattr.initialize_internal_attributes(TransientAuxAxis1D) # Copy internal attrs from parents - +# internattr.initialize_internal_attributes(TransientAuxAxis1D) # Copy +# internal attrs from parents diff --git a/Packages/cdms2/Lib/avariable.py b/Packages/cdms2/Lib/avariable.py index db174105e..ae31c1171 100644 --- a/Packages/cdms2/Lib/avariable.py +++ b/Packages/cdms2/Lib/avariable.py @@ -1,26 +1,26 @@ -## Automatically adapted for numpy.oldnumeric Aug 01, 2007 by -## Further modified to be pure new numpy June 24th 2008 +# Automatically adapted for numpy.oldnumeric Aug 01, 2007 by +# Further modified to be pure new numpy June 24th 2008 "CDMS Variable objects, abstract interface" import numpy import re import warnings -import cdmsNode -from cdmsobj import CdmsObj +from . import cdmsNode +from .cdmsobj import CdmsObj import cdms2 -from slabinterface import Slab -from sliceut import * -from error import CDMSError -from axis import axisMatchIndex, axisMatchAxis, axisMatches, unspecified, CdtimeTypes, AbstractAxis -import selectors +from .slabinterface import Slab +from .sliceut import * +from .error import CDMSError +from .axis import axisMatchIndex, axisMatchAxis, axisMatches, unspecified, CdtimeTypes, AbstractAxis +from . import selectors import copy # from regrid2 import Regridder, PressureRegridder, CrossSectionRegridder -from mvCdmsRegrid import CdmsRegrid +from .mvCdmsRegrid import CdmsRegrid from regrid2.mvGenericRegrid import guessPeriodicity -#import PropertiedClasses -from convention import CF1 -from grid import AbstractRectGrid -#import internattr +# import PropertiedClasses +from .convention import CF1 +from .grid import AbstractRectGrid +# import internattr InvalidRegion = "Invalid region: " OutOfRange = "Coordinate interval is out of range or intersection has no data: " @@ -32,9 +32,10 @@ _numeric_compatibility = False # Backward compatibility with numpy beha # True: return 0-D arrays # MV axis=1 by default + def getMinHorizontalMask(var): """ - Get the minimum mask associated with 'x' and 'y' (i.e. with the + Get the minimum mask associated with 'x' and 'y' (i.e. with the min number of ones) across all axes @param var CDMS variable with a mask @return mask array or None if order 'x' and 'y' were not found @@ -46,7 +47,7 @@ def getMinHorizontalMask(var): shp = var.shape ndims = len(shp) - order = var.getOrder() # e.g. 'zxty-', ndims = 5 + order = var.getOrder() # e.g. 'zxty-', ndims = 5 # run a few checks numX = order.count('x') @@ -57,43 +58,43 @@ def getMinHorizontalMask(var): msg = """ Not able to locate the horizontal (y, x) axes for order = %s in getMinHorizontalMask """ % str(order) - raise CDMSError, msg - - - ps = [] # index position of x/y, e.g. [1,3] - es = [] # end indices, sizes of x/y axes + raise CDMSError(msg) + + ps = [] # index position of x/y, e.g. [1,3] + es = [] # end indices, sizes of x/y axes nonHorizShape = [] found = False - for i in range(ndims-1, -1, -1): - # iterate backwards because the horizontal + for i in range(ndims - 1, -1, -1): + # iterate backwards because the horizontal # axes are more likely to be last o = order[i] # curvilinear coordinates have '-' in place of - # x or y, also check for '-' but exit if we think + # x or y, also check for '-' but exit if we think # we found the x and y coords if not found and (o in 'xy') or (not hasXY and o == '-'): - ps = [i,] + ps - es = [shp[i],] + es + ps = [i, ] + ps + es = [shp[i], ] + es if len(ps) == 2: found = True else: - nonHorizShape = [shp[i],] + nonHorizShape + nonHorizShape = [shp[i], ] + nonHorizShape if len(ps) == 2: - # found all the horizontal axes, start with mask + # found all the horizontal axes, start with mask # set to invalid everywhere mask = numpy.ones(es, numpy.bool8) # iterate over all non-horizontal axes, there can be as # many as you want... for it in MultiArrayIter(nonHorizShape): - inds = it.getIndices() # (i0, i1, i2) + inds = it.getIndices() # (i0, i1, i2) # build the slice operator, there are three parts - # (head, middle, and tail), some parts may be + # (head, middle, and tail), some parts may be # missing # slce = 'i0,' + ':,' + 'i1,' + ':,' + 'i2,' - slce = ('%d,'*ps[0]) % tuple(inds[:ps[0]]) + ':,' \ - + ('%d,'*(ps[1]-ps[0]-1)) % tuple(inds[ps[0]:ps[1]-1]) \ - + ':,' + ('%d,'*(ndims-ps[1]-1)) % tuple(inds[ps[1]-1:]) + slce = ('%d,' * ps[0]) % tuple(inds[:ps[0]]) + ':,' \ + + ('%d,' * (ps[1] - ps[0] - 1)) % tuple(inds[ps[0]:ps[1] - 1]) \ + + ':,' + \ + ('%d,' * (ndims - ps[1] - 1)) % tuple(inds[ps[1] - 1:]) # evaluate the slice for this time, level.... mask &= eval('var.mask[' + slce + ']') return mask @@ -101,45 +102,49 @@ Not able to locate the horizontal (y, x) axes for order = %s in getMinHorizontal msg = """ Could not find all the horizontal axes for order = %s in getMinHorizontalMask """ % str(order) - raise CDMSError, msg - return None + raise CDMSError(msg) + return None + def setNumericCompatibility(mode): global _numeric_compatibility - if mode==True or mode=='on': + if mode or mode == 'on': _numeric_compatibility = True - elif mode==False or mode=='off': + elif mode == False or mode == 'off': _numeric_compatibility = False + def getNumericCompatibility(): return _numeric_compatibility + class AbstractVariable(CdmsObj, Slab): - def __init__ (self, parent=None, variableNode=None): + + def __init__(self, parent=None, variableNode=None): """Not to be called by users. variableNode is the variable tree node, if any. parent is the containing dataset instance. """ - if variableNode is not None and variableNode.tag !='variable': - raise CDMSError, 'Node is not a variable node' + if variableNode is not None and variableNode.tag != 'variable': + raise CDMSError('Node is not a variable node') CdmsObj.__init__(self, variableNode) - val = self.__cdms_internals__ + ['id','domain'] - self.___cdms_internals__ = val + val = self.__cdms_internals__ + ['id', 'domain'] + self.___cdms_internals__ = val Slab.__init__(self) self.id = None # Transient variables key on this to create a default ID self.parent = parent self._grid_ = None # Variable grid, if any - if not hasattr(self,'missing_value'): + if not hasattr(self, 'missing_value'): self.missing_value = None elif numpy.isnan(self.missing_value): - self.missing_value = None + self.missing_value = None # Reminder: children to define self.shape and set self.id - def __array__ (self, t=None, context=None): #Numeric, ufuncs call this + def __array__(self, t=None, context=None): # Numeric, ufuncs call this return numpy.ma.filled(self.getValue(squeeze=0)) - def __call__ (self, *args, **kwargs): + def __call__(self, *args, **kwargs): "Selection of a subregion using selectors" # separate options from selector specs d = kwargs.copy() @@ -152,13 +157,13 @@ class AbstractVariable(CdmsObj, Slab): s = selectors.Selector(*args, **d) # get the selection return s.unmodified_select(self, raw=raw, - squeeze=squeeze, - order=order, - grid=grid) + squeeze=squeeze, + order=order, + grid=grid) select = __call__ - def rank (self): + def rank(self): return len(self.shape) def _returnArray(self, ar, squeeze, singles=None): @@ -166,85 +171,90 @@ class AbstractVariable(CdmsObj, Slab): # job is to make sure we return an numpy.ma or a scalar. # If singles is not None, squeeze dimension indices in singles inf = 1.8e308 - if isinstance(ar,cdms2.tvariable.TransientVariable): - result = numpy.ma.array(ar._data,mask=ar.mask) - elif numpy.ma.isMaskedArray(ar): #already numpy.ma, only need squeeze. + if isinstance(ar, cdms2.tvariable.TransientVariable): + result = numpy.ma.array(ar._data, mask=ar.mask) + elif numpy.ma.isMaskedArray(ar): # already numpy.ma, only need squeeze. result = ar elif isinstance(ar, numpy.ndarray): missing = self.getMissing() if missing is None: result = numpy.ma.masked_array(ar) - elif missing==inf or missing!=missing: # (x!=x) ==> x is NaN + elif missing == inf or missing != missing: # (x!=x) ==> x is NaN result = numpy.ma.masked_object(ar, missing, copy=0) - elif ar.dtype.char=='c': + elif ar.dtype.char == 'c': # umath.equal is not implemented - resultmask = (ar==missing) + resultmask = (ar == missing) if not resultmask.any(): resultmask = numpy.ma.nomask - result = numpy.ma.masked_array(ar, mask=resultmask, fill_value=missing) + result = numpy.ma.masked_array( + ar, + mask=resultmask, + fill_value=missing) else: result = numpy.ma.masked_values(ar, missing, copy=0) elif ar is numpy.ma.masked: - return ar - else: # scalar, but it might be the missing value + return ar + else: # scalar, but it might be the missing value missing = self.getMissing() if missing is None: - return ar #scalar + return ar # scalar else: result = numpy.ma.masked_values(ar, missing, copy=0) squoze = 0 if squeeze: n = 1 - newshape=[] + newshape = [] for s in result.shape: - if s == 1: - squoze = 1 - continue - else: - n = n * s - newshape.append(s) + if s == 1: + squoze = 1 + continue + else: + n = n * s + newshape.append(s) elif singles is not None: n = 1 - newshape=[] + newshape = [] oldshape = result.shape for i in range(len(oldshape)): - if i in singles: - squoze = 1 - continue - else: - s = oldshape[i] - n = n * s - newshape.append(s) - + if i in singles: + squoze = 1 + continue + else: + s = oldshape[i] + n = n * s + newshape.append(s) + else: n = numpy.ma.size(result) if n == 1 and squeeze: - return numpy.ma.ravel(result)[0] # scalar or masked + return numpy.ma.ravel(result)[0] # scalar or masked if squoze: result.shape = newshape return result def generateGridkey(self, convention, vardict): - """ generateGridkey(): Determine if the variable is gridded, + """ generateGridkey(): Determine if the variable is gridded, and generate ((latname, lonname, order, maskname, class), lat, lon) if gridded, or (None, None, None) if not gridded. vardict is the variable dictionary of the parent""" lat, nlat = convention.getVarLatId(self, vardict) lon, nlon = convention.getVarLonId(self, vardict) if (lat is not None) and (lat is lon): - raise CDMSError, "Axis %s is both a latitude and longitude axis! Check standard_name and/or axis attributes."%lat.id + raise CDMSError( + "Axis %s is both a latitude and longitude axis! Check standard_name and/or axis attributes." % + lat.id) # Check for 2D grid if (lat is None) or (lon is None): return None, lat, lon # Check for a rectilinear grid - if isinstance(lat, AbstractAxis) and isinstance(lon, AbstractAxis) and (lat.rank()==lon.rank()==1): + if isinstance(lat, AbstractAxis) and isinstance(lon, AbstractAxis) and (lat.rank() == lon.rank() == 1): return self.generateRectGridkey(lat, lon), lat, lon # Check for a curvilinear grid: - if lat.rank()==lon.rank()==2: + if lat.rank() == lon.rank() == 2: # check that they are defined on the same indices as self vardomain = self.getAxisIds() @@ -258,7 +268,7 @@ class AbstractVariable(CdmsObj, Slab): if axisid not in vardomain: allok = 0 break - + # It's a curvilinear grid if allok: if hasattr(lat, 'maskid'): @@ -268,7 +278,7 @@ class AbstractVariable(CdmsObj, Slab): return (lat.id, lon.id, 'yx', maskid, 'curveGrid'), lat, lon # Check for a generic grid: - if lat.rank()==lon.rank()==1: + if lat.rank() == lon.rank() == 1: # check that they are defined on the same indices as self vardomain = self.getAxisIds() @@ -282,7 +292,7 @@ class AbstractVariable(CdmsObj, Slab): if axisid not in vardomain: allok = 0 break - + # It's a generic grid if allok: if hasattr(lat, 'maskid'): @@ -307,12 +317,14 @@ class AbstractVariable(CdmsObj, Slab): ilat = k k += 1 - if ilat==-1: - raise CDMSError, "Cannot find latitude axis; check standard_name and/or axis attributes" - if ilon==-1: - raise CDMSError, "Cannot find longitude axis; check standard_name and/or axis attributes" + if ilat == -1: + raise CDMSError( + "Cannot find latitude axis; check standard_name and/or axis attributes") + if ilon == -1: + raise CDMSError( + "Cannot find longitude axis; check standard_name and/or axis attributes") - if ilat0: + elif len(axes) > 0: # If forcing use of input axes, make sure they are not copied. - # Same if the grid is not rectilinear - this is when forceaxes is set. + # Same if the grid is not rectilinear - this is when forceaxes is + # set. copyaxes = (forceaxes is None) and (resultgrid is None) - result = TransientVariable(resultArray, - copy=0, - fill_value = newmissing, - axes=axes, - copyaxes = copyaxes, - grid = resultgrid, - attributes=self.attributes, - id = self.id) + result = TransientVariable(resultArray, + copy=0, + fill_value=newmissing, + axes=axes, + copyaxes=copyaxes, + grid=resultgrid, + attributes=self.attributes, + id=self.id) if grid is not None: order2 = grid.getOrder() if order is None: order = order2 elif order != order2: - raise CDMSError, 'grid, order options not compatible.' + raise CDMSError('grid, order options not compatible.') result = result.reorder(order).regrid(grid) if raw == 0: return result @@ -627,7 +653,7 @@ class AbstractVariable(CdmsObj, Slab): else: # Return numpy.ma for zero rank, so that __cmp__ works. return resultArray - def getSlice (self, *specs, **keys): + def getSlice(self, *specs, **keys): """x.getSlice takes arguments of the following forms and produces a return array. The keyword argument squeeze determines whether or not the shape of the returned array contains dimensions whose @@ -652,21 +678,21 @@ class AbstractVariable(CdmsObj, Slab): of that dimension, as in normal Python indexing. """ # Turn on squeeze and raw options by default. - keys['numericSqueeze'] = keys.get('numericSqueeze',0) - keys['squeeze'] = keys.get('squeeze',1-keys['numericSqueeze']) - keys['raw'] = keys.get('raw',1) + keys['numericSqueeze'] = keys.get('numericSqueeze', 0) + keys['squeeze'] = keys.get('squeeze', 1 - keys['numericSqueeze']) + keys['raw'] = keys.get('raw', 1) keys['order'] = keys.get('order', None) keys['grid'] = keys.get('grid', None) isitem = keys.get('isitem', 0) result = self.subSlice(*specs, **keys) # return a scalar for 0-D slices - if isitem and result.size==1 and (not _numeric_compatibility) and not result.mask.item(): + if isitem and result.size == 1 and (not _numeric_compatibility) and not result.mask.item(): result = result.item() return result def expertSlice(self, slicelist): - raise CDMSError, NotImplemented + 'expertSlice' + raise CDMSError(NotImplemented + 'expertSlice') def getRegion(self, *specs, **keys): """getRegion @@ -702,65 +728,67 @@ class AbstractVariable(CdmsObj, Slab): """ # By default, squeeze and raw options are on - keys['squeeze'] = keys.get ('squeeze', 1) - keys['raw'] = keys.get('raw',1) + keys['squeeze'] = keys.get('squeeze', 1) + keys['raw'] = keys.get('raw', 1) keys['order'] = keys.get('order', None) keys['grid'] = keys.get('grid', None) return self.subRegion(*specs, **keys) - def subRegion (self, *specs, **keys): + def subRegion(self, *specs, **keys): - speclist = self._process_specs (specs, keys) - slicelist = self.reg_specs2slices (speclist) + speclist = self._process_specs(specs, keys) + slicelist = self.reg_specs2slices(speclist) - squeeze = keys.get ('squeeze', 0) - raw = keys.get('raw',0) + squeeze = keys.get('squeeze', 0) + raw = keys.get('raw', 0) order = keys.get('order', None) grid = keys.get('grid', None) - raweasy = raw==1 and order is None and grid is None + raweasy = raw == 1 and order is None and grid is None if grid is not None and order is None: order = grid.getOrder() - # Check if any slice wraps around. wrapdim = -1 - + axes = [] circulardim = None - + for idim in range(len(slicelist)): item = slicelist[idim] axis = self.getAxis(idim) axislen = len(axis) - if(axis.isCircular()): circulardim=idim + if(axis.isCircular()): + circulardim = idim - wraptest1 = ( axis.isCircular() and speclist[idim] != unspecified) + wraptest1 = (axis.isCircular() and speclist[idim] != unspecified) start, stop = item.start, item.stop - wraptest2 = not ((start is None or (0<=start= 0: - raise CDMSError, "Too many dimensions wrap around." + raise CDMSError("Too many dimensions wrap around.") wrapdim = idim break - + else: # No wraparound, just read the data - # redo the speclist -> slice if passed circular test but not wrapped test + # redo the speclist -> slice if passed circular test but not + # wrapped test if(circulardim is not None): - slicelist = self.reg_specs2slices (speclist,force=circulardim) - - d = {'raw':raw, - 'squeeze':squeeze, - 'order':order, - 'grid':grid, - } + slicelist = self.reg_specs2slices(speclist, force=circulardim) + + d = {'raw': raw, + 'squeeze': squeeze, + 'order': order, + 'grid': grid, + } return self.subSlice(*slicelist, **d) # @@ -775,11 +803,11 @@ class AbstractVariable(CdmsObj, Slab): # shift the wrap slice to the positive side and calc number of cycles shifted # - wb=wrapslice.start - we=wrapslice.stop - ws=wrapslice.step - size=length - cycle=self.getAxis(wrapdim).getModulo() + wb = wrapslice.start + we = wrapslice.stop + ws = wrapslice.step + size = length + cycle = self.getAxis(wrapdim).getModulo() # # ncycle: @@ -789,92 +817,93 @@ class AbstractVariable(CdmsObj, Slab): # ncyclesrev: # resetting the world coordinate for reversed direction # - - ncycles=0 - ncyclesrev=0 - - if(ws>0): - - if(wb>0): - ncycles=1 - while(wb>=0): - wb=wb-size - we=we-size - ncycles=ncycles-1 + + ncycles = 0 + ncyclesrev = 0 + + if(ws > 0): + + if(wb > 0): + ncycles = 1 + while(wb >= 0): + wb = wb - size + we = we - size + ncycles = ncycles - 1 else: - ncycles=0 - while(wb<0): - wb=wb+size - we=we+size - ncycles=ncycles+1 - + ncycles = 0 + while(wb < 0): + wb = wb + size + we = we + size + ncycles = ncycles + 1 + if(wb < 0): - wb=wb+size - we=we+size - + wb = wb + size + we = we + size + # reversed direction - + else: # do the ncycles for resetting world coordinate - wbrev=wb - werev=we - werevNoneTest=0 + wbrev = wb + werev = we + werevNoneTest = 0 if(werev is None): - werev=0 - werevNoneTest=1 + werev = 0 + werevNoneTest = 1 - ncycleRevStart=1 + ncycleRevStart = 1 if(wbrev > 0): - ncyclesrev=ncycleRevStart - while(wbrev>=0): - wbrev=wbrev-size - werev=werev-size - ncyclesrev=ncyclesrev-1 + ncyclesrev = ncycleRevStart + while(wbrev >= 0): + wbrev = wbrev - size + werev = werev - size + ncyclesrev = ncyclesrev - 1 else: - ncyclesrev=0 - while(wbrev<0): - wbrev=wbrev+size - werev=werev+size - ncyclesrev=ncyclesrev+1 + ncyclesrev = 0 + while(wbrev < 0): + wbrev = wbrev + size + werev = werev + size + ncyclesrev = ncyclesrev + 1 while(werev < 0): - wbrev=wbrev+size - werev=werev+size + wbrev = wbrev + size + werev = werev + size # number of cycles to make the slice positive - while( we<0 and we != None ): - wb=wb+size - we=we+size - ncycles=ncycles+1 - - wb=wbrev - we=werev - if(werevNoneTest): we=None - - wrapslice=slice(wb,we,ws) - + while(we < 0 and we is not None): + wb = wb + size + we = we + size + ncycles = ncycles + 1 + + wb = wbrev + we = werev + if(werevNoneTest): + we = None + + wrapslice = slice(wb, we, ws) + # # calc the actual positive slices and create data array # - donew=1 + donew = 1 if(donew): wraps = splitSliceExt(wrapslice, length) - for kk in range(0,len(wraps)): - sl=wraps[kk] - + for kk in range(0, len(wraps)): + sl = wraps[kk] + slicelist[wrapdim] = sl if(kk == 0): ar1 = self.getSlice(squeeze=0, *slicelist) - result=ar1 + result = ar1 else: ar2 = self.getSlice(squeeze=0, *slicelist) - result = numpy.ma.concatenate((result,ar2),axis=wrapdim) + result = numpy.ma.concatenate((result, ar2), axis=wrapdim) else: @@ -883,8 +912,7 @@ class AbstractVariable(CdmsObj, Slab): ar1 = self.getSlice(squeeze=0, *slicelist) slicelist[wrapdim] = wrap2 ar2 = self.getSlice(squeeze=0, *slicelist) - result = numpy.ma.concatenate((ar1,ar2),axis=wrapdim) - + result = numpy.ma.concatenate((ar1, ar2), axis=wrapdim) if raweasy: return self._returnArray(result, squeeze) @@ -895,26 +923,28 @@ class AbstractVariable(CdmsObj, Slab): # #---------------------------------------------------------------------- - wrapspec=speclist[wrapdim] - + wrapspec = speclist[wrapdim] + axes = [] for i in range(self.rank()): - if squeeze and numpy.ma.size(result, i) == 1: continue + if squeeze and numpy.ma.size(result, i) == 1: + continue sl = slicelist[i] if i == wrapdim: axis = self.getAxis(i).subAxis(wb, we, ws) - + if(ws > 0): - delta_beg_wrap_dimvalue = ncycles*cycle + delta_beg_wrap_dimvalue = ncycles * cycle else: - delta_beg_wrap_dimvalue = ncyclesrev*cycle + delta_beg_wrap_dimvalue = ncyclesrev * cycle axis.setBounds(axis.getBounds() - delta_beg_wrap_dimvalue) - - axis[:]= (axis[:] - delta_beg_wrap_dimvalue).astype(axis.typecode()) + + axis[:] = (axis[:] - delta_beg_wrap_dimvalue).astype( + axis.typecode()) else: axis = self.getAxis(i).subaxis(sl.start, sl.stop, sl.step) @@ -922,18 +952,18 @@ class AbstractVariable(CdmsObj, Slab): result = self._returnArray(result, squeeze) result = TransientVariable(result, - copy=0, - fill_value = self.missing_value, - axes=axes, - attributes=self.attributes, - id = self.id) + copy=0, + fill_value=self.missing_value, + axes=axes, + attributes=self.attributes, + id=self.id) if grid is not None: order2 = grid.getOrder() if order is None: order = order2 elif order != order2: - raise CDMSError, 'grid, order options not compatible.' - + raise CDMSError('grid, order options not compatible.') + result = result.reorder(order).regrid(grid) if raw == 0: return result @@ -943,22 +973,22 @@ class AbstractVariable(CdmsObj, Slab): def getValue(self, squeeze=1): """Return the entire set of values.""" return self.getSlice(Ellipsis, squeeze=squeeze) - - def assignValue(self,data): - raise CDMSError, NotImplemented + 'assignValue' - def reorder (self, order): + def assignValue(self, data): + raise CDMSError(NotImplemented + 'assignValue') + + def reorder(self, order): """return self reordered per the specification order""" - if order is None: + if order is None: return self axes = self.getAxisList() permutation = order2index(axes, order) if permutation == range(len(axes)): return self - return MV.transpose (self, permutation) + return MV.transpose(self, permutation) - def regrid (self, togrid, missing=None, order=None, mask=None, **keywords): - """return self regridded to the new grid. + def regrid(self, togrid, missing=None, order=None, mask=None, **keywords): + """return self regridded to the new grid. One can use the regrid2.Regridder optional arguments as well. Example: @@ -973,48 +1003,49 @@ class AbstractVariable(CdmsObj, Slab): @param keywords optional keyword arguments dependent on regridTool @return regridded variable """ - # there is a circular dependency between cdms2 and regrid2. In + # there is a circular dependency between cdms2 and regrid2. In # principle, cdms2 files should not import regrid2, we're bending # rules here... import regrid2 from regrid2 import Horizontal - if togrid is None: + if togrid is None: return self else: - fromgrid = self.getGrid() # this returns the horizontal grid only + fromgrid = self.getGrid() # this returns the horizontal grid only # default w/o bounds - regridTool = 'libcf' + regridTool = 'libcf' regridMethod = 'linear' - if self.getAxis(-1).attributes.has_key('topology'): + if 'topology' in self.getAxis(-1).attributes: if self.getAxis(-1).attributes['topology'] == 'circular': # for the ESMF regridders - keywords['periodicity'] = guessPeriodicity(self.getAxis(-1).getBounds()) + keywords['periodicity'] = guessPeriodicity( + self.getAxis(-1).getBounds()) keywords['mkCyclic'] = 1 # for LibCF regridder # check if there are bounds and we have esmf - if fromgrid.getBounds() is not None and hasattr(regrid2,"ESMFRegrid"): + if fromgrid.getBounds() is not None and hasattr(regrid2, "ESMFRegrid"): regridTool = 'esmf' regridMethod = 'linear' # Hum ok if only 1 longitude regrid fails, let's check - if len(togrid.getLongitude())==1: - # esmf can't deal with this - regridTool = "regrid2" + if len(togrid.getLongitude()) == 1: + # esmf can't deal with this + regridTool = "regrid2" # let user override userSpecifiesMethod = False for rm in 'rm', 'method', 'regridmethod', 'regrid_method', 'regridMethod': - if keywords.has_key(rm): + if rm in keywords: regridMethod = keywords[rm] del keywords[rm] userSpecifiesMethod = True userSpecifiesTool = False for rt in 'rt', 'tool', 'regridtool', 'regrid_tool', 'regridTool': - if keywords.has_key(rt): + if rt in keywords: regridTool = keywords[rt] del keywords[rt] userSpecifiesTool = True @@ -1027,8 +1058,8 @@ class AbstractVariable(CdmsObj, Slab): # make sure the tool can do it if re.search('^regrid', regridTool, re.I) is not None and \ - ( len(fromgrid.getLatitude().shape) > 1 or \ - len(togrid.getLatitude().shape) > 1 ): + (len(fromgrid.getLatitude().shape) > 1 or + len(togrid.getLatitude().shape) > 1): message = """ avariable.regrid: regrid2 cannot do curvilinear, will switch to esmf..." """ @@ -1038,7 +1069,7 @@ avariable.regrid: regrid2 cannot do curvilinear, will switch to esmf..." if re.search('esmf', regridTool, re.I): # make sure source grids have bounds haveBounds = True - for g in fromgrid,: + for g in fromgrid, : for c in g.getLatitude(), g.getLongitude(): haveBounds &= (c.getBounds() is not None) if not haveBounds: @@ -1048,19 +1079,18 @@ avariable.regrid: regridTool = 'esmf' requires bounds for source grid, will swit warnings.warn(message, Warning) regridTool = 'libcf' regridMethod = 'linear' - if not hasattr(regrid2,"ESMFRegrid"): - message = """ + if not hasattr(regrid2, "ESMFRegrid"): + message = """ avariable.regrid: regridTool = 'esmf' but your version does not seems to be built with esmf, will switch to regridTool = 'libcf' """ - warnings.warn(message, Warning) - regridTool = 'libcf' - regridMethod = 'linear' - + warnings.warn(message, Warning) + regridTool = 'libcf' + regridMethod = 'linear' if re.search('conserv', regridMethod, re.I): # make sure destination grid has bounds haveBounds = True - for g in togrid,: + for g in togrid, : for c in g.getLatitude(), g.getLongitude(): haveBounds &= (c.getBounds() is not None) if not haveBounds: @@ -1074,47 +1104,48 @@ avariable.regrid: regridMethod = 'conserve' requires bounds for destination grid message = """ avariable.regrid: We chose regridTool = %s for you among the following choices: Tools -> 'regrid2' (old behavior) - 'esmf' (conserve, patch, linear) or + 'esmf' (conserve, patch, linear) or 'libcf' (linear)""" % regridTool warnings.warn(message, Warning) if not userSpecifiesMethod and re.search('^regrid', regridTool, re.I) is None: message = """ -avariable.regrid: We chose regridMethod = %s for you among the following choices: +avariable.regrid: We chose regridMethod = %s for you among the following choices: 'conserve' or 'linear' or 'patch'""" % regridMethod warnings.warn(message, Warning) if re.search('^regrid', regridTool, re.I): - if keywords.has_key('diag') and \ + if 'diag' in keywords and \ isinstance(keywords['diag'], dict): keywords['diag']['regridTool'] = 'regrid' # the original cdms2 regridder regridf = Horizontal(fromgrid, togrid) - return regridf(self, missing=missing, order=order, + return regridf(self, missing=missing, order=order, mask=mask, **keywords) # emsf or libcf... srcGridMask = None # set the source mask if a mask is defined with the source data - if numpy.any(self.mask == True): + if numpy.any(self.mask): srcGridMask = getMinHorizontalMask(self) # compute the interpolation weights - ro = CdmsRegrid(fromgrid, togrid, - dtype = self.dtype, - regridMethod = regridMethod, - regridTool = regridTool, - srcGridMask = srcGridMask, - srcGridAreas = None, - dstGridMask = None, - dstGridAreas = None, + ro = CdmsRegrid(fromgrid, togrid, + dtype=self.dtype, + regridMethod=regridMethod, + regridTool=regridTool, + srcGridMask=srcGridMask, + srcGridAreas=None, + dstGridMask=None, + dstGridAreas=None, **keywords) # now interpolate return ro(self, **keywords) - def pressureRegrid (self, newLevel, missing=None, order=None, method="log"): + def pressureRegrid( + self, newLevel, missing=None, order=None, method="log"): """Return the variable regridded to new pressure levels. The variable should be a function of lat, lon, pressure, and (optionally) time. is an axis of the result pressure levels. @@ -1126,12 +1157,13 @@ avariable.regrid: We chose regridMethod = %s for you among the following choices fromlevel = self.getLevel() if fromlevel is None: - raise CDMSError, 'No pressure level' + raise CDMSError('No pressure level') pregridf = PressureRegridder(fromlevel, newLevel) result = pregridf(self, missing=missing, order=order, method=method) return result - def crossSectionRegrid(self, newLevel, newLatitude, missing=None, order=None, method="log"): + def crossSectionRegrid( + self, newLevel, newLatitude, missing=None, order=None, method="log"): """Return the variable regridded to new pressure levels and latitudes. The variable should be a function of lat, level, and (optionally) time. is an axis of the result pressure levels. @@ -1145,14 +1177,18 @@ avariable.regrid: We chose regridMethod = %s for you among the following choices fromlevel = self.getLevel() fromlat = self.getLatitude() if fromlevel is None: - raise CDMSError, 'No pressure level' + raise CDMSError('No pressure level') if fromlat is None: - raise CDMSError, 'No latitude level' - xregridf = CrossSectionRegridder(fromlat, newLatitude, fromlevel, newLevel) + raise CDMSError('No latitude level') + xregridf = CrossSectionRegridder( + fromlat, + newLatitude, + fromlevel, + newLevel) result = xregridf(self, missing=missing, order=order, method=method) return result - def _process_specs (self, specs, keys): + def _process_specs(self, specs, keys): """Process the arguments for a getSlice, getRegion, etc. Returns an array of specifications for all dimensions. Any Ellipsis has been eliminated. @@ -1163,36 +1199,39 @@ avariable.regrid: We chose regridMethod = %s for you among the following choices if Ellipsis in specs: nellipses = 1 elif numpy.newaxis in specs: - raise CDMSError, 'Sorry, you cannot use NewAxis in this context ' + str(specs) + raise CDMSError( + 'Sorry, you cannot use NewAxis in this context ' + str(specs)) else: nellipses = 0 - if nsupplied-nellipses > myrank: - raise CDMSError, InvalidRegion + \ - "too many dimensions: %d, for variable %s"%(len(specs),self.id) + if nsupplied - nellipses > myrank: + raise CDMSError(InvalidRegion + + "too many dimensions: %d, for variable %s" % (len(specs), self.id)) - speclist = [unspecified]*myrank + speclist = [unspecified] * myrank i = 0 j = 0 while i < nsupplied: if specs[i] is Ellipsis: - j = myrank - (nsupplied - (i+1)) + j = myrank - (nsupplied - (i + 1)) else: - speclist[j] = specs[i] - j = j + 1 + speclist[j] = specs[i] + j = j + 1 i = i + 1 for k, v in keys.items(): - if k in ['squeeze','raw','grid','order']: + if k in ['squeeze', 'raw', 'grid', 'order']: continue i = self.getAxisIndex(k) if i >= 0: if speclist[i] is not unspecified: - raise CDMSError, 'Conflict between specifier %s and %s'%(`speclist[i]`,`keys`) + raise CDMSError( + 'Conflict between specifier %s and %s' % + (repr(speclist[i]), repr(keys))) speclist[i] = v return speclist - def _single_specs (self, specs): + def _single_specs(self, specs): """Return a list of dimension indices where the spec is an index.""" myrank = self.rank() nsupplied = len(specs) @@ -1201,7 +1240,7 @@ avariable.regrid: We chose regridMethod = %s for you among the following choices singles = [] while i < nsupplied: if specs[i] is Ellipsis: - j = myrank - (nsupplied - (i+1)) + j = myrank - (nsupplied - (i + 1)) else: if isinstance(specs[i], int): singles.append(j) @@ -1209,7 +1248,7 @@ avariable.regrid: We chose regridMethod = %s for you among the following choices i = i + 1 return singles - def specs2slices (self, speclist, force=None): + def specs2slices(self, speclist, force=None): """Create an equivalent list of slices from an index specification An index specification is a list of acceptable items, which are -- an integer @@ -1220,22 +1259,22 @@ avariable.regrid: We chose regridMethod = %s for you among the following choices The size of the speclist must be self.rank() """ if len(speclist) != self.rank(): - raise CDMSError, "Incorrect length of speclist in specs2slices." + raise CDMSError("Incorrect length of speclist in specs2slices.") slicelist = [] for i in range(self.rank()): key = speclist[i] if isinstance(key, int): # x[i] - slicelist.append (slice(key,key+1)) - elif isinstance(key, slice): # x[i:j:k] + slicelist.append(slice(key, key + 1)) + elif isinstance(key, slice): # x[i:j:k] slicelist.append(key) elif key is unspecified or key is None or key == ':': - slicelist.append (slice(0, len(self.getAxis(i)))) + slicelist.append(slice(0, len(self.getAxis(i)))) elif key is Ellipsis: - raise CDMSError, "Misuse of ellipsis in specification." + raise CDMSError("Misuse of ellipsis in specification.") elif isinstance(key, tuple): slicelist.append(slice(*key)) else: - raise CDMSError, 'invalid index: %s'% str(key) + raise CDMSError('invalid index: %s' % str(key)) # Change default or negative start, stop to positive for i in range(self.rank()): axis = self.getAxis(i) @@ -1246,86 +1285,106 @@ avariable.regrid: We chose regridMethod = %s for you among the following choices # # allow negative indices in a wrapped (isCircular() = 1) axis # - circular=(axis.isCircular() and force is None) + circular = (axis.isCircular() and force is None) altered = 0 - if step is None: + if step is None: altered = 1 - step=1 + step = 1 - if ( ( start is None or stop is None or start<0 or stop<0 ) and ( circular == 0 ) ): + if ((start is None or stop is None or start < 0 or stop < 0) and (circular == 0)): altered = 1 adjustit = 1 - if step>0: - if start is None: - start=0 - if stop is None: - stop=length - if start==-1 and stop==0: - stop=length + if step > 0: + if start is None: + start = 0 + if stop is None: + stop = length + if start == -1 and stop == 0: + stop = length else: - if start is None: - start=length-1 + if start is None: + start = length - 1 if stop is None: # stop=-1 adjustit = 0 - if start<0: - start=start%length - if stop<0 and adjustit: - stop=stop%length - if altered: + if start < 0: + start = start % length + if stop < 0 and adjustit: + stop = stop % length + if altered: slicelist[i] = slice(start, stop, step) return slicelist - def reg_specs2slices(self, initspeclist,force=None): + def reg_specs2slices(self, initspeclist, force=None): # Don't use input to store return value - speclist=copy.copy(initspeclist) + speclist = copy.copy(initspeclist) for i in range(self.rank()): item = speclist[i] if isinstance(item, slice): newitem = item - elif item==':' or item is None or item is unspecified: + elif item == ':' or item is None or item is unspecified: axis = self.getAxis(i) - newitem = slice(0,len(axis)) + newitem = slice(0, len(axis)) elif isinstance(item, list) or \ - isinstance(item, tuple): + isinstance(item, tuple): axis = self.getAxis(i) - if len(item)==2: # (start,end) + if len(item) == 2: # (start,end) indexInterval = axis.mapIntervalExt(item) - elif len(item)==3: # (start,end,'xxx') - coordInterval = (item[0],item[1]) - indexInterval = axis.mapIntervalExt(coordInterval,item[2]) - elif len(item)==4: - coordInterval = (item[0],item[1]) - indexInterval = axis.mapIntervalExt(coordInterval,item[2],item[3]) - elif len(item)==5: - coordInterval = (item[0],item[1]) - indexInterval = axis.mapIntervalExt(coordInterval,item[2],item[3],item[4]) - elif len(item)==6: - coordInterval = (item[0],item[1]) - indexInterval = axis.mapIntervalExt(coordInterval,item[2],item[3],item[4],item[5]) + elif len(item) == 3: # (start,end,'xxx') + coordInterval = (item[0], item[1]) + indexInterval = axis.mapIntervalExt(coordInterval, item[2]) + elif len(item) == 4: + coordInterval = (item[0], item[1]) + indexInterval = axis.mapIntervalExt( + coordInterval, item[2], item[3]) + elif len(item) == 5: + coordInterval = (item[0], item[1]) + indexInterval = axis.mapIntervalExt( + coordInterval, + item[2], + item[3], + item[4]) + elif len(item) == 6: + coordInterval = (item[0], item[1]) + indexInterval = axis.mapIntervalExt( + coordInterval, + item[2], + item[3], + item[4], + item[5]) else: - raise CDMSError, InvalidRegion + "invalid format for coordinate interval: %s"%str(item) + raise CDMSError( + InvalidRegion + "invalid format for coordinate interval: %s" % + str(item)) if indexInterval is None: - raise CDMSError, OutOfRange + str(item) - newitem = slice(indexInterval[0],indexInterval[1],indexInterval[2]) + raise CDMSError(OutOfRange + str(item)) + newitem = slice( + indexInterval[0], + indexInterval[1], + indexInterval[2]) elif isinstance(item, (numpy.floating, float, numpy.integer, int, long, basestring)) or type(item) in CdtimeTypes: axis = self.getAxis(i) # # default is 'ccn' in axis.mapIntervalExt # - indexInterval = axis.mapIntervalExt((item,item)) + indexInterval = axis.mapIntervalExt((item, item)) if indexInterval is None: - raise CDMSError, OutOfRange + str(item) - newitem = slice(indexInterval[0],indexInterval[1],indexInterval[2]) + raise CDMSError(OutOfRange + str(item)) + newitem = slice( + indexInterval[0], + indexInterval[1], + indexInterval[2]) else: - raise CDMSError, InvalidRegion + "invalid format for coordinate interval: %s"%str(item) + raise CDMSError( + InvalidRegion + "invalid format for coordinate interval: %s" % + str(item)) speclist[i] = newitem - slicelist = self.specs2slices(speclist,force) + slicelist = self.specs2slices(speclist, force) return slicelist def _decodedType(self): @@ -1340,7 +1399,7 @@ avariable.regrid: We chose regridMethod = %s for you among the following choices def isEncoded(self): "True iff self is represented as packed data." - return (hasattr(self,"scale_factor") or hasattr(self,"add_offset")) + return (hasattr(self, "scale_factor") or hasattr(self, "add_offset")) def decode(self, ar): "Decode compressed data. ar is a masked array, scalar, or numpy.ma.masked" @@ -1348,18 +1407,20 @@ avariable.regrid: We chose regridMethod = %s for you among the following choices if hasattr(self, 'scale_factor'): scale_factor = self.scale_factor else: - scale_factor = numpy.array([1.0],resulttype) - + scale_factor = numpy.array([1.0], resulttype) + if hasattr(self, 'add_offset'): add_offset = self.add_offset else: - add_offset = numpy.array([0.0],resulttype) - + add_offset = numpy.array([0.0], resulttype) + if ar is not numpy.ma.masked: - result = scale_factor*ar + add_offset - if isinstance(result,numpy.ma.MaskedArray): + result = scale_factor * ar + add_offset + if isinstance(result, numpy.ma.MaskedArray): result = result.astype(resulttype) - numpy.ma.set_fill_value(result, numpy.ma.default_fill_value(0.)) + numpy.ma.set_fill_value( + result, + numpy.ma.default_fill_value(0.)) else: tmp = numpy.array(result) result = tmp.astype(resulttype)[0] @@ -1381,7 +1442,9 @@ avariable.regrid: We chose regridMethod = %s for you among the following choices result.append(j) break else: - raise CDMSError, 'Variable and grid do not share common dimensions: %s'%self.id + raise CDMSError( + 'Variable and grid do not share common dimensions: %s' % + self.id) return tuple(result) @@ -1391,106 +1454,109 @@ avariable.regrid: We chose regridMethod = %s for you among the following choices if isinstance(key, tuple): speclist = self._process_specs(key, {}) else: - if isinstance(key, int) and key>=len(self): - raise IndexError, "Index too large: %d"%key + if isinstance(key, int) and key >= len(self): + raise IndexError("Index too large: %d" % key) speclist = self._process_specs([key], {}) # Note: raw=0 ensures that a TransientVariable is returned return self.getSlice(numericSqueeze=1, raw=0, isitem=1, *speclist) - + def __getslice__(self, low, high): # Note: raw=0 ensures that a TransientVariable is returned - return self.getSlice (slice(low, high), numericSqueeze = 1, raw=0) + return self.getSlice(slice(low, high), numericSqueeze=1, raw=0) def typecode(self): - raise CDMSError, NotImplemented + 'typecode' + raise CDMSError(NotImplemented + 'typecode') - def __abs__(self): + def __abs__(self): return MV.absolute(self) - def __neg__(self): + def __neg__(self): return MV.negative(self) def __add__(self, other): return MV.add(self, other) - + __radd__ = __add__ - def __lshift__ (self, n): + def __lshift__(self, n): return MV.left_shift(self, n) - def __rshift__ (self, n): + def __rshift__(self, n): return MV.right_shift(self, n) - - def __sub__(self, other): + + def __sub__(self, other): return MV.subtract(self, other) - def __rsub__(self, other): + def __rsub__(self, other): return MV.subtract(other, self) def __mul__(self, other): return MV.multiply(self, other) - + __rmul__ = __mul__ - def __div__(self, other): + def __div__(self, other): return MV.divide(self, other) - def __rdiv__(self, other): + def __rdiv__(self, other): return MV.divide(other, self) - def __pow__(self,other, third=None): + def __pow__(self, other, third=None): return MV.power(self, other, third) - def __iadd__(self, other): + def __iadd__(self, other): "Add other to self in place." return MV.add(self, other) # See if we can improve these later. - def __isub__(self, other): + def __isub__(self, other): "Subtract other from self in place." return MV.subtract(self, other) # See if we can improve these later. - def __imul__(self, other): + def __imul__(self, other): "Multiply self by other in place." return MV.multiply(self, other) # See if we can improve these later. - def __idiv__(self, other): + def __idiv__(self, other): "Divide self by other in place." return MV.divide(self, other) # See if we can improve these later. - def __eq__(self,other): - return MV.equal(self,other) + def __eq__(self, other): + return MV.equal(self, other) - def __ne__(self,other): - return MV.not_equal(self,other) + def __ne__(self, other): + return MV.not_equal(self, other) - def __lt__(self,other): - return MV.less(self,other) + def __lt__(self, other): + return MV.less(self, other) - def __le__(self,other): - return MV.less_equal(self,other) + def __le__(self, other): + return MV.less_equal(self, other) - def __gt__(self,other): - return MV.greater(self,other) + def __gt__(self, other): + return MV.greater(self, other) - def __ge__(self,other): - return MV.greater_equal(self,other) + def __ge__(self, other): + return MV.greater_equal(self, other) - def __sqrt__(self): + def __sqrt__(self): return MV.sqrt(self) - def astype (self, tc): + def astype(self, tc): "return self as array of given type." return self.subSlice().astype(tc) - -## internattr.add_internal_attribute(AbstractVariable, 'id', 'parent') -#PropertiedClasses.set_property(AbstractVariable, 'missing_value', acts=AbstractVariable._setmissing, nodelete=1) + +# internattr.add_internal_attribute(AbstractVariable, 'id', 'parent') +# PropertiedClasses.set_property(AbstractVariable, 'missing_value', +# acts=AbstractVariable._setmissing, nodelete=1) __rp = r'\s*([-txyz0-9]{1,1}|\(\s*\w+\s*\)|[.]{3,3})\s*' __crp = re.compile(__rp) -def orderparse (order): + + +def orderparse(order): """Parse an order string. Returns a list of axes specifiers. Order elements can be: Letters t, x, y, z meaning time, longitude, latitude, level @@ -1501,13 +1567,14 @@ def orderparse (order): (name) meaning an axis whose id is name """ if not isinstance(order, basestring): - raise CDMSError, 'order arguments must be strings.' + raise CDMSError('order arguments must be strings.') pos = 0 - result=[] + result = [] order = order.strip() while pos < len(order): m = __crp.match(order, pos) - if m is None: break + if m is None: + break r = m.group(1) if r[0] == '(': pass @@ -1520,11 +1587,12 @@ def orderparse (order): pos = m.end(0) if pos != len(order): - raise CDMSError, 'Order string "' + order + \ - '" malformed, index '+str(pos) + raise CDMSError('Order string "' + order + + '" malformed, index ' + str(pos)) return result -def order2index (axes, order): + +def order2index(axes, order): """Find the index permutation of axes to match order. The argument order is a string. Order elements can be: @@ -1540,22 +1608,23 @@ def order2index (axes, order): elif isinstance(order, list): result = order else: - raise CDMSError, 'order2index, order specified of bad type:' + str(type(order)) + raise CDMSError( + 'order2index, order specified of bad type:' + str(type(order))) n = len(axes) ie = n - permutation = [None]*n + permutation = [None] * n j = 0 pos = 0 while j < len(result): item = result[j] if isinstance(item, basestring): - if item == 't': + if item == 't': spec = 'time' - elif item == 'x': + elif item == 'x': spec = 'longitude' - elif item == 'y': + elif item == 'y': spec = 'latitude' - elif item == 'z': + elif item == 'z': spec = 'level' elif item == '-': pos += 1 @@ -1566,25 +1635,26 @@ def order2index (axes, order): for k in range(n): if axisMatches(axes[k], spec): if k in permutation: - raise CDMSError, 'Duplicate item in order %s' % order + raise CDMSError('Duplicate item in order %s' % order) permutation[pos] = k pos += 1 break else: - raise CDMSError, 'No axis matching order spec %s' %str(item) + raise CDMSError('No axis matching order spec %s' % str(item)) elif isinstance(item, int): if item in permutation: - raise CDMSError, 'Duplicate item in order %s' % order + raise CDMSError('Duplicate item in order %s' % order) if item >= n: - raise CDMSError, 'Index %d out of range in order %s' %\ - (item,order) + raise CDMSError('Index %d out of range in order %s' % + (item, order)) permutation[pos] = item pos += 1 elif item is Ellipsis: nleft = len(result) - j - 1 pos = n - nleft else: - raise CDMSError, 'List specified for order contains bad item: ' + repr(item) + raise CDMSError( + 'List specified for order contains bad item: ' + repr(item)) j += 1 for i in range(n): @@ -1593,7 +1663,7 @@ def order2index (axes, order): if permutation[j] is None: permutation[j] = i break - return permutation + return permutation -from tvariable import TransientVariable -import MV2 as MV +from .tvariable import TransientVariable +from . import MV2 as MV diff --git a/Packages/cdms2/Lib/axis.py b/Packages/cdms2/Lib/axis.py index 458096c22..1f9561313 100644 --- a/Packages/cdms2/Lib/axis.py +++ b/Packages/cdms2/Lib/axis.py @@ -1,12 +1,13 @@ -## Automatically adapted for numpy.oldnumeric Aug 01, 2007 by -## Further modified to be pure new numpy June 24th 2008 +# Automatically adapted for numpy.oldnumeric Aug 01, 2007 by +# Further modified to be pure new numpy June 24th 2008 """ CDMS Axis objects """ _debug = 0 std_axis_attributes = ['name', 'units', 'length', 'values', 'bounds'] -import sys, copy +import sys +import copy import numpy # import regrid2._regrid import cdmsNode @@ -16,17 +17,24 @@ from cdmsobj import CdmsObj, Max32int from sliceut import reverseSlice, splitSlice, splitSliceExt from error import CDMSError import forecast -#import internattr +# import internattr from UserList import UserList + + class AliasList (UserList): + def __init__(self, alist): - UserList.__init__(self,alist) - def __setitem__ (self, i, value): + UserList.__init__(self, alist) + + def __setitem__(self, i, value): self.data[i] = value.lower() + def __setslice(self, i, j, values): self.data[i:j] = map(lambda x: x.lower(), values) + def append(self, value): self.data.append(value.lower()) + def extend(self, values): self.data.extend(map("".lower, values)) @@ -46,35 +54,35 @@ ReadOnlyAxis = "Axis is read-only: " InvalidNCycles = "Invalid number of cycles requested for wrapped dimension: " ComptimeType = type(cdtime.comptime(0)) -ReltimeType = type(cdtime.reltime(0,"days")) +ReltimeType = type(cdtime.reltime(0, "days")) CdtimeTypes = (ComptimeType, ReltimeType) # Map between cdtime calendar and CF tags calendarToTag = { - cdtime.MixedCalendar : 'gregorian', - cdtime.NoLeapCalendar : 'noleap', - cdtime.GregorianCalendar : 'proleptic_gregorian', - cdtime.JulianCalendar : 'julian', - cdtime.Calendar360 : '360_day', - cdtime.ClimCalendar : 'clim_noncf', - cdtime.ClimLeapCalendar : 'climleap_noncf', - cdtime.DefaultCalendar : 'gregorian', - cdtime.StandardCalendar : 'proleptic_gregorian', + cdtime.MixedCalendar: 'gregorian', + cdtime.NoLeapCalendar: 'noleap', + cdtime.GregorianCalendar: 'proleptic_gregorian', + cdtime.JulianCalendar: 'julian', + cdtime.Calendar360: '360_day', + cdtime.ClimCalendar: 'clim_noncf', + cdtime.ClimLeapCalendar: 'climleap_noncf', + cdtime.DefaultCalendar: 'gregorian', + cdtime.StandardCalendar: 'proleptic_gregorian', } tagToCalendar = { - 'gregorian' : cdtime.MixedCalendar, - 'standard' : cdtime.GregorianCalendar, - 'noleap' : cdtime.NoLeapCalendar, - 'julian' : cdtime.JulianCalendar, - 'proleptic_gregorian' : cdtime.GregorianCalendar, - '360_day' : cdtime.Calendar360, - '360' : cdtime.Calendar360, - '365_day' : cdtime.NoLeapCalendar, - 'clim' : cdtime.ClimCalendar, - 'clim_noncf' : cdtime.ClimCalendar, - 'climleap_noncf' : cdtime.ClimLeapCalendar, - 'climleap' : cdtime.ClimLeapCalendar, + 'gregorian': cdtime.MixedCalendar, + 'standard': cdtime.GregorianCalendar, + 'noleap': cdtime.NoLeapCalendar, + 'julian': cdtime.JulianCalendar, + 'proleptic_gregorian': cdtime.GregorianCalendar, + '360_day': cdtime.Calendar360, + '360': cdtime.Calendar360, + '365_day': cdtime.NoLeapCalendar, + 'clim': cdtime.ClimCalendar, + 'clim_noncf': cdtime.ClimCalendar, + 'climleap_noncf': cdtime.ClimLeapCalendar, + 'climleap': cdtime.ClimLeapCalendar, } # This is not an error message, it is used to detect which things have @@ -86,64 +94,77 @@ _autobounds = 2 # Automatically generate axis and grid b # Modes: # 0 : off (not bounds generation) # 1 : on (generate bounds) - # 2 : grid (generate bounds for lat/lon grids only) + # 2 : grid (generate bounds for lat/lon + # grids only) # Set autobounds mode to 'on' or 'off'. If on, getBounds will automatically # generate boundary information for an axis or grid, if not explicitly defined. # If 'off', and no boundary data is explicitly defined, the bounds will NOT # be generated; getBounds will return None for the boundaries. + + def setAutoBounds(mode): global _autobounds - if mode=='on' or mode==1: - _autobounds=1 - elif mode=='off' or mode==0: - _autobounds=0 - elif mode=='grid' or mode==2: - _autobounds=2 + if mode == 'on' or mode == 1: + _autobounds = 1 + elif mode == 'off' or mode == 0: + _autobounds = 0 + elif mode == 'grid' or mode == 2: + _autobounds = 2 + def getAutoBounds(): return _autobounds # Create a transient axis + + def createAxis(data, bounds=None, id=None, copy=0): return TransientAxis(data, bounds, id, copy=copy) # Generate a Gaussian latitude axis, north-to-south + + def createGaussianAxis(nlat): import regrid2._regrid - lats,wts,bnds = regrid2._regrid.gridattr(nlat,'gaussian') - - # For odd number of latitudes, gridattr returns 0 in the second half of lats - if nlat%2: - mid = nlat/2 - lats[mid+1:] = -lats[:mid][::-1] - - latBounds = numpy.zeros((nlat,2),numpy.float) - latBounds[:,0] = bnds[:-1] - latBounds[:,1] = bnds[1:] - lat = createAxis(lats,latBounds,id="latitude") + lats, wts, bnds = regrid2._regrid.gridattr(nlat, 'gaussian') + + # For odd number of latitudes, gridattr returns 0 in the second half of + # lats + if nlat % 2: + mid = nlat / 2 + lats[mid + 1:] = -lats[:mid][::-1] + + latBounds = numpy.zeros((nlat, 2), numpy.float) + latBounds[:, 0] = bnds[:-1] + latBounds[:, 1] = bnds[1:] + lat = createAxis(lats, latBounds, id="latitude") lat.designateLatitude() lat.units = "degrees_north" return lat # Generate an equal-area latitude axis, north-to-south + + def createEqualAreaAxis(nlat): import regrid2._regrid - lats,wts,bnds = regrid2._regrid.gridattr(nlat,'equalarea') - latBounds = numpy.zeros((nlat,2),numpy.float) - latBounds[:,0] = bnds[:-1] - latBounds[:,1] = bnds[1:] - lat = createAxis(lats,latBounds,id="latitude") + lats, wts, bnds = regrid2._regrid.gridattr(nlat, 'equalarea') + latBounds = numpy.zeros((nlat, 2), numpy.float) + latBounds[:, 0] = bnds[:-1] + latBounds[:, 1] = bnds[1:] + lat = createAxis(lats, latBounds, id="latitude") lat.designateLatitude() lat.units = "degrees_north" return lat # Generate a uniform latitude axis + + def createUniformLatitudeAxis(startLat, nlat, deltaLat): - latArray = startLat + deltaLat*numpy.arange(nlat) - lat = createAxis(latArray,id="latitude") + latArray = startLat + deltaLat * numpy.arange(nlat) + lat = createAxis(latArray, id="latitude") lat.designateLatitude() lat.units = "degrees_north" latBounds = lat.genGenericBounds(width=deltaLat) @@ -151,18 +172,21 @@ def createUniformLatitudeAxis(startLat, nlat, deltaLat): return lat # Generate a uniform longitude axis + + def createUniformLongitudeAxis(startLon, nlon, deltaLon): - lonArray = startLon + deltaLon*numpy.arange(nlon) - lon = createAxis(lonArray,id="longitude") + lonArray = startLon + deltaLon * numpy.arange(nlon) + lon = createAxis(lonArray, id="longitude") lon.designateLongitude() lon.units = "degrees_east" lonBounds = lon.genGenericBounds(width=deltaLon) lon.setBounds(lonBounds) return lon -def mapLinearIntersection(xind,yind,iind, - aMinusEps,aPlusEps,bPlusEps,bMinusEps, - boundLeft,nodeSubI,boundRight): + +def mapLinearIntersection(xind, yind, iind, + aMinusEps, aPlusEps, bPlusEps, bMinusEps, + boundLeft, nodeSubI, boundRight): """ Return true iff the coordinate interval (a,b) intersects the node @@ -182,34 +206,35 @@ def mapLinearIntersection(xind,yind,iind, """ if(iind == 'n' or iind == 'e'): - testC_ = ( aMinusEps <= nodeSubI ) - test_C = ( nodeSubI <= bPlusEps ) - testO_ = ( aPlusEps < nodeSubI ) - test_O = ( nodeSubI < bMinusEps ) + testC_ = (aMinusEps <= nodeSubI) + test_C = (nodeSubI <= bPlusEps) + testO_ = (aPlusEps < nodeSubI) + test_O = (nodeSubI < bMinusEps) elif(iind == 'b'): - testC_ = ( aMinusEps <= boundRight ) - test_C = ( boundLeft <= bPlusEps ) - testO_ = ( aPlusEps < boundRight ) - test_O = ( boundLeft < bMinusEps ) + testC_ = (aMinusEps <= boundRight) + test_C = (boundLeft <= bPlusEps) + testO_ = (aPlusEps < boundRight) + test_O = (boundLeft < bMinusEps) elif(iind == 's'): - testC_ = ( aMinusEps <= boundLeft ) - test_C = ( boundRight <= bPlusEps ) - testO_ = ( aPlusEps < boundLeft ) - test_O = ( boundRight < bMinusEps ) + testC_ = (aMinusEps <= boundLeft) + test_C = (boundRight <= bPlusEps) + testO_ = (aPlusEps < boundLeft) + test_O = (boundRight < bMinusEps) if(xind == 'c' and yind == 'c'): - test=(testC_ and test_C) + test = (testC_ and test_C) elif(xind == 'c' and yind == 'o'): - test=(testC_ and test_O) + test = (testC_ and test_O) elif(xind == 'o' and yind == 'c'): - test=(testO_ and test_C) + test = (testO_ and test_C) elif(xind == 'o' and yind == 'o'): - test=(testO_ and test_O) + test = (testO_ and test_O) return(test) -def mapLinearExt(axis, bounds, interval, indicator ='ccn', epsilon=None, stride=1, wrapped=0): +def mapLinearExt(axis, bounds, interval, + indicator='ccn', epsilon=None, stride=1, wrapped=0): """Map coordinate interval to index interval, without wraparound. interval has the form (x,y) where x and y are the endpoints in coordinate space. indicator is a three-character @@ -222,137 +247,139 @@ def mapLinearExt(axis, bounds, interval, indicator ='ccn', epsilon=None, stride= 'b' - the interval intersects the cell bounds 's' - the cell bounds are a subset of the interval 'e' - same as 'n', plus an extra node on either side. - + Returns the corresponding index interval (i,j), where iy: - x,y = y,x - xind = indicator[1] - yind = indicator[0] - + x, y = interval + + iind = indicator[2] + + if x > y: + x, y = y, x + xind = indicator[1] + yind = indicator[0] + else: xind = indicator[0] yind = indicator[1] - if axis[0]>axis[-1]: + if axis[0] > axis[-1]: ar = axis[::-1] - if bounds[0,0]1: - epsilon = eps * min(abs(ar[1]-ar[0]), abs(ar[-1]-ar[-2])) + eps = 1.0e-5 + if len(ar) > 1: + epsilon = eps * min(abs(ar[1] - ar[0]), abs(ar[-1] - ar[-2])) else: - epsilon=eps + epsilon = eps # # interval bound +/- epsilon # - aMinusEps=(x-epsilon) - aPlusEps=(x+epsilon) - bMinusEps=(y-epsilon) - bPlusEps=(y+epsilon) - + aMinusEps = (x - epsilon) + aPlusEps = (x + epsilon) + bMinusEps = (y - epsilon) + bPlusEps = (y + epsilon) - #oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo + # oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo # # out-of-bounds requests # - #oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo + # oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo - if iind in ['n','e']: + if iind in ['n', 'e']: mina = ar[0] maxa = ar[-1] else: - mina = bd[0,0] - maxa = bd[-1,1] - + mina = bd[0, 0] + maxa = bd[-1, 1] + if(bPlusEps < mina or aMinusEps > maxa): return None - #nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn + # nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn # # empty node check # - #nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn + # nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn # Handle empty intersections if ( - ( ((aPlusEps) > ar[-1]) and (iind == 'n') and (xind == 'o') ) or - ( ((aMinusEps) >= ar[-1]) and (iind == 'n') and (xind == 'c') ) or - ( ((bMinusEps) < ar[0] ) and (iind == 'n') and (yind == 'o') ) or - ( ((bPlusEps) <= ar[0] ) and (iind == 'n') and (yind == 'c') ) + (((aPlusEps) > ar[-1]) and (iind == 'n') and (xind == 'o')) or + (((aMinusEps) >= ar[-1]) and (iind == 'n') and (xind == 'c')) or + (((bMinusEps) < ar[0]) and (iind == 'n') and (yind == 'o')) or + (((bPlusEps) <= ar[0]) and (iind == 'n') and (yind == 'c')) ): return None - - bdMaxRight=max(bd[-1][0],bd[-1][1]) - bdMinLeft=min(bd[0][0],bd[0][1]) + bdMaxRight = max(bd[-1][0], bd[-1][1]) + bdMinLeft = min(bd[0][0], bd[0][1]) if ( - ( ( (aMinusEps) > bdMaxRight ) and (iind != 'n') and (xind == 'o') ) or - ( ( (aMinusEps) >= bdMaxRight ) and (iind != 'n') and (xind == 'c') ) or - ( ( (bPlusEps) < bdMinLeft ) and (iind != 'n') and (yind == 'o') ) or - ( ( (bPlusEps) <= bdMinLeft ) and (iind != 'n') and (yind == 'c') ) - ): + (((aMinusEps) > bdMaxRight) and (iind != 'n') and (xind == 'o')) or + (((aMinusEps) >= bdMaxRight) and (iind != 'n') and (xind == 'c')) or + (((bPlusEps) < bdMinLeft) and (iind != 'n') and (yind == 'o')) or + (((bPlusEps) <= bdMinLeft) and (iind != 'n') and (yind == 'c')) + ): return None - - # The intersection is nonempty; use searchsorted to get left/right limits for testing - ii,jj = numpy.searchsorted(ar,(x,y)) + # The intersection is nonempty; use searchsorted to get left/right limits + # for testing + + ii, jj = numpy.searchsorted(ar, (x, y)) # # find index range for left (iStart,iEnd) and right (jStart,jEnd) # - - # iEnd + 2 because last point in loop not done - iStart=ii-1 - iEnd=ii+2 - if(iStart < 0): iStart=0 - if( iEnd >= length ): iEnd = length - 1 - jStart=jj-1 - jEnd=jj+2 - if( jStart < 0 ): jStart=0 - if( jEnd >= length ): jEnd = length - 1 + # iEnd + 2 because last point in loop not done + iStart = ii - 1 + iEnd = ii + 2 + if(iStart < 0): + iStart = 0 + if(iEnd >= length): + iEnd = length - 1 + + jStart = jj - 1 + jEnd = jj + 2 + if(jStart < 0): + jStart = 0 + if(jEnd >= length): + jEnd = length - 1 # # initialise the index to -1 (does not exist) # - iInterval=-1 - jInterval=-1 - iIntervalB=-1 - jIntervalB=-1 + iInterval = -1 + jInterval = -1 + iIntervalB = -1 + jIntervalB = -1 - #pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp + # pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp # # preliminary checks # - #pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp - + # pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp if(iStart == jStart == iEnd == jEnd): iInterval = jInterval = iStart @@ -362,172 +389,173 @@ def mapLinearExt(axis, bounds, interval, indicator ='ccn', epsilon=None, stride= else: - #llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll + # llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll # # left interval check # - #llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll + # llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll # - user check - - for i in range(iStart,iEnd+1): - nodeSubI=ar[i] - boundLeft=bd[i][0] - boundRight=bd[i][1] + for i in range(iStart, iEnd + 1): + + nodeSubI = ar[i] + boundLeft = bd[i][0] + boundRight = bd[i][1] - test=mapLinearIntersection(xind,yind,iind, - aMinusEps,aPlusEps,bPlusEps,bMinusEps, - boundLeft,nodeSubI,boundRight) + test = mapLinearIntersection(xind, yind, iind, + aMinusEps, aPlusEps, bPlusEps, bMinusEps, + boundLeft, nodeSubI, boundRight) - if( iInterval == -1 and test ): + if(iInterval == -1 and test): iInterval = i break # - "B" check for extension - - for i in range(iStart,iEnd+1): - nodeSubI=ar[i] - boundLeft=bd[i][0] - boundRight=bd[i][1] + for i in range(iStart, iEnd + 1): - testB=mapLinearIntersection(xind,yind,'b', - aMinusEps,aPlusEps,bPlusEps,bMinusEps, - boundLeft,nodeSubI,boundRight) + nodeSubI = ar[i] + boundLeft = bd[i][0] + boundRight = bd[i][1] - if( iIntervalB == -1 and testB ): + testB = mapLinearIntersection(xind, yind, 'b', + aMinusEps, aPlusEps, bPlusEps, bMinusEps, + boundLeft, nodeSubI, boundRight) + + if(iIntervalB == -1 and testB): iIntervalB = i break - #rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr + # rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr # # right interval check # - #rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr + # rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr - for j in range(jStart,jEnd+1): + for j in range(jStart, jEnd + 1): - nodeSubI=ar[j] - boundLeft=bd[j][0] - boundRight=bd[j][1] + nodeSubI = ar[j] + boundLeft = bd[j][0] + boundRight = bd[j][1] # # user test # - test=mapLinearIntersection(xind,yind,iind, - aMinusEps,aPlusEps,bPlusEps,bMinusEps, - boundLeft,nodeSubI,boundRight) + test = mapLinearIntersection(xind, yind, iind, + aMinusEps, aPlusEps, bPlusEps, bMinusEps, + boundLeft, nodeSubI, boundRight) - if( ( jInterval == -1 and iInterval != -1 and test == 0 and j <= jEnd ) ): - jInterval = j-1 + if((jInterval == -1 and iInterval != -1 and test == 0 and j <= jEnd)): + jInterval = j - 1 - if( (j == length-1 and test == 1) ): + if((j == length - 1 and test == 1)): jInterval = j - + # no break here... # - # B test on right + # B test on right # - for j in range(jStart,jEnd+1): + for j in range(jStart, jEnd + 1): - nodeSubI=ar[j] - boundLeft=bd[j][0] - boundRight=bd[j][1] + nodeSubI = ar[j] + boundLeft = bd[j][0] + boundRight = bd[j][1] - testB=mapLinearIntersection(xind,yind,'b', - aMinusEps,aPlusEps,bPlusEps,bMinusEps, - boundLeft,nodeSubI,boundRight) + testB = mapLinearIntersection(xind, yind, 'b', + aMinusEps, aPlusEps, bPlusEps, bMinusEps, + boundLeft, nodeSubI, boundRight) - if( ( jIntervalB == -1 and iIntervalB != -1 and testB == 0 and j <= jEnd ) ): - jIntervalB = j-1 + if((jIntervalB == -1 and iIntervalB != -1 and testB == 0 and j <= jEnd)): + jIntervalB = j - 1 - if( ( j == length-1 and testB == 1) ): + if((j == length - 1 and testB == 1)): jIntervalB = j - - #eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee + # eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee # # extension check # - #eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee + # eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee if(iind == 'e'): # if B index does not exist return - if(iIntervalB < 0 or jIntervalB <0): + if(iIntervalB < 0 or jIntervalB < 0): return None # if user index exists: - elif ( ( iInterval > -1 and jInterval > -1 ) ): + elif ((iInterval > -1 and jInterval > -1)): if(jInterval < iInterval): - - npoints=iInterval-jInterval + + npoints = iInterval - jInterval if(npoints > 0): - (iInterval,jInterval)=(jInterval+1,iInterval+1) - + (iInterval, jInterval) = (jInterval + 1, iInterval + 1) + else: - jInterval=iInterval - iInterval=jInterval+1 - + jInterval = iInterval + iInterval = jInterval + 1 + else: - iInterval = iInterval-1 - jInterval = jInterval+1 - + iInterval = iInterval - 1 + jInterval = jInterval + 1 + # else set index interval to B index interval else: - - iInterval=iIntervalB - jInterval=jIntervalB + + iInterval = iIntervalB + jInterval = jIntervalB if(iInterval == jInterval): - if( x < ar[iInterval] and iInterval > 0 ): - iInterval=jInterval-1 - elif( jIntervalB < length-1 ): - jInterval=iInterval+1 + if(x < ar[iInterval] and iInterval > 0): + iInterval = jInterval - 1 + elif(jIntervalB < length - 1): + jInterval = iInterval + 1 if(jInterval < iInterval): - npoints=jInterval-iInterval + npoints = jInterval - iInterval if(npoints > 2): - jInterval=iIntervalB - iInterval=jIntervalB + jInterval = iIntervalB + iInterval = jIntervalB else: - jInterval=iIntervalB - iInterval=jIntervalB+1 - - # Since the lookup is linear, ensure that the result is in range [0..length) - iInterval = max(iInterval,0) - jInterval = min(jInterval,length-1) - - #ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + jInterval = iIntervalB + iInterval = jIntervalB + 1 + + # Since the lookup is linear, ensure that the result is in range + # [0..length) + iInterval = max(iInterval, 0) + jInterval = min(jInterval, length - 1) + + # ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff # # final checks # - #ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + # ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff # if jInteval < iInterval have a single point; set to iInterval if(jInterval < iInterval): - jInterval=iInterval - + jInterval = iInterval + elif(jInterval < 0 and iInterval < 0): return None - + # Reverse back if necessary - if direc=='dec': - iInterval,jInterval = length-jInterval-1,length-iInterval-1 - - iReturn=iInterval - jReturn=jInterval+1 + if direc == 'dec': + iInterval, jInterval = length - jInterval - 1, length - iInterval - 1 + + iReturn = iInterval + jReturn = jInterval + 1 + + return (iReturn, jReturn) - return (iReturn,jReturn) -def lookupArray(ar,value): +def lookupArray(ar, value): """Lookup value in array ar. Return index such that: (a) ar is monotonically increasing: value <= ar[index], index==0..len(ar)-1 @@ -537,42 +565,46 @@ def lookupArray(ar,value): value < ar[index], index==len(ar) """ ar = numpy.ma.filled(ar) - ascending = (ar[0](len(vec2)-len(vec1)): - return (0,-1) # vec1 is too large, cannot be a subset - issubset = numpy.alltrue(numpy.less(numpy.absolute(vec1-vec2[index:index+len(vec1)]),tol)) + index = lookupArray(vec2, vec1[0]) + if index > (len(vec2) - len(vec1)): + return (0, -1) # vec1 is too large, cannot be a subset + issubset = numpy.alltrue( + numpy.less(numpy.absolute(vec1 - vec2[index:index + len(vec1)]), tol)) if issubset: - return (issubset,index) + return (issubset, index) else: - return (0,-1) + return (0, -1) + def isOverlapVector(vec1, vec2, atol=1.e-8): """Returns (isoverlap, index) where: @@ -580,32 +612,35 @@ def isOverlapVector(vec1, vec2, atol=1.e-8): index is the index such that vec1[0]<=vec2[index]. If index==len(vec2), then vec1[0]>vec2[len(vec2)-1] """ - index = lookupArray(vec2,vec1[0]) - if index==0 and abs(vec1[0]-vec2[0]): - return (0,index) - elif index==len(vec2): - return (1,index) + index = lookupArray(vec2, vec1[0]) + if index == 0 and abs(vec1[0] - vec2[0]): + return (0, index) + elif index == len(vec2): + return (1, index) else: - ar2 = vec2[index:index+len(vec1)] + ar2 = vec2[index:index + len(vec1)] ar1 = vec1[:len(ar2)] isoverlap = numpy.ma.allclose(ar1, ar2, atol=atol) if isoverlap: - return (isoverlap,index) + return (isoverlap, index) else: - return (0,index) + return (0, index) + def allclose(ax1, ax2, rtol=1.e-5, atol=1.e-8): """True if all elements of axes ax1 and ax2 are close, in the sense of numpy.ma.allclose.""" - return ((ax1 is ax2) or numpy.ma.allclose(ax1[:],ax2[:],rtol=rtol,atol=atol)) + return ((ax1 is ax2) or numpy.ma.allclose(ax1[:], ax2[:], rtol=rtol, atol=atol)) -# AbstractAxis defines the common axis interface. +# AbstractAxis defines the common axis interface. # Concrete axis classes are derived from this class. + class AbstractAxis(CdmsObj): - def __init__ (self, parent, node): - CdmsObj.__init__ (self, node) - val = self.__cdms_internals__ + ['id',] + + def __init__(self, parent, node): + CdmsObj.__init__(self, node) + val = self.__cdms_internals__ + ['id', ] self.___cdms_internals__ = val self.parent = parent self.id = id @@ -613,11 +648,11 @@ class AbstractAxis(CdmsObj): self._data_ = None # Cached wraparound values for circular axes self._doubledata_ = None - - def __str__ (self): + + def __str__(self): return "\n".join(self.listall() + "\n" - __repr__ = __str__ + __repr__=__str__ def __len__(self): raise CDMSError, MethodNotImplemented @@ -626,7 +661,7 @@ class AbstractAxis(CdmsObj): return (len(self),) def _getdtype(self, name): - tc = self.typecode() + tc=self.typecode() return numpy.dtype(tc) def __getitem__(self, key): @@ -648,17 +683,17 @@ class AbstractAxis(CdmsObj): # If persistent is true, write metadata to the container. def designateLatitude(self, persistent=0): if persistent: - self.axis = "Y" + self.axis="Y" else: - self.__dict__['axis'] = "Y" + self.__dict__['axis']="Y" self.attributes['axis']="Y" # Return true iff the axis is a latitude axis def isLatitude(self): - id = self.id.strip().lower() - if (hasattr(self,'axis') and self.axis=='Y'): return 1 - units = getattr(self,"units","").strip().lower() - if units in ["degrees_north","degree_north","degree_n","degrees_n","degreen","degreesn"]: + id=self.id.strip().lower() + if (hasattr(self, 'axis') and self.axis == 'Y'): return 1 + units=getattr(self, "units", "").strip().lower() + if units in ["degrees_north", "degree_north", "degree_n", "degrees_n", "degreen", "degreesn"]: return 1 return (id[0:3] == 'lat') or (id in latitude_aliases) @@ -666,25 +701,25 @@ class AbstractAxis(CdmsObj): # If persistent is true, write metadata to the container. def designateLevel(self, persistent=0): if persistent: - self.axis = "Z" + self.axis="Z" else: - self.__dict__['axis'] = "Z" + self.__dict__['axis']="Z" self.attributes['axis']="Z" # Return true iff the axis is a level axis def isLevel(self): - id = self.id.strip().lower() - if (hasattr(self,'axis') and self.axis=='Z'): return 1 - if getattr(self,"positive","").strip().lower() in ["up","down"]: + id=self.id.strip().lower() + if (hasattr(self, 'axis') and self.axis == 'Z'): return 1 + if getattr(self, "positive", "").strip().lower() in ["up", "down"]: return 1 try: - #Ok let's see if this thing as pressure units + # Ok let's see if this thing as pressure units import genutil - p=genutil.udunits(1,"Pa") - units=getattr(self,'units',"").strip() + p=genutil.udunits(1, "Pa") + units=getattr(self, 'units', "").strip() p2=p.to(units) return 1 - except Exception,err: + except Exception, err: pass return ((id[0:3] == 'lev') or (id[0:5] == 'depth') or (id in level_aliases)) @@ -693,30 +728,30 @@ class AbstractAxis(CdmsObj): # If modulo is defined, set as circular def designateLongitude(self, persistent=0, modulo=360.0): if persistent: - self.axis = "X" + self.axis="X" if modulo is None: - self.topology = 'linear' + self.topology='linear' else: - self.modulo = modulo - self.topology = 'circular' + self.modulo=modulo + self.topology='circular' else: - self.__dict__['axis'] = "X" + self.__dict__['axis']="X" self.attributes['axis']="X" if modulo is None: - self.__dict__['topology'] = 'linear' - self.attributes['topology'] = 'linear' + self.__dict__['topology']='linear' + self.attributes['topology']='linear' else: - self.__dict__['modulo'] = modulo - self.__dict__['topology'] = 'circular' - self.attributes['modulo'] = modulo - self.attributes['topology'] = 'circular' + self.__dict__['modulo']=modulo + self.__dict__['topology']='circular' + self.attributes['modulo']=modulo + self.attributes['topology']='circular' # Return true iff the axis is a longitude axis def isLongitude(self): - id = self.id.strip().lower() - if (hasattr(self,'axis') and self.axis=='X'): return 1 - units = getattr(self,"units","").strip().lower() - if units in ["degrees_east","degree_east","degree_e","degrees_e","degreee","degreese"]: + id=self.id.strip().lower() + if (hasattr(self, 'axis') and self.axis == 'X'): return 1 + units=getattr(self, "units", "").strip().lower() + if units in ["degrees_east", "degree_east", "degree_e", "degrees_e", "degreee", "degreese"]: return 1 return (id[0:3] == 'lon') or (id in longitude_aliases) @@ -724,63 +759,65 @@ class AbstractAxis(CdmsObj): # If persistent is true, write metadata to the container. def designateTime(self, persistent=0, calendar=None): if calendar is None: - calendar = cdtime.DefaultCalendar + calendar=cdtime.DefaultCalendar if persistent: - self.axis = "T" + self.axis="T" if calendar is not None: self.setCalendar(calendar, persistent) else: - self.__dict__['axis'] = "T" - self.attributes['axis'] = "T" + self.__dict__['axis']="T" + self.attributes['axis']="T" if calendar is not None: self.setCalendar(calendar, persistent) # For isTime(), keep track of whether each id is for a time axis or not, for better performance. - # This dictionary is a class variable (not a member of any particular instance). - idtaxis = {} # id:type where type is 'T' for time, 'O' for other + # This dictionary is a class variable (not a member of any particular + # instance). + idtaxis={} # id:type where type is 'T' for time, 'O' for other # Return true iff the axis is a time axis def isTime(self): - id = self.id.strip().lower() - if hasattr(self,'axis'): - if self.axis=='T': return 1 + id=self.id.strip().lower() + if hasattr(self, 'axis'): + if self.axis == 'T': return 1 elif self.axis is not None: return 0 # Have we saved the id-to-axis type information already? if id in self.idtaxis: - if self.idtaxis[id]=='T': + if self.idtaxis[id] == 'T': return 1 else: return 0 - ## Try to figure it out from units + # Try to figure it out from units try: import genutil - units=getattr(self,"units","").lower() - sp = units.split("since") - if len(sp)>1: - t=genutil.udunits(1,"day") - s = sp[0].strip() - if s in t.available_units() and t.known_units()[s]=="TIME": - self.idtaxis[id] = 'T' + units=getattr(self, "units", "").lower() + sp=units.split("since") + if len(sp) > 1: + t=genutil.udunits(1, "day") + s=sp[0].strip() + if s in t.available_units() and t.known_units()[s] == "TIME": + self.idtaxis[id]='T' return 1 - #try the plural version since udunits only as singular (day noy days) - s=s+"s" - if s in t.available_units() and t.known_units()[s]=="TIME": - self.idtaxis[id] = 'T' + # try the plural version since udunits only as singular (day noy + # days) + s=s + "s" + if s in t.available_units() and t.known_units()[s] == "TIME": + self.idtaxis[id]='T' return 1 except: pass - #return (id[0:4] == 'time') or (id in time_aliases) + # return (id[0:4] == 'time') or (id in time_aliases) if (id[0:4] == 'time') or (id in time_aliases): self.idtaxis[id]='T' return 1 else: - self.idtaxis[id] = 'O' + self.idtaxis[id]='O' return 0 # Return true iff the axis is a forecast axis def isForecast(self): - id = self.id.strip().lower() - if (hasattr(self,'axis') and self.axis=='F'): return 1 + id=self.id.strip().lower() + if (hasattr(self, 'axis') and self.axis == 'F'): return 1 return (id[0:6] == 'fctau0') or (id in forecast_aliases) def isForecastTime(self): return self.isForecast() @@ -790,15 +827,15 @@ class AbstractAxis(CdmsObj): if not hasattr(self, 'units'): raise CDMSError, "No time units defined" if calendar is None: - calendar = self.getCalendar() + calendar=self.getCalendar() if self.isForecast(): - result = [ forecast.comptime(t) for t in self[:] ] + result=[forecast.comptime(t) for t in self[:]] else: - result = [] + result=[] for val in self[:]: result.append(cdtime.reltime(val, self.units).tocomp(calendar)) return result - + # # mf 20010418 -- output DTGs (YYYYMMDDHH) # @@ -806,22 +843,22 @@ class AbstractAxis(CdmsObj): "Array version of cdtime tocomp. Returns a list of component times in DTG format." if not hasattr(self, 'units'): raise CDMSError, "No time units defined" - result = [] + result=[] if calendar is None: - calendar = self.getCalendar() + calendar=self.getCalendar() for val in self[:]: comptime=cdtime.reltime(val, self.units).tocomp(calendar) s=repr(comptime) tt=s.split(' ') - + ttt=tt[0].split('-') yr=int(ttt[0]) mo=int(ttt[1]) da=int(ttt[2]) - + ttt=tt[1].split(':') hr=int(ttt[0]) - dtg="%04d%02d%02d%02d"%(yr,mo,da,hr) + dtg="%04d%02d%02d%02d" % (yr, mo, da, hr) result.append(dtg) return result @@ -831,27 +868,35 @@ class AbstractAxis(CdmsObj): import datetime if not hasattr(self, 'units'): raise CDMSError, "No time units defined" - result = [] + result=[] if calendar is None: - calendar = self.getCalendar() + calendar=self.getCalendar() for val in self[:]: c=cdtime.reltime(val, self.units).tocomp(calendar) - dtg = datetime.datetime(c.year,c.month,c.day,c.hour,c.minute,int(c.second),int((c.second-int(c.second))*1000)) + dtg=datetime.datetime( + c.year, + c.month, + c.day, + c.hour, + c.minute, + int(c.second), + int((c.second - int(c.second)) * 1000)) result.append(dtg) return result - def asRelativeTime( self, units=None ): + def asRelativeTime(self, units=None): "Array version of cdtime torel. Returns a list of relative times." - sunits = getattr(self,'units',None) - if sunits==None or sunits=='None': + sunits=getattr(self, 'units', None) + if sunits is None or sunits == 'None': raise CDMSError, "No time units defined" - if units==None or units=='None': + if units is None or units == 'None': units=sunits if self.isForecast(): - result = [ forecast.comptime(t).torel(units) for t in self[:] ] + result=[forecast.comptime(t).torel(units) for t in self[:]] else: - cal = self.getCalendar() - result = [ cdtime.reltime(t,sunits).torel(units,cal) for t in self[:] ] + cal=self.getCalendar() + result=[cdtime.reltime(t, sunits).torel(units, cal) + for t in self[:]] return result def toRelativeTime(self, units, calendar=None): @@ -860,31 +905,35 @@ class AbstractAxis(CdmsObj): raise CDMSError, "No time units defined" n=len(self[:]) b=self.getBounds() - scal = self.getCalendar() + scal=self.getCalendar() if calendar is None: - calendar = scal + calendar=scal else: self.setCalendar(calendar) for i in range(n): tmp=cdtime.reltime(self[i], self.units).tocomp(scal) - tmp2 = numpy.array(float(tmp.torel(units, calendar).value)).astype(self[:].dtype.char) - ## if i==1 : print self[:].dtype.char,'tmp2:',tmp2,tmp2.astype('f'),self[i],self[i].astype('f') + tmp2=numpy.array(float(tmp.torel(units, calendar).value)).astype( + self[:].dtype.char) + # if i==1 : print + # self[:].dtype.char,'tmp2:',tmp2,tmp2.astype('f'),self[i],self[i].astype('f') self[i]=tmp2 if b is not None: - tmp=cdtime.reltime(b[i,0], self.units).tocomp(scal) - b[i,0]=numpy.array(float(tmp.torel(units, calendar).value)).astype(b.dtype.char) - tmp=cdtime.reltime(b[i,1], self.units).tocomp(scal) - b[i,1]=numpy.array(float(tmp.torel(units, calendar).value)).astype(b.dtype.char) + tmp=cdtime.reltime(b[i, 0], self.units).tocomp(scal) + b[i, 0]=numpy.array( + float(tmp.torel(units, calendar).value)).astype(b.dtype.char) + tmp=cdtime.reltime(b[i, 1], self.units).tocomp(scal) + b[i, 1]=numpy.array( + float(tmp.torel(units, calendar).value)).astype(b.dtype.char) if b is not None: self.setBounds(b) self.units=units return -#mfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmf +# mfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmf # # mf 20010412 -- test if an Axis is intrinsically circular # -#mfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmf +# mfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmf # Return true iff the axis wraps around @@ -892,22 +941,22 @@ class AbstractAxis(CdmsObj): # (1) self.topology=='circular', or # (2) self.topology is undefined, and the axis is a longitude def isCircularAxis(self): - - if hasattr(self,'topology'): - iscircle = (self.topology=='circular') + + if hasattr(self, 'topology'): + iscircle=(self.topology == 'circular') elif self.isLongitude(): - iscircle = 1 + iscircle=1 else: - iscircle = 0 + iscircle=0 return iscircle -#mfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmf +# mfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmf # # mf 20010405 -- test if an transient Axis is REALLY circular # -#mfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmf +# mfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmf # Return true iff the axis wraps around @@ -916,45 +965,45 @@ class AbstractAxis(CdmsObj): # (2) self.topology is undefined, and the axis is a longitude def isCircular(self): - if hasattr(self,'realtopology'): - if self.realtopology=='circular': return 1 - elif self.realtopology=='linear': return 0 + if hasattr(self, 'realtopology'): + if self.realtopology == 'circular': return 1 + elif self.realtopology == 'linear': return 0 if(len(self) < 2): return 0 - - baxis = self[0] - eaxis = self[-1] - deltaend = self[-1] - self[-2] - eaxistest = eaxis + deltaend - baxis + + baxis=self[0] + eaxis=self[-1] + deltaend=self[-1] - self[-2] + eaxistest=eaxis + deltaend - baxis cycle=self.getModuloCycle() - tol=0.01*deltaend + tol=0.01 * deltaend test=0 if(abs(eaxistest - cycle) < tol): test=1 - - if hasattr(self,'topology') and test == 1: - iscircle = (self.topology=='circular') + + if hasattr(self, 'topology') and test == 1: + iscircle=(self.topology == 'circular') elif (self.isLongitude() and test == 1): - iscircle = 1 + iscircle=1 else: - iscircle = 0 + iscircle=0 # save realtopology attribute in __dict__, don't write it to the file - if iscircle==1: self.__dict__['realtopology'] = 'circular' - elif iscircle==0: self.__dict__['realtopology'] = 'linear' + if iscircle == 1: self.__dict__['realtopology']='circular' + elif iscircle == 0: self.__dict__['realtopology']='linear' return iscircle def designateCircular(self, modulo, persistent=0): if persistent: - self.topology = 'circular' - self.modulo = modulo + self.topology='circular' + self.modulo=modulo else: - self.__dict__['topology'] = 'circular' - self.__dict__['modulo'] = modulo - self.attributes['modulo'] = modulo - self.attributes['topology'] = 'linear' + self.__dict__['topology']='circular' + self.__dict__['modulo']=modulo + self.attributes['modulo']=modulo + self.attributes['topology']='linear' def isLinear(self): raise CDMSError, MethodNotImplemented @@ -973,62 +1022,62 @@ class AbstractAxis(CdmsObj): # or None. If the axis does not have a calendar attribute, return the global # calendar. def getCalendar(self): - if hasattr(self,'calendar'): - calendar = self.calendar.lower() + if hasattr(self, 'calendar'): + calendar=self.calendar.lower() else: - calendar = None + calendar=None - cdcal = tagToCalendar.get(calendar, cdtime.DefaultCalendar) + cdcal=tagToCalendar.get(calendar, cdtime.DefaultCalendar) return cdcal # Set the calendar def setCalendar(self, calendar, persistent=1): if persistent: - self.calendar = calendarToTag.get(calendar, None) + self.calendar=calendarToTag.get(calendar, None) self.attributes['calendar']=self.calendar if self.calendar is None: raise CDMSError, InvalidCalendar % calendar else: - self.__dict__['calendar'] = calendarToTag.get(calendar, None) + self.__dict__['calendar']=calendarToTag.get(calendar, None) self.attributes['calendar']=self.calendar if self.__dict__['calendar'] is None: raise CDMSError, InvalidCalendar % calendar def getData(self): raise CDMSError, MethodNotImplemented - + # Return the entire array def getValue(self): return self.__getitem__(slice(None)) - def assignValue(self,data): - self.__setitem__(slice(None),data) + def assignValue(self, data): + self.__setitem__(slice(None), data) def _time2value(self, value): """ Map value of type comptime, reltime, or string of form "yyyy-mm-dd hh:mi:ss" to value""" if self.isTime(): if type(value) in CdtimeTypes: - value = value.torel(self.units, self.getCalendar()).value - elif isinstance(value, basestring) and value not in [':',unspecified]: - cal = self.getCalendar() - value = cdtime.s2c(value, cal).torel(self.units, cal).value + value=value.torel(self.units, self.getCalendar()).value + elif isinstance(value, basestring) and value not in [':', unspecified]: + cal=self.getCalendar() + value=cdtime.s2c(value, cal).torel(self.units, cal).value return value def getModuloCycle(self): - if hasattr(self,'modulo'): - cycle = self.modulo + if hasattr(self, 'modulo'): + cycle=self.modulo # # mf 20010419 test if attribute is a string (non CF), set to 360.0 # if isnstance(cycle, basestring): - cycle = 360.0 + cycle=360.0 else: - cycle = 360.0 + cycle=360.0 if isinstance(cycle, numpy.ndarray): - cycle = cycle[0] + cycle=cycle[0] return(cycle) @@ -1040,7 +1089,7 @@ class AbstractAxis(CdmsObj): return(self.getModuloCycle()) - def mapInterval(self,interval,indicator='ccn',cycle=None): + def mapInterval(self, interval, indicator='ccn', cycle=None): """ Map coordinate interval to index interval. interval has one of the forms: @@ -1071,295 +1120,301 @@ class AbstractAxis(CdmsObj): Note: if the interval is interior to the axis, but does not span any axis element, a singleton (i,i+1) indicating an adjacent index is returned. """ - i,j,k = self.mapIntervalExt(interval,indicator,cycle) - j = min(j, i+len(self)) - #i=i-1 - return (i,j) + i, j, k=self.mapIntervalExt(interval, indicator, cycle) + j=min(j, i + len(self)) + # i=i-1 + return (i, j) -#mfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmf +# mfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmf # # mf 20010308 - 20010412 -- general handing of wrapping # -#mfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmf +# mfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmf - def mapIntervalExt(self,interval,indicator='ccn',cycle=None,epsilon=None): + def mapIntervalExt( + self, interval, indicator='ccn', cycle=None, epsilon=None): """Like mapInterval, but returns (i,j,k) where k is stride, and (i,j) is not restricted to one cycle.""" # nCycleMax : max number of cycles a user a specify in wrapping nCycleMax=6 - + # interval is None returns the full interval - if interval is None or interval==':': + if interval is None or interval == ':': return (0, len(self), 1) # Allow intervals of the same form as getRegion. - if len(interval)==3: - x,y,indicator = interval - interval = (x,y) - elif len(interval)==4: - x,y,indicator,cycle = interval - interval = (x,y) + if len(interval) == 3: + x, y, indicator=interval + interval=(x, y) + elif len(interval) == 4: + x, y, indicator, cycle=interval + interval=(x, y) # check length of indicator if overridden by user # - indicator = indicator.lower() - if len(indicator)==2: indicator += 'n' + indicator=indicator.lower() + if len(indicator) == 2: indicator += 'n' - if( ( len(indicator) != 3 ) or - ( (indicator[0] != 'c' and indicator[0] != 'o') or + if((len(indicator) != 3) or + ((indicator[0] != 'c' and indicator[0] != 'o') or (indicator[1] != 'c' and indicator[1] != 'o') or (indicator[2] != 'n' and indicator[2] != 'b' and indicator[2] != 's' and indicator[2] != 'e') ) ): raise CDMSError, "EEE: 3-character interval/intersection indicator incomplete or incorrect = "\ - +indicator - + + indicator + if self._data_ is None: - self._data_ = self.getData() + self._data_=self.getData() - #ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt + # ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt # Handle time types - interval = (self._time2value(interval[0]), self._time2value(interval[1])) + interval=( + self._time2value(interval[0]), + self._time2value(interval[1])) # If the interval is reversed wrt self, reverse the interval and # set the stride to -1 - if (interval[0]<=interval[1])==(self[0]<=self[-1]): + if (interval[0] <= interval[1]) == (self[0] <= self[-1]): stride=1 else: stride=-1 - interval = (interval[1],interval[0]) - indicator = indicator[1]+indicator[0]+indicator[2] + interval=(interval[1], interval[0]) + indicator=indicator[1] + indicator[0] + indicator[2] - #mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm + # mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm # # basic test for wrapping - is axis REALLY circular? # - #ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + # ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - xind = indicator[0] - yind = indicator[1] - iind = indicator[2] + xind=indicator[0] + yind=indicator[1] + iind=indicator[2] - xi,yi = interval + xi, yi=interval - length = len(self) - ar = self[:] - ar0 = ar[0] - arn = ar[-1] - armin = min(ar0,arn) - armax = max(ar0,arn) + length=len(self) + ar=self[:] + ar0=ar[0] + arn=ar[-1] + armin=min(ar0, arn) + armax=max(ar0, arn) # Wrapped if circular and at least one value is outside the axis range. - wraptest1 = self.isCircular() - wraptest2 = not ((armin <= xi <= armax) and (armin <= yi <= armax)) - + wraptest1=self.isCircular() + wraptest2=not ((armin <= xi <= armax) and (armin <= yi <= armax)) + if (wraptest1 and wraptest2): # - # find cycle and calc # of cycles in the interval + # find cycle and calc # of cycles in the interval # - + cycle=self.getModulo() - - intervalLength=yi-xi - intervalCycles=intervalLength/cycle - - bd = self.getBounds() - - nPointsCycle = len(ar) - ar0 = ar[0] - ar1 = ar[-1] + intervalLength=yi - xi + intervalCycles=intervalLength / cycle + + bd=self.getBounds() + + nPointsCycle=len(ar) + + ar0=ar[0] + ar1=ar[-1] # # test for reversed coordinates # - - if ar0>ar1: - cycle = -1 * abs(cycle) - #eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee + if ar0 > ar1: + cycle=-1 * abs(cycle) + + # eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee # # make sure xi0 and yixi: xi,yi = yi,xi + + if cycle > 0 and yi < xi: xi, yi=yi, xi + if cycle < 0 and yi > xi: xi, yi=yi, xi # calculate the number of cycles to shift to positive side - - nCycleShift=numpy.floor((xi-ar0)/cycle) - xp = xi - cycle * nCycleShift - yp = xp + intervalLength - # Extend the data vector with wraparound number of cycles in interval and shifts + nCycleShift=numpy.floor((xi - ar0) / cycle) + xp=xi - cycle * nCycleShift + yp=xp + intervalLength + + # Extend the data vector with wraparound number of cycles in + # interval and shifts + + nCycle=int(intervalCycles + 1.0 + 0.5) + abs(nCycleShift) + - nCycle = int(intervalCycles + 1.0 + 0.5) + abs(nCycleShift) - - # # check if nCycle is > nCycleMax # if(nCycle >= nCycleMax): raise CDMSError, InvalidNCycles + repr(nCycle) - self._doubledata_ = numpy.concatenate(( ar, ar + cycle )) + self._doubledata_=numpy.concatenate((ar, ar + cycle)) k=2 - while(k= vice i > + # mf 20010328 negative stride i >= vice i > #---------------------------------------------------------------------- - - if wrap and ((k>0 and j>size) or (k<0 and i >= size)) and self.isCircular(): - modulo = self.getModuloCycle() + + if wrap and ((k > 0 and j > size) or (k < 0 and i >= size)) and self.isCircular(): + modulo=self.getModuloCycle() if modulo is not None: # If self is decreasing and stride is positive, # or self is increasing and stride is negative, subtract the modulus, # otherwise add it. - if (self[0]>self[-1])==(k>0): - modulo = -modulo + if (self[0] > self[-1]) == (k > 0): + modulo=-modulo #---------------------------------------------------------------------- # # mf 20010329 -- N vice two slice scheme (more general) # - #---------------------------------------------------------------------- + #------------------------------------------------------------------ donew=1 if(donew): - sn = splitSliceExt(slice(i,j,k),size) - if(_debug): print "SSSS1-------------------- ",sn,len(sn) + sn=splitSliceExt(slice(i, j, k), size) + if(_debug): print "SSSS1-------------------- ", sn, len(sn) - for kk in range(0,len(sn)): + for kk in range(0, len(sn)): sl=sn[kk] - if(_debug): print "SSSSSSSS kk = ",kk,sl - part = self[sl] + kk*modulo - if(_debug): print "SSSSSSSSSSSSSSS modulo",part[0],part[-1],modulo + if(_debug): print "SSSSSSSS kk = ", kk, sl + part=self[sl] + kk * modulo + if(_debug): print "SSSSSSSSSSSSSSS modulo", part[0], part[-1], modulo if(kk == 0): - data = part + data=part else: - data = numpy.concatenate((data,part)) + data=numpy.concatenate((data, part)) if fullBounds is not None: - bound = fullBounds[sl] + kk*modulo + bound=fullBounds[sl] + kk * modulo if (kk == 0): - bounds = bound + bounds=bound else: - bounds = numpy.concatenate((bounds,bound)) + bounds=numpy.concatenate((bounds, bound)) else: - bounds = None - - + bounds=None + + else: - - s1, s2 = splitSlice(slice(i,j,k),size) - if(_debug): print "SSSS0: original ",s1,s2 - - part1 = self[s1] - part2 = self[s2]+modulo - if(_debug): print "SSSSSSSSSSSSSSS modulo",self[0],self[-1],modulo - data = numpy.concatenate((part1,part2)) + + s1, s2=splitSlice(slice(i, j, k), size) + if(_debug): print "SSSS0: original ", s1, s2 + + part1=self[s1] + part2=self[s2] + modulo + if(_debug): print "SSSSSSSSSSSSSSS modulo", self[0], self[-1], modulo + data=numpy.concatenate((part1, part2)) if fullBounds is not None: - bounds1 = fullBounds[s1] - bounds2 = fullBounds[s2]+modulo - bounds = numpy.concatenate((bounds1,bounds2)) + bounds1=fullBounds[s1] + bounds2=fullBounds[s2] + modulo + bounds=numpy.concatenate((bounds1, bounds2)) else: - bounds = None - + bounds=None + else: # no wraparound - data = self[i:j:k] + data=self[i:j:k] if fullBounds is not None: - bounds = fullBounds[i:j:k] + bounds=fullBounds[i:j:k] else: - bounds = None - - newaxis = TransientAxis(data, bounds, id=self.id, copy=1) + bounds=None + + newaxis=TransientAxis(data, bounds, id=self.id, copy=1) if self.isLatitude(): newaxis.designateLatitude() if self.isLongitude(): newaxis.designateLongitude() @@ -1367,190 +1422,201 @@ class AbstractAxis(CdmsObj): if self.isTime(): newaxis.designateTime() for attname in self.attributes.keys(): - if attname not in ["datatype", "length","isvar","name_in_file","partition","partition_length"]: + if attname not in ["datatype", "length", "isvar", "name_in_file", "partition", "partition_length"]: setattr(newaxis, attname, getattr(self, attname)) - newaxis.attributes[attname]=getattr(self,attname) + newaxis.attributes[attname]=getattr(self, attname) # Change circular topology to linear if a strict subset was copied - if hasattr(self,"topology") and self.topology=="circular" and len(newaxis)=self[i]>=bounds[i,1]: + if not bounds[i, 0] >= self[i] >= bounds[i, 1]: raise CDMSError, InvalidBoundsArray + \ -'bounds[%i]=%f is not in the range [%f,%f]'%(i,self[i],bounds[i,1],bounds[i,0]) +'bounds[%i]=%f is not in the range [%f,%f]' % ( + i, self[i], bounds[i, 1], bounds[i, 0]) return bounds - # Generate bounds from midpoints. width is the width of the zone if the axis has one value. + # Generate bounds from midpoints. width is the width of the zone if the + # axis has one value. def genGenericBounds(self, width=1.0): if self._data_ is None: - self._data_ = self.getData() - ar = self._data_ - if len(self)>1: - leftPoint = numpy.array([1.5*ar[0]-0.5*ar[1]]) - midArray = (ar[0:-1]+ar[1:])/2.0 - rightPoint = numpy.array([1.5*ar[-1]-0.5*ar[-2]]) - bnds = numpy.concatenate((leftPoint,midArray,rightPoint)) + self._data_=self.getData() + ar=self._data_ + if len(self) > 1: + leftPoint=numpy.array([1.5 * ar[0] - 0.5 * ar[1]]) + midArray=(ar[0:-1] + ar[1:]) / 2.0 + rightPoint=numpy.array([1.5 * ar[-1] - 0.5 * ar[-2]]) + bnds=numpy.concatenate((leftPoint, midArray, rightPoint)) else: - delta = width/2.0 - bnds = numpy.array([self[0]-delta,self[0]+delta]) + delta=width / 2.0 + bnds=numpy.array([self[0] - delta, self[0] + delta]) # Transform to (n,2) array - retbnds = numpy.zeros((len(ar),2),numpy.float) - retbnds[:,0] = bnds[:-1] - retbnds[:,1] = bnds[1:] + retbnds=numpy.zeros((len(ar), 2), numpy.float) + retbnds[:, 0]=bnds[:-1] + retbnds[:, 1]=bnds[1:] if self.isLatitude(): - retbnds[0,:] = numpy.maximum(-90.0, numpy.minimum(90.0,retbnds[0,:])) - retbnds[-1,:] = numpy.maximum(-90.0, numpy.minimum(90.0,retbnds[-1,:])) + retbnds[0, :]=numpy.maximum( + -90.0, numpy.minimum(90.0, retbnds[0, :])) + retbnds[-1, :]=numpy.maximum( + -90.0, numpy.minimum(90.0, retbnds[-1, :])) return retbnds - def clone (self, copyData=1): + def clone(self, copyData=1): """clone (self, copyData=1) Return a copy of self as a transient axis. If copyData is 1, make a separate copy of the data.""" - b = self.getBounds() - if copyData==1: - mycopy = createAxis(copy.copy(self[:])) + b=self.getBounds() + if copyData == 1: + mycopy=createAxis(copy.copy(self[:])) else: - mycopy = createAxis(self[:]) - mycopy.id = self.id + mycopy=createAxis(self[:]) + mycopy.id=self.id try: mycopy.setBounds(b) except CDMSError: - b = mycopy.genGenericBounds() + b=mycopy.genGenericBounds() mycopy.setBounds(b) for k, v in self.attributes.items(): setattr(mycopy, k, v) return mycopy - def listall (self, all=None): + def listall(self, all=None): "Get list of info about this axis." - aname = self.id - result = [] + aname=self.id + result=[] result.append(' id: ' + aname) if self.isLatitude(): result.append(' Designated a latitude axis.') if self.isLongitude(): result.append(' Designated a longitude axis.') if self.isTime(): result.append(' Designated a time axis.') if self.isLevel(): result.append(' Designated a level axis.') try: - units = self.units + units=self.units result.append(' units: ' + units) except: pass - d = self.getValue() + d=self.getValue() result.append(' Length: ' + str(len(d))) result.append(' First: ' + str(d[0])) result.append(' Last: ' + str(d[-1])) - flag = 1 + flag=1 for k in self.attributes.keys(): if k in std_axis_attributes: continue if flag: result.append(' Other axis attributes:') - flag = 0 - result.append(' '+k+': '+str(self.attributes[k])) + flag=0 + result.append(' ' + k + ': ' + str(self.attributes[k])) result.append(' Python id: %s' % hex(id(self))) if all: result.append(" Values:") result.append(str(d)) - b = self.getBounds() + b=self.getBounds() result.append(" Bounds:") result.append(str(b)) return result def info(self, flag=None, device=None): "Write info about axis; include dimension values and weights if flag" - if device is None: device = sys.stdout + if device is None: device=sys.stdout device.write(str(self)) def isVirtual(self): "Return true iff coordinate values are implicitly defined." return 0 - shape = property(_getshape,None) - dtype = _getdtype + shape=property(_getshape, None) + dtype=_getdtype -## PropertiedClasses.set_property(AbstractAxis, 'shape', -## AbstractAxis._getshape, nowrite=1, nodelete=1) -## PropertiedClasses.set_property(AbstractAxis, 'dtype', -## AbstractAxis._getdtype, nowrite=1, nodelete=1) -## internattr.add_internal_attribute (AbstractAxis, 'id', 'parent') +# PropertiedClasses.set_property(AbstractAxis, 'shape', +# AbstractAxis._getshape, nowrite=1, nodelete=1) +# PropertiedClasses.set_property(AbstractAxis, 'dtype', +# AbstractAxis._getdtype, nowrite=1, nodelete=1) +# internattr.add_internal_attribute (AbstractAxis, 'id', 'parent') # One-dimensional coordinate axis in a dataset class Axis(AbstractAxis): - def __init__(self,parent,axisNode=None): + def __init__(self, parent, axisNode=None): if axisNode is not None and axisNode.tag != 'axis': raise CDMSError, 'Creating axis, node is not an axis node.' AbstractAxis.__init__(self, parent, axisNode) if axisNode is not None: if axisNode.partition is not None: - flatpart = axisNode.partition - self.__dict__['partition']=numpy.reshape(flatpart,(len(flatpart)/2,2)) + flatpart=axisNode.partition + self.__dict__['partition']=numpy.reshape( + flatpart, (len(flatpart) / 2, 2)) self.attributes['partition']=self.partition - self.id = axisNode.id - + self.id=axisNode.id + def typecode(self): return cdmsNode.CdToNumericType.get(self._node_.datatype) # Handle slices of the form x[i], x[i:j:k], x[(slice(i,j,k),)], and x[...] def __getitem__(self, key): - node = self._node_ - length = len(node) + node=self._node_ + length=len(node) # Allow key of form (slice(i,j),) etc. - if isinstance(key, tuple) and len(key)==1: - key = key[0] + if isinstance(key, tuple) and len(key) == 1: + key=key[0] - if isinstance(key, (int, numpy.int,numpy.int32)): # x[i] - if key>=length: + if isinstance(key, (int, numpy.int, numpy.int32)): # x[i] + if key >= length: raise IndexError, 'index out of bounds' else: - # Don't generate the entire array (if linear) just for one value - return node.data[key%length] - elif isinstance(key, slice): # x[i:j:k] + # Don't generate the entire array (if linear) just for one + # value + return node.data[key % length] + elif isinstance(key, slice): # x[i:j:k] if self._data_ is None: - self._data_ = node.getData() + self._data_=node.getData() return self._data_[key.start:key.stop:key.step] - elif isinstance(key, Ellipsis.__class__): # x[...] + elif isinstance(key, Ellipsis.__class__): # x[...] if self._data_ is None: - self._data_ = node.getData() + self._data_=node.getData() return self._data_ elif isinstance(key, tuple): - raise IndexError,'axis is one-dimensional' + raise IndexError, 'axis is one-dimensional' else: - raise IndexError,'index must be an integer: %s'%`key` + raise IndexError, 'index must be an integer: %s' % `key` # Get axis data def getData(self): @@ -1559,7 +1625,7 @@ class Axis(AbstractAxis): # Handle slices of the form x[i:j] def __getslice__(self, low, high): if self._data_ is None: - self._data_ = self.getData() + self._data_=self.getData() return self._data_[low:high] def __len__(self): @@ -1567,85 +1633,85 @@ class Axis(AbstractAxis): # Return true iff the axis representation is linear def isLinear(self): - return self._node_.dataRepresent==cdmsNode.CdLinear + return self._node_.dataRepresent == cdmsNode.CdLinear # Return the bounds array, or generate a default if autoBounds mode is on def getBounds(self): - boundsArray = self.getExplicitBounds() + boundsArray=self.getExplicitBounds() try: self.validateBounds(boundsArray) except: - boundsArray = None - abopt = getAutoBounds() - if boundsArray is None and (abopt==1 or (abopt==2 and (self.isLatitude() or self.isLongitude()))) : - boundsArray = self.genGenericBounds() - + boundsArray=None + abopt=getAutoBounds() + if boundsArray is None and (abopt == 1 or (abopt == 2 and (self.isLatitude() or self.isLongitude()))): + boundsArray=self.genGenericBounds() + return boundsArray # Return the bounds array, or None def getExplicitBounds(self): - boundsArray = None - if hasattr(self,'bounds'): - boundsName = self.bounds + boundsArray=None + if hasattr(self, 'bounds'): + boundsName=self.bounds try: - boundsVar = self.parent.variables[boundsName] - boundsArray = numpy.ma.filled(boundsVar.getSlice()) + boundsVar=self.parent.variables[boundsName] + boundsArray=numpy.ma.filled(boundsVar.getSlice()) except KeyError: - boundsArray = None + boundsArray=None return boundsArray def getCalendar(self): - if hasattr(self,'calendar'): - calendar = self.calendar.lower() + if hasattr(self, 'calendar'): + calendar=self.calendar.lower() elif self.parent is not None and hasattr(self.parent, 'calendar'): - calendar = self.parent.calendar.lower() + calendar=self.parent.calendar.lower() else: - calendar = None + calendar=None - cdcal = tagToCalendar.get(calendar, cdtime.DefaultCalendar) + cdcal=tagToCalendar.get(calendar, cdtime.DefaultCalendar) return cdcal # In-memory coordinate axis class TransientAxis(AbstractAxis): - axis_count = 0 + axis_count=0 def __init__(self, data, bounds=None, id=None, attributes=None, copy=0): AbstractAxis.__init__(self, None, None) if id is None: - TransientAxis.axis_count = TransientAxis.axis_count + 1 - id = 'axis_' + str(TransientAxis.axis_count) + TransientAxis.axis_count=TransientAxis.axis_count + 1 + id='axis_' + str(TransientAxis.axis_count) if attributes is None: - if hasattr(data, 'attributes'): attributes = data.attributes + if hasattr(data, 'attributes'): attributes=data.attributes if attributes is not None: for name, value in attributes.items(): if name not in ['missing_value', 'name']: setattr(self, name, value) - self.id = id + self.id=id if isinstance(data, AbstractAxis): if copy == 0: - self._data_ = data[:] + self._data_=data[:] else: - self._data_ = numpy.array(data[:]) + self._data_=numpy.array(data[:]) elif isinstance(data, numpy.ndarray): if copy == 0: - self._data_ = data + self._data_=data else: - self._data_ = numpy.array(data) + self._data_=numpy.array(data) elif isinstance(data, numpy.ma.MaskedArray): if numpy.ma.getmask(data) is not numpy.ma.nomask: raise CDMSError, \ 'Cannot construct an axis with a missing value.' - data = data.data + data=data.data if copy == 0: - self._data_ = data + self._data_=data else: - self._data_ = numpy.array(data) + self._data_=numpy.array(data) elif data is None: - self._data_ = None + self._data_=None else: - self._data_ = numpy.array(data) + self._data_=numpy.array(data) - self._doubledata_ = None + self._doubledata_=None self.setBounds(bounds) def __getitem__(self, key): @@ -1655,10 +1721,10 @@ class TransientAxis(AbstractAxis): return self._data_[low:high] def __setitem__(self, index, value): - self._data_[index] = numpy.ma.filled(value) + self._data_[index]=numpy.ma.filled(value) def __setslice__(self, low, high, value): - self._data_[low:high] = numpy.ma.filled(value) + self._data_[low:high]=numpy.ma.filled(value) def __len__(self): return len(self._data_) @@ -1666,7 +1732,7 @@ class TransientAxis(AbstractAxis): def getBounds(self): if self._bounds_ is not None: return copy.copy(self._bounds_) - elif (getAutoBounds()==1 or (getAutoBounds()==2 and (self.isLatitude() or self.isLongitude()))): + elif (getAutoBounds() == 1 or (getAutoBounds() == 2 and (self.isLatitude() or self.isLongitude()))): return self.genGenericBounds() else: return None @@ -1682,29 +1748,33 @@ class TransientAxis(AbstractAxis): # # mf 20010308 - add validate key word, by default do not validate # - def setBounds(self, bounds, persistent=0, validate=0, index=None, boundsid=None): + def setBounds(self, bounds, persistent=0, + validate=0, index=None, boundsid=None): if bounds is not None: if isinstance(bounds, numpy.ma.MaskedArray): - bounds = numpy.ma.filled(bounds) + bounds=numpy.ma.filled(bounds) if validate: - bounds = self.validateBounds(bounds) + bounds=self.validateBounds(bounds) else: # Just do the absolute minimum validation - requiredShape = (len(self),2) - requiredShape2 = (len(self)+1,) - if bounds.shape!=requiredShape and bounds.shape!=requiredShape2: + requiredShape=(len(self), 2) + requiredShape2=(len(self) + 1,) + if bounds.shape != requiredShape and bounds.shape != requiredShape2: raise CDMSError, InvalidBoundsArray + \ - 'shape is %s, should be %s or %s'%(`bounds.shape`,`requiredShape`,`requiredShape2`) - if bounds.shape==requiredShape2: # case of "n+1" bounds + 'shape is %s, should be %s or %s' % ( + `bounds.shape`, + `requiredShape`, + `requiredShape2`) + if bounds.shape == requiredShape2: # case of "n+1" bounds bounds2=numpy.zeros(requiredShape) - bounds2[:,0]=bounds[:-1] - bounds2[:,1]=bounds[1::] + bounds2[:, 0]=bounds[:-1] + bounds2[:, 1]=bounds[1::] bounds=bounds2 - self._bounds_ = copy.copy(bounds) + self._bounds_=copy.copy(bounds) else: - if (getAutoBounds()==1 or (getAutoBounds()==2 and (self.isLatitude() or self.isLongitude()))): - self._bounds_ = self.genGenericBounds() + if (getAutoBounds() == 1 or (getAutoBounds() == 2 and (self.isLatitude() or self.isLongitude()))): + self._bounds_=self.genGenericBounds() else: - self._bounds_ = None + self._bounds_=None def isLinear(self): return 0 @@ -1719,17 +1789,17 @@ class TransientVirtualAxis(TransientAxis): def __init__(self, axisname, axislen): TransientAxis.__init__(self, None, id=axisname) - self._virtualLength = axislen # length of the axis + self._virtualLength=axislen # length of the axis def __len__(self): return self._virtualLength - def __str__ (self): - return ""%(self.id, self._virtualLength) + def __str__(self): + return "" % (self.id, self._virtualLength) - __repr__ = __str__ + __repr__=__str__ - def clone (self, copyData=1): + def clone(self, copyData=1): """clone (self, copyData=1) Return a copy of self as a transient virtual axis. If copyData is 1, make a separate copy of the data.""" @@ -1747,7 +1817,7 @@ class TransientVirtualAxis(TransientAxis): def setBounds(self, bounds): "No boundaries on virtual axes" - self._bounds_ = None + self._bounds_=None def __getitem__(self, key): return self.getData()[key] @@ -1755,79 +1825,84 @@ class TransientVirtualAxis(TransientAxis): def __getslice__(self, low, high): return self.getData()[low:high] -## PropertiedClasses.initialize_property_class (TransientVirtualAxis) +# PropertiedClasses.initialize_property_class (TransientVirtualAxis) # One-dimensional coordinate axis in a CdmsFile. class FileAxis(AbstractAxis): - + def __init__(self, parent, axisname, obj=None): - AbstractAxis.__init__ (self, parent, None) - val = self.__cdms_internals__ +['name_in_file',] - self.___cdms_internals__ = val - self.id = axisname - self._obj_ = obj + AbstractAxis.__init__(self, parent, None) + val=self.__cdms_internals__ + ['name_in_file', ] + self.___cdms_internals__=val + self.id=axisname + self._obj_=obj # Overshadows file boundary data, if not None - self._boundsArray_ = None - (units,typecode,name_in_file,parent_varname,dimtype,ncid) = \ - parent._file_.dimensioninfo[axisname] - self.__dict__['_units'] = units - att = self.attributes + self._boundsArray_=None + (units, typecode, name_in_file, parent_varname, + dimtype, ncid)=parent._file_.dimensioninfo[axisname] + self.__dict__['_units']=units + att=self.attributes att['units']=units - self.attributes = att - self.name_in_file = self.id + self.attributes=att + self.name_in_file=self.id if name_in_file: - self.name_in_file = name_in_file + self.name_in_file=name_in_file # Combine the attributes of the variable object, if any if obj is not None: for attname in self._obj_.__dict__.keys(): - attval = getattr(self._obj_,attname) + attval=getattr(self._obj_, attname) if not callable(attval): - self.__dict__[attname] = attval - att = self.attributes + self.__dict__[attname]=attval + att=self.attributes att[attname]=attval - self.attributes= att - + self.attributes=att + def getData(self): - if cdmsobj._debug==1: - print 'Getting array for axis',self.id + if cdmsobj._debug == 1: + print 'Getting array for axis', self.id if self.parent is None: raise CDMSError, FileWasClosed + self.id try: - result = self.parent._file_.readDimension(self.id) + result=self.parent._file_.readDimension(self.id) except: try: - result = apply(self._obj_.getitem, (slice(None,None),)) + result=apply(self._obj_.getitem, (slice(None, None),)) except: - raise CDMSError,'Data for dimension %s not found'%self.id + raise CDMSError, 'Data for dimension %s not found' % self.id return result def typecode(self): if self.parent is None: raise CDMSError, FileWasClosed + self.id - (units,typecode,name_in_file,parent_varname,dimtype,ncid) = \ - self.parent._file_.dimensioninfo[self.id] + (units, typecode, name_in_file, parent_varname, + dimtype, ncid)=self.parent._file_.dimensioninfo[self.id] return typecode - + def _setunits(self, value): - self._units = value + self._units=value self.attributes['units']=value if self.parent is None: raise CDMSError, FileWasClosed + self.id setattr(self._obj_, 'units', value) - (units,typecode,name_in_file,parent_varname,dimtype,ncid) = \ - self.parent._file_.dimensioninfo[self.id] - self.parent._file_.dimensioninfo[self.id] = \ - (value,typecode,name_in_file,parent_varname,dimtype,ncid) + (units, typecode, name_in_file, parent_varname, + dimtype, ncid)=self.parent._file_.dimensioninfo[self.id] + self.parent._file_.dimensioninfo[self.id]=( + value, + typecode, + name_in_file, + parent_varname, + dimtype, + ncid) def _getunits(self): return self._units def _delunits(self): del(self._units) del(self.attributes['units']) - delattr(self._obj_,'units') + delattr(self._obj_, 'units') - def __getattr__(self,name): + def __getattr__(self, name): if name == 'units': return self._units try: @@ -1835,27 +1910,27 @@ class FileAxis(AbstractAxis): except: raise AttributeError # setattr writes external attributes to the file - def __setattr__ (self, name, value): + def __setattr__(self, name, value): if name == 'units': self._setunits(value) return if hasattr(self, 'parent') and self.parent is None: raise CDMSError, FileWasClosed + self.id -## s = self.get_property_s (name) -## if s is not None: -## s(self, name, value) -## return - if not name in self.__cdms_internals__ and name[0]!='_': +# s = self.get_property_s (name) +# if s is not None: +# s(self, name, value) +# return + if not name in self.__cdms_internals__ and name[0] != '_': setattr(self._obj_, name, value) self.attributes[name]=value - self.__dict__[name] = value + self.__dict__[name]=value # delattr deletes external global attributes in the file def __delattr__(self, name): -## d = self.get_property_d(name) -## if d is not None: -## d(self, name) -## return +# d = self.get_property_d(name) +# if d is not None: +# d(self, name) +# return if name == "units": self._delunits() return @@ -1870,83 +1945,84 @@ class FileAxis(AbstractAxis): # Read data # If the axis has a related Cdunif variable object, just read that variable - # otherwise, cache the Cdunif (read-only) data values in self._data_. in this case, - # the axis is not extensible, so it is not necessary to reread it each time. + # otherwise, cache the Cdunif (read-only) data values in self._data_. in this case, + # the axis is not extensible, so it is not necessary to reread it each + # time. def __getitem__(self, key): if self.parent is None: raise CDMSError, FileWasClosed + self.id # See __getslice__ comment below. - if (self._obj_ is not None) and (self.parent._mode_!='r') and not (hasattr(self.parent,'format') and self.parent.format=="DRS"): + if (self._obj_ is not None) and (self.parent._mode_ != 'r') and not (hasattr(self.parent, 'format') and self.parent.format == "DRS"): # For negative strides, get the equivalent slice with positive stride, # then reverse the result. - if (isinstance(key, slice) and (key.step is not None) and key.step<0: - posslice = reverseSlice(key,len(self)) - result = apply(self._obj_.getitem, (posslice,)) + if (isinstance(key, slice) and (key.step is not None) and key.step < 0: + posslice=reverseSlice(key, len(self)) + result=apply(self._obj_.getitem, (posslice,)) return result[::-1] else: - if isinstance(key, int) and key>=len(self): - raise IndexError, 'Index out of bounds: %d'%key + if isinstance(key, int) and key >= len(self): + raise IndexError, 'Index out of bounds: %d' % key if isinstance(key, tuple): - key = (key,) + key=(key,) return apply(self._obj_.getitem, key) if self._data_ is None: - self._data_ = self.getData() - length = len(self._data_) + self._data_=self.getData() + length=len(self._data_) if isinstance(key, int): # x[i] - if key>=length: + if key >= length: raise IndexError, 'index out of bounds' else: - return self._data_[key%length] - elif isinstance(key, slice): # x[i:j:k] + return self._data_[key % length] + elif isinstance(key, slice): # x[i:j:k] return self._data_[key.start:key.stop:key.step] - elif isinstance(key, Ellipsis.__class__): # x[...] + elif isinstance(key, Ellipsis.__class__): # x[...] return self._data_ elif isinstance(key, tuple): - raise IndexError,'axis is one-dimensional' + raise IndexError, 'axis is one-dimensional' else: - raise IndexError,'index must be an integer or slice: %s'%`key` + raise IndexError, 'index must be an integer or slice: %s' % `key` def __getslice__(self, low, high): # Hack to prevent netCDF overflow error on 64-bit architectures - high = min(Max32int, high) - + high=min(Max32int, high) + # Hack to fix a DRS bug: force use of readDimension for DRS axes. # Since DRS is read-only here, it is OK just to cache all dimensions. if self.parent is None: raise CDMSError, FileWasClosed + self.id - if (self._obj_ is not None) and (self.parent._mode_!='r') and not (hasattr(self.parent,'format') and self.parent.format=="DRS"): - return apply(self._obj_.getslice,(low,high)) + if (self._obj_ is not None) and (self.parent._mode_ != 'r') and not (hasattr(self.parent, 'format') and self.parent.format == "DRS"): + return apply(self._obj_.getslice, (low, high)) else: if self._data_ is None: - self._data_ = self.getData() + self._data_=self.getData() return self._data_[low:high] def __setitem__(self, index, value): if self._obj_ is None: raise CDMSError, ReadOnlyAxis + self.id if self.parent is None: - raise CDMSError, FileWasClosed+self.id - return apply(self._obj_.setitem,(index,numpy.ma.filled(value))) + raise CDMSError, FileWasClosed + self.id + return apply(self._obj_.setitem, (index, numpy.ma.filled(value))) def __setslice__(self, low, high, value): # Hack to prevent netCDF overflow error on 64-bit architectures - high = min(Max32int, high) + high=min(Max32int, high) if self._obj_ is None: raise CDMSError, ReadOnlyAxis + self.id if self.parent is None: - raise CDMSError, FileWasClosed+self.id - return apply(self._obj_.setslice,(low,high,numpy.ma.filled(value))) + raise CDMSError, FileWasClosed + self.id + return apply(self._obj_.setslice, (low, high, numpy.ma.filled(value))) def __len__(self): if self.parent is None: raise CDMSError, FileWasClosed + self.id if self._obj_ is not None: - length = len(self._obj_) + length=len(self._obj_) elif self._data_ is None: - self._data_ = self.getData() - length = len(self._data_) + self._data_=self.getData() + length=len(self._data_) else: - length = len(self._data_) + length=len(self._data_) return length def isLinear(self): @@ -1954,31 +2030,31 @@ class FileAxis(AbstractAxis): # Return the bounds array, or generate a default if autobounds mode is set def getBounds(self): - boundsArray = self.getExplicitBounds() + boundsArray=self.getExplicitBounds() try: - boundsArray = self.validateBounds(boundsArray) - except Exception,err: - boundsArray = None - if boundsArray is None and (getAutoBounds()==1 or (getAutoBounds()==2 and (self.isLatitude() or self.isLongitude()))): - boundsArray = self.genGenericBounds() - + boundsArray=self.validateBounds(boundsArray) + except Exception, err: + boundsArray=None + if boundsArray is None and (getAutoBounds() == 1 or (getAutoBounds() == 2 and (self.isLatitude() or self.isLongitude()))): + boundsArray=self.genGenericBounds() + return boundsArray # Return the bounds array, or None def getExplicitBounds(self): if self._boundsArray_ is None: - boundsArray = None - if hasattr(self,'bounds'): - boundsName = self.bounds + boundsArray=None + if hasattr(self, 'bounds'): + boundsName=self.bounds try: - boundsVar = self.parent[boundsName] - boundsArray = numpy.ma.filled(boundsVar) - self._boundsArray_ = boundsArray # for climatology performance - except KeyError,err: + boundsVar=self.parent[boundsName] + boundsArray=numpy.ma.filled(boundsVar) + self._boundsArray_=boundsArray # for climatology performance + except KeyError, err: print err - boundsArray = None + boundsArray=None else: - boundsArray = self._boundsArray_ + boundsArray=self._boundsArray_ return boundsArray @@ -1989,58 +2065,63 @@ class FileAxis(AbstractAxis): # index in the extended dimension (default is index=0). # If the bounds variable is new, use the name boundsid, or 'bounds_' # if unspecified. - def setBounds(self, bounds, persistent=0, validate=0, index=None, boundsid=None): + def setBounds(self, bounds, persistent=0, + validate=0, index=None, boundsid=None): if persistent: if index is None: if validate: - bounds = self.validateBounds(bounds) - index = 0 + bounds=self.validateBounds(bounds) + index=0 # Create the bound axis, if necessary - file = self.parent + file=self.parent if file._boundAxis_ is None: # First look for 'bound' of length two - if file.axes.has_key("bound") and len(file.axes["bound"])==2: - file._boundAxis_ = file.axes["bound"] + if file.axes.has_key("bound") and len(file.axes["bound"]) == 2: + file._boundAxis_=file.axes["bound"] else: - file._boundAxis_ = file.createVirtualAxis("bound",2) + file._boundAxis_=file.createVirtualAxis("bound", 2) # Create the boundary variable if necessary - if hasattr(self,'bounds'): - boundName = self.bounds - boundVar = file.variables[boundName] + if hasattr(self, 'bounds'): + boundName=self.bounds + boundVar=file.variables[boundName] else: if boundsid is None: - boundName = "bounds_"+self.id + boundName="bounds_" + self.id else: - boundName = boundsid - boundVar = file.createVariable(boundName, cdmsNode.NumericToCdType.get(bounds.dtype.char), (self,file._boundAxis_)) + boundName=boundsid + boundVar=file.createVariable( + boundName, + cdmsNode.NumericToCdType.get(bounds.dtype.char), + (self, + file._boundAxis_)) # And link to self - self.bounds = boundName - self._boundsArray_ = None + self.bounds=boundName + self._boundsArray_=None - boundVar[index:index+len(bounds)] = bounds + boundVar[index:index + len(bounds)]=bounds else: - self._boundsArray_ = copy.copy(bounds) + self._boundsArray_=copy.copy(bounds) def getCalendar(self): - if hasattr(self,'calendar'): - calendar = self.calendar.lower() + if hasattr(self, 'calendar'): + calendar=self.calendar.lower() elif self.parent is not None and hasattr(self.parent, 'calendar'): - calendar = self.parent.calendar.lower() + calendar=self.parent.calendar.lower() else: - calendar = None + calendar=None - cdcal = tagToCalendar.get(calendar, cdtime.DefaultCalendar) + cdcal=tagToCalendar.get(calendar, cdtime.DefaultCalendar) return cdcal def isVirtual(self): "Return true iff coordinate values are implicitly defined." # No virtual axes in GrADS files - if self.parent is not None and hasattr(self.parent, 'format') and self.parent.format=='GRADS': + if self.parent is not None and hasattr(self.parent, 'format') and self.parent.format == 'GRADS': return 0 return (self._obj_ is None) @@ -2050,11 +2131,11 @@ class FileAxis(AbstractAxis): return (self.parent._file_.dimensions[self.id] is None) else: return False -## PropertiedClasses.set_property (FileAxis, 'units', -## acts=FileAxis._setunits, -## nodelete=1 -## ) -## internattr.add_internal_attribute(FileAxis, 'name_in_file') +# PropertiedClasses.set_property (FileAxis, 'units', +# acts=FileAxis._setunits, +# nodelete=1 +# ) +# internattr.add_internal_attribute(FileAxis, 'name_in_file') class FileVirtualAxis(FileAxis): """An axis with no explicit representation of data values in the file. @@ -2066,8 +2147,8 @@ class FileVirtualAxis(FileAxis): def __init__(self, parent, axisname, axislen): FileAxis.__init__(self, parent, axisname) - self._virtualLength = axislen # length of the axis - + self._virtualLength=axislen # length of the axis + def __len__(self): return self._virtualLength @@ -2078,95 +2159,95 @@ class FileVirtualAxis(FileAxis): "Return true iff coordinate values are implicitly defined." return 1 -## PropertiedClasses.initialize_property_class (FileVirtualAxis) +# PropertiedClasses.initialize_property_class (FileVirtualAxis) -######## Functions for selecting axes -def axisMatchAxis (axes, specifications=None, omit=None, order=None): - """Given a list of axes and a specification or list of +# Functions for selecting axes +def axisMatchAxis(axes, specifications=None, omit=None, order=None): + """Given a list of axes and a specification or list of specificatons, and a specification or list of specifications - of those axes to omit, return a list of - those axes in the list that match the specification but - do not include in the list any axes that matches an omit + of those axes to omit, return a list of + those axes in the list that match the specification but + do not include in the list any axes that matches an omit specification. If specifications is None, include all axes less the omitted ones. - Individual specifications must be integer indices into axes or + Individual specifications must be integer indices into axes or matching criteria as detailed in axisMatches. Axes are returned in the order they occur in the axes argument unless - order is given. + order is given. - order can be a string containing the symbols t,x,y,z, or -. - If a - is given, any elements of the result not chosen otherwise are + order can be a string containing the symbols t,x,y,z, or -. + If a - is given, any elements of the result not chosen otherwise are filled in from left to right with remaining candidates. """ return [axes[i] for i in \ axisMatchIndex(axes, specifications, omit, order)] -def axisMatchIndex (axes, specifications=None, omit=None, order=None): - """Given a list of axes and a specification or list of +def axisMatchIndex(axes, specifications=None, omit=None, order=None): + """Given a list of axes and a specification or list of specificatons, and a specification or list of specifications - of those axes to omit, return a list of the indices of - those axes in the list that match the specification but - do not include in the list any axes that matches an omit + of those axes to omit, return a list of the indices of + those axes in the list that match the specification but + do not include in the list any axes that matches an omit specification. If specifications is None, include all axes less the omitted ones. - Individual specifications must be integer indices into axes or + Individual specifications must be integer indices into axes or matching criteria as detailed in axisMatches. The indices of axes are returned in the order the axes occur in the axes argument, unless order is given. - order can be a string containing the symbols t,x,y,z, or -. - If a - is given, any elements of the result not chosen otherwise are + order can be a string containing the symbols t,x,y,z, or -. + If a - is given, any elements of the result not chosen otherwise are filled in from left to right with remaining candidates. """ if specifications is None: - speclist = axes + speclist=axes elif isinstance(specifications, basestring): - speclist = [specifications] + speclist=[specifications] elif isinstance(specifications, list): - speclist = specifications + speclist=specifications elif isinstance(specifications, tuple): speclist=list(specifications) elif isinstance(specifications, int): - speclist = [specifications] + speclist=[specifications] elif callable(specifications): - speclist = [specifications] - else: # to allow arange, etc. - speclist = list(numpy.ma.filled(specifications)) + speclist=[specifications] + else: # to allow arange, etc. + speclist=list(numpy.ma.filled(specifications)) - candidates = [] + candidates=[] for i in range(len(axes)): for s in speclist: if isinstance(s, int): - r = (s == i) + r=(s == i) else: - r = axisMatches(axes[i], s) + r=axisMatches(axes[i], s) if r: candidates.append(i) break if not candidates: - return candidates #list empty + return candidates # list empty if omit is None: - omitlist = [] + omitlist=[] elif isinstance(omit, basestring): - omitlist = [omit] + omitlist=[omit] elif isinstance(omit, list): - omitlist = omit + omitlist=omit elif isinstance(omit, tuple): omitlist=list(omit) elif isinstance(omit, int): - omitlist = [omit] + omitlist=[omit] elif callable(omit): - omitlist = [omit] + omitlist=[omit] elif isinstance(omit, AbstractAxis): - omitlist = [omit] + omitlist=[omit] else: raise CDMSError, 'Unknown type of omit specifier.' @@ -2179,11 +2260,11 @@ def axisMatchIndex (axes, specifications=None, omit=None, order=None): elif isinstance(s, AbstractAxis): for i in range(len(candidates)): if s is axes[candidates[i]]: - del candidates[i] + del candidates[i] break else: for i in range(len(candidates)): - r = axisMatches(axes[candidates[i]], s) + r=axisMatches(axes[candidates[i]], s) if r: del candidates[i] break @@ -2191,31 +2272,31 @@ def axisMatchIndex (axes, specifications=None, omit=None, order=None): if order is None: return candidates - n = len(candidates) - m = len(order) - result = [None]*n + n=len(candidates) + m=len(order) + result=[None] * n # this loop is done this way for future escapes where elements of order # are not single chars. - j = 0 - io = 0 + j=0 + io=0 while j < n: if j >= m or order[io] == '-': - result[j] = candidates[0] + result[j]=candidates[0] del candidates[0] j += 1 io += 1 continue elif order[j] == 't': - oj = 'time' + oj='time' io += 1 elif order[j] == 'x': - oj = 'longitude' + oj='longitude' io += 1 elif order[j] == 'y': - oj = 'latitude' + oj='latitude' io += 1 elif order[j] == 'z': - oj = 'level' + oj='level' io += 1 else: # later could put in escaped ids or indices @@ -2223,21 +2304,21 @@ def axisMatchIndex (axes, specifications=None, omit=None, order=None): for i in range(n): if axisMatches(axes[candidates[i]], oj): - result[j] = candidates[i] + result[j]=candidates[i] del candidates[i] break else: raise CDMSError, "Axis requested in order specification not there" - j += 1 + j += 1 return result - + def axisMatches(axis, specification): """Return 1 or 0 depending on whether axis matches the specification. Specification must be one of: - 1. a string representing an axis id or one of - the keywords time, fctau0, latitude or lat, longitude or lon, or - lev or level. + 1. a string representing an axis id or one of + the keywords time, fctau0, latitude or lat, longitude or lon, or + lev or level. axis may be surrounded with parentheses or spaces. @@ -2249,20 +2330,20 @@ def axisMatches(axis, specification): if the value returned is true, the axis matches. 3. an axis object; will match if it is the same object as axis. - """ + """ if isinstance(specification, basestring): - s = specification.lower() - s = s.strip() + s=specification.lower() + s=s.strip() while s[0] == '(': if s[-1] != ')': raise CDMSError, 'Malformed axis spec, ' + specification - s = s[1:-1].strip() + s=s[1:-1].strip() if axis.id.lower() == s: return 1 elif (s == 'time') or (s in time_aliases): - return axis.isTime() + return axis.isTime() elif (s == 'fctau0') or (s in forecast_aliases): - return axis.isForecast() + return axis.isForecast() elif (s[0:3] == 'lat') or (s in latitude_aliases): return axis.isLatitude() elif (s[0:3] == 'lon') or (s in longitude_aliases): @@ -2273,10 +2354,10 @@ def axisMatches(axis, specification): return 0 elif callable(specification): - r = specification(axis) - if r: + r=specification(axis) + if r: return 1 - else: + else: return 0 elif isinstance(specification, AbstractAxis): @@ -2284,26 +2365,26 @@ def axisMatches(axis, specification): raise CDMSError, "Specification not acceptable: "\ + str(type(specification)) + ', ' + str(specification) - + def concatenate(axes, id=None, attributes=None): """Concatenate the axes, return a transient axis.""" - - data = numpy.ma.concatenate([ax[:] for ax in axes]) - boundsArray = [ax.getBounds() for ax in axes] + + data=numpy.ma.concatenate([ax[:] for ax in axes]) + boundsArray=[ax.getBounds() for ax in axes] if None in boundsArray: - bounds = None + bounds=None else: - bounds = numpy.ma.concatenate(boundsArray) + bounds=numpy.ma.concatenate(boundsArray) return TransientAxis(data, bounds=bounds, id=id, attributes=attributes) def take(ax, indices): """Take values indicated by indices list, return a transient axis.""" # Bug in ma compatibility module - data = numpy.ma.take(ax[:], indices) - abounds = ax.getBounds() + data=numpy.ma.take(ax[:], indices) + abounds=ax.getBounds() if abounds is not None: - bounds = numpy.ma.take(abounds, indices, axis=0) + bounds=numpy.ma.take(abounds, indices, axis=0) else: - bounds = None + bounds=None return TransientAxis(data, bounds=bounds, id=ax.id, attributes=ax.attributes) diff --git a/Packages/cdms2/Lib/bindex.py b/Packages/cdms2/Lib/bindex.py index 9156c9709..913d6fdbd 100644 --- a/Packages/cdms2/Lib/bindex.py +++ b/Packages/cdms2/Lib/bindex.py @@ -1,9 +1,11 @@ -## Automatically adapted for numpy.oldnumeric Aug 01, 2007 by -## Further modified to be pure new numpy June 24th 2008 +# Automatically adapted for numpy.oldnumeric Aug 01, 2007 by +# Further modified to be pure new numpy June 24th 2008 """Bin index for non-rectilinear grids""" -import _bindex, numpy +import _bindex +import numpy + def bindexHorizontalGrid(latlin, lonlin): """Create a bin index for a horizontal grid. @@ -12,14 +14,16 @@ def bindexHorizontalGrid(latlin, lonlin): Returns the index. """ - lonlin = numpy.mod(lonlin,360) - NI,NJ = _bindex.getLens() - head = numpy.zeros(NI*NJ,dtype='l') # This should match NBINI, NBINJ in bindex.c - next = numpy.zeros(len(latlin),dtype='l') + lonlin = numpy.mod(lonlin, 360) + NI, NJ = _bindex.getLens() + head = numpy.zeros(NI * NJ, dtype='l') + # This should match NBINI, NBINJ in bindex.c + next = numpy.zeros(len(latlin), dtype='l') _bindex.bindex(latlin, lonlin, head, next) - + return (head, next) + def intersectHorizontalGrid(latspecs, lonspecs, latlin, lonlin, index): """Intersect a horizontal grid with a lat-lon region. @@ -31,7 +35,7 @@ def intersectHorizontalGrid(latspecs, lonspecs, latlin, lonlin, index): Returns an array of indices, in latlin/lonlin, of the points in the intersection. """ - points = numpy.zeros(len(latlin),dtype='l') + points = numpy.zeros(len(latlin), dtype='l') if latspecs is None: slat = -90.0 elat = 90.0 @@ -41,14 +45,14 @@ def intersectHorizontalGrid(latspecs, lonspecs, latlin, lonlin, index): elat = latspecs[1] latopt = latspecs[2] - if slat>elat: + if slat > elat: tmp = slat slat = elat elat = tmp # If the longitude range is >=360.0, just intersect with the full range. # Otherwise, the points array could overflow and generate a seg fault. - if lonspecs is None or abs(lonspecs[1]-lonspecs[0])>=360.0: + if lonspecs is None or abs(lonspecs[1] - lonspecs[0]) >= 360.0: slon = 0.0 elon = 360.0 lonopt = 'co' @@ -57,11 +61,22 @@ def intersectHorizontalGrid(latspecs, lonspecs, latlin, lonlin, index): elon = lonspecs[1] lonopt = lonspecs[2] - if slon>elon: + if slon > elon: tmp = slon slon = elon elon = tmp - npoints = _bindex.intersect(slat, slon, elat, elon, latlin, lonlin, index[0], index[1], points, latopt, lonopt) + npoints = _bindex.intersect( + slat, + slon, + elat, + elon, + latlin, + lonlin, + index[0], + index[1], + points, + latopt, + lonopt) return points[:npoints] diff --git a/Packages/cdms2/Lib/cache.py b/Packages/cdms2/Lib/cache.py index c7456b503..12163fe94 100644 --- a/Packages/cdms2/Lib/cache.py +++ b/Packages/cdms2/Lib/cache.py @@ -1,8 +1,16 @@ """ CDMS cache management and file movement objects """ -import cdurllib, urlparse, tempfile, os, time, cdmsobj, sys, errno, shelve -from error import CDMSError +import cdurllib +import urlparse +import tempfile +import os +import time +import cdmsobj +import sys +import errno +import shelve +from .error import CDMSError MethodNotImplemented = "Method not yet implemented" SchemeNotSupported = "Scheme not supported: " LockError = "Lock error:" @@ -14,6 +22,7 @@ _lock_max_tries = 10 # Number of tries for a lock _lock_naptime = 1 # Seconds between lock tries _cache_tempdir = None # Default temporary directory + def lock(filename): """ Acquire a file-based lock with the given name. @@ -32,48 +41,50 @@ def lock(filename): while (not success) and (tries < _lock_max_tries): try: if cdmsobj._debug: - print 'Process %d: Trying to acquire lock %s'%(os.getpid(),path) - fd = os.open(path, os.O_CREAT | os.O_WRONLY | os.O_EXCL, 0666) + print 'Process %d: Trying to acquire lock %s' % (os.getpid(), path) + fd = os.open(path, os.O_CREAT | os.O_WRONLY | os.O_EXCL, 0o666) # If the open failed because the file already exists, keep trying, otherwise # reraise the error except OSError: - if sys.exc_value.errno!=errno.EEXIST: + if sys.exc_value.errno != errno.EEXIST: raise tries = tries + 1 else: if cdmsobj._debug: - print 'Process %d: Acquired lock %s after %d tries'%(os.getpid(),path,tries) + print 'Process %d: Acquired lock %s after %d tries' % (os.getpid(), path, tries) success = 1 break # Sleep until next retry if cdmsobj._debug: - print 'Process %d: Failed to acquire lock %s, sleeping'%(os.getpid(),path) + print 'Process %d: Failed to acquire lock %s, sleeping' % (os.getpid(), path) time.sleep(_lock_naptime) # Error if the lock could not be acquired if not success: - raise CDMSError, LockError + 'Could not acquire a lock on %s'%path + raise CDMSError(LockError + 'Could not acquire a lock on %s' % path) # The lock succeeded, so just close the file - we don't need to write # anything here else: os.close(fd) + def unlock(filename): """ Delete a file-based lock with the given name. - Usage:unlock(filename) + Usage:unlock(filename) If the function returns, the lock was successfully deleted. Note: This function is UNIX-specific. """ path = lockpath(filename) if cdmsobj._debug: - print 'Process %d: Unlocking %s'%(os.getpid(),path) + print 'Process %d: Unlocking %s' % (os.getpid(), path) os.unlink(path) + def lockpath(filename): """ Generate the pathname of a lock. Creates the directory containing the lock @@ -84,12 +95,12 @@ def lockpath(filename): if not _cache_tempdir: tempfile.mktemp() - _cache_tempdir = os.path.join(tempfile.tempdir,'cdms') + _cache_tempdir = os.path.join(tempfile.tempdir, 'cdms') if not os.path.isdir(_cache_tempdir): if cdmsobj._debug: - print 'Process %d: Creating cache directory %s'%(os.getpid(),_cache_tempdir) - os.mkdir(_cache_tempdir,0777) - return os.path.join(_cache_tempdir,filename) + print 'Process %d: Creating cache directory %s' % (os.getpid(), _cache_tempdir) + os.mkdir(_cache_tempdir, 0o777) + return os.path.join(_cache_tempdir, filename) _useWindow = 0 # If true, use a progress dialog _pythonTransfer = 0 @@ -97,6 +108,7 @@ _globusTransfer = 1 _requestManagerTransfer = 2 _transferMethod = _pythonTransfer # Method of transferring files + def useWindow(): """ Specify that dialog windows should be used if possible. Do not call this directly, use @@ -105,6 +117,7 @@ def useWindow(): global _useWindow _useWindow = 1 + def useTTY(): """ Informational messages such as FTP status should be sent to the terminal. See useWindow. @@ -112,6 +125,7 @@ def useTTY(): global _useWindow _useWindow = 0 + def useGlobusTransfer(): """ Specify that file transfers should use the Globus storage API (SC-API). See usePythonTransfer. @@ -119,6 +133,7 @@ def useGlobusTransfer(): global _transferMethod _transferMethod = _globusTransfer + def usePythonTransfer(): """ Specify that file transfers should use the Python libraries urllib, ftplib. See useGlobusTransfer. @@ -126,15 +141,18 @@ def usePythonTransfer(): global _transferMethod _transferMethod = _pythonTransfer + def useRequestManagerTransfer(): try: import reqm except ImportError: - raise CDMSError, RequestManagerNotSupported + raise CDMSError(RequestManagerNotSupported) global _transferMethod _transferMethod = _requestManagerTransfer -def copyFile(fromURL, toURL, callback=None, lcpath=None, userid=None, useReplica=1): + +def copyFile(fromURL, toURL, callback=None, + lcpath=None, userid=None, useReplica=1): """ Copy file to local file . For FTP transfers, if cache._useWindow is true, display a progress dialog, otherwise just print progress messages. @@ -145,15 +163,16 @@ def copyFile(fromURL, toURL, callback=None, lcpath=None, userid=None, useReplica """ if callback is None: if _useWindow: - import gui + from . import gui dialogParent = gui.getProgressParent() dialog = gui.CdProgressDialog(dialogParent, fromURL) callback = gui.updateProgressGui else: callback = cdurllib.sampleReportHook - (scheme,netloc,path,parameters,query,fragment)=urlparse.urlparse(fromURL) - if scheme=='ftp': - if _transferMethod==_pythonTransfer: + (scheme, netloc, path, parameters, query, + fragment) = urlparse.urlparse(fromURL) + if scheme == 'ftp': + if _transferMethod == _pythonTransfer: urlopener = cdurllib.CDURLopener() # In window environment, attach the dialog to the opener. This will @@ -167,51 +186,57 @@ def copyFile(fromURL, toURL, callback=None, lcpath=None, userid=None, useReplica except: if _useWindow: dialog.Destroy() - raise - elif _transferMethod==_globusTransfer: # Transfer via Globus SC-API + raise + elif _transferMethod == _globusTransfer: # Transfer via Globus SC-API try: import globus.storage except ImportError: - raise CDMSError, GlobusNotSupported + raise CDMSError(GlobusNotSupported) - globus.storage.transfer(fromURL, "file:"+toURL) + globus.storage.transfer(fromURL, "file:" + toURL) else: - raise CDMSError, SchemeNotSupported + scheme + raise CDMSError(SchemeNotSupported + scheme) return - elif _transferMethod==_requestManagerTransfer: # Request manager gransfer - import reqm, signal + elif _transferMethod == _requestManagerTransfer: # Request manager gransfer + import reqm + import signal # Define an alarm handler, to poll the request manager def handler(signum, frame): pass - # Obtain server reference from environment variable ESG_REQM_REF if present + # Obtain server reference from environment variable ESG_REQM_REF if + # present serverRef = os.environ.get('ESG_REQM_REF', '/tmp/esg_rqm.ref') server = reqm.RequestManager(iorFile=serverRef) - result, token = server.requestFile(userid, lcpath, path, toURL, useReplica) + result, token = server.requestFile( + userid, lcpath, path, toURL, useReplica) server.execute(token) # Poll the request manager for completion, signalled by estim<=0.0 - while 1: + while True: signal.signal(signal.SIGALRM, handler) estim = server.estimate(token) - print 'Estimate: ',estim - if estim<=0.0: break + print 'Estimate: ', estim + if estim <= 0.0: + break signal.alarm(3) # Number of seconds between polls signal.pause() #!!!! Remove this when gsincftp uses the right target name !!! - -## oldpath = os.path.join(os.path.dirname(toURL),path) -## os.rename(oldpath,toURL) + +# oldpath = os.path.join(os.path.dirname(toURL),path) +# os.rename(oldpath,toURL) #!!!! - + return else: - raise CDMSError, SchemeNotSupported + scheme + raise CDMSError(SchemeNotSupported + scheme) # A simple data cache + + class Cache: indexpath = None # Path of data cache index @@ -227,9 +252,10 @@ class Cache: except: pass lock("index_lock") - self.index = shelve.open(self.indexpath) # Persistent cache index + self.index = shelve.open(self.indexpath) # Persistent cache index try: - os.chmod(self.indexpath,0666) # Make index file world writeable + os.chmod(self.indexpath, 0o666) + # Make index file world writeable except: pass self.index.close() @@ -237,7 +263,7 @@ class Cache: # Clean up pending read notifications in the cache. This will also # mess up tranfers in progress... self.clean() - self.direc = os.path.dirname(self.indexpath) # Cache directory + self.direc = os.path.dirname(self.indexpath) # Cache directory def get(self, filekey): """ @@ -269,7 +295,7 @@ class Cache: lock("index_lock") try: if cdmsobj._debug: - print 'Process %d: Adding cache file %s,\n key %s'%(os.getpid(),path,filekey) + print 'Process %d: Adding cache file %s,\n key %s' % (os.getpid(), path, filekey) self.index = shelve.open(self.indexpath) self.index[filekey] = path except: @@ -294,7 +320,8 @@ class Cache: pass unlock("index_lock") - def copyFile(self, fromURL, filekey, lcpath=None, userid=None, useReplica=None): + def copyFile(self, fromURL, filekey, + lcpath=None, userid=None, useReplica=None): """ Copy the file into the cache. Return the result path. @@ -302,9 +329,9 @@ class Cache: is the string user ID, is true iff the request manager should search the replica catalog for the actual file to transfer. """ - + # Put a notification into the cache, that this file is being read. - self.put(filekey,"__READ_PENDING__") + self.put(filekey, "__READ_PENDING__") # Get a temporary file in the cache tempdir = tempfile.tempdir @@ -314,21 +341,29 @@ class Cache: # Copy to the temporary file try: - copyFile(fromURL, toPath, lcpath=lcpath, userid=userid, useReplica=useReplica) - os.chmod(toPath,0666) # Make cache files world writeable + copyFile( + fromURL, + toPath, + lcpath=lcpath, + userid=userid, + useReplica=useReplica) + os.chmod(toPath, 0o666) + # Make cache files world writeable except: - # Remove the notification on error, and the temp file, then re-raise + # Remove the notification on error, and the temp file, then + # re-raise self.deleteEntry(filekey) if os.path.isfile(toPath): os.unlink(toPath) raise # Add to the cache index - self.put(filekey,toPath) + self.put(filekey, toPath) return toPath - def getFile(self, fromURL, filekey, naptime=5, maxtries=60, lcpath=None, userid=None, useReplica=None): + def getFile(self, fromURL, filekey, naptime=5, + maxtries=60, lcpath=None, userid=None, useReplica=None): """ Get the file with . If the file is in the cache, read it. If another process is transferring it into the cache, wait for the @@ -351,23 +386,34 @@ class Cache: """ # If the file is being read into the cache, just wait for it tempname = self.get(filekey) - # Note: This is not bulletproof: another process could set the cache at this point + # Note: This is not bulletproof: another process could set the cache at + # this point if tempname is None: - fpath = self.copyFile(fromURL,filekey,lcpath=lcpath,userid=userid,useReplica=useReplica) - elif tempname=="__READ_PENDING__": + fpath = self.copyFile( + fromURL, + filekey, + lcpath=lcpath, + userid=userid, + useReplica=useReplica) + elif tempname == "__READ_PENDING__": success = 0 for i in range(maxtries): if cdmsobj._debug: - print 'Process %d: Waiting for read completion, %s'%(os.getpid(),`filekey`) + print 'Process %d: Waiting for read completion, %s' % (os.getpid(), repr(filekey)) time.sleep(naptime) tempname = self.get(filekey) # The read failed, or the entry was deleted. if tempname is None: - fpath = self.copyFile(fromURL,filekey,lcpath=lcpath,userid=userid,useReplica=useReplica) + fpath = self.copyFile( + fromURL, + filekey, + lcpath=lcpath, + userid=userid, + useReplica=useReplica) # The read is not yet complete - elif tempname=="__READ_PENDING__": + elif tempname == "__READ_PENDING__": continue # The read is finished. @@ -376,13 +422,13 @@ class Cache: success = 1 break if not success: - raise CDMSError, TimeOutError +`filekey` + raise CDMSError(TimeOutError + repr(filekey)) else: fpath = tempname if cdmsobj._debug: - print 'Process %d: Got file %s from cache %s'%(os.getpid(),fromURL,fpath) + print 'Process %d: Got file %s from cache %s' % (os.getpid(), fromURL, fpath) return fpath def delete(self): @@ -394,10 +440,11 @@ class Cache: self.index = shelve.open(self.indexpath) for key in self.index.keys(): path = self.index[key] - if path=="__READ_PENDING__": continue # Don't remove read-pending notifications + if path == "__READ_PENDING__": + continue # Don't remove read-pending notifications try: if cdmsobj._debug: - print 'Process %d: Deleting cache file %s'%(os.getpid(),path) + print 'Process %d: Deleting cache file %s' % (os.getpid(), path) os.unlink(path) except: pass @@ -415,7 +462,7 @@ class Cache: self.index = shelve.open(self.indexpath) for key in self.index.keys(): path = self.index[key] - if path=="__READ_PENDING__": + if path == "__READ_PENDING__": del self.index[key] self.index.close() unlock("index_lock") diff --git a/Packages/cdms2/Lib/cdmsNode.py b/Packages/cdms2/Lib/cdmsNode.py index 5d82a9526..3e34f34f7 100644 --- a/Packages/cdms2/Lib/cdmsNode.py +++ b/Packages/cdms2/Lib/cdmsNode.py @@ -1,5 +1,5 @@ -## Automatically adapted for numpy.oldnumeric Aug 01, 2007 by -## Further modified to be pure new numpy June 24th 2008 +# Automatically adapted for numpy.oldnumeric Aug 01, 2007 by +# Further modified to be pure new numpy June 24th 2008 """ CDMS node classes @@ -13,10 +13,12 @@ import sys from error import CDMSError # Regular expressions -_Name = re.compile('[a-zA-Z0-9_:][-a-zA-Z0-9._:]*$') # Note: allows digit as first character +_Name = re.compile('[a-zA-Z0-9_:][-a-zA-Z0-9._:]*$') + # Note: allows digit as first character _Integer = re.compile('[0-9]+$') _ArraySep = re.compile('[\[\],\s]+') -_Illegal = re.compile('([<>&\"\'])|([^\t\r\n -\176\240-\377])') #" illegal chars in content +_Illegal = re.compile('([<>&\"\'])|([^\t\r\n -\176\240-\377])') + #" illegal chars in content # Data types @@ -31,42 +33,51 @@ CdDouble = CDML.CdDouble CdString = CDML.CdString CdFromObject = CDML.CdFromObject CdAny = CDML.CdAny -CdDatatypes = [CdChar,CdByte,CdShort,CdInt,CdLong,CdInt64,CdFloat,CdDouble,CdString] +CdDatatypes = [ + CdChar, + CdByte, + CdShort, + CdInt, + CdLong, + CdInt64, + CdFloat, + CdDouble, + CdString] CdScalar = CDML.CdScalar CdArray = CDML.CdArray -NumericToCdType = {numpy.sctype2char(numpy.float32):CdFloat, - numpy.sctype2char(numpy.float):CdDouble, - numpy.sctype2char(numpy.int16):CdShort, - numpy.sctype2char(numpy.int32):CdInt, - numpy.sctype2char(numpy.int):CdLong, - numpy.sctype2char(numpy.int64):CdInt64, - numpy.sctype2char(numpy.intc):CdLong, - numpy.sctype2char(numpy.int8):CdByte, - 'c':CdChar, - 'B':'B', - 'H':'H', - 'L':'L', - 'q':CdInt64, - 'Q':'Q', - 'S':'S' +NumericToCdType = {numpy.sctype2char(numpy.float32): CdFloat, + numpy.sctype2char(numpy.float): CdDouble, + numpy.sctype2char(numpy.int16): CdShort, + numpy.sctype2char(numpy.int32): CdInt, + numpy.sctype2char(numpy.int): CdLong, + numpy.sctype2char(numpy.int64): CdInt64, + numpy.sctype2char(numpy.intc): CdLong, + numpy.sctype2char(numpy.int8): CdByte, + 'c': CdChar, + 'B': 'B', + 'H': 'H', + 'L': 'L', + 'q': CdInt64, + 'Q': 'Q', + 'S': 'S' } -CdToNumericType = {CdChar:'c', - CdByte:numpy.int8, - CdShort:numpy.int16, - CdInt:numpy.int32, - CdLong:numpy.int, - CdInt64:numpy.int64, - CdFloat:numpy.float32, - CdDouble:numpy.float} +CdToNumericType = {CdChar: 'c', + CdByte: numpy.int8, + CdShort: numpy.int16, + CdInt: numpy.int32, + CdLong: numpy.int, + CdInt64: numpy.int64, + CdFloat: numpy.float32, + CdDouble: numpy.float} # Grid types UnknownGridType = "unknown" GaussianGridType = "gaussian" UniformGridType = "uniform" -CdGridtypes = [UnknownGridType,GaussianGridType,UniformGridType] +CdGridtypes = [UnknownGridType, GaussianGridType, UniformGridType] DuplicateIdError = "Duplicate identifier: " InvalidArgumentError = "Invalid argument: " @@ -74,6 +85,8 @@ InvalidDatatype = "Invalid datatype: " InvalidGridtype = "Invalid grid type: " InvalidIdError = "Invalid identifier: " NotMonotonic = "Result array is not monotonic " + + class NotMonotonicError(CDMSError): pass @@ -94,6 +107,8 @@ CdSingleton = 2 # '"' --> " # "'" --> ' # all other illegal characters are removed #" + + def mapIllegalToEntity(matchobj): s = matchobj.group(0) if s == '<': @@ -102,49 +117,55 @@ def mapIllegalToEntity(matchobj): return '>' elif s == '&': return '&' - elif s == '"': #" + elif s == '"': # " return '"' - elif s=="'": + elif s == "'": return ''' else: return "" # Named node + + class CdmsNode: def __init__(self, tag, id=None, parent=None): if id and _Name.match(id) is None: raise CDMSError, InvalidIdError + id - self.attribute = {} # External attributes, attribute[name]=(value,cdDatatype) + self.attribute = {} + # External attributes, attribute[name]=(value,cdDatatype) self.child = [] # Children self.id = id # Identifier string self.parent = parent # Parent node in a tree, None for root self.tag = tag # XML tag string self.content = None # XML content string - self.dtd = CDML.CDML().dtd.get(self.tag) # CDML Document Type Definition for this tag - self.extra = CDML.CDML().extra.get(self.tag) # Extra datatype constraints + self.dtd = CDML.CDML().dtd.get(self.tag) + # CDML Document Type Definition for this tag + self.extra = CDML.CDML().extra.get( + self.tag) # Extra datatype constraints CdmsNode.mapToExternal(self) # Don't call subclass mapToExternal! # Map to external attributes def mapToExternal(self): if self.id is not None and _Name.match(self.id) is None: raise CDMSError, InvalidIdError + self.id - if self.id is not None: self.setExternalAttr('id',self.id) + if self.id is not None: + self.setExternalAttr('id', self.id) # Set content from a string. The interpretation # of content is class-dependent - def setContentFromString(self,content): - self.content=content + def setContentFromString(self, content): + self.content = content # Get content def getContent(self): return self.content # Add a child node - def add(self,child): + def add(self, child): if child is not None: self.child.append(child) - child.parent=self + child.parent = self return child # Return a list of child nodes @@ -152,13 +173,13 @@ class CdmsNode: return self.child # Get the child node at index k - def getChildAt(self,index): + def getChildAt(self, index): return self.child[index] # Remove and return the child at index k - def removeChildAt(self,index): + def removeChildAt(self, index): child = self.child[index] - self.child = self.child[:index]+self.child[index+1:] + self.child = self.child[:index] + self.child[index + 1:] return child # Get the number of children @@ -166,7 +187,7 @@ class CdmsNode: return len(self.child) # Get the index of a node - def getIndex(self,node): + def getIndex(self, node): index = -1 for i in range(len(self.child)): if node is self.child[i]: @@ -180,20 +201,21 @@ class CdmsNode: # True iff node is a leaf node def isLeaf(self): - return self.child==[] + return self.child == [] # Set an external attribute # 'attr' is an Attr object def setExternalAttrFromAttr(self, attr): - if attr.value is None: return - self.attribute[attr.name]=(attr.value,attr.getDatatype()) + if attr.value is None: + return + self.attribute[attr.name] = (attr.value, attr.getDatatype()) # Get an external attribute, as an Attr instance def getExternalAttrAsAttr(self, name): attrPair = self.attribute.get(name) if attrPair: - (value,datatype) = attrPair - attr = AttrNode(name,value) + (value, datatype) = attrPair + attr = AttrNode(name, value) attr.datatype = datatype return attr else: @@ -201,7 +223,7 @@ class CdmsNode: # Set an external attribute def setExternalAttr(self, name, value, datatype=None): - attr = AttrNode(name,value) + attr = AttrNode(name, value) attr.datatype = datatype self.setExternalAttrFromAttr(attr) @@ -209,7 +231,7 @@ class CdmsNode: def getExternalAttr(self, name): attrPair = self.attribute.get(name) if attrPair: - (value,datatype) = attrPair + (value, datatype) = attrPair return value else: return None @@ -220,71 +242,88 @@ class CdmsNode: # Set the external attribute dictionary. The input dictionary # is of the form {name:value,...} where value is a string. - def setExternalDict(self,dict): + def setExternalDict(self, dict): for key in dict.keys(): - self.attribute[key]=(dict[key],CdString) + self.attribute[key] = (dict[key], CdString) # Write to a file, with formatting. # tablevel is the start number of tabs - def write(self,fd=None,tablevel=0,format=1): - if fd is None: fd = sys.stdout + def write(self, fd=None, tablevel=0, format=1): + if fd is None: + fd = sys.stdout printLimit = get_printoptions()['threshold'] - set_printoptions(threshold=inf) # Ensure that all Numeric array values will be printed + set_printoptions(threshold=inf) + # Ensure that all Numeric array values will be printed if self.dtd: validAttrs = self.dtd.keys() else: validAttrs = None - if format: fd.write(tablevel*'\t') - fd.write('<'+self.tag) - if format: fd.write('\n') + if format: + fd.write(tablevel * '\t') + fd.write('<' + self.tag) + if format: + fd.write('\n') # Write valid attributes for attname in self.attribute.keys(): if (validAttrs and (attname in validAttrs)) or (not validAttrs): - if format: fd.write((tablevel+1)*'\t') - (attval,datatype)=self.attribute[attname] + if format: + fd.write((tablevel + 1) * '\t') + (attval, datatype) = self.attribute[attname] # attvalstr = string.replace(str(attval),'"',"'") # Map " to ' - attvalstr = _Illegal.sub(mapIllegalToEntity,str(attval)) # Map illegal chars to entities + attvalstr = _Illegal.sub( + mapIllegalToEntity, + str(attval)) # Map illegal chars to entities if format: - fd.write(attname+'\t="'+attvalstr+'"') + fd.write(attname + '\t="' + attvalstr + '"') else: - fd.write(' '+attname+'="'+attvalstr+'"') - if format: fd.write('\n') - if format: fd.write((tablevel+1)*'\t') + fd.write(' ' + attname + '="' + attvalstr + '"') + if format: + fd.write('\n') + if format: + fd.write((tablevel + 1) * '\t') fd.write('>') - if format: fd.write('\n') + if format: + fd.write('\n') # Write extra attributes for attname in self.attribute.keys(): if validAttrs and (attname not in validAttrs): - (attval,datatype)=self.attribute[attname] - attr = AttrNode(attname,attval) - attr.datatype=datatype + (attval, datatype) = self.attribute[attname] + attr = AttrNode(attname, attval) + attr.datatype = datatype attr.mapToExternal() - attr.write(fd,tablevel+1,format) + attr.write(fd, tablevel + 1, format) # Write content content = self.getContent() if content is not None: - content = _Illegal.sub(mapIllegalToEntity,content) # Map illegal chars to entities - if format: fd.write((tablevel+1)*'\t') + content = _Illegal.sub( + mapIllegalToEntity, + content) # Map illegal chars to entities + if format: + fd.write((tablevel + 1) * '\t') fd.write(content) - if format: fd.write('\n') + if format: + fd.write('\n') # Write children for node in self.child: - node.write(fd,tablevel+1,format) + node.write(fd, tablevel + 1, format) - if format: fd.write((tablevel+1)*'\t') - fd.write('') - if format: fd.write('\n') + if format: + fd.write((tablevel + 1) * '\t') + fd.write('') + if format: + fd.write('\n') set_printoptions(threshold=printLimit) # Restore original - # Write to a file without formatting. - def write_raw(self,fd=None): - if fd is None: fd = sys.stdout - self.write(fd,0,0) + # Write to a file without formatting. + def write_raw(self, fd=None): + if fd is None: + fd = sys.stdout + self.write(fd, 0, 0) # Write an LDIF (LDAP interchange format) entry # parentdn is the parent LDAP distinguished name @@ -292,41 +331,50 @@ class CdmsNode: # A trailing newline is added iff format==1 # Note: unlike write, this does not write children as well def write_ldif(self, parentdn, userAttrs=[], fd=None, format=1): - if fd is None: fd = sys.stdout + if fd is None: + fd = sys.stdout if self.dtd: validAttrs = self.dtd.keys() else: validAttrs = None # Write distinguished name - newdn = "%s=%s,%s"%(self.tag,self.id,parentdn) - fd.write("dn: %s\n"%newdn) + newdn = "%s=%s,%s" % (self.tag, self.id, parentdn) + fd.write("dn: %s\n" % newdn) # Write valid attributes for attname in self.attribute.keys(): if (validAttrs and (attname in validAttrs)) or (not validAttrs): - (attval,datatype)=self.attribute[attname] - # attvalstr = _Illegal.sub(mapIllegalToEntity,str(attval)) # Map illegal chars to entities + (attval, datatype) = self.attribute[attname] + # attvalstr = _Illegal.sub(mapIllegalToEntity,str(attval)) # + # Map illegal chars to entities if not isinstance(attval, basestring): attval = `attval` attvalstr = attval.strip() - attvalstr = re.sub('\n','\n ',attvalstr) # Make sure continuation lines are preceded with a space - if attvalstr=='': attvalstr = "none" - fd.write("%s: %s\n"%(attname,attvalstr)) - + attvalstr = re.sub( + '\n', + '\n ', + attvalstr) # Make sure continuation lines are preceded with a space + if attvalstr == '': + attvalstr = "none" + fd.write("%s: %s\n" % (attname, attvalstr)) + # Write extra attributes for attname in self.attribute.keys(): if validAttrs and (attname not in validAttrs): - (attval,datatype)=self.attribute[attname] + (attval, datatype) = self.attribute[attname] if not isinstance(attval, basestring): attval = `attval` - attval = re.sub('\n','\n ',attval) # Make sure continuation lines are preceded with a space - fd.write("attr: %s=%s\n"%(attname,attval)) + attval = re.sub( + '\n', + '\n ', + attval) # Make sure continuation lines are preceded with a space + fd.write("attr: %s=%s\n" % (attname, attval)) # Write content # content = self.getContent() # if content is not None: - # content = _Illegal.sub(mapIllegalToEntity,content) # Map illegal chars to entities + # content = _Illegal.sub(mapIllegalToEntity,content) # Map illegal chars to entities # fd.write("value: %s"%(content,)) # Write user attributes @@ -335,61 +383,64 @@ class CdmsNode: else: newAttrs = userAttrs for entry in list(newAttrs): - fd.write("%s\n"%entry) + fd.write("%s\n" % entry) # Write classes fd.write("objectclass: top\n") - fd.write("objectclass: %s\n"%(self.tag)) + fd.write("objectclass: %s\n" % (self.tag)) - if format==1: + if format == 1: fd.write('\n') return newdn # Validate attributes - def validate(self,idtable=None): + def validate(self, idtable=None): # Check validity of enumerated values and references validKeys = self.dtd.keys() for attname in self.attribute.keys(): if attname in validKeys: - (atttype,default)=self.dtd[attname] - if isinstance(atttype,tuple): - attval=self.getExternalAttr(attname) - assert attval in atttype, 'Invalid attribute %s=%s must be in %s'%(attname,attval,`atttype`) - elif atttype==CDML.Idref: - attval=self.getExternalAttr(attname) + (atttype, default) = self.dtd[attname] + if isinstance(atttype, tuple): + attval = self.getExternalAttr(attname) + assert attval in atttype, 'Invalid attribute %s=%s must be in %s' % ( + attname, attval, `atttype`) + elif atttype == CDML.Idref: + attval = self.getExternalAttr(attname) if idtable: if not idtable.has_key(attval): - print 'Warning: ID reference not found: %s=%s'%(attname,attval) - + print 'Warning: ID reference not found: %s=%s' % (attname, attval) + # Validate children for node in self.children(): node.validate(idtable) - + # Container object for other CDMS objects + + class DatasetNode(CdmsNode): def __init__(self, id): - CdmsNode.__init__(self,"dataset",id ) + CdmsNode.__init__(self, "dataset", id) self.idtable = {} # Validate the dataset and all child nodes - def validate(self,idtable=None): + def validate(self, idtable=None): if not idtable: - idtable=self.idtable - CdmsNode.validate(self,idtable) + idtable = self.idtable + CdmsNode.validate(self, idtable) # Add a child node with an ID - def addId(self,id,child): - if self.idtable.has_key(id): - raise CDMSError, DuplicateIdError +id - CdmsNode.add(self,child) - self.idtable[id]=child + def addId(self, id, child): + if self.idtable.has_key(id): + raise CDMSError, DuplicateIdError + id + CdmsNode.add(self, child) + self.idtable[id] = child return child # Get a child node from its ID - def getChildNamed(self,id): + def getChildNamed(self, id): return self.idtable.get(id) # Get the ID table @@ -399,66 +450,80 @@ class DatasetNode(CdmsNode): # Dump to a CDML file. # path is the file to dump to, or None for standard output. # if format is true, write with tab, newline formatting - def dump(self,path=None,format=1): + def dump(self, path=None, format=1): if path: try: - fd = open(path,'w') + fd = open(path, 'w') except IOError: - raise IOError,'%s: %s'%(sys.exc_value,path) + raise IOError, '%s: %s' % (sys.exc_value, path) else: fd = sys.stdout fd.write('') - if format: fd.write('\n') - fd.write('') - if format: fd.write('\n') - self.write(fd,0,format) - if fd!=sys.stdout: fd.close() + if format: + fd.write('\n') + fd.write( + '') + if format: + fd.write('\n') + self.write(fd, 0, format) + if fd != sys.stdout: + fd.close() # Spatio-temporal variable # Two ways to create a variable: # (1) var = VariableNode(id,datatype,domain) # (2) var = VariableNode(id,datatype) # var.setDomain(domain) + + class VariableNode(CdmsNode): # Create a variable. # If validate is true, validate immediately + def __init__(self, id, datatype, domain): - assert isinstance(datatype,basestring), 'Invalid datatype: '+`datatype` - assert datatype in CdDatatypes, 'Invalid datatype: '+`datatype` - CdmsNode.__init__(self,"variable",id) + assert isinstance( + datatype, basestring), 'Invalid datatype: ' + `datatype` + assert datatype in CdDatatypes, 'Invalid datatype: ' + `datatype` + CdmsNode.__init__(self, "variable", id) self.datatype = datatype self.setDomain(domain) VariableNode.mapToExternal(self) # Set the domain - def setDomain(self,domain): + def setDomain(self, domain): if not self.isLeaf(): self.removeChildAt(0) self.add(domain) # Get the domain def getDomain(self): - if self.getChildCount()>0: + if self.getChildCount() > 0: return self.getChildAt(0) else: return None # Map to external attributes def mapToExternal(self): - self.setExternalAttr('datatype',self.datatype) - + self.setExternalAttr('datatype', self.datatype) + # Coordinate axis + + class AxisNode(CdmsNode): # If datatype is None, assume values [0,1,..,length-1] # data is a numpy array, if specified - def __init__(self, id, length, datatype=CdLong,data=None): - assert isinstance(length, int), 'Invalid length: '+`length` - assert isinstance(datatype, basestring), 'Invalid datatype: '+`datatype` - assert datatype in CdDatatypes, 'Invalid datatype: '+`datatype` - if data is not None: assert isinstance(data, numpy.ndarray), 'data must be a 1-D Numeric array' - CdmsNode.__init__(self,"axis",id) + + def __init__(self, id, length, datatype=CdLong, data=None): + assert isinstance(length, int), 'Invalid length: ' + `length` + assert isinstance( + datatype, basestring), 'Invalid datatype: ' + `datatype` + assert datatype in CdDatatypes, 'Invalid datatype: ' + `datatype` + if data is not None: + assert isinstance( + data, numpy.ndarray), 'data must be a 1-D Numeric array' + CdmsNode.__init__(self, "axis", id) self.datatype = datatype self.data = data # data representation is CdLinear or CdVector @@ -477,48 +542,51 @@ class AxisNode(CdmsNode): # Map to external attributes def mapToExternal(self): - self.setExternalAttr('datatype',self.datatype) - self.setExternalAttr('length',self.length) + self.setExternalAttr('datatype', self.datatype) + self.setExternalAttr('length', self.length) # Set data from content string # The content of an axis is the data array. - def setContentFromString(self,datastring): + def setContentFromString(self, datastring): datatype = self.datatype numericType = CdToNumericType.get(datatype) - if numericType is None: raise CDMSError, InvalidDatatype + datatype + if numericType is None: + raise CDMSError, InvalidDatatype + datatype stringlist = _ArraySep.split(datastring) numlist = [] for numstring in stringlist: - if numstring=='': continue + if numstring == '': + continue numlist.append(float(numstring)) - if len(numlist)>0: + if len(numlist) > 0: # NB! len(zero-length array) causes IndexError on Linux! - dataArray = numpy.array(numlist,numericType) + dataArray = numpy.array(numlist, numericType) self.data = dataArray self.length = len(self.data) # Set the partition from a string. This does not # set the external string representation - def setPartitionFromString(self,partstring): + def setPartitionFromString(self, partstring): stringlist = _ArraySep.split(partstring) numlist = [] for numstring in stringlist: - if numstring=='': continue + if numstring == '': + continue numlist.append(int(numstring)) - dataArray = numpy.array(numlist,numpy.int) - if len(dataArray)>0: + dataArray = numpy.array(numlist, numpy.int) + if len(dataArray) > 0: self.partition = dataArray # Get the content string: the data values if the representation # is as a vector, or ane empty string otherwise def getContent(self): - if self.data is None or self.dataRepresent==CdLinear: + if self.data is None or self.dataRepresent == CdLinear: return '' else: return str(self.data) # Set the data as an array, check for monotonicity - def setData(self,data): + def setData(self, data): # If this axis is currently linear, remove the linear node if self.dataRepresent == CdLinear: @@ -527,8 +595,8 @@ class AxisNode(CdmsNode): self.data = data self.dataRepresent = CdVector self.length = len(data) - self.setExternalAttr('length',self.length) - if self.monotonicity()==CdNotMonotonic: + self.setExternalAttr('length', self.length) + if self.monotonicity() == CdNotMonotonic: raise NotMonotonicError, NotMonotonic # Get the data as an array @@ -540,9 +608,9 @@ class AxisNode(CdmsNode): # Set the data as a linear vector # If the partition is set, derive the vector length from it - def setLinearData(self,linearNode, partition=None): + def setLinearData(self, linearNode, partition=None): self.data = linearNode - if self.getChildCount()>0: + if self.getChildCount() > 0: self.removeChildAt(0) # Remove the previous linear node self.add(linearNode) self.dataRepresent = CdLinear @@ -553,23 +621,23 @@ class AxisNode(CdmsNode): self.partition = partition self.length = partition[-1] linearNode.length = self.length - self.setExternalAttr('partition',str(self.partition)) - self.setExternalAttr('length',self.length) + self.setExternalAttr('partition', str(self.partition)) + self.setExternalAttr('length', self.length) # Test if axis data vectors are equal - def equal(self,axis): + def equal(self, axis): # Require that partitions (if any) are equal if self.partition is not None and axis.partition is not None: - if len(self.partition)!=len(axis.partition): + if len(self.partition) != len(axis.partition): return 0 - if not numpy.alltrue(numpy.equal(self.partition,axis.partition)): + if not numpy.alltrue(numpy.equal(self.partition, axis.partition)): return 0 elif self.partition is not None or axis.partition is not None: return 0 - + if self.dataRepresent == axis.dataRepresent == CdVector: try: - return numpy.alltrue(numpy.equal(self.data,axis.data)) + return numpy.alltrue(numpy.equal(self.data, axis.data)) except ValueError: return 0 elif self.dataRepresent == axis.dataRepresent == CdLinear: @@ -581,34 +649,34 @@ class AxisNode(CdmsNode): # Test if axis data vectors are element-wise close # True iff for each respective element a and b, abs((b-a)/b)<=eps - def isClose(self,axis,eps): - if eps==0: + def isClose(self, axis, eps): + if eps == 0: return self.equal(axis) if self.dataRepresent == axis.dataRepresent == CdVector: try: - return numpy.alltrue(numpy.less_equal(numpy.absolute(self.data-axis.data),numpy.absolute(eps*self.data))) + return numpy.alltrue(numpy.less_equal(numpy.absolute(self.data - axis.data), numpy.absolute(eps * self.data))) except ValueError: return 0 elif self.dataRepresent == axis.dataRepresent == CdLinear: - return self.data.isClose(axis.data,eps) + return self.data.isClose(axis.data, eps) elif self.dataRepresent == CdVector: - return axis.data.isCloseVector(self.data,eps) + return axis.data.isCloseVector(self.data, eps) else: - return self.data.isCloseVector(axis.data,eps) + return self.data.isCloseVector(axis.data, eps) # Test for strict monotonicity. # Returns CdNotMonotonic, CdIncreasing, CdDecreasing, or CdSingleton def monotonicity(self): if self.dataRepresent == CdLinear: return self.data.monotonicity() - elif self.length==1: + elif self.length == 1: return CdSingleton else: first = self.data[:-1] second = self.data[1:] - if numpy.alltrue(numpy.less(first,second)): + if numpy.alltrue(numpy.less(first, second)): return CdIncreasing - elif numpy.alltrue(numpy.greater(first,second)): + elif numpy.alltrue(numpy.greater(first, second)): return CdDecreasing else: return CdNotMonotonic @@ -616,24 +684,24 @@ class AxisNode(CdmsNode): # Extend axes. 'isreltime' is true iff # the axes are relative time axes # If allowgaps is true, allow gaps when extending linear vectors - def extend(self,axis,isreltime=0,allowgaps=0): + def extend(self, axis, isreltime=0, allowgaps=0): # Set trylin true if should try to catenate linear vectors - if self.dataRepresent==CdLinear: + if self.dataRepresent == CdLinear: anode = self.data - if axis.dataRepresent==CdLinear: + if axis.dataRepresent == CdLinear: bnode = axis.data trylin = 1 - elif axis.length==1: + elif axis.length == 1: bnode = LinearDataNode(axis.data[0], 0.0, 1) trylin = 1 else: trylin = 0 - elif self.length==1: + elif self.length == 1: anode = LinearDataNode(self.data[0], 0.0, 1) - if axis.dataRepresent==CdLinear: + if axis.dataRepresent == CdLinear: bnode = axis.data trylin = 1 - elif axis.length==1: + elif axis.length == 1: bnode = LinearDataNode(axis.data[0], 0.0, 1) trylin = 1 else: @@ -641,25 +709,25 @@ class AxisNode(CdmsNode): else: trylin = 0 - if isreltime==1: + if isreltime == 1: units1 = self.getExternalAttr('units') units2 = axis.getExternalAttr('units') else: units1 = units2 = None - if trylin==1: + if trylin == 1: try: aindex = 0 alength = anode.length bindex = alength blength = bnode.length - if isreltime==1 and units1 and units2 and units1!=units2: - rtime = cdtime.reltime(bnode.start,units2) + if isreltime == 1 and units1 and units2 and units1 != units2: + rtime = cdtime.reltime(bnode.start, units2) offset = rtime.torel(units1).value - bnode.start = bnode.start+offset + bnode.start = bnode.start + offset else: offset = None - linNode = anode.concatenate(bnode,allowgaps) + linNode = anode.concatenate(bnode, allowgaps) except NotMonotonicError: # The dimensions cannot be extended as linear arrays, # so try to extend them as vectors @@ -667,15 +735,20 @@ class AxisNode(CdmsNode): else: # Extend the partition attribute if offset is not None: - bindex = int(offset/linNode.delta+0.5) - if self.partition is None: - partition = numpy.array([aindex,aindex+alength,bindex,bindex+blength]) - self.partition_length = alength+blength + bindex = int(offset / linNode.delta + 0.5) + if self.partition is None: + partition = numpy.array( + [aindex, + aindex + alength, + bindex, + bindex + blength]) + self.partition_length = alength + blength else: - partition = numpy.concatenate((self.partition,[bindex,bindex+blength])) - self.partition_length = self.partition_length+blength - self.setLinearData(linNode,partition) - self.setExternalAttr('partition_length',self.partition_length) + partition = numpy.concatenate( + (self.partition, [bindex, bindex + blength])) + self.partition_length = self.partition_length + blength + self.setLinearData(linNode, partition) + self.setExternalAttr('partition_length', self.partition_length) return self # Else get both axis vectors, concatenate @@ -688,29 +761,31 @@ class AxisNode(CdmsNode): blength = len(ar2) # Adjust array2 if relative time and units differ - if isreltime==1: + if isreltime == 1: if units1 and units2 and units1 != units2: - rtime = cdtime.reltime(0.0,units2) + rtime = cdtime.reltime(0.0, units2) delta = rtime.torel(units1).value - ar2 = ar2+delta + ar2 = ar2 + delta - ar = numpy.concatenate((ar1,ar2)) + ar = numpy.concatenate((ar1, ar2)) try: self.setData(ar) except NotMonotonicError: # Restore original array and resignal self.setData(ar1) - raise NotMonotonicError, NotMonotonic+`ar` + raise NotMonotonicError, NotMonotonic + `ar` # Extend the partition attribute - if self.partition is None: - self.partition = numpy.array([aindex,aindex+alength,bindex,bindex+blength]) - self.partition_length = alength+blength + if self.partition is None: + self.partition = numpy.array( + [aindex, aindex + alength, bindex, bindex + blength]) + self.partition_length = alength + blength else: - self.partition = numpy.concatenate((self.partition,[bindex,bindex+blength])) - self.partition_length = self.partition_length+blength - self.setExternalAttr('partition',str(self.partition)) - self.setExternalAttr('partition_length',self.partition_length) + self.partition = numpy.concatenate( + (self.partition, [bindex, bindex + blength])) + self.partition_length = self.partition_length + blength + self.setExternalAttr('partition', str(self.partition)) + self.setExternalAttr('partition_length', self.partition_length) return self @@ -718,16 +793,21 @@ class AxisNode(CdmsNode): return len(self.data) # Linear data element + + class LinearDataNode(CdmsNode): - validStartTypes = [int, float, type(cdtime.comptime(0)), type(cdtime.reltime(0,"hours"))] + validStartTypes = [ + int, float, type(cdtime.comptime(0)), type(cdtime.reltime(0, "hours"))] validDeltaTypes = [int, float, list] def __init__(self, start, delta, length): - assert isinstance(start, numpy.floating) or isinstance(start, numpy.integer) or (type(start) in self.validStartTypes), 'Invalid start argument: '+`start` - assert isinstance(start, numpy.floating) or isinstance(start, numpy.integer) or (type(delta) in self.validDeltaTypes), 'Invalid delta argument: '+`delta` - assert isinstance(length, int), 'Invalid length argument: '+`length` - CdmsNode.__init__(self,"linear") + assert isinstance(start, numpy.floating) or isinstance(start, numpy.integer) or ( + type(start) in self.validStartTypes), 'Invalid start argument: ' + `start` + assert isinstance(start, numpy.floating) or isinstance(start, numpy.integer) or ( + type(delta) in self.validDeltaTypes), 'Invalid delta argument: ' + `delta` + assert isinstance(length, int), 'Invalid length argument: ' + `length` + CdmsNode.__init__(self, "linear") self.delta = delta self.length = length self.start = start @@ -735,53 +815,57 @@ class LinearDataNode(CdmsNode): # Get an indexed value def __getitem__(self, index): - return self.start + index*self.delta + return self.start + index * self.delta # Map to external attributes def mapToExternal(self): - self.setExternalAttr("start",self.start) - self.setExternalAttr("delta",self.delta) - self.setExternalAttr("length",self.length) + self.setExternalAttr("start", self.start) + self.setExternalAttr("delta", self.delta) + self.setExternalAttr("length", self.length) # Equality of linear vectors - def equal(self,axis): - return self.delta==axis.delta and self.length==axis.length and self.start==axis.start + def equal(self, axis): + return self.delta == axis.delta and self.length == axis.length and self.start == axis.start # Closeness of linear vectors - def isClose(self,axis,eps): - if eps==0: + def isClose(self, axis, eps): + if eps == 0: return self.equal(axis) else: - return self.delta==axis.delta and self.length==axis.length and abs(self.start-axis.start)<=abs(eps*self.start) + return self.delta == axis.delta and self.length == axis.length and abs(self.start - axis.start) <= abs(eps * self.start) # Equality of linear vector and array - def equalVector(self,ar): - diff = ar[1:]-ar[:-1] + def equalVector(self, ar): + diff = ar[1:] - ar[:-1] try: - comp = numpy.alltrue(numpy.equal((self.delta)*numpy.ones(self.length-1),diff)) + comp = numpy.alltrue( + numpy.equal((self.delta) * numpy.ones(self.length - 1), diff)) except ValueError: return 0 return comp # Closeness of linear vector and array - def isCloseVector(self,ar,eps): - if eps==0: + def isCloseVector(self, ar, eps): + if eps == 0: return self.equalVector(ar) - diff = ar[1:]-ar[:-1] - diff2 = self.delta*numpy.ones(self.length-1) + diff = ar[1:] - ar[:-1] + diff2 = self.delta * numpy.ones(self.length - 1) try: - comp = numpy.alltrue(numpy.less_equal(numpy.absolute(diff2-diff),numpy.absolute(eps*diff2))) + comp = numpy.alltrue( + numpy.less_equal(numpy.absolute(diff2 - diff), + numpy.absolute(eps * diff2))) except ValueError: return 0 return comp - # Return monotonicity: CdNotMonotonic, CdIncreasing, CdDecreasing, or CdSingleton + # Return monotonicity: CdNotMonotonic, CdIncreasing, CdDecreasing, or + # CdSingleton def monotonicity(self): - if self.length==1: + if self.length == 1: return CdSingleton - elif self.delta>0.0: + elif self.delta > 0.0: return CdIncreasing - elif self.delta<0.0: + elif self.delta < 0.0: return CdDecreasing else: return CdNotMonotonic @@ -789,34 +873,39 @@ class LinearDataNode(CdmsNode): # Return a vector representation, given a CDMS datatype def toVector(self, datatype): numericType = CdToNumericType.get(datatype) - if numericType is None: raise CDMSError, InvalidDatatype + datatype + if numericType is None: + raise CDMSError, InvalidDatatype + datatype start = self.start delta = self.delta length = self.length - if length>1: - stop = start + (length-0.99)*delta - if delta==0.0: delta=1.0 - ar = numpy.arange(start,stop,delta,numericType) + if length > 1: + stop = start + (length - 0.99) * delta + if delta == 0.0: + delta = 1.0 + ar = numpy.arange(start, stop, delta, numericType) else: - ar = numpy.array([start],numericType) + ar = numpy.array([start], numericType) return ar # Concatenate linear arrays, preserving linearity # If allowgaps is set, don't require that the linear arrays be contiguous # Return a new linear node - def concatenate(self,linearNode,allowgaps=0): - if self.length>1 and linearNode.length>1 and self.delta != linearNode.delta: - raise NotMonotonicError, NotMonotonic + 'linear vector deltas do not match: %s,%s'%(`self.delta`,`linearNode.delta`) + def concatenate(self, linearNode, allowgaps=0): + if self.length > 1 and linearNode.length > 1 and self.delta != linearNode.delta: + raise NotMonotonicError, NotMonotonic + \ + 'linear vector deltas do not match: %s,%s' % ( + `self.delta`, `linearNode.delta`) - if self.length>1: + if self.length > 1: delta = self.delta - elif linearNode.length>1: + elif linearNode.length > 1: delta = linearNode.delta else: delta = linearNode.start - self.start - if allowgaps==0: - if linearNode.start-self.start != self.length*delta: - raise NotMonotonicError, NotMonotonic + 'linear vectors are not contiguous' + if allowgaps == 0: + if linearNode.start - self.start != self.length * delta: + raise NotMonotonicError, NotMonotonic + \ + 'linear vectors are not contiguous' length = self.length + linearNode.length return LinearDataNode(self.start, delta, length) @@ -824,12 +913,16 @@ class LinearDataNode(CdmsNode): return self.length # Rectilinear lat-lon grid + + class RectGridNode(CdmsNode): # Create a grid # All arguments are strings - def __init__(self, id, latitude, longitude, gridtype=UnknownGridType, order="yx", mask=None): - CdmsNode.__init__(self,"rectGrid",id) + + def __init__(self, id, latitude, longitude, + gridtype=UnknownGridType, order="yx", mask=None): + CdmsNode.__init__(self, "rectGrid", id) self.latitude = latitude self.longitude = longitude self.gridtype = gridtype @@ -839,17 +932,20 @@ class RectGridNode(CdmsNode): # Map to external attributes def mapToExternal(self): - self.setExternalAttr('type',self.gridtype) + self.setExternalAttr('type', self.gridtype) self.setExternalAttr('latitude', self.latitude) - self.setExternalAttr('longitude',self.longitude) - self.setExternalAttr('order',self.order) - if self.mask is not None: self.setExternalAttr('mask',self.mask) + self.setExternalAttr('longitude', self.longitude) + self.setExternalAttr('order', self.order) + if self.mask is not None: + self.setExternalAttr('mask', self.mask) # Link to an external element + + class XLinkNode(CdmsNode): def __init__(self, id, uri, contentRole, content=''): - CdmsNode.__init__(self,"xlink",id) + CdmsNode.__init__(self, "xlink", id) self.uri = uri self.contentRole = contentRole self.content = content @@ -857,33 +953,39 @@ class XLinkNode(CdmsNode): # Map to external attributes def mapToExternal(self): - self.setExternalAttr("href",self.uri,CdString) - self.setExternalAttr("content-role",self.contentRole,CdString) + self.setExternalAttr("href", self.uri, CdString) + self.setExternalAttr("content-role", self.contentRole, CdString) # Link to a document + + class DocLinkNode(CdmsNode): def __init__(self, uri, content=''): - CdmsNode.__init__(self,"doclink") + CdmsNode.__init__(self, "doclink") self.uri = uri self.content = content DocLinkNode.mapToExternal(self) # Map to external attributes def mapToExternal(self): - self.setExternalAttr("href",self.uri,CdString) + self.setExternalAttr("href", self.uri, CdString) # Domain + + class DomainNode(CdmsNode): def __init__(self): - CdmsNode.__init__(self,"domain") + CdmsNode.__init__(self, "domain") # Domain element + + class DomElemNode(CdmsNode): def __init__(self, name, start=None, length=None): - CdmsNode.__init__(self,"domElem") + CdmsNode.__init__(self, "domElem") self.name = name self.start = start self.length = length @@ -891,14 +993,16 @@ class DomElemNode(CdmsNode): # Map to external attributes def mapToExternal(self): - self.setExternalAttr('name',self.name) - if self.start is not None: self.setExternalAttr('start',self.start) - if self.length is not None: self.setExternalAttr('length',self.length) + self.setExternalAttr('name', self.name) + if self.start is not None: + self.setExternalAttr('start', self.start) + if self.length is not None: + self.setExternalAttr('length', self.length) # Set the name - def setName(self,name): + def setName(self, name): self.name = name - self.setExternalAttr('name',self.name) + self.setExternalAttr('name', self.name) # Get the name def getName(self): @@ -906,78 +1010,85 @@ class DomElemNode(CdmsNode): # Write to a file, with formatting. # tablevel is the start number of tabs - def write(self,fd=None,tablevel=0,format=1): - if fd is None: fd = sys.stdout - if format: fd.write(tablevel*'\t') - fd.write('<'+self.tag) + def write(self, fd=None, tablevel=0, format=1): + if fd is None: + fd = sys.stdout + if format: + fd.write(tablevel * '\t') + fd.write('<' + self.tag) for attname in self.attribute.keys(): - (attval,datatype)=self.attribute[attname] + (attval, datatype) = self.attribute[attname] # attvalstr = string.replace(str(attval),'"',"'") # Map " to ' - attvalstr = _Illegal.sub(mapIllegalToEntity,str(attval)) # Map illegal chars to entities - fd.write(' '+attname+'="'+attvalstr+'"') + attvalstr = _Illegal.sub( + mapIllegalToEntity, + str(attval)) # Map illegal chars to entities + fd.write(' ' + attname + '="' + attvalstr + '"') fd.write('/>') - if format: fd.write('\n') + if format: + fd.write('\n') # Attribute node - only used as a placeholder during parse and write # Attr nodes are not placed on the tree # # Two ways to create an Attr object: # (1) attr = AttrNode(name,value) -# datatype = sometype # optionally, to override intrinsic type +# datatype = sometype # optionally, to override intrinsic type # (2) attr = AttrNode(name,None) # attr.setValueFromString(somestring,sometype) + + class AttrNode(CdmsNode): def __init__(self, name, value=None): - CdmsNode.__init__(self,"attr") - if not (isinstance(value,(int, numpy.integer, float, numpy.floating, basestring)) \ + CdmsNode.__init__(self, "attr") + if not (isinstance(value, (int, numpy.integer, float, numpy.floating, basestring)) or value is None: - raise CDMSError, 'Invalid attribute type: '+`value` - self.name = name - self.value = value - self.datatype = None # CDMS datatype, use getDatatype to retrieve - self.content = '' # string content + raise CDMSError, 'Invalid attribute type: ' + `value` + self.name=name + self.value=value + self.datatype=None # CDMS datatype, use getDatatype to retrieve + self.content='' # string content # Note: mapToExternal is not called at init time, must be called explicitly # if needed def mapToExternal(self): - self.attribute['name']=(self.name,CdString) - self.attribute['datatype']=(self.getDatatype(),CdString) - self.content = self.getValueAsString() + self.attribute['name']=(self.name, CdString) + self.attribute['datatype']=(self.getDatatype(), CdString) + self.content=self.getValueAsString() def getDatatype(self): if self.datatype: return self.datatype elif isinstance(self.value, basestring): return CdString - elif isinstance(self.value, (float,numpy.floating)): + elif isinstance(self.value, (float, numpy.floating)): return CdDouble elif isinstance(self.value, (int, numpy.integer)): return CdLong else: - raise CDMSError, 'Invalid attribute type: '+`self.value` + raise CDMSError, 'Invalid attribute type: ' + `self.value` def getLength(self): return 1 # Map a string of a given datatype to a value # Returns ValueError if the conversion fails - def setValueFromString(self,valString,datatype): - val = None + def setValueFromString(self, valString, datatype): + val=None if not isinstance(valString, basestring): raise CDMSError, 'input value is not a string' if datatype == CdString: val=valString - elif datatype in (CdShort,CdInt,CdLong): + elif datatype in (CdShort, CdInt, CdLong): try: val=int(valString) except ValueError: - raise CDMSError, 'value is not an integer: '+valString - elif datatype in (CdFloat,CdDouble): + raise CDMSError, 'value is not an integer: ' + valString + elif datatype in (CdFloat, CdDouble): try: val=float(valString) except ValueError: - raise CDMSError, 'value is not floating-point: '+valString + raise CDMSError, 'value is not floating-point: ' + valString self.value=val self.datatype=datatype return val @@ -987,36 +1098,40 @@ class AttrNode(CdmsNode): # Set content # This may be called multiple times, so append - def setContentFromString(self,content): - self.content = self.content+content + def setContentFromString(self, content): + self.content=self.content + content # Write to a file, with formatting. # tablevel is the start number of tabs - def write(self,fd=None,tablevel=0,format=1): - if fd is None: fd = sys.stdout + def write(self, fd=None, tablevel=0, format=1): + if fd is None: fd=sys.stdout if self.dtd: - validAttrs = self.dtd.keys() + validAttrs=self.dtd.keys() else: - validAttrs = None + validAttrs=None - if format: fd.write(tablevel*'\t') - fd.write('<'+self.tag) + if format: fd.write(tablevel * '\t') + fd.write('<' + self.tag) # Write valid attributes for attname in self.attribute.keys(): if (validAttrs and (attname in validAttrs)) or (not validAttrs): - (attval,datatype)=self.attribute[attname] + (attval, datatype)=self.attribute[attname] # attvalstr = string.replace(str(attval),'"',"'") # Map " to ' - attvalstr = _Illegal.sub(mapIllegalToEntity,str(attval)) # Map illegal chars to entities - fd.write(' '+attname+'="'+attvalstr+'"') + attvalstr=_Illegal.sub( + mapIllegalToEntity, + str(attval)) # Map illegal chars to entities + fd.write(' ' + attname + '="' + attvalstr + '"') fd.write('>') # Write content if self.content is not None: - content = _Illegal.sub(mapIllegalToEntity,self.content) # Map illegal chars to entities + content=_Illegal.sub( + mapIllegalToEntity, + self.content) # Map illegal chars to entities fd.write(content) - fd.write('') + fd.write('') if format: fd.write('\n') if __name__ == '__main__': @@ -1049,7 +1164,7 @@ if __name__ == '__main__': # hAxis = AxisNode('h',len(h),CdDouble,h) # jAxis = AxisNode('j',len(j),CdDouble); jAxis.setLinearData(j) # kAxis = AxisNode('k',len(k),CdDouble,k) - + # print aAxis.monotonicity() # print hAxis.monotonicity() # print kAxis.monotonicity() @@ -1057,29 +1172,29 @@ if __name__ == '__main__': # print dAxis.monotonicity() # print jAxis.monotonicity() - m = LinearDataNode(1,2,3) - n = LinearDataNode(11,2,3) - p = LinearDataNode(15,-4,3) - q = numpy.array([4.,2.,1.]) - r = numpy.array([11.,9.,8.]) - s = numpy.array([7.]) - t = numpy.array([9.]) - v = numpy.array([5.]) - - mAxis = AxisNode('m',len(m),CdLong); mAxis.setLinearData(m) - nAxis = AxisNode('n',len(n),CdLong); nAxis.setLinearData(n) - pAxis = AxisNode('p',len(p),CdLong); pAxis.setLinearData(p) - qAxis = AxisNode('q',len(q),CdDouble,q) - rAxis = AxisNode('r',len(r),CdDouble,r) - sAxis = AxisNode('s',len(s),CdDouble,s) - tAxis = AxisNode('t',len(t),CdDouble,t) - vAxis = AxisNode('v',len(v),CdDouble,v) + m=LinearDataNode(1, 2, 3) + n=LinearDataNode(11, 2, 3) + p=LinearDataNode(15, -4, 3) + q=numpy.array([4., 2., 1.]) + r=numpy.array([11., 9., 8.]) + s=numpy.array([7.]) + t=numpy.array([9.]) + v=numpy.array([5.]) + + mAxis=AxisNode('m', len(m), CdLong); mAxis.setLinearData(m) + nAxis=AxisNode('n', len(n), CdLong); nAxis.setLinearData(n) + pAxis=AxisNode('p', len(p), CdLong); pAxis.setLinearData(p) + qAxis=AxisNode('q', len(q), CdDouble, q) + rAxis=AxisNode('r', len(r), CdDouble, r) + sAxis=AxisNode('s', len(s), CdDouble, s) + tAxis=AxisNode('t', len(t), CdDouble, t) + vAxis=AxisNode('v', len(v), CdDouble, v) def printType(axis): - if axis.dataRepresent==CdLinear: print 'linear' + if axis.dataRepresent == CdLinear: print 'linear' else: print 'vector' - - def testit(a,b): + + def testit(a, b): import copy x=copy.copy(a) print x.extend(b).getData() @@ -1095,6 +1210,6 @@ if __name__ == '__main__': # testit(mAxis,rAxis) # testit(vAxis,nAxis) # testit(sAxis,rAxis) - + # Errors: # testit(mAxis,nAxis) diff --git a/Packages/cdms2/Lib/cdmsURLopener.py b/Packages/cdms2/Lib/cdmsURLopener.py index f401bf8d5..e0b710131 100644 --- a/Packages/cdms2/Lib/cdmsURLopener.py +++ b/Packages/cdms2/Lib/cdmsURLopener.py @@ -3,15 +3,16 @@ import urllib + class CDMSURLopener(urllib.FancyURLopener): - # Override FancyURLopener error handling - raise an exception - # Can also define function http_error_DDD where DDD is the 3-digit error code, - # to handle specific errors. - def http_error_default(self, url, fp, errcode, errmsg, headers): - void = fp.read() - fp.close() - raise IOError, ('http error', errcode, errmsg, headers) + # Override FancyURLopener error handling - raise an exception + # Can also define function http_error_DDD where DDD is the 3-digit error code, + # to handle specific errors. -urllib._urlopener = CDMSURLopener() + def http_error_default(self, url, fp, errcode, errmsg, headers): + void = fp.read() + fp.close() + raise IOError('http error', errcode, errmsg, headers) +urllib._urlopener = CDMSURLopener() diff --git a/Packages/cdms2/Lib/cdmsobj.py b/Packages/cdms2/Lib/cdmsobj.py index 8fad6b3ab..30961e26b 100644 --- a/Packages/cdms2/Lib/cdmsobj.py +++ b/Packages/cdms2/Lib/cdmsobj.py @@ -2,7 +2,7 @@ CDMS module-level functions and definitions """ -import cdmsNode +from . import cdmsNode import cdtime import glob import os @@ -26,7 +26,7 @@ CdArray = cdmsNode.CdArray Unlimited = 1 # Unlimited axis designator -Max32int = 2**31-1 # Maximum 32-bit integer +Max32int = 2**31 - 1 # Maximum 32-bit integer # Regular expressions for each template specifier _Daynum = '[0-3][0-9]' @@ -41,7 +41,7 @@ _Percent = '%' _Second = '[0-5][0-9]' _Year2 = '[0-9][0-9]' _Year4 = '[0-9]{4,4}' -_Zulu = _Hour+'[z|Z]'+_Year4+_Monthnum+_Daynum +_Zulu = _Hour + '[z|Z]' + _Year4 + _Monthnum + _Daynum # Positions for time lists _yr = 0 @@ -93,42 +93,67 @@ _specifierMap = { '%v': (_Name, 'name', 'var', None), '%y': (_Year2, 'year2', 'time', _yr), '%z': (_Zulu, 'zulu', 'time', None), - } - -_monthListUpper = ['JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC'] +} + +_monthListUpper = [ + 'JAN', + 'FEB', + 'MAR', + 'APR', + 'MAY', + 'JUN', + 'JUL', + 'AUG', + 'SEP', + 'OCT', + 'NOV', + 'DEC'] _monthMapUpper = { - 'JAN':1, - 'FEB':2, - 'MAR':3, - 'APR':4, - 'MAY':5, - 'JUN':6, - 'JUL':7, - 'AUG':8, - 'SEP':9, - 'OCT':10, - 'NOV':11, - 'DEC':12, - } - -_monthListLower = ['jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec'] + 'JAN': 1, + 'FEB': 2, + 'MAR': 3, + 'APR': 4, + 'MAY': 5, + 'JUN': 6, + 'JUL': 7, + 'AUG': 8, + 'SEP': 9, + 'OCT': 10, + 'NOV': 11, + 'DEC': 12, +} + +_monthListLower = [ + 'jan', + 'feb', + 'mar', + 'apr', + 'may', + 'jun', + 'jul', + 'aug', + 'sep', + 'oct', + 'nov', + 'dec'] _monthMapLower = { - 'jan':1, - 'feb':2, - 'mar':3, - 'apr':4, - 'may':5, - 'jun':6, - 'jul':7, - 'aug':8, - 'sep':9, - 'oct':10, - 'nov':11, - 'dec':12, - } - -_specre = re.compile('(%%|%G|%H|%L|%M|%S|%Y|%d|%eG|%eH|%eL|%eM|%eS|%eY|%ed|%ef|%eg|%eh|%em|%en|%ey|%ez|%f|%g|%h|%m|%n|%v|%y|%z)') -_filere = re.compile('[^'+os.sep+']+') + 'jan': 1, + 'feb': 2, + 'mar': 3, + 'apr': 4, + 'may': 5, + 'jun': 6, + 'jul': 7, + 'aug': 8, + 'sep': 9, + 'oct': 10, + 'nov': 11, + 'dec': 12, +} + +_specre = re.compile( + '(%%|%G|%H|%L|%M|%S|%Y|%d|%eG|%eH|%eL|%eM|%eS|%eY|%ed|%ef|%eg|%eh|%em|%en|%ey|%ez|%f|%g|%h|%m|%n|%v|%y|%z)') +_filere = re.compile('[^' + os.sep + ']+') _debug = 0 # Print debug info @@ -137,12 +162,14 @@ AbsoluteTemplate = "Template must be a relative path: " # Module-level functions # Set debug mode, to 'on' or 'off' + + def setDebugMode(mode): global _debug - if mode=='on': - _debug=1 - elif mode=='off': - _debug=0 + if mode == 'on': + _debug = 1 + elif mode == 'off': + _debug = 0 # Map a template to a regular expression # Returns (regex,dimtypes), where regex is the regular expression @@ -151,206 +178,226 @@ def setDebugMode(mode): # where specStrings is the specifier associated with the dimension type, # or for time, the list of specifiers in the order (yr,mo,dy,hr,mi,se) # where each element is the specifier for that time element + + def templateToRegex(template): matchspec = {} - dimtypes = {'var':None, - 'time':[None,None,None,None,None,None], - 'etime':[None,None,None,None,None,None], - 'level':None, - 'elevel':None, + dimtypes = {'var': None, + 'time': [None, None, None, None, None, None], + 'etime': [None, None, None, None, None, None], + 'level': None, + 'elevel': None, } # Map spec to regex # (The default arg bring matchspec and dimtypes into the local scope) def retspec(matchobj, matchspec=matchspec, dimtypes=dimtypes): spec = matchobj.group(0) - pat,name,dimtype,pos = _specifierMap[spec] + pat, name, dimtype, pos = _specifierMap[spec] - if dimtype=='var': - dimtypes['var']=spec - elif dimtype in ('time','etime'): + if dimtype == 'var': + dimtypes['var'] = spec + elif dimtype in ('time', 'etime'): if pos is not None: - dimtypes[dimtype][pos]=spec - elif name in ('zulu','ezulu'): - pass # Crack Zulu time - elif dimtype in ('level','elevel'): - dimtypes[dimtype]=spec - - if matchspec.has_key(spec): - return '(?P='+name+')' + dimtypes[dimtype][pos] = spec + elif name in ('zulu', 'ezulu'): + pass # Crack Zulu time + elif dimtype in ('level', 'elevel'): + dimtypes[dimtype] = spec + + if spec in matchspec: + return '(?P=' + name + ')' else: matchspec[spec] = 1 - return '(?P<'+name+'>'+pat+')' - - templatere = _specre.sub(retspec,template) - return (templatere,dimtypes) + return '(?P<' + name + '>' + pat + ')' + + templatere = _specre.sub(retspec, template) + return (templatere, dimtypes) + def retglob(matchobj): return '*' # Generate a component time from a matchobj and list of specs -def generateTime(matchobj,timespecs): + + +def generateTime(matchobj, timespecs): iyr = 0 imo = 1 idy = 1 ihr = 0 imi = 0 ise = 0 - yrspec,mospec,dyspec,hrspec,mispec,sespec = timespecs + yrspec, mospec, dyspec, hrspec, mispec, sespec = timespecs if yrspec: - pat,name,dimtype,pos = _specifierMap[yrspec] + pat, name, dimtype, pos = _specifierMap[yrspec] yrstr = matchobj.group(name) iyr = int(yrstr) # Map 2-digit year to [1950,2049) - if yrspec in ('%y','%ey'): - if iyr<50: - iyr = iyr+2000 + if yrspec in ('%y', '%ey'): + if iyr < 50: + iyr = iyr + 2000 else: - iyr = iyr+1900 + iyr = iyr + 1900 if mospec: - pat,name,dimtype,pos = _specifierMap[mospec] + pat, name, dimtype, pos = _specifierMap[mospec] mostr = matchobj.group(name) - if mospec in ('%G','%eG'): + if mospec in ('%G', '%eG'): imo = _monthMapUpper[mostr] - elif mospec in ('%g','%eg'): + elif mospec in ('%g', '%eg'): imo = _monthMapLower[mostr] - elif mospec in ('%m','%em','%n','%en'): + elif mospec in ('%m', '%em', '%n', '%en'): imo = int(mostr) if dyspec: - pat,name,dimtype,pos = _specifierMap[dyspec] + pat, name, dimtype, pos = _specifierMap[dyspec] dystr = matchobj.group(name) idy = int(dystr) if hrspec: - pat,name,dimtype,pos = _specifierMap[hrspec] + pat, name, dimtype, pos = _specifierMap[hrspec] hrstr = matchobj.group(name) ihr = int(hrstr) if mispec: - pat,name,dimtype,pos = _specifierMap[mispec] + pat, name, dimtype, pos = _specifierMap[mispec] mistr = matchobj.group(name) imi = int(mistr) if sespec: - pat,name,dimtype,pos = _specifierMap[sespec] + pat, name, dimtype, pos = _specifierMap[sespec] sestr = matchobj.group(name) ise = int(sestr) - return cdtime.comptime(iyr,imo,idy,ihr,imi,ise) + return cdtime.comptime(iyr, imo, idy, ihr, imi, ise) # Find all files in 'direc' which match 'template'. # template is a relative path, and may contain specifiers # in directory names. Returns a list [(f,m),..,(f,m)] where # f is a matching file name, and m is a list [var,time,etime,level,elevel] # of matching values in f. Any or all elems of the list may be None. -def matchingFiles(direc,template): + + +def matchingFiles(direc, template): if os.path.isabs(template): - raise AbsoluteTemplate, template + raise AbsoluteTemplate(template) # Generate a glob pattern normTemplate = os.path.normpath(template) - globPattern = _filere.sub(retglob,normTemplate) + globPattern = _filere.sub(retglob, normTemplate) # Map the template to a regular expression - templatere,dimtypes = templateToRegex(template) + templatere, dimtypes = templateToRegex(template) ctre = re.compile(templatere) # Get a list of candidate files try: os.chdir(direc) except os.error: - raise IOError,'%s: %s'%(sys.exc_value,direc) - + raise IOError('%s: %s' % (sys.exc_info()[1], direc)) + candlist = glob.glob(globPattern) - # Look for matches + # Look for matches matchfiles = [] for candfile in candlist: matchobj = ctre.match(candfile) # Create matching values - if matchobj is None: continue - matchnames = [None,None,None,None,None] + if matchobj is None: + continue + matchnames = [None, None, None, None, None] if dimtypes['var'] is not None: matchnames[_var] = matchobj.group('name') - if dimtypes['time'] != [None,None,None,None,None,None]: - matchnames[_time] = generateTime(matchobj,dimtypes['time']) - if dimtypes['etime'] != [None,None,None,None,None,None]: - matchnames[_etime] = generateTime(matchobj,dimtypes['etime']) + if dimtypes['time'] != [None, None, None, None, None, None]: + matchnames[_time] = generateTime(matchobj, dimtypes['time']) + if dimtypes['etime'] != [None, None, None, None, None, None]: + matchnames[_etime] = generateTime(matchobj, dimtypes['etime']) if dimtypes['level'] is not None: matchnames[_level] = int(matchobj.group('level')) if dimtypes['elevel'] is not None: matchnames[_elevel] = int(matchobj.group('elevel')) - matchfiles.append((candfile,matchnames)) + matchfiles.append((candfile, matchnames)) return matchfiles # Get a string time component from a spec and a component time -def getTimeAsString(spec,time): - if spec in ('%G','%eG'): + +def getTimeAsString(spec, time): + + if spec in ('%G', '%eG'): imo = time.month - specstr = _monthListUpper[imo-1] - elif spec in ('%H','%eH'): + specstr = _monthListUpper[imo - 1] + elif spec in ('%H', '%eH'): specstr = str(time.hour) - elif spec in ('%M','%eM'): + elif spec in ('%M', '%eM'): specstr = str(time.minute) - elif spec in ('%S','%eS'): + elif spec in ('%S', '%eS'): specstr = str(int(time.second)) - elif spec in ('%Y','%eY'): + elif spec in ('%Y', '%eY'): specstr = str(time.year).zfill(4) - elif spec in ('%d','%ed'): + elif spec in ('%d', '%ed'): specstr = str(time.day) - elif spec in ('%f','%ef'): + elif spec in ('%f', '%ef'): specstr = str(time.day).zfill(2) - elif spec in ('%g','%eg'): + elif spec in ('%g', '%eg'): imo = time.month - specstr = _monthListLower[imo-1] - elif spec in ('%h','%eh'): + specstr = _monthListLower[imo - 1] + elif spec in ('%h', '%eh'): specstr = str(time.hour).zfill(2) - elif spec in ('%m','%em'): + elif spec in ('%m', '%em'): specstr = str(time.month) - elif spec in ('%n','%en'): + elif spec in ('%n', '%en'): specstr = str(time.month).zfill(2) - elif spec in ('%y','%ey'): - specstr = str(time.year%100).zfill(2) - elif spec in ('%z','%ez'): - specstr = getTimeAsString('%H',time)+'Z'+getTimeAsString('%Y',time)+getTimeAsString('%n',time)+getTimeAsString('%d',time) + elif spec in ('%y', '%ey'): + specstr = str(time.year % 100).zfill(2) + elif spec in ('%z', '%ez'): + specstr = getTimeAsString( + '%H', + time) + 'Z' + getTimeAsString( + '%Y', + time) + getTimeAsString( + '%n', + time) + getTimeAsString( + '%d', + time) return specstr # Generate a file path, given a template and matchname list. # matchnames is a list [varname,time,etime,level,elevel], where # any or all elems may be None. If matchnames be a longer list, # it is not an error but the additional elements are ignored. -def getPathFromTemplate(template,matchnames): + + +def getPathFromTemplate(template, matchnames): # Map spec to value string # (Default arg brings matchnames into the local scope) def retpath(matchobj, matchnames=matchnames): spec = matchobj.group(0) - pat,name,dimtype,pos = _specifierMap[spec] - var,time,etime,level,elevel = matchnames[0:5] + pat, name, dimtype, pos = _specifierMap[spec] + var, time, etime, level, elevel = matchnames[0:5] - if dimtype=='var': + if dimtype == 'var': if var is None: specstr = spec else: specstr = var - elif dimtype=='time': + elif dimtype == 'time': if time is None: specstr = spec else: - specstr = getTimeAsString(spec,time) - elif dimtype=='etime': + specstr = getTimeAsString(spec, time) + elif dimtype == 'etime': if etime is None: specstr = spec else: - specstr = getTimeAsString(spec,etime) - elif dimtype=='level': + specstr = getTimeAsString(spec, etime) + elif dimtype == 'level': if level is None: specstr = spec else: specstr = str(level) - elif dimtype=='elevel': + elif dimtype == 'elevel': if elevel is None: specstr = spec else: @@ -358,7 +405,7 @@ def getPathFromTemplate(template,matchnames): return specstr - path = _specre.sub(retpath,template) + path = _specre.sub(retpath, template) return path # Search an object or list of objects for a string attribute which @@ -369,6 +416,7 @@ def getPathFromTemplate(template,matchnames): # 'rectGrid','xlink', or None. If tag is None, all object classes are # searched. If attribute is None, all attributes are searched. + def searchPattern(objlist, pattern, attribute=None, tag=None): if tag is not None: tag = tag.lower() @@ -378,7 +426,7 @@ def searchPattern(objlist, pattern, attribute=None, tag=None): returnlist = [] for obj in objlist: - returnlist = returnlist + obj.searchPattern(regexp,attribute,tag) + returnlist = returnlist + obj.searchPattern(regexp, attribute, tag) return returnlist @@ -390,6 +438,7 @@ def searchPattern(objlist, pattern, attribute=None, tag=None): # 'rectGrid','xlink', or None. If tag is None, all object classes are # searched. If attribute is None, all attributes are searched. + def matchPattern(objlist, pattern, attribute=None, tag=None): if tag is not None: tag = tag.lower() @@ -399,7 +448,7 @@ def matchPattern(objlist, pattern, attribute=None, tag=None): returnlist = [] for obj in objlist: - returnlist = returnlist + obj.matchPattern(regexp,attribute,tag) + returnlist = returnlist + obj.matchPattern(regexp, attribute, tag) return returnlist @@ -418,7 +467,9 @@ def matchPattern(objlist, pattern, attribute=None, tag=None): # # lambda obj: obj.partition_length > 1000 # -# is sufficient, it is not necessary to test for the existence of the attribute. +# is sufficient, it is not necessary to test for the existence of the +# attribute. + def searchPredicate(objlist, predicate, tag=None): if tag is not None: @@ -428,7 +479,7 @@ def searchPredicate(objlist, predicate, tag=None): returnlist = [] for obj in objlist: - returnlist = returnlist + obj.searchPredicate(predicate,tag) + returnlist = returnlist + obj.searchPredicate(predicate, tag) return returnlist @@ -436,74 +487,80 @@ def searchPredicate(objlist, predicate, tag=None): # Classes # Generic CDMS object has a tree node, attributes + + class CdmsObj (object): -## def __setattr__(self,name,value): -## object.__setattr__(self,name,value) -## if not name in self.__cdms_internals__ and not name[0]=='_': -## self.attributes[name]=value -## ## if name == 'shape' : -## ## print self.__class__,name,value +# def __setattr__(self,name,value): +# object.__setattr__(self,name,value) +# if not name in self.__cdms_internals__ and not name[0]=='_': +# self.attributes[name]=value +# if name == 'shape' : +# print self.__class__,name,value def _listatts(self): - dic={} - for nm,val in self.__dict__.items(): - if (nm[0]!='_' and not nm in self.__cdms_internals__) or nm in ['_FillValue']: - dic[nm]=val + dic = {} + for nm, val in self.__dict__.items(): + if (nm[0] != '_' and not nm in self.__cdms_internals__) or nm in ['_FillValue']: + dic[nm] = val if nm == '_units': - dic['units']=val + dic['units'] = val return dic - def _setatts(self,value): + + def _setatts(self, value): return - attributes = property(_listatts,_setatts) - - - def __init__(self, node = None): - if not hasattr(self,'___cdms_internals__'): - self.__dict__['___cdms_internals__']=[ - '__cdms_internals__','___cdms_internals__', - '_node_','_obj_', - '_numericType_','_grid_','_bounds_', - 'parent','attributes','shape','autoApiInfo'] - self.attributes={} + attributes = property(_listatts, _setatts) + + def __init__(self, node=None): + if not hasattr(self, '___cdms_internals__'): + self.__dict__['___cdms_internals__'] = [ + '__cdms_internals__', '___cdms_internals__', + '_node_', '_obj_', + '_numericType_', '_grid_', '_bounds_', + 'parent', 'attributes', 'shape', 'autoApiInfo'] + self.attributes = {} self._node_ = node if node is not None: - # Build an attribute dictionary from the node, + # Build an attribute dictionary from the node, # CDML datatype constraints - if hasattr(node,'datatype'): + if hasattr(node, 'datatype'): parenttype = node.datatype else: parenttype = None atts = node.getExternalDict() adict = self.__dict__ for attname in atts.keys(): - (attval,datatype)=atts[attname] # (XML value, datatype) + (attval, datatype) = atts[attname] # (XML value, datatype) constraint = node.extra.get(attname) if constraint is not None: - (scaletype,reqtype)=constraint # (CdScalar|CdArray, required type) - if reqtype==CdFromObject: + (scaletype, + reqtype) = constraint # (CdScalar|CdArray, required type) + if reqtype == CdFromObject: reqtype = parenttype - if reqtype!=datatype and datatype==CdString and scaletype==CdScalar: - if reqtype in (CdFloat,CdDouble): + if reqtype != datatype and datatype == CdString and scaletype == CdScalar: + if reqtype in (CdFloat, CdDouble): try: attval = float(attval) except: - raise RuntimeError,"%s=%s must be a float"%(attname,attval) - elif reqtype in (CdShort,CdInt,CdLong,CdInt64): + raise RuntimeError( + "%s=%s must be a float" % + (attname, attval)) + elif reqtype in (CdShort, CdInt, CdLong, CdInt64): try: attval = int(attval) except: - raise RuntimeError,"%s=%s must be an integer"%(attname,attval) + raise RuntimeError( + "%s=%s must be an integer" % + (attname, attval)) adict[attname] = attval self.attributes[attname] = attval - def searchone(self, pattern, attname): """Return true if the attribute with name attname is a string attribute which contains the compiled regular expression pattern, or if attname is None and pattern matches at least one string - attribute. Return false if the attribute is not found or is not + attribute. Return false if the attribute is not found or is not a string. ::: Input::: @@ -516,12 +573,12 @@ class CdmsObj (object): """ if attname is None: for attval in self.attributes.values(): - if isinstance(attval,basestring) and pattern.search(attval) is not None: + if isinstance(attval, basestring) and pattern.search(attval) is not None: return 1 return 0 - elif self.attributes.has_key(attname): + elif attname in self.attributes: attval = self.attributes[attname] - return isinstance(attval,basestring) and pattern.search(attval) is not None + return isinstance(attval, basestring) and pattern.search(attval) is not None else: return 0 @@ -546,18 +603,19 @@ class CdmsObj (object): """ if attname is None: for attval in self.attributes.values(): - if isinstance(attval,basestring) and pattern.match(attval) is not None: + if isinstance(attval, basestring) and pattern.match(attval) is not None: return 1 return 0 - elif self.attributes.has_key(attname): + elif attname in self.attributes: attval = self.attributes[attname] - return isinstance(attval,basestring) and pattern.match(attval) is not None + return isinstance(attval, basestring) and pattern.match(attval) is not None else: return 0 # Search for a pattern in a string-valued attribute. If attribute is None, - # search all string attributes. If tag is not None, it must match the internal node tag. - def searchPattern(self,pattern,attribute,tag): + # search all string attributes. If tag is not None, it must match the + # internal node tag. + def searchPattern(self, pattern, attribute, tag): """ Search for a pattern in a string-valued attribute. If attribute is None, search all string attributes. If tag is not None, it must match the internal node tag. ::: @@ -567,11 +625,11 @@ class CdmsObj (object): tag :: (str/None) (2) node tag ::: Output::: - result :: (list) (0) + result :: (list) (0) ::: """ - if tag is None or tag.lower()==self._node_.tag: - if self.searchone(pattern,attribute): + if tag is None or tag.lower() == self._node_.tag: + if self.searchone(pattern, attribute): return [self] else: return [] @@ -579,8 +637,9 @@ class CdmsObj (object): return [] # Match a pattern in a string-valued attribute. If attribute is None, - # search all string attributes. If tag is not None, it must match the internal node tag. - def matchPattern(self,pattern,attribute,tag): + # search all string attributes. If tag is not None, it must match the + # internal node tag. + def matchPattern(self, pattern, attribute, tag): """ Match for a pattern in a string-valued attribute. If attribute is None, search all string attributes. If tag is not None, it must match the internal node tag. ::: @@ -590,11 +649,11 @@ class CdmsObj (object): tag :: (str/None) (2) node tag ::: Output::: - result :: (list) (0) + result :: (list) (0) ::: """ - if tag is None or tag.lower()==self._node_.tag: - if self.matchone(pattern,attribute): + if tag is None or tag.lower() == self._node_.tag: + if self.matchone(pattern, attribute): return [self] else: return [] @@ -604,7 +663,7 @@ class CdmsObj (object): # Apply a truth-valued predicate. Return a list containing a single instance: [self] # if the predicate is true and either tag is None or matches the object node tag. # If the predicate returns false, return an empty list - def searchPredicate(self,predicate,tag): + def searchPredicate(self, predicate, tag): """ Apply a truth-valued predicate. Return a list containing a single instance: [self] if the predicate is true and either tag is None or matches the object node tag. If the predicate returns false, return an empty list ::: @@ -613,12 +672,12 @@ class CdmsObj (object): tag :: (str/None) (1) node tag ::: Output::: - result :: (list) (0) + result :: (list) (0) ::: """ - if tag is None or tag.lower()==self._node_.tag: + if tag is None or tag.lower() == self._node_.tag: try: - if apply(predicate,(self,))==1: + if predicate(*(self,)) == 1: result = [self] except: result = [] @@ -626,7 +685,7 @@ class CdmsObj (object): result = [] return result - def dump(self,path=None,format=1): + def dump(self, path=None, format=1): """ dump(self,path=None,format=1) Dump an XML representation of this object to a file. 'path' is the result file name, None for standard output. @@ -641,24 +700,21 @@ class CdmsObj (object): ::: """ if self._node_ is None: - raise CDMSError, "No tree node found" - self._node_.dump(path,format) + raise CDMSError("No tree node found") + self._node_.dump(path, format) def _getinternals(self): return self.___cdms_internals__ - def _setinternals(self,value): + + def _setinternals(self, value): self.___cdms_internals__ = value - __cdms_internals__ = property(_getinternals,_setinternals) -#internattr.add_internal_attribute(CdmsObj) + __cdms_internals__ = property(_getinternals, _setinternals) +# internattr.add_internal_attribute(CdmsObj) if __name__ == '__main__': x = CdmsObj(None) x.someatt = 1 assert x.attributes['someatt'] == x.someatt - assert not x.attributes.has_key('_node') + assert '_node' not in x.attributes # need tests for the search routines... print "Test passed." - - - - diff --git a/Packages/cdms2/Lib/cdurllib.py b/Packages/cdms2/Lib/cdurllib.py index 6ae1848b3..eefccb114 100644 --- a/Packages/cdms2/Lib/cdurllib.py +++ b/Packages/cdms2/Lib/cdurllib.py @@ -1,13 +1,18 @@ """Customized URLopener""" -import urllib, getpass, socket, string, sys +import urllib +import getpass +import socket +import string +import sys MAXFTPCACHE = 10 # Trim the ftp cache beyond this size + class CDURLopener(urllib.URLopener): def __init__(self, proxies=None): - urllib.URLopener.__init__(self,proxies) + urllib.URLopener.__init__(self, proxies) self._userObject = None # Attach an object to be returned with callbacks @@ -17,12 +22,15 @@ class CDURLopener(urllib.URLopener): # Use FTP protocol def open_ftp(self, url): host, path = urllib.splithost(url) - if not host: raise IOError, ('ftp error', 'no host given') + if not host: + raise IOError, ('ftp error', 'no host given') host, port = urllib.splitport(host) user, host = urllib.splituser(host) # if user: user, passwd = splitpasswd(user) - if user: passwd = getpass.getpass() - else: passwd = None + if user: + passwd = getpass.getpass() + else: + passwd = None host = urllib.unquote(host) user = urllib.unquote(user or '') passwd = urllib.unquote(passwd or '') @@ -36,7 +44,8 @@ class CDURLopener(urllib.URLopener): path = urllib.unquote(path) dirs = string.splitfields(path, '/') dirs, file = dirs[:-1], dirs[-1] - if dirs and not dirs[0]: dirs = dirs[1:] + if dirs and not dirs[0]: + dirs = dirs[1:] key = (user, host, port, string.joinfields(dirs, '/')) # XXX thread unsafe! if len(self.ftpcache) > MAXFTPCACHE: @@ -47,12 +56,14 @@ class CDURLopener(urllib.URLopener): del self.ftpcache[k] v.close() try: - if not self.ftpcache.has_key(key): - print 'Creating ftpwrapper: ',user,host,port,dirs + if key not in self.ftpcache: + print 'Creating ftpwrapper: ', user, host, port, dirs self.ftpcache[key] = \ urllib.ftpwrapper(user, passwd, host, port, dirs) - if not file: type = 'D' - else: type = 'I' + if not file: + type = 'D' + else: + type = 'I' for attr in attrs: attr, value = urllib.splitvalue(attr) if string.lower(attr) == 'type' and \ @@ -60,18 +71,19 @@ class CDURLopener(urllib.URLopener): type = string.upper(value) (fp, retrlen) = self.ftpcache[key].retrfile(file, type) if retrlen is not None and retrlen >= 0: - import mimetools, StringIO + import mimetools + import StringIO headers = mimetools.Message(StringIO.StringIO( 'Content-Length: %d\n' % retrlen)) else: headers = noheaders() return urllib.addinfourl(fp, headers, "ftp:" + url) - except urllib.ftperrors(), msg: + except urllib.ftperrors() as msg: raise IOError, ('ftp error', msg), sys.exc_info()[2] def retrieve(self, url, filename=None, reporthook=None, blocksize=262144): url = urllib.unwrap(url) - if self.tempcache and self.tempcache.has_key(url): + if self.tempcache and url in self.tempcache: return self.tempcache[url] type, url1 = urllib.splittype(url) if not filename and (not type or type == 'file'): @@ -80,7 +92,7 @@ class CDURLopener(urllib.URLopener): hdrs = fp.info() del fp return url2pathname(urllib.splithost(url1)[1]), hdrs - except IOError, msg: + except IOError as msg: pass fp = self.open(url) headers = fp.info() @@ -101,28 +113,28 @@ class CDURLopener(urllib.URLopener): size = -1 blocknum = 1 if reporthook: - if headers.has_key("content-length"): + if "content-length" in headers: size = int(headers["Content-Length"]) stayopen = reporthook(0, bs, size, self._userObject) - if stayopen==0: + if stayopen == 0: raise KeyboardInterrupt bytesread = 0 block = fp.read(bs) if reporthook: stayopen = reporthook(1, bs, size, self._userObject) - if stayopen==0: + if stayopen == 0: raise KeyboardInterrupt while block: tfp.write(block) bytesread = bytesread + len(block) -## print blocknum, bytesread, size, -## if blocknum*blocksize!=bytesread: -## print ' (*)' -## else: -## print +# print blocknum, bytesread, size, +# if blocknum*blocksize!=bytesread: +# print ' (*)' +# else: +# print if block and reporthook: stayopen = reporthook(blocknum, bs, size, self._userObject) - if stayopen==0: + if stayopen == 0: raise KeyboardInterrupt blocknum = blocknum + 1 block = fp.read(bs) @@ -132,23 +144,25 @@ class CDURLopener(urllib.URLopener): del tfp return result + def sampleReportHook(blocknum, blocksize, size, userObj): - sizekb = size/1024 - percent = min(100,int(100.0*float(blocknum*blocksize)/float(size))) - print "Read: %3d%% of %dK"%(percent,sizekb) + sizekb = size / 1024 + percent = min(100, int(100.0 * float(blocknum * blocksize) / float(size))) + print "Read: %3d%% of %dK" % (percent, sizekb) return 1 if __name__ == '__main__': import sys - if len(sys.argv)!=4: + if len(sys.argv) != 4: print 'Usage: cdurllib.py URL filename blocksize' sys.exit(1) url = sys.argv[1] filename = sys.argv[2] blocksize = int(sys.argv[3]) - + urlopener = CDURLopener() - fname, headers = urlopener.retrieve(url, filename, sampleReportHook, blocksize) + fname, headers = urlopener.retrieve( + url, filename, sampleReportHook, blocksize) print fname, 'written' diff --git a/Packages/cdms2/Lib/cdurlparse.py b/Packages/cdms2/Lib/cdurlparse.py index e743ebbc8..d88dd4087 100644 --- a/Packages/cdms2/Lib/cdurlparse.py +++ b/Packages/cdms2/Lib/cdurlparse.py @@ -9,25 +9,26 @@ from string import joinfields, splitfields, find, rfind # A classification of schemes ('' means apply by default) uses_relative = ['ftp', 'http', 'ldap', 'gopher', 'nntp', 'wais', 'file', - 'https', 'shttp', - 'prospero', ''] + 'https', 'shttp', + 'prospero', ''] uses_netloc = ['ftp', 'http', 'ldap', 'gopher', 'nntp', 'telnet', 'wais', - 'file', - 'https', 'shttp', 'snews', - 'prospero', ''] + 'file', + 'https', 'shttp', 'snews', + 'prospero', ''] non_hierarchical = ['gopher', 'hdl', 'mailto', 'news', 'telnet', 'wais', - 'snews', - ] + 'snews', + ] uses_params = ['ftp', 'hdl', 'prospero', 'http', 'ldap', - 'https', 'shttp', - ''] + 'https', 'shttp', + ''] uses_query = ['http', 'ldap', 'wais', - 'https', 'shttp', - 'gopher', - ''] -uses_fragment = ['ftp', 'hdl', 'http', 'ldap', 'gopher', 'news', 'nntp', 'wais', - 'https', 'shttp', 'snews', - 'file', 'prospero', ''] + 'https', 'shttp', + 'gopher', + ''] +uses_fragment = [ + 'ftp', 'hdl', 'http', 'ldap', 'gopher', 'news', 'nntp', 'wais', + 'https', 'shttp', 'snews', + 'file', 'prospero', ''] # Characters valid in scheme names scheme_chars = string.letters + string.digits + '+-.' @@ -35,6 +36,7 @@ scheme_chars = string.letters + string.digits + '+-.' MAX_CACHE_SIZE = 20 _parse_cache = {} + def clear_cache(): """Clear the parse cache.""" global _parse_cache @@ -46,134 +48,141 @@ def clear_cache(): # Return a 6-tuple: (scheme, netloc, path, params, query, fragment). # Note that we don't break the components up in smaller bits # (e.g. netloc is a single string) and we don't expand % escapes. -def urlparse(url, scheme = '', allow_fragments = 1): - key = url, scheme, allow_fragments - cached = _parse_cache.get(key, None) - if cached: - return cached - if len(_parse_cache) >= MAX_CACHE_SIZE: # avoid runaway growth - clear_cache() - find = string.find - netloc = path = params = query = fragment = '' - i = find(url, ':') - if i > 0: - if url[:i] in ['http','ldap']: # optimize the common case - scheme = string.lower(url[:i]) - url = url[i+1:] - if url[:2] == '//': - i = find(url, '/', 2) - if i < 0: - i = len(url) - netloc = url[2:i] - url = url[i:] - if allow_fragments: - i = string.rfind(url, '#') - if i >= 0: - fragment = url[i+1:] - url = url[:i] - i = find(url, '?') - if i >= 0: - query = url[i+1:] - url = url[:i] - i = find(url, ';') - if i >= 0: - params = url[i+1:] - url = url[:i] - tuple = scheme, netloc, url, params, query, fragment - _parse_cache[key] = tuple - return tuple - for c in url[:i]: - if c not in scheme_chars: - break - else: - scheme, url = string.lower(url[:i]), url[i+1:] - if scheme in uses_netloc: - if url[:2] == '//': - i = find(url, '/', 2) - if i < 0: - i = len(url) - netloc, url = url[2:i], url[i:] - if allow_fragments and scheme in uses_fragment: - i = string.rfind(url, '#') - if i >= 0: - url, fragment = url[:i], url[i+1:] - if scheme in uses_query: - i = find(url, '?') - if i >= 0: - url, query = url[:i], url[i+1:] - if scheme in uses_params: - i = find(url, ';') - if i >= 0: - url, params = url[:i], url[i+1:] - tuple = scheme, netloc, url, params, query, fragment - _parse_cache[key] = tuple - return tuple +def urlparse(url, scheme='', allow_fragments=1): + key = url, scheme, allow_fragments + cached = _parse_cache.get(key, None) + if cached: + return cached + if len(_parse_cache) >= MAX_CACHE_SIZE: # avoid runaway growth + clear_cache() + find = string.find + netloc = path = params = query = fragment = '' + i = find(url, ':') + if i > 0: + if url[:i] in ['http', 'ldap']: # optimize the common case + scheme = string.lower(url[:i]) + url = url[i + 1:] + if url[:2] == '//': + i = find(url, '/', 2) + if i < 0: + i = len(url) + netloc = url[2:i] + url = url[i:] + if allow_fragments: + i = string.rfind(url, '#') + if i >= 0: + fragment = url[i + 1:] + url = url[:i] + i = find(url, '?') + if i >= 0: + query = url[i + 1:] + url = url[:i] + i = find(url, ';') + if i >= 0: + params = url[i + 1:] + url = url[:i] + tuple = scheme, netloc, url, params, query, fragment + _parse_cache[key] = tuple + return tuple + for c in url[:i]: + if c not in scheme_chars: + break + else: + scheme, url = string.lower(url[:i]), url[i + 1:] + if scheme in uses_netloc: + if url[:2] == '//': + i = find(url, '/', 2) + if i < 0: + i = len(url) + netloc, url = url[2:i], url[i:] + if allow_fragments and scheme in uses_fragment: + i = string.rfind(url, '#') + if i >= 0: + url, fragment = url[:i], url[i + 1:] + if scheme in uses_query: + i = find(url, '?') + if i >= 0: + url, query = url[:i], url[i + 1:] + if scheme in uses_params: + i = find(url, ';') + if i >= 0: + url, params = url[:i], url[i + 1:] + tuple = scheme, netloc, url, params, query, fragment + _parse_cache[key] = tuple + return tuple # Put a parsed URL back together again. This may result in a slightly # different, but equivalent URL, if the URL that was parsed originally # had redundant delimiters, e.g. a ? with an empty query (the draft # states that these are equivalent). -def urlunparse((scheme, netloc, url, params, query, fragment)): - if netloc or (scheme in uses_netloc and url[:2] == '//'): - if url[:1] != '/': url = '/' + url - url = '//' + (netloc or '') + url - if scheme: - url = scheme + ':' + url - if params: - url = url + ';' + params - if query: - url = url + '?' + query - if fragment: - url = url + '#' + fragment - return url + + +def urlunparse(xxx_todo_changeme): + (scheme, netloc, url, params, query, fragment) = xxx_todo_changeme + if netloc or (scheme in uses_netloc and url[:2] == '//'): + if url[:1] != '/': + url = '/' + url + url = '//' + (netloc or '') + url + if scheme: + url = scheme + ':' + url + if params: + url = url + ';' + params + if query: + url = url + '?' + query + if fragment: + url = url + '#' + fragment + return url # Join a base URL and a possibly relative URL to form an absolute # interpretation of the latter. -def urljoin(base, url, allow_fragments = 1): - if not base: - return url - bscheme, bnetloc, bpath, bparams, bquery, bfragment = \ - urlparse(base, '', allow_fragments) - scheme, netloc, path, params, query, fragment = \ - urlparse(url, bscheme, allow_fragments) - if scheme != bscheme or scheme not in uses_relative: - return urlunparse((scheme, netloc, path, - params, query, fragment)) - if scheme in uses_netloc: - if netloc: - return urlunparse((scheme, netloc, path, - params, query, fragment)) - netloc = bnetloc - if path[:1] == '/': - return urlunparse((scheme, netloc, path, - params, query, fragment)) - if not path: - return urlunparse((scheme, netloc, bpath, - params, query or bquery, fragment)) - i = rfind(bpath, '/') - if i >= 0: - path = bpath[:i] + '/' + path - segments = splitfields(path, '/') - if segments[-1] == '.': - segments[-1] = '' - while '.' in segments: - segments.remove('.') - while 1: - i = 1 - n = len(segments) - 1 - while i < n: - if segments[i] == '..' and segments[i-1]: - del segments[i-1:i+1] - break - i = i+1 - else: - break - if len(segments) == 2 and segments[1] == '..' and segments[0] == '': - segments[-1] = '' - elif len(segments) >= 2 and segments[-1] == '..': - segments[-2:] = [''] - return urlunparse((scheme, netloc, joinfields(segments, '/'), - params, query, fragment)) + + +def urljoin(base, url, allow_fragments=1): + if not base: + return url + bscheme, bnetloc, bpath, bparams, bquery, bfragment = \ + urlparse(base, '', allow_fragments) + scheme, netloc, path, params, query, fragment = \ + urlparse(url, bscheme, allow_fragments) + if scheme != bscheme or scheme not in uses_relative: + return urlunparse((scheme, netloc, path, + params, query, fragment)) + if scheme in uses_netloc: + if netloc: + return urlunparse((scheme, netloc, path, + params, query, fragment)) + netloc = bnetloc + if path[:1] == '/': + return urlunparse((scheme, netloc, path, + params, query, fragment)) + if not path: + return urlunparse((scheme, netloc, bpath, + params, query or bquery, fragment)) + i = rfind(bpath, '/') + if i >= 0: + path = bpath[:i] + '/' + path + segments = splitfields(path, '/') + if segments[-1] == '.': + segments[-1] = '' + while '.' in segments: + segments.remove('.') + while True: + i = 1 + n = len(segments) - 1 + while i < n: + if segments[i] == '..' and segments[i - 1]: + del segments[i - 1:i + 1] + break + i = i + 1 + else: + break + if len(segments) == 2 and segments[1] == '..' and segments[0] == '': + segments[-1] = '' + elif len(segments) >= 2 and segments[-1] == '..': + segments[-2:] = [''] + return urlunparse((scheme, netloc, joinfields(segments, '/'), + params, query, fragment)) + def urldefrag(url): """Removes any existing fragment from URL. @@ -222,35 +231,37 @@ test_input = """ """ # XXX The result for //g is actually http://g/; is this a problem? + def test(): - import sys - base = '' - if sys.argv[1:]: - fn = sys.argv[1] - if fn == '-': - fp = sys.stdin - else: - fp = open(fn) - else: - import StringIO - fp = StringIO.StringIO(test_input) - while 1: - line = fp.readline() - if not line: break - words = string.split(line) - if not words: - continue - url = words[0] - parts = urlparse(url) - print '%-10s : %s' % (url, parts) - abs = urljoin(base, url) - if not base: - base = abs - wrapped = '' % abs - print '%-10s = %s' % (url, wrapped) - if len(words) == 3 and words[1] == '=': - if wrapped != words[2]: - print 'EXPECTED', words[2], '!!!!!!!!!!' + import sys + base = '' + if sys.argv[1:]: + fn = sys.argv[1] + if fn == '-': + fp = sys.stdin + else: + fp = open(fn) + else: + import StringIO + fp = StringIO.StringIO(test_input) + while True: + line = fp.readline() + if not line: + break + words = string.split(line) + if not words: + continue + url = words[0] + parts = urlparse(url) + print '%-10s : %s' % (url, parts) + abs = urljoin(base, url) + if not base: + base = abs + wrapped = '' % abs + print '%-10s = %s' % (url, wrapped) + if len(words) == 3 and words[1] == '=': + if wrapped != words[2]: + print 'EXPECTED', words[2], '!!!!!!!!!!' if __name__ == '__main__': - test() + test() diff --git a/Packages/cdms2/Lib/cdxmllib.py b/Packages/cdms2/Lib/cdxmllib.py index 7c1aff308..70b91d9ba 100644 --- a/Packages/cdms2/Lib/cdxmllib.py +++ b/Packages/cdms2/Lib/cdxmllib.py @@ -11,6 +11,7 @@ import re version = '0.3' + class Error(RuntimeError): pass @@ -20,7 +21,7 @@ _S = '[ \t\r\n]+' # white space _opS = '[ \t\r\n]*' # optional white space _Name = '[a-zA-Z_:][-a-zA-Z0-9._:]*' # valid XML name _QStr = "(?:'[^']*'|\"[^\"]*\")" # quoted XML string -illegal = re.compile('[^\t\r\n -\176\240-\377]') # illegal chars in content +illegal = re.compile('[^\t\r\n -\176\240-\377]') # illegal chars in content interesting = re.compile('[]&<]') amp = re.compile('&') @@ -33,37 +34,37 @@ newline = re.compile('\n') attrfind = re.compile( _S + '(?P' + _Name + ')' '(' + _opS + '=' + _opS + - '(?P'+_QStr+'|[-a-zA-Z0-9.:+*%?!\(\)_#=~]+))?') + '(?P' + _QStr + '|[-a-zA-Z0-9.:+*%?!\(\)_#=~]+))?') starttagopen = re.compile('<' + _Name) starttagend = re.compile(_opS + '(?P/?)>') -starttagmatch = re.compile('<(?P'+_Name+')' - '(?P(?:'+attrfind.pattern+')*)'+ - starttagend.pattern) +starttagmatch = re.compile('<(?P' + _Name + ')' + '(?P(?:' + attrfind.pattern + ')*)' + + starttagend.pattern) endtagopen = re.compile('') -endbracketfind = re.compile('(?:[^>\'"]|'+_QStr+')*>') +endbracketfind = re.compile('(?:[^>\'"]|' + _QStr + ')*>') tagfind = re.compile(_Name) cdataopen = re.compile(r'') # this matches one of the following: # SYSTEM SystemLiteral # PUBLIC PubidLiteral SystemLiteral -_SystemLiteral = '(?P<%s>'+_QStr+')' +_SystemLiteral = '(?P<%s>' + _QStr + ')' _PublicLiteral = '(?P<%s>"[-\'\(\)+,./:=?;!*#@$_%% \n\ra-zA-Z0-9]*"|' \ - "'[-\(\)+,./:=?;!*#@$_%% \n\ra-zA-Z0-9]*')" + "'[-\(\)+,./:=?;!*#@$_%% \n\ra-zA-Z0-9]*')" _ExternalId = '(?:SYSTEM|' \ - 'PUBLIC'+_S+_PublicLiteral%'pubid'+ \ - ')'+_S+_SystemLiteral%'syslit' -doctype = re.compile(''+_Name+')' - '(?:'+_S+_ExternalId+')?'+_opS) -xmldecl = re.compile('<\?xml'+_S+ - 'version'+_opS+'='+_opS+'(?P'+_QStr+')'+ - '(?:'+_S+'encoding'+_opS+'='+_opS+ - "(?P'[A-Za-z][-A-Za-z0-9._]*'|" - '"[A-Za-z][-A-Za-z0-9._]*"))?' - '(?:'+_S+'standalone'+_opS+'='+_opS+ - '(?P\'(?:yes|no)\'|"(?:yes|no)"))?'+ - _opS+'\?>') + 'PUBLIC' + _S + _PublicLiteral % 'pubid' + \ + ')' + _S + _SystemLiteral % 'syslit' +doctype = re.compile('' + _Name + ')' + '(?:' + _S + _ExternalId + ')?' + _opS) +xmldecl = re.compile('<\?xml' + _S + + 'version' + _opS + '=' + _opS + '(?P' + _QStr + ')' + + '(?:' + _S + 'encoding' + _opS + '=' + _opS + + "(?P'[A-Za-z][-A-Za-z0-9._]*'|" + '"[A-Za-z][-A-Za-z0-9._]*"))?' + '(?:' + _S + 'standalone' + _opS + '=' + _opS + + '(?P\'(?:yes|no)\'|"(?:yes|no)"))?' + + _opS + '\?>') procopen = re.compile(r'<\?(?P' + _Name + ')' + _opS) procclose = re.compile(_opS + r'\?>') commentopen = re.compile(' tm1.shape = (1, :, :) tm1 = reshape(cvar, tuple([1] + list(cvar.shape))) # Attach needed items var = cdms2.createVariable(tm1, - axes = axes, - grid = grid, - attributes = atts, - id = cvar.standard_name) + axes=axes, + grid=grid, + attributes=atts, + id=cvar.standard_name) # Create cdms2 transient variable if firsttime: @@ -253,26 +268,31 @@ class TimeAggregatedFileVariable: # insert the new time axis. taA = new.getTime() newTime = axisConcatenate((taA, timeAxis), - attributes = axisTime.attributes, - id = axisTime.id) - axes = self.buildAxes(newTime, self.fvs[file].getAxisList()) + attributes=axisTime.attributes, + id=axisTime.id) + axes = self.buildAxes( + newTime, + self.fvs[file].getAxisList()) tmp = MV2concatenate((new, var)) new = cdms2.createVariable(tmp, - axes = axes, - grid = grid, - attributes = atts, - id = cvar.standard_name) + axes=axes, + grid=grid, + attributes=atts, + id=cvar.standard_name) else: new = self.fvs[fileIndices][timeIndices] return new + class TimeFileVariable: + """ Construct an aggregated time dependant variable. """ + def __init__(self, hostObj, varName): """ Create a list of file variable with grid attached @@ -297,8 +317,12 @@ class TimeFileVariable: # Open the files fn = hostObj.timeVars[varName][gridIndex][timeFileIndex] - f = cdms2.open(fn, mode) # Need f and u because they serve slightly different purposes - u = CdunifFile(fn, mode) # f.axes exists while axes is not a part of u + f = cdms2.open( + fn, + mode) # Need f and u because they serve slightly different purposes + u = CdunifFile( + fn, + mode) # f.axes exists while axes is not a part of u # u.variables[varName].gridIndex = gridIndex # Turn the coordinates into a list @@ -310,12 +334,14 @@ class TimeFileVariable: coordsaux = f._convention_.getAxisAuxIds(u.variables, coords1d) # Convert the variable into a FileVariable - f.variables[varName] = FileVariable(f, varName, u.variables[varName]) + f.variables[varName] = FileVariable( + f, varName, u.variables[varName]) # Add the coordinates to the file for coord in coords: f.variables[coord] = g.variables[coord] - f.variables[coord] = FileAxis2D(f, coord, g.variables[coord]) + f.variables[coord] = FileAxis2D( + f, coord, g.variables[coord]) # Build the axes for key in f.axes.keys(): @@ -323,7 +349,8 @@ class TimeFileVariable: # Set the boundaries for coord in coords: - bounds = f._convention_.getVariableBounds(f, f.variables[coord]) + bounds = f._convention_.getVariableBounds( + f, f.variables[coord]) f.variables[coord].setBounds(bounds) # Initialize the domain @@ -331,10 +358,16 @@ class TimeFileVariable: var.initDomain(f.axes) # Add the grid - gridkey, lat, lon = f.variables[varName].generateGridkey(f._convention_, f.variables) + gridkey, lat, lon = f.variables[ + varName].generateGridkey(f._convention_, f.variables) gridname = ("grid%d_" % gridIndex) + "%dx%d" % lat.shape -# grid = FileGenericGrid(lat, lon, gridname, parent = f, maskvar = None) - grid = FileCurveGrid(lat, lon, gridname, parent = f, maskvar = None) +# grid = FileGenericGrid(lat, lon, gridname, parent = f, maskvar = None) + grid = FileCurveGrid( + lat, + lon, + gridname, + parent=f, + maskvar=None) f.variables[varName]._grid_ = grid vars.append(f.variables[varName]) @@ -343,23 +376,23 @@ class TimeFileVariable: self._repr_string = "TimeFileVariable" - def listall(self, all = None): + def listall(self, all=None): """ Gain access to cdms2 listall method. Requires a TimeFileVariable @param all @returns list """ - return self[0][0].listall(all = all) + return self[0][0].listall(all=all) - def showall(self, all = None, device = None): + def showall(self, all=None, device=None): """ Gain access to cdms2 showall method Requires a TimeFileVariable @param all - @param device + @param device @returns list """ - return self[0][0][:].showall(all = all, device = device) + return self[0][0][:].showall(all=all, device=device) def __getitem__(self, gridIndex): """ @@ -367,11 +400,13 @@ class TimeFileVariable: """ return self.vars[gridIndex] -############################################################################### -############## DEPRECIATED - Testing required to fully remove ################# -############################################################################### +# +# DEPRECIATED - Testing required to fully remove ################# +# + class TimeTransientVariable: + def __init__(self, hostObj, varName, **slicekwargs): """ Constructor @@ -402,15 +437,18 @@ class TimeTransientVariable: for timeFileIndex in range(hostObj.nTimeDataFiles): - fName = hostObj.timeDepVars[varName][gridIndex][timeFileIndex] + fName = hostObj.timeDepVars[ + varName][ + gridIndex][ + timeFileIndex] fh = cdms2.open(fName, hostObj=hostObj) # TransientVariable var = fh(varName, **slicekwargs) # Attach the grid to the variable - grid = cdms2.gsStaticVariable.createTransientGrid(gFName, \ - var.attributes['coordinates']) + grid = cdms2.gsStaticVariable.createTransientGrid(gFName, + var.attributes['coordinates']) axis0 = var.getAxis(0) gridaxes = grid.getAxisList() axes = [axis0] + list(gridaxes) @@ -420,21 +458,21 @@ class TimeTransientVariable: # Create cdms2 transient variable if timeFileIndex == 0: new = cdms2.createVariable(var, - axes = axes, - grid = grid, - attributes = atts, - id = var.standard_name) + axes=axes, + grid=grid, + attributes=atts, + id=var.standard_name) else: - tmp =MV2concatenate((new, var)) + tmp = MV2concatenate((new, var)) axis0 = tmp.getAxis(0) gridaxes = grid.getAxisList() axes = [axis0, gridaxes[0], gridaxes[1]] # new.append(tmp) new = cdms2.createVariable(tmp, - axes = axes, - grid = grid, - attributes = atts, - id = var.standard_name) + axes=axes, + grid=grid, + attributes=atts, + id=var.standard_name) fh.close() # Add the variable to the index @@ -443,10 +481,10 @@ class TimeTransientVariable: self._repr_string = "TimeTransientVariable" -################################################################### +# def test(): pass -if __name__ == '__main__': test() - +if __name__ == '__main__': + test() diff --git a/Packages/cdms2/Lib/gui.py b/Packages/cdms2/Lib/gui.py index 65e13cd8c..44fab4cb6 100644 --- a/Packages/cdms2/Lib/gui.py +++ b/Packages/cdms2/Lib/gui.py @@ -5,6 +5,7 @@ from cdms import cache _progressParent = None # Parent frame of progress gui + def setProgressParent(parent): """ Enable the FTP progress GUI, and set the parent frame. @@ -12,7 +13,9 @@ def setProgressParent(parent): """ global _progressParent _progressParent = parent - cache.useWindow() # Notify cache module that window dialogs should be used. + cache.useWindow() + # Notify cache module that window dialogs should be used. + def getProgressParent(): """ @@ -21,6 +24,7 @@ def getProgressParent(): """ return _progressParent + def updateProgressGui(blocknum, blocksize, size, prog): """ Callback function for the FTP progress dialog. @@ -31,25 +35,28 @@ def updateProgressGui(blocknum, blocksize, size, prog): Return: 0 to signal that a cancel has been received, 1 to continue reading. """ - sizekb = size/1024L - percent = min(100,int(100.0*float(blocknum*blocksize)/float(size))) - if percent<100: - noInterrupt = prog.Update(percent,"Read: %3d%% of %dK"%(percent,sizekb)) + sizekb = size / 1024 + percent = min(100, int(100.0 * float(blocknum * blocksize) / float(size))) + if percent < 100: + noInterrupt = prog.Update( + percent, "Read: %3d%% of %dK" % + (percent, sizekb)) else: noInterrupt = 1 # Don't interrupt - finish up cleanly prog.Destroy() - if noInterrupt==0: + if noInterrupt == 0: prog.Destroy() return noInterrupt + class CdProgressDialog(wxProgressDialog): # is the parent frame. # filename is the file being read. - def __init__(self, frame, filename): - wxProgressDialog.__init__(self,"FTP: %s"%filename, - "Connecting ...", - 100, - frame, - wxPD_CAN_ABORT | wxPD_APP_MODAL | wxPD_REMAINING_TIME) + def __init__(self, frame, filename): + wxProgressDialog.__init__(self, "FTP: %s" % filename, + "Connecting ...", + 100, + frame, + wxPD_CAN_ABORT | wxPD_APP_MODAL | wxPD_REMAINING_TIME) diff --git a/Packages/cdms2/Lib/hgrid.py b/Packages/cdms2/Lib/hgrid.py index 1f53d3702..aa09ca8c5 100644 --- a/Packages/cdms2/Lib/hgrid.py +++ b/Packages/cdms2/Lib/hgrid.py @@ -1,5 +1,5 @@ -## Automatically adapted for numpy.oldnumeric Aug 01, 2007 by -## Further modified to be pure new numpy June 24th 2008 +# Automatically adapted for numpy.oldnumeric Aug 01, 2007 by +# Further modified to be pure new numpy June 24th 2008 """CDMS HorizontalGrid objects""" @@ -7,19 +7,20 @@ import numpy import cdms2 import os import os.path -## import PropertiedClasses -from error import CDMSError -from grid import AbstractGrid, LongitudeType, LatitudeType, VerticalType, TimeType, CoordTypeToLoc -from coord import TransientVirtualAxis -from axis import getAutoBounds, allclose -import bindex,_bindex +# import PropertiedClasses +from .error import CDMSError +from .grid import AbstractGrid, LongitudeType, LatitudeType, VerticalType, TimeType, CoordTypeToLoc +from .coord import TransientVirtualAxis +from .axis import getAutoBounds, allclose +import bindex, _bindex +from functools import reduce MethodNotImplemented = "Method not yet implemented" def _flatten(boundsar): boundsshape = boundsar.shape - if len(boundsshape)>2: - newshape = (reduce((lambda x,y: x*y), boundsshape[:-1], 1), boundsshape[-1]) + if len(boundsshape) > 2: + newshape = (reduce((lambda x, y: x*y), boundsshape[:-1], 1), boundsshape[-1]) boundsar.shape = newshape return boundsar @@ -40,17 +41,17 @@ class AbstractHorizontalGrid(AbstractGrid): # Generate default bounds def genBounds(self): - raise CDMSError, MethodNotImplemented + raise CDMSError(MethodNotImplemented) # Get the n-th axis. naxis is 0 or 1. def getAxis(self, naxis): - raise CDMSError, MethodNotImplemented + raise CDMSError(MethodNotImplemented) def getBounds(self): """Get the grid cell boundaries, as a tuple (latitudeBounds, longitudeBounds) """ latbnds, lonbnds = (self._lataxis_.getExplicitBounds(), self._lonaxis_.getExplicitBounds()) - if (latbnds is None or lonbnds is None) and getAutoBounds() in [1,2]: + if (latbnds is None or lonbnds is None) and getAutoBounds() in [1, 2]: nlatbnds, nlonbnds = self.genBounds() if latbnds is None: latbnds = nlatbnds @@ -76,27 +77,27 @@ class AbstractHorizontalGrid(AbstractGrid): def getMesh(self): """Get the mesh array used by the meshfill plot.""" - raise CDMSError, MethodNotImplemented + raise CDMSError(MethodNotImplemented) def getWeightsArray(self): """Return normalized area weights, as an array of the same shape as the grid. """ - raise CDMSError, MethodNotImplemented + raise CDMSError(MethodNotImplemented) def listall (self, all=None): - result=[] + result = [] result.append('Grid has Python id %s.' % hex(id(self))) return result - def setMask(self,mask,permanent=0): + def setMask(self, mask, permanent=0): self._maskVar_ = mask def subGridRegion(self, latRegion, lonRegion): - raise CDMSError, MethodNotImplemented + raise CDMSError(MethodNotImplemented) def hasCoordType(self, coordType): - return ((coordType==LatitudeType) or (coordType==LongitudeType)) + return ((coordType == LatitudeType) or (coordType == LongitudeType)) def checkConvex(self): """Check that each cell of the grid is convex in lon-lat space, with nodes defined counter-clockwise. @@ -116,10 +117,10 @@ class AbstractHorizontalGrid(AbstractGrid): for n0 in range(nnode): n1 = (n0+1)%nnode n2 = (n1+1)%nnode - vec0lon = lonb[:,n1] - lonb[:,n0] - vec0lat = latb[:,n1] - latb[:,n0] - vec1lon = lonb[:,n2] - lonb[:,n1] - vec1lat = latb[:,n2] - latb[:,n1] + vec0lon = lonb[:, n1] - lonb[:, n0] + vec0lat = latb[:, n1] - latb[:, n0] + vec1lon = lonb[:, n2] - lonb[:, n1] + vec1lat = latb[:, n2] - latb[:, n1] cross = vec0lon*vec1lat - vec0lat*vec1lon mask = where(less(cross, 0.0), 1, 0) @@ -170,24 +171,24 @@ class AbstractHorizontalGrid(AbstractGrid): for node in range(2*nnode): n0 = node%nnode n1 = (n0+1)%nnode - vec0lon = lonb2[k,n1]-lonb2[k,n0] - if vec0lon>threshold: - lonb2[k,n1] -= 360.0 - elif vec0lon<-threshold: - lonb2[k,n1] += 360.0 + vec0lon = lonb2[k, n1]-lonb2[k, n0] + if vec0lon > threshold: + lonb2[k, n1] -= 360.0 + elif vec0lon < -threshold: + lonb2[k, n1] += 360.0 # If the cross-product test still fails, restore # the original values and add to the nonConvexCells list for n0 in range(nnode): n1 = (n0+1)%nnode n2 = (n1+1)%nnode - vec0lon = lonb2[k,n1] - lonb2[k,n0] - vec0lat = latb2[k,n1] - latb2[k,n0] - vec1lon = lonb2[k,n2] - lonb2[k,n1] - vec1lat = latb2[k,n2] - latb2[k,n1] + vec0lon = lonb2[k, n1] - lonb2[k, n0] + vec0lat = latb2[k, n1] - latb2[k, n0] + vec1lon = lonb2[k, n2] - lonb2[k, n1] + vec1lat = latb2[k, n2] - latb2[k, n1] cross = vec0lon*vec1lat - vec0lat*vec1lon - if cross<0: + if cross < 0: lonb2[k] = savelons newbadcells.append(nonConvexCells[k]) break @@ -207,7 +208,7 @@ class AbstractCurveGrid(AbstractHorizontalGrid): """Create a curvilinear grid. """ if latAxis.shape != lonAxis.shape: - raise CDMSError, 'Latitude and longitude axes must have the same shape.' + raise CDMSError('Latitude and longitude axes must have the same shape.') AbstractHorizontalGrid.__init__(self, latAxis, lonAxis, id, maskvar, tempmask, node) self._index_ = None @@ -217,7 +218,7 @@ class AbstractCurveGrid(AbstractHorizontalGrid): return TransientCurveGrid(newlat, newlon, id=self.id) def __repr__(self): - return ""%(self.id, `self.shape`) + return ""%(self.id, repr(self.shape)) __str__ = __repr__ def getMesh(self, transpose=None): @@ -226,20 +227,20 @@ class AbstractCurveGrid(AbstractHorizontalGrid): latbounds and lonbounds according to the tuple, (1,0,2) in this case. """ if self._mesh_ is None: - LAT=0 - LON=1 + LAT = 0 + LON = 1 latbounds, lonbounds = self.getBounds() -## ## following work aronud a numpy.ma bug -## latbounds=latbounds.filled() -## lonbounds=lonbounds.filled() +# following work aronud a numpy.ma bug +# latbounds=latbounds.filled() +# lonbounds=lonbounds.filled() if latbounds is None or lonbounds is None: - raise CDMSError, 'No boundary data is available for grid %s'%self.id - if (transpose is not None) and (transpose[1]==0): - latbounds = numpy.transpose(latbounds, (1,0,2)) - lonbounds = numpy.transpose(lonbounds, (1,0,2)) - mesh = numpy.zeros((self.size(),2,latbounds.shape[-1]),latbounds.dtype.char) - mesh[:,LAT,:] = numpy.reshape(latbounds,(self.size(),latbounds.shape[-1])) - mesh[:,LON,:] = numpy.reshape(lonbounds,(self.size(),latbounds.shape[-1])) + raise CDMSError('No boundary data is available for grid %s'%self.id) + if (transpose is not None) and (transpose[1] == 0): + latbounds = numpy.transpose(latbounds, (1, 0, 2)) + lonbounds = numpy.transpose(lonbounds, (1, 0, 2)) + mesh = numpy.zeros((self.size(), 2, latbounds.shape[-1]), latbounds.dtype.char) + mesh[:, LAT,:] = numpy.reshape(latbounds, (self.size(), latbounds.shape[-1])) + mesh[:, LON,:] = numpy.reshape(lonbounds, (self.size(), latbounds.shape[-1])) self._mesh_ = mesh return self._mesh_ @@ -291,9 +292,9 @@ class AbstractCurveGrid(AbstractHorizontalGrid): mask.shape = (ngrid,) clat = numpy.ma.filled(copy.copy(blat)) - clat.shape = (ngrid,4) + clat.shape = (ngrid, 4) clon = numpy.ma.filled(copy.copy(blon)) - clon.shape = (ngrid,4) + clon.shape = (ngrid, 4) # Write the file if gridTitle is None: @@ -309,12 +310,12 @@ class AbstractCurveGrid(AbstractHorizontalGrid): gridcenterlon.units = "degrees" gridimask = cufile.createVariable("grid_imask", 'i', ("grid_size",)) gridimask.units = "unitless" - gridcornerlat = cufile.createVariable("grid_corner_lat", 'd', ("grid_size","grid_corners")) + gridcornerlat = cufile.createVariable("grid_corner_lat", 'd', ("grid_size", "grid_corners")) gridcornerlat.units = "degrees" - gridcornerlon = cufile.createVariable("grid_corner_lon", 'd', ("grid_size","grid_corners")) + gridcornerlon = cufile.createVariable("grid_corner_lon", 'd', ("grid_size", "grid_corners")) gridcornerlon.units = "degrees" - griddims[:] = numpy.array([nj,ni], numpy.int32) + griddims[:] = numpy.array([nj, ni], numpy.int32) gridcenterlat[:] = centerLat gridcenterlon[:] = centerLon gridimask[:] = mask @@ -324,9 +325,9 @@ class AbstractCurveGrid(AbstractHorizontalGrid): def toGenericGrid(self, gridid=None): import copy - from auxcoord import TransientAuxAxis1D - from coord import TransientVirtualAxis - from gengrid import TransientGenericGrid + from .auxcoord import TransientAuxAxis1D + from .coord import TransientVirtualAxis + from .gengrid import TransientGenericGrid lat = numpy.ma.filled(self._lataxis_) latunits = self._lataxis_.units @@ -345,11 +346,11 @@ class AbstractCurveGrid(AbstractHorizontalGrid): mask.shape = (ngrid,) cornerLat = numpy.ma.filled(copy.copy(blat)) - cornerLat.shape = (ngrid,4) + cornerLat.shape = (ngrid, 4) cornerLon = numpy.ma.filled(copy.copy(blon)) - cornerLon.shape = (ngrid,4) + cornerLon.shape = (ngrid, 4) - iaxis = TransientVirtualAxis("cell",ngrid) + iaxis = TransientVirtualAxis("cell", ngrid) lataxis = TransientAuxAxis1D(centerLat, axes=(iaxis,), bounds=cornerLat, attributes={'units':latunits}, id="latitude") @@ -381,21 +382,21 @@ class AbstractCurveGrid(AbstractHorizontalGrid): The file, normally a CdmsFile, should already be open for writing and will be closed.""" import time - from tvariable import TransientVariable + from .tvariable import TransientVariable # Set attributes - if ( hasattr(file,'Conventions') ): - if ( file.Conventions.find('Gridspec')<0 ): + if ( hasattr(file, 'Conventions') ): + if ( file.Conventions.find('Gridspec') < 0 ): file.Conventions = file.Conventions + ' Gridspec-0.0' else: file.Conventions = 'Gridspec-0.0' - if ( hasattr(file,'gs_filetypes') ): - if ( file.gs_filetypes.find('Curvilinear_Tile')<0 ): + if ( hasattr(file, 'gs_filetypes') ): + if ( file.gs_filetypes.find('Curvilinear_Tile') < 0 ): file.gs_filetypes = file.gs_filetypes + ' Curvilinear_Tile' else: file.gs_filetypes = 'Curvilinear_Tile' - t=time.time() - id=int((t-int(t))*1.0e9) + t = time.time() + id = int((t-int(t))*1.0e9) file.gs_id = id file.gs_originalfilename = os.path.basename( file.id ) @@ -411,19 +412,19 @@ class AbstractCurveGrid(AbstractHorizontalGrid): getattr( file, 'history', '' ) + newhistory # former tile variable and attributes - if ( hasattr(self,'long_name') and self.long_name!=None ): + if ( hasattr(self, 'long_name') and self.long_name != None ): file.long_name = self.long_name else: file.long_name = 'gridspec_tile' # gs_geometryType is no longer required of Gridspec files, but as yet # there is no other proposal for describing the geometry (July 2010) - if ( hasattr(self,'gs_geometryType') and self.gs_geometryType!=None): + if ( hasattr(self, 'gs_geometryType') and self.gs_geometryType != None): file.gs_geometryType = self.gs_geometryType else: file.gs_geometryType = 'spherical' # gs_discretizationType is no longer required of Gridspec files, but it's # harmless and may come in useful - if ( hasattr(self,'gs_discretizationType') and self.gs_discretizationType!=None ): + if ( hasattr(self, 'gs_discretizationType') and self.gs_discretizationType != None ): file.gs_discretizationType = self.gs_discretizationType else: file.gs_discretizationType = 'logically_rectangular' @@ -434,11 +435,11 @@ class AbstractCurveGrid(AbstractHorizontalGrid): # Set up and write variables. When written, cdms writes not only the arrays # but also their coordinates, e.g. gs_nip. - x=self._lonaxis_ - if ( not hasattr(x,'units') ): + x = self._lonaxis_ + if ( not hasattr(x, 'units') ): print "Warning, no units found for longitude" x.units = 'degree_east' - if ( not hasattr(x,'standard_name') ): + if ( not hasattr(x, 'standard_name') ): print "Warning, no standard_name found for longitude axis" x.standard_name = 'longitude' if ( x.standard_name == 'geographic_longitude'): @@ -448,11 +449,11 @@ class AbstractCurveGrid(AbstractHorizontalGrid): # _lonaxis_ is a TransientAxis2D, hence a TransientVariable # But I don't know where the attribute _TransientVariable__domain comes from - y=self._lataxis_ - if ( not hasattr(y,'units') ): + y = self._lataxis_ + if ( not hasattr(y, 'units') ): print "Warning, no units found for latitude" y.units = 'degree_north' - if ( not hasattr(y,'standard_name') ): + if ( not hasattr(y, 'standard_name') ): print "Warning, no standard_name found for latitude axis" y.standard_name = 'latitude' if ( y.standard_name == 'geographic_latitude'): @@ -460,18 +461,18 @@ class AbstractCurveGrid(AbstractHorizontalGrid): y.standard_name = 'latitude' y.id = file.gs_latv - if( not hasattr(x,'_TransientVariable__domain') ): + if( not hasattr(x, '_TransientVariable__domain') ): # There probably doesn't exist enough information to write a correct # grid, but this will help. x._TransientVariable__domain = [ (x,), (y,) ] - x._TransientVariable__domain[0][0].id='gs_njp' - x._TransientVariable__domain[1][0].id='gs_nip' - if ( not hasattr(y,'_TransientVariable__domain') ) : + x._TransientVariable__domain[0][0].id = 'gs_njp' + x._TransientVariable__domain[1][0].id = 'gs_nip' + if ( not hasattr(y, '_TransientVariable__domain') ) : # There probably doesn't exist enough information to write a correct # grid, but this will help. y._TransientVariable__domain = [ (x,), (y,) ] - y._TransientVariable__domain[0][0].id='gs_njp' - y._TransientVariable__domain[1][0].id='gs_nip' + y._TransientVariable__domain[0][0].id = 'gs_njp' + y._TransientVariable__domain[1][0].id = 'gs_nip' file.write(x) file.write(y) @@ -486,12 +487,12 @@ class AbstractCurveGrid(AbstractHorizontalGrid): # The functionality (other than checking gsfile) is now done by the writeg # method above. if ( not hasattr( self, "gsfile" ) ): - self.gsfile=None - self.gspath=None - if ( self.gsfile!=None ): + self.gsfile = None + self.gspath = None + if ( self.gsfile != None ): return ( tcg.gsfile, tcg.gspath ) else: - raise RuntimeError, 'The libCF/Gridspec API does not provide for writing CurveGrids<<<' + raise RuntimeError('The libCF/Gridspec API does not provide for writing CurveGrids<<<') def init_from_gridspec( self, filename ): """reads to grid from a Gridspec-compliant file. The filename should be a @@ -575,8 +576,8 @@ class AbstractCurveGrid(AbstractHorizontalGrid): j = k k += 1 - if i==-1 or j==-1: - raise RuntimeError, 'Grid lat/lon domains do not match variable domain' + if i == -1 or j == -1: + raise RuntimeError('Grid lat/lon domains do not match variable domain') return ((islice, jslice), (inewaxis, jnewaxis)) @@ -584,14 +585,14 @@ class AbstractCurveGrid(AbstractHorizontalGrid): """Get the grid index""" if self._index_ is None: # Trying to stick in Stephane Raynaud's patch for autodetection - nj,ni = self._lataxis_.shape + nj, ni = self._lataxis_.shape dlon = numpy.max(self._lonaxis_)-numpy.min(self._lonaxis_) - dx = max(dlon/ni,dlon/nj) + dx = max(dlon/ni, dlon/nj) dlat = numpy.max(self._lataxis_)-numpy.min(self._lataxis_) - dy = max(dlat/ni,dlat/nj) + dy = max(dlat/ni, dlat/nj) latlin = numpy.ravel(numpy.ma.filled(self._lataxis_)) lonlin = numpy.ravel(numpy.ma.filled(self._lonaxis_)) - _bindex.setDeltas(dx,dy) + _bindex.setDeltas(dx, dy) self._index_ = bindex.bindexHorizontalGrid(latlin, lonlin) return self._index_ @@ -614,12 +615,12 @@ class AbstractCurveGrid(AbstractHorizontalGrid): latlin = numpy.ravel(numpy.ma.filled(self._lataxis_)) lonlin = numpy.ravel(numpy.ma.filled(self._lonaxis_)) points = bindex.intersectHorizontalGrid(latspec, lonspec, latlin, lonlin, index) - if len(points)==0: - raise CDMSError, 'No data in the specified region, longitude=%s, latitude=%s'%(`lonspec`, `latspec`) + if len(points) == 0: + raise CDMSError('No data in the specified region, longitude=%s, latitude=%s'%(repr(lonspec), repr(latspec))) fullmask = numpy.ones(ni*nj) numpy.put(fullmask, points, 0) - fullmask = numpy.reshape(fullmask, (ni,nj)) + fullmask = numpy.reshape(fullmask, (ni, nj)) iind = points/nj jind = points - iind*nj @@ -628,7 +629,7 @@ class AbstractCurveGrid(AbstractHorizontalGrid): yid = self.getAxis(0).id xid = self.getAxis(1).id - indexspecs = {yid:slice(imin,imax), xid:slice(jmin,jmax)} + indexspecs = {yid:slice(imin, imax), xid:slice(jmin, jmax)} return submask, indexspecs @@ -677,9 +678,9 @@ class AbstractCurveGrid(AbstractHorizontalGrid): used = [] # axes already matched for i in missing: for item in axes: - if (item not in used) and len(selfaxes[i])==len(item) and allclose(selfaxes[i], item): - result._lataxis_.setAxis(i,item) - result._lonaxis_.setAxis(i,item) + if (item not in used) and len(selfaxes[i]) == len(item) and allclose(selfaxes[i], item): + result._lataxis_.setAxis(i, item) + result._lonaxis_.setAxis(i, item) used.append(item) break else: @@ -693,18 +694,18 @@ class AbstractCurveGrid(AbstractHorizontalGrid): having the same length as the number of cells in the grid, similarly for flatlon.""" if self._flataxes_ is None: - import MV2 as MV + from . import MV2 as MV alat = MV.filled(self.getLatitude()) alon = MV.filled(self.getLongitude()) alatflat = numpy.ravel(alat) alonflat = numpy.ravel(alon) self._flataxes_ = (alatflat, alonflat) return self._flataxes_ - shape = property(_getShape,None) + shape = property(_getShape, None) -## PropertiedClasses.set_property (AbstractCurveGrid, 'shape', -## AbstractCurveGrid._getShape, nowrite=1, -## nodelete=1) +# PropertiedClasses.set_property (AbstractCurveGrid, 'shape', +# AbstractCurveGrid._getShape, nowrite=1, +# nodelete=1) class DatasetCurveGrid(AbstractCurveGrid): @@ -715,7 +716,7 @@ class DatasetCurveGrid(AbstractCurveGrid): self.parent = parent def __repr__(self): - return ""%(self.id, `self.shape`) + return ""%(self.id, repr(self.shape)) class FileCurveGrid(AbstractCurveGrid): @@ -726,7 +727,7 @@ class FileCurveGrid(AbstractCurveGrid): self.parent = parent def __repr__(self): - return ""%(self.id, `self.shape`) + return ""%(self.id, repr(self.shape)) class TransientCurveGrid(AbstractCurveGrid): @@ -741,7 +742,7 @@ class TransientCurveGrid(AbstractCurveGrid): AbstractCurveGrid.__init__(self, latAxis, lonAxis, id, maskvar, tempmask) def __repr__(self): - return ""%(self.id, `self.shape`) + return ""%(self.id, repr(self.shape)) def toCurveGrid(self, gridid=None): if gridid is None: @@ -758,17 +759,17 @@ def readScripCurveGrid(fileobj, dims, whichType, whichGrid): whichType is the type of file, either "grid" or "mapping" if whichType is "mapping", whichGrid is the choice of grid, either "source" or "destination" """ - from coord import TransientAxis2D + from .coord import TransientAxis2D if 'S' in fileobj.variables.keys(): - if whichType=="grid": + if whichType == "grid": gridCornerLatName = 'grid_corner_lat' gridCornerLonName = 'grid_corner_lon' gridMaskName = 'grid_imask' gridCenterLatName = 'grid_center_lat' gridCenterLonName = 'grid_center_lon' titleName = 'title' - elif whichGrid=="destination": + elif whichGrid == "destination": gridCornerLatName = 'yv_b' gridCornerLonName = 'xv_b' gridMaskName = 'mask_b' @@ -783,14 +784,14 @@ def readScripCurveGrid(fileobj, dims, whichType, whichGrid): gridCenterLonName = 'xc_a' titleName = 'source_grid' else: - if whichType=="grid": + if whichType == "grid": gridCornerLatName = 'grid_corner_lat' gridCornerLonName = 'grid_corner_lon' gridMaskName = 'grid_imask' gridCenterLatName = 'grid_center_lat' gridCenterLonName = 'grid_center_lon' titleName = 'title' - elif whichGrid=="destination": + elif whichGrid == "destination": gridCornerLatName = 'dst_grid_corner_lat' gridCornerLonName = 'dst_grid_corner_lon' gridMaskName = 'dst_grid_imask' @@ -813,17 +814,17 @@ def readScripCurveGrid(fileobj, dims, whichType, whichGrid): nj = dims[0] gridshape = (ni, nj) boundsshape = (ni, nj, ncorners) - if hasattr(cornerLat, 'units') and cornerLat.units.lower()[0:6]=='radian': + if hasattr(cornerLat, 'units') and cornerLat.units.lower()[0:6] == 'radian': cornerLat = (cornerLat*(180.0/numpy.pi)).reshape(boundsshape) cornerLon = (cornerLon*(180.0/numpy.pi)).reshape(boundsshape) else: cornerLat = cornerLat.reshape(boundsshape) cornerLon = cornerLon.reshape(boundsshape) - iaxis = TransientVirtualAxis("i",ni) - jaxis = TransientVirtualAxis("j",nj) + iaxis = TransientVirtualAxis("i", ni) + jaxis = TransientVirtualAxis("j", nj) - if vardict.has_key(gridMaskName): + if gridMaskName in vardict: # SCRIP convention: 0 for invalid data # numpy.ma convention: 1 for invalid data mask = 1 - fileobj(gridMaskName) @@ -831,27 +832,27 @@ def readScripCurveGrid(fileobj, dims, whichType, whichGrid): else: mask = None - if vardict.has_key(gridCenterLatName): + if gridCenterLatName in vardict: centerLat = fileobj(gridCenterLatName).reshape(gridshape) gclat = fileobj[gridCenterLatName] - if hasattr(gclat, "units") and gclat.units.lower()=='radians': + if hasattr(gclat, "units") and gclat.units.lower() == 'radians': centerLat *= (180.0/numpy.pi) else: - centerLat = cornerLat[:,:,0] + centerLat = cornerLat[:,:, 0] - if vardict.has_key(gridCenterLonName): + if gridCenterLonName in vardict: centerLon = fileobj(gridCenterLonName).reshape(gridshape) gclon = fileobj[gridCenterLonName] - if hasattr(gclon, "units") and gclon.units.lower()=='radians': + if hasattr(gclon, "units") and gclon.units.lower() == 'radians': centerLon *= (180.0/numpy.pi) else: - centerLon = cornerLon[:,:,0] + centerLon = cornerLon[:,:, 0] - if hasattr(fileobj,titleName): + if hasattr(fileobj, titleName): gridid = getattr(fileobj, titleName) - gridid = gridid.strip().replace(' ','_') + gridid = gridid.strip().replace(' ', '_') else: - gridid="" + gridid = "" lataxis = TransientAxis2D(centerLat, axes=(iaxis, jaxis), bounds=cornerLat, attributes={'units':'degrees_north'}, id="latitude") diff --git a/Packages/cdms2/Lib/mvBaseWriter.py b/Packages/cdms2/Lib/mvBaseWriter.py index 5f099c704..db80b843e 100644 --- a/Packages/cdms2/Lib/mvBaseWriter.py +++ b/Packages/cdms2/Lib/mvBaseWriter.py @@ -3,13 +3,14 @@ """ Abstract class for writing data into file -This code is provided with the hope that it will be useful. +This code is provided with the hope that it will be useful. No guarantee is provided whatsoever. Use at your own risk. Alex Pletzer, Tech-X Corp. (2011) """ -import mvSphereMesh +from . import mvSphereMesh + class BaseWriter: @@ -17,7 +18,7 @@ class BaseWriter: """ Constructor @param var a cdms2 variable - @param sphereRadius radius of the sphere upon which the grid will + @param sphereRadius radius of the sphere upon which the grid will be projected @param maxElev max elevation/depth normalized to the sphere radius """ @@ -26,12 +27,12 @@ class BaseWriter: self.shape = sphere_mesh.shape - # there is currently a bug in vizSchema which causes - # visit to crash if the leading index is 1, this is + # there is currently a bug in vizSchema which causes + # visit to crash if the leading index is 1, this is # a workaround the problem if self.shape[0] == 1: - self.shape = list(sphere_mesh.shape[1:]) + [1,] - + self.shape = list(sphere_mesh.shape[1:]) + [1, ] + self.mesh = sphere_mesh.getXYZCoords(sphereRadius) def write(self, filename): @@ -39,5 +40,5 @@ class BaseWriter: Write data to file. This method is overloaded. @param filename file name """ - raise NotImplementedError, \ - 'write method not implemented in derived class' + raise NotImplementedError( + 'write method not implemented in derived class') diff --git a/Packages/cdms2/Lib/mvCdmsRegrid.py b/Packages/cdms2/Lib/mvCdmsRegrid.py index 5a1f34361..24c169acf 100644 --- a/Packages/cdms2/Lib/mvCdmsRegrid.py +++ b/Packages/cdms2/Lib/mvCdmsRegrid.py @@ -9,8 +9,9 @@ import operator import re import numpy import cdms2 -from error import CDMSError +from .error import CDMSError import regrid2 +from functools import reduce def _areCellsOk(cornerCoords, mask=None): """ @@ -43,8 +44,8 @@ def _areCellsOk(cornerCoords, mask=None): # compute area elements in Cartesian space lat0 = numpy.array(cornerCoords[0][ :-1, :-1], numpy.float64) lat1 = numpy.array(cornerCoords[0][ :-1, 1: ], numpy.float64) - lat2 = numpy.array(cornerCoords[0][1: , 1: ], numpy.float64) - lat3 = numpy.array(cornerCoords[0][1: , :-1], numpy.float64) + lat2 = numpy.array(cornerCoords[0][1:, 1: ], numpy.float64) + lat3 = numpy.array(cornerCoords[0][1:, :-1], numpy.float64) the0 = lat0*numpy.pi/180. the1 = lat1*numpy.pi/180. @@ -52,8 +53,8 @@ def _areCellsOk(cornerCoords, mask=None): the3 = lat3*numpy.pi/180. lam0 = numpy.array(cornerCoords[1][ :-1, :-1], numpy.float64)*numpy.pi/180. lam1 = numpy.array(cornerCoords[1][ :-1, 1: ], numpy.float64)*numpy.pi/180. - lam2 = numpy.array(cornerCoords[1][1: , 1: ], numpy.float64)*numpy.pi/180. - lam3 = numpy.array(cornerCoords[1][1: , :-1], numpy.float64)*numpy.pi/180. + lam2 = numpy.array(cornerCoords[1][1:, 1: ], numpy.float64)*numpy.pi/180. + lam3 = numpy.array(cornerCoords[1][1:, :-1], numpy.float64)*numpy.pi/180. x0, y0, z0 = projectToSphere(the0, lam0) x1, y1, z1 = projectToSphere(the1, lam1) @@ -128,7 +129,7 @@ def _areCellsOk(cornerCoords, mask=None): if len(inds[0]) > 0: # package the result badCellIndices = [(inds[0][i], inds[1][i]) for i in range(len(inds[0]))] - bcis1 = [(inds[0][i] , inds[1][i]+1) for i in range(len(inds[0]))] + bcis1 = [(inds[0][i], inds[1][i]+1) for i in range(len(inds[0]))] bcis2 = [(inds[0][i]+1, inds[1][i]+1) for i in range(len(inds[0]))] bcis3 = [(inds[0][i]+1, inds[1][i] ) for i in range(len(inds[0]))] badCellCoords = [[(cornerCoords[0][badCellIndices[i]], cornerCoords[1][badCellIndices[i]]), @@ -159,10 +160,10 @@ def _buildBounds(bounds): bnd[:-1] = bounds[..., 0] bnd[ -1] = bounds[ -1, 1] elif len(bndShape) > 1: - bnd[:-1, :-1] = bounds[ :, :, 0] - bnd[:-1, -1] = bounds[ :, -1, 1] + bnd[:-1, :-1] = bounds[:,:, 0] + bnd[:-1, -1] = bounds[:, -1, 1] bnd[ -1, -1] = bounds[ -1, -1, 2] - bnd[ -1, :-1] = bounds[ -1, :, 3] + bnd[ -1, :-1] = bounds[ -1,:, 3] return bnd @@ -381,8 +382,9 @@ coordMin = %7.2f, boundMin = %7.2f, coordMax = %7.2f, boundMax = %7.2f # If LibCF handleCut is True, the bounds are needed to extend the grid # close the cut at the top - if re.search('LibCF', regridTool, re.I) and args.has_key('handleCut'): - if args['handleCut']: srcBounds = getBoundList(srcCoords) + if re.search('LibCF', regridTool, re.I) and 'handleCut' in args: + if args['handleCut']: + srcBounds = getBoundList(srcCoords) srcCoordsArrays = [numpy.array(sc) for sc in srcCoords] dstCoordsArrays = [numpy.array(dc) for dc in dstCoords] @@ -439,7 +441,7 @@ coordMin = %7.2f, boundMin = %7.2f, coordMax = %7.2f, boundMax = %7.2f **args) # fill in diagnostic data - if args.has_key('diag'): + if 'diag' in args: self.regridObj.fillInDiagnosticData(diag = args['diag'], rootPe = 0) # construct the axis list for dstVar diff --git a/Packages/cdms2/Lib/mvSphereMesh.py b/Packages/cdms2/Lib/mvSphereMesh.py index 7b95922e2..1a5469c9c 100644 --- a/Packages/cdms2/Lib/mvSphereMesh.py +++ b/Packages/cdms2/Lib/mvSphereMesh.py @@ -3,22 +3,24 @@ """ Class for representing grids on the sphere Alex Pletzer, Tech-X Corp. (2011) -This code is provided with the hope that it will be useful. +This code is provided with the hope that it will be useful. No guarantee is provided whatsoever. Use at your own risk. """ import numpy +from functools import reduce + class SphereMesh: - + def __init__(self, var, sphereThickness=0.1): """ Constructor @param var cdms2 variable - @param sphereThickness thickness of the shell in normalized + @param sphereThickness thickness of the shell in normalized sphere radius """ - + self.isRectilinear = True self.ndims = 0 self.elvPositiveDown = False @@ -40,7 +42,7 @@ class SphereMesh: if getattr(elvs, 'positive') == 'down': self.elvPositiveDown = True - # determine the dimensionality and + # determine the dimensionality and # whether the grid is rectilinear for axis in lons, lats, elvs: if axis is not None: @@ -53,25 +55,31 @@ class SphereMesh: self.shape = [] for axis in lons, lats, elvs: if axis is not None: - self.shape.append( len(axis) ) + self.shape.append(len(axis)) self.shape.reverse() while len(self.shape) < 3: - self.shape = [1,] + list(self.shape) + self.shape = [1, ] + list(self.shape) # store lon, lat, elv as a curvilinear grid if self.isRectilinear: # apply tensore product of axes to generat curvilinear coordinates if elvs is not None: - self.elvs = numpy.outer(numpy.outer( numpy.ones(self.shape[:0], numpy.float32), elvs), - numpy.ones(self.shape[0+1:], numpy.float32)).reshape(self.shape) + self.elvs = numpy.outer( + numpy.outer( + numpy.ones(self.shape[:0], + numpy.float32), + elvs), + numpy.ones(self.shape[0 + 1:], numpy.float32)).reshape(self.shape) else: - self.elvs = numpy.zeros( self.shape, numpy.float32 ) - self.lats = numpy.outer(numpy.outer( numpy.ones(self.shape[:1], numpy.float32), lats), - numpy.ones(self.shape[1+1:], numpy.float32)).reshape(self.shape) - self.lons = numpy.outer(numpy.outer( numpy.ones(self.shape[:2], numpy.float32), lons), - numpy.ones(self.shape[2+1:], numpy.float32)).reshape(self.shape) - + self.elvs = numpy.zeros(self.shape, numpy.float32) + self.lats = numpy.outer( + numpy.outer(numpy.ones(self.shape[:1], numpy.float32), lats), + numpy.ones(self.shape[1 + 1:], numpy.float32)).reshape(self.shape) + self.lons = numpy.outer( + numpy.outer(numpy.ones(self.shape[:2], numpy.float32), lons), + numpy.ones(self.shape[2 + 1:], numpy.float32)).reshape(self.shape) + else: # already in curvilinear form self.lons = lons[:] @@ -79,10 +87,10 @@ class SphereMesh: if elvs is not None: self.elvs = elvs[:] else: - self.elvs = numpy.zeros( self.shape, numpy.float32 ) + self.elvs = numpy.zeros(self.shape, numpy.float32) # reshape as flat arrays - sz = reduce(lambda x, y: x*y, self.shape) + sz = reduce(lambda x, y: x * y, self.shape) self.lons = numpy.reshape(self.lons, (sz,)) self.lats = numpy.reshape(self.lats, (sz,)) self.elvs = numpy.reshape(self.elvs, (sz,)) @@ -90,32 +98,33 @@ class SphereMesh: def getXYZCoords(self, sphereRadius=1.0): """ Get the curvilinear cartesian coordinates - @param sphereRadius radius of sphere + @param sphereRadius radius of sphere @return mesh """ - sz = reduce(lambda x, y: x*y, self.shape) - rr = sphereRadius*(1.0 + self.elvs) + sz = reduce(lambda x, y: x * y, self.shape) + rr = sphereRadius * (1.0 + self.elvs) diffElv = self.maxElv - self.minElv - rr = sphereRadius*numpy.ones(self.lons.shape, numpy.float32 ) + rr = sphereRadius * numpy.ones(self.lons.shape, numpy.float32) if diffElv != 0: - coeff = sphereRadius*self.sphereThickness/diffElv + coeff = sphereRadius * self.sphereThickness / diffElv if self.elvPositiveDown: # depth - rr += coeff*(self.maxElv - self.elvs) + rr += coeff * (self.maxElv - self.elvs) else: # height - rr += coeff*(self.elvs - self.minElv) + rr += coeff * (self.elvs - self.minElv) - mesh = numpy.zeros( (sz, 3), numpy.float32 ) - cosLats = numpy.cos( self.lats*numpy.pi/180. ) - mesh[:, 0] = rr*numpy.cos(self.lons*numpy.pi/180.)*cosLats - mesh[:, 1] = rr*numpy.sin(self.lons*numpy.pi/180.)*cosLats - mesh[:, 2] = rr*numpy.sin(self.lats*numpy.pi/180.) + mesh = numpy.zeros((sz, 3), numpy.float32) + cosLats = numpy.cos(self.lats * numpy.pi / 180.) + mesh[:, 0] = rr * numpy.cos(self.lons * numpy.pi / 180.) * cosLats + mesh[:, 1] = rr * numpy.sin(self.lons * numpy.pi / 180.) * cosLats + mesh[:, 2] = rr * numpy.sin(self.lats * numpy.pi / 180.) return mesh -##################################################################### +# # Tests + def test2DRect(): """ Test data on 2D rectilinear grid @@ -123,17 +132,18 @@ def test2DRect(): import cdms2 from numpy import pi, cos, sin nlat, nlon = 12, 15 - grid = cdms2.createUniformGrid(-0.0, nlat, 60./(nlat-1), - 0., nlon, 30./nlon) + grid = cdms2.createUniformGrid(-0.0, nlat, 60. / (nlat - 1), + 0., nlon, 30. / nlon) lons = grid.getLongitude() lats = grid.getLatitude() - data = numpy.outer(cos(3*pi*lats[:]/180.0), - sin(5*pi*lons[:]/180.0)) - var = cdms2.createVariable(data, id='fake_data_2d_rect', + data = numpy.outer(cos(3 * pi * lats[:] / 180.0), + sin(5 * pi * lons[:] / 180.0)) + var = cdms2.createVariable(data, id='fake_data_2d_rect', axes=(lats, lons)) sphere_mesh = SphereMesh(var, 0.1) print sphere_mesh.getXYZCoords() + def test2D(): """ Test data on 2D curvilinear grid @@ -143,33 +153,34 @@ def test2D(): from cdms2.hgrid import TransientCurveGrid from numpy import pi, cos, sin nlat, nlon = 3, 4 - dlon, dlat = 60.0/float(nlon - 1), 30.0/float(nlat - 1) - lons1D = numpy.array([0.0 + i*dlon for i in range(nlon)]) - lats1D = numpy.array([0.0 + j*dlat for j in range(nlat)]) + dlon, dlat = 60.0 / float(nlon - 1), 30.0 / float(nlat - 1) + lons1D = numpy.array([0.0 + i * dlon for i in range(nlon)]) + lats1D = numpy.array([0.0 + j * dlat for j in range(nlat)]) lons = numpy.outer(numpy.ones((nlat,)), lons1D) lats = numpy.outer(lats1D, numpy.ones((nlon,))) - data = cos(3*pi*lats/180.0) * sin(5*pi*lons/180.0) + data = cos(3 * pi * lats / 180.0) * sin(5 * pi * lons / 180.0) # create grid iaxis = TransientVirtualAxis("i", nlon) jaxis = TransientVirtualAxis("j", nlat) - lataxis = TransientAxis2D(lats, - axes=(jaxis, iaxis), - attributes={'units': 'degree_north'}, - id='lats') - lonaxis = TransientAxis2D(lons, - axes=(jaxis, iaxis), - attributes={'units': 'degree_east'}, - id='lons') - grid = TransientCurveGrid(lataxis, lonaxis, id='lats_lons') - - var = cdms2.createVariable(data, id='fake_data_2d', - axes = grid.getAxisList(), - grid = grid, - attributes = {'coordinates': 'lats lons'}, + lataxis = TransientAxis2D(lats, + axes=(jaxis, iaxis), + attributes={'units': 'degree_north'}, + id='lats') + lonaxis = TransientAxis2D(lons, + axes=(jaxis, iaxis), + attributes={'units': 'degree_east'}, + id='lons') + grid = TransientCurveGrid(lataxis, lonaxis, id='lats_lons') + + var = cdms2.createVariable(data, id='fake_data_2d', + axes=grid.getAxisList(), + grid=grid, + attributes={'coordinates': 'lats lons'}, ) sphere_mesh = SphereMesh(var) print sphere_mesh.getXYZCoords() + def test3DRect(): """ Test data on 3d rectilinear grid @@ -177,29 +188,30 @@ def test3DRect(): import cdms2 from numpy import pi, cos, sin, exp nelv, nlat, nlon = 3, 4, 5 - delv, dlon, dlat = 90000./float(nelv-1), \ - 60.0/float(nlon-1), 30.0/float(nlat-1) - elvs1D = numpy.array([100000 - i*delv for i in range(nelv)]) - lons1D = numpy.array([0.0 + i*dlon for i in range(nlon)]) - lats1D = numpy.array([0.0 + i*dlat for i in range(nlat)]) + delv, dlon, dlat = 90000. / float(nelv - 1), \ + 60.0 / float(nlon - 1), 30.0 / float(nlat - 1) + elvs1D = numpy.array([100000 - i * delv for i in range(nelv)]) + lons1D = numpy.array([0.0 + i * dlon for i in range(nlon)]) + lats1D = numpy.array([0.0 + i * dlat for i in range(nlat)]) # any order should work - lons = numpy.zeros( (nlon, nlat, nelv), numpy.float32 ) - lats = numpy.zeros( (nlon, nlat, nelv), numpy.float32 ) - elvs = numpy.zeros( (nlon, nlat, nelv), numpy.float32 ) - data = numpy.zeros( (nlon, nlat, nelv), numpy.float32 ) + lons = numpy.zeros((nlon, nlat, nelv), numpy.float32) + lats = numpy.zeros((nlon, nlat, nelv), numpy.float32) + elvs = numpy.zeros((nlon, nlat, nelv), numpy.float32) + data = numpy.zeros((nlon, nlat, nelv), numpy.float32) for i in range(nlon): for j in range(nlat): for k in range(nelv): elvs[i, j, k] = elvs1D[k] lats[i, j, k] = lats1D[j] lons[i, j, k] = lons1D[i] - data[i, j, k] = cos(3*pi*lats[i, j, k]/180.) * \ - sin(5*pi*lons[i, j, k]/180.) * exp(-elvs[i, j, k]) - var = cdms2.createVariable(data, id='fake_data_3d_rect', + data[i, j, k] = cos(3 * pi * lats[i, j, k] / 180.) * \ + sin(5 * pi * lons[i, j, k] / 180.) * exp(-elvs[i, j, k]) + var = cdms2.createVariable(data, id='fake_data_3d_rect', axes=(elvs, lats, lons)) sphere_mesh = SphereMesh(var) print sphereMesh.getXYZCoords() + def test3DposDown(): """ Test 3d data with elev positive down. Need to work with 1D axes. @@ -208,31 +220,33 @@ def test3DposDown(): import cdms2 import numpy nlev, nlat, nlon = 4, 5, 6 - dlev, dlat, dlon = 5000./float(nlev-1), 180./float(nlat-1), 360./float(nlon-1) + dlev, dlat, dlon = 5000. / \ + float(nlev - 1), 180. / float(nlat - 1), 360. / float(nlon - 1) levs1d = numpy.arange(0., 5001., dlev) - lats1d = numpy.array([0. - i*dlat for i in range(nlat)]) - lons1d = numpy.array([0. - i*dlon for i in range(nlon)]) + lats1d = numpy.array([0. - i * dlat for i in range(nlat)]) + lons1d = numpy.array([0. - i * dlon for i in range(nlon)]) data = numpy.zeros((nlev, nlat, nlon), numpy.float32) for k in range(nlev): for j in range(nlat): for i in range(nlon): - data[k, j, i] = numpy.cos(3*numpy.pi*lats1d[j]/180.) * \ - numpy.sin(5*numpy.pi*lons1d[i]/180.) * \ + data[k, j, i] = numpy.cos(3 * numpy.pi * lats1d[j] / 180.) * \ + numpy.sin(5 * numpy.pi * lons1d[i] / 180.) * \ numpy.exp(-levs1d[k]) - a1 = cdms2.axis.TransientAxis(levs1d, id = 'levels', - attributes = {'positive':'down'}) - a2 = cdms2.axis.TransientAxis(lats1d, id = 'latitude') - a3 = cdms2.axis.TransientAxis(lons1d, id = 'longitude') - var = cdms2.createVariable(data, id = 'pos_down_3d_data', - axes = (a1, a2, a3)) + a1 = cdms2.axis.TransientAxis(levs1d, id='levels', + attributes={'positive': 'down'}) + a2 = cdms2.axis.TransientAxis(lats1d, id='latitude') + a3 = cdms2.axis.TransientAxis(lons1d, id='longitude') + var = cdms2.createVariable(data, id='pos_down_3d_data', + axes=(a1, a2, a3)) sphereMesh = SphereMesh(var) aa = sphereMesh.getXYZCoords() bb = aa.reshape((4, 5, 6, 3)) - for i in range(nlev): print levs1d[i], bb[i, 0, 0, :] + for i in range(nlev): + print levs1d[i], bb[i, 0, 0, :] -if __name__ == '__main__': +if __name__ == '__main__': # test2DRect() # test2D() # test3DRect() diff --git a/Packages/cdms2/Lib/mvVTKSGWriter.py b/Packages/cdms2/Lib/mvVTKSGWriter.py index 353d8b19b..fd2327245 100644 --- a/Packages/cdms2/Lib/mvVTKSGWriter.py +++ b/Packages/cdms2/Lib/mvVTKSGWriter.py @@ -3,13 +3,14 @@ """ Write data to VTK file format using the structured grid format Alex Pletzer, Tech-X Corp. (2011) -This code is provided with the hope that it will be useful. +This code is provided with the hope that it will be useful. No guarantee is provided whatsoever. Use at your own risk. """ import numpy import time -import mvBaseWriter +from . import mvBaseWriter + class VTKSGWriter(mvBaseWriter.BaseWriter): @@ -29,10 +30,10 @@ class VTKSGWriter(mvBaseWriter.BaseWriter): npts = self.mesh.shape[0] print >> f, 'POINTS %d float' % npts for i in range(npts): - print >> f, '%f %f %f' % tuple(self.mesh[i,:]) + print >> f, '%f %f %f' % tuple(self.mesh[i, :]) n0, n1, n2 = self.shape # nodal data - print >> f, 'POINT_DATA %d' % (n0*n1*n2) + print >> f, 'POINT_DATA %d' % (n0 * n1 * n2) print >> f, 'SCALARS %s float' % (self.var.id) print >> f, 'LOOKUP_TABLE default' if n0 > 1: @@ -43,34 +44,34 @@ class VTKSGWriter(mvBaseWriter.BaseWriter): else: for j in range(n1): for i in range(n2): - print >> f, '%f' % self.var[j, i] + print >> f, '%f' % self.var[j, i] f.close() -###################################################################### +# def test2DRect(): import cdms2 from numpy import pi, cos, sin nlat, nlon = 6, 10 - grid = cdms2.createUniformGrid(-0.0, nlat, 60./(nlat-1), - 0., nlon, 30./nlon) + grid = cdms2.createUniformGrid(-0.0, nlat, 60. / (nlat - 1), + 0., nlon, 30. / nlon) lons = grid.getLongitude() lats = grid.getLatitude() - data = numpy.outer(cos(3*pi*lats[:]/180.0), - sin(5*pi*lons[:]/180.0)) - var = cdms2.createVariable(data, id='fake_data_2d_rect', + data = numpy.outer(cos(3 * pi * lats[:] / 180.0), + sin(5 * pi * lons[:] / 180.0)) + var = cdms2.createVariable(data, id='fake_data_2d_rect', axes=(lats, lons)) vw = VTKSGWriter(var) vw.write('test2DRect_SG.vtk') + def test3D(): import cdms2 var = cdms2.open('sample_data/ta_ncep_87-6-88-4.nc', 'r')('ta') - vw = VTKSGWriter(var[0,0:10,0:20,0:30]) + vw = VTKSGWriter(var[0, 0:10, 0:20, 0:30]) vw.write('test3D_SG.vtk') -if __name__ == '__main__': +if __name__ == '__main__': test2DRect() test3D() - diff --git a/Packages/cdms2/Lib/mvVTKUGWriter.py b/Packages/cdms2/Lib/mvVTKUGWriter.py index 50dcb1195..e712efaf7 100644 --- a/Packages/cdms2/Lib/mvVTKUGWriter.py +++ b/Packages/cdms2/Lib/mvVTKUGWriter.py @@ -3,13 +3,14 @@ """ Write data to VTK file format using the unstructured grid format Alex Pletzer, Tech-X Corp. (2011) -This code is provided with the hope that it will be useful. +This code is provided with the hope that it will be useful. No guarantee is provided whatsoever. Use at your own risk. """ import numpy import time -import mvBaseWriter +from . import mvBaseWriter + class VTKUGWriter(mvBaseWriter.BaseWriter): @@ -26,9 +27,9 @@ class VTKUGWriter(mvBaseWriter.BaseWriter): npts = self.mesh.shape[0] print >> f, 'POINTS %d float' % npts for i in range(npts): - print >> f, '%f %f %f' % tuple(self.mesh[i,:]) + print >> f, '%f %f %f' % tuple(self.mesh[i, :]) n0, n1, n2 = self.shape - ncells = (n0 - 1)*(n1 - 1)*(n2 - 1) + ncells = (n0 - 1) * (n1 - 1) * (n2 - 1) if ncells != 0: # 3d ntot = ncells * (8 + 1) @@ -36,17 +37,17 @@ class VTKUGWriter(mvBaseWriter.BaseWriter): for k in range(n0 - 1): for j in range(n1 - 1): for i in range(n2 - 1): - index = i + n2*(j + n1*k) + index = i + n2 * (j + n1 * k) print >> f, '8 %d %d %d %d %d %d %d %d' % \ - (index, index+1, index+1+n2, index+n2, - index+n1*n2, index+n1*n2+1, - index+n1*n2+1+n2, index+n1*n2+n2) + (index, index + 1, index + 1 + n2, index + n2, + index + n1 * n2, index + n1 * n2 + 1, + index + n1 * n2 + 1 + n2, index + n1 * n2 + n2) print >> f, 'CELL_TYPES %d' % ncells for i in range(ncells): # hexahedron print >> f, 12 # nodal data - print >> f, 'POINT_DATA %d' % (n0*n1*n2) + print >> f, 'POINT_DATA %d' % (n0 * n1 * n2) print >> f, 'SCALARS %s float' % (self.var.id) print >> f, 'LOOKUP_TABLE default' for k in range(n0): @@ -55,52 +56,52 @@ class VTKUGWriter(mvBaseWriter.BaseWriter): print >> f, '%f' % self.var[k, j, i] else: # 2d - ncells = (n1 - 1)*(n2 - 1) + ncells = (n1 - 1) * (n2 - 1) ntot = ncells * (4 + 1) print >> f, 'CELLS %d %d' % (ncells, ntot) for j in range(n1 - 1): for i in range(n2 - 1): - index = i + n2*j + index = i + n2 * j print >> f, '4 %d %d %d %d' % \ - (index, index+1, index+1+n2, index+n2) + (index, index + 1, index + 1 + n2, index + n2) print >> f, 'CELL_TYPES %d' % ncells for i in range(ncells): # quad print >> f, 9 # nodal data - print >> f, 'POINT_DATA %d' % (n0*n1*n2) + print >> f, 'POINT_DATA %d' % (n0 * n1 * n2) print >> f, 'SCALARS %s float' % (self.var.id) print >> f, 'LOOKUP_TABLE default' for j in range(n1): for i in range(n2): - print >> f, '%f' % self.var[j, i] + print >> f, '%f' % self.var[j, i] f.close() -###################################################################### +# def test2DRect(): import cdms2 from numpy import pi, cos, sin nlat, nlon = 6, 10 - grid = cdms2.createUniformGrid(-0.0, nlat, 60./(nlat-1), - 0., nlon, 30./nlon) + grid = cdms2.createUniformGrid(-0.0, nlat, 60. / (nlat - 1), + 0., nlon, 30. / nlon) lons = grid.getLongitude() lats = grid.getLatitude() - data = numpy.outer(cos(3*pi*lats[:]/180.0), - sin(5*pi*lons[:]/180.0)) - var = cdms2.createVariable(data, id='fake_data_2d_rect', + data = numpy.outer(cos(3 * pi * lats[:] / 180.0), + sin(5 * pi * lons[:] / 180.0)) + var = cdms2.createVariable(data, id='fake_data_2d_rect', axes=(lats, lons)) vw = VTKUGWriter(var) vw.write('test2DRect.vtk') + def test3D(): import cdms2 var = cdms2.open('sample_data/ta_ncep_87-6-88-4.nc', 'r')('ta') - vw = VTKUGWriter(var[0,0:10,0:20,0:30]) + vw = VTKUGWriter(var[0, 0:10, 0:20, 0:30]) vw.write('test3D.vtk') -if __name__ == '__main__': +if __name__ == '__main__': test2DRect() test3D() - diff --git a/Packages/cdms2/Lib/mvVsWriter.py b/Packages/cdms2/Lib/mvVsWriter.py index aed81a79f..72bb31526 100644 --- a/Packages/cdms2/Lib/mvVsWriter.py +++ b/Packages/cdms2/Lib/mvVsWriter.py @@ -3,14 +3,15 @@ """ Write data to VizSchema compliant file Alex Pletzer, Tech-X Corp. (2011) -This code is provided with the hope that it will be useful. +This code is provided with the hope that it will be useful. No guarantee is provided whatsoever. Use at your own risk. """ import numpy -import mvBaseWriter +from . import mvBaseWriter import re + class VsWriter(mvBaseWriter.BaseWriter): def write(self, filename): @@ -21,58 +22,59 @@ class VsWriter(mvBaseWriter.BaseWriter): try: import tables except: - raise ImportError, 'You must have pytables installed' - + raise ImportError('You must have pytables installed') + if filename.find('.vsh5') < 0 and filename.find('.h5') < 0: - filename += '.vsh5' # VizSchema hdf5 format + filename += '.vsh5' # VizSchema hdf5 format # open file h5file = tables.openFile(filename, 'w') # put mesh meshid = 'mesh_' + self.var.id - mdata = numpy.reshape(self.mesh, self.shape + [3,]) + mdata = numpy.reshape(self.mesh, self.shape + [3, ]) mset = h5file.createArray("/", meshid, mdata) mset.attrs.vsType = "mesh" mset.attrs.vsKind = "structured" mset.attrs.vsIndexOrder = "compMinorC" # data - dset = h5file.createArray("/", self.var.id, + dset = h5file.createArray("/", self.var.id, numpy.reshape(self.var, self.shape)) dset.attrs.vsType = "variable" dset.attrs.vsMesh = meshid # additional attributes for a in self.var.attributes: # Skip mpi objects - if re.match('mpi',a.lower()): + if re.match('mpi', a.lower()): continue setattr(dset.attrs, a, getattr(self.var, a)) # close file h5file.close() -###################################################################### +# + def test2DRect(): import cdms2 from numpy import pi, cos, sin nlat, nlon = 3, 4 - grid = cdms2.createUniformGrid(-0.0, nlat, 60./(nlat-1), - 0., nlon, 30./nlon) + grid = cdms2.createUniformGrid(-0.0, nlat, 60. / (nlat - 1), + 0., nlon, 30. / nlon) lons = grid.getLongitude() lats = grid.getLatitude() - data = numpy.outer(cos(3*pi*lats[:]/180.0), - sin(5*pi*lons[:]/180.0)) - var = cdms2.createVariable(data, id='fake_data_2d_rect', + data = numpy.outer(cos(3 * pi * lats[:] / 180.0), + sin(5 * pi * lons[:] / 180.0)) + var = cdms2.createVariable(data, id='fake_data_2d_rect', axes=(lats, lons)) vw = VsWriter(var) vw.write('test2DRect.vsh5') + def test3D(): import cdms2 var = cdms2.open('sample_data/ta_ncep_87-6-88-4.nc', 'r')('ta') - vw = VsWriter(var[0,0:10,0:20,0:30]) + vw = VsWriter(var[0, 0:10, 0:20, 0:30]) vw.write('test3D.vsh5') -if __name__ == '__main__': +if __name__ == '__main__': test2DRect() test3D() - diff --git a/Packages/cdms2/Lib/restApi.py b/Packages/cdms2/Lib/restApi.py index 2b5ef1059..0ee17424d 100644 --- a/Packages/cdms2/Lib/restApi.py +++ b/Packages/cdms2/Lib/restApi.py @@ -6,116 +6,136 @@ try: except: pass import os -#import bz2 +# import bz2 + class esgfConnectionException(Exception): pass + + class esgfDatasetException(Exception): pass + + class esgfFilesException(Exception): pass - ## def __init__(self,value): - ## self.value=value - ## def __repr__(self): - ## msg = "rest API error: %s" % repr(value) - ## print msg - ## return msg + # def __init__(self,value): + # self.value=value + # def __repr__(self): + # msg = "rest API error: %s" % repr(value) + # print msg + # return msg + class FacetConnection(object): - def __init__(self,host='pcmdi9.llnl.gov'): - self.rqst="http://%s/esg-search/search?facets=*&type=Dataset&limit=1&latest=true" % host - self.rqst_count="http://%s/esg-search/search?facets=*&type=File&limit=0&latest=true" % host + + def __init__(self, host='pcmdi9.llnl.gov'): + self.rqst = "http://%s/esg-search/search?facets=*&type=Dataset&limit=1&latest=true" % host + self.rqst_count = "http://%s/esg-search/search?facets=*&type=File&limit=0&latest=true" % host self.EsgfObjectException = esgfConnectionException - def get_xmlelement(self,facet_param=None): + + def get_xmlelement(self, facet_param=None): try: - rqst=self.rqst + rqst = self.rqst if facet_param: - rqst=rqst+'&%s'%facet_param - #print rqst + rqst = rqst + '&%s' % facet_param + # print rqst url = urllib2.urlopen(rqst) - except Exception,msg: - raise self.EsgfObjectException(msg) + except Exception as msg: + raise self.EsgfObjectException(msg) r = url.read() try: e = xml.etree.ElementTree.fromstring(r) return e - except Exception,err: - raise self.EsgfObjectException("Could not interpret server's results: %s" % err) - def make_facet_dict(self,xmlelement): - facet_dict={} + except Exception as err: + raise self.EsgfObjectException( + "Could not interpret server's results: %s" % + err) + + def make_facet_dict(self, xmlelement): + facet_dict = {} for lst in xmlelement.findall('lst'): - if lst.get('name')=='facet_counts': - myelement=lst + if lst.get('name') == 'facet_counts': + myelement = lst for node in myelement.findall('lst'): - if node.get('name')=='facet_fields': + if node.get('name') == 'facet_fields': for child in node.getchildren(): - facet_name=child.get('name') - facet_dict[facet_name]=[] + facet_name = child.get('name') + facet_dict[facet_name] = [] for grandchild in child.getchildren(): - facet_dict[facet_name].append("%s (%s)"%(str(grandchild.get('name')),str(grandchild.text))) + facet_dict[facet_name].append( + "%s (%s)" % + (str(grandchild.get('name')), str(grandchild.text))) return facet_dict - def get_xmlelement_count(self,facet_param=None): + + def get_xmlelement_count(self, facet_param=None): try: - rqst=self.rqst_count + rqst = self.rqst_count if facet_param: - rqst=rqst+'&%s'%facet_param - #print rqst + rqst = rqst + '&%s' % facet_param + # print rqst url = urllib2.urlopen(rqst) - except Exception,msg: - raise self.EsgfObjectException(msg) + except Exception as msg: + raise self.EsgfObjectException(msg) r = url.read() try: e = xml.etree.ElementTree.fromstring(r) return e - except Exception,err: - raise self.EsgfObjectException("Could not interpret server's results: %s" % err) + except Exception as err: + raise self.EsgfObjectException( + "Could not interpret server's results: %s" % + err) - def make_facet_dict_count(self,xmlelement): - myelementlist=xmlelement.findall('result') - count=None + def make_facet_dict_count(self, xmlelement): + myelementlist = xmlelement.findall('result') + count = None if len(myelementlist) > 0: - myelement=myelementlist[0] - count=int(myelement.get('numFound')) + myelement = myelementlist[0] + count = int(myelement.get('numFound')) return count -validSearchTypes = ["Dataset","File"]#"ById","ByTimeStamp"] +validSearchTypes = ["Dataset", "File"] # "ById","ByTimeStamp"] + + class esgfConnection(object): - def __init__(self,host,port=80,timeout=15,limit=None,offset=0,mapping=None,datasetids=None,fileids=None,restPath=None): - self.port=port - url=str(host).replace("://","^^^---^^^") - sp= url.split("/") - host = sp[0].replace("^^^---^^^","://") + + def __init__(self, host, port=80, timeout=15, limit=None, offset=0, + mapping=None, datasetids=None, fileids=None, restPath=None): + self.port = port + url = str(host).replace("://", "^^^---^^^") + sp = url.split("/") + host = sp[0].replace("^^^---^^^", "://") if restPath is None: restPath = "/".join(sp[1:]) - if len(restPath)==0: - self.restPath="/esg-search/search" + if len(restPath) == 0: + self.restPath = "/esg-search/search" else: - self.restPath=restPath + self.restPath = restPath else: - self.restPath=restPath - self.host=host - #self.host="esg-datanode.jpl.nasa.gov" + self.restPath = restPath + self.host = host + # self.host="esg-datanode.jpl.nasa.gov" self.defaultSearchType = "Dataset" self.EsgfObjectException = esgfConnectionException - self.validSearchTypes=validSearchTypes - self.validSearchTypes=["Dataset",] - all = self._search("facets=*",searchType=None) - ## Now figure out the facet fields + self.validSearchTypes = validSearchTypes + self.validSearchTypes = ["Dataset", ] + all = self._search("facets=*", searchType=None) + # Now figure out the facet fields self.serverOrder = [] for e in all: - if e.tag=="lst" and "name" in e.keys() and e.get("name")=="responseHeader": - ## ok found the Header + if e.tag == "lst" and "name" in e.keys() and e.get("name") == "responseHeader": + # ok found the Header for s in e: - if s.get("name")=="params": - params=s + if s.get("name") == "params": + params = s break - self.params={"text":None,"limit":limit,"offset":offset} - self.searchableKeys=set(["text","limit","offset"]) + self.params = {"text": None, "limit": limit, "offset": offset} + self.searchableKeys = set(["text", "limit", "offset"]) for p in params: - if p.get("name")=="facet.field": + if p.get("name") == "facet.field": for f in p: self.serverOrder.append(f.text) - self.params[f.text]=None + self.params[f.text] = None self.searchableKeys.add(f.text) self.keys = self.params.keys @@ -123,61 +143,68 @@ class esgfConnection(object): self.values = self.params.values if datasetids is not None: - self.datasetids=genutil.StringConstructor(datasetids) + self.datasetids = genutil.StringConstructor(datasetids) else: - self.datasetids=None + self.datasetids = None if fileids is not None: - self.fileids=genutil.StringConstructor(fileids) + self.fileids = genutil.StringConstructor(fileids) if datasetids is not None: - self.fileids.template=self.fileids.template.replace("%(datasetid)",self.datasetids.template) + self.fileids.template = self.fileids.template.replace( + "%(datasetid)", self.datasetids.template) elif self.datasetids is not None: - self.fileids=genutil.StringConstructor("%s.%%(filename)" % self.datasetids.template) + self.fileids = genutil.StringConstructor( + "%s.%%(filename)" % + self.datasetids.template) else: - self.fileids=None - #self.setMapping(mapping) - self.mapping=mapping - - ## def setUserOrder(self,value): - ## self.userOrder=value - ## def getUserOrder(self): - ## return self.userOrder - ## order=property(getUserOrder,setUserOrder) - def __getitem__(self,key): + self.fileids = None + # self.setMapping(mapping) + self.mapping = mapping + + # def setUserOrder(self,value): + # self.userOrder=value + # def getUserOrder(self): + # return self.userOrder + # order=property(getUserOrder,setUserOrder) + def __getitem__(self, key): try: val = self.params[key] except: raise self.EsgfObjectException("Invalid key: %s" % repr(key)) return val - def __setitem__(self,key,value): + + def __setitem__(self, key, value): if not key in self.params.keys(): - raise self.EsgfObjectException("Invalid key: %s, valid keys are: %s" % (repr(key),repr(self.params.keys()))) - self.params[key]=value + raise self.EsgfObjectException( + "Invalid key: %s, valid keys are: %s" % + (repr(key), repr(self.params.keys()))) + self.params[key] = value return - - def _search(self,search="",searchType=None,stringType=False): + def _search(self, search="", searchType=None, stringType=False): if searchType is None: - searchType=self.defaultSearchType + searchType = self.defaultSearchType if not searchType in self.validSearchTypes: - raise self.EsgfObjectException("Valid Search types are: %s" % repr(self.validSearchTypes)) - while search[0]=="&": - search=search[1:] - rqst = "%s/?type=%s&%s" % (self.restPath,searchType,search) - #print "REQUEST: %s%s" % (self.host,rqst) - myhost=str(self.host) - myport=str(self.port) - if myhost.find("://")>-1: - urltype="" + raise self.EsgfObjectException( + "Valid Search types are: %s" % + repr(self.validSearchTypes)) + while search[0] == "&": + search = search[1:] + rqst = "%s/?type=%s&%s" % (self.restPath, searchType, search) + # print "REQUEST: %s%s" % (self.host,rqst) + myhost = str(self.host) + myport = str(self.port) + if myhost.find("://") > -1: + urltype = "" else: - urltype="http://" + urltype = "http://" try: - rqst="%s%s:%s/%s" % (urltype,myhost,myport,rqst) - tmp=rqst[6:].replace("//","/") - rqst=rqst[:6]+tmp - #print "Request:%s"%rqst + rqst = "%s%s:%s/%s" % (urltype, myhost, myport, rqst) + tmp = rqst[6:].replace("//", "/") + rqst = rqst[:6] + tmp + # print "Request:%s"%rqst url = urllib2.urlopen(rqst) - except Exception,msg: - raise self.EsgfObjectException(msg) + except Exception as msg: + raise self.EsgfObjectException(msg) r = url.read() if stringType: return r @@ -185,539 +212,591 @@ class esgfConnection(object): try: e = xml.etree.ElementTree.fromstring(r) return e - except Exception,err: - raise self.EsgfObjectException("Could not interpret server's results: %s" % err) + except Exception as err: + raise self.EsgfObjectException( + "Could not interpret server's results: %s" % + err) - def generateRequest(self,stringType=False,**keys): + def generateRequest(self, stringType=False, **keys): search = "" - params={"limit":self["limit"],"offset":self["offset"]} + params = {"limit": self["limit"], "offset": self["offset"]} - ## for k in self.keys(): - ## if self[k] is not None and k in self.searchableKeys and k!="type": - ## params[k]=self[k] + # for k in self.keys(): + # if self[k] is not None and k in self.searchableKeys and k!="type": + # params[k]=self[k] - for k in keys.keys(): if k == "stringType": - stringType=keys[k] + stringType = keys[k] continue elif k == "type": continue - ## elif not k in self.searchableKeys: - ## raise self.EsgfObjectException("Invalid key: %s, valid keys are: %s" % (repr(k),repr(self.params.keys()))) + # elif not k in self.searchableKeys: + # raise self.EsgfObjectException("Invalid key: %s, valid keys are: + # %s" % (repr(k),repr(self.params.keys()))) if keys[k] is not None: - params[k]=keys[k] + params[k] = keys[k] search = "" for k in params.keys(): - if isinstance(params[k],list): + if isinstance(params[k], list): for v in params[k]: - if isinstance(v,str): - v=v.strip() - search+="&%s=%s" % (k,v) + if isinstance(v, str): + v = v.strip() + search += "&%s=%s" % (k, v) else: v = params[k] - if isinstance(v,str): - v=v.strip() - search+="&%s=%s" % (k,v) + if isinstance(v, str): + v = v.strip() + search += "&%s=%s" % (k, v) -# search = "&".join(map(lambda x : "%s=%s" % (x[0],x[1]), params.items())) - search=search.replace(" ","%20") +# search = "&".join(map(lambda x : "%s=%s" % (x[0],x[1]), params.items())) + search = search.replace(" ", "%20") return search - - def request(self,**keys): - numFound=0 + + def request(self, **keys): + numFound = 0 cont = True - r=[] + r = [] limit = self["limit"] while cont: - #print "Continuing",limit - self["offset"]=numFound - if limit is None or limit>1000: - self["limit"]=1000 + # print "Continuing",limit + self["offset"] = numFound + if limit is None or limit > 1000: + self["limit"] = 1000 search = self.generateRequest(**keys) - stringType=keys.get("stringType",False) - r.append(self._search(search,stringType=stringType)) - if numFound==0: + stringType = keys.get("stringType", False) + r.append(self._search(search, stringType=stringType)) + if numFound == 0: for s in r[0][:]: - if s.tag=="result": + if s.tag == "result": n = int(s.get("numFound")) - numFound+=self["limit"] + numFound += self["limit"] if limit is None: - if numFound>=n: + if numFound >= n: cont = False else: - if numFound>=limit: - cont=False - #print "N is:",numFound,n - self["limit"]=limit - self["offset"]=0 + if numFound >= limit: + cont = False + # print "N is:",numFound,n + self["limit"] = limit + self["offset"] = 0 return r - - def extractTag(self,f): - out=None - if f.tag=="str": - out=f.text - elif f.tag=="arr": - out=[] + + def extractTag(self, f): + out = None + if f.tag == "str": + out = f.text + elif f.tag == "arr": + out = [] for sub in f[:]: out.append(self.extractTag(sub)) - - elif f.tag=="float": + + elif f.tag == "float": out = float(f.text) - elif f.tag=="int": + elif f.tag == "int": out = int(f.text) - elif f.tag=="date": - ## Convert to cdtime? - out =f.text + elif f.tag == "date": + # Convert to cdtime? + out = f.text else: - out=f - if isinstance(out,list) and len(out)==1: - out=out[0] + out = f + if isinstance(out, list) and len(out) == 1: + out = out[0] return out - - def searchDatasets(self,**keys): + + def searchDatasets(self, **keys): resps = self.request(**keys) - stringType=keys.get("stringType",False) + stringType = keys.get("stringType", False) if stringType: return resp datasets = [] for resp in resps: for r in resp[:]: - if r.tag=="result": - ##Ok let's go thru these datasets + if r.tag == "result": + # Ok let's go thru these datasets for d in r[:]: - #print "************************************************" - tmpkeys={} + # print + # "************************************************" + tmpkeys = {} for f in d[:]: k = f.get("name") - tmpkeys[k]=self.extractTag(f) - if tmpkeys["type"]=="Dataset": + tmpkeys[k] = self.extractTag(f) + if tmpkeys["type"] == "Dataset": datasetid = tmpkeys["id"] - #print datasetid,self.restPath - #print "KEYS FOR DATASET",keys.keys() - datasets.append(esgfDataset(host=self.host,port=self.port,limit=1000,offset=0,mapping=self.mapping,datasetids=self.datasetids,fileids=self.fileids,keys=tmpkeys,originalKeys=keys,restPath=self.restPath)) + # print datasetid,self.restPath + # print "KEYS FOR DATASET",keys.keys() + datasets.append( + esgfDataset(host=self.host, + port=self.port, + limit=1000, + offset=0, + mapping=self.mapping, + datasetids=self.datasetids, + fileids=self.fileids, + keys=tmpkeys, + originalKeys=keys, + restPath=self.restPath)) return datasets + class esgfDataset(esgfConnection): - def __init__(self,host=None,port=80,limit=1000,offset=0,mapping=None,datasetids=None,fileids=None,_http=None,restPath=None,keys={},originalKeys={}): + + def __init__(self, host=None, port=80, limit=1000, offset=0, mapping=None, + datasetids=None, fileids=None, _http=None, restPath=None, keys={}, originalKeys={}): if host is None: raise esgfDatasetException("You need to pass url") - self.host=host - #self.host="esg-datanode.jpl.nasa.gov" - self.port=port - self.defaultSearchType="File" + self.host = host + # self.host="esg-datanode.jpl.nasa.gov" + self.port = port + self.defaultSearchType = "File" if restPath is None: - self.restPath="/esg-search/search" + self.restPath = "/esg-search/search" else: - self.restPath=restPath + self.restPath = restPath if datasetids is None: if "dataset_id_template_" in keys: - tmp=keys["dataset_id_template_"] - if tmp[:5]=="cmip5": - tmp = tmp.replace("valid_institute","institute") - tmp="%(project)"+tmp[5:] - self.datasetids = genutil.StringConstructor(tmp.replace(")s",")")) - elif "project" in keys and keys["project"]=="cmip5": - self.datasetids = genutil.StringConstructor("%(project).%(product).%(institute).%(model).%(experiment).%(time_frequency).%(realm).%(cmor_table).%(ensemble)") + tmp = keys["dataset_id_template_"] + if tmp[:5] == "cmip5": + tmp = tmp.replace("valid_institute", "institute") + tmp = "%(project)" + tmp[5:] + self.datasetids = genutil.StringConstructor( + tmp.replace(")s", ")")) + elif "project" in keys and keys["project"] == "cmip5": + self.datasetids = genutil.StringConstructor( + "%(project).%(product).%(institute).%(model).%(experiment).%(time_frequency).%(realm).%(cmor_table).%(ensemble)") else: - self.datasetids=None - if isinstance(datasetids,genutil.StringConstructor): - self.datasetids=datasetids - elif isinstance(datasetids,str): - self.datasetids=genutil.StringConstructor(datasetids) + self.datasetids = None + if isinstance(datasetids, genutil.StringConstructor): + self.datasetids = datasetids + elif isinstance(datasetids, str): + self.datasetids = genutil.StringConstructor(datasetids) if fileids is not None: - if isinstance(fileids,genutil.StringConstructor): - self.fileids=fileids + if isinstance(fileids, genutil.StringConstructor): + self.fileids = fileids else: - self.fileids=genutil.StringConstructor(fileids) + self.fileids = genutil.StringConstructor(fileids) if self.datasetids is not None: - self.fileids.template=self.fileids.template.replace("%(datasetid)",self.datasetids.template) + self.fileids.template = self.fileids.template.replace( + "%(datasetid)", self.datasetids.template) elif self.datasetids is not None: - self.fileids=genutil.StringConstructor("%s.%%(filename)" % self.datasetids.template) + self.fileids = genutil.StringConstructor( + "%s.%%(filename)" % + self.datasetids.template) else: - self.fileids=None - self.originalKeys=originalKeys - self.validSearchTypes=validSearchTypes - self.validSearchTypes=["File",] + self.fileids = None + self.originalKeys = originalKeys + self.validSearchTypes = validSearchTypes + self.validSearchTypes = ["File", ] self.EsgfObjectException = esgfDatasetException - self.params=keys + self.params = keys self.keys = self.params.keys self.items = self.params.items self.values = self.params.values - #self.id=self["id"] - self.params["limit"]=limit - self.params["offset"]=offset - self.mapping=mapping - #print "SEARCHING DS:",originalKeys - self.resp=None + # self.id=self["id"] + self.params["limit"] = limit + self.params["offset"] = offset + self.mapping = mapping + # print "SEARCHING DS:",originalKeys + self.resp = None self.cacheTime = None # self.search() # self.remap() - - ## Ok now we need to "map" this according to the user wishes - - - - ## def mappedItems(): - ## mapped=[] - ## mapppoint=self.mapped - ## for k in self.mapping.keys(): - ## keys=[] - ## level=[k,mappoint.keys()] - ## mappoint - def _extractFiles(self,resp,**inKeys): - ## We need to stick in there the bit from Luca to fill in the matching key from facet for now it's empty - files=[] - skipped = ["type","title","timestamp","service","id","score","file_url","service_type"] + + # Ok now we need to "map" this according to the user wishes + + # def mappedItems(): + # mapped=[] + # mapppoint=self.mapped + # for k in self.mapping.keys(): + # keys=[] + # level=[k,mappoint.keys()] + # mappoint + def _extractFiles(self, resp, **inKeys): + # We need to stick in there the bit from Luca to fill in the matching + # key from facet for now it's empty + files = [] + skipped = [ + "type", + "title", + "timestamp", + "service", + "id", + "score", + "file_url", + "service_type"] for r in resp[:]: - if r.tag=="result": + if r.tag == "result": for d in r[:][:]: - keys={} + keys = {} for f in d[:]: k = f.get("name") - keys[k]=self.extractTag(f) - if keys["type"]=="File": - ## if self["id"]=="obs4MIPs.NASA-JPL.AIRS.mon": - ## verbose=True - ## else: - ## verbose=False - ## #verbose=True - ## if verbose: print "OK",keys["variable"],keys["file_id"],self["id"] - ## if verbose: print "FILEIDS:",self.fileids - ## if verbose: print "Fileids:",self.fileids.template - ## if verbose: print "keys:",keys - ## if self.fileids is not None: - ## try: - ## if verbose: print "file:",keys["file_id"],self.fileids.template - ## k2 = self.fileids.reverse(keys["file_id"]) - ## if verbose: print "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",k2 - ## for k in k2.keys(): - ## keys[k]=k2[k] - ## except: - ## if verbose: print "Failed:",ids[i].text,self.fileids.template - ## pass - ## if verbose: print "KEYS FOR FILE:",keys.keys() - ## if verbose: print "INKEYS:",inKeys.keys() - ## matched = True - ## matchWithKeys = {} - ## for k in self.keys(): - ## if k in self.originalKeys.keys(): - ## matchWithKeys[k]=self.originalKeys[k] - ## else: - ## matchWithKeys[k]=self[k] - ## for s in skipped: - ## try: - ## matchWithKeys.pop(s) - ## except: - ## pass - ## for k in inKeys.keys(): - ## matchWithKeys[k]=inKeys[k] - ## if verbose: print "matching:",matchWithKeys.keys() - ## for k in keys.keys(): - ## if k in matchWithKeys.keys(): - ## if verbose: print "Testing:",k,keys[k] - ## v = matchWithKeys[k] - ## if isinstance(v,(str,int,float)): - ## if verbose: print "\tComparing with:",v - ## if v != keys[k]: - ## matched = False - ## if verbose: print "\t\tNOPE" - ## break - ## elif isinstance(v,list): - ## if verbose: print "\tComparing with (and %i more):%s"%(len(v),v[0]),v - ## if not keys[k] in v: - ## matched = False - ## if verbose: print "\t\tNOPE" - ## break - ## else: - ## print "\twould compare %s with type: %s if I knew how to" % (str(v),type(v)) - ## if verbose: print keys["file_id"],matched - ## if matched : - ## for k in self.keys(): - ## if not k in keys.keys(): - ## keys[k]=self[k] - ## print "KEYS:",keys - files.append(esgfFile(**keys)) + keys[k] = self.extractTag(f) + if keys["type"] == "File": + # if self["id"]=="obs4MIPs.NASA-JPL.AIRS.mon": + # verbose=True + # else: + # verbose=False + # verbose=True + # if verbose: print "OK",keys["variable"],keys["file_id"],self["id"] + # if verbose: print "FILEIDS:",self.fileids + # if verbose: print "Fileids:",self.fileids.template + # if verbose: print "keys:",keys + # if self.fileids is not None: + # try: + # if verbose: print "file:",keys["file_id"],self.fileids.template + # k2 = self.fileids.reverse(keys["file_id"]) + # if verbose: print "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",k2 + # for k in k2.keys(): + # keys[k]=k2[k] + # except: + # if verbose: print "Failed:",ids[i].text,self.fileids.template + # pass + # if verbose: print "KEYS FOR FILE:",keys.keys() + # if verbose: print "INKEYS:",inKeys.keys() + # matched = True + # matchWithKeys = {} + # for k in self.keys(): + # if k in self.originalKeys.keys(): + # matchWithKeys[k]=self.originalKeys[k] + # else: + # matchWithKeys[k]=self[k] + # for s in skipped: + # try: + # matchWithKeys.pop(s) + # except: + # pass + # for k in inKeys.keys(): + # matchWithKeys[k]=inKeys[k] + # if verbose: print "matching:",matchWithKeys.keys() + # for k in keys.keys(): + # if k in matchWithKeys.keys(): + # if verbose: print "Testing:",k,keys[k] + # v = matchWithKeys[k] + # if isinstance(v,(str,int,float)): + # if verbose: print "\tComparing with:",v + # if v != keys[k]: + # matched = False + # if verbose: print "\t\tNOPE" + # break + # elif isinstance(v,list): + # if verbose: print "\tComparing with (and %i more):%s"%(len(v),v[0]),v + # if not keys[k] in v: + # matched = False + # if verbose: print "\t\tNOPE" + # break + # else: + # print "\twould compare %s with type: %s if I knew how to" % (str(v),type(v)) + # if verbose: print keys["file_id"],matched + # if matched : + # for k in self.keys(): + # if not k in keys.keys(): + # keys[k]=self[k] + # print "KEYS:",keys + files.append(esgfFile(**keys)) return files - + def info(self): print self def __str__(self): st = "Dataset Information\nid: %s\nKeys:\n" % self.id for k in self.keys(): - st+="\t%s : %s\n" % (k,self[k]) + st += "\t%s : %s\n" % (k, self[k]) return st - + def clearWebCache(self): self.resp = None - def saveCache(self,target="."): + def saveCache(self, target="."): if self.resp is None: return if os.path.isdir(target): - target = os.path.join(target,"esgfDatasetsCache.pckl") + target = os.path.join(target, "esgfDatasetsCache.pckl") if os.path.exists(target): - f=open(source) - #dict=eval(bz2.decompress(f.read())) - dict=eval(f.read()) + f = open(source) + # dict=eval(bz2.decompress(f.read())) + dict = eval(f.read()) f.close() else: - dict={} - dict[self.id]=[self["timestamp"],xml.etree.ElementTree.tostring(self.resp),self.originalKeys] - f=open(target,"w") - #f.write(bz2.compress(repr(self.cache))) + dict = {} + dict[self.id] = [self["timestamp"], + xml.etree.ElementTree.tostring( + self.resp), + self.originalKeys] + f = open(target, "w") + # f.write(bz2.compress(repr(self.cache))) f.write(repr(self.cache)) f.close() - - def loadCache(self,source): - if isinstance(source,dict): - dict=source + + def loadCache(self, source): + if isinstance(source, dict): + dict = source else: if os.path.isdir(source): - source = os.path.join(source,"esgfDatasetsCache.pckl") + source = os.path.join(source, "esgfDatasetsCache.pckl") if os.path.exists(source): - f=open(source) - #dict=eval(bz2.decompress(f.read())) - dict=eval(f.read()) + f = open(source) + # dict=eval(bz2.decompress(f.read())) + dict = eval(f.read()) f.close() else: - dict={} - vals = dict.get(self.id,["",None,{}]) + dict = {} + vals = dict.get(self.id, ["", None, {}]) if vals[1] is not None: - self.cacheTime=vals[0] - self.resp=xml.etree.ElementTree.fromstring(vals[0]) - self.originalKeys=vals[1] - + self.cacheTime = vals[0] + self.resp = xml.etree.ElementTree.fromstring(vals[0]) + self.originalKeys = vals[1] + def clearOriginalQueryCache(self): - self.originalKeys={} + self.originalKeys = {} def clear(self): self.clearWebCache() self.clearOriginalQueryCache() - - def search(self,**keys): - #search = self.generateRequest(**keys) - stringType=keys.get("stringType",False) + + def search(self, **keys): + # search = self.generateRequest(**keys) + stringType = keys.get("stringType", False) keys.update(self.originalKeys) - st="" + st = "" if not "limit" in keys: - keys["limit"]=[self["limit"]] + keys["limit"] = [self["limit"]] if not "offset" in keys: - keys["offset"]=[self["offset"]] + keys["offset"] = [self["offset"]] for k in keys: - if k in ["searchString","stringType",]: + if k in ["searchString", "stringType", ]: continue for v in keys[k]: - st+="&%s=%s"%(k,v) - #st+="&%s=%s" % (k,keys[k]) - #if self.resp is None: - #self.resp = self._search("dataset_id=%s%s" % (self["id"],st),stringType=stringType) - self.resp = self._search(st,stringType=stringType) + st += "&%s=%s" % (k, v) + # st+="&%s=%s" % (k,keys[k]) + # if self.resp is None: + # self.resp = self._search("dataset_id=%s%s" % + # (self["id"],st),stringType=stringType) + self.resp = self._search(st, stringType=stringType) if stringType: return self.resp - return esgfFiles(self._extractFiles(self.resp,**keys),self) + return esgfFiles(self._extractFiles(self.resp, **keys), self) class esgfFiles(object): - def __init__(self,files,parent,mapping=None,datasetids=None,fileids=None): - self._files=files - if not isinstance(parent,esgfDataset): + + def __init__(self, files, parent, + mapping=None, datasetids=None, fileids=None): + self._files = files + if not isinstance(parent, esgfDataset): raise esgfFilesException("parent must be an esgfDataset instance") - self.parent=parent + self.parent = parent self.EsgfObjectException = esgfFilesException if datasetids is None: - datasetids=parent.datasetids - if isinstance(datasetids,genutil.StringConstructor): - self.datasetids=datasetids - elif isinstance(datasetids,str): - self.datasetids=genutil.StringConstructor(datasetids) + datasetids = parent.datasetids + if isinstance(datasetids, genutil.StringConstructor): + self.datasetids = datasetids + elif isinstance(datasetids, str): + self.datasetids = genutil.StringConstructor(datasetids) else: - self.datasetids=None + self.datasetids = None if fileids is not None: - if isinstance(fileids,genutil.StringConstructor): - self.fileids=fileids + if isinstance(fileids, genutil.StringConstructor): + self.fileids = fileids else: - self.fileids=genutil.StringConstructor(fileids) + self.fileids = genutil.StringConstructor(fileids) if self.datasetids is not None: - self.fileids.template=self.fileids.template.replace("%(datasetid)",self.datasetids.template) + self.fileids.template = self.fileids.template.replace( + "%(datasetid)", self.datasetids.template) elif self.datasetids is not None: - self.fileids=genutil.StringConstructor("%s.%%(filename)" % self.datasetids.template) + self.fileids = genutil.StringConstructor( + "%s.%%(filename)" % + self.datasetids.template) else: - self.fileids=parent.fileids + self.fileids = parent.fileids if mapping is None: - mapping=parent.mapping + mapping = parent.mapping self.setMapping(mapping) self.remap() - self.projects_dict = {"CMIP5": "%(project).%(product).%(institute).%(model).%(experiment).%(time_frequency).%(realm).%(cmor_table).%(ensemble)" } - - def __getitem__(self,item): - if isinstance(item,int): + self.projects_dict = { + "CMIP5": "%(project).%(product).%(institute).%(model).%(experiment).%(time_frequency).%(realm).%(cmor_table).%(ensemble)"} + + def __getitem__(self, item): + if isinstance(item, int): return self._files[item] - elif isinstance(item,str): + elif isinstance(item, str): for f in self._files: - if f["id"]==item: + if f["id"] == item: return f - elif isinstance(item,slice): + elif isinstance(item, slice): return self._files[item] else: raise esgfFilesException("unknown item type: %s" % type(item)) - def __setitem__(self,item): + + def __setitem__(self, item): raise esgfFilesException("You cannot set items") + def __len__(self): return len(self._files) + def getMapping(self): - if isinstance(self.mapping,genutil.StringConstructor): + if isinstance(self.mapping, genutil.StringConstructor): return self.mapping.template else: return self.mapping + def getMappingKeys(self): - if isinstance(self.mapping,genutil.StringConstructor): + if isinstance(self.mapping, genutil.StringConstructor): return self.mapping.keys() else: return None - def setMapping(self,mapping): + + def setMapping(self, mapping): if mapping is None: - self.mapping="" + self.mapping = "" if self.datasetids is not None: - self.mapping=self.datasetids + self.mapping = self.datasetids else: for k in self.parent.keys(): - if not k in ["limit","offset","text"]: - self.mapping+="%%(%s)" % k + if not k in ["limit", "offset", "text"]: + self.mapping += "%%(%s)" % k else: - self.mapping=mapping - #print "Stage 1 mapping:",self.mapping - if not isinstance(self.mapping,genutil.StringConstructor): + self.mapping = mapping + # print "Stage 1 mapping:",self.mapping + if not isinstance(self.mapping, genutil.StringConstructor): if self.datasetids is not None: - self.mapping=self.mapping.replace("%(datasetid)",self.datasetids.template) + self.mapping = self.mapping.replace( + "%(datasetid)", + self.datasetids.template) self.mapping = genutil.StringConstructor(self.mapping) - #print "Stage 2:",self.mapping.template - - ## vk = self.parent.keys() - ## for k in self.mapping.keys(): - ## ok = False - ## if self.datasetids is not None: - ## vk += self.datasetids.keys() - ## if k in self.datasetids.keys(): - ## ok = True - ## if self.fileids is not None: - ## vk+=self.fileids.keys() - ## if k in self.fileids.keys(): - ## ok = True - ## if k in self.parent.keys(): - ## ok=True - ## ## Ok second to last hope... Matching to datasetids - ## if isinstance(self.datasetids,genutil.StringConstructor) and ok is False: - ## try: - ## mapid = self.datasetids.reverse(self.parent.id) - ## vk+=mapid.keys() - ## if k in mapid.keys(): - ## ok = True - - ## except: - ## #print "Couldn't map: %s to %s" % (self.parent.id,self.datasetids.template) - ## pass - ## if ok is False: - ## vk = set(vk) - ## raise self.EsgfObjectException("Invalid mapping key: %s, valid keys are: %s" % (k,sorted(vk))) - - def remap(self,mapping=None,verbose=False): + # print "Stage 2:",self.mapping.template + + # vk = self.parent.keys() + # for k in self.mapping.keys(): + # ok = False + # if self.datasetids is not None: + # vk += self.datasetids.keys() + # if k in self.datasetids.keys(): + # ok = True + # if self.fileids is not None: + # vk+=self.fileids.keys() + # if k in self.fileids.keys(): + # ok = True + # if k in self.parent.keys(): + # ok=True + # Ok second to last hope... Matching to datasetids + # if isinstance(self.datasetids,genutil.StringConstructor) and ok is False: + # try: + # mapid = self.datasetids.reverse(self.parent.id) + # vk+=mapid.keys() + # if k in mapid.keys(): + # ok = True + + # except: + # print "Couldn't map: %s to %s" % (self.parent.id,self.datasetids.template) + # pass + # if ok is False: + # vk = set(vk) + # raise self.EsgfObjectException("Invalid mapping key: %s, valid keys + # are: %s" % (k,sorted(vk))) + + def remap(self, mapping=None, verbose=False): if mapping is None: thismapping = self.mapping else: thismapping = mapping - self.mapped={} + self.mapped = {} savedmapping = thismapping - #print "Remap:",self.mapping.template - ## if verbose: print "################ REMAPPING: %s: %s #############################" % (thismapping.template,repr(thismapping.keys())) + # print "Remap:",self.mapping.template + # if verbose: print "################ REMAPPING: %s: %s + # #############################" % + # (thismapping.template,repr(thismapping.keys())) for f in self._files: - mappoint=self.mapped - tabs="" - nok=0 + mappoint = self.mapped + tabs = "" + nok = 0 nlevels = len(thismapping.keys()) - #print "This mapping",thismapping.template,nlevels + # print "This mapping",thismapping.template,nlevels if nlevels == 0: - ## ok no mapping, let's try to figure this one out + # ok no mapping, let's try to figure this one out if 'dataset_id_template_' in f.keys(): - #print "We are good to go" - ds = f['dataset_id_template_'].replace(")s",")") + # print "We are good to go" + ds = f['dataset_id_template_'].replace(")s", ")") thismapping = genutil.StringConstructor(ds) for k in thismapping.keys(): - ## if verbose: print tabs,"keys:",k,"File keys:",f.keys() - ## if k == self.mapping.keys()[0]: - ## f.matched.keys() - ## else: - ## ## if verbose: print + # if verbose: print tabs,"keys:",k,"File keys:",f.keys() + # if k == self.mapping.keys()[0]: + # f.matched.keys() + # else: + # if verbose: print if k in f.keys(): - ## if verbose: print tabs,k,f[k] - nok+=1 + # if verbose: print tabs,k,f[k] + nok += 1 cont = f[k] - if not isinstance(cont,(str,int,float)): + if not isinstance(cont, (str, int, float)): break if not cont in mappoint.keys(): - mappoint[cont]={} + mappoint[cont] = {} elif k in self.parent.keys(): - ## if verbose: print tabs,k,f[k] - nok+=1 + # if verbose: print tabs,k,f[k] + nok += 1 cont = self[k] if not cont in mappoint.keys(): - mappoint[cont]={} - elif isinstance(self.fileids,genutil.StringConstructor): + mappoint[cont] = {} + elif isinstance(self.fileids, genutil.StringConstructor): try: mapid = self.fileids.reverse(self.parent.id) - ## if verbose: - ## print "MAPID:",k,mapid + # if verbose: + # print "MAPID:",k,mapid if k in mapid.keys(): - ## if verbose: print tabs,k,mapid[k] - nok+=1 + # if verbose: print tabs,k,mapid[k] + nok += 1 cont = mapid[k] if not cont in mappoint.keys(): - mappoint[cont]={} + mappoint[cont] = {} except: break else: break - mappoint=mappoint[cont] - tabs+="\t" - tmp = mappoint.get("files",[]) + mappoint = mappoint[cont] + tabs += "\t" + tmp = mappoint.get("files", []) tmp.append(f) mappoint["files"] = tmp thismapping = savedmapping - ## if verbose: print "################ REMAPPED: %s #############################" % (thismapping,) + # if verbose: print "################ REMAPPED: %s + # #############################" % (thismapping,) + class esgfFile(object): - def __init__(self,**keys): - self.__items__=keys + + def __init__(self, **keys): + self.__items__ = keys self.keys = self.__items__.keys self.items = self.__items__.items self.values = self.__items__.values - services=[] - #print "Keys:",self.keys() - #print self["url"] - S=self["url"] - if isinstance(S,str): - S=[S,] + services = [] + # print "Keys:",self.keys() + # print self["url"] + S = self["url"] + if isinstance(S, str): + S = [S, ] for service in S: - url,s2,s1 = service.split("|") - setattr(self,s1,url) + url, s2, s1 = service.split("|") + setattr(self, s1, url) services.append(s1) - self.services=services - self.id=self["id"] + self.services = services + self.id = self["id"] - def __getitem__(self,key): + def __getitem__(self, key): val = self.__items__[key] return val - - def __setitem__(self,key,value): - self.__items__[key]=value + + def __setitem__(self, key, value): + self.__items__[key] = value return def __str__(self): - st = "File Information\nid: %s\nParent Dataset: %s" % (self["id"],self["dataset_id"]) - st+="Matched keys: %s\n" % (repr(self.__items__)) + st = "File Information\nid: %s\nParent Dataset: %s" % ( + self["id"], self["dataset_id"]) + st += "Matched keys: %s\n" % (repr(self.__items__)) for service in self.services: - st+="service: %s @ %s\n" % (service,getattr(self,service)) + st += "service: %s @ %s\n" % (service, getattr(self, service)) return st[:-1] diff --git a/Packages/cdms2/Lib/selectors.py b/Packages/cdms2/Lib/selectors.py index f22443976..2a35705d1 100644 --- a/Packages/cdms2/Lib/selectors.py +++ b/Packages/cdms2/Lib/selectors.py @@ -1,42 +1,48 @@ """Classes to support easy selection of climate data""" import cdtime -from axis import axisMatches -from error import CDMSError -from grid import AbstractRectGrid, defaultRegion, setRegionSpecs, LongitudeType, LatitudeType, TimeType, VerticalType +from .axis import axisMatches +from .error import CDMSError +from .grid import AbstractRectGrid, defaultRegion, setRegionSpecs, LongitudeType, LatitudeType, TimeType, VerticalType _debug = 0 + + class SelectorError (CDMSError): + "The exception type for errors in the selector packages" - def __init__ (self, args): + + def __init__(self, args): self.args = args + class Selector: + """Selector class""" - def __init__ (self, *args, **kwargs): + + def __init__(self, *args, **kwargs): """Positional args are SelectorComponents or Selectors Keyword args and their value are passed to kwselect to create - selectors. All the selector components are put into the + selectors. All the selector components are put into the components list of this Selector, along with all the components of any Selector arguments. """ self.__components = [] self.refine(*args, **kwargs) for a in args: - if isinstance(a,SelectorComponent): + if isinstance(a, SelectorComponent): try: - self.__str__=a.__str__ + self.__str__ = a.__str__ except: pass - - def components (self): + def components(self): "List of selector components, each an instance of SelectorComponent." return self.__components[:] - - def refine (self, *args, **kwargs): - """Add components to this selector using the same syntax as the - constructor. Ignores non-keyword arguments that are not + + def refine(self, *args, **kwargs): + """Add components to this selector using the same syntax as the + constructor. Ignores non-keyword arguments that are not SelectorComponents or Selectors. """ for a in args: @@ -46,27 +52,27 @@ class Selector: self.__components.append(a) elif isinstance(a, Selector): for x in a.components(): - self.refine(x) + self.refine(x) else: self.refine(positionalComponent(a)) for k, v in kwargs.items(): - self.refine(kwselect(k, v)) - - def __repr__ (self): + self.refine(kwselect(k, v)) + + def __repr__(self): s = 'Selector(' sep = '' for c in self.__components: s = s + sep + repr(c) sep = ', ' return s + ')' - - def __and__ (self, other): - """Implements the & operator, which returns + + def __and__(self, other): + """Implements the & operator, which returns self.clone() refined by other """ if not isinstance(other, Selector): - raise SelectorError, 'Cannot combine Selector with non-selector' + raise SelectorError('Cannot combine Selector with non-selector') s = self.clone() s.refine(other) return s @@ -75,7 +81,7 @@ class Selector: "Makes a copy of this Selector." return Selector(*self.__components) - def __call__ (self, *args, **kwargs): + def __call__(self, *args, **kwargs): """Return a new selector consisting of this one refined by the given arguments. Arguments are as per the constructor or method refine. """ @@ -92,31 +98,31 @@ class Selector: Options modify the result of the selection. The options and their default values are: -- raw = 0: if 1, return an numpy.ma only - -- squeeze = 0: If 1, eliminate any dimensions of length 1 + -- squeeze = 0: If 1, eliminate any dimensions of length 1 from the result. - -- order = None: If given, is a string such as + -- order = None: If given, is a string such as variable.getOrder() returns. Result is permuted into this order. - -- grid = None: If given, is a grid object; result is + -- grid = None: If given, is a grid object; result is regridded onto this grid. Each of the components contributes arguments suitable for the - subRegion call in class cdms.AbstractVariable. If a component + subRegion call in class cdms.AbstractVariable. If a component is to modify the same axis as a previous component, its application is postponed. subRegion is called and the result is then fed - to each of the components' "post" method. This returns a + to each of the components' "post" method. This returns a possibly modified result, which becomes the input to the next - component's post method. + component's post method. This procedure is repeated until no more components are postponed. Then the options are applied to the result in the order - listed above, and the result is returned. + listed above, and the result is returned. Execption SelectorError is thrown if the selection is impossible. The result is a TransientVariable and id(variable) <> id(result) even if there are no components. - """ + """ d = kwargs.copy() raw = d.setdefault('raw', 0) squeeze = d.setdefault('squeeze', 0) @@ -125,13 +131,14 @@ class Selector: del d['squeeze'], d['grid'], d['order'], d['raw'] # make the selector s = self(*args, **d) - return s.unmodified_select(variable, - squeeze=squeeze, - order=order, - grid=grid, + return s.unmodified_select(variable, + squeeze=squeeze, + order=order, + grid=grid, raw=raw) - def unmodified_select(self, variable, raw=0, squeeze=0, order=None, grid=None): + def unmodified_select( + self, variable, raw=0, squeeze=0, order=None, grid=None): "Select using this selector without further modification" result = variable components = self.components() @@ -143,71 +150,80 @@ class Selector: newcomponents = [] specs = defaultRegion() for c in components: - if c.specifyGrid(variable, vargrid, specs): # specs is modified + if c.specifyGrid(variable, vargrid, specs): # specs is modified newcomponents.append(c) components = newcomponents if specs != defaultRegion(): vgindices = result.getGridIndices() mask, indexspecs = vargrid.intersect(specs) result = result(**indexspecs) - result = result.setMaskFromGridMask(mask, vgindices) # Propagate the grid mask to result + result = result.setMaskFromGridMask( + mask, + vgindices) # Propagate the grid mask to result # Now select on non-coordinate components. while(components): axes = result.getAxisList() - if _debug: print "Axes:", axes - specifications = [':']*len(axes) - confined_by = [None]*len(axes) - aux = {} # for extra state + if _debug: + print "Axes:", axes + specifications = [':'] * len(axes) + confined_by = [None] * len(axes) + aux = {} # for extra state overflow = [] - if _debug: print "Component list:", components + if _debug: + print "Component list:", components for c in components: if c.specify(result, axes, specifications, confined_by, aux): - if _debug: print 'Defer ' + repr(c) + if _debug: + print 'Defer ' + repr(c) overflow.append(c) elif _debug: print "After applying", c, ":" - print "specifications=", specifications + print "specifications=", specifications print "Confined_by", confined_by print "aux", aux print "-----------------" - if _debug: + if _debug: print 'About to call subRegion:', specifications fetched = result.subRegion(*specifications) axismap = range(len(axes)) for c in components: - if c in overflow: continue - fetched = c.post(fetched, result, axes, specifications, + if c in overflow: + continue + fetched = c.post(fetched, result, axes, specifications, confined_by, aux, axismap) if not len(overflow) < len(components): - raise SelectorError, \ - 'Internal selector error, infinite loop detected.' + raise SelectorError( + 'Internal selector error, infinite loop detected.') components = overflow result = fetched if squeeze != 0 or \ order is not None or \ grid is not None or \ - raw !=0 or \ - result is variable: + raw != 0 or \ + result is variable: # result is variable when there are no components, for example. return result.subRegion(squeeze=squeeze, order=order, grid=grid, raw=raw) else: return result - + + class SelectorComponent: + """Base class representing selection for a given set of axes. """ - def specify (self, slab, axes, specifications, confined_by, aux): - """Refine the specification suitable for slab.subRegion + + def specify(self, slab, axes, specifications, confined_by, aux): + """Refine the specification suitable for slab.subRegion Set confined_by to yourself for each axis you confine. - If you would normally confine an axis to ':', don't, + If you would normally confine an axis to ':', don't, unless you *require* that axis not be confined by other components. - + Returning: - Return 1 if you wish to skip your turn. You'll be called + Return 1 if you wish to skip your turn. You'll be called later with the results of the other selectors. Raise a SelectorError exception if you can't do your job. @@ -218,10 +234,10 @@ class SelectorComponent: Store any info you want in dictionary aux[id(self)] """ return 0 - + def specifyGrid(self, var, grid, specs): """Refine the specification suitable for grid.intersect(). - + 'var' is a variable. 'grid' is the grid associated with the variable. 'specs' is the result set of specifications, of the form defined in the grid module. @@ -235,47 +251,53 @@ class SelectorComponent: """ return 1 - def post (self, fetched, slab, axes, specifications, confined_by, aux, axismap): + def post(self, fetched, slab, axes, + specifications, confined_by, aux, axismap): """Post-process fetched if desired, return new value. - Arguments slab, axes, specifications, confined_by, and aux are - pre-subRegion call. - - axismap gives the indices of fetched's axes in axes and should + Arguments slab, axes, specifications, confined_by, and aux are + pre-subRegion call. + + axismap gives the indices of fetched's axes in axes and should be modified as required by this method. Set axismap[i] to None to indicate that you have eliminated an axis. """ return fetched - + + class axisComponent (SelectorComponent): + "A SelectorComponent that confines exactly one axis or coordinate dimension (e.g. latitude)." - def __init__ (self, id, spec): + + def __init__(self, id, spec): self.id = id self.spec = spec - def specify (self, slab, axes, specifications, confined_by, aux): + def specify(self, slab, axes, specifications, confined_by, aux): "Do specification for axis self.id; skip if axis not present." for i in range(len(axes)): if axisMatches(axes[i], self.id): - if confined_by[i] is None: - specifications[i] = self.spec - confined_by[i] = self - return 0 - else: - return 1 + if confined_by[i] is None: + specifications[i] = self.spec + confined_by[i] = self + return 0 + else: + return 1 return 0 - def __repr__ (self): - s = repr(self.__class__)+'("'+self.id+'", '+repr(self.spec) + ')' + def __repr__(self): + s = repr(self.__class__) + \ + '("' + self.id + '", ' + repr(self.spec) + ')' return s - + + class coordinateComponent(axisComponent): + "A SelectorComponent that confines exactly one coordinate dimension (e.g., latitude)" def __init__(self, id, spec): axisComponent.__init__(self, id, spec) def specifyGrid(self, var, grid, specs): - "Determine if this component confines the grid, and if so set the specs and return 1" if grid.hasCoordType(self.id): setRegionSpecs(grid, self.spec, self.id, specs) @@ -283,42 +305,52 @@ class coordinateComponent(axisComponent): else: return 1 + class requiredComponent (SelectorComponent): + """Checks to see that a specific id axis must be present.""" - def __init__ (self, ids): + + def __init__(self, ids): """Checks to see that a specific axis or axes must be present. Initialize with a sequence of ids. """ self.ids = ids - - def specify (self, slab, axes, specifications, confined_by, aux): + + def specify(self, slab, axes, specifications, confined_by, aux): """Doesn't confine but checks for existance.""" for id in self.ids: for i in range(len(axes)): if axisMatches(axes[i], id): break else: - raise SelectorError, \ - 'Required axis %s not present in this variable.' % (id,) + raise SelectorError( + 'Required axis %s not present in this variable.' % + (id,)) return 0 + class indexComponent (axisComponent): - """An axisComponent that confines exactly one axis by - specifying indices. + + """An axisComponent that confines exactly one axis by + specifying indices. """ - def __init__ (self, id, start=None, stop=None, stride=None): + + def __init__(self, id, start=None, stop=None, stride=None): self.id = id - self.spec = slice(start,stop, stride) + self.spec = slice(start, stop, stride) + class indexedComponent (SelectorComponent): - """A SelectorComponent that confines exactly one axis - whose index is given. + + """A SelectorComponent that confines exactly one axis + whose index is given. """ - def __init__ (self, index, value): + + def __init__(self, index, value): self.index = index self.spec = value - def specify (self, slab, axes, specifications, confined_by, aux): + def specify(self, slab, axes, specifications, confined_by, aux): "Do the specification for axis whose index is self.index." i = self.index if confined_by[i] is None: @@ -328,13 +360,16 @@ class indexedComponent (SelectorComponent): else: return 1 + class positionalComponent (SelectorComponent): + """A SelectorComponent that confines the next axis available. """ - def __init__ (self, v): + + def __init__(self, v): self.v = v - def specify (self, slab, axes, specifications, confined_by, aux): + def specify(self, slab, axes, specifications, confined_by, aux): "Find the next unconfined axis and confine it." n = 0 for i in range(len(axes)): @@ -344,51 +379,59 @@ class positionalComponent (SelectorComponent): aux[id(self)] = i return 0 else: - raise SelectorError, \ - 'positional component cannot be applied, insufficent rank:' +\ - repr(self) + raise SelectorError('positional component cannot be applied, insufficent rank:' + + repr(self)) - def __repr__ (self): + def __repr__(self): s = repr(self.__class__) + '(' + repr(self.v) + ')' return s - -def longitude (*value): + + +def longitude(*value): "Creates default selector corresponding to keyword longitude = value" if not value: return all if len(value) == 1: value = value[0] - if value == ':': return all + if value == ':': + return all return Selector(coordinateComponent(LongitudeType, value)) - -def latitude (*value): + + +def latitude(*value): "Creates default selector corresponding to keyword latitude = value" if not value: return all if len(value) == 1: value = value[0] - if value == ':': return all + if value == ':': + return all return Selector(coordinateComponent(LatitudeType, value)) - -def time (*value): + + +def time(*value): """Creates a default selector corresponding to keyword time=value """ if not value: return all if len(value) == 1: value = value[0] - if value == ':': return all + if value == ':': + return all return Selector(coordinateComponent(TimeType, value)) -def level (*value): + +def level(*value): "Creates default selector corresponding to keyword level = value" if not value: return all if len(value) == 1: value = value[0] - if value == ':': return all + if value == ':': + return all return Selector(coordinateComponent(VerticalType, value)) + def required(values): """Creates a selector that requires a certain axis to be present.""" if values is None: @@ -397,12 +440,13 @@ def required(values): values = (values,) return Selector(requiredComponent(values)) -def kwselect (k, value): + +def kwselect(k, value): """Turn a keyword/value pair into a SelectorComponent The words latitude, longitude, time, and level are used to pass value to the routine of the same name. Otherise, axis is called using k as the id. - """ + """ kx = k[0:3].lower() if kx == 'lat': return latitude(value) @@ -416,17 +460,25 @@ def kwselect (k, value): return required(value) else: return Selector(requiredComponent((k,)), axisComponent(k, value)) - + all = Selector() -def timeslice (start=None,stop=None,stride=None): + +def timeslice(start=None, stop=None, stride=None): return Selector(indexComponent('time', start, stop, stride)) -def latitudeslice (start=None,stop=None,stride=None): + + +def latitudeslice(start=None, stop=None, stride=None): return Selector(indexComponent('latitude', start, stop, stride)) -def longitudeslice (start=None,stop=None,stride=None): + + +def longitudeslice(start=None, stop=None, stride=None): return Selector(indexComponent('longitude', start, stop, stride)) -def levelslice (start=None,stop=None,stride=None): + + +def levelslice(start=None, stop=None, stride=None): return Selector(indexComponent('level', start, stop, stride)) -def setslice (id, start=None,stop=None,stride=None): - return Selector(indexComponent(id, start, stop, stride)) + +def setslice(id, start=None, stop=None, stride=None): + return Selector(indexComponent(id, start, stop, stride)) diff --git a/Packages/cdms2/Lib/slabinterface.py b/Packages/cdms2/Lib/slabinterface.py index 642aea131..f12738ee7 100644 --- a/Packages/cdms2/Lib/slabinterface.py +++ b/Packages/cdms2/Lib/slabinterface.py @@ -1,64 +1,67 @@ -## Automatically adapted for numpy.oldnumeric Aug 01, 2007 by -## Further modified to be pure new numpy June 24th 2008 +# Automatically adapted for numpy.oldnumeric Aug 01, 2007 by +# Further modified to be pure new numpy June 24th 2008 "Read part of the old cu slab interface implemented over CDMS" import numpy import sys -from error import CDMSError -from axis import std_axis_attributes +from .error import CDMSError +from .axis import std_axis_attributes import cdms2 as cdms + class Slab: + """Slab is the cu api This is an abstract class to inherit in AbstractVariable About axes: weight and bounds attributes always set but may be None - if bounds are None, getdimattribute returns result of querying the + if bounds are None, getdimattribute returns result of querying the axis. """ std_slab_atts = ['filename', - 'missing_value', - 'comments', - 'grid_name', - 'grid_type', - 'time_statistic', - 'long_name', - 'units'] - def __init__ (self): + 'missing_value', + 'comments', + 'grid_name', + 'grid_type', + 'time_statistic', + 'long_name', + 'units'] + + def __init__(self): pass - def getattribute (self, name): + def getattribute(self, name): "Get the attribute name." - defaultdict = {'filename':'N/A', - 'comments':'', - 'grid_name':'N/A', - 'grid_type':'N/A', - 'time_statistic':'', - 'long_name':'', - 'units':''} + defaultdict = {'filename': 'N/A', + 'comments': '', + 'grid_name': 'N/A', + 'grid_type': 'N/A', + 'time_statistic': '', + 'long_name': '', + 'units': ''} result = None - if name in defaultdict.keys() and not hasattr(self,name): - if name=='filename': - if (not hasattr(self,'parent')) or self.parent is None: + if name in defaultdict.keys() and not hasattr(self, name): + if name == 'filename': + if (not hasattr(self, 'parent')) or self.parent is None: result = '' else: result = self.parent.id - elif name=='grid_name': + elif name == 'grid_name': grid = self.getGrid() if grid is None: result = defaultdict[name] else: result = grid.id - elif name=='grid_type': + elif name == 'grid_type': grid = self.getGrid() if grid is None: result = defaultdict[name] - elif isinstance(grid,cdms.grid.TransientRectGrid): + elif isinstance(grid, cdms.grid.TransientRectGrid): result = grid.getType() - elif isinstance(grid,cdms.gengrid.AbstractGenericGrid): + elif isinstance(grid, cdms.gengrid.AbstractGenericGrid): result = 'GenericGrid' - elif isinstance(grid,cdms.hgrid.AbstractCurveGrid): + elif isinstance(grid, cdms.hgrid.AbstractCurveGrid): result = 'CurvilinearGrid' else: result = defaultdict[name] @@ -67,23 +70,23 @@ class Slab: result = getattr(self, name) except AttributeError: result = None - + return result - def setattribute (self, name, value): + def setattribute(self, name, value): "Set the attribute name to value." setattr(self, name, value) - def createattribute (self, name, value): + def createattribute(self, name, value): "Create an attribute and set its name to value." setattr(self, name, value) - def deleteattribute (self, name): + def deleteattribute(self, name): "Delete the named attribute." if hasattr(self, name): delattr(self, name) - def listattributes (self): + def listattributes(self): "Return a list of attribute names." return self.attributes.keys() @@ -92,10 +95,11 @@ class Slab: a = self.getAxis(dim) result = [] for x in std_axis_attributes + a.attributes.keys(): - if not x in result: result.append(x) + if not x in result: + result.append(x) return result - def getdimattribute (self, dim, field): + def getdimattribute(self, dim, field): """Get the attribute named field from the dim'th dimension. For bounds returns the old cu one-dimensional version. """ @@ -121,38 +125,37 @@ class Slab: return g.getWeights()[0] elif d.isLongitude(): return g.getWeights()[1] - else: #should be impossible, actually + else: # should be impossible, actually return numpy.ones(len(d)) elif field == "bounds": b = d.getBounds() n = b.shape[0] - result = numpy.zeros(n+1, b.dtype.char) - result[0:-1] = b[:,0] - result[-1] = b[-1,1] + result = numpy.zeros(n + 1, b.dtype.char) + result[0:-1] = b[:, 0] + result[-1] = b[-1, 1] return result - elif d.attributes.has_key(field): + elif field in d.attributes: return d.attributes[field] else: - raise CDMSError, "No %s attribute on given axis." % field - - + raise CDMSError("No %s attribute on given axis." % field) + def showdim(self): - "Show the dimension attributes and values." + "Show the dimension attributes and values." result = [] for nd in range(self.rank()): - result.append('** Dimension ' + str(nd+1) + ' **') + result.append('** Dimension ' + str(nd + 1) + ' **') result = result + self.getAxis(nd).listall(1) print '\n'.join(result) def listdimnames(self): "Return a list of the names of the dimensions." - result=[] + result = [] for nd in range(self.rank()): result.append(self.getdimattribute(nd, 'name')) return result - def listall (self, all=None): + def listall(self, all=None): "Get list of info about this slab." vname = self.id result = [] @@ -162,8 +165,10 @@ class Slab: for x in Slab.std_slab_atts: result.append(x + ": " + str(self.getattribute(x))) for x in self.attributes.keys(): - if x in Slab.std_slab_atts: continue - if x == 'name': continue + if x in Slab.std_slab_atts: + continue + if x == 'name': + continue result.append(x + ": " + str(self.attributes[x])) g = self.getGrid() if g is None: @@ -171,29 +176,30 @@ class Slab: else: result = result + g.listall(all) for nd in range(self.rank()): - result.append('** Dimension ' + str(nd+1) + ' **') + result.append('** Dimension ' + str(nd + 1) + ' **') result = result + self.getAxis(nd).listall(all) result.append('*** End of description for %s ***' % vname) return result def info(self, flag=None, device=None): "Write info about slab; include dimension values and weights if flag" - if device is None: device = sys.stdout + if device is None: + device = sys.stdout device.write('\n'.join(self.listall(all=flag))) device.write("\n") -def cdms_bounds2cu_bounds (b): + +def cdms_bounds2cu_bounds(b): "Bounds are len(v) by 2 in cdms but len(v)+1 in cu" - cub = numpy.ma.zeros(len(b)+1, numpy.float32) + cub = numpy.ma.zeros(len(b) + 1, numpy.float32) b1 = b.astype(numpy.float32) - if len(b)>1: - if (b[0,0] 1: + if (b[0, 0] < b[0, 1]) == (b[0, 0] < b[-1, 0]): + cub[0] = b[0, 0] + cub[1:] = b[:, 1] else: - cub[0] = b[0,1] - cub[1:] = b[:,0] + cub[0] = b[0, 1] + cub[1:] = b[:, 0] else: cub[:] = b[0] - return numpy.array( cub ) - + return numpy.array(cub) diff --git a/Packages/cdms2/Lib/sliceut.py b/Packages/cdms2/Lib/sliceut.py index e69e83262..4b8b55821 100644 --- a/Packages/cdms2/Lib/sliceut.py +++ b/Packages/cdms2/Lib/sliceut.py @@ -6,41 +6,41 @@ # Returns a slice, or None if the intersection is empty. -def sliceIntersect(aSlice,interval): - p0,p1 = interval +def sliceIntersect(aSlice, interval): + p0, p1 = interval i = aSlice.start j = aSlice.stop k = aSlice.step if k is None: - k=1 + k = 1 # If the slice has a negative step, generate the # equivalent slice with positive step - irev=0 - if k<0: + irev = 0 + if k < 0: k = -k - pk = ((j-i+k)/k)*k+i - j = i+1 + pk = ((j - i + k) / k) * k + i + j = i + 1 i = pk irev = 1 # Calculate the intersection for an increasing slice - px = ((p0-i+k-1)/k)*k+i - a = max(px,i) - b = min(j,p1) - if a0: + if step > 0: start = aSlice.start stop = aSlice.stop else: @@ -72,121 +74,131 @@ def lenSlice(aSlice): stop = aSlice.start step = -step - return ((stop-start-1)/step + 1) + return ((stop - start - 1) / step + 1) + -def reverseSlice(s,size): +def reverseSlice(s, size): """For 'reversed' slices (slices with negative stride), return an equivalent slice with positive step. For positive strides, just return the slice unchanged. """ - if s.step>0 or s.step is None: + if s.step > 0 or s.step is None: return s i = s.start j = s.stop k = s.step if i is None: - i=size-1 - elif i<0: - i = i%size + i = size - 1 + elif i < 0: + i = i % size if j is None: - j=-1 - elif -size-10: - wrap1 = slice(i,size,k) - wrap2 = slice((i-size)%k, j-size, k) + i, j, k = s.start, s.stop, s.step + if k > 0: + wrap1 = slice(i, size, k) + wrap2 = slice((i - size) % k, j - size, k) else: - wrap1 = slice(i-size, None, k) - wrap2 = slice(size+(i-size)%k, j, k) - return (wrap1,wrap2) + wrap1 = slice(i - size, None, k) + wrap2 = slice(size + (i - size) % k, j, k) + return (wrap1, wrap2) -def splitSliceExt(s,size): +def splitSliceExt(s, size): """ mf 20010330 -- For a 'wraparound' slice, return N equivalent slices within the range 0...(N*size) N = anything""" - i,j,k = s.start,s.stop,s.step + i, j, k = s.start, s.stop, s.step # slice of form [i:] sets j to large int - if j>2000000000L: + if j > 2000000000: j = size - _debug=0 - if(_debug): print "SSSS0: ",i,j,k - - wrap=[] - - if k>0: - - iter=0 - if(_debug): print "SSSS1: iter ",iter,j,size,k - while(j>0): - if(_debug): print " " - if(_debug): print "SSSS2: iter",iter,j,size,k - jo=size - if(iter>0): jo=size+1 - if(_debug): print "SSSS3: iter",iter,j,jo - if(j 0: + + iter = 0 + if(_debug): + print "SSSS1: iter ", iter, j, size, k + while(j > 0): + if(_debug): + print " " + if(_debug): + print "SSSS2: iter", iter, j, size, k + jo = size + if(iter > 0): + jo = size + 1 + if(_debug): + print "SSSS3: iter", iter, j, jo + if(j < size): + jo = j + if(_debug): + print "SSSS4: iter", iter, j, jo + wrap.append(slice(i, jo, k)) + j = j - size + i = 0 + iter = iter + 1 + else: - wraprev=[] - iter=0 - if(_debug): print "SSSS1 neg: iter ",iter,i,j,size,k - while(i>=0): - if(_debug): print " " - if(_debug): print "SSSS2 neg: iter",iter,i,j,size,k - io=size-1 - if(_debug): print "SSSS3 neg: iter",iter,i,j,io - if(i= 0): + if(_debug): + print " " + if(_debug): + print "SSSS2 neg: iter", iter, i, j, size, k + io = size - 1 + if(_debug): + print "SSSS3 neg: iter", iter, i, j, io + if(i < size): + io = i + if(_debug): + print "SSSS4 neg: iter", iter, i, j, io + + # mf 20010405 python does not return nothing for + # slice(size-1,size-1,-1); force it + if(not (io == size - 1 and j == size - 1)): + wraprev.append(slice(io, j, k)) + + i = i - size + j = None + iter = iter + 1 # # reverse # - for k in range(0,len(wraprev)): - kk=len(wraprev)-k-1 + for k in range(0, len(wraprev)): + kk = len(wraprev) - k - 1 wrap.append(wraprev[kk]) - if(_debug): print "SSSS5 neg: ",kk,wraprev[kk] + if(_debug): + print "SSSS5 neg: ", kk, wraprev[kk] return (wrap) - - - - - - - diff --git a/Packages/cdms2/Lib/tvariable.py b/Packages/cdms2/Lib/tvariable.py index 7d9db8b9d..9ebcca9c6 100644 --- a/Packages/cdms2/Lib/tvariable.py +++ b/Packages/cdms2/Lib/tvariable.py @@ -1,4 +1,4 @@ -# Automatically adapted for numpy.oldnumeric Aug 01, 2007 by +# Automatically adapted for numpy.oldnumeric Aug 01, 2007 by # Further modified to be pure new numpy June 24th 2008 """ @@ -8,18 +8,18 @@ Contains also the write part of the old cu interface. """ import json import re -import typeconv +from . import typeconv import numpy from numpy import sctype2char -from error import CDMSError -from avariable import AbstractVariable +from .error import CDMSError +from .avariable import AbstractVariable -from axis import createAxis, AbstractAxis -from grid import createRectGrid, AbstractRectGrid -from hgrid import AbstractCurveGrid -from gengrid import AbstractGenericGrid +from .axis import createAxis, AbstractAxis +from .grid import createRectGrid, AbstractRectGrid +from .hgrid import AbstractCurveGrid +from .gengrid import AbstractGenericGrid -# dist array support +# dist array support HAVE_MPI = False try: from mpi4py import MPI @@ -30,38 +30,43 @@ except: id_builtin = id # built_in gets clobbered by keyword + def fromJSON(jsn): """ Recreate a TV from a dumped jsn object""" D = json.loads(jsn) - ## First recreates the axes - axes=[] + # First recreates the axes + axes = [] for a in D["_axes"]: - ax = createAxis(numpy.array(a["_values"],dtype=a["_dtype"]),id=a["id"]) - for k,v in a.iteritems(): - if not k in ["_values","id","_dtype"]: - setattr(ax,k,v) + ax = createAxis( + numpy.array(a["_values"], + dtype=a["_dtype"]), + id=a["id"]) + for k, v in a.iteritems(): + if not k in ["_values", "id", "_dtype"]: + setattr(ax, k, v) axes.append(ax) - ## Now prep the variable - V= createVariable(D["_values"],id=D["id"],typecode=D["_dtype"]) + # Now prep the variable + V = createVariable(D["_values"], id=D["id"], typecode=D["_dtype"]) V.setAxisList(axes) - for k,v in D.iteritems(): - if not k in ["id","_values","_axes","_grid","_fill_value","_dtype",]: - setattr(V,k,v) + for k, v in D.iteritems(): + if not k in ["id", "_values", "_axes", "_grid", "_fill_value", "_dtype", ]: + setattr(V, k, v) V.set_fill_value(D["_fill_value"]) return V -class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): +class TransientVariable(AbstractVariable, numpy.ma.MaskedArray): + "An in-memory variable." variable_count = 0 _missing = numpy.ma.MaskedArray.fill_value - def _getShape(self): return self._data.shape - shape = property(_getShape,None) + shape = property(_getShape, None) + def iscontiguous(self): return self.flags['CONTIGUOUS'] @@ -70,79 +75,84 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): out = numpy.ascontiguousarray(d) m = numpy.ma.getmask(self) if m is not numpy.ma.nomask: - m= numpy.ascontiguousarray(m) - out = TransientVariable(out,mask=m,attributes=self.attributes) + m = numpy.ascontiguousarray(m) + out = TransientVariable(out, mask=m, attributes=self.attributes) out.setAxisList(self.getAxisList()) out.setMissing(self.getMissing()) return out - + ascontiguous = ascontiguousarray - + def asma(self): - return numpy.ma.array(self._data,mask=self._mask) - - def _update_from(self,obj): - numpy.ma.MaskedArray._update_from(self,obj) - if not hasattr(self,'___cdms_internals__'): - self.__dict__['___cdms_internals__']=['__cdms_internals__','___cdms_internals__','_node_','parent','attributes','shape'] - if not hasattr(self,'attributes'): - self.attributes={} - self._grid_ = getattr(obj,'_grid_',None) + return numpy.ma.array(self._data, mask=self._mask) + + def _update_from(self, obj): + numpy.ma.MaskedArray._update_from(self, obj) + if not hasattr(self, '___cdms_internals__'): + self.__dict__[ + '___cdms_internals__'] = [ + '__cdms_internals__', + '___cdms_internals__', + '_node_', + 'parent', + 'attributes', + 'shape'] + if not hasattr(self, 'attributes'): + self.attributes = {} + self._grid_ = getattr(obj, '_grid_', None) try: - for nm,val in obj.__dict__.items(): - if nm[0]=='_': -## print nm + for nm, val in obj.__dict__.items(): + if nm[0] == '_': +# print nm pass -## self.__dict__[nm]=val +# self.__dict__[nm]=val else: - setattr(self,nm,val) - except Exception,err: + setattr(self, nm, val) + except Exception as err: pass - id = getattr(self,'id',None) + id = getattr(self, 'id', None) if id is None: - TransientVariable.variable_count+=1 - id = 'variable_'+str(TransientVariable.variable_count) - self.id=id - self.name = getattr(obj,'name',id) - if not hasattr(self,'__domain'): + TransientVariable.variable_count += 1 + id = 'variable_' + str(TransientVariable.variable_count) + self.id = id + self.name = getattr(obj, 'name', id) + if not hasattr(self, '__domain'): self.initDomain(axes=None) - - def __array_finalize__(self,obj): - numpy.ma.MaskedArray.__array_finalize__(self,obj) + def __array_finalize__(self, obj): + numpy.ma.MaskedArray.__array_finalize__(self, obj) return - - __mul__ = AbstractVariable.__mul__ - __rmul__ = AbstractVariable.__rmul__ - __imul__ = AbstractVariable.__imul__ - __abs__ = AbstractVariable.__abs__ - __neg__ = AbstractVariable.__neg__ - __add__ = AbstractVariable.__add__ - __iadd__ = AbstractVariable.__iadd__ - __radd__ = AbstractVariable.__radd__ + __mul__ = AbstractVariable.__mul__ + __rmul__ = AbstractVariable.__rmul__ + __imul__ = AbstractVariable.__imul__ + __abs__ = AbstractVariable.__abs__ + __neg__ = AbstractVariable.__neg__ + __add__ = AbstractVariable.__add__ + __iadd__ = AbstractVariable.__iadd__ + __radd__ = AbstractVariable.__radd__ __lshift__ = AbstractVariable.__lshift__ __rshift__ = AbstractVariable.__rshift__ - __sub__ = AbstractVariable.__sub__ - __rsub__ = AbstractVariable.__rsub__ - __isub__ = AbstractVariable.__isub__ - __div__ = AbstractVariable.__div__ - __rdiv__ = AbstractVariable.__rdiv__ - __idiv__ = AbstractVariable.__idiv__ - __pow__ = AbstractVariable.__pow__ - __eq__ = AbstractVariable.__eq__ - __ne__ = AbstractVariable.__ne__ - __lt__ = AbstractVariable.__lt__ - __le__ = AbstractVariable.__le__ - __gt__ = AbstractVariable.__gt__ - __ge__ = AbstractVariable.__ge__ - __sqrt__ = AbstractVariable.__sqrt__ - - def __init__(self,data, typecode=None, copy=1, savespace=0, + __sub__ = AbstractVariable.__sub__ + __rsub__ = AbstractVariable.__rsub__ + __isub__ = AbstractVariable.__isub__ + __div__ = AbstractVariable.__div__ + __rdiv__ = AbstractVariable.__rdiv__ + __idiv__ = AbstractVariable.__idiv__ + __pow__ = AbstractVariable.__pow__ + __eq__ = AbstractVariable.__eq__ + __ne__ = AbstractVariable.__ne__ + __lt__ = AbstractVariable.__lt__ + __le__ = AbstractVariable.__le__ + __gt__ = AbstractVariable.__gt__ + __ge__ = AbstractVariable.__ge__ + __sqrt__ = AbstractVariable.__sqrt__ + + def __init__(self, data, typecode=None, copy=1, savespace=0, mask=numpy.ma.nomask, fill_value=None, grid=None, - axes=None, attributes=None, id=None, copyaxes=1, dtype=None, - order=False, no_update_from=False,**kargs): - """createVariable (self, data, typecode=None, copy=0, savespace=0, + axes=None, attributes=None, id=None, copyaxes=1, dtype=None, + order=False, no_update_from=False, **kargs): + """createVariable (self, data, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, grid=None, axes=None, attributes=None, id=None, dtype=None, order=False) The savespace argument is ignored, for backward compatibility only. @@ -150,69 +160,70 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): try: if data.fill_value is not None: self._setmissing(data.fill_value) - fill_value=data.fill_value + fill_value = data.fill_value except: pass if fill_value is not None: - self._setmissing(fill_value) - if attributes is not None and "_FillValue" in attributes.keys(): - self._setmissing(attributes["_FillValue"]) + self._setmissing(fill_value) + if attributes is not None and "_FillValue" in attributes.keys(): + self._setmissing(attributes["_FillValue"]) - # tile index, None means no mosaic + # tile index, None means no mosaic self.tileIndex = None - + # Compatibility: assuming old typecode, map to new if dtype is None and typecode is not None: dtype = typeconv.convtypecode2(typecode) typecode = sctype2char(dtype) if isinstance(data, tuple): data = list(data) - - AbstractVariable.__init__ (self) + + AbstractVariable.__init__(self) if isinstance(data, AbstractVariable): if not isinstance(data, TransientVariable): data = data.subSlice() -## if attributes is None: attributes = data.attributes +# if attributes is None: attributes = data.attributes if axes is None and not no_update_from: axes = map(lambda x: x[0], data.getDomain()) if grid is None and not no_update_from: grid = data.getGrid() if (grid is not None) and (not isinstance(grid, AbstractRectGrid)) \ - and (not grid.checkAxes(axes)): - grid = grid.reconcile(axes) # Make sure grid and axes are consistent - - ncopy = (copy!=0) + and (not grid.checkAxes(axes)): + grid = grid.reconcile( + axes) # Make sure grid and axes are consistent + ncopy = (copy != 0) # Initialize the geometry if grid is not None: - copyaxes=0 # Otherwise grid axes won't match domain. + copyaxes = 0 # Otherwise grid axes won't match domain. if axes is not None: - self.initDomain(axes, copyaxes=copyaxes) # Note: clobbers the grid, so set the grid after. + self.initDomain(axes, copyaxes=copyaxes) + # Note: clobbers the grid, so set the grid after. if grid is not None: self.setGrid(grid) - + # Initialize the attributes if attributes is not None: for key, value in attributes.items(): - if (key in ['shape','flat','imaginary','real'] or key[0]=='_') and key not in ['_FillValue']: - raise CDMSError, 'Bad key in attributes: ' + key + if (key in ['shape', 'flat', 'imaginary', 'real'] or key[0] == '_') and key not in ['_FillValue']: + raise CDMSError('Bad key in attributes: ' + key) elif key == 'missing_value': - #ignore if fill value given explicitly + # ignore if fill value given explicitly if fill_value is None: self._setmissing(value) - elif key not in ['scale_factor','add_offset']: + elif key not in ['scale_factor', 'add_offset']: setattr(self, key, value) # Sync up missing_value attribute and the fill value. self.missing_value = self._getmissing() self._FillValue = self._getmissing() if id is not None: - if not isinstance(id,(unicode,str)): - raise CDMSError, 'id must be a string' + if not isinstance(id, (unicode, str)): + raise CDMSError('id must be a string') self.id = id - elif hasattr(data,'id'): + elif hasattr(data, 'id'): self.id = data.id if self.id is None: @@ -227,22 +238,21 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): self.__mpiWindows = {} self.__mpiType = self.__getMPIType() - def _getmissing(self): return self._missing - def _setmissing(self,value): - self._missing=numpy.array(value).astype(self.dtype) + def _setmissing(self, value): + self._missing = numpy.array(value).astype(self.dtype) - missing = property(_getmissing,_setmissing) - fill_value = property(_getmissing,_setmissing) - _FillValue = property(_getmissing,_setmissing) - missing_value = property(_getmissing,_setmissing) + missing = property(_getmissing, _setmissing) + fill_value = property(_getmissing, _setmissing) + _FillValue = property(_getmissing, _setmissing) + missing_value = property(_getmissing, _setmissing) - def __new__(cls, data, typecode=None, copy=0, savespace=0, - mask=numpy.ma.nomask, fill_value=None, grid=None, - axes=None, attributes=None, id=None, copyaxes=1, dtype=None, order=False,**kargs): - """createVariable (self, data, typecode=None, copy=0, savespace=0, + def __new__(cls, data, typecode=None, copy=0, savespace=0, + mask=numpy.ma.nomask, fill_value=None, grid=None, + axes=None, attributes=None, id=None, copyaxes=1, dtype=None, order=False, **kargs): + """createVariable (self, data, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, grid=None, axes=None, attributes=None, id=None, dtype=None, order=False) The savespace argument is ignored, for backward compatibility only. @@ -258,61 +268,60 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): data = data.subSlice() if isinstance(data, numpy.ma.MaskedArray): try: - if fill_value is None: fill_value = data.fill_value + if fill_value is None: + fill_value = data.fill_value except: pass - ncopy = (copy!=0) + ncopy = (copy != 0) if mask is None: try: mask = data.mask - except Exception,err: + except Exception as err: mask = numpy.ma.nomask # Handle the case where ar[i:j] returns a single masked value if data is numpy.ma.masked: - #shape = tuple(len(axes)*[1]) + # shape = tuple(len(axes)*[1]) data = numpy.ma.masked.data - #data.shape = shape + # data.shape = shape mask = numpy.ma.masked.mask - #mask.shape = shape -## if data.getattr('mask',None) is not numpy.ma.nomask: -## mask = data.mask -## print 'passing:',mask.shape,data.shape,numpy.shape(cls) + # mask.shape = shape +# if data.getattr('mask',None) is not numpy.ma.nomask: +# mask = data.mask +# print 'passing:',mask.shape,data.shape,numpy.shape(cls) if fill_value is not None: fill_value = numpy.array(fill_value).astype(dtype) else: fill_value = numpy.ma.MaskedArray(1).astype(dtype).item() + self = numpy.ma.MaskedArray.__new__(cls, data, dtype=dtype, + copy=ncopy, + mask=mask, + fill_value=fill_value, + subok=False, + order=order) - self = numpy.ma.MaskedArray.__new__(cls, data, dtype = dtype, - copy = ncopy, - mask = mask, - fill_value = fill_value, - subok = False, - order = order) - - - return self # typecode = numpy.ma.array.typecode def typecode(self): return self.dtype.char - def assignValue(self,data): + def assignValue(self, data): self[...] = data def getValue(self, squeeze=1): return self.filled() - def expertSlice (self, slicelist): + def expertSlice(self, slicelist): return numpy.ma.MaskedArray.__getitem__(self, slicelist) - def initDomain (self, axes, copyaxes=1): - # lazy evaluation via getAxis to avoid creating axes that aren't ever used. + def initDomain(self, axes, copyaxes=1): + # lazy evaluation via getAxis to avoid creating axes that aren't ever + # used. newgrid = None - self.__domain = [None]*self.rank() + self.__domain = [None] * self.rank() if axes is not None: flataxes = [] try: @@ -325,22 +334,25 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): elif isinstance(item, AbstractRectGrid) or isinstance(item, AbstractCurveGrid): flataxes.append(item.getAxis(0)) flataxes.append(item.getAxis(1)) - copyaxes=0 + copyaxes = 0 newgrid = item elif isinstance(item, AbstractGenericGrid): flataxes.append(item.getAxis(0)) - copyaxes=0 + copyaxes = 0 newgrid = item else: - raise CDMSError, "Invalid item in axis list:\n"+`item` + raise CDMSError( + "Invalid item in axis list:\n" + repr(item)) if len(flataxes) != self.rank(): - raise CDMSError, "Wrong number of axes to initialize domain." + raise CDMSError("Wrong number of axes to initialize domain.") for i in range(len(flataxes)): if flataxes[i] is not None: - if (not flataxes[i].isVirtual()) and copyaxes==1: + if (not flataxes[i].isVirtual()) and copyaxes == 1: self.copyAxis(i, flataxes[i]) else: - self.setAxis(i, flataxes[i]) # No sense copying a virtual axis. + self.setAxis( + i, + flataxes[i]) # No sense copying a virtual axis. if newgrid is not None: # Do this after setting the axes, so the grid is consistent self.setGrid(newgrid) @@ -350,25 +362,31 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): junk = self.getAxis(i) # will force a fill in return self.__domain - def getAxis (self, n): - if n < 0: n = n + self.rank() + def getAxis(self, n): + if n < 0: + n = n + self.rank() if self.__domain[n] is None: length = numpy.ma.size(self, n) - # axis = createAxis(numpy.ma.arange(numpy.ma.size(self, n), typecode=numpy.Float)) - axis = createAxis(numpy.ma.arange(numpy.ma.size(self, n), dtype=numpy.float_)) + # axis = createAxis(numpy.ma.arange(numpy.ma.size(self, n), + # typecode=numpy.Float)) + axis = createAxis( + numpy.ma.arange(numpy.ma.size(self, n), dtype=numpy.float_)) axis.id = "axis_" + str(n) self.__domain[n] = (axis, 0, length, length) return self.__domain[n][0] - - def setAxis (self, n, axis, savegrid=0): + + def setAxis(self, n, axis, savegrid=0): """Set n axis of self to a copy of axis. (0-based index) """ - if n < 0: n = n + self.rank() + if n < 0: + n = n + self.rank() axislen = self.shape[n] - if len(axis)!=axislen: - raise CDMSError,"axis length %d does not match corresponding dimension %d"%(len(axis),axislen) + if len(axis) != axislen: + raise CDMSError( + "axis length %d does not match corresponding dimension %d" % + (len(axis), axislen)) if not isinstance(axis, AbstractAxis): - raise CDMSError,"copydimension, other not a slab." + raise CDMSError("copydimension, other not a slab.") self.__domain[n] = (axis, 0, len(axis), len(axis)) def setAxisList(self, axislist): @@ -376,26 +394,27 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): for i in range(len(axislist)): self.setAxis(i, axislist[i]) - def copyAxis (self, n, axis): + def copyAxis(self, n, axis): """Set n axis of self to a copy of axis. (0-based index) Invalidates grid. """ - if n < 0: n = n + self.rank() + if n < 0: + n = n + self.rank() if not isinstance(axis, AbstractAxis): - raise CDMSError,"copydimension, other not an axis." + raise CDMSError("copydimension, other not an axis.") b = axis.getBounds() mycopy = createAxis(axis[:], b) mycopy.id = axis.id for k, v in axis.attributes.items(): - setattr(mycopy, k, v) - self.setAxis (n, mycopy) - - def copyDomain (self, other): + setattr(mycopy, k, v) + self.setAxis(n, mycopy) + + def copyDomain(self, other): "Set the axes and grid by copying variable other." if not isinstance(other, AbstractVariable): - raise CDMSError,"copyDomain, other not a variable." + raise CDMSError("copyDomain, other not a variable.") if self.rank() != other.rank(): - raise CDMSError, "copyDomain, ranks do not match." + raise CDMSError("copyDomain, ranks do not match.") for i in range(self.rank()): self.copyAxis(i, other.getAxis(i)) self.setGrid(other.getGrid()) @@ -406,21 +425,23 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): for i in range(self.rank()): ax = self.getAxis(i) if ax.isLatitude(): - order = order+'y' + order = order + 'y' lat = ax elif ax.isLongitude(): - order = order+'x' + order = order + 'x' lon = ax - if len(order)==2: break + if len(order) == 2: + break - if order in ['yx','xy']: - self._grid_ = createRectGrid(lat,lon,order) + if order in ['yx', 'xy']: + self._grid_ = createRectGrid(lat, lon, order) return self._grid_ - def astype (self, tc): + def astype(self, tc): "return self as array of given type." - maresult = numpy.ma.MaskedArray.astype(self,tc) - return TransientVariable(maresult, copy=0, axes=self.getAxisList(), fill_value=self.fill_value, + maresult = numpy.ma.MaskedArray.astype(self, tc) + return TransientVariable( + maresult, copy=0, axes=self.getAxisList(), fill_value=self.fill_value, attributes=self.attributes, id=self.id, grid=self.getGrid()) def setMaskFromGridMask(self, mask, gridindices): @@ -437,18 +458,18 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): shapeprep.append(self.shape[i]) # Broadcast mask - if tprep!=[]: + if tprep != []: newshape = tuple(shapeprep + list(mask.shape)) bigmask = numpy.resize(mask, newshape) # Generate the tranpose vector t = tuple(tprep + list(gridindices)) - tinv = [0]*len(t) + tinv = [0] * len(t) for i in range(len(t)): tinv[t[i]] = i # And reshape to fit the variable - if tinv!=range(len(tinv)): + if tinv != range(len(tinv)): bigmask = numpy.transpose(bigmask, tuple(tinv)) else: @@ -463,25 +484,25 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): return result # Old cu interface - def copydimension (self, idim, other, jdim): - """Set idim dimension of self to variable other's jdim'th + def copydimension(self, idim, other, jdim): + """Set idim dimension of self to variable other's jdim'th This is for old cu compatibility. Use copyAxis for new code. """ if not isinstance(other, AbstractVariable): - raise CDMSError,"copydimension, other not a variable." + raise CDMSError("copydimension, other not a variable.") a = other.getAxis(jdim) self.copyAxis(idim, a) def setdimattribute(self, dim, field, value): "Set the attribute named field from the dim'th dimension." if dim < 0 or dim >= self.rank(): - raise CDMSError, "setdimattribute, dim out of bounds." + raise CDMSError("setdimattribute, dim out of bounds.") d = self.getAxis(dim) if field == "name": if not isinstance(value, basestring): - raise CDMSError, "setdimattribute: name not a string" + raise CDMSError("setdimattribute: name not a string") d.id = value - + elif field == "values": # note -- invalidates grid, may break old code. a = createAxis(numpy.ma.filled(value[:])) @@ -492,28 +513,29 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): elif field == "units": if not isinstance(value, basestring): - raise CDMSError, "setdimattribute: units not a string" + raise CDMSError("setdimattribute: units not a string") d.units = value elif field == "weights": # Well, you can't really do this without modifying the grid - raise CDMSError, "setdimattribute weights not implemented." + raise CDMSError("setdimattribute weights not implemented.") elif field == "bounds": if value is None: - d.setBounds(None) + d.setBounds(None) else: - b = numpy.ma.filled(value) - if numpy.ma.rank(b) == 2: - d.setBounds(b) - elif numpy.ma.rank(b) == 1: - b1 = numpy.zeros((len(b)-1,2), b.dtype.char) - b1[:,0] = b[:-1] - b1[:,1] = b[1:] - d.setBounds(b1) - else: - raise CDMSError, \ - "setdimattribute, bounds improper shape: " + b.shape + b = numpy.ma.filled(value) + if numpy.ma.rank(b) == 2: + d.setBounds(b) + elif numpy.ma.rank(b) == 1: + b1 = numpy.zeros((len(b) - 1, 2), b.dtype.char) + b1[:, 0] = b[:-1] + b1[:, 1] = b[1:] + d.setBounds(b1) + else: + raise CDMSError( + "setdimattribute, bounds improper shape: " + + b.shape) else: setattr(d, field, value) @@ -524,57 +546,57 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): result = createVariable(self, copy=copyData) return result - def dumps(self,*args,**kargs): - ## Probably need something for curv/gen grids + def dumps(self, *args, **kargs): + # Probably need something for curv/gen grids """ Dumps Variable to a jason object, args are passed directly to json.dump""" - J={} - for k,v in self.attributes.iteritems(): - if k=="autoApiInfo": + J = {} + for k, v in self.attributes.iteritems(): + if k == "autoApiInfo": continue - J[k]=v - J['id']=self.id - axes=[] + J[k] = v + J['id'] = self.id + axes = [] for a in self.getAxisList(): - ax={} - for A,v in a.attributes.iteritems(): - ax[A]=v - ax['id']=a.id - ax["_values"]=a[:].tolist() - ax["_dtype"]=a[:].dtype.char + ax = {} + for A, v in a.attributes.iteritems(): + ax[A] = v + ax['id'] = a.id + ax["_values"] = a[:].tolist() + ax["_dtype"] = a[:].dtype.char axes.append(ax) - J["_axes"]=axes - J["_values"]=self[:].filled(self.fill_value).tolist() - J["_fill_value"]=float(self.fill_value) - J["_dtype"]=self.typecode() - J["_grid"]=None #self.getGrid() - return json.dumps(J,*args,**kargs) + J["_axes"] = axes + J["_values"] = self[:].filled(self.fill_value).tolist() + J["_fill_value"] = float(self.fill_value) + J["_dtype"] = self.typecode() + J["_grid"] = None # self.getGrid() + return json.dumps(J, *args, **kargs) def isEncoded(self): "Transient variables are not encoded" return 0 - def __len__ (self): + def __len__(self): "Length of first dimension" - if self.rank()>0: - (axis,start,length,true_length) = self.getDomain()[0] + if self.rank() > 0: + (axis, start, length, true_length) = self.getDomain()[0] else: length = 0 return length - def __str__ (self): + def __str__(self): return numpy.ma.MaskedArray.__str__(self) - def __repr__ (self): + def __repr__(self): return self.id + '\n' + numpy.ma.MaskedArray.__repr__(self) + '\n' def set_fill_value(self, value): "Set missing value attribute and fill value" AbstractVariable.setMissing(self, value) - #self.__dict__['_fill_value'] = self.missing_value - ## Fix submitted by Ghislain Picard, this was broken with numpy 1.5 - numpy.ma.MaskedArray.set_fill_value(self,value) + # self.__dict__['_fill_value'] = self.missing_value + # Fix submitted by Ghislain Picard, this was broken with numpy 1.5 + numpy.ma.MaskedArray.set_fill_value(self, value) - def setMissing (self, value): + def setMissing(self, value): "Set missing value attribute and fill value" self.set_fill_value(value) @@ -595,7 +617,7 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): """ return self.tileIndex - def toVisit(self, filename, format='Vs', sphereRadius=1.0, + def toVisit(self, filename, format='Vs', sphereRadius=1.0, maxElev=0.1): """ Save data to file for postprocessing by the VisIt visualization tool @@ -604,21 +626,21 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): sphereRadius: radius of the earth maxElev: maximum elevation for representation on the sphere """ - import mvSphereMesh - import mvVTKSGWriter - import mvVsWriter + from . import mvSphereMesh + from . import mvVTKSGWriter + from . import mvVsWriter try: # required by mvVsWriter import tables except: - # fall back + # fall back format = 'VTK' def generateTimeFileName(filename, tIndex, tIndexMax, suffix): - ndigits = len('%d'%tIndexMax) - itdigits = len('%d'%tIndex) - tiStr = '0'*(ndigits-itdigits) + ('%d'%tIndex) - return re.sub(r'\.' + suffix, '_%s.%s' % (tiStr, suffix), + ndigits = len('%d' % tIndexMax) + itdigits = len('%d' % tIndex) + tiStr = '0' * (ndigits - itdigits) + ('%d' % tIndex) + return re.sub(r'\.' + suffix, '_%s.%s' % (tiStr, suffix), filename) # determine whether data are time dependent @@ -632,46 +654,48 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): counter += 1 if axis == 'time': timeIndex = counter - - if timeAxis == None or timeIndex == -1: + + if timeAxis is None or timeIndex == -1: # static data if format == 'VTK': vw = mvVTKSGWriter.VTKSGWriter(self, maxElev) - if filename.find('.vtk') == -1: + if filename.find('.vtk') == -1: filename += '.vtk' vw.write(filename) else: vw = mvVsWriter.VsWriter(self, maxElev) - if filename.find('.vsh5') == -1: + if filename.find('.vsh5') == -1: filename += '.vsh5' vw.write(filename) else: # time dependent data tIndexMax = len(timeAxis) for tIndex in range(tIndexMax): - sliceOp = 'self[' + (':,'*timeIndex) + ('%d,'%tIndex) + '...]' + sliceOp = 'self[' + ( + ':,' * timeIndex) + ('%d,' % + tIndex) + '...]' var = eval(sliceOp) if format == 'VTK': if filename.find('.vtk') == -1: filename += '.vtk' - tFilename = generateTimeFileName(filename, + tFilename = generateTimeFileName(filename, tIndex, tIndexMax, 'vtk') vw = mvVTKSGWriter.VTKSGWriter(var, maxElev) vw.write(tFilename) else: if filename.find('.h5') == -1: filename += '.h5' - tFilename = generateTimeFileName(filename, + tFilename = generateTimeFileName(filename, tIndex, tIndexMax, 'h5') vw = mvVsWriter.VsWriter(var, maxElev) vw.write(tFilename) - - # Following are distributed array methods, they require mpi4py + + # Following are distributed array methods, they require mpi4py # to be installed def setMPIComm(self, comm): """ - Set the MPI communicator. This is a no-op if MPI + Set the MPI communicator. This is a no-op if MPI is not available. """ if HAVE_MPI: @@ -698,7 +722,7 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): def exposeHalo(self, ghostWidth=1): """ Expose the halo to other processors. The halo is the region - within the local MPI data domain that is accessible to other + within the local MPI data domain that is accessible to other processors. The halo encompasses the edge of the data region and has thickness ghostWidth. @@ -715,9 +739,9 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): # given direction, a 1 represents a layer of # thickness ghostWidth on the high index side, # -1 on the low index side. - winId = tuple( [0 for i in range(dim) ] \ - + [drect] + \ - [0 for i in range(dim+1, ndims) ] ) + winId = tuple([0 for i in range(dim)] + + [drect] + + [0 for i in range(dim + 1, ndims)]) slce = slice(0, ghostWidth) if drect == 1: @@ -726,19 +750,19 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): slab = self.__getSlab(dim, slce) # create the MPI window - dataSrc = numpy.zeros(self[slab].shape, self.dtype) - dataDst = numpy.zeros(self[slab].shape, self.dtype) + dataSrc = numpy.zeros(self[slab].shape, self.dtype) + dataDst = numpy.zeros(self[slab].shape, self.dtype) self.__mpiWindows[winId] = { 'slab': slab, 'dataSrc': dataSrc, 'dataDst': dataDst, 'window': MPI.Win.Create(dataSrc, comm=self.__mpiComm), - } - + } + def getHaloEllipsis(self, side): """ - Get the ellipsis for a given halo side. - + Get the ellipsis for a given halo side. + side - a tuple of zeros and one +1 or -1. To access the "north" side for instance, set side=(1, 0), (-1, 0) to access the south side, (0, 1) the east @@ -746,7 +770,7 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): Return none if halo was not exposed (see exposeHalo) """ - if HAVE_MPI and self.__mpiWindows.has_key(side): + if HAVE_MPI and side in self.__mpiWindows: return self.__mpiWindows[side]['slab'] else: return None @@ -754,20 +778,20 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): def fetchHaloData(self, pe, side): """ Fetch the halo data from another processor. The halo side - is a subdomain of the halo that is exposed to other + is a subdomain of the halo that is exposed to other processors. It is an error to call this method when MPI is not enabled. This is a collective method (must be called by all processes), which involves synchronization of data among all processors. pe - processor owning the halo data. This is a no - operation when pe is None. + operation when pe is None. side - a tuple of zeros and one +1 or -1. To access the "north" side for instance, set side=(1, 0), (-1, 0) to access the south side, (0, 1) the east - side, etc. + side, etc. - Note: collective, all procs must invoke this method. If some + Note: collective, all procs must invoke this method. If some processors should not fetch then pass None for pe. """ if HAVE_MPI: @@ -780,37 +804,37 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): dataSrc[...] = self[slab] win = iw['window'] - win.Fence() # get the data ready + win.Fence() # get the data ready if pe is not None: - win.Get( [dataDst, self.__mpiType], pe ) - win.Fence() # make sure the communication completed + win.Get([dataDst, self.__mpiType], pe) + win.Fence() # make sure the communication completed return dataDst else: - raise CDMSError, 'Must have MPI to invoke fetchHaloData' + raise CDMSError('Must have MPI to invoke fetchHaloData') def freeHalo(self): """ - Free the MPI windows attached to the halo. This must be + Free the MPI windows attached to the halo. This must be called before MPI_Finalize. """ for iw in self.__mpiWindows: - self.__mpiWindows[iw]['window'].Free() + self.__mpiWindows[iw]['window'].Free() def __getSlab(self, dim, slce): """ Get slab. A slab is a multi-dimensional slice extending in all directions except along dim where slce applies - + dim - dimension (0=first index, 1=2nd index...) slce - python slice object along dimension dim - + return slab """ ndims = len(self.shape) - + slab = [ slice(0, None) for i in range(dim) ] \ - + [slce] + \ - [ slice(0, None) for i in range(dim+1, ndims) ] + + [slce] + \ + [slice(0, None) for i in range(dim + 1, ndims)] return tuple(slab) def __getMPIType(self): @@ -834,50 +858,54 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): elif dtyp == numpy.int8: typ = MPI.INT8_T else: - return None + return None else: return typ -## PropertiedClasses.set_property(TransientVariable, 'shape', -## nowrite=1, nodelete=1) +# PropertiedClasses.set_property(TransientVariable, 'shape', +# nowrite=1, nodelete=1) + -def createVariable(*args,**kargs): - if kargs.get("fromJSON",False): +def createVariable(*args, **kargs): + if kargs.get("fromJSON", False): return fromJSON(*args) else: - return TransientVariable(*args,**kargs) + return TransientVariable(*args, **kargs) -def isVariable (s): + +def isVariable(s): "Is s a variable?" return isinstance(s, AbstractVariable) + def asVariable(s, writeable=1): - """Returns s if s is a Variable; if writeable is 1, return - s if s is a TransientVariable. If s is not a variable of + """Returns s if s is a Variable; if writeable is 1, return + s if s is a TransientVariable. If s is not a variable of the desired type, attempt to make it so and return that. If we fail raise CDMSError """ target_class = AbstractVariable - if writeable: target_class = TransientVariable + if writeable: + target_class = TransientVariable if isinstance(s, target_class): return s elif isinstance(s, AbstractVariable): return s.subSlice() - + try: result = createVariable(s) except CDMSError: - result = None - + result = None + # if result.dtype.char == numpy.ma.PyObject: if issubclass(result.dtype.type, numpy.object_): result = None if result is None: - raise CDMSError, "asVariable could not make a Variable from the input." + raise CDMSError("asVariable could not make a Variable from the input.") return result if __name__ == '__main__': - for s in [(20,), (4,5)]: + for s in [(20,), (4, 5)]: x = numpy.arange(20) x.shape = s t = createVariable(x) @@ -886,21 +914,24 @@ if __name__ == '__main__': assert numpy.ma.allclose(x, t) assert t.dtype.char == numpy.int assert numpy.ma.size(t) == numpy.ma.size(x) - assert numpy.ma.size(t,0) == len(t) - assert numpy.ma.allclose(t.getAxis(0)[:], numpy.ma.arange(numpy.ma.size(t,0))) + assert numpy.ma.size(t, 0) == len(t) + assert numpy.ma.allclose( + t.getAxis(0)[:], numpy.ma.arange(numpy.ma.size(t, 0))) t.missing_value = -99 assert t.missing_value == -99 assert t.fill_value == -99 - t = createVariable(numpy.ma.arange(5), mask=[0,0,0,1,0]) - t.set_fill_value (1000) + t = createVariable(numpy.ma.arange(5), mask=[0, 0, 0, 1, 0]) + t.set_fill_value(1000) assert t.fill_value == 1000 assert t.missing_value == 1000 t.missing_value = -99 assert t[2] == 2 t[3] = numpy.ma.masked assert t[3] is numpy.ma.masked - f = createVariable(numpy.ma.arange(5, typecode=numpy.float32), mask=[0,0,0,1,0]) - f2 = createVariable(numpy.ma.arange(5, typecode=numpy.float32), mask=[0,0,0,1,0]) + f = createVariable( + numpy.ma.arange(5, typecode=numpy.float32), mask=[0, 0, 0, 1, 0]) + f2 = createVariable( + numpy.ma.arange(5, typecode=numpy.float32), mask=[0, 0, 0, 1, 0]) f[3] = numpy.ma.masked assert f[3] is numpy.ma.masked assert numpy.ma.allclose(2.0, f[2]) @@ -910,6 +941,6 @@ if __name__ == '__main__': assert t.getdimattribute(0, 'name') == 'fudge' f2b = f2.getdimattribute(0, 'bounds') t.setdimattribute(0, 'bounds', f2b) - assert numpy.ma.allclose(f.getdimattribute(0,'bounds'), f2.getdimattribute(0,'bounds')) + assert numpy.ma.allclose( + f.getdimattribute(0, 'bounds'), f2.getdimattribute(0, 'bounds')) print "Transient Variable test passed ok." - diff --git a/Packages/cdms2/Lib/typeconv.py b/Packages/cdms2/Lib/typeconv.py index 0f2bd2c18..541785877 100644 --- a/Packages/cdms2/Lib/typeconv.py +++ b/Packages/cdms2/Lib/typeconv.py @@ -4,21 +4,23 @@ import numpy as np oldtype2dtype = {'1': np.dtype(np.byte), 's': np.dtype(np.short), -# 'i': np.dtype(np.intc), -# 'l': np.dtype(int), -# 'b': np.dtype(np.ubyte), + # 'i': np.dtype(np.intc), + # 'l': np.dtype(int), + # 'b': np.dtype(np.ubyte), 'w': np.dtype(np.ushort), 'u': np.dtype(np.uintc), -# 'f': np.dtype(np.single), -# 'd': np.dtype(float), -# 'F': np.dtype(np.csingle), -# 'D': np.dtype(complex), -# 'O': np.dtype(object), -# 'c': np.dtype('c'), + # 'f': np.dtype(np.single), + # 'd': np.dtype(float), + # 'F': np.dtype(np.csingle), + # 'D': np.dtype(complex), + # 'O': np.dtype(object), + # 'c': np.dtype('c'), None: np.dtype(int) - } + } # converts typecode=None to int + + def convtypecode(typecode, dtype=None): if dtype is None: try: @@ -28,8 +30,10 @@ def convtypecode(typecode, dtype=None): else: return dtype -#if both typecode and dtype are None +# if both typecode and dtype are None # return None + + def convtypecode2(typecode, dtype=None): if dtype is None: if typecode is None: @@ -45,10 +49,12 @@ def convtypecode2(typecode, dtype=None): _changedtypes = {'B': 'b', 'b': '1', 'h': 's', -## 'H': 'w', + # 'H': 'w', 'I': 'u'} + class _oldtypecodes(dict): + def __getitem__(self, obj): char = np.dtype(obj).char try: diff --git a/Packages/cdms2/Lib/variable.py b/Packages/cdms2/Lib/variable.py index 23650e3d8..f271acc1d 100644 --- a/Packages/cdms2/Lib/variable.py +++ b/Packages/cdms2/Lib/variable.py @@ -1,20 +1,20 @@ -## Automatically adapted for numpy.oldnumeric Aug 01, 2007 by +# Automatically adapted for numpy.oldnumeric Aug 01, 2007 by """ DatasetVariable: Dataset-based variables """ from cdms2 import Cdunif import numpy -import cdmsNode +from . import cdmsNode import cdtime import copy import os import sys -import cdmsobj -from cdmsobj import CdmsObj, getPathFromTemplate, Max32int -from avariable import AbstractVariable -from sliceut import * -from error import CDMSError +from . import cdmsobj +from .cdmsobj import CdmsObj, getPathFromTemplate, Max32int +from .avariable import AbstractVariable +from .sliceut import * +from .error import CDMSError InvalidGridElement = "Grid domain elements are not yet implemented: " InvalidRegion = "Invalid region: " @@ -24,44 +24,47 @@ TooManyPartitions = "Variable has too many partitioned axes, max is two: " WriteNotImplemented = "Dataset write operation not implemented" FileClosed = "Cannot read from closed file or dataset, variable: " + def timeindex(value, units, basetime, delta, delunits, calendar): """ Calculate (t - basetime)/delu where t = reltime(value, units) and delu is the time interval (delta, delunits) (e.g., 1 month). """ tval = cdtime.reltime(value, units) - tounits = "%s since %s"%(delunits, basetime) + tounits = "%s since %s" % (delunits, basetime) newval = tval.torel(tounits, calendar) - return int(newval.value/delta) + return int(newval.value / delta) + class DatasetVariable(AbstractVariable): - def __init__(self,parent,id, variableNode=None): + def __init__(self, parent, id, variableNode=None): """ "Variable (parent, variableNode=None)" variableNode is the variable tree node, if any. parent is the containing dataset instance. """ - AbstractVariable.__init__ (self, parent, variableNode) - val = self.__cdms_internals__ + ['domain','name_in_file'] + AbstractVariable.__init__(self, parent, variableNode) + val = self.__cdms_internals__ + ['domain', 'name_in_file'] self.___cdms_internals__ = val self.id = id self.domain = [] # Get self.name_in_file from the .xml file if present if not hasattr(self, 'name_in_file'): self.name_in_file = id - + # if self.attributes.has_key('name_in_file'): # self.name_in_file = self.attributes['name_in_file'] - if variableNode is not None: - self._numericType_ = cdmsNode.CdToNumericType.get(variableNode.datatype) + if variableNode is not None: + self._numericType_ = cdmsNode.CdToNumericType.get( + variableNode.datatype) else: self._numericType_ = numpy.float assert self.id is not None - - def __len__ (self): + + def __len__(self): "Length of first dimension" - if len(self.domain)>0: - (axis,start,length,true_length) = self.domain[0] + if len(self.domain) > 0: + (axis, start, length, true_length) = self.domain[0] else: length = 0 @@ -72,33 +75,34 @@ class DatasetVariable(AbstractVariable): # parentid = self.parent.id # else: # parentid = "**CLOSED**" -# return ""%(self.id, parentid, `self.shape`) +# return ""%(self.id, parentid, +# `self.shape`) def __getitem__(self, key): if self.parent is None: - raise CDMSError, FileClosed+str(self.id) + raise CDMSError(FileClosed + str(self.id)) return AbstractVariable.__getitem__(self, key) - + def getValue(self, squeeze=1): """Return the entire set of values.""" if self.parent is None: - raise CDMSError, FileClosed+self.id + raise CDMSError(FileClosed + self.id) return self.getSlice(Ellipsis, squeeze=squeeze) - + def __getslice__(self, low, high): if self.parent is None: - raise CDMSError, FileClosed+self.id + raise CDMSError(FileClosed + self.id) # Hack to prevent netCDF overflow error on 64-bit architectures high = min(Max32int, high) - + return AbstractVariable.__getslice__(self, low, high) def __setitem__(self, index, value): - raise CDMSError, WriteNotImplemented + raise CDMSError(WriteNotImplemented) def __setslice__(self, low, high, value): - raise CDMSError, WriteNotImplemented + raise CDMSError(WriteNotImplemented) def _getShape(self): return self.getShape() @@ -108,19 +112,19 @@ class DatasetVariable(AbstractVariable): return numpy.dtype(tc) def getShape(self): - shape=[] - for (axis,start,length,true_length) in self.domain: + shape = [] + for (axis, start, length, true_length) in self.domain: shape.append(length) return tuple(shape) - def typecode (self): - return numpy.dtype(self._numericType_).char + def typecode(self): + return numpy.dtype(self._numericType_).char def size(self): "Number of elements." n = 1 for k in self.shape: - n = k*n + n = k * n return n def initDomain(self, axisdict, griddict): @@ -133,9 +137,9 @@ class DatasetVariable(AbstractVariable): if domelem is None: domelem = griddict.get(dename) if grid is None: - raise CDMSError, NoSuchAxisOrGrid + dename + raise CDMSError(NoSuchAxisOrGrid + dename) else: - raise CDMSError, InvalidGridElement + dename + raise CDMSError(InvalidGridElement + dename) partlenstr = denode.getExternalAttr('partition_length') if partlenstr is not None: truelen = int(partlenstr) @@ -145,26 +149,27 @@ class DatasetVariable(AbstractVariable): # Get the template def getTemplate(self): - if hasattr(self,'template'): + if hasattr(self, 'template'): template = self.template - elif hasattr(self.parent,'template'): + elif hasattr(self.parent, 'template'): template = self.parent.template else: template = None return template - def getAxis (self, n): - if n < 0: n = n + self.rank() + def getAxis(self, n): + if n < 0: + n = n + self.rank() return self.domain[n][0] - def getDomain (self): + def getDomain(self): return self.domain # Get the paths associated with the interval region specified # by 'intervals'. This incorporates most of the logic of __getitem__, # without actually reading the data. - # - # 'specs' is a list of interval range specifications as defined + # + # 'specs' is a list of interval range specifications as defined # for getSlice. # # The function returns a list of tuples of the form (path,slicelist), @@ -176,11 +181,11 @@ class DatasetVariable(AbstractVariable): # f = Cdunif.CdunifFile(path,'r') # var = f.variables[self.name_in_file] # data = apply(var.getitem,slicelist) - # + # def getPaths(self, *specs, **keys): # Create an equivalent list of slices - speclist = self._process_specs (specs, keys) + speclist = self._process_specs(specs, keys) slicelist = self.specs2slices(speclist) # Generate the filelist @@ -190,20 +195,20 @@ class DatasetVariable(AbstractVariable): result = [] if partitionSlices is None: pass - elif npart==0: + elif npart == 0: filename, slicelist = partitionSlices if filename is not None: result.append((filename, tuple(slicelist))) - elif npart==1: + elif npart == 1: for filename, slicelist in partitionSlices: if filename is not None: result.append((filename, tuple(slicelist))) - elif npart==2: + elif npart == 2: for filelist in partitionSlices: for filename, slicelist in filelist: if filename is not None: result.append((filename, tuple(slicelist))) - + return result def genMatch(self, axis, interval, matchnames): @@ -217,34 +222,34 @@ class DatasetVariable(AbstractVariable): returns the modified matchnames tuple. """ if axis.isTime(): - if hasattr(self.parent,'cdms_filemap'): + if hasattr(self.parent, 'cdms_filemap'): start = interval[0] end = interval[1] else: # Use template method time0 = axis[interval[0]] - time1 = axis[interval[1]-1] - isabs = (axis.units.find(" as ")!=-1) + time1 = axis[interval[1] - 1] + isabs = (axis.units.find(" as ") != -1) if isabs: - start = cdtime.abstime(time0,axis.units) - end = cdtime.abstime(time1,axis.units) + start = cdtime.abstime(time0, axis.units) + end = cdtime.abstime(time1, axis.units) else: cal = axis.getCalendar() - start = cdtime.reltime(time0,axis.units).tocomp(cal) - end = cdtime.reltime(time1,axis.units).tocomp(cal) + start = cdtime.reltime(time0, axis.units).tocomp(cal) + end = cdtime.reltime(time1, axis.units).tocomp(cal) matchnames[1] = start matchnames[2] = end elif axis.isForecast(): start = axis.getValue()[interval[0]] - end = axis.getValue()[interval[1]-1] + end = axis.getValue()[interval[1] - 1] matchnames[5] = start matchnames[6] = end else: - if hasattr(self.parent,'cdms_filemap'): + if hasattr(self.parent, 'cdms_filemap'): start = interval[0] end = interval[1] else: start = int(axis[interval[0]]) - end = int(axis[interval[1]-1]) + end = int(axis[interval[1] - 1]) matchnames[3] = start matchnames[4] = end @@ -254,12 +259,13 @@ class DatasetVariable(AbstractVariable): """Lookup or generate the file path, depending on whether a filemap or template is present. """ - if hasattr(self.parent,'cdms_filemap'): + if hasattr(self.parent, 'cdms_filemap'): id, tstart, tend, levstart, levend, fcstart, fcend = matchnames - filename = self.parent._filemap_[(self.id, tstart, levstart, fcstart)] + filename = self.parent._filemap_[ + (self.id, tstart, levstart, fcstart)] # ... filemap uses dataset IDs else: - filename = getPathFromTemplate(template,matchnames) + filename = getPathFromTemplate(template, matchnames) return filename def getPartition(self, axis): @@ -268,7 +274,7 @@ class DatasetVariable(AbstractVariable): get the partition from the _varpart_ attribute, otherwise (for templating) use axis.partition. """ - if hasattr(self.parent,'cdms_filemap'): + if hasattr(self.parent, 'cdms_filemap'): if axis.isTime(): partition = self._varpart_[0] elif axis.isForecast(): @@ -279,7 +285,7 @@ class DatasetVariable(AbstractVariable): partition = axis.partition return partition - def expertPaths (self, slist): + def expertPaths(self, slist): """ expertPaths(self, slicelist) takes a list of slices, returns a 3-tuple: (npart, dimensionlist, partitionSlices) where: @@ -316,7 +322,7 @@ class DatasetVariable(AbstractVariable): # Handle rank-0 variables separately if self.rank() == 0: - matchnames = [realid,None,None,None,None,None,None] + matchnames = [realid, None, None, None, None, None, None] filename = self.getFilePath(matchnames, template) result = (0, (), (filename, [])) @@ -325,162 +331,164 @@ class DatasetVariable(AbstractVariable): # Find the number of partitioned axes npart = 0 ndim = 0 - for (axis,start,length,true_length) in self.domain: - if hasattr(axis,'partition'): - npart = npart+1 - if npart==1: + for (axis, start, length, true_length) in self.domain: + if hasattr(axis, 'partition'): + npart = npart + 1 + if npart == 1: part1 = axis npart1 = ndim - elif npart==2: + elif npart == 2: part2 = axis npart2 = ndim else: - raise CDMSError, TooManyPartitions + variable.id - ndim = ndim+1 + raise CDMSError(TooManyPartitions + variable.id) + ndim = ndim + 1 # If no partitioned axes, just read the data - if npart==0: - matchnames = [realid,None,None,None,None,None,None] + if npart == 0: + matchnames = [realid, None, None, None, None, None, None] filename = self.getFilePath(matchnames, template) result = (0, (), (filename, slicelist)) # If one partitioned axes: - elif npart==1: + elif npart == 1: # intersect the slice and partition for that axis slice1 = slicelist[npart1] - (axis,startelem,length,true_length) = self.domain[npart1] + (axis, startelem, length, true_length) = self.domain[npart1] partition = slicePartition(slice1, self.getPartition(axis)) - if partition==[]: + if partition == []: return (1, (npart1,), None) # For each (interval, partslice) in the partition: resultlist = [] (firstinterval, firstslice) = partition[0] prevhigh = firstinterval[0] - for (interval,partslice) in partition: + for (interval, partslice) in partition: # If the previous interval high is less than # the current interval low value, interpose # missing data. low = interval[0] - if prevhigh1, it might not intersect, # so don't interpose missing data in this case. if missing_slice is not None: slicelist[npart1] = missing_slice - resultlist.append((None,copy.copy(slicelist))) + resultlist.append((None, copy.copy(slicelist))) prevhigh = interval[1] # generate the filename - matchnames = [realid, None, None, None, None,None,None] + matchnames = [realid, None, None, None, None, None, None] matchnames = self.genMatch(axis, interval, matchnames) filename = self.getFilePath(matchnames, template) # adjust the partslice for the interval offset # and replace in the slice list - filestart = partslice.start-interval[0] - filestop = partslice.stop-interval[0] - fileslice = slice(filestart,filestop,partslice.step) + filestart = partslice.start - interval[0] + filestop = partslice.stop - interval[0] + fileslice = slice(filestart, filestop, partslice.step) slicelist[npart1] = fileslice - resultlist.append((filename,copy.copy(slicelist))) + resultlist.append((filename, copy.copy(slicelist))) - result = (1,(npart1,),resultlist) + result = (1, (npart1,), resultlist) # If two partitioned axes, 2-D version of previous case - if npart==2: + if npart == 2: slice1 = slicelist[npart1] slice2 = slicelist[npart2] - (axis1,startelem1,length1,true_length1) = self.domain[npart1] - (axis2,startelem2,length2,true_length2) = self.domain[npart2] + (axis1, startelem1, length1, true_length1) = self.domain[npart1] + (axis2, startelem2, length2, true_length2) = self.domain[npart2] partition1 = slicePartition(slice1, self.getPartition(axis1)) partition2 = slicePartition(slice2, self.getPartition(axis2)) - if partition1==[] or partition2==[]: - return (2, (npart1,npart2), None) + if partition1 == [] or partition2 == []: + return (2, (npart1, npart2), None) # For each (interval, partslice) in the partition: resultlist = [] (firstinterval1, firstslice1) = partition1[0] prevhigh1 = firstinterval1[0] - for (interval1,partslice1) in partition1: + for (interval1, partslice1) in partition1: # If the previous interval high is less than # the current interval low value, interpose # missing data. low = interval1[0] - if prevhigh1 Date: Wed, 27 Apr 2016 09:36:48 -0700 Subject: [PATCH 037/191] begining of adressing flake8 but giving up --- Packages/cdms2/Lib/restApi.py | 126 ++++------------------------ Packages/cdms2/Lib/selectors.py | 4 +- Packages/cdms2/Lib/slabinterface.py | 3 +- Packages/cdms2/Lib/tvariable.py | 26 +++--- Packages/cdms2/Lib/typeconv.py | 2 +- Packages/cdms2/Lib/variable.py | 15 +--- Packages/cdms2/Lib/xlink.py | 11 --- 7 files changed, 32 insertions(+), 155 deletions(-) delete mode 100644 Packages/cdms2/Lib/xlink.py diff --git a/Packages/cdms2/Lib/restApi.py b/Packages/cdms2/Lib/restApi.py index 0ee17424d..159d50112 100644 --- a/Packages/cdms2/Lib/restApi.py +++ b/Packages/cdms2/Lib/restApi.py @@ -1,4 +1,3 @@ -import cdms2 import urllib2 import xml.etree.ElementTree try: @@ -173,7 +172,7 @@ class esgfConnection(object): return val def __setitem__(self, key, value): - if not key in self.params.keys(): + if key not in self.params.keys(): raise self.EsgfObjectException( "Invalid key: %s, valid keys are: %s" % (repr(key), repr(self.params.keys()))) @@ -183,7 +182,7 @@ class esgfConnection(object): def _search(self, search="", searchType=None, stringType=False): if searchType is None: searchType = self.defaultSearchType - if not searchType in self.validSearchTypes: + if searchType not in self.validSearchTypes: raise self.EsgfObjectException( "Valid Search types are: %s" % repr(self.validSearchTypes)) @@ -226,14 +225,8 @@ class esgfConnection(object): # params[k]=self[k] for k in keys.keys(): - if k == "stringType": - stringType = keys[k] + if k in ["stringType", "type"]: continue - elif k == "type": - continue - # elif not k in self.searchableKeys: - # raise self.EsgfObjectException("Invalid key: %s, valid keys are: - # %s" % (repr(k),repr(self.params.keys()))) if keys[k] is not None: params[k] = keys[k] @@ -309,23 +302,18 @@ class esgfConnection(object): resps = self.request(**keys) stringType = keys.get("stringType", False) if stringType: - return resp + return resps datasets = [] for resp in resps: for r in resp[:]: if r.tag == "result": # Ok let's go thru these datasets for d in r[:]: - # print - # "************************************************" tmpkeys = {} for f in d[:]: k = f.get("name") tmpkeys[k] = self.extractTag(f) if tmpkeys["type"] == "Dataset": - datasetid = tmpkeys["id"] - # print datasetid,self.restPath - # print "KEYS FOR DATASET",keys.keys() datasets.append( esgfDataset(host=self.host, port=self.port, @@ -364,7 +352,7 @@ class esgfDataset(esgfConnection): tmp.replace(")s", ")")) elif "project" in keys and keys["project"] == "cmip5": self.datasetids = genutil.StringConstructor( - "%(project).%(product).%(institute).%(model).%(experiment).%(time_frequency).%(realm).%(cmor_table).%(ensemble)") + "%(project).%(product).%(institute).%(model).%(experiment).%(time_frequency).%(realm).%(cmor_table).%(ensemble)") # noqa else: self.datasetids = None if isinstance(datasetids, genutil.StringConstructor): @@ -393,38 +381,16 @@ class esgfDataset(esgfConnection): self.keys = self.params.keys self.items = self.params.items self.values = self.params.values - # self.id=self["id"] self.params["limit"] = limit self.params["offset"] = offset self.mapping = mapping - # print "SEARCHING DS:",originalKeys self.resp = None self.cacheTime = None -# self.search() -# self.remap() - - # Ok now we need to "map" this according to the user wishes - - # def mappedItems(): - # mapped=[] - # mapppoint=self.mapped - # for k in self.mapping.keys(): - # keys=[] - # level=[k,mappoint.keys()] - # mappoint + def _extractFiles(self, resp, **inKeys): # We need to stick in there the bit from Luca to fill in the matching # key from facet for now it's empty files = [] - skipped = [ - "type", - "title", - "timestamp", - "service", - "id", - "score", - "file_url", - "service_type"] for r in resp[:]: if r.tag == "result": for d in r[:][:]: @@ -433,66 +399,6 @@ class esgfDataset(esgfConnection): k = f.get("name") keys[k] = self.extractTag(f) if keys["type"] == "File": - # if self["id"]=="obs4MIPs.NASA-JPL.AIRS.mon": - # verbose=True - # else: - # verbose=False - # verbose=True - # if verbose: print "OK",keys["variable"],keys["file_id"],self["id"] - # if verbose: print "FILEIDS:",self.fileids - # if verbose: print "Fileids:",self.fileids.template - # if verbose: print "keys:",keys - # if self.fileids is not None: - # try: - # if verbose: print "file:",keys["file_id"],self.fileids.template - # k2 = self.fileids.reverse(keys["file_id"]) - # if verbose: print "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",k2 - # for k in k2.keys(): - # keys[k]=k2[k] - # except: - # if verbose: print "Failed:",ids[i].text,self.fileids.template - # pass - # if verbose: print "KEYS FOR FILE:",keys.keys() - # if verbose: print "INKEYS:",inKeys.keys() - # matched = True - # matchWithKeys = {} - # for k in self.keys(): - # if k in self.originalKeys.keys(): - # matchWithKeys[k]=self.originalKeys[k] - # else: - # matchWithKeys[k]=self[k] - # for s in skipped: - # try: - # matchWithKeys.pop(s) - # except: - # pass - # for k in inKeys.keys(): - # matchWithKeys[k]=inKeys[k] - # if verbose: print "matching:",matchWithKeys.keys() - # for k in keys.keys(): - # if k in matchWithKeys.keys(): - # if verbose: print "Testing:",k,keys[k] - # v = matchWithKeys[k] - # if isinstance(v,(str,int,float)): - # if verbose: print "\tComparing with:",v - # if v != keys[k]: - # matched = False - # if verbose: print "\t\tNOPE" - # break - # elif isinstance(v,list): - # if verbose: print "\tComparing with (and %i more):%s"%(len(v),v[0]),v - # if not keys[k] in v: - # matched = False - # if verbose: print "\t\tNOPE" - # break - # else: - # print "\twould compare %s with type: %s if I knew how to" % (str(v),type(v)) - # if verbose: print keys["file_id"],matched - # if matched : - # for k in self.keys(): - # if not k in keys.keys(): - # keys[k]=self[k] - # print "KEYS:",keys files.append(esgfFile(**keys)) return files @@ -514,7 +420,7 @@ class esgfDataset(esgfConnection): if os.path.isdir(target): target = os.path.join(target, "esgfDatasetsCache.pckl") if os.path.exists(target): - f = open(source) + f = open(target) # dict=eval(bz2.decompress(f.read())) dict = eval(f.read()) f.close() @@ -560,9 +466,9 @@ class esgfDataset(esgfConnection): stringType = keys.get("stringType", False) keys.update(self.originalKeys) st = "" - if not "limit" in keys: + if "limit" not in keys: keys["limit"] = [self["limit"]] - if not "offset" in keys: + if "offset" not in keys: keys["offset"] = [self["offset"]] for k in keys: if k in ["searchString", "stringType", ]: @@ -615,7 +521,8 @@ class esgfFiles(object): self.setMapping(mapping) self.remap() self.projects_dict = { - "CMIP5": "%(project).%(product).%(institute).%(model).%(experiment).%(time_frequency).%(realm).%(cmor_table).%(ensemble)"} + "CMIP5": "%(project).%(product).%(institute).%(model).%(experiment).%(time_frequency).%(realm).%(cmor_table).%(ensemble)" # noqa + } def __getitem__(self, item): if isinstance(item, int): @@ -654,7 +561,7 @@ class esgfFiles(object): self.mapping = self.datasetids else: for k in self.parent.keys(): - if not k in ["limit", "offset", "text"]: + if k not in ["limit", "offset", "text"]: self.mapping += "%%(%s)" % k else: self.mapping = mapping @@ -731,24 +638,21 @@ class esgfFiles(object): cont = f[k] if not isinstance(cont, (str, int, float)): break - if not cont in mappoint.keys(): + if cont not in mappoint.keys(): mappoint[cont] = {} elif k in self.parent.keys(): # if verbose: print tabs,k,f[k] nok += 1 cont = self[k] - if not cont in mappoint.keys(): + if cont not in mappoint.keys(): mappoint[cont] = {} elif isinstance(self.fileids, genutil.StringConstructor): try: mapid = self.fileids.reverse(self.parent.id) - # if verbose: - # print "MAPID:",k,mapid if k in mapid.keys(): - # if verbose: print tabs,k,mapid[k] nok += 1 cont = mapid[k] - if not cont in mappoint.keys(): + if cont not in mappoint.keys(): mappoint[cont] = {} except: break diff --git a/Packages/cdms2/Lib/selectors.py b/Packages/cdms2/Lib/selectors.py index 2a35705d1..9ec6c6721 100644 --- a/Packages/cdms2/Lib/selectors.py +++ b/Packages/cdms2/Lib/selectors.py @@ -1,6 +1,5 @@ """Classes to support easy selection of climate data""" -import cdtime from .axis import axisMatches from .error import CDMSError from .grid import AbstractRectGrid, defaultRegion, setRegionSpecs, LongitudeType, LatitudeType, TimeType, VerticalType @@ -203,7 +202,7 @@ class Selector: grid is not None or \ raw != 0 or \ result is variable: - # result is variable when there are no components, for example. + # result is variable when there are no components, for example. return result.subRegion(squeeze=squeeze, order=order, grid=grid, raw=raw) else: @@ -371,7 +370,6 @@ class positionalComponent (SelectorComponent): def specify(self, slab, axes, specifications, confined_by, aux): "Find the next unconfined axis and confine it." - n = 0 for i in range(len(axes)): if confined_by[i] is None: specifications[i] = self.v diff --git a/Packages/cdms2/Lib/slabinterface.py b/Packages/cdms2/Lib/slabinterface.py index f12738ee7..a0fc8910e 100644 --- a/Packages/cdms2/Lib/slabinterface.py +++ b/Packages/cdms2/Lib/slabinterface.py @@ -95,7 +95,7 @@ class Slab: a = self.getAxis(dim) result = [] for x in std_axis_attributes + a.attributes.keys(): - if not x in result: + if x not in result: result.append(x) return result @@ -192,7 +192,6 @@ class Slab: def cdms_bounds2cu_bounds(b): "Bounds are len(v) by 2 in cdms but len(v)+1 in cu" cub = numpy.ma.zeros(len(b) + 1, numpy.float32) - b1 = b.astype(numpy.float32) if len(b) > 1: if (b[0, 0] < b[0, 1]) == (b[0, 0] < b[-1, 0]): cub[0] = b[0, 0] diff --git a/Packages/cdms2/Lib/tvariable.py b/Packages/cdms2/Lib/tvariable.py index 9ebcca9c6..0a2b3cdd5 100644 --- a/Packages/cdms2/Lib/tvariable.py +++ b/Packages/cdms2/Lib/tvariable.py @@ -43,14 +43,14 @@ def fromJSON(jsn): dtype=a["_dtype"]), id=a["id"]) for k, v in a.iteritems(): - if not k in ["_values", "id", "_dtype"]: + if k not in ["_values", "id", "_dtype"]: setattr(ax, k, v) axes.append(ax) # Now prep the variable V = createVariable(D["_values"], id=D["id"], typecode=D["_dtype"]) V.setAxisList(axes) for k, v in D.iteritems(): - if not k in ["id", "_values", "_axes", "_grid", "_fill_value", "_dtype", ]: + if k not in ["id", "_values", "_axes", "_grid", "_fill_value", "_dtype", ]: setattr(V, k, v) V.set_fill_value(D["_fill_value"]) return V @@ -103,12 +103,10 @@ class TransientVariable(AbstractVariable, numpy.ma.MaskedArray): try: for nm, val in obj.__dict__.items(): if nm[0] == '_': -# print nm pass -# self.__dict__[nm]=val else: setattr(self, nm, val) - except Exception as err: + except Exception: pass id = getattr(self, 'id', None) if id is None: @@ -193,14 +191,12 @@ class TransientVariable(AbstractVariable, numpy.ma.MaskedArray): grid = grid.reconcile( axes) # Make sure grid and axes are consistent - ncopy = (copy != 0) - # Initialize the geometry if grid is not None: copyaxes = 0 # Otherwise grid axes won't match domain. if axes is not None: self.initDomain(axes, copyaxes=copyaxes) - # Note: clobbers the grid, so set the grid after. + # Note: clobbers the grid, so set the grid after. if grid is not None: self.setGrid(grid) @@ -277,7 +273,7 @@ class TransientVariable(AbstractVariable, numpy.ma.MaskedArray): if mask is None: try: mask = data.mask - except Exception as err: + except Exception: mask = numpy.ma.nomask # Handle the case where ar[i:j] returns a single masked value @@ -359,7 +355,7 @@ class TransientVariable(AbstractVariable, numpy.ma.MaskedArray): def getDomain(self): for i in range(self.rank()): if self.__domain[i] is None: - junk = self.getAxis(i) # will force a fill in + self.getAxis(i) # will force a fill in return self.__domain def getAxis(self, n): @@ -442,7 +438,7 @@ class TransientVariable(AbstractVariable, numpy.ma.MaskedArray): maresult = numpy.ma.MaskedArray.astype(self, tc) return TransientVariable( maresult, copy=0, axes=self.getAxisList(), fill_value=self.fill_value, - attributes=self.attributes, id=self.id, grid=self.getGrid()) + attributes=self.attributes, id=self.id, grid=self.getGrid()) def setMaskFromGridMask(self, mask, gridindices): """Set the mask for self, given a grid mask and the variable domain @@ -626,12 +622,11 @@ class TransientVariable(AbstractVariable, numpy.ma.MaskedArray): sphereRadius: radius of the earth maxElev: maximum elevation for representation on the sphere """ - from . import mvSphereMesh from . import mvVTKSGWriter from . import mvVsWriter try: # required by mvVsWriter - import tables + import tables # noqa except: # fall back format = 'VTK' @@ -739,8 +734,7 @@ class TransientVariable(AbstractVariable, numpy.ma.MaskedArray): # given direction, a 1 represents a layer of # thickness ghostWidth on the high index side, # -1 on the low index side. - winId = tuple([0 for i in range(dim)] - + [drect] + + winId = tuple([0 for i in range(dim)] + [drect] + [0 for i in range(dim + 1, ndims)]) slce = slice(0, ghostWidth) @@ -832,7 +826,7 @@ class TransientVariable(AbstractVariable, numpy.ma.MaskedArray): """ ndims = len(self.shape) - slab = [ slice(0, None) for i in range(dim) ] \ + slab = [slice(0, None) for i in range(dim)] \ + [slce] + \ [slice(0, None) for i in range(dim + 1, ndims)] return tuple(slab) diff --git a/Packages/cdms2/Lib/typeconv.py b/Packages/cdms2/Lib/typeconv.py index 541785877..e63ad64d3 100644 --- a/Packages/cdms2/Lib/typeconv.py +++ b/Packages/cdms2/Lib/typeconv.py @@ -1,6 +1,6 @@ +import numpy as np __all__ = ['oldtype2dtype', 'convtypecode', 'convtypecode2', 'oldtypecodes'] -import numpy as np oldtype2dtype = {'1': np.dtype(np.byte), 's': np.dtype(np.short), diff --git a/Packages/cdms2/Lib/variable.py b/Packages/cdms2/Lib/variable.py index f271acc1d..c96dd5e21 100644 --- a/Packages/cdms2/Lib/variable.py +++ b/Packages/cdms2/Lib/variable.py @@ -3,17 +3,13 @@ """ DatasetVariable: Dataset-based variables """ -from cdms2 import Cdunif import numpy from . import cdmsNode import cdtime import copy -import os -import sys -from . import cdmsobj -from .cdmsobj import CdmsObj, getPathFromTemplate, Max32int +from .cdmsobj import getPathFromTemplate, Max32int from .avariable import AbstractVariable -from .sliceut import * +from .sliceut import * # noqa from .error import CDMSError InvalidGridElement = "Grid domain elements are not yet implemented: " @@ -335,10 +331,8 @@ class DatasetVariable(AbstractVariable): if hasattr(axis, 'partition'): npart = npart + 1 if npart == 1: - part1 = axis npart1 = ndim elif npart == 2: - part2 = axis npart2 = ndim else: raise CDMSError(TooManyPartitions + variable.id) @@ -476,7 +470,7 @@ class DatasetVariable(AbstractVariable): # Handle negative slices revlist = [] - # Slices to apply to result if reversals needed + # Slices to apply to result if reversals needed slist = [] # Slices with positive strides haveReversals = 0 # True iff result array needs reversing i = 0 @@ -500,7 +494,6 @@ class DatasetVariable(AbstractVariable): for i in range(len(self.domain)): if self.domain[i][0].isForecast(): fci = i - fcv = initslist[i].start break # If no intersection, return an 'empty' array. @@ -536,7 +529,7 @@ class DatasetVariable(AbstractVariable): result = self._returnArray( var.getitem( *tuple(slicelist[0:fci] + slicelist[fci + 1:])), - 0) + 0) # But the result still needs an index in the forecast direction, # which is simple to do because there is only one forecast # per file: diff --git a/Packages/cdms2/Lib/xlink.py b/Packages/cdms2/Lib/xlink.py deleted file mode 100644 index 6270a7509..000000000 --- a/Packages/cdms2/Lib/xlink.py +++ /dev/null @@ -1,11 +0,0 @@ -""" -CDMS Xlink objects - pointers to other objects -""" - - -class Xlink(CdmsObj): - - def __init__(self, xlinkNode=None): - assert xlinkNode is None or xlinkNode.tag == 'xlink',\ - 'Node is not a link node' - CdmsObj.__init__(self, xlinkNode) -- GitLab From 995fa79e87d50986eb3bc5a976d0c47d3186239a Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Thu, 28 Apr 2016 10:08:15 -0700 Subject: [PATCH 038/191] Update VTKPlots.py --- Packages/vcs/vcs/VTKPlots.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Packages/vcs/vcs/VTKPlots.py b/Packages/vcs/vcs/VTKPlots.py index 4d870cd15..8cfe83a28 100644 --- a/Packages/vcs/vcs/VTKPlots.py +++ b/Packages/vcs/vcs/VTKPlots.py @@ -755,7 +755,10 @@ class VTKVCSBackend(object): plot.onClosing(cell) def plotContinents(self, wc, projection, wrap, vp, priority, **kargs): - contData = vcs2vtk.prepContinents(self.canvas._continentspath()) + continents_path = self.canvas._continentspath() + if continents_path is None: + return (None, 1, 1) + contData = vcs2vtk.prepContinents(continents_path) contMapper = vtk.vtkPolyDataMapper() contMapper.SetInputData(contData) contActor = vtk.vtkActor() -- GitLab From 6ad67a3f9dcfa3b10cb1579b9a17087a1fbf55fe Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Thu, 28 Apr 2016 14:14:37 -0700 Subject: [PATCH 039/191] Added test --- testing/vcs/CMakeLists.txt | 8 +++++- testing/vcs/test_vcs_no_continents.py | 38 +++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 testing/vcs/test_vcs_no_continents.py diff --git a/testing/vcs/CMakeLists.txt b/testing/vcs/CMakeLists.txt index a5faf6e24..7024dd66a 100644 --- a/testing/vcs/CMakeLists.txt +++ b/testing/vcs/CMakeLists.txt @@ -1016,13 +1016,19 @@ cdat_add_test(test_vcs_init_open_sizing "${PYTHON_EXECUTABLE}" ${cdat_SOURCE_DIR}/testing/vcs/test_vcs_init_open_sizing.py ) -# Rename baseline +## Rename baseline cdat_add_test(test_vcs_matplotlib_colormap "${PYTHON_EXECUTABLE}" ${cdat_SOURCE_DIR}/testing/vcs/test_vcs_matplotlib_colormap.py ${BASELINE_DIR}/test_vcs_matplotlib_colormap.png ) +cdat_add_test(test_vcs_no_continents + "${PYTHON_EXECUTABLE}" + ${cdat_SOURCE_DIR}/testing/vcs/test_vcs_no_continents.py + ${BASELINE_DIR}/test_vcs_no_continents.png +) + add_subdirectory(vtk_ui) add_subdirectory(editors) diff --git a/testing/vcs/test_vcs_no_continents.py b/testing/vcs/test_vcs_no_continents.py new file mode 100644 index 000000000..03630d457 --- /dev/null +++ b/testing/vcs/test_vcs_no_continents.py @@ -0,0 +1,38 @@ +import cdms2 +import os +import sys +import vcs + +# Load the clt data: +dataFile = cdms2.open(os.path.join(vcs.sample_data, "clt.nc")) +clt = dataFile("clt") +clt = clt(latitude=(-90.0, 90.0), longitude=(-180., 175.), squeeze=1, + time=('1979-1-1 0:0:0.0', '1988-12-1 0:0:0.0')) + +# Initialize canvas: +canvas = vcs.init() +canvas.setantialiasing(0) +canvas.setbgoutputdimensions(1200,1091,units="pixels") +canvas.drawlogooff() + +t1 = vcs.createtemplate() +t1.scale(.5, "y") +t1.move(-.15, "y") +t2 = vcs.createtemplate(source=t1.name) +t2.move(.5, 'y') + +canvas.plot(clt, t1, continents=0, bg=True) +canvas.plot(clt, t2, continents=1, bg=True) + +# Load the image testing module: +testingDir = os.path.join(os.path.dirname(__file__), "..") +sys.path.append(testingDir) +import checkimage + +# Create the test image and compare: +baseline = sys.argv[1] +testFile = "test_vcs_no_continents.png" +canvas.png(testFile) +ret = checkimage.check_result_image(testFile, baseline, + checkimage.defaultThreshold) +sys.exit(ret) -- GitLab From 9e3f9eeed01503090890e4ee9f3b9a3e52768a4d Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Mon, 9 May 2016 15:42:19 -0700 Subject: [PATCH 040/191] Fixed failing baselines --- Packages/vcs/vcs/boxfill.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Packages/vcs/vcs/boxfill.py b/Packages/vcs/vcs/boxfill.py index e17145437..4003606c9 100755 --- a/Packages/vcs/vcs/boxfill.py +++ b/Packages/vcs/vcs/boxfill.py @@ -767,8 +767,8 @@ class Gfb(object): if dx == 0: high_end += .00001 return [low_end, high_end] - - contourLevels = numpy.arange(low_end, high_end + dx, dx) + float_epsilon = numpy.finfo(numpy.float32).eps + contourLevels = numpy.arange(low_end, high_end + float_epsilon, dx) return contourLevels @@ -788,9 +788,10 @@ class Gfb(object): return vcs.mklabels(scale) else: # Create our own scale - dx = (self.level_2 - self.level_1) / float(len(scale)) + dx = (self.level_2 - self.level_1) / float(len(scale) - 1) real_values = [self.level_1, self.level_2] - levels = numpy.arange(levels[0], levels[-1] + dx, dx) + float_epsilon = numpy.finfo(numpy.float32).eps + levels = numpy.arange(levels[0], levels[-1] + float_epsilon, dx) else: real_values = levels -- GitLab From 08d3eba0f2ae9230343f4838ec8db1ab09a67c4b Mon Sep 17 00:00:00 2001 From: Dan Lipsa Date: Fri, 22 Apr 2016 11:52:46 -0400 Subject: [PATCH 041/191] ENH #1881: Add plot_based_dual_grid option to plot(). Traditionally, we created a point or cell dataset based on the plot requested. For isofill, isoline and vector we created point datasets, for boxfill and meshfill we created cell datasets. We keep this behavior for backward compatibility but we add a parameter plot_based_dual_grid to plot(). If this parameter is missing or it is True, we have the traditional behavior. If this parameter is False, we create the dataset that is specified in the file, regardless of the plot requested. --- Packages/cdms2/Lib/avariable.py | 15 +- Packages/cdms2/Lib/axis.py | 97 +++++-- Packages/cdms2/Lib/tvariable.py | 5 +- Packages/vcs/vcs/Canvas.py | 6 +- Packages/vcs/vcs/vcs2vtk.py | 274 +++++++------------- Packages/vcs/vcs/vcsvtk/boxfillpipeline.py | 6 +- Packages/vcs/vcs/vcsvtk/isofillpipeline.py | 27 +- Packages/vcs/vcs/vcsvtk/isolinepipeline.py | 32 +-- Packages/vcs/vcs/vcsvtk/meshfillpipeline.py | 11 +- Packages/vcs/vcs/vcsvtk/pipeline2d.py | 55 +++- Packages/vcs/vcs/vcsvtk/vectorpipeline.py | 33 ++- 11 files changed, 260 insertions(+), 301 deletions(-) diff --git a/Packages/cdms2/Lib/avariable.py b/Packages/cdms2/Lib/avariable.py index dd2a2792d..f15d7a069 100644 --- a/Packages/cdms2/Lib/avariable.py +++ b/Packages/cdms2/Lib/avariable.py @@ -363,6 +363,16 @@ class AbstractVariable(CdmsObj, Slab): if axisMatches(self.getAxis(i), axis_spec): return i return -1 + + def hasCellData(self): + ''' + If any of the variable's axis has explicit bounds, we have cell data + otherwise we have point data. + ''' + for axis in self.getAxisList(): + if (axis.getExplicitBounds() is not None): + return True + return False def getAxisListIndex (self, axes=None, omit=None, order=None): """Return a list of indices of axis objects; @@ -511,7 +521,6 @@ class AbstractVariable(CdmsObj, Slab): return result - # Get an order string, such as "tzyx" def getOrder(self, ids=0): """getOrder(ids=0) returns the order string, such as tzyx. @@ -915,7 +924,9 @@ class AbstractVariable(CdmsObj, Slab): else: delta_beg_wrap_dimvalue = ncyclesrev*cycle - axis.setBounds(axis.getBounds() - delta_beg_wrap_dimvalue) + isGeneric = [False] + b = axis.getBounds(isGeneric) - delta_beg_wrap_dimvalue + axis.setBounds(b, isGeneric=isGeneric[0]) axis[:]= (axis[:] - delta_beg_wrap_dimvalue).astype(axis.typecode()) diff --git a/Packages/cdms2/Lib/axis.py b/Packages/cdms2/Lib/axis.py index 703c0e938..209fbda42 100644 --- a/Packages/cdms2/Lib/axis.py +++ b/Packages/cdms2/Lib/axis.py @@ -105,8 +105,8 @@ def getAutoBounds(): return _autobounds # Create a transient axis -def createAxis(data, bounds=None, id=None, copy=0): - return TransientAxis(data, bounds, id, copy=copy) +def createAxis(data, bounds=None, id=None, copy=0, genericBounds=False): + return TransientAxis(data, bounds=bounds, id=id, copy=copy, genericBounds=genericBounds) # Generate a Gaussian latitude axis, north-to-south def createGaussianAxis(nlat): @@ -959,13 +959,41 @@ class AbstractAxis(CdmsObj): def isLinear(self): raise CDMSError, MethodNotImplemented - def getBounds(self): + def getBounds(self, isGeneric=None): + ''' + isGeneric is a list with one boolean which says if the bounds + are read from file (False) or generated (True) + ''' raise CDMSError, MethodNotImplemented - # Return None if not explicitly defined def getExplicitBounds(self): + ''' + Return None if not explicitly defined + This is a way to determine if attributes are defined at cell + or at point level. If this function returns None attributes are + defined at points, otherwise they are defined at cells + ''' raise CDMSError, MethodNotImplemented + def getBoundsForDualGrid(self, dualGrid): + ''' + dualGrid changes the type of dataset from the current type to the dual. + So, if we have a point dataset we switch to a cell dataset and viceversa. + ''' + explicitBounds = self.getExplicitBounds() + if (explicitBounds is None): + # point data + if (dualGrid): + return self.getBounds() + else: + return None + else: + # cell data + if (dualGrid): + return None + else: + return explicitBounds + def setBounds(self, bounds): raise CDMSError, MethodNotImplemented @@ -1279,7 +1307,8 @@ class AbstractAxis(CdmsObj): The stride k can be positive or negative. Wraparound is supported for longitude dimensions or those with a modulus attribute. """ - fullBounds = self.getBounds() + isGeneric = [False] + fullBounds = self.getBounds(isGeneric) _debug=0 _debugprefix="SS__XX subaxis " @@ -1359,7 +1388,7 @@ class AbstractAxis(CdmsObj): else: bounds = None - newaxis = TransientAxis(data, bounds, id=self.id, copy=1) + newaxis = TransientAxis(data, bounds, id=self.id, copy=1, genericBounds=isGeneric[0]) if self.isLatitude(): newaxis.designateLatitude() if self.isLongitude(): newaxis.designateLongitude() @@ -1440,17 +1469,18 @@ class AbstractAxis(CdmsObj): """clone (self, copyData=1) Return a copy of self as a transient axis. If copyData is 1, make a separate copy of the data.""" - b = self.getBounds() + isGeneric = [False] + b = self.getBounds(isGeneric) if copyData==1: mycopy = createAxis(copy.copy(self[:])) else: mycopy = createAxis(self[:]) mycopy.id = self.id try: - mycopy.setBounds(b) + mycopy.setBounds(b, isGeneric=isGeneric[0]) except CDMSError: b = mycopy.genGenericBounds() - mycopy.setBounds(b) + mycopy.setBounds(b, isGeneric=False) for k, v in self.attributes.items(): setattr(mycopy, k, v) return mycopy @@ -1570,7 +1600,13 @@ class Axis(AbstractAxis): return self._node_.dataRepresent==cdmsNode.CdLinear # Return the bounds array, or generate a default if autoBounds mode is on - def getBounds(self): + def getBounds(self, isGeneric=None): + ''' + If isGeneric is a list with one element, we set its element to True if the + bounds were generated and False if bounds were read from the file. + ''' + if (isGeneric): + isGeneric[0] = False boundsArray = self.getExplicitBounds() try: self.validateBounds(boundsArray) @@ -1578,6 +1614,8 @@ class Axis(AbstractAxis): boundsArray = None abopt = getAutoBounds() if boundsArray is None and (abopt==1 or (abopt==2 and (self.isLatitude() or self.isLongitude()))) : + if (isGeneric): + isGeneric[0] = True boundsArray = self.genGenericBounds() return boundsArray @@ -1609,7 +1647,10 @@ class Axis(AbstractAxis): # In-memory coordinate axis class TransientAxis(AbstractAxis): axis_count = 0 - def __init__(self, data, bounds=None, id=None, attributes=None, copy=0): + def __init__(self, data, bounds=None, id=None, attributes=None, copy=0, genericBounds=False): + ''' + genericBounds specify if bounds were generated (True) or read from a file (False) + ''' AbstractAxis.__init__(self, None, None) if id is None: TransientAxis.axis_count = TransientAxis.axis_count + 1 @@ -1646,7 +1687,8 @@ class TransientAxis(AbstractAxis): self._data_ = numpy.array(data) self._doubledata_ = None - self.setBounds(bounds) + self._genericBounds_ = genericBounds + self.setBounds(bounds, isGeneric=genericBounds) def __getitem__(self, key): return self._data_[key] @@ -1663,10 +1705,15 @@ class TransientAxis(AbstractAxis): def __len__(self): return len(self._data_) - def getBounds(self): + def getBounds(self, isGeneric=None): + if (isGeneric): + isGeneric[0] = self._genericBounds_ if self._bounds_ is not None: return copy.copy(self._bounds_) elif (getAutoBounds()==1 or (getAutoBounds()==2 and (self.isLatitude() or self.isLongitude()))): + if (isGeneric): + isGeneric[0] = True + self._genericBounds_ = True return self.genGenericBounds() else: return None @@ -1675,14 +1722,17 @@ class TransientAxis(AbstractAxis): return self._data_ def getExplicitBounds(self): - return copy.copy(self._bounds_) + if (self._genericBounds_): + return None + else: + return copy.copy(self._bounds_) # Set bounds. The persistent argument is for compatibility with # persistent versions, is ignored. Same for boundsid and index. # # mf 20010308 - add validate key word, by default do not validate - # - def setBounds(self, bounds, persistent=0, validate=0, index=None, boundsid=None): + # isGeneric is False if bounds were generated, True if they were read from a file + def setBounds(self, bounds, persistent=0, validate=0, index=None, boundsid=None, isGeneric=False): if bounds is not None: if isinstance(bounds, numpy.ma.MaskedArray): bounds = numpy.ma.filled(bounds) @@ -1700,9 +1750,11 @@ class TransientAxis(AbstractAxis): bounds2[:,1]=bounds[1::] bounds=bounds2 self._bounds_ = copy.copy(bounds) + self._genericBounds_ = isGeneric else: if (getAutoBounds()==1 or (getAutoBounds()==2 and (self.isLatitude() or self.isLongitude()))): self._bounds_ = self.genGenericBounds() + self._genericBounds_ = True else: self._bounds_ = None @@ -1745,7 +1797,7 @@ class TransientVirtualAxis(TransientAxis): "Return true iff coordinate values are implicitly defined." return 1 - def setBounds(self, bounds): + def setBounds(self, bounds, isGeneric=False): "No boundaries on virtual axes" self._bounds_ = None @@ -1953,13 +2005,19 @@ class FileAxis(AbstractAxis): return 0 # All file axes are vector representation # Return the bounds array, or generate a default if autobounds mode is set - def getBounds(self): + # If isGeneric is a list with one element, we set its element to True if the + # bounds were generated and False if bounds were read from the file. + def getBounds(self, isGeneric=None): + if (isGeneric): + isGeneric[0] = False boundsArray = self.getExplicitBounds() try: boundsArray = self.validateBounds(boundsArray) except Exception,err: boundsArray = None if boundsArray is None and (getAutoBounds()==1 or (getAutoBounds()==2 and (self.isLatitude() or self.isLongitude()))): + if (isGeneric): + isGeneric[0] = True boundsArray = self.genGenericBounds() return boundsArray @@ -1989,7 +2047,8 @@ class FileAxis(AbstractAxis): # index in the extended dimension (default is index=0). # If the bounds variable is new, use the name boundsid, or 'bounds_' # if unspecified. - def setBounds(self, bounds, persistent=0, validate=0, index=None, boundsid=None): + # isGeneric is only used for TransientAxis + def setBounds(self, bounds, persistent=0, validate=0, index=None, boundsid=None, isGeneric=False): if persistent: if index is None: if validate: diff --git a/Packages/cdms2/Lib/tvariable.py b/Packages/cdms2/Lib/tvariable.py index 27cab8156..152875adf 100644 --- a/Packages/cdms2/Lib/tvariable.py +++ b/Packages/cdms2/Lib/tvariable.py @@ -384,8 +384,9 @@ class TransientVariable(AbstractVariable,numpy.ma.MaskedArray): if n < 0: n = n + self.rank() if not isinstance(axis, AbstractAxis): raise CDMSError,"copydimension, other not an axis." - b = axis.getBounds() - mycopy = createAxis(axis[:], b) + isGeneric = [False] + b = axis.getBounds(isGeneric) + mycopy = createAxis(axis[:], b, genericBounds=isGeneric[0]) mycopy.id = axis.id for k, v in axis.attributes.items(): setattr(mycopy, k, v) diff --git a/Packages/vcs/vcs/Canvas.py b/Packages/vcs/vcs/Canvas.py index d98270c55..cee91f99d 100644 --- a/Packages/vcs/vcs/Canvas.py +++ b/Packages/vcs/vcs/Canvas.py @@ -2333,7 +2333,11 @@ Options::: # bunch of plots in a row) display_name = "__display_123" # VCS Display plot name (used to prevent duplicate display plots) ratio = 1.5|"autot"|"auto" # Ratio of height/width for the plot; autot and auto will choose a - # "good" ratio for you. + # "good" ratio for you. + plot_based_dual_grid = True | False # Plot the actual grid or the dual grid based on what is + # needed by the plot: isofill, isoline, vector need + # point attributes, boxfill and meshfill need cell attributes + # The default is True (if the parameter is not specified). Graphics Output in Background Mode: bg = 0|1 # if ==1, create images in the background (Don't display the VCS Canvas) diff --git a/Packages/vcs/vcs/vcs2vtk.py b/Packages/vcs/vcs/vcs2vtk.py index d6c449b05..86cfcfd0a 100644 --- a/Packages/vcs/vcs/vcs2vtk.py +++ b/Packages/vcs/vcs/vcs2vtk.py @@ -180,142 +180,48 @@ def handleProjectionEdgeCases(projection, data): return data -def genGridOnPoints(data1, gm, deep=True, grid=None, geo=None, - data2=None): - continents = False - projection = vcs.elements["projection"][gm.projection] - xm, xM, ym, yM = None, None, None, None - useStructuredGrid = True - - data1 = handleProjectionEdgeCases(projection, data1) - if data2 is not None: - data2 = handleProjectionEdgeCases(projection, data2) - - try: - g = data1.getGrid() - if grid is None: - x = g.getLongitude()[:] - y = g.getLatitude()[:] - xm = x[0] - xM = x[-1] - ym = y[0] - yM = y[-1] - continents = True - wrap = [0, 360] - # Ok need unstrctured grid - if isinstance(g, cdms2.gengrid.AbstractGenericGrid): - useStructuredGrid = False - except: - # hum no grid that's much easier - wrap = None - if grid is None: - x = data1.getAxis(-1)[:] - y = data1.getAxis(-2)[:] - xm = x[0] - xM = x[-1] - ym = y[0] - yM = y[-1] - - if grid is None: - if x.ndim == 1: - y = y[:, numpy.newaxis] * numpy.ones(x.shape)[numpy.newaxis, :] - x = x[numpy.newaxis, :] * numpy.ones(y.shape) - x = x.flatten() - y = y.flatten() - sh = list(x.shape) - sh.append(1) - x = numpy.reshape(x, sh) - y = numpy.reshape(y, sh) - # Ok we have our points in 2D let's create unstructured points grid - if xm is None: - xm = x.min() - if xM is None: - xM = x.max() - if ym is None: - ym = y.min() - if yM is None: - yM = y.max() - z = numpy.zeros(x.shape) - m3 = numpy.concatenate((x, y), axis=1) - m3 = numpy.concatenate((m3, z), axis=1) - deep = True - pts = vtk.vtkPoints() - # Convert nupmy array to vtk ones - ppV = numpy_to_vtk_wrapper(m3, deep=deep) - pts.SetData(ppV) - xm, xM, ym, yM, tmp, tmp2 = pts.GetBounds() - else: - xm, xM, ym, yM, tmp, tmp2 = grid.GetPoints().GetBounds() - vg = grid - oldpts = pts - if geo is None: - bounds = pts.GetBounds() - xm, xM, ym, yM = [bounds[0], bounds[1], bounds[2], bounds[3]] - # We use zooming feature (gm.datawc) for linear and polar projections. - # We use wrapped coordinates for doing the projection - # such that parameters like the central meridian are set correctly. - if (gm.g_name == 'Gfm'): - # axes are not lon/lat for meshfill - wc = [gm.datawc_x1, gm.datawc_x2, gm.datawc_y1, gm.datawc_y2] - else: - wc = vcs.utils.getworldcoordinates(gm, - data1.getAxis(-1), - data1.getAxis(-2)) - geo, geopts = project(pts, projection, getWrappedBounds( - wc, [xm, xM, ym, yM], wrap)) - pts = geopts - # Sets the vertices into the grid - if grid is None: - if useStructuredGrid: - vg = vtk.vtkStructuredGrid() - vg.SetDimensions(data1.shape[1], data1.shape[0], 1) - else: - vg = vtk.vtkUnstructuredGrid() - vg.SetPoints(oldpts) - vg.SetPoints(pts) - else: - vg = grid - scalar = numpy_to_vtk_wrapper(data1.filled(0.).flat, - deep=False) - scalar.SetName("scalar") - vg.GetPointData().SetScalars(scalar) - out = {"vtk_backend_grid": vg, - "xm": xm, - "xM": xM, - "ym": ym, - "yM": yM, - "continents": continents, - "wrap": wrap, - "geo": geo, - "data": data1, - "data2": data2 - } - return out - - -# Returns the bounds list for 'axis'. If axis has n elements the -# bounds list will have n+1 elements -def getBoundsList(axis): - bounds = numpy.zeros(len(axis) + 1) - try: - axisBounds = axis.getBounds() +def getBoundsList(axis, hasCellData, dualGrid): + ''' + Returns the bounds list for 'axis'. If axis has n elements the + bounds list will have n+1 elements + If there are not explicit bounds in the file we return None + ''' + needsCellData = (hasCellData != dualGrid) + axisBounds = axis.getBoundsForDualGrid(dualGrid) + # we still have to generate bounds for non lon-lat axes, because + # the default in axis.py is 2 (generate bounds only for lat/lon axis) + # this is used for non lon-lat plots - by default numpy arrays are POINT data + if (not axis.isLatitude() and not axis.isLongitude() and needsCellData): + axisBounds = axis.genGenericBounds() + if (axisBounds is not None): + bounds = numpy.zeros(len(axis) + 1) if (axis[0] < axis[-1]): # axis is increasing - bounds[:len(axis)] = axisBounds[:, 0] - bounds[len(axis)] = axisBounds[-1, 1] + if (axisBounds[0][0] < axisBounds[0][1]): + # interval is increasing + bounds[:len(axis)] = axisBounds[:, 0] + bounds[len(axis)] = axisBounds[-1, 1] + else: + # interval is decreasing + bounds[:len(axis)] = axisBounds[:, 1] + bounds[len(axis)] = axisBounds[-1, 0] else: # axis is decreasing - bounds[:len(axis)] = axisBounds[:, 1] - bounds[len(axis)] = axisBounds[-1, 0] - except Exception: - # No luck we have to generate bounds ourselves - bounds[1:-1] = (axis[:-1] + axis[1:]) / 2. - bounds[0] = axis[0] - (axis[1] - axis[0]) / 2. - bounds[-1] = axis[-1] + (axis[-1] - axis[-2]) / 2. - return bounds + if (axisBounds[0][0] < axisBounds[0][1]): + # interval is increasing + bounds[:len(axis)] = axisBounds[:, 1] + bounds[len(axis)] = axisBounds[-1, 0] + else: + # interval is decreasing + bounds[:len(axis)] = axisBounds[:, 0] + bounds[len(axis)] = axisBounds[-1, 1] + return bounds + else: + return None -def genGrid(data1, data2, gm, deep=True, grid=None, geo=None): +def genGrid(data1, data2, gm, deep=True, grid=None, geo=None, genVectors=False, + dualGrid=False): continents = False wrap = None m3 = None @@ -325,6 +231,8 @@ def genGrid(data1, data2, gm, deep=True, grid=None, geo=None): projection = vcs.elements["projection"][gm.projection] data1 = handleProjectionEdgeCases(projection, data1) + if data2 is not None: + data2 = handleProjectionEdgeCases(projection, data2) try: # First try to see if we can get a mesh out of this g = data1.getGrid() @@ -388,6 +296,7 @@ def genGrid(data1, data2, gm, deep=True, grid=None, geo=None): # Ok a simple structured grid is enough if grid is None: vg = vtk.vtkStructuredGrid() + hasCellData = data1.hasCellData() if g is not None: # Ok we have grid continents = True @@ -406,38 +315,49 @@ def genGrid(data1, data2, gm, deep=True, grid=None, geo=None): lon = data1.getAxis(-1) lat = data1.getAxis(-2) # Ok let's try to get the bounds - lon2 = getBoundsList(lon) - lat2 = getBoundsList(lat) + lon2 = getBoundsList(lon, hasCellData, dualGrid) + lat2 = getBoundsList(lat, hasCellData, dualGrid) + if (lon2 is not None and lat2 is not None): + lon3 = lon2 + lat3 = lat2 + else: + lon3 = lon + lat3 = lat + cellData = False # Note that m,M is min,max for an increasing list # and max,min for a decreasing list - xm = lon2[0] - xM = lon2[-1] - ym = lat2[0] - yM = lat2[-1] - - lat = lat2[:, numpy.newaxis] * \ - numpy.ones(lon2.shape)[numpy.newaxis, :] - lon = lon2[numpy.newaxis, - :] * numpy.ones(lat2.shape)[:, - numpy.newaxis] + xm = lon3[0] + xM = lon3[-1] + ym = lat3[0] + yM = lat3[-1] + + lat = lat3[:, numpy.newaxis] * numpy.ones(lon3.shape)[numpy.newaxis, :] + lon = lon3[numpy.newaxis, :] * numpy.ones(lat3.shape)[:, numpy.newaxis] elif grid is None: # No grid info from data, making one up data1 = cdms2.asVariable(data1) lon = data1.getAxis(-1) lat = data1.getAxis(-2) # Ok let's try to get the bounds - lon2 = getBoundsList(lon) - lat2 = getBoundsList(lat) + lon2 = getBoundsList(lon, hasCellData, dualGrid) + lat2 = getBoundsList(lat, hasCellData, dualGrid) + if (lon2 is not None and lat2 is not None): + lon3 = lon2 + lat3 = lat2 + else: + lon3 = lon + lat3 = lat + cellData = False # Note that m,M is min,max for an increasing list # and max,min for a decreasing list - xm = lon2[0] - xM = lon2[-1] - ym = lat2[0] - yM = lat2[-1] - lat = lat2[:, numpy.newaxis] * \ - numpy.ones(lon2.shape)[numpy.newaxis, :] - lon = lon2[numpy.newaxis, :] * \ - numpy.ones(lat2.shape)[:, numpy.newaxis] + xm = lon3[0] + xM = lon3[-1] + ym = lat3[0] + yM = lat3[-1] + lat = lat3[:, numpy.newaxis] * \ + numpy.ones(lon3.shape)[numpy.newaxis, :] + lon = lon3[numpy.newaxis, :] * \ + numpy.ones(lat3.shape)[:, numpy.newaxis] if grid is None: vg.SetDimensions(lat.shape[1], lat.shape[0], 1) lon = numpy.ma.ravel(lon) @@ -461,15 +381,23 @@ def genGrid(data1, data2, gm, deep=True, grid=None, geo=None): ym = lat.min() yM = lat.max() - # scalar data - scalar = numpy_to_vtk_wrapper(data1.filled(0.).flat, - deep=False) - scalar.SetName("scalar") - gridForScalar = grid if grid else vg + # attribute data + gridForAttribute = grid if grid else vg + if genVectors: + attribute = generateVectorArray(data1, data2, gridForAttribute) + else: + attribute = numpy_to_vtk_wrapper(data1.filled(0.).flat, + deep=False) + attribute.SetName("scalar") if cellData: - gridForScalar.GetCellData().SetScalars(scalar) + attributes = gridForAttribute.GetCellData() + else: + attributes = gridForAttribute.GetPointData() + if genVectors: + attributes.SetVectors(attribute) else: - gridForScalar.GetPointData().SetScalars(scalar) + attributes.SetScalars(attribute) + if grid is None: # First create the points/vertices (in vcs terms) pts = vtk.vtkPoints() @@ -489,8 +417,8 @@ def genGrid(data1, data2, gm, deep=True, grid=None, geo=None): # wrapping pedigreeId = vtk.vtkIntArray() pedigreeId.SetName("PedigreeIds") - pedigreeId.SetNumberOfTuples(scalar.GetNumberOfTuples()) - for i in range(0, scalar.GetNumberOfTuples()): + pedigreeId.SetNumberOfTuples(attribute.GetNumberOfTuples()) + for i in range(0, attribute.GetNumberOfTuples()): pedigreeId.SetValue(i, i) if cellData: vg.GetCellData().SetPedigreeIds(pedigreeId) @@ -533,7 +461,8 @@ def genGrid(data1, data2, gm, deep=True, grid=None, geo=None): "wrap": wrap, "geo": geo, "cellData": cellData, - "data": data1 + "data": data1, + "data2": data2 } return out @@ -1853,27 +1782,8 @@ def generateVectorArray(data1, data2, vtk_grid): w = numpy.concatenate((u, v), axis=1) w = numpy.concatenate((w, z), axis=1) - # HACK The grid returned by vtk2vcs.genGrid is not the same size as the - # data array. I'm not sure where the issue is...for now let's just zero-pad - # data array so that we can at least test rendering until Charles gets - # back from vacation: - wLen = len(w) - numPts = vtk_grid.GetNumberOfPoints() - if wLen != numPts: - warnings.warn("!!! Warning during vector plotting: " - "Number of points does not " - "match the number of vectors to be " - "glyphed (%s points vs %s " - "vectors). The vectors will be " - "padded/truncated to match for " - "rendering purposes, but the resulting " - "image should not be " - "trusted." % (numPts, wLen)) - newShape = (numPts,) + w.shape[1:] - w = numpy.ma.resize(w, newShape) - w = numpy_to_vtk_wrapper(w, deep=False) - w.SetName("vectors") + w.SetName("vector") return w diff --git a/Packages/vcs/vcs/vcsvtk/boxfillpipeline.py b/Packages/vcs/vcs/vcsvtk/boxfillpipeline.py index 772652172..1eb39085c 100644 --- a/Packages/vcs/vcs/vcsvtk/boxfillpipeline.py +++ b/Packages/vcs/vcs/vcsvtk/boxfillpipeline.py @@ -24,6 +24,7 @@ class BoxfillPipeline(Pipeline2D): self._contourLabels = None self._mappers = None self._customBoxfillArgs = {} + self._needsCellData = True def _updateScalarData(self): """Overrides baseclass implementation.""" @@ -93,11 +94,6 @@ class BoxfillPipeline(Pipeline2D): # Use consecutive colors: self._contourColors = range(self._gm.color_1, self._gm.color_2 + 1) - def _createPolyDataFilter(self): - """Overrides baseclass implementation.""" - self._vtkPolyDataFilter = vtk.vtkDataSetSurfaceFilter() - self._vtkPolyDataFilter.SetInputData(self._vtkDataSet) - def _plotInternal(self): """Overrides baseclass implementation.""" # Special case for custom boxfills: diff --git a/Packages/vcs/vcs/vcsvtk/isofillpipeline.py b/Packages/vcs/vcs/vcsvtk/isofillpipeline.py index e2ee5360e..8f46aa5bd 100644 --- a/Packages/vcs/vcs/vcsvtk/isofillpipeline.py +++ b/Packages/vcs/vcs/vcsvtk/isofillpipeline.py @@ -13,36 +13,11 @@ class IsofillPipeline(Pipeline2D): def __init__(self, gm, context_): super(IsofillPipeline, self).__init__(gm, context_) - - def _updateVTKDataSet(self): - """Overrides baseclass implementation.""" - # Force point data for isoline/isofill - genGridDict = vcs2vtk.genGridOnPoints(self._data1, self._gm, - deep=False, - grid=self._vtkDataSet, - geo=self._vtkGeoTransform) - genGridDict["cellData"] = False - self._data1 = genGridDict["data"] - self._updateFromGenGridDict(genGridDict) + self._needsCellData = False def _updateContourLevelsAndColors(self): self._updateContourLevelsAndColorsGeneric() - def _createPolyDataFilter(self): - """Overrides baseclass implementation.""" - self._vtkPolyDataFilter = vtk.vtkDataSetSurfaceFilter() - if self._useCellScalars: - # Sets data to point instead of just cells - c2p = vtk.vtkCellDataToPointData() - c2p.SetInputData(self._vtkDataSet) - c2p.Update() - # For contouring duplicate points seem to confuse it - self._vtkPolyDataFilter.SetInputConnection(c2p.GetOutputPort()) - else: - self._vtkPolyDataFilter.SetInputData(self._vtkDataSet) - self._vtkPolyDataFilter.Update() - self._resultDict["vtk_backend_filter"] = self._vtkPolyDataFilter - def _plotInternal(self): """Overrides baseclass implementation.""" diff --git a/Packages/vcs/vcs/vcsvtk/isolinepipeline.py b/Packages/vcs/vcs/vcsvtk/isolinepipeline.py index af79a45b8..2d9b66472 100644 --- a/Packages/vcs/vcs/vcsvtk/isolinepipeline.py +++ b/Packages/vcs/vcs/vcsvtk/isolinepipeline.py @@ -12,21 +12,7 @@ class IsolinePipeline(Pipeline2D): def __init__(self, gm, context_): super(IsolinePipeline, self).__init__(gm, context_) - - def _updateVTKDataSet(self): - """Overrides baseclass implementation.""" - # Force point data for isoline/isofill - genGridDict = vcs2vtk.genGridOnPoints(self._data1, self._gm, - deep=False, - grid=self._vtkDataSet, - geo=self._vtkGeoTransform) - genGridDict["cellData"] = False - self._data1 = genGridDict["data"] - self._updateFromGenGridDict(genGridDict) - - data = vcs2vtk.numpy_to_vtk_wrapper(self._data1.filled(0.).flat, - deep=False) - self._vtkDataSet.GetPointData().SetScalars(data) + self._needsCellData = False def _updateContourLevelsAndColors(self): """Overrides baseclass implementation.""" @@ -49,20 +35,6 @@ class IsolinePipeline(Pipeline2D): # Contour colors: self._contourColors = self._gm.linecolors - def _createPolyDataFilter(self): - """Overrides baseclass implementation.""" - self._vtkPolyDataFilter = vtk.vtkDataSetSurfaceFilter() - if self._useCellScalars: - # Sets data to point instead of just cells - c2p = vtk.vtkCellDataToPointData() - c2p.SetInputData(self._vtkDataSet) - c2p.Update() - # For contouring duplicate points seem to confuse it - self._vtkPolyDataFilter.SetInputConnection(c2p.GetOutputPort()) - else: - self._vtkPolyDataFilter.SetInputData(self._vtkDataSet) - self._resultDict["vtk_backend_filter"] = self._vtkPolyDataFilter - def _plotInternal(self): """Overrides baseclass implementation.""" tmpLevels = [] @@ -164,7 +136,7 @@ class IsolinePipeline(Pipeline2D): numLevels = len(l) cot = vtk.vtkContourFilter() - if self._useCellScalars: + if self._hasCellData: cot.SetInputConnection(self._vtkPolyDataFilter.GetOutputPort()) else: cot.SetInputData(self._vtkDataSet) diff --git a/Packages/vcs/vcs/vcsvtk/meshfillpipeline.py b/Packages/vcs/vcs/vcsvtk/meshfillpipeline.py index 90c06718d..7101a4729 100644 --- a/Packages/vcs/vcs/vcsvtk/meshfillpipeline.py +++ b/Packages/vcs/vcs/vcsvtk/meshfillpipeline.py @@ -15,6 +15,7 @@ class MeshfillPipeline(Pipeline2D): super(MeshfillPipeline, self).__init__(gm, context_) self._patternActors = [] + self._needsCellData = True def _updateScalarData(self): """Overrides baseclass implementation.""" @@ -25,16 +26,6 @@ class MeshfillPipeline(Pipeline2D): def _updateContourLevelsAndColors(self): self._updateContourLevelsAndColorsGeneric() - def _createPolyDataFilter(self): - """Overrides baseclass implementation.""" - self._vtkPolyDataFilter = vtk.vtkDataSetSurfaceFilter() - if self._useCellScalars: - self._vtkPolyDataFilter.SetInputData(self._vtkDataSet) - else: - p2c = vtk.vtkPointDataToCellData() - p2c.SetInputData(self._vtkDataSet) - self._vtkPolyDataFilter.SetInputConnection(p2c.GetOutputPort()) - def _plotInternal(self): prepedContours = self._prepContours() diff --git a/Packages/vcs/vcs/vcsvtk/pipeline2d.py b/Packages/vcs/vcs/vcsvtk/pipeline2d.py index 4d370db8a..baa2f8915 100644 --- a/Packages/vcs/vcs/vcsvtk/pipeline2d.py +++ b/Packages/vcs/vcs/vcsvtk/pipeline2d.py @@ -1,9 +1,10 @@ from .pipeline import Pipeline from .. import vcs2vtk -import vcs -import numpy import fillareautils +import numpy +import vcs +import vtk import warnings @@ -45,8 +46,10 @@ class IPipeline2D(Pipeline): - _useContinents: Whether or not to plot continents. - _dataWrapModulo: Wrap modulo as [YMax, XMax], in degrees. 0 means 'no wrapping'. - - _useCellScalars: True if data is applied to cell, false if data is + - _hasCellData: True if data is applied to cell, false if data is applied to points. + - _needsCellData: True if the plot needs cell scalars, false if + the plot needs point scalars - _scalarRange: The range of _data1 as tuple(float min, float max) - _maskedDataMapper: The mapper used to render masked data. """ @@ -74,7 +77,8 @@ class IPipeline2D(Pipeline): self._colorMap = None self._useContinents = None self._dataWrapModulo = None - self._useCellScalars = None + self._hasCellData = None + self._needsCellData = None self._scalarRange = None self._maskedDataMapper = None @@ -82,7 +86,7 @@ class IPipeline2D(Pipeline): """Create _data1 and _data2 from _originalData1 and _originalData2.""" raise NotImplementedError("Missing override.") - def _updateVTKDataSet(self): + def _updateVTKDataSet(self, plotBasedDualGrid): """Apply the vcs data to _vtkDataSet, creating it if necessary.""" raise NotImplementedError("Missing override.") @@ -275,7 +279,8 @@ class Pipeline2D(IPipeline2D): self._scalarRange = vcs.minmax(self._data1) # Create/update the VTK dataset. - self._updateVTKDataSet() + plotBasedDualGrid = kargs.get('plot_based_dual_grid', True) + self._updateVTKDataSet(plotBasedDualGrid) # Update the results: self._resultDict["vtk_backend_grid"] = self._vtkDataSet @@ -311,16 +316,40 @@ class Pipeline2D(IPipeline2D): self._min = self._data1.min() self._max = self._data1.max() - def _updateVTKDataSet(self): - """Overrides baseclass implementation.""" + def _updateVTKDataSet(self, plotBasedDualGrid): + """ + """ + if (plotBasedDualGrid): + hasCellData = self._data1.hasCellData() + dualGrid = (hasCellData != self._needsCellData) + else: + dualGrid = False genGridDict = vcs2vtk.genGrid(self._data1, self._data2, self._gm, deep=False, grid=self._vtkDataSet, - geo=self._vtkGeoTransform) - + geo=self._vtkGeoTransform, dualGrid=dualGrid) self._data1 = genGridDict["data"] self._updateFromGenGridDict(genGridDict) + def _createPolyDataFilter(self): + """This is only used when we use the grid stored in the file for all plots.""" + self._vtkPolyDataFilter = vtk.vtkDataSetSurfaceFilter() + if self._hasCellData == self._needsCellData: + self._vtkPolyDataFilter.SetInputData(self._vtkDataSet) + elif self._hasCellData: + # use cells but needs points + c2p = vtk.vtkCellDataToPointData() + c2p.SetInputData(self._vtkDataSet) + self._vtkPolyDataFilter.SetInputConnection(c2p.GetOutputPort()) + else: + # use points but needs cells + p2c = vtk.vtkPointDataToCellData() + p2c.SetInputData(self._vtkDataSet) + # For contouring duplicate points seem to confuse it + self._vtkPolyDataFilter.SetInputConnection(p2c.GetOutputPort()) + self._vtkPolyDataFilter.Update() + self._resultDict["vtk_backend_filter"] = self._vtkPolyDataFilter + def _updateFromGenGridDict(self, genGridDict): """Overrides baseclass implementation.""" self._vtkDataSet = genGridDict['vtk_backend_grid'] @@ -329,7 +358,7 @@ class Pipeline2D(IPipeline2D): self._useContinents = genGridDict['continents'] self._dataWrapModulo = genGridDict['wrap'] self._vtkGeoTransform = genGridDict['geo'] - self._useCellScalars = genGridDict['cellData'] + self._hasCellData = genGridDict['cellData'] def _createMaskedDataMapper(self): """Overrides baseclass implementation.""" @@ -338,11 +367,11 @@ class Pipeline2D(IPipeline2D): if color is not None: color = self.getColorIndexOrRGBA(_colorMap, color) self._maskedDataMapper = vcs2vtk.putMaskOnVTKGrid( - self._data1, self._vtkDataSet, color, self._useCellScalars, + self._data1, self._vtkDataSet, color, self._hasCellData, deep=False) self._resultDict["vtk_backend_missing_mapper"] = ( - self._maskedDataMapper, color, self._useCellScalars) + self._maskedDataMapper, color, self._hasCellData) def getPlottingBounds(self): """gm.datawc if it is set or dataset_bounds if there is not geographic projection diff --git a/Packages/vcs/vcs/vcsvtk/vectorpipeline.py b/Packages/vcs/vcs/vcsvtk/vectorpipeline.py index b8c4eaead..bc34e3c9e 100644 --- a/Packages/vcs/vcs/vcsvtk/vectorpipeline.py +++ b/Packages/vcs/vcs/vcsvtk/vectorpipeline.py @@ -33,14 +33,21 @@ class VectorPipeline(Pipeline): lon = None latAccessor = data1.getLatitude() - lonAccesrsor = data1.getLongitude() + lonAccessor = data1.getLongitude() if latAccessor: lat = latAccessor[:] - if lonAccesrsor: - lon = lonAccesrsor[:] + if lonAccessor: + lon = lonAccessor[:] - gridGenDict = vcs2vtk.genGridOnPoints(data1, self._gm, deep=False, grid=grid, - geo=transform, data2=data2) + plotBasedDualGrid = kargs.get('plot_based_dual_grid', True) + if (plotBasedDualGrid): + hasCellData = data1.hasCellData() + dualGrid = hasCellData + else: + dualGrid = False + gridGenDict = vcs2vtk.genGrid(data1, data2, self._gm, deep=False, grid=grid, + geo=transform, genVectors=True, + dualGrid=dualGrid) data1 = gridGenDict["data"] data2 = gridGenDict["data2"] @@ -54,6 +61,7 @@ class VectorPipeline(Pipeline): continents = gridGenDict['continents'] self._dataWrapModulo = gridGenDict['wrap'] geo = gridGenDict['geo'] + cellData = gridGenDict['cellData'] if geo is not None: newv = vtk.vtkDoubleArray() @@ -83,16 +91,19 @@ class VectorPipeline(Pipeline): returned["vtk_backend_grid"] = grid returned["vtk_backend_geo"] = geo - missingMapper = vcs2vtk.putMaskOnVTKGrid(data1, grid, None, False, - deep=False) + missingMapper = vcs2vtk.putMaskOnVTKGrid(data1, grid, actorColor=None, + cellData=cellData, deep=False) # None/False are for color and cellData # (sent to vcs2vtk.putMaskOnVTKGrid) returned["vtk_backend_missing_mapper"] = (missingMapper, None, False) - w = vcs2vtk.generateVectorArray(data1, data2, grid) - - grid.GetPointData().AddArray(w) + # convert to point data + if cellData: + c2p = vtk.vtkCellDataToPointData() + c2p.SetInputData(grid) + c2p.Update() + grid = c2p.GetOutput() # Vector attempt l = self._gm.line @@ -119,7 +130,7 @@ class VectorPipeline(Pipeline): glyphFilter = vtk.vtkGlyph2D() glyphFilter.SetInputData(grid) - glyphFilter.SetInputArrayToProcess(1, 0, 0, 0, "vectors") + glyphFilter.SetInputArrayToProcess(1, 0, 0, 0, "vector") glyphFilter.SetSourceConnection(arrow.GetOutputPort()) glyphFilter.SetVectorModeToUseVector() -- GitLab From 0d6bfec7174d847b46038d1c86a7ca06beceb3db Mon Sep 17 00:00:00 2001 From: Dan Lipsa Date: Wed, 4 May 2016 16:24:18 -0400 Subject: [PATCH 042/191] BUG: Fix mean computation for point datasets. With the new flag TransientAxis._genericBounds_ TransientAxis.getExplicitBounds returns None if the bounds were not read from a NetCDF file but were autogenerated. This creates a problem in cdutil.averager as bound axis are artificially extended to -90, 90 So, for a latbnds=[[90, 88], [88, 84], ..., [4, 0]] we extended it to [[90, 88], [88,84], ..., [4, -90]]. We remove the code that did this. This fix also improves the baseline for testEsmfRegridRegion. --- Packages/cdms2/Lib/grid.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Packages/cdms2/Lib/grid.py b/Packages/cdms2/Lib/grid.py index f11ca1764..9930f263a 100644 --- a/Packages/cdms2/Lib/grid.py +++ b/Packages/cdms2/Lib/grid.py @@ -496,14 +496,6 @@ class AbstractRectGrid(AbstractGrid): else: latbnds = lat.genGenericBounds() - # Stretch latitude bounds to +/- 90.0 - if ascending: - latbnds[0,0] = min(latbnds[0,0],-90.0) - latbnds[-1,1] = max(latbnds[-1,1],90.0) - else: - latbnds[0,0] = max(latbnds[0,0],+90.0) - latbnds[-1,1] = min(latbnds[-1,1],-90.0) - # Get longitude bounds lon = self.getLongitude() if len(lon)>1: -- GitLab From 2acc77cdf88741f93b8ff79c357d623b993197ea Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Wed, 11 May 2016 09:12:41 -0700 Subject: [PATCH 043/191] Made flake8 pass, removed extra line, unwrapped some wrapped lines --- Packages/vcs/vcs/boxfill.py | 7 ++----- Packages/vcs/vcs/template.py | 23 +++++++++++++++++------ 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/Packages/vcs/vcs/boxfill.py b/Packages/vcs/vcs/boxfill.py index 4003606c9..b403895fc 100755 --- a/Packages/vcs/vcs/boxfill.py +++ b/Packages/vcs/vcs/boxfill.py @@ -742,8 +742,7 @@ class Gfb(object): nlev = float(self.color_2 - self.color_1 + 1) autolevels = False - if numpy.allclose(self.level_1, 1.e20) or \ - numpy.allclose(self.level_2, 1.e20): + if numpy.allclose(self.level_1, 1.e20) or numpy.allclose(self.level_2, 1.e20): autolevels = True low_end = varmin high_end = varmax @@ -755,7 +754,6 @@ class Gfb(object): low_end = numpy.ma.log10(low_end) high_end = numpy.ma.log10(high_end) - if autolevels: # Use nice values for the scale scale = vcs.mkscale(low_end, high_end) @@ -776,8 +774,7 @@ class Gfb(object): if self.legend: return self.legend - if numpy.allclose(self.level_1, 1.e20) or \ - numpy.allclose(self.level_2, 1.e20): + if numpy.allclose(self.level_1, 1.e20) or numpy.allclose(self.level_2, 1.e20): autolevels = True else: autolevels = False diff --git a/Packages/vcs/vcs/template.py b/Packages/vcs/vcs/template.py index 3eaac046b..fd2ee2f0c 100644 --- a/Packages/vcs/vcs/template.py +++ b/Packages/vcs/vcs/template.py @@ -56,6 +56,18 @@ def _setgen(self, name, cls, value): setattr(self, "_%s" % name, value) +def epsilon_gte(a, b): + """a >= b, using floating point epsilon value.""" + float_epsilon = numpy.finfo(numpy.float32).eps + return -float_epsilon < a - b + + +def epsilon_lte(a, b): + """a <= b, using floating point epsilon value.""" + float_epsilon = numpy.finfo(numpy.float32).eps + return float_epsilon > a - b + + # read .scr file def process_src(nm, code): """Takes VCS script code (string) as input and generates boxfill gm from it""" @@ -1874,15 +1886,14 @@ class P(object): if legend is None: legend = vcs.mklabels(levels) # We'll use the less precise float epsilon since this is just for labels - float_epsilon = numpy.finfo(numpy.float32).eps if levels[0] < levels[1]: - # <= - comparison = lambda a, b: float_epsilon > a - b + comparison = epsilon_lte else: - # >= - comparison = lambda a, b: -float_epsilon < a - b + comparison = epsilon_gte + + def in_bounds(x): + return comparison(levels[0], x) and comparison(x, levels[-1]) - in_bounds = lambda x: comparison(levels[0], x) and comparison(x, levels[-1]) dlong = dD / (len(levels) - 1) for l in legend.keys(): -- GitLab From 60d644963a9cdf7a0b4a8467ae9563d1db002166 Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Thu, 12 May 2016 13:36:33 -0700 Subject: [PATCH 044/191] Harden histogram a bit --- Packages/vcsaddons/Lib/core.py | 20 +++++----- Packages/vcsaddons/Lib/histograms.py | 58 ++++++++++++++++++++++------ 2 files changed, 56 insertions(+), 22 deletions(-) diff --git a/Packages/vcsaddons/Lib/core.py b/Packages/vcsaddons/Lib/core.py index 8421e247c..d1b49bf11 100644 --- a/Packages/vcsaddons/Lib/core.py +++ b/Packages/vcsaddons/Lib/core.py @@ -20,7 +20,7 @@ class VCSaddon(object): self.x=vcs.init() else: self.x=x - + if template is None: self.template = self.x.gettemplate() elif isinstance(template,str): @@ -39,10 +39,10 @@ class VCSaddon(object): self.datawc_y1=1.e20 self.datawc_y2=1.e20 self.colormap="default" - self.xmtics1='*' - self.xmtics2='*' - self.ymtics1='*' - self.ymtics2='*' + self.xmtics1='' + self.xmtics2='' + self.ymtics1='' + self.ymtics2='' self.xticlabels1='*' self.xticlabels2='*' self.yticlabels1='*' @@ -60,7 +60,7 @@ class VCSaddon(object): self.datawc_x1=gm.datawc_x1 self.datawc_x2=gm.datawc_x2 self.datawc_y1=gm.datawc_y1 - self.datawc_y2=gm.datawc_x2 + self.datawc_y2=gm.datawc_y2 self.colormap=gm.colormap self.xmtics1=gm.xmtics1 self.xmtics2=gm.xmtics2 @@ -78,7 +78,7 @@ class VCSaddon(object): self.projection=gm.projection self.name = name vcsaddons.gms[self.g_type][name]=self - + def list(self): print 'graphics method = ',self.g_name @@ -103,9 +103,9 @@ class VCSaddon(object): raise "Plot function not implemented for graphic method type: %s" % self.g_name def prep_plot(self,xmn,xmx,ymn,ymx): - + self.save() - + if self.datawc_x1!=1.e20: xmn = self.datawc_x1 if self.datawc_x2!=1.e20: @@ -180,4 +180,4 @@ class VCSaddon(object): def creategm(self,name,source='default'): return self.__init__(name,source=source,x=self.x,template=self.template) - + diff --git a/Packages/vcsaddons/Lib/histograms.py b/Packages/vcsaddons/Lib/histograms.py index 60f866492..452ac671e 100644 --- a/Packages/vcsaddons/Lib/histograms.py +++ b/Packages/vcsaddons/Lib/histograms.py @@ -60,31 +60,48 @@ class Ghg(VCSaddon): try: data_name = data.id + data.units except AttributeError: - data_name = data.id + try: + data_name = data.id + except AttributeError: + data_name = "array" # We'll just flatten the data... if they want to be more precise, should pass in more precise data - data = data.flatten().asma() + if isinstance(data, cdms2.avariable.AbstractVariable): + data = data.asma() + data = data.flatten() # ok now we have a good x and a good data if not self.bins: self.bins = vcs.utils.mkscale(*vcs.minmax(data)) + # Sort the bins + self.bins.sort() + + # Prune duplicates + pruned_bins = [] + for bin in self.bins: + if pruned_bins and numpy.allclose(bin, pruned_bins[-1]): + continue + pruned_bins.append(bin) + self.bins = pruned_bins data_bins = numpy.digitize(data, self.bins) - 1 binned = [data[data_bins==i] for i in range(len(self.bins))] - means = [] stds = [] max_possible_deviance = 0 for ind, databin in enumerate(binned): - means.append(databin.mean()) - stds.append(databin.std()) + if len(databin) > 0: + means.append(databin.mean()) + stds.append(databin.std()) + else: + means.append(0) + stds.append(0) if len(self.bins) > ind + 1: max_possible_deviance = max(means[ind] - self.bins[ind], self.bins[ind + 1] - means[ind], max_possible_deviance) else: max_possible_deviance = max(means[ind] - self.bins[ind], max_possible_deviance) - color_values = [std / max_possible_deviance for std in stds] y_values = [len(databin) for databin in binned] nbars = len(self.bins) - 1 @@ -97,11 +114,27 @@ class Ghg(VCSaddon): line.viewport = [ template.data.x1, template.data.x2, template.data.y1, template.data.y2] - xmn, xmx = vcs.minmax(self.bins) - # Make the y scale be slightly larger than the largest bar - ymn, ymx = 0, max(y_values) * 1.25 + vcs_min_max = vcs.minmax(self.bins) + if numpy.allclose(self.datawc_x1, 1e20): + xmn = vcs_min_max[0] + else: + xmn = self.datawc_x1 + + if numpy.allclose(self.datawc_x2, 1e20): + xmx = vcs_min_max[1] + else: + xmx = self.datawc_x2 + + if numpy.allclose(self.datawc_y2, 1e20): + # Make the y scale be slightly larger than the largest bar + ymx = max(y_values) * 1.25 + else: + ymx = self.datawc_y2 - #xmn, xmx, ymn, ymx = self.prep_plot(xmn, xmx, ymn, ymx) + if numpy.allclose(self.datawc_y1, 1e20): + ymn = 0 + else: + ymn = self.datawc_y1 fill.worldcoordinate = [xmn, xmx, ymn, ymx] line.worldcoordinate = [xmn, xmx, ymn, ymx] @@ -166,7 +199,8 @@ class Ghg(VCSaddon): else: # Shouldn't ever get here since level 0 is 0 assert False - + else: + assert False styles.append(self.fillareastyles[lev_ind]) cols.append(self.fillareacolors[lev_ind]) indices.append(self.fillareaindices[lev_ind]) @@ -192,7 +226,7 @@ class Ghg(VCSaddon): displays = [] x_axis = cdms2.createAxis(self.bins, id=data_name) - y_axis = cdms2.createAxis(vcs.mkscale(0, ymx), id="bin_size") + y_axis = cdms2.createAxis(vcs.mkscale(ymn, ymx), id="bin_size") displays.append(x.plot(fill, bg=bg, render=False)) arr = MV2.masked_array(y_values) -- GitLab From 5dd0a949f1b5b26c51cbb4513fd165f519031573 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Sat, 30 Apr 2016 21:49:57 -0400 Subject: [PATCH 045/191] Using common module for regression testing --- Packages/testing/__init__.py | 0 .../testing/regression.py | 23 +++++++++- Packages/testing/setup.py | 14 ++++++ testing/vcs/test_vcs_1D_datawc.py | 21 +++------ testing/vcs/test_vcs_1D_datawc_missing.py | 29 ++---------- testing/vcs/test_vcs_1D_with_manyDs.py | 30 ++---------- testing/vcs/test_vcs_1d_in_boxfill.py | 27 ++--------- ...cs_1d_marker_not_shown_if_xaxis_flipped.py | 33 ++----------- testing/vcs/test_vcs_1d_missing.py | 26 ++--------- testing/vcs/test_vcs_animate_boxfill.py | 15 ++---- testing/vcs/test_vcs_animate_isofill.py | 23 ++++------ testing/vcs/test_vcs_animate_isoline.py | 27 ++++------- .../vcs/test_vcs_animate_isoline_colored.py | 20 +++----- .../test_vcs_animate_isoline_text_labels.py | 11 ++--- ...vcs_animate_isoline_text_labels_colored.py | 10 ++-- testing/vcs/test_vcs_animate_meshfill.py | 10 +--- testing/vcs/test_vcs_antialiasing.py | 1 - testing/vcs/test_vcs_aspect_ratio.py | 35 +++++--------- testing/vcs/test_vcs_auto_time_labels.py | 23 +++------- testing/vcs/test_vcs_autot_axis_titles.py | 22 ++------- testing/vcs/test_vcs_bad_time_units.py | 12 ++--- testing/vcs/test_vcs_basic_gms.py | 19 ++------ testing/vcs/test_vcs_basic_text.py | 17 ++----- testing/vcs/test_vcs_basic_vectors.py | 19 ++------ ...st_vcs_box_custom_as_def_vistrails_exts.py | 42 +++++------------ .../test_vcs_boxfill_10x10_masked_numpy.py | 28 +++-------- testing/vcs/test_vcs_boxfill_10x10_numpy.py | 27 +++-------- testing/vcs/test_vcs_boxfill_custom.py | 21 ++------- testing/vcs/test_vcs_boxfill_custom_ext1.py | 22 ++------- .../vcs/test_vcs_boxfill_custom_ext1_ext2.py | 22 ++------- testing/vcs/test_vcs_boxfill_custom_ext2.py | 20 ++------ ...t_vcs_boxfill_custom_non_default_levels.py | 24 ++-------- .../test_vcs_boxfill_decreasing_latitude.py | 27 ++--------- testing/vcs/test_vcs_boxfill_lambert_crash.py | 17 ++----- testing/vcs/test_vcs_boxfill_lev1_lev2.py | 35 ++++---------- .../vcs/test_vcs_boxfill_lev1_lev2_ext1.py | 37 +++++---------- .../test_vcs_boxfill_lev1_lev2_ext1_ext2.py | 39 +++++----------- .../vcs/test_vcs_boxfill_lev1_lev2_ext2.py | 37 +++++---------- .../test_vcs_boxfill_lev1_lev2_ta_missing.py | 39 +++++----------- testing/vcs/test_vcs_boxfill_polar.py | 31 +++---------- testing/vcs/test_vcs_boxfill_robinson_wrap.py | 15 +----- testing/vcs/test_vcs_canvas_background.py | 19 ++------ .../vcs/test_vcs_canvas_background_update.py | 20 ++------ testing/vcs/test_vcs_click_info.py | 20 ++------ testing/vcs/test_vcs_close.py | 6 --- testing/vcs/test_vcs_colormaps_source.py | 24 ++-------- .../vcs/test_vcs_colorpicker_appearance.py | 7 +-- testing/vcs/test_vcs_configurator_resize.py | 8 ++-- testing/vcs/test_vcs_continents.py | 25 ++-------- testing/vcs/test_vcs_create_get.py | 1 - testing/vcs/test_vcs_draw_logo_on.py | 16 ++----- testing/vcs/test_vcs_fillarea_transparency.py | 17 ++----- testing/vcs/test_vcs_first_png_blank.py | 19 ++------ testing/vcs/test_vcs_flipNone.py | 26 ++--------- testing/vcs/test_vcs_flipX.py | 26 ++--------- testing/vcs/test_vcs_flipXY.py | 25 ++-------- testing/vcs/test_vcs_flipY.py | 24 ++-------- testing/vcs/test_vcs_gen_meshfill.py | 29 ++---------- .../test_vcs_gms_animate_projected_plots.py | 23 ++-------- testing/vcs/test_vcs_gms_patterns_hatches.py | 16 ++----- testing/vcs/test_vcs_hatches_patterns.py | 24 ++-------- testing/vcs/test_vcs_import.py | 1 - testing/vcs/test_vcs_infinity.py | 20 ++------ testing/vcs/test_vcs_iso_celine_part1.py | 21 +++------ testing/vcs/test_vcs_iso_celine_part2.py | 25 +++------- ...st_vcs_isofill_data_read_north_to_south.py | 22 ++------- .../vcs/test_vcs_isofill_isoline_labels.py | 29 ++---------- .../vcs/test_vcs_isofill_mask_cell_shift.py | 29 +++--------- testing/vcs/test_vcs_isoline_labels.py | 34 +++----------- .../vcs/test_vcs_isoline_labels_background.py | 26 ++--------- ..._isoline_labels_multi_label_input_types.py | 46 +++++++------------ .../vcs/test_vcs_isoline_labelskipdistance.py | 26 ++--------- testing/vcs/test_vcs_isoline_numpy.py | 22 +++------ testing/vcs/test_vcs_isoline_width_stipple.py | 27 ++--------- testing/vcs/test_vcs_issue_960_labels.py | 26 ++++------- testing/vcs/test_vcs_lambert.py | 23 ++-------- testing/vcs/test_vcs_large_pattern_hatch.py | 27 ++--------- testing/vcs/test_vcs_legend.py | 17 ++----- testing/vcs/test_vcs_lon_axes_freak_out.py | 31 +++---------- testing/vcs/test_vcs_markers.py | 26 +++-------- testing/vcs/test_vcs_matplotlib_colormap.py | 26 ++--------- testing/vcs/test_vcs_mercator_edge.py | 23 ++-------- testing/vcs/test_vcs_meshfill_draw_mesh.py | 28 ++++------- testing/vcs/test_vcs_meshfill_no_wrapping.py | 26 ++--------- testing/vcs/test_vcs_meshfill_regular_grid.py | 23 ++-------- testing/vcs/test_vcs_meshfill_vertices.py | 21 ++------- testing/vcs/test_vcs_meshfill_zoom.py | 27 +++-------- testing/vcs/test_vcs_mintics.py | 20 ++------ testing/vcs/test_vcs_missing_colorname.py | 24 ++-------- ..._vcs_monotonic_decreasing_yxvsx_default.py | 29 ++++-------- testing/vcs/test_vcs_oned_level_axis.py | 27 +++-------- testing/vcs/test_vcs_patterns.py | 22 ++------- testing/vcs/test_vcs_plot_file_var.py | 14 +++--- .../test_vcs_plot_unstructured_via_boxfill.py | 20 ++------ testing/vcs/test_vcs_png_to_base64.py | 2 +- testing/vcs/test_vcs_png_window_resize.py | 17 ++----- .../vcs/test_vcs_polar_set_opt_param_polar.py | 30 +++--------- testing/vcs/test_vcs_remove_marker_none_1d.py | 24 ++-------- testing/vcs/test_vcs_setcolormap.py | 26 ++--------- .../vcs/test_vcs_settings_color_name_rgba.py | 27 +++-------- .../test_vcs_settings_color_name_rgba_1d.py | 22 ++------- ...st_vcs_settings_color_name_rgba_boxfill.py | 23 ++-------- ...st_vcs_settings_color_name_rgba_isoline.py | 23 ++-------- ...t_vcs_settings_color_name_rgba_meshfill.py | 23 ++-------- testing/vcs/test_vcs_star_triangle_markers.py | 17 ++----- testing/vcs/test_vcs_taylor_2quads.py | 33 ++----------- testing/vcs/test_vcs_taylor_template_ctl.py | 29 ++---------- testing/vcs/test_vcs_user_passed_date.py | 17 ++----- .../test_vcs_user_passed_date_as_string.py | 17 ++----- testing/vcs/test_vcs_vectors_missing.py | 27 +++-------- testing/vcs/test_vcs_vectors_robinson.py | 16 ++----- testing/vcs/test_vcs_vectors_robinson_wrap.py | 16 ++----- testing/vcs/test_vcs_verify_boxfill_basics.py | 13 +++--- testing/vcs/test_vcs_wmo_marker.py | 17 ++----- testing/vcs/test_vcs_wmo_markers.py | 25 +++------- testing/vcs/vtk_ui/vtk_ui_test.py | 14 ++---- .../vcsaddons/test_12_plot_one_leg_per_row.py | 15 ++---- .../test_12_plot_one_leg_per_row_right.py | 16 ++----- ...test_EzTemplate_12_plots_legd_direction.py | 17 ++----- ...t_EzTemplate_12_plots_margins_thickness.py | 15 ++---- .../test_EzTemplate_12_plots_mix_glb_local.py | 14 +----- .../test_EzTemplate_12_plots_spacing.py | 16 ++----- .../test_vcs_addons_EzTemplate_2x2.py | 24 +++------- .../vcsaddons/test_vcsaddons_preview_2x2.py | 16 ++----- 124 files changed, 589 insertions(+), 2135 deletions(-) create mode 100644 Packages/testing/__init__.py rename testing/checkimage.py => Packages/testing/regression.py (84%) create mode 100755 Packages/testing/setup.py diff --git a/Packages/testing/__init__.py b/Packages/testing/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/testing/checkimage.py b/Packages/testing/regression.py similarity index 84% rename from testing/checkimage.py rename to Packages/testing/regression.py index 9871f3557..68f381ce4 100644 --- a/testing/checkimage.py +++ b/Packages/testing/regression.py @@ -12,9 +12,28 @@ import os.path import re import sys import logging +import vcs defaultThreshold=10.0 +def init(): + testingDir = os.path.join(os.path.dirname(__file__), "..") + sys.path.append(testingDir) + + vcsinst = vcs.init() + vcsinst.setantialiasing(0) + vcsinst.drawlogooff() + vcsinst.setbgoutputdimensions(1200,1091,units="pixels") + return vcsinst + +def run(vcsinst, fname, baseline=sys.argv[1], threshold=defaultThreshold): + vcsinst.png(fname) + sys.exit(check_result_image(fname, baseline, threshold)) + +def run_wo_terminate(vcsinst, fname, baseline=sys.argv[1], threshold=defaultThreshold): + vcsinst.png(fname) + return check_result_image(fname, baseline, threshold) + def image_compare(testImage, baselineImage): imageDiff = vtk.vtkImageDifference() imageDiff.SetInputData(testImage) @@ -53,8 +72,8 @@ def find_alternates(fname): results.append(os.path.join(dirname, i)) return results -def check_result_image(fname, baselinefname, threshold = defaultThreshold, - baseline = True, cleanup=True): +def check_result_image(fname, baselinefname=sys.argv[1], threshold=defaultThreshold, + baseline=True, cleanup=True): testImage = image_from_file(fname) if testImage is None: print "Testing image missing, test failed." diff --git a/Packages/testing/setup.py b/Packages/testing/setup.py new file mode 100755 index 000000000..70f790d7b --- /dev/null +++ b/Packages/testing/setup.py @@ -0,0 +1,14 @@ +import os, sys +from distutils.core import setup +import cdat_info + +sys.path.append(os.environ.get('BUILD_DIR',"build")) + +setup(name="testing", + version=cdat_info.Version, + description="Testing infrastructure for cdat", + url="http://uvcdat.llnl.gov", + packages=['testing'], + package_dir={'testing': 'testing',}, + install_requires=['numpy','vcs', 'vtk'], +) diff --git a/testing/vcs/test_vcs_1D_datawc.py b/testing/vcs/test_vcs_1D_datawc.py index 1595a6cd7..8e671bb93 100644 --- a/testing/vcs/test_vcs_1D_datawc.py +++ b/testing/vcs/test_vcs_1D_datawc.py @@ -4,15 +4,13 @@ import vcs,numpy,cdms2,MV2,os,sys src=sys.argv[1] pth = os.path.join(os.path.dirname(__file__),"..") sys.path.append(pth) -import checkimage -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") +import testing.regression as regression + +x = regression.init() yx =x.createyxvsx() -data = """-11.14902417 -9.17390922 -7.29515002 +data = """-11.14902417 -9.17390922 -7.29515002 -7.51774549 -8.63608171 -10.4827395 -9.93859485 -7.3394366 -5.39241468 -5.74825567 -6.74967902 -7.09622319 -5.93836983 -4.04592997 -2.65591499 @@ -30,14 +28,9 @@ data = numpy.array(data,dtype=numpy.float) data = MV2.array(data) yx.datawc_x1 = 0 yx.datawc_x2 = 80 -yx.datawc_y1 =-12 -yx.datawc_y2 = 12 +yx.datawc_y1 =-12 +yx.datawc_y2 = 12 x.plot(data,yx,bg=1) -fnm = "test_vcs_1D_datawc.png" -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, "test_vcs_1D_datawc.png", src) \ No newline at end of file diff --git a/testing/vcs/test_vcs_1D_datawc_missing.py b/testing/vcs/test_vcs_1D_datawc_missing.py index 07e6f560a..d6caabc8e 100644 --- a/testing/vcs/test_vcs_1D_datawc_missing.py +++ b/testing/vcs/test_vcs_1D_datawc_missing.py @@ -1,19 +1,11 @@ -import vcs,numpy,cdms2,MV2,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +import vcs, numpy, cdms2, MV2, os, sys, testing.regression as regression -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") - -yx =x.createyxvsx() +x = regression.init() +yx = x.createyxvsx() data = """ --999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. +-999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. 0.059503571833625334 0.059503571833625334 0.05664014775641405 0.05193557222118004 0.04777129850801233 0.0407139313814465 0.029382624830271705 @@ -42,16 +34,5 @@ data = """ """.split() data = numpy.array(data,dtype=numpy.float) data = MV2.masked_less(data,-900) -#yx.datawc_x1 = 0 -#yx.datawc_x2 = 80 -##yx.datawc_y1 =-12 -#yx.datawc_y2 = 12 - - x.plot(data,yx,bg=1) -fnm = "test_vcs_1D_datawc_missing.png" -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, "test_vcs_1D_datawc_missing.png") diff --git a/testing/vcs/test_vcs_1D_with_manyDs.py b/testing/vcs/test_vcs_1D_with_manyDs.py index 1caba446e..28a6a7a8b 100644 --- a/testing/vcs/test_vcs_1D_with_manyDs.py +++ b/testing/vcs/test_vcs_1D_with_manyDs.py @@ -1,31 +1,9 @@ -import vcs,numpy,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage - -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") +import vcs, numpy, cdms2, MV2, os, sys, testing.regression as regression +x = regression.init() d = numpy.sin(numpy.arange(100)) -d=numpy.reshape(d,(10,10)) - - +d = numpy.reshape(d,(10,10)) one = x.create1d() - x.plot(d,one,bg=1) - - -fnm = "test_1D_with_manyDs.png" -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) - - - +regression.run(x, "test_1D_with_manyDs.png", sys.argv[1]) \ No newline at end of file diff --git a/testing/vcs/test_vcs_1d_in_boxfill.py b/testing/vcs/test_vcs_1d_in_boxfill.py index 292fe98a3..1da574394 100644 --- a/testing/vcs/test_vcs_1d_in_boxfill.py +++ b/testing/vcs/test_vcs_1d_in_boxfill.py @@ -1,29 +1,8 @@ -import vcs,numpy,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage - -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") +import vcs, numpy, cdms2, MV2, os, sys, testing.regression as regression +x = regression.init() d = numpy.sin(numpy.arange(100)) - b = x.createboxfill() - x.plot(d,b,bg=1) - - -fnm = "test_1d_in_boxfill.png" -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) - - - +regression.run(x, "test_1d_in_boxfill.png", sys.argv[1]) \ No newline at end of file diff --git a/testing/vcs/test_vcs_1d_marker_not_shown_if_xaxis_flipped.py b/testing/vcs/test_vcs_1d_marker_not_shown_if_xaxis_flipped.py index c350e4c59..f850f977e 100644 --- a/testing/vcs/test_vcs_1d_marker_not_shown_if_xaxis_flipped.py +++ b/testing/vcs/test_vcs_1d_marker_not_shown_if_xaxis_flipped.py @@ -1,42 +1,15 @@ -import vcs -import numpy -import MV2 -import cdms2 -import sys -import os -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage - -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") +import vcs, numpy, cdms2, MV2, os, sys, testing.regression as regression +x = regression.init() data = MV2.array([4,5,6,7,1,3,7,9,])+230. - p = cdms2.createAxis([2,5,100,200,500,800,850,1000]) - data.setAxis(0,p) - data.id="jim" - gm=x.create1d() - gm.linewidth=0 gm.datawc_x1=1000 gm.datawc_x2=0 - gm.markersize=30 - x.plot(data,gm,bg=1) - -fnm = "test_1d_marker_not_shown_if_xaxis_flipped.png" -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, "test_1d_marker_not_shown_if_xaxis_flipped.png", sys.argv[1]) \ No newline at end of file diff --git a/testing/vcs/test_vcs_1d_missing.py b/testing/vcs/test_vcs_1d_missing.py index 3a6880bdd..8c124e09c 100644 --- a/testing/vcs/test_vcs_1d_missing.py +++ b/testing/vcs/test_vcs_1d_missing.py @@ -3,15 +3,11 @@ import vcs,numpy,cdms2,MV2,os,sys src=sys.argv[1] pth = os.path.join(os.path.dirname(__file__),"..") sys.path.append(pth) -import checkimage +import testing.regression as regression -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") +x = regression.init() yx =x.createyxvsx() - -data = """-11.14902417 -9.17390922 -7.29515002 +data = """-11.14902417 -9.17390922 -7.29515002 -7.51774549 -8.63608171 -10.4827395 -9.93859485 -7.3394366 -5.39241468 -5.74825567 -6.74967902 -7.09622319 -5.93836983 -4.04592997 -2.65591499 @@ -30,17 +26,5 @@ data = MV2.array(data) data=MV2.masked_where(MV2.logical_and(data>-4,data<-2),data) -#yx.datawc_x1 = 0 -#yx.datawc_x2 = 80 -##yx.datawc_y1 =-12 -#yx.datawc_y2 = 12 - - -x.plot(data,yx,bg=1) -fnm = "test_vcs_1d_missing.png" -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +x.plot(data, yx, bg=1) +regression.run(x, "test_vcs_1d_missing.png", src) diff --git a/testing/vcs/test_vcs_animate_boxfill.py b/testing/vcs/test_vcs_animate_boxfill.py index 2bbd53c26..641b59edb 100644 --- a/testing/vcs/test_vcs_animate_boxfill.py +++ b/testing/vcs/test_vcs_animate_boxfill.py @@ -1,20 +1,14 @@ -import vcs -import cdms2 -import os -import sys -import time +import vcs, numpy, cdms2, MV2, os, sys, time, testing.regression as regression + pth = os.path.join(os.path.dirname(__file__),"..") sys.path.append(pth) -import checkimage - f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) s=f("clt",slice(0,12)) # read only 12 times steps to speed up things -x=vcs.init() +x = regression.init() x.setantialiasing(0) x.drawlogooff() x.setbgoutputdimensions(1200,1091,units="pixels") - gm=x.createboxfill() x.plot(s,gm,bg=1) x.animate.create() @@ -26,8 +20,7 @@ src_pth = sys.argv[1] pth = os.path.join(src_pth,prefix) ret = 0 for p in pngs: - print "Checking:",p - ret += checkimage.check_result_image(p,os.path.join(pth,os.path.split(p)[1]),checkimage.defaultThreshold) + ret += regression.check_result_image(p,os.path.join(pth,os.path.split(p)[1])) if ret == 0: os.removedirs(os.path.split(p)[0]) os.remove("%s.mp4" % prefix) diff --git a/testing/vcs/test_vcs_animate_isofill.py b/testing/vcs/test_vcs_animate_isofill.py index ba5ea0e8d..591d66362 100644 --- a/testing/vcs/test_vcs_animate_isofill.py +++ b/testing/vcs/test_vcs_animate_isofill.py @@ -1,20 +1,13 @@ -import vcs -import cdms2 -import os -import sys -import time + +import vcs, numpy, cdms2, MV2, os, sys, time, testing.regression as regression + pth = os.path.join(os.path.dirname(__file__),"..") sys.path.append(pth) -import checkimage - -f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) -s=f("clt",slice(0,12)) # read only 12 times steps to speed up things -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") +f = cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) +s = f("clt",slice(0,12)) # read only 12 times steps to speed up things +x = regression.init() gm=x.createisofill() x.plot(s,gm,bg=1) x.animate.create() @@ -26,8 +19,8 @@ src_pth = sys.argv[1] pth = os.path.join(src_pth,prefix) ret = 0 for p in pngs: - print "Checking:",p - ret += checkimage.check_result_image(p,os.path.join(pth,os.path.split(p)[1]),checkimage.defaultThreshold) + ret += regression.check_result_image(p,os.path.join(pth,os.path.split(p)[1]), + regression.defaultThreshold) if ret == 0: os.removedirs(os.path.split(p)[0]) os.remove("%s.mp4" % prefix) diff --git a/testing/vcs/test_vcs_animate_isoline.py b/testing/vcs/test_vcs_animate_isoline.py index 41e0c7318..cea333d3b 100644 --- a/testing/vcs/test_vcs_animate_isoline.py +++ b/testing/vcs/test_vcs_animate_isoline.py @@ -1,33 +1,24 @@ -import vcs -import cdms2 -import os -import sys -import time +import vcs, numpy, cdms2, MV2, os, sys, time, testing.regression as regression + pth = os.path.join(os.path.dirname(__file__),"..") sys.path.append(pth) -import checkimage - -f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) -s=f("clt",slice(0,12)) # read only 12 times steps to speed up things -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") +f = cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) +s = f("clt",slice(0,12)) # read only 12 times steps to speed up things -iso=x.createisoline() -x.plot(s,iso,bg=1) +x = regression.init() +iso = x.createisoline() +x.plot(s,iso, bg=1) x.animate.create() print "Saving now" prefix= os.path.split(__file__)[1][:-3] x.animate.save("%s.mp4"%prefix) -pngs = x.animate.close(preserve_pngs = True) # so we can look at them again +pngs = x.animate.close(preserve_pngs=True) # so we can look at them again src_pth = sys.argv[1] pth = os.path.join(src_pth,prefix) ret = 0 for p in pngs: - print "Checking:",p - ret += checkimage.check_result_image(p,os.path.join(pth,os.path.split(p)[1]),checkimage.defaultThreshold) + ret += regression.check_result_image(p,os.path.join(pth,os.path.split(p)[1])) if ret == 0: os.removedirs(os.path.split(p)[0]) os.remove("%s.mp4" % prefix) diff --git a/testing/vcs/test_vcs_animate_isoline_colored.py b/testing/vcs/test_vcs_animate_isoline_colored.py index 4fed45c86..4519ac16c 100644 --- a/testing/vcs/test_vcs_animate_isoline_colored.py +++ b/testing/vcs/test_vcs_animate_isoline_colored.py @@ -1,19 +1,12 @@ -import vcs -import cdms2 -import os -import sys -import time +import vcs, numpy, cdms2, MV2, os, sys, time, testing.regression as regression + pth = os.path.join(os.path.dirname(__file__),"..") sys.path.append(pth) -import checkimage -f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) -s=f("clt",slice(0,12)) # read only 12 times steps to speed up things +f = cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) +s = f("clt",slice(0,12)) # read only 12 times steps to speed up things -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") +x = regression.init() iso=x.createisoline() levs = range(0,101,10) @@ -34,8 +27,7 @@ src_pth = sys.argv[1] pth = os.path.join(src_pth,prefix) ret = 0 for p in pngs: - print "Checking:",p - ret += checkimage.check_result_image(p,os.path.join(pth,os.path.split(p)[1]),checkimage.defaultThreshold) + ret += regression.check_result_image(p,os.path.join(pth,os.path.split(p)[1])) if ret == 0: os.removedirs(os.path.split(p)[0]) os.remove("%s.mp4" % prefix) diff --git a/testing/vcs/test_vcs_animate_isoline_text_labels.py b/testing/vcs/test_vcs_animate_isoline_text_labels.py index 7a3be1fc5..0e83c02c6 100644 --- a/testing/vcs/test_vcs_animate_isoline_text_labels.py +++ b/testing/vcs/test_vcs_animate_isoline_text_labels.py @@ -1,11 +1,7 @@ -import vcs -import cdms2 -import os -import sys -import time +import vcs, numpy, cdms2, MV2, os, sys, time, testing.regression as regression + pth = os.path.join(os.path.dirname(__file__),"..") sys.path.append(pth) -import checkimage f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) s=f("clt",slice(0,12)) # read only 12 times steps to speed up things @@ -27,8 +23,7 @@ src_pth = sys.argv[1] pth = os.path.join(src_pth,prefix) ret = 0 for p in pngs: - print "Checking:",p - ret += checkimage.check_result_image(p,os.path.join(pth,os.path.split(p)[1]),checkimage.defaultThreshold) + ret += regression.check_result_image(p,os.path.join(pth,os.path.split(p)[1])) if ret == 0: os.removedirs(os.path.split(p)[0]) os.remove("%s.mp4" % prefix) diff --git a/testing/vcs/test_vcs_animate_isoline_text_labels_colored.py b/testing/vcs/test_vcs_animate_isoline_text_labels_colored.py index cf009e4a8..02711e219 100644 --- a/testing/vcs/test_vcs_animate_isoline_text_labels_colored.py +++ b/testing/vcs/test_vcs_animate_isoline_text_labels_colored.py @@ -1,11 +1,7 @@ -import vcs -import cdms2 -import os -import sys -import time +import vcs, numpy, cdms2, MV2, os, sys, time, testing.regression as regression + pth = os.path.join(os.path.dirname(__file__),"..") sys.path.append(pth) -import checkimage f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) s=f("clt",slice(0,12)) # read only 12 times steps to speed up things @@ -36,7 +32,7 @@ pth = os.path.join(src_pth,prefix) ret = 0 for p in pngs: print "Checking:",p - ret += checkimage.check_result_image(p,os.path.join(pth,os.path.split(p)[1]),checkimage.defaultThreshold) + ret += regression.check_result_image(p,os.path.join(pth,os.path.split(p)[1])) if ret == 0: os.removedirs(os.path.split(p)[0]) os.remove("%s.mp4" % prefix) diff --git a/testing/vcs/test_vcs_animate_meshfill.py b/testing/vcs/test_vcs_animate_meshfill.py index 78d6b1551..aa89a8639 100644 --- a/testing/vcs/test_vcs_animate_meshfill.py +++ b/testing/vcs/test_vcs_animate_meshfill.py @@ -1,12 +1,7 @@ -import vcs -import cdms2 -import os -import sys -import MV2 +import vcs, numpy, cdms2, MV2, os, sys, testing.regression as regression pth = os.path.join(os.path.dirname(__file__),"..") sys.path.append(pth) -import checkimage f=cdms2.open(os.path.join(vcs.sample_data,"sampleCurveGrid4.nc")) s=f("sample") @@ -38,8 +33,7 @@ src_pth = sys.argv[1] pth = os.path.join(src_pth,prefix) ret = 0 for p in pngs: - print "Checking:",p - ret += checkimage.check_result_image(p,os.path.join(pth,os.path.split(p)[1]),checkimage.defaultThreshold) + ret += regression.check_result_image(p,os.path.join(pth,os.path.split(p)[1])) if ret == 0: os.removedirs(os.path.split(p)[0]) os.remove("%s.mp4" % prefix) diff --git a/testing/vcs/test_vcs_antialiasing.py b/testing/vcs/test_vcs_antialiasing.py index 34f43e040..f744d3e04 100644 --- a/testing/vcs/test_vcs_antialiasing.py +++ b/testing/vcs/test_vcs_antialiasing.py @@ -1,4 +1,3 @@ - import vcs x=vcs.init() x.drawlogooff() diff --git a/testing/vcs/test_vcs_aspect_ratio.py b/testing/vcs/test_vcs_aspect_ratio.py index 1e59304a3..9e3cb3767 100644 --- a/testing/vcs/test_vcs_aspect_ratio.py +++ b/testing/vcs/test_vcs_aspect_ratio.py @@ -1,27 +1,20 @@ - -import vcs -import cdms2 -import sys -import os -import MV2 -import vcs,numpy,cdms2,MV2,os,sys -src=sys.argv[1] +import vcs, numpy, cdms2, MV2, os, sys, testing.regression as regression +src = sys.argv[1] pth0 = os.path.dirname(_file__) pth = os.path.join(pth0,"..") sys.path.append(pth) -import checkimage -f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) -s=f("clt",time=slice(0,1),squeeze=1) -gm=vcs.createisofill() +f = cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) +s = f("clt",time=slice(0,1),squeeze=1) +gm = vcs.createisofill() def plot_a_ratio(s,gm,ratio): ret = 0 - x=vcs.init() -x.drawlogooff() + x = regression.init() + x.drawlogooff() x.open() x.geometry(400,800) - y=vcs.init() + y = regression.init() y.open() y.geometry(800,400) for X in [x,y]: @@ -32,19 +25,13 @@ x.drawlogooff() orient = "port" fnm = "aspect_ratio_%s_%s.png" % (orient,ratio) X.png(fnm) - print "fnm:",fnm src = os.path.join(pth0,fnm) - print "src:",src - ret += checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) + ret += regression.check_result_image(fnm, src) return ret -ret = 0 +ret = 0 for ratio in ["1t","2t",".5t","autot"]: ret += plot_a_ratio(s,gm,ratio) -sys.exit(ret) - - - - +sys.exit(ret) \ No newline at end of file diff --git a/testing/vcs/test_vcs_auto_time_labels.py b/testing/vcs/test_vcs_auto_time_labels.py index 2dfa661a9..e5422b29c 100644 --- a/testing/vcs/test_vcs_auto_time_labels.py +++ b/testing/vcs/test_vcs_auto_time_labels.py @@ -1,18 +1,7 @@ -import vcs,cdms2,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) -s=f("clt",longitude=slice(34,35),squeeze=1) -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") +import vcs, cdms2, os, sys, testing.regression as regression + +f = cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) +s = f("clt",longitude=slice(34,35),squeeze=1) +x = regression.init() x.plot(s,bg=1) -fnm = "test_vcs_auto_time_labels.png" -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, "test_vcs_auto_time_labels.png", sys.argv[1]) \ No newline at end of file diff --git a/testing/vcs/test_vcs_autot_axis_titles.py b/testing/vcs/test_vcs_autot_axis_titles.py index ec485ccc0..dcc0f00b1 100644 --- a/testing/vcs/test_vcs_autot_axis_titles.py +++ b/testing/vcs/test_vcs_autot_axis_titles.py @@ -1,7 +1,4 @@ -import vcs -import cdms2 -import os -import sys +import vcs, cdms2, os, sys, testing.regression as regression testConfig = {'a_boxfill': ('clt.nc', 'clt'), 'a_mollweide_boxfill': ('clt.nc', 'clt'), @@ -11,10 +8,6 @@ testConfig = {'a_boxfill': ('clt.nc', 'clt'), 'a_robinson_isoline': ('clt.nc', 'clt')} # Tests if ratio=autot works correctly for background and foreground plots -src = sys.argv[1] -bg = 1 -if (sys.argv[2] == 'foreground'): - bg = 0 plot = sys.argv[3] x_over_y = sys.argv[4] if (x_over_y == '0.5'): @@ -26,12 +19,9 @@ else: pth = os.path.join(os.path.dirname(__file__), "..") sys.path.append(pth) -import checkimage - f = cdms2.open(vcs.sample_data + "/" + testConfig[plot][0]) s = f(testConfig[plot][1]) - -x = vcs.init(bg=bg, geometry=(xSize, ySize)) +x = regression.init(bg=bg, geometry=(xSize, ySize)) # graphics method if (plot.find('boxfill') != -1): @@ -50,10 +40,4 @@ x.setantialiasing(0) x.drawlogooff() x.plot(s, gm, ratio="autot") name = "test_autot_axis_titles_" + plot[2:] + "_" + x_over_y + "_" + str(bg) + ".png" -x.png(name) - -print "name:", name -print "src:", src - -ret = checkimage.check_result_image(name, src, checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, name, sys.argv[1]) \ No newline at end of file diff --git a/testing/vcs/test_vcs_bad_time_units.py b/testing/vcs/test_vcs_bad_time_units.py index b89c2f7a7..0bdcd16c2 100644 --- a/testing/vcs/test_vcs_bad_time_units.py +++ b/testing/vcs/test_vcs_bad_time_units.py @@ -1,8 +1,8 @@ -import cdms2,vcs -import os,sys +import cdms2, vcs +import os, sys -f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) -s=f("clt",slice(0,1)) +f = cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) +s = f("clt",slice(0,1)) s.getTime().units="XXX-))rvv" -x=vcs.init() -x.plot(s,bg=1) +x = vcs.init() +x.plot(s, bg=1) diff --git a/testing/vcs/test_vcs_basic_gms.py b/testing/vcs/test_vcs_basic_gms.py index daa144d9d..2cffb86e6 100644 --- a/testing/vcs/test_vcs_basic_gms.py +++ b/testing/vcs/test_vcs_basic_gms.py @@ -1,6 +1,4 @@ - -import sys,os -import argparse +import argparse, os, sys, cdms2, MV2, testing.regression as regression, vcs, vtk p = argparse.ArgumentParser(description="Basic gm testing code for vcs") p.add_argument("--source", dest="src", help="source image file") @@ -25,20 +23,9 @@ args = p.parse_args(sys.argv[1:]) gm_type= args.gm src = args.src -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage - -import vcs -import sys -import cdms2 -import vtk -import os -import MV2 - bg = not args.show -x=vcs.init() +x = vcs.init() x.setantialiasing(0) x.drawlogooff() if bg: @@ -143,7 +130,7 @@ print "fnm:",fnm print "src:",src if args.show: raw_input("Press Enter") -ret = checkimage.check_result_image(fnm+'.png',src,20., cleanup=not args.keep) +ret = regression.check_result_image(fnm+'.png',src,20., cleanup=not args.keep) if args.show: raw_input("Press Enter") sys.exit(ret) diff --git a/testing/vcs/test_vcs_basic_text.py b/testing/vcs/test_vcs_basic_text.py index d46bd4f48..d69f37ce0 100644 --- a/testing/vcs/test_vcs_basic_text.py +++ b/testing/vcs/test_vcs_basic_text.py @@ -1,11 +1,6 @@ -import vcs,numpy,cdms2,MV2,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage - -x=vcs.init() +import vcs, numpy, cdms2, MV2, os, sys, testing.regression as regression +x = regression.init() x.drawlogooff() x.setbgoutputdimensions(1200,1091,units="pixels") txt=x.createtext() @@ -16,10 +11,4 @@ txt.halign = "center" txt.valign="base" txt.angle=45 x.plot(txt,bg=1) -fnm = "test_basic_text.png" -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, "test_basic_text.png", sys.argv[1]) diff --git a/testing/vcs/test_vcs_basic_vectors.py b/testing/vcs/test_vcs_basic_vectors.py index 561f7f2d8..37626e670 100644 --- a/testing/vcs/test_vcs_basic_vectors.py +++ b/testing/vcs/test_vcs_basic_vectors.py @@ -1,6 +1,5 @@ +import argparse, os, sys, numpy, cdms2, MV2, vcs, vtk -import sys,os -import argparse p = argparse.ArgumentParser(description="Basic gm testing code for vcs") p.add_argument("--source", dest="src", help="source image file") @@ -18,21 +17,11 @@ args = p.parse_args(sys.argv[1:]) if not args.show: src = args.src - pth = os.path.join(os.path.dirname(__file__),"..") - sys.path.append(pth) - import checkimage - -import vcs -import sys -import cdms2 -import vtk -import os -import MV2 -import numpy + import testing.regression as regression bg = not args.show -x=vcs.init() +x = vcs.init() x.setantialiasing(0) x.drawlogooff() if bg: @@ -95,7 +84,7 @@ else: x.png(fnm) print "fnm:",fnm print "src:",src - ret = checkimage.check_result_image(fnm+'.png',src,checkimage.defaultThreshold, cleanup=not args.keep) + ret = regression.check_result_image(fnm+'.png',src, regression.defaultThreshold, cleanup=not args.keep) if args.show: raw_input("Press Enter") sys.exit(ret) diff --git a/testing/vcs/test_vcs_box_custom_as_def_vistrails_exts.py b/testing/vcs/test_vcs_box_custom_as_def_vistrails_exts.py index c012c09ca..7d81b8981 100644 --- a/testing/vcs/test_vcs_box_custom_as_def_vistrails_exts.py +++ b/testing/vcs/test_vcs_box_custom_as_def_vistrails_exts.py @@ -1,30 +1,12 @@ -import vcs -import cdms2 -import os -import sys -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage - -f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) -s=f("clt",slice(0,1),squeeze=1) - -x=vcs.init() -x.drawlogooff() -x.setantialiasing(0) -x.setbgoutputdimensions(1200,1091,units="pixels") - -gm=x.createboxfill() -gm.boxfill_type="custom" -gm.levels=[1.e20,1.e20] -gm.ext_1="y" -gm.ext_2="y" - -x.plot(s,gm,bg=1) -fnm = "test_box_custom_as_def_vistrails_exts.png" -src =sys.argv[1] -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +import os, sys, cdms2, vcs, testing.regression as regression + +f = cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) +s = f("clt",slice(0,1),squeeze=1) +x = regression.init() +gm = x.createboxfill() +gm.boxfill_type = "custom" +gm.levels = [1.e20,1.e20] +gm.ext_1 = "y" +gm.ext_2 = "y" +x.plot(s, gm, bg=1) +regression.run(x, "test_box_custom_as_def_vistrails_exts.png", sys.argv[1]) \ No newline at end of file diff --git a/testing/vcs/test_vcs_boxfill_10x10_masked_numpy.py b/testing/vcs/test_vcs_boxfill_10x10_masked_numpy.py index b2cdf8319..2444cc8a8 100644 --- a/testing/vcs/test_vcs_boxfill_10x10_masked_numpy.py +++ b/testing/vcs/test_vcs_boxfill_10x10_masked_numpy.py @@ -1,23 +1,9 @@ +import vcs, numpy, os, sys, testing.regression as regression -import vcs,numpy,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +s = numpy.sin(numpy.arange(100)) +s = numpy.reshape(s,(10,10)) +s = numpy.ma.masked_greater(s,.5) -s= numpy.sin(numpy.arange(100)) -s=numpy.reshape(s,(10,10)) -s=numpy.ma.masked_greater(s,.5) -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") -x.plot(s,bg=1) -fnm= "test_vcs_boxfill_10x10_masked_numpy.png" - -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +x = regression.init() +x.plot(s, bg=1) +regression.run(x, "test_vcs_boxfill_10x10_masked_numpy.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_boxfill_10x10_numpy.py b/testing/vcs/test_vcs_boxfill_10x10_numpy.py index 079105198..a45aa5889 100644 --- a/testing/vcs/test_vcs_boxfill_10x10_numpy.py +++ b/testing/vcs/test_vcs_boxfill_10x10_numpy.py @@ -1,22 +1,7 @@ +import vcs, numpy, os, sys, testing.regression as regression -import vcs,numpy,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage - -s= numpy.sin(numpy.arange(100)) -s=numpy.reshape(s,(10,10)) -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") -x.plot(s,bg=1) -fnm= "test_vcs_boxfill_10x10_numpy.png" - -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +s = numpy.sin(numpy.arange(100)) +s = numpy.reshape(s,(10,10)) +x = regression.init() +x.plot(s) +regression.run(x, "test_vcs_boxfill_10x10_numpy.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_boxfill_custom.py b/testing/vcs/test_vcs_boxfill_custom.py index 16685d971..5330a1103 100644 --- a/testing/vcs/test_vcs_boxfill_custom.py +++ b/testing/vcs/test_vcs_boxfill_custom.py @@ -1,7 +1,4 @@ -import cdms2 -import os -import sys -import vcs +import cdms2, os, sys, vcs, testing.regression as regression # Load the clt data: dataFile = cdms2.open(os.path.join(vcs.sample_data, "clt.nc")) @@ -10,10 +7,7 @@ clt = clt(latitude=(-90.0, 90.0), longitude=(-180., 175.), squeeze=1, time=('1979-1-1 0:0:0.0', '1988-12-1 0:0:0.0')) # Initialize canvas: -canvas = vcs.init() -canvas.setantialiasing(0) -canvas.setbgoutputdimensions(1200,1091,units="pixels") -canvas.drawlogooff() +canvas = regression.init() # Create and plot quick boxfill with default settings: boxfill=canvas.createboxfill() @@ -24,14 +18,5 @@ boxfill.boxfill_type = 'custom' canvas.plot(clt, boxfill, bg=1) # Load the image testing module: -testingDir = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(testingDir) -import checkimage - # Create the test image and compare: -baseline = sys.argv[1] -testFile = "test_boxfill_custom.png" -canvas.png(testFile) -ret = checkimage.check_result_image(testFile, baseline, - checkimage.defaultThreshold) -sys.exit(ret) +regression.run(canvas, "test_boxfill_custom.png") diff --git a/testing/vcs/test_vcs_boxfill_custom_ext1.py b/testing/vcs/test_vcs_boxfill_custom_ext1.py index dd16ab837..7a5e2005e 100644 --- a/testing/vcs/test_vcs_boxfill_custom_ext1.py +++ b/testing/vcs/test_vcs_boxfill_custom_ext1.py @@ -1,7 +1,4 @@ -import cdms2 -import os -import sys -import vcs +import cdms2, os, sys, vcs, testing.regression as regression # Load the clt data: dataFile = cdms2.open(os.path.join(vcs.sample_data, "clt.nc")) @@ -10,10 +7,7 @@ clt = clt(latitude=(-90.0, 90.0), longitude=(-180., 175.), squeeze=1, time=('1979-1-1 0:0:0.0', '1988-12-1 0:0:0.0')) # Initialize canvas: -canvas = vcs.init() -canvas.setantialiasing(0) -canvas.setbgoutputdimensions(1200,1091,units="pixels") -canvas.drawlogooff() +canvas = regression.init() # Create and plot quick boxfill with default settings: boxfill=canvas.createboxfill() @@ -28,14 +22,4 @@ boxfill.fillareacolors=vcs.getcolors(boxfill.levels) canvas.plot(clt, boxfill, bg=1) # Load the image testing module: -testingDir = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(testingDir) -import checkimage - -# Create the test image and compare: -baseline = sys.argv[1] -testFile = "test_boxfill_custom_ext1.png" -canvas.png(testFile) -ret = checkimage.check_result_image(testFile, baseline, - checkimage.defaultThreshold) -sys.exit(ret) +regression.run(canvas, "test_boxfill_custom_ext1.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_boxfill_custom_ext1_ext2.py b/testing/vcs/test_vcs_boxfill_custom_ext1_ext2.py index 68b5a9a41..744071671 100644 --- a/testing/vcs/test_vcs_boxfill_custom_ext1_ext2.py +++ b/testing/vcs/test_vcs_boxfill_custom_ext1_ext2.py @@ -1,7 +1,4 @@ -import cdms2 -import os -import sys -import vcs +import os, sys, cdms2, vcs, testing.regression as regression # Load the clt data: dataFile = cdms2.open(os.path.join(vcs.sample_data, "clt.nc")) @@ -10,10 +7,7 @@ clt = clt(latitude=(-90.0, 90.0), longitude=(-180., 175.), squeeze=1, time=('1979-1-1 0:0:0.0', '1988-12-1 0:0:0.0')) # Initialize canvas: -canvas = vcs.init() -canvas.setantialiasing(0) -canvas.setbgoutputdimensions(1200,1091,units="pixels") -canvas.drawlogooff() +canvas = regression.init() # Create and plot quick boxfill with default settings: boxfill=canvas.createboxfill() @@ -29,14 +23,4 @@ boxfill.fillareacolors=vcs.getcolors(boxfill.levels) canvas.plot(clt, boxfill, bg=1) # Load the image testing module: -testingDir = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(testingDir) -import checkimage - -# Create the test image and compare: -baseline = sys.argv[1] -testFile = "test_boxfill_custom_ext1_ext2.png" -canvas.png(testFile) -ret = checkimage.check_result_image(testFile, baseline, - checkimage.defaultThreshold) -sys.exit(ret) +regression.run(canvas, "test_boxfill_custom_ext1_ext2.png") diff --git a/testing/vcs/test_vcs_boxfill_custom_ext2.py b/testing/vcs/test_vcs_boxfill_custom_ext2.py index 959fc2c6c..d45950bdb 100644 --- a/testing/vcs/test_vcs_boxfill_custom_ext2.py +++ b/testing/vcs/test_vcs_boxfill_custom_ext2.py @@ -3,6 +3,8 @@ import os import sys import vcs +import testing.regression as regression + # Load the clt data: dataFile = cdms2.open(os.path.join(vcs.sample_data, "clt.nc")) clt = dataFile("clt") @@ -10,10 +12,7 @@ clt = clt(latitude=(-90.0, 90.0), longitude=(-180., 175.), squeeze=1, time=('1979-1-1 0:0:0.0', '1988-12-1 0:0:0.0')) # Initialize canvas: -canvas = vcs.init() -canvas.setantialiasing(0) -canvas.setbgoutputdimensions(1200,1091,units="pixels") -canvas.drawlogooff() +canvas = regression.init() # Create and plot quick boxfill with default settings: boxfill=canvas.createboxfill() @@ -27,15 +26,4 @@ boxfill.fillareacolors=vcs.getcolors(boxfill.levels) canvas.plot(clt, boxfill, bg=1) -# Load the image testing module: -testingDir = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(testingDir) -import checkimage - -# Create the test image and compare: -baseline = sys.argv[1] -testFile = "test_boxfill_custom_ext2.png" -canvas.png(testFile) -ret = checkimage.check_result_image(testFile, baseline, - checkimage.defaultThreshold) -sys.exit(ret) +regression.run(canvas, "test_boxfill_custom_ext2.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_boxfill_custom_non_default_levels.py b/testing/vcs/test_vcs_boxfill_custom_non_default_levels.py index 7363d2250..b84db2bb5 100644 --- a/testing/vcs/test_vcs_boxfill_custom_non_default_levels.py +++ b/testing/vcs/test_vcs_boxfill_custom_non_default_levels.py @@ -1,7 +1,4 @@ -import cdms2 -import os -import sys -import vcs +import cdms2, os, sys, vcs, testing.regression as regression # Load the clt data: dataFile = cdms2.open(os.path.join(vcs.sample_data, "clt.nc")) @@ -10,10 +7,7 @@ clt = clt(latitude=(-90.0, 90.0), longitude=(-180., 175.), squeeze=1, time=('1979-1-1 0:0:0.0', '1988-12-1 0:0:0.0')) # Initialize canvas: -canvas = vcs.init() -canvas.setantialiasing(0) -canvas.setbgoutputdimensions(1200,1091,units="pixels") -canvas.drawlogooff() +canvas = regression.init() # Create and plot quick boxfill with default settings: boxfill=canvas.createboxfill() @@ -25,16 +19,4 @@ boxfill.levels=levels boxfill.fillareacolors=vcs.getcolors(levels) canvas.plot(clt, boxfill, bg=1) - -# Load the image testing module: -testingDir = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(testingDir) -import checkimage - -# Create the test image and compare: -baseline = sys.argv[1] -testFile = "test_boxfill_custom_no_default_levels.png" -canvas.png(testFile) -ret = checkimage.check_result_image(testFile, baseline, - checkimage.defaultThreshold) -sys.exit(ret) +regression.run(canvas, "test_boxfill_custom_no_default_levels.png") diff --git a/testing/vcs/test_vcs_boxfill_decreasing_latitude.py b/testing/vcs/test_vcs_boxfill_decreasing_latitude.py index 009b947a9..1f727e3b5 100755 --- a/testing/vcs/test_vcs_boxfill_decreasing_latitude.py +++ b/testing/vcs/test_vcs_boxfill_decreasing_latitude.py @@ -1,23 +1,10 @@ #!/usr/bin/env python -import cdms2 -import cdutil -import os -import sys -import vcs - -pth = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(pth) -import checkimage +import cdms2, cdutil, os, sys, vcs, testing.regression as regression f = cdms2.open(sys.argv[2]) ice = f("variable_6") -x = vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200, 900, units="pixels") +x = regression.init() -#gm = x.createisofill() -#gm.label = "y" gm = x.createboxfill() gm.boxfill_type = "custom" @@ -44,12 +31,8 @@ tmpl.legend.y1 = .03 tmpl.legend.y2 = .055 tmpl.max.priority = 1 -#tmpl.crdate.priority=1 -#tmpl.crdate.x=.8 -#tmpl.crdate.y=.95 txt = x.createtext() txt.height = 20 -#txt.color=242 txt.valign = "half" txt.halign = "center" @@ -69,8 +52,4 @@ gm.datawc_y2 = 30 gm.datawc_y1 = 90 x.plot(ice, gm, tmpl, bg = 1) -fnm = "test_boxfill_decreasing_latitude.png" -x.png(fnm) -ret = checkimage.check_result_image(fnm, sys.argv[1], checkimage.defaultThreshold) -sys.exit(ret) - +regression.run(x, "test_boxfill_decreasing_latitude.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_boxfill_lambert_crash.py b/testing/vcs/test_vcs_boxfill_lambert_crash.py index f1827882f..f445ba555 100644 --- a/testing/vcs/test_vcs_boxfill_lambert_crash.py +++ b/testing/vcs/test_vcs_boxfill_lambert_crash.py @@ -1,17 +1,10 @@ #!/usr/bin/env python -import cdms2 -import os -import sys -import vcs - -pth = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(pth) -import checkimage +import cdms2, os, sys, vcs, testing.regression as regression f = cdms2.open(sys.argv[2]) -a=f("Z3") +a = f("Z3") -x=vcs.init() +x = regression.init() x.setantialiasing(0) x.drawlogooff() x.setbgoutputdimensions(1200, 900, units="pixels") @@ -24,6 +17,4 @@ x.plot(a(latitude=(20,60),longitude=(-160,-120)),b, bg=1) fileName = os.path.basename(__file__) fileName = os.path.splitext(fileName)[0] fileName += '.png' -x.png(fileName) -ret = checkimage.check_result_image(fileName, sys.argv[1], checkimage.defaultThreshold) -sys.exit(ret) +ret = regression.run(x, fileName) diff --git a/testing/vcs/test_vcs_boxfill_lev1_lev2.py b/testing/vcs/test_vcs_boxfill_lev1_lev2.py index 5c69d7af3..c5b5cbcbe 100644 --- a/testing/vcs/test_vcs_boxfill_lev1_lev2.py +++ b/testing/vcs/test_vcs_boxfill_lev1_lev2.py @@ -1,25 +1,10 @@ - -import cdms2,sys,vcs,sys,os -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -f=cdms2.open(vcs.sample_data+"/clt.nc") -s=f("clt",slice(0,1),squeeze=1) -b=x.createboxfill() -b.level_1=.5 -b.level_2=14.5 -x.plot(s,b,bg=1) - -fnm= "test_boxfill_lev1_lev2.png" - -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) - +import os, sys, cdms2, vcs, testing.regression as regression + +x = regression.init() +f = cdms2.open(vcs.sample_data+"/clt.nc") +s = f("clt",slice(0,1),squeeze=1) +b = x.createboxfill() +b.level_1 = .5 +b.level_2 = 14.5 +x.plot(s, b, bg=1) +regression.run(x, "test_boxfill_lev1_lev2.png") diff --git a/testing/vcs/test_vcs_boxfill_lev1_lev2_ext1.py b/testing/vcs/test_vcs_boxfill_lev1_lev2_ext1.py index 594949238..67f87029e 100644 --- a/testing/vcs/test_vcs_boxfill_lev1_lev2_ext1.py +++ b/testing/vcs/test_vcs_boxfill_lev1_lev2_ext1.py @@ -1,26 +1,11 @@ - -import cdms2,sys,vcs,sys,os -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -f=cdms2.open(vcs.sample_data+"/clt.nc") -s=f("clt",slice(0,1),squeeze=1) -b=x.createboxfill() -b.level_1=20 -b.level_2=80 -b.ext_1="y" -x.plot(s,b,bg=1) - -fnm= "test_boxfill_lev1_lev2_ext1.png" - -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) - +import os, sys, cdms2, vcs, testing.regression as regression + +x = regression.init() +f = cdms2.open(vcs.sample_data+"/clt.nc") +s = f("clt",slice(0,1),squeeze=1) +b = x.createboxfill() +b.level_1 = 20 +b.level_2 = 80 +b.ext_1 = "y" +x.plot(s, b, bg=1) +regression.run(x, "test_boxfill_lev1_lev2_ext1.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_boxfill_lev1_lev2_ext1_ext2.py b/testing/vcs/test_vcs_boxfill_lev1_lev2_ext1_ext2.py index 9e355d1e1..dc7958c59 100644 --- a/testing/vcs/test_vcs_boxfill_lev1_lev2_ext1_ext2.py +++ b/testing/vcs/test_vcs_boxfill_lev1_lev2_ext1_ext2.py @@ -1,27 +1,12 @@ - -import cdms2,sys,vcs,sys,os -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -f=cdms2.open(vcs.sample_data+"/clt.nc") -s=f("clt",slice(0,1),squeeze=1) -b=x.createboxfill() -b.level_1=20 -b.level_2=80 -b.ext_1="y" -b.ext_2="y" -x.plot(s,b,bg=1) - -fnm= "test_boxfill_lev1_lev2_ext1_ext2.png" - -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) - +import os, sys, cdms2, vcs, testing.regression as regression + +x = regression.init() +f = cdms2.open(vcs.sample_data+"/clt.nc") +s = f("clt", slice(0,1), squeeze=1) +b = x.createboxfill() +b.level_1 = 20 +b.level_2 = 80 +b.ext_1 = "y" +b.ext_2 = "y" +x.plot(s, b, bg=1) +regression.run(x, "test_boxfill_lev1_lev2_ext1_ext2.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_boxfill_lev1_lev2_ext2.py b/testing/vcs/test_vcs_boxfill_lev1_lev2_ext2.py index 375c93d8a..398325eab 100644 --- a/testing/vcs/test_vcs_boxfill_lev1_lev2_ext2.py +++ b/testing/vcs/test_vcs_boxfill_lev1_lev2_ext2.py @@ -1,26 +1,11 @@ - -import cdms2,sys,vcs,sys,os -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -f=cdms2.open(vcs.sample_data+"/clt.nc") -s=f("clt",slice(0,1),squeeze=1) -b=x.createboxfill() -b.level_1=20 -b.level_2=80 -b.ext_2="y" -x.plot(s,b,bg=1) - -fnm= "test_boxfill_lev1_lev2_ext2.png" - -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) - +import os, sys, cdms2, vcs, testing.regression as regression + +x = regression.init() +f = cdms2.open(vcs.sample_data+"/clt.nc") +s = f("clt",slice(0,1),squeeze=1) +b = x.createboxfill() +b.level_1 = 20 +b.level_2 = 80 +b.ext_2 = "y" +x.plot(s, b, bg=1) +regression.run(x, "test_boxfill_lev1_lev2_ext2.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_boxfill_lev1_lev2_ta_missing.py b/testing/vcs/test_vcs_boxfill_lev1_lev2_ta_missing.py index 984179e5c..d2a39a1ba 100644 --- a/testing/vcs/test_vcs_boxfill_lev1_lev2_ta_missing.py +++ b/testing/vcs/test_vcs_boxfill_lev1_lev2_ta_missing.py @@ -1,28 +1,11 @@ - -import cdms2,sys,vcs,sys,os -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") -f=cdms2.open(vcs.sample_data+"/ta_ncep_87-6-88-4.nc") -s=f("ta",slice(0,1),longitude=slice(34,35),squeeze=1)-273.15 -s=cdms2.MV2.masked_less(s,-45.) -b=x.createboxfill() -b.level_1=-40 -b.level_2=40 -x.plot(s,b,bg=1) - -fnm= "test_boxfill_lev1_lev2_ta_missing.png" - -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) -raw_input() - +import os, sys, cdms2, vcs, testing.regression as regression + +x = regression.init() +f = cdms2.open(vcs.sample_data+"/ta_ncep_87-6-88-4.nc") +s = f("ta",slice(0,1),longitude=slice(34,35),squeeze=1)-273.15 +s = cdms2.MV2.masked_less(s,-45.) +b = x.createboxfill() +b.level_1 = -40 +b.level_2 = 40 +x.plot(s, b, bg=1) +regression.run(x, "test_boxfill_lev1_lev2_ta_missing.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_boxfill_polar.py b/testing/vcs/test_vcs_boxfill_polar.py index e4f534c9d..869d09802 100644 --- a/testing/vcs/test_vcs_boxfill_polar.py +++ b/testing/vcs/test_vcs_boxfill_polar.py @@ -1,33 +1,16 @@ -#!/usr/bin/env python -import cdms2 -import os -import sys -import vcs +import os, sys, cdms2, vcs, testing.regression as regression -pth = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(pth) -import checkimage f = cdms2.open(vcs.sample_data + "/clt.nc") -a=f("clt") +a = f("clt") -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200, 900, units="pixels") - -p=x.getprojection("polar") -b=x.createboxfill() -b.projection=p -#b.datawc_y1 = 90 -#b.datawc_y2 = -90 - -x.setbgoutputdimensions(1200,1091,units="pixels") +x = regression.init() +p = x.getprojection("polar") +b = x.createboxfill() +b.projection = p x.plot(a(latitude=(90,-90)), b, bg=1) fileName = os.path.basename(__file__) fileName = os.path.splitext(fileName)[0] fileName += '.png' -x.png(fileName) -ret = checkimage.check_result_image(fileName, sys.argv[1], checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, fileName) \ No newline at end of file diff --git a/testing/vcs/test_vcs_boxfill_robinson_wrap.py b/testing/vcs/test_vcs_boxfill_robinson_wrap.py index 81b3206bd..de66e516c 100644 --- a/testing/vcs/test_vcs_boxfill_robinson_wrap.py +++ b/testing/vcs/test_vcs_boxfill_robinson_wrap.py @@ -1,15 +1,7 @@ -#!/usr/bin/env python -import cdms2, cdutil, genutil -import vcs,os -import sys +import os, sys, cdms2, cdutil, genutil, vcs, testing.regression as regression # This tests if extending the longitude to more than 360 decrees is handled correctly by # proj4. See https://github.com/UV-CDAT/uvcdat/issues/1728 for more information. -pth = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(pth) -import checkimage - - cdmsfile = cdms2.open(os.path.join(vcs.sample_data, "clt.nc")) clt2 = cdmsfile('clt') clt3 = clt2(latitude=(-90.0, 90.0),squeeze=1,longitude=(-180, 200.0),time=('1979-01', '1988-12'),) @@ -19,7 +11,4 @@ kwargs = {} kwargs[ 'cdmsfile' ] = cdmsfile.id kwargs['bg'] = 1 canvas.plot(clt3, gmBoxfill, **kwargs) -fnm = "test_robinson_wrap.png" -canvas.png(fnm) -ret = checkimage.check_result_image(fnm, sys.argv[1], checkimage.defaultThreshold) -sys.exit(ret) +regression.run(canvas, "test_robinson_wrap.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_canvas_background.py b/testing/vcs/test_vcs_canvas_background.py index 1d39b330d..2c72b51f3 100644 --- a/testing/vcs/test_vcs_canvas_background.py +++ b/testing/vcs/test_vcs_canvas_background.py @@ -1,19 +1,6 @@ -import vcs, cdms2, os, sys - -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage - -x = vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(500,500,units="pixels") +import os, sys, cdms2, vcs, testing.regression as regression +x = regression.init() x.backgroundcolor = (255, 255, 255) x.open() -fnm = "test_backgroundcolor_white.png" -x.png(fnm) - -src=sys.argv[1] -ret = checkimage.check_result_image(fnm, src, checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, "test_backgroundcolor_white.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_canvas_background_update.py b/testing/vcs/test_vcs_canvas_background_update.py index 454f0ef09..a28c08713 100644 --- a/testing/vcs/test_vcs_canvas_background_update.py +++ b/testing/vcs/test_vcs_canvas_background_update.py @@ -1,22 +1,8 @@ -import vcs, cdms2, os, sys - -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage - -x = vcs.init() - -x.drawlogooff() -x.setbgoutputdimensions(500,500, units="pixels") +import os, sys, cdms2, vcs, testing.regression as regression +x = regression.init() x.backgroundcolor = (255, 255, 255) x.open() x.backgroundcolor = (255, 255, 0) x.update() -fnm = "test_backgroundcolor_yellow.png" -x.png(fnm) - -src=sys.argv[1] -ret = checkimage.check_result_image(fnm, src, checkimage.defaultThreshold) - -sys.exit(ret) +regression.run(x, "test_backgroundcolor_yellow.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_click_info.py b/testing/vcs/test_vcs_click_info.py index 0fe587792..c16a6c0d4 100644 --- a/testing/vcs/test_vcs_click_info.py +++ b/testing/vcs/test_vcs_click_info.py @@ -1,7 +1,4 @@ -import cdms2 -import sys -import vcs -import os +import os, sys, cdms2, vcs, testing.regression as regression testConfig = {'a_boxfill': ('clt.nc', 'clt', (200, 200)), 'a_mollweide_boxfill': ('clt.nc', 'clt', (222, 322)), @@ -11,15 +8,7 @@ testConfig = {'a_boxfill': ('clt.nc', 'clt', (200, 200)), # Tests if the info produced when clicking on a map is correct. src = sys.argv[1] plot = sys.argv[2] -pth = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(pth) -import checkimage -x = vcs.init() -x.setantialiasing(0) -x.drawlogooff() -# Needs to set the size of window so it is consistent accross -# test platforms -x.open(814, 606) +x = regression.init() # data f = cdms2.open(vcs.sample_data + "/" + testConfig[plot][0]) @@ -47,7 +36,4 @@ fileName = os.path.basename(src) fileName = os.path.splitext(fileName)[0] fileName += '.png' -x.png(fileName, width=814, height= 606) - -ret = checkimage.check_result_image(fileName, src, checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, fileName) \ No newline at end of file diff --git a/testing/vcs/test_vcs_close.py b/testing/vcs/test_vcs_close.py index 7bf007224..3457a648e 100644 --- a/testing/vcs/test_vcs_close.py +++ b/testing/vcs/test_vcs_close.py @@ -1,7 +1,5 @@ import os, sys, vcs, cdms2 -#import checkimage -#src=sys.argv[1] pth = os.path.join(os.path.dirname(__file__),"..") sys.path.append(pth) cdmsfile = cdms2.open(vcs.sample_data+"/clt.nc") @@ -9,8 +7,4 @@ data = cdmsfile('clt') x = vcs.init() x.plot(data, bg=1) x.close() -#x.plot(data[4][1:89], bg=1) -#fnm = "test_vcs_close.png" -#x.png(fnm) -#ret = checkimage.check_result_image(fnm, src, checkimage.defaultThreshold) sys.exit(0) diff --git a/testing/vcs/test_vcs_colormaps_source.py b/testing/vcs/test_vcs_colormaps_source.py index 1dcc7d880..2cfc02721 100644 --- a/testing/vcs/test_vcs_colormaps_source.py +++ b/testing/vcs/test_vcs_colormaps_source.py @@ -1,27 +1,12 @@ -import vcs -import argparse -import cdms2 -import os -import sys - - -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +import argparse, os, sys, cdms2, vcs, testing.regression as regression parser = argparse.ArgumentParser() - parser.add_argument("-g",dest="gm",default="boxfill",choices = ["boxfill","isofill","meshfill","isoline","vector","1d"]) parser.add_argument("-s",dest="src",default="vcs",choices=["vcs","canvas","gm"]) parser.add_argument("-b",dest="baseline") - - args = parser.parse_args() -x=vcs.init() -x.setantialiasing(0) -x.setbgoutputdimensions(1200, 1091, units="pixels") -x.drawlogooff() +x = regression.init() exec("gm = x.create%s()" % args.gm) @@ -55,7 +40,4 @@ else: fnm = "test_vcs_colormaps_source_%s_%s.png" % (args.gm,args.src) x.png(fnm) baselineImage = args.baseline -ret = checkimage.check_result_image(fnm, baselineImage, - checkimage.defaultThreshold) - -sys.exit(ret) +ret = regression.run(x, fnm, baselineImage) \ No newline at end of file diff --git a/testing/vcs/test_vcs_colorpicker_appearance.py b/testing/vcs/test_vcs_colorpicker_appearance.py index c92534071..4ccba61fd 100644 --- a/testing/vcs/test_vcs_colorpicker_appearance.py +++ b/testing/vcs/test_vcs_colorpicker_appearance.py @@ -1,7 +1,6 @@ import vcs, vtk picker = vcs.colorpicker.ColorPicker(500, 250, None, 0) - win = picker.render_window win.Render() @@ -16,8 +15,6 @@ png_writer.Write() import sys, os if len(sys.argv) > 1: - src = sys.argv[1] - sys.path.append(os.path.join(os.path.dirname(__file__), "..")) - import checkimage - ret = checkimage.check_result_image(fnm, src, checkimage.defaultThreshold) + import testing.regression as regression + ret = regression.check_result_image(fnm, sys.argv[1]) sys.exit(ret) diff --git a/testing/vcs/test_vcs_configurator_resize.py b/testing/vcs/test_vcs_configurator_resize.py index b6179626d..7692e6218 100644 --- a/testing/vcs/test_vcs_configurator_resize.py +++ b/testing/vcs/test_vcs_configurator_resize.py @@ -20,9 +20,7 @@ png_writer.Write() import sys, os if len(sys.argv) > 1: - pth = os.path.join(os.path.dirname(__file__), "..") - sys.path.append(pth) - import checkimage + import testing.regression as regression src = sys.argv[1] - ret = checkimage.check_result_image(fnm, src, checkimage.defaultThreshold) - sys.exit(ret) + ret = regression.check_result_image(fnm, src) + sys.exit(ret) \ No newline at end of file diff --git a/testing/vcs/test_vcs_continents.py b/testing/vcs/test_vcs_continents.py index 9ae3d62de..c102df9de 100644 --- a/testing/vcs/test_vcs_continents.py +++ b/testing/vcs/test_vcs_continents.py @@ -1,22 +1,14 @@ -import cdms2 -import os -import sys -import vcs -import EzTemplate +import os, sys, EzTemplate, cdms2, vcs, testing.regression as regression # Load the clt data: dataFile = cdms2.open(os.path.join(vcs.sample_data, "clt.nc")) clt = dataFile("clt", time="1979-1-1", squeeze=1) - # Zero out the array so we can see the continents clearly clt[:] = 0 # Initialize canvas: -canvas = vcs.init() -canvas.setantialiasing(0) -canvas.setbgoutputdimensions(1200, 1091, units="pixels") -canvas.drawlogooff() +canvas = regression.init() # Create and plot quick boxfill with default settings: boxfill = canvas.createboxfill() @@ -64,15 +56,4 @@ for i in range(12): canvas.plot(clt, template, boxfill, continents=7, continents_line=cont_line, bg=1) os.environ["UVCDAT_DIR"] = current_dotdir -# Load the image testing module: -testingDir = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(testingDir) -import checkimage - -# Create the test image and compare: -baseline = sys.argv[1] -testFile = "test_continents.png" -canvas.png(testFile) -ret = checkimage.check_result_image(testFile, baseline, - 25) -sys.exit(ret) +regression.run(canvas, "test_continents.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_create_get.py b/testing/vcs/test_vcs_create_get.py index ec525d1b4..adb879d64 100644 --- a/testing/vcs/test_vcs_create_get.py +++ b/testing/vcs/test_vcs_create_get.py @@ -1,4 +1,3 @@ - import vcs x=vcs.init() x.drawlogooff() diff --git a/testing/vcs/test_vcs_draw_logo_on.py b/testing/vcs/test_vcs_draw_logo_on.py index 65271eb15..4a0c28d2c 100644 --- a/testing/vcs/test_vcs_draw_logo_on.py +++ b/testing/vcs/test_vcs_draw_logo_on.py @@ -1,19 +1,9 @@ -import vcs,numpy,cdms2,MV2,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +import vcs, numpy, cdms2, MV2, os, sys, testing.regression as regression -x=vcs.init() -x.setantialiasing(0) -x.setbgoutputdimensions(1200,1091,units="pixels") +x = vcs.init() a=numpy.arange(100) a.shape=(10,10) x.plot(a,bg=1) fnm = "test_vcs_draw_logo_on.png" x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.check_result_image(fnm, sys.argv[1]) diff --git a/testing/vcs/test_vcs_fillarea_transparency.py b/testing/vcs/test_vcs_fillarea_transparency.py index dc3a8bf4b..831b3e029 100644 --- a/testing/vcs/test_vcs_fillarea_transparency.py +++ b/testing/vcs/test_vcs_fillarea_transparency.py @@ -1,13 +1,6 @@ -import vcs -import sys,os -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +import vcs, sys, os, testing.regression as regression -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1090,units="pixels") +x = regression.init() fa1 = x.createfillarea() @@ -29,8 +22,4 @@ x.plot(fa1,bg=True) x.plot(fa2,bg=True) fnm = os.path.split(__file__[:-2]+"png")[-1] -x.png(fnm) -src = sys.argv[1] - -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, fnm) \ No newline at end of file diff --git a/testing/vcs/test_vcs_first_png_blank.py b/testing/vcs/test_vcs_first_png_blank.py index d11c59e6d..1e0bd8e28 100644 --- a/testing/vcs/test_vcs_first_png_blank.py +++ b/testing/vcs/test_vcs_first_png_blank.py @@ -1,20 +1,7 @@ +import vcs, numpy, cdms2, MV2, os, sys, testing.regression as regression -import vcs,numpy,cdms2,MV2,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) T=f('clt') -v = vcs.init() -v.setantialiasing(0) -v.setbgoutputdimensions(1200,1091,units="pixels") +v = regression.init() v.plot(T,bg=1) -# This will write a blank plot to a file: -fnm = "first_png_blank.png" -v.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(v, 'first_png_blank.png') \ No newline at end of file diff --git a/testing/vcs/test_vcs_flipNone.py b/testing/vcs/test_vcs_flipNone.py index a76e271f1..79b69ffdd 100644 --- a/testing/vcs/test_vcs_flipNone.py +++ b/testing/vcs/test_vcs_flipNone.py @@ -1,26 +1,8 @@ +import vcs, numpy, cdms2, MV2, os, sys, testing.regression as regression -import vcs,numpy,cdms2,MV2,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() - -x.setbgoutputdimensions(1200,1091,units="pixels") - -f=cdms2.open(os.path.join(vcs.sample_data,"ta_ncep_87-6-88-4.nc")) - - +x = regression.init() +f = cdms2.open(os.path.join(vcs.sample_data,"ta_ncep_87-6-88-4.nc")) vr = "ta" s=f(vr,slice(0,1),longitude=slice(90,91),squeeze=1,level=(0,10000)) x.plot(s,bg=1) -fnm = "test_vcs_flipNone.png" -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) - - +regression.run(x, 'test_vcs_flipNone.png') \ No newline at end of file diff --git a/testing/vcs/test_vcs_flipX.py b/testing/vcs/test_vcs_flipX.py index 0de7001aa..e211bf16a 100644 --- a/testing/vcs/test_vcs_flipX.py +++ b/testing/vcs/test_vcs_flipX.py @@ -1,26 +1,8 @@ +import vcs, numpy, cdms2, MV2, os, sys, testing.regression as regression -import vcs,numpy,cdms2,MV2,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() - -x.setbgoutputdimensions(1200,1091,units="pixels") - -f=cdms2.open(os.path.join(vcs.sample_data,"ta_ncep_87-6-88-4.nc")) - - +x = regression.init() +f = cdms2.open(os.path.join(vcs.sample_data,"ta_ncep_87-6-88-4.nc")) vr = "ta" s=f(vr,slice(0,1),longitude=slice(90,91),squeeze=1,latitude=(90,-90),level=(0,10000)) x.plot(s,bg=1) -fnm = "test_vcs_flipX.png" -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) - - +regression.run(x, 'test_vcs_flipX.png') \ No newline at end of file diff --git a/testing/vcs/test_vcs_flipXY.py b/testing/vcs/test_vcs_flipXY.py index 8dd0f8d89..779a0fe7e 100644 --- a/testing/vcs/test_vcs_flipXY.py +++ b/testing/vcs/test_vcs_flipXY.py @@ -1,26 +1,9 @@ +import vcs, numpy, cdms2, MV2, os, sys, testing.regression as regression -import vcs,numpy,cdms2,MV2,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() - -x.setbgoutputdimensions(1200,1091,units="pixels") - -f=cdms2.open(os.path.join(vcs.sample_data,"ta_ncep_87-6-88-4.nc")) - +x = regression.init() +f = cdms2.open(os.path.join(vcs.sample_data,"ta_ncep_87-6-88-4.nc")) vr = "ta" s=f(vr,slice(0,1),longitude=slice(90,91),squeeze=1,latitude=(90,-90)) x.plot(s,bg=1) -fnm = "test_vcs_flipXY.png" -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) - - +regression.run(x, 'test_vcs_flipXY.png') \ No newline at end of file diff --git a/testing/vcs/test_vcs_flipY.py b/testing/vcs/test_vcs_flipY.py index 7194f3f30..5efa57745 100644 --- a/testing/vcs/test_vcs_flipY.py +++ b/testing/vcs/test_vcs_flipY.py @@ -1,26 +1,8 @@ +import vcs, numpy, cdms2, MV2, os, sys, testing.regression as regression -import vcs,numpy,cdms2,MV2,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() - -x.setbgoutputdimensions(1200,1091,units="pixels") - +x = regression.init() f=cdms2.open(os.path.join(vcs.sample_data,"ta_ncep_87-6-88-4.nc")) - - vr = "ta" s=f(vr,slice(0,1),longitude=slice(90,91),squeeze=1) x.plot(s,bg=1) -fnm = "test_vcs_flipY.png" -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) - - +regression.run(x, 'test_vcs_flipY.png') \ No newline at end of file diff --git a/testing/vcs/test_vcs_gen_meshfill.py b/testing/vcs/test_vcs_gen_meshfill.py index b726a20a6..e59940554 100644 --- a/testing/vcs/test_vcs_gen_meshfill.py +++ b/testing/vcs/test_vcs_gen_meshfill.py @@ -1,39 +1,16 @@ +import os, sys, numpy, vcs, testing.regression as regression -import vcs,numpy,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage - -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") - +x = regression.init() data = numpy.array([1,2,3,4]) - blon = numpy.array([-1,1,1,0,-1]) blat = numpy.array([0,0,1,2,1]) - acell=numpy.array([blat,blon]) bcell = numpy.array([blat,blon+2.5]) ccell = numpy.array([blat+2.5,blon+2.5]) dcell = numpy.array([blat+2.5,blon]) - mesh = numpy.array([acell,bcell,ccell,dcell]) - m=x.createmeshfill() x.plot(data,mesh,m,bg=1) - - -fnm = "test_vcs_gen_meshfill.png" -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) - - +regression.run(x, "test_vcs_gen_meshfill.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_gms_animate_projected_plots.py b/testing/vcs/test_vcs_gms_animate_projected_plots.py index 2e521cd4a..3de234e41 100644 --- a/testing/vcs/test_vcs_gms_animate_projected_plots.py +++ b/testing/vcs/test_vcs_gms_animate_projected_plots.py @@ -1,15 +1,5 @@ # Test animation of projected plots - -import argparse -import cdms2 -import MV2 -import os -import sys -import vcs - -pth = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(pth) -import checkimage # noqa +import argparse, os, sys, cdms2, MV2, vcs, testing.regression as regression p = argparse.ArgumentParser(description="Testing animation of projected plots") p.add_argument("--gm_type", dest="gm", help="gm to test") @@ -19,18 +9,13 @@ p.add_argument("--source", dest="src", help="path to baseline image") p.add_argument("--keep", dest="keep", action="store_true", default=False, help="Save images, even if baseline matches.") p.add_argument("--threshold", dest="threshold", type=int, - default=checkimage.defaultThreshold, + default=regression.defaultThreshold, help="Threshold value for image differnces") args = p.parse_args(sys.argv[1:]) gm_type = args.gm - -x = vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200, 1091, units="pixels") - +x = regression.init() s = None if gm_type == "meshfill": @@ -72,7 +57,7 @@ pngs = x.animate.close(preserve_pngs=True) # so we can look at them again ret = 0 pdir = os.path.split(pngs[0])[0] p = pdir + os.sep + "anim_0.png" -ret = checkimage.check_result_image(p, args.src, args.threshold) +ret = regression.check_result_image(p, args.src, args.threshold) if ret == 0 and not args.keep: for f in pngs: if os.path.isfile(f): diff --git a/testing/vcs/test_vcs_gms_patterns_hatches.py b/testing/vcs/test_vcs_gms_patterns_hatches.py index 4030429a0..a7681a420 100644 --- a/testing/vcs/test_vcs_gms_patterns_hatches.py +++ b/testing/vcs/test_vcs_gms_patterns_hatches.py @@ -1,14 +1,4 @@ -# Test the use of patterns/hatches for plots - -import argparse -import cdms2 -import os -import sys -import vcs - -pth = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(pth) -import checkimage # noqa +import argparse, os, sys, cdms2, vcs, testing.regression as regression p = argparse.ArgumentParser(description="Patterns/hatches testing code for vcs gms") p.add_argument("--source", dest="src", help="source image file") @@ -22,7 +12,7 @@ p.add_argument("--lat2", dest="lat2", default=90, type=float, help="Last latitud p.add_argument("--lon1", dest="lon1", default=-180, type=float, help="First Longitude") p.add_argument("--lon2", dest="lon2", default=180, type=float, help="Last Longitude") p.add_argument("--keep", dest="keep", action="store_true", help="Save image, even if baseline matches.") -p.add_argument("--threshold", dest="threshold", type=int, default=checkimage.defaultThreshold, +p.add_argument("--threshold", dest="threshold", type=int, default=regression.defaultThreshold, help="Default threshold") p.add_argument("--non-contiguous", dest="contig", default=True, action="store_false", help="use non contiguous levels") @@ -98,7 +88,7 @@ fnm += nm_xtra x.png(fnm) print "fnm:", fnm print "src:", src -ret = checkimage.check_result_image(fnm+'.png', src, +ret = regression.check_result_image(fnm+'.png', src, args.threshold, cleanup=not args.keep) if args.show: diff --git a/testing/vcs/test_vcs_hatches_patterns.py b/testing/vcs/test_vcs_hatches_patterns.py index 8cd1766f0..8a467259c 100644 --- a/testing/vcs/test_vcs_hatches_patterns.py +++ b/testing/vcs/test_vcs_hatches_patterns.py @@ -1,17 +1,6 @@ -import os -import sys -import vcs +import os, sys, vcs, testing.regression as regression -pth = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(pth) -import checkimage - -baselineImage = sys.argv[1] - -# Initialize the graphics canvas -x = vcs.init() -x.setantialiasing(0) -x.setbgoutputdimensions(1200, 1091, units="pixels") +x = regression.init() # Create a test plot for listing all the hatches and patterns style_list = [] @@ -77,11 +66,4 @@ plot_title.y = [.9] x.plot(plot_title, bg=1) x.plot(fill_test, bg=1) x.plot(fill_info, bg=1) - -testImage = os.path.abspath("test_vcs_hatches_patterns.png") -x.png(testImage) - -ret = checkimage.check_result_image(testImage, baselineImage, - checkimage.defaultThreshold) - -sys.exit(ret) +regression.run(x, "test_vcs_hatches_patterns.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_import.py b/testing/vcs/test_vcs_import.py index c12242125..01c3d0447 100644 --- a/testing/vcs/test_vcs_import.py +++ b/testing/vcs/test_vcs_import.py @@ -1,3 +1,2 @@ - import vcs diff --git a/testing/vcs/test_vcs_infinity.py b/testing/vcs/test_vcs_infinity.py index 235f551eb..daf406016 100644 --- a/testing/vcs/test_vcs_infinity.py +++ b/testing/vcs/test_vcs_infinity.py @@ -1,28 +1,16 @@ - -import vcs,numpy,cdms2,MV2,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -import numpy +import os, sys, numpy, MV2, cdms2, testing.regression as regression s= numpy.sin(numpy.arange(100)) -s=numpy.reshape(s,(10,10)) +s = numpy.reshape(s,(10,10)) s[4,6] = numpy.inf s[7,9] = numpy.NINF s[9,2] = numpy.nan -x=vcs.init() +x = regression.init() x.setantialiasing(0) x.drawlogooff() x.setbgoutputdimensions(1200,1091,units="pixels") x.plot(s,bg=1) fnm = "infinity.png" -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) - +regression.run(x, fnm) \ No newline at end of file diff --git a/testing/vcs/test_vcs_iso_celine_part1.py b/testing/vcs/test_vcs_iso_celine_part1.py index 586918d36..a8fcc5ae7 100644 --- a/testing/vcs/test_vcs_iso_celine_part1.py +++ b/testing/vcs/test_vcs_iso_celine_part1.py @@ -1,22 +1,13 @@ +import os,sys, MV2, numpy, vcs, cdms2, testing.regression as regression -import vcs,numpy,cdms2,MV2,os,sys src=sys.argv[1] pth0 = os.path.dirname(__file__) -pth = os.path.join(pth0,"..") -sys.path.append(pth) -import checkimage -f=cdms2.open(os.path.join(pth0,"celine.nc")) -s=f("data") -x=vcs.init() +f = cdms2.open(os.path.join(pth0,"celine.nc")) +s = f("data") +x = regression.init() x.setantialiasing(0) -x.drawlogooff() x.scriptrun(os.path.join(pth0,"celine.json")) -i=x.getisofill("celine") +i = x.getisofill("celine") x.plot(s,i,bg=1) fnm = "test_celine_iso.png" -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, fnm) \ No newline at end of file diff --git a/testing/vcs/test_vcs_iso_celine_part2.py b/testing/vcs/test_vcs_iso_celine_part2.py index f99f821da..c1c1df5b1 100644 --- a/testing/vcs/test_vcs_iso_celine_part2.py +++ b/testing/vcs/test_vcs_iso_celine_part2.py @@ -1,26 +1,15 @@ +import os, sys, MV2, numpy, vcs, cdms2, testing.regression as regression -import vcs,numpy,cdms2,MV2,os,sys -src=sys.argv[1] pth0 = os.path.dirname(__file__) -pth = os.path.join(pth0,"..") -sys.path.append(pth) -import checkimage -f=cdms2.open(os.path.join(pth0,"celine.nc")) -s=f("data") -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() +f = cdms2.open(os.path.join(pth0,"celine.nc")) +s = f("data") +x = regression.init() x.scriptrun(os.path.join(pth0,"celine.json")) -i=x.getisofill("celine") -b=vcs.createboxfill() +i = x.getisofill("celine") +b = vcs.createboxfill() b.levels=i.levels b.fillareacolors=i.fillareacolors b.boxfill_type="custom" x.plot(s,b,bg=1) fnm = "test_celine_iso_2.png" -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, fnm) \ No newline at end of file diff --git a/testing/vcs/test_vcs_isofill_data_read_north_to_south.py b/testing/vcs/test_vcs_isofill_data_read_north_to_south.py index 5f12f65b0..8d1cc949c 100644 --- a/testing/vcs/test_vcs_isofill_data_read_north_to_south.py +++ b/testing/vcs/test_vcs_isofill_data_read_north_to_south.py @@ -1,24 +1,10 @@ -import cdms2 -import vcs -import sys -import os -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +import os, sys, cdms2, vcs, testing.regression as regression + f = cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) clt = f("clt",latitude=(80.0, 38.0),squeeze=1,longitude=(-180.0, 180.0),time=slice(0,1)) -x = vcs.init() -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") -x.setantialiasing(0) +x = regression.init() gm = vcs.createisofill() gm.projection="polar" x.plot( clt,gm,bg=1) fnm = os.path.split(__file__)[-1][:-2]+"png" -src= sys.argv[1] -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, fnm) \ No newline at end of file diff --git a/testing/vcs/test_vcs_isofill_isoline_labels.py b/testing/vcs/test_vcs_isofill_isoline_labels.py index d230fc8fc..192ffc4bf 100644 --- a/testing/vcs/test_vcs_isofill_isoline_labels.py +++ b/testing/vcs/test_vcs_isofill_isoline_labels.py @@ -1,24 +1,10 @@ -import vcs,cdms2,sys,os - -baselineImage = sys.argv[1] - -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +import os, sys, cdms2, vcs, testing.regression as regression dataset = cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) data = dataset("clt") - -canvas = vcs.init() -canvas.setantialiasing(0) -canvas.setbgoutputdimensions(1200, 1091, units="pixels") -canvas.drawlogooff() - +canvas = regression.init() isofill = canvas.createisofill() - -# First plot the isofill canvas.plot(data, isofill, bg=1) - isoline = canvas.createisoline() isoline.label="y" texts=[] @@ -35,13 +21,6 @@ for i in range(10): isoline.text = texts isoline.linecolors = colors -# Next plot the isolines with labels +# Plot the isolines with labels canvas.plot(data, isoline, bg=1) - -testImage = os.path.abspath("test_isofill_isoline_labels.png") -canvas.png(testImage) - -ret = checkimage.check_result_image(testImage, baselineImage, - checkimage.defaultThreshold) - -sys.exit(ret) +regression.run(canvas, "test_isofill_isoline_labels.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_isofill_mask_cell_shift.py b/testing/vcs/test_vcs_isofill_mask_cell_shift.py index 9bc867113..199b1586d 100644 --- a/testing/vcs/test_vcs_isofill_mask_cell_shift.py +++ b/testing/vcs/test_vcs_isofill_mask_cell_shift.py @@ -1,25 +1,8 @@ -import os,sys -import MV2 -import vcs -import cdms2 -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() - -x.setbgoutputdimensions(1200,1091,units="pixels") - -f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) -s=f("clt",slice(0,1),latitude=(30,70),longitude=(-130,-60)) -s2=MV2.masked_greater(s,65.) +import os, sys, MV2, cdms2, vcs, testing.regression as regression +x = regression.init() +f = cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) +s = f("clt",slice(0,1),latitude=(30, 70),longitude=(-130, -60)) +s2 = MV2.masked_greater(s, 65.) x.plot(s2,"default","isofill",bg=1) -fnm = "test_vcs_isofill_mask_cell_shift.png" -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, "test_vcs_isofill_mask_cell_shift.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_isoline_labels.py b/testing/vcs/test_vcs_isoline_labels.py index 77033f2c8..460235431 100644 --- a/testing/vcs/test_vcs_isoline_labels.py +++ b/testing/vcs/test_vcs_isoline_labels.py @@ -1,20 +1,8 @@ -import vcs,cdms2,sys,os - -# ('/path/to/filename', '.extension') -baseline = os.path.splitext(sys.argv[1]) - -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +import os, sys, cdms2, vcs, testing.regression as regression dataset = cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) data = dataset("clt") - -canvas = vcs.init() -canvas.setantialiasing(0) -canvas.setbgoutputdimensions(1200, 1091, units="pixels") -canvas.drawlogooff() - +canvas = regression.init() isoline = canvas.createisoline() isoline.label="y" texts=[] @@ -33,24 +21,17 @@ isoline.text = texts # First test using isoline.text[...].color canvas.plot(data, isoline, bg=1) +baseline = os.path.splitext(sys.argv[1]) baselineImage = "%s%s"%baseline -testImage = os.path.abspath("test_isoline_labels.png") -canvas.png(testImage) - -ret = checkimage.check_result_image(testImage, baselineImage, - checkimage.defaultThreshold) +ret = regression.run_wo_terminate(canvas, "test_isoline_labels.png", baselineImage) # Now set isoline.linecolors and test again. canvas.clear() isoline.linecolors = colors canvas.plot(data, isoline, bg=1) - baselineImage = "%s%d%s"%(baseline[0], 2, baseline[1]) testImage = os.path.abspath("test_isoline_labels2.png") -canvas.png(testImage) - -ret += checkimage.check_result_image(testImage, baselineImage, - checkimage.defaultThreshold) +ret += regression.run_wo_terminate(canvas, testImage, baselineImage) # Now set isoline.textcolors and test again. canvas.clear() @@ -59,9 +40,6 @@ canvas.plot(data, isoline, bg=1) baselineImage = "%s%d%s"%(baseline[0], 3, baseline[1]) testImage = os.path.abspath("test_isoline_labels3.png") -canvas.png(testImage) - -ret += checkimage.check_result_image(testImage, baselineImage, - checkimage.defaultThreshold) +ret += regression.run_wo_terminate(canvas, testImage, baselineImage) sys.exit(ret) diff --git a/testing/vcs/test_vcs_isoline_labels_background.py b/testing/vcs/test_vcs_isoline_labels_background.py index da1d1e6ac..08088836a 100644 --- a/testing/vcs/test_vcs_isoline_labels_background.py +++ b/testing/vcs/test_vcs_isoline_labels_background.py @@ -1,26 +1,13 @@ -import cdms2 -import os -import sys -import vcs +import os, sys, cdms2, vcs, testing.regression as regression import random -# ('/path/to/filename', '.extension') -baseline = os.path.splitext(sys.argv[1]) - -pth = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(pth) -import checkimage - (latmin, latmax, lonmin, lonmax) = (-90, 90, -180, 180) dataset = cdms2.open(os.path.join(vcs.sample_data, "tas_cru_1979.nc")) data = dataset("tas", time=slice(0, 1), latitude=(latmin, latmax), longitude=(lonmin, lonmax, 'co'), squeeze=1) dataset.close() -canvas = vcs.init() -canvas.setantialiasing(0) -canvas.setbgoutputdimensions(1200, 1091, units="pixels") -canvas.drawlogooff() +canvas = regression.init() canvas.backgroundcolor = [100, 105, 105] isoline = canvas.createisoline() @@ -50,11 +37,6 @@ isoline.labelskipdistance = 15.0 # First test using isoline.text[...].color canvas.plot(data, isoline, bg=1) - +baseline = os.path.splitext(sys.argv[1]) baselineImage = "%s%s" % baseline -testImage = os.path.abspath("test_isoline_labels_background.png") -canvas.png(testImage) - -ret = checkimage.check_result_image(testImage, baselineImage, - checkimage.defaultThreshold) -sys.exit(ret) +regression.run(canvas, baselineImage) \ No newline at end of file diff --git a/testing/vcs/test_vcs_isoline_labels_multi_label_input_types.py b/testing/vcs/test_vcs_isoline_labels_multi_label_input_types.py index da5e5d3c3..8c6e13a7e 100644 --- a/testing/vcs/test_vcs_isoline_labels_multi_label_input_types.py +++ b/testing/vcs/test_vcs_isoline_labels_multi_label_input_types.py @@ -1,30 +1,18 @@ -import vcs -import cdms2 -import os,sys -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) -s=f("clt") -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") -iso=x.createisoline() -t=x.createtext() -t.color=243 -t.height=25 -to=x.createtextorientation() -to.height = 55 -tt=x.createtexttable() -tt.color=245 -iso.textcolors=[None,None,None,242,244] -iso.text=[t,tt,to] -iso.label="y" -x.plot(s,iso,bg=1) -x.png("test_vcs_isoline_labels_multi_label_input_types.png") - -src=sys.argv[1] +import os, sys, cdms2, vcs, testing.regression as regression -ret = checkimage.check_result_image('test_vcs_isoline_labels_multi_label_input_types.png',src,checkimage.defaultThreshold) -sys.exit(ret) +f = cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) +s = f("clt") +x = regression.init() +iso = x.createisoline() +t = x.createtext() +t.color = 243 +t.height = 25 +to = x.createtextorientation() +to.height = 55 +tt = x.createtexttable() +tt.color = 245 +iso.textcolors = [None,None,None,242,244] +iso.text = [t,tt,to] +iso.label = "y" +x.plot(s, iso, bg=1) +regression.run(x, "test_vcs_isoline_labels_multi_label_input_types.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_isoline_labelskipdistance.py b/testing/vcs/test_vcs_isoline_labelskipdistance.py index 04ecdfabb..4b119e0bc 100644 --- a/testing/vcs/test_vcs_isoline_labelskipdistance.py +++ b/testing/vcs/test_vcs_isoline_labelskipdistance.py @@ -1,21 +1,8 @@ -import cdms2 -import os -import sys -import vcs - -baselineImage = sys.argv[1] - -pth = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(pth) -import checkimage +import os, sys, cdms2, vcs, testing.regression as regression dataset = cdms2.open(os.path.join(vcs.sample_data, "clt.nc")) data = dataset("clt") - -canvas = vcs.init() -canvas.setantialiasing(0) -canvas.setbgoutputdimensions(1200, 1091, units="pixels") -canvas.drawlogooff() +canvas = regression.init() isoline = canvas.createisoline() isoline.label = "y" @@ -36,11 +23,4 @@ isoline.linecolors = colors # Next plot the isolines with labels canvas.plot(data, isoline, bg=1) - -testImage = os.path.abspath("test_isoline_labelskipdistance.png") -canvas.png(testImage) - -ret = checkimage.check_result_image(testImage, baselineImage, - checkimage.defaultThreshold) - -sys.exit(ret) +regression.run(canvas, "test_isoline_labelskipdistance.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_isoline_numpy.py b/testing/vcs/test_vcs_isoline_numpy.py index ced140e77..147f2f499 100644 --- a/testing/vcs/test_vcs_isoline_numpy.py +++ b/testing/vcs/test_vcs_isoline_numpy.py @@ -1,21 +1,13 @@ -import vcs,cdms2,sys,os -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -x=vcs.init() +import os, sys, cdms2, vcs, testing.regression as regression + +x = regression.init() x.setantialiasing(0) x.setbgoutputdimensions(1200,1091,units="pixels") x.drawlogooff() fnm = os.path.join(vcs.sample_data,'clt.nc') -f=cdms2.open(fnm) - -s=f("clt") -gm=x.createisofill() +f = cdms2.open(fnm) +s = f("clt") +gm = x.createisofill() x.plot(s.filled(),gm,bg=1) fnm = "test_vcs_isoline_numpy.png" -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, fnm) \ No newline at end of file diff --git a/testing/vcs/test_vcs_isoline_width_stipple.py b/testing/vcs/test_vcs_isoline_width_stipple.py index b563436c2..5da8f91f4 100644 --- a/testing/vcs/test_vcs_isoline_width_stipple.py +++ b/testing/vcs/test_vcs_isoline_width_stipple.py @@ -1,22 +1,8 @@ -import cdms2 -import os -import sys -import vcs - -baselineImage = sys.argv[1] - -pth = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(pth) -import checkimage # noqa +import os, sys, cdms2, vcs, testing.regression as regression dataset = cdms2.open(os.path.join(vcs.sample_data, "clt.nc")) data = dataset("clt") - -canvas = vcs.init() -canvas.setantialiasing(0) -canvas.setbgoutputdimensions(1200, 1091, units="pixels") -canvas.drawlogooff() - +canvas = regression.init() isoline = canvas.createisoline() isoline.label = "y" texts = [] @@ -35,15 +21,8 @@ for i in range(7): isoline.levels = levels isoline.text = texts isoline.linecolors = colors - isoline.linewidths = (1, 2, 3, 4, 1) isoline.line = ('dot', 'dash', 'solid', 'dash-dot', 'long-dash', 'dot', 'dash') - # Next plot the isolines with labels canvas.plot(data, isoline, bg=1) - -testImage = os.path.abspath("test_isoline_width_stipple.png") -canvas.png(testImage) - -ret = checkimage.check_result_image(testImage, baselineImage, 30) -sys.exit(ret) +regression.run(canvas, "test_isoline_width_stipple.png") diff --git a/testing/vcs/test_vcs_issue_960_labels.py b/testing/vcs/test_vcs_issue_960_labels.py index ee45216cd..7da2104ff 100644 --- a/testing/vcs/test_vcs_issue_960_labels.py +++ b/testing/vcs/test_vcs_issue_960_labels.py @@ -1,29 +1,19 @@ -import sys,os,cdms2,vcs -import vcs -src1=sys.argv[1] -src2=sys.argv[2] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") +import os, sys, cdms2, vcs, testing.regression as regression + +src1 = sys.argv[1] +src2 = sys.argv[2] +x = regression.init() f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) s=f("clt",time=slice(0,1),latitude=(-7,5),squeeze=1) x.plot(s,bg=1) fnm = "test_vcs_issue_960_labels_1.png" x.png(fnm) -print "fnm:",fnm -print "src:",src1 -ret = checkimage.check_result_image(fnm,src1,checkimage.defaultThreshold) +ret = regression.check_result_image(fnm, src1) b=x.createboxfill() b.datawc_y1=-7 b.datawc_y2=5 x.plot(s,b,bg=1) fnm = "test_vcs_issue_960_labels_2.png" x.png(fnm) -print "fnm:",fnm -print "src:",src2 -ret += checkimage.check_result_image(fnm,src2,checkimage.defaultThreshold) -sys.exit(ret) +ret += regression.check_result_image(fnm, src2) +sys.exit(ret) \ No newline at end of file diff --git a/testing/vcs/test_vcs_lambert.py b/testing/vcs/test_vcs_lambert.py index 17a50209f..c78e71e9b 100644 --- a/testing/vcs/test_vcs_lambert.py +++ b/testing/vcs/test_vcs_lambert.py @@ -1,27 +1,10 @@ -import vcs,cdms2 -import os,sys +import os, sys, cdms2, vcs, testing.regression as regression f = cdms2.open(os.path.join(vcs.sample_data, "clt.nc")) s = f("clt") -x = vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1090,units="pixels") +x = regression.init() iso = x.createisofill() p=x.createprojection() p.type="lambert" - iso.projection = p x.plot(s(latitude=(20, 60),longitude=(-140,-20)), iso, bg=True) - -# Load the image testing module: -testingDir = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(testingDir) -import checkimage - -# Create the test image and compare: -baseline = sys.argv[1] -testFile = "test_vcs_lambert.png" -x.png(testFile) -ret = checkimage.check_result_image(testFile, baseline, - checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, "test_vcs_lambert.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_large_pattern_hatch.py b/testing/vcs/test_vcs_large_pattern_hatch.py index 3bcf0827d..782cfb14b 100644 --- a/testing/vcs/test_vcs_large_pattern_hatch.py +++ b/testing/vcs/test_vcs_large_pattern_hatch.py @@ -1,31 +1,12 @@ -import vcs -import sys -import os - -baseline = sys.argv[1] - -pth = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(pth) -import checkimage - -canvas = vcs.init() -canvas.setantialiasing(0) -canvas.setbgoutputdimensions(1200,1090, units="pixels") -canvas.drawlogooff() +import os, sys, vcs, testing.regression as regression +canvas = regression.init() fillarea = vcs.createfillarea() fillarea.x = [[0, .33, .33, 0], [.33, .67, .67, .33], [.67, 1, 1, .67]] fillarea.y = [[0, 0, 1, 1]] * 3 fillarea.style = ["solid", "pattern", "hatch"] fillarea.index = [1, 5, 5] fillarea.color = [50, 50, 50] - canvas.plot(fillarea, bg=True) - -testImage = os.path.abspath("test_vcs_large_pattern_hatch.png") -canvas.png(testImage) - -ret = checkimage.check_result_image(testImage, baseline, - checkimage.defaultThreshold) - -sys.exit(ret) +fnm = os.path.abspath("test_vcs_large_pattern_hatch.png") +regression.run(canvas, fnm) \ No newline at end of file diff --git a/testing/vcs/test_vcs_legend.py b/testing/vcs/test_vcs_legend.py index 26beec7e5..a352bc080 100644 --- a/testing/vcs/test_vcs_legend.py +++ b/testing/vcs/test_vcs_legend.py @@ -1,5 +1,4 @@ -import sys,os -import argparse +import os, sys, argparse, cdms2, MV2, vcs, testing.regression as regression p = argparse.ArgumentParser(description="Basic gm testing code for vcs") p.add_argument("--source", dest="src", help="source image file") @@ -14,20 +13,10 @@ args = p.parse_args(sys.argv[1:]) gm_type= args.gm src = args.src -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage - -import vcs -import sys -import cdms2 -import vtk -import os -import MV2 bg = not args.show -x=vcs.init() +x = vcs.init() x.setantialiasing(0) x.drawlogooff() if bg: @@ -81,7 +70,7 @@ fnm = "test_vcs_legend_%s_%s_ext1_%s_ext2_%s" % (gm_type.lower(),args.orientatio x.png(fnm) print "fnm:",fnm print "src:",src -ret = checkimage.check_result_image(fnm+'.png',src,checkimage.defaultThreshold, cleanup=not args.keep) +ret = regression.check_result_image(fnm+'.png', src,regression.defaultThreshold, cleanup=not args.keep) if args.show: raw_input("Press Enter") sys.exit(ret) diff --git a/testing/vcs/test_vcs_lon_axes_freak_out.py b/testing/vcs/test_vcs_lon_axes_freak_out.py index ecb63f2a5..f18328f58 100644 --- a/testing/vcs/test_vcs_lon_axes_freak_out.py +++ b/testing/vcs/test_vcs_lon_axes_freak_out.py @@ -1,30 +1,11 @@ -import os,sys,vcs,cdms2 -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +import os, sys, cdms2, vcs, testing.regression as regression +f = cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) +s = f("clt") +s3 = f("clt",longitude=(0,360)) -f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) -s=f("clt") -s3=f("clt",longitude=(0,360)) - -print s.shape,s3.shape - - -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") - +x = regression.init() x.plot(s,bg=1) x.clear() x.plot(s3,bg=1) - -fnm = "test_lon_axes_freak_out.png" - -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, "test_lon_axes_freak_out.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_markers.py b/testing/vcs/test_vcs_markers.py index 50f4f00d1..21b7a671b 100644 --- a/testing/vcs/test_vcs_markers.py +++ b/testing/vcs/test_vcs_markers.py @@ -1,28 +1,14 @@ +import os, sys, numpy, cdms2, MV2, vcs, testing.regression as regression -import vcs,numpy,cdms2,MV2,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage - -x=vcs.init() -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") - +x = regression.init() m = x.createmarker() -m.x=[[0.,],[5,],[10.,],[15.]] -m.y=[[0.,],[5,],[10.,],[15.]] +m.x = [[0.,],[5,],[10.,],[15.]] +m.y = [[0.,],[5,],[10.,],[15.]] m.worldcoordinate=[-5,20,-5,20] + #m.worldcoordinate=[-10,10,0,10] m.type=['plus','diamond','square_fill',"hurricane"] m.color=[242,243,244,242] m.size=[20,20,20,5] x.plot(m,bg=1) -fnm= "test_markers.png" - -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, "test_markers.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_matplotlib_colormap.py b/testing/vcs/test_vcs_matplotlib_colormap.py index 06b9f49b9..baf0e1bb0 100644 --- a/testing/vcs/test_vcs_matplotlib_colormap.py +++ b/testing/vcs/test_vcs_matplotlib_colormap.py @@ -1,7 +1,4 @@ -import cdms2 -import os -import sys -import vcs +import os, sys, cdms2, vcs, testing.regression as regression # Load the clt data: dataFile = cdms2.open(os.path.join(vcs.sample_data, "clt.nc")) @@ -10,24 +7,7 @@ clt = clt(latitude=(-90.0, 90.0), longitude=(-180., 175.), squeeze=1, time=('1979-1-1 0:0:0.0', '1988-12-1 0:0:0.0')) # Initialize canvas: -canvas = vcs.init() -canvas.setantialiasing(0) -canvas.setbgoutputdimensions(1200,1091,units="pixels") -canvas.drawlogooff() - +canvas = regression.init() canvas.setcolormap(vcs.matplotlib2vcs("viridis")) - canvas.plot(clt, bg=1) - -# Load the image testing module: -testingDir = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(testingDir) -import checkimage - -# Create the test image and compare: -baseline = sys.argv[1] -testFile = "test_matplotlib_colormap.png" -canvas.png(testFile) -ret = checkimage.check_result_image(testFile, baseline, - checkimage.defaultThreshold) -sys.exit(ret) +regression.run(canvas, "test_matplotlib_colormap.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_mercator_edge.py b/testing/vcs/test_vcs_mercator_edge.py index eb6d79cdb..31f6cb83b 100644 --- a/testing/vcs/test_vcs_mercator_edge.py +++ b/testing/vcs/test_vcs_mercator_edge.py @@ -1,24 +1,9 @@ -import vcs,cdms2 -import os,sys +import os, sys, cdms2, vcs, testing.regression as regression + f = cdms2.open(os.path.join(vcs.sample_data, "clt.nc")) s = f("clt") -x = vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") +x = regression.init() iso = x.createisofill() iso.projection = "mercator" x.plot(s(latitude=(-90, 90)), iso, bg=1) - -# Load the image testing module: -testingDir = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(testingDir) -import checkimage - -# Create the test image and compare: -baseline = sys.argv[1] -testFile = "test_vcs_mercator_edge.png" -x.png(testFile) -ret = checkimage.check_result_image(testFile, baseline, - checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, "test_vcs_mercator_edge.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_meshfill_draw_mesh.py b/testing/vcs/test_vcs_meshfill_draw_mesh.py index ef214e648..08801d7a6 100644 --- a/testing/vcs/test_vcs_meshfill_draw_mesh.py +++ b/testing/vcs/test_vcs_meshfill_draw_mesh.py @@ -1,23 +1,11 @@ -import vcs,cdms2,sys,os -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -x=vcs.init() -x.setantialiasing(0) -x.setbgoutputdimensions(1200,1091,units="pixels") -x.drawlogooff() -fnmcurv = os.path.join(vcs.sample_data,'sampleCurveGrid4.nc') -f=cdms2.open(fnmcurv) +import os, sys, cdms2, vcs, testing.regression as regression -s=f("sample") -m=x.createmeshfill() -m.mesh=True +x = regression.init() +fnmcurv = os.path.join(vcs.sample_data,'sampleCurveGrid4.nc') +f = cdms2.open(fnmcurv) +s = f("sample") +m = x.createmeshfill() +m.mesh = True x.plot(s,m,bg=1) -fnm = "test_meshfill_draw_mesh.png" -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, "test_meshfill_draw_mesh.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_meshfill_no_wrapping.py b/testing/vcs/test_vcs_meshfill_no_wrapping.py index 967758c78..9ee4a99f1 100755 --- a/testing/vcs/test_vcs_meshfill_no_wrapping.py +++ b/testing/vcs/test_vcs_meshfill_no_wrapping.py @@ -1,23 +1,7 @@ -#!/usr/bin/env python -import cdms2 -import os -import sys -import vcs - -pth = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(pth) -import checkimage - - -f=cdms2.open(sys.argv[2]) -h=f("heat") -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200, 900, units="pixels") +import os, sys, cdms2, vcs, testing.regression as regression +f = cdms2.open(sys.argv[2]) +h = f("heat") +x = regression.init() x.plot(h, bg=1) -fnm = "vcs_test_meshfill_no_wrapping.png" -x.png(fnm) -ret = checkimage.check_result_image(fnm, sys.argv[1], checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, "vcs_test_meshfill_no_wrapping.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_meshfill_regular_grid.py b/testing/vcs/test_vcs_meshfill_regular_grid.py index 9a955f9ff..77a390b22 100644 --- a/testing/vcs/test_vcs_meshfill_regular_grid.py +++ b/testing/vcs/test_vcs_meshfill_regular_grid.py @@ -1,22 +1,7 @@ -import vcs, cdms2, os, sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() +import os, sys, cdms2, vcs, testing.regression as regression -x.setbgoutputdimensions(1200,1091,units="pixels") -x = vcs.init() -x.setantialiasing(0) +x = regression.init() f = cdms2.open(os.path.join(vcs.sample_data, "clt.nc")) s = f("clt") -x.meshfill(s,bg=1) -fnm = "test_meshfill_regular_grid.png" -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +x.meshfill(s, bg=1) +regression.run(x, "test_meshfill_regular_grid.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_meshfill_vertices.py b/testing/vcs/test_vcs_meshfill_vertices.py index 6317ef071..103e68109 100644 --- a/testing/vcs/test_vcs_meshfill_vertices.py +++ b/testing/vcs/test_vcs_meshfill_vertices.py @@ -1,19 +1,8 @@ -import numpy -import vcs -import sys -import os -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +import os, sys, numpy, vcs, testing.regression as regression -x=vcs.init() - -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200, 1090, units="pixels") +x = regression.init() data_values = [ 25, 45, 55.] - data_lon = [ 5., 10., 15.] data_lat = [ 5., 10., 15.] @@ -50,8 +39,4 @@ m.levels = [20,30,50,70,80] m.mesh = True x.plot(numpy.array(data_values,),mesh,m,bg=True) -x.png("test_vcs_meshfill_vertices_issue.png") -src = sys.argv[1] -ret = checkimage.check_result_image("test_vcs_meshfill_vertices_issue.png", - src, checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, "test_vcs_meshfill_vertices_issue.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_meshfill_zoom.py b/testing/vcs/test_vcs_meshfill_zoom.py index 1026f0ff0..c366d8010 100644 --- a/testing/vcs/test_vcs_meshfill_zoom.py +++ b/testing/vcs/test_vcs_meshfill_zoom.py @@ -1,14 +1,4 @@ -#!/usr/bin/env python -import cdms2 -import os -import sys -import vcs - -# We test if gm.datawc zooms in correctly into the plot. This works only for -# data using a linear projection. It does not work for geographic projections. -pth = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(pth) -import checkimage +import os, sys, cdms2, vcs, testing.regression as regression flip = False if (len(sys.argv) == 3): @@ -19,12 +9,10 @@ fileName = os.path.splitext(fileName)[0] if (flip): fileName = fileName + '_flip' fileName = fileName + '.png' -f=cdms2.open(os.path.join(vcs.sample_data, "sampleCurveGrid4.nc")) -s=f("sample") -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -m=x.createmeshfill() +f = cdms2.open(os.path.join(vcs.sample_data, "sampleCurveGrid4.nc")) +s = f("sample") +x = regression.init() +m = x.createmeshfill() # m.mesh = True m.datawc_x1 = -20 m.datawc_x2 = 20 @@ -33,7 +21,4 @@ if (flip): m.datawc_y1 = -20 m.datawc_y2 = 20 x.plot(s,m, bg=1) -x.png(fileName) -ret = checkimage.check_result_image(fileName, sys.argv[1], checkimage.defaultThreshold) -sys.exit(ret) - +regression.run(x, fileName) \ No newline at end of file diff --git a/testing/vcs/test_vcs_mintics.py b/testing/vcs/test_vcs_mintics.py index 01f65848b..302c22fd4 100644 --- a/testing/vcs/test_vcs_mintics.py +++ b/testing/vcs/test_vcs_mintics.py @@ -1,16 +1,10 @@ -import vcs,numpy,cdms2,MV2,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +import os, sys, numpy, cdms2, MV2, vcs, testing.regression as regression -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") +x = regression.init() f = cdms2.open(os.path.join(vcs.sample_data, "clt.nc")) s = f("clt") box = x.createboxfill() + # Should ignore the string here box.xmtics1 = {i:"Test" for i in range(-180, 180, 15) if i % 30 != 0} box.ymtics1 = {i:"Test" for i in range(-90, 90, 5) if i % 10 != 0} @@ -23,10 +17,4 @@ template.xmintic2.priority = 1 template.xmintic2.y2 += template.xmintic1.y1 - template.xmintic1.y2 template.ymintic2.priority = 1 x.plot(s, template, box, bg=1) -fnm = "test_vcs_mintics.png" -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, "test_vcs_mintics.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_missing_colorname.py b/testing/vcs/test_vcs_missing_colorname.py index 1ed68b475..9b3db7545 100644 --- a/testing/vcs/test_vcs_missing_colorname.py +++ b/testing/vcs/test_vcs_missing_colorname.py @@ -1,7 +1,4 @@ -import cdms2 -import os -import sys -import vcs +import os, sys, cdms2, vcs, testing.regression as regression # Load the clt data: dataFile = cdms2.open(os.path.join(vcs.sample_data, "clt.nc")) @@ -11,10 +8,7 @@ height, width = clt.shape clt.mask = [[True if i % 2 else False for i in range(width)] for _ in range(height)] # Initialize canvas: -canvas = vcs.init() -canvas.setantialiasing(0) -canvas.setbgoutputdimensions(1200,1091,units="pixels") -canvas.drawlogooff() +canvas = regression.init() # Create and plot quick boxfill with default settings: # Only have to test boxfill because all 2D methods use the same code @@ -25,16 +19,4 @@ boxfill = canvas.createboxfill() boxfill.missing = "Medium Aquamarine" canvas.plot(clt, boxfill, bg=1) - -# Load the image testing module: -testingDir = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(testingDir) -import checkimage - -# Create the test image and compare: -baseline = sys.argv[1] -testFile = "test_vcs_missing_colorname.png" -canvas.png(testFile) -ret = checkimage.check_result_image(testFile, baseline, - checkimage.defaultThreshold) -sys.exit(ret) +regression.run(canvas, "test_vcs_missing_colorname.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_monotonic_decreasing_yxvsx_default.py b/testing/vcs/test_vcs_monotonic_decreasing_yxvsx_default.py index 9f30f40ae..4dcd059a0 100644 --- a/testing/vcs/test_vcs_monotonic_decreasing_yxvsx_default.py +++ b/testing/vcs/test_vcs_monotonic_decreasing_yxvsx_default.py @@ -1,27 +1,14 @@ -import vcs,numpy,cdms2,MV2,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -x=vcs.init() -x.setantialiasing(0) +import os, sys, numpy, cdms2, MV2, vcs, testing.regression as regression -x.setbgoutputdimensions(1200,1091,units="pixels") - -t=cdms2.createAxis(numpy.arange(120)) +x = regression.init() +t = cdms2.createAxis(numpy.arange(120)) t.designateTime() -t.id="time" -t.units="months since 2014" +t.id = "time" +t.units = "months since 2014" data = MV2.arange(120,0,-1) -data.id="data" +data.id = "data" data.setAxis(0,t) -x=vcs.init() -x.setantialiasing(0) +x = regression.init() x.plot(data,bg=1) fnm = 'test_vcs_monotonic_decreasing_yxvsx_default.png' - -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, fnm) \ No newline at end of file diff --git a/testing/vcs/test_vcs_oned_level_axis.py b/testing/vcs/test_vcs_oned_level_axis.py index 25479a56b..ecb708c77 100644 --- a/testing/vcs/test_vcs_oned_level_axis.py +++ b/testing/vcs/test_vcs_oned_level_axis.py @@ -1,24 +1,9 @@ +import os, sys, vcs, cdms2, cdutil, testing.regression as regression -import sys,cdutil -import vcs -import os -import cdms2 -src = sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage - -f=cdms2.open(os.path.join(vcs.sample_data,"ta_ncep_87-6-88-4.nc")) -ta=f("ta",time=slice(0,1),squeeze=1) -ta=cdutil.averager(ta,axis="yx") -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") +f = cdms2.open(os.path.join(vcs.sample_data,"ta_ncep_87-6-88-4.nc")) +ta = f("ta",time=slice(0,1),squeeze=1) +ta = cdutil.averager(ta,axis="yx") +x = regression.init() x.plot(ta,bg=1) fnm = "test_oned_level_axis.png" -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, fnm) \ No newline at end of file diff --git a/testing/vcs/test_vcs_patterns.py b/testing/vcs/test_vcs_patterns.py index fed4f41a8..c407f7cfe 100644 --- a/testing/vcs/test_vcs_patterns.py +++ b/testing/vcs/test_vcs_patterns.py @@ -1,19 +1,8 @@ -import cdms2 -import os -import sys -import vcs - -src = sys.argv[1] -pth = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(pth) -import checkimage +import os, sys, vcs, cdms2, testing.regression as regression f = cdms2.open(vcs.sample_data+"/clt.nc") s = f("clt", time=slice(0, 1), squeeze=1) -x = vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200, 1090, units="pixels") +x = regression.init() iso = vcs.createisofill("isoleg") iso.levels = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100] iso.fillareastyle = "pattern" @@ -21,9 +10,4 @@ iso.fillareacolors = vcs.getcolors([0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]) iso.fillareaindices = [1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20] x.plot(s, iso, bg=1) fnm = "test_vcs_patterns.png" -x.png(fnm) - -print "fnm:", fnm -print "src:", src -ret = checkimage.check_result_image(fnm, src, checkimage.defaultThreshold+5.) -sys.exit(ret) +regression.run(x, fnm, threshold=regression.defaultThreshold+5.) \ No newline at end of file diff --git a/testing/vcs/test_vcs_plot_file_var.py b/testing/vcs/test_vcs_plot_file_var.py index e20f947a6..0dd68945d 100644 --- a/testing/vcs/test_vcs_plot_file_var.py +++ b/testing/vcs/test_vcs_plot_file_var.py @@ -1,8 +1,6 @@ -import vcs -import os -import sys -import cdms2 -f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) -V=f("clt") -x=vcs.init() -x.plot(V,bg=1) +import os, sys, vcs, cdms2 + +f = cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) +V = f("clt") +x = vcs.init() +x.plot(V, bg=1) diff --git a/testing/vcs/test_vcs_plot_unstructured_via_boxfill.py b/testing/vcs/test_vcs_plot_unstructured_via_boxfill.py index 4aa1d24eb..535ff432e 100644 --- a/testing/vcs/test_vcs_plot_unstructured_via_boxfill.py +++ b/testing/vcs/test_vcs_plot_unstructured_via_boxfill.py @@ -1,21 +1,7 @@ -import vcs -import os,sys -import cdms2 - -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) - -import checkimage +import vcs, os, sys, cdms2, testing.regression as regression f = cdms2.open(os.path.join(vcs.sample_data,"sampleCurveGrid4.nc")) s = f("sample") -x = vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") +x = regression.init() x.plot(s,bg=1) -fnm = "test_plot_unstructured_via_boxfill.png" -src = sys.argv[1] -x.png(fnm) -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, "test_plot_unstructured_via_boxfill.png") diff --git a/testing/vcs/test_vcs_png_to_base64.py b/testing/vcs/test_vcs_png_to_base64.py index 6b88b3511..f6d78e2fa 100644 --- a/testing/vcs/test_vcs_png_to_base64.py +++ b/testing/vcs/test_vcs_png_to_base64.py @@ -1,4 +1,4 @@ -import vcs,numpy,cdms2,MV2,os,sys +import vcs, numpy, cdms2, MV2, os, sys x = vcs.init() x.drawlogooff() diff --git a/testing/vcs/test_vcs_png_window_resize.py b/testing/vcs/test_vcs_png_window_resize.py index 0adeeb66b..a6346ca28 100644 --- a/testing/vcs/test_vcs_png_window_resize.py +++ b/testing/vcs/test_vcs_png_window_resize.py @@ -1,20 +1,9 @@ -import vcs -import sys -import os +import vcs, sys, os, testing.regression as regression -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -x=vcs.init() +x = regression.init() x.setantialiasing(0) x.drawlogooff() x.open(814,628) x.plot([1,2,3,4,5,6,7]) fnm = __file__[:-3]+".png" -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, fnm) \ No newline at end of file diff --git a/testing/vcs/test_vcs_polar_set_opt_param_polar.py b/testing/vcs/test_vcs_polar_set_opt_param_polar.py index 8c508ca3c..4e777fb2b 100644 --- a/testing/vcs/test_vcs_polar_set_opt_param_polar.py +++ b/testing/vcs/test_vcs_polar_set_opt_param_polar.py @@ -1,29 +1,13 @@ +import vcs, cdms2, sys, os, testing.regression as regression -import vcs -import cdms2 -import sys -import os - -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage - -f=cdms2.open(os.path.join(vcs.sample_data,'clt.nc')) -s=f("clt",slice(0,1),squeeze=1) -x=vcs.init() +f = cdms2.open(os.path.join(vcs.sample_data,'clt.nc')) +s = f("clt",slice(0,1),squeeze=1) +x = regression.init() x.setantialiasing(0) x.drawlogooff() x.setbgoutputdimensions(1200,1091,units="pixels") -i=x.createisofill() -p=x.getprojection("polar") +i = x.createisofill() +p = x.getprojection("polar") i.projection=p x.plot(s,i,bg=1) -fnm= "test_polar_set_opt_param_polar.png" -x.png(fnm) - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) - +regression.run(x, "test_polar_set_opt_param_polar.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_remove_marker_none_1d.py b/testing/vcs/test_vcs_remove_marker_none_1d.py index f868361b0..e112f86bc 100644 --- a/testing/vcs/test_vcs_remove_marker_none_1d.py +++ b/testing/vcs/test_vcs_remove_marker_none_1d.py @@ -3,31 +3,13 @@ # # J-Y Peterschmitt - LSCE - 03/2015 -import vcs,numpy,cdms2,MV2,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +import vcs, numpy, cdms2, MV2, os, sys, testing.regression as regression dummy_data = numpy.arange(50, dtype=numpy.float32) - -x = vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") - +x = regression.init() gm = x.createyxvsx('test_yxvsx') - -# Remove the marker gm.marker = None - x.plot(gm, dummy_data,bg=1) - fnm = "test_remove_marker_none_1d.png" -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) -# The end +regression.run(x, fnm) \ No newline at end of file diff --git a/testing/vcs/test_vcs_setcolormap.py b/testing/vcs/test_vcs_setcolormap.py index c3e639660..78d7fad81 100644 --- a/testing/vcs/test_vcs_setcolormap.py +++ b/testing/vcs/test_vcs_setcolormap.py @@ -1,32 +1,12 @@ -import cdms2 -import os -import sys -import vcs - -baselineFilename = sys.argv[1] -checkImagePath = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(checkImagePath) -import checkimage +import cdms2, os, sys, vcs, testing.regression as regression cdmsfile = cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) data = cdmsfile('clt') - -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") - +x = regression.init() t=x.gettemplate('default') x.plot(data, t, bg=True) # This should force the image to update x.setcolormap('bl_to_drkorang') - -testFilename = "test_vcs_setcolormap.png" -x.png(testFilename) - -ret = checkimage.check_result_image(testFilename, - baselineFilename, - checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, "test_vcs_setcolormap.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_settings_color_name_rgba.py b/testing/vcs/test_vcs_settings_color_name_rgba.py index 0b6aeef22..0fa6ec288 100644 --- a/testing/vcs/test_vcs_settings_color_name_rgba.py +++ b/testing/vcs/test_vcs_settings_color_name_rgba.py @@ -1,28 +1,13 @@ -import vcs -import numpy -import os -import sys -import cdms2 -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +import vcs, numpy, os, sys, cdms2, testing.regression as regression -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1090,units="pixels") +x = regression.init() -f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) -data=f("clt",slice(0,1,)) +f = cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) +data = f("clt",slice(0,1,)) gm = x.createisofill() gm.levels = range(0,110,10) gm.fillareacolors = ["green","red","blue","bisque","yellow","grey", [100,0,0,50], [0,100,0],"salmon",[0,0,100,75]] x.plot(data,gm,bg=True) -fnm = 'test_vcs_settings_color_name_rgba_isofill.png' -src = sys.argv[1] -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +fnm = "test_vcs_settings_color_name_rgba_isofill.png" +regression.run(x, fnm) \ No newline at end of file diff --git a/testing/vcs/test_vcs_settings_color_name_rgba_1d.py b/testing/vcs/test_vcs_settings_color_name_rgba_1d.py index 0fe844c20..8bca782a6 100644 --- a/testing/vcs/test_vcs_settings_color_name_rgba_1d.py +++ b/testing/vcs/test_vcs_settings_color_name_rgba_1d.py @@ -1,16 +1,6 @@ -import vcs -import numpy -import os -import sys -import cdms2 -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +import vcs, numpy, os, sys, cdms2, testing.regression as regression -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1090,units="pixels") +x = regression.init() f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) data=f("clt")[:,5,8] @@ -18,10 +8,4 @@ gm = x.create1d() gm.linecolor="salmon" gm.markercolor = [0,0,100] x.plot(data,gm,bg=True) -fnm = 'test_vcs_settings_color_name_rgba_1d.png' -src = sys.argv[1] -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, 'test_vcs_settings_color_name_rgba_1d.png') \ No newline at end of file diff --git a/testing/vcs/test_vcs_settings_color_name_rgba_boxfill.py b/testing/vcs/test_vcs_settings_color_name_rgba_boxfill.py index 043d331c8..34228513e 100644 --- a/testing/vcs/test_vcs_settings_color_name_rgba_boxfill.py +++ b/testing/vcs/test_vcs_settings_color_name_rgba_boxfill.py @@ -1,17 +1,6 @@ -import vcs -import numpy -import os -import sys -import cdms2 -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage - -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1090,units="pixels") +import vcs, numpy, os, sys, cdms2, testing.regression as regression +x = regression.init() f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) data=f("clt",slice(0,1,)) gm = x.createboxfill() @@ -20,10 +9,4 @@ gm.levels = range(0,110,10) gm.fillareacolors = ["green","red","blue","bisque","yellow","grey", [100,0,0,50], [0,100,0],"salmon",[0,0,100,75]] x.plot(data,gm,bg=True) -fnm = 'test_vcs_settings_color_name_rgba_boxfill.png' -src = sys.argv[1] -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, 'test_vcs_settings_color_name_rgba_boxfill.png') \ No newline at end of file diff --git a/testing/vcs/test_vcs_settings_color_name_rgba_isoline.py b/testing/vcs/test_vcs_settings_color_name_rgba_isoline.py index 200293dbe..c23edc2a6 100644 --- a/testing/vcs/test_vcs_settings_color_name_rgba_isoline.py +++ b/testing/vcs/test_vcs_settings_color_name_rgba_isoline.py @@ -1,17 +1,6 @@ -import vcs -import numpy -import os -import sys -import cdms2 -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage - -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1090,units="pixels") +import vcs, numpy, os, sys, cdms2, testing.regression as regression +x=regression.init() f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) data=f("clt",slice(0,1,)) gm = x.createisoline() @@ -19,10 +8,4 @@ gm.levels = range(0,110,10) gm.linecolors = ["green","red","blue","bisque","yellow","grey", [100,0,0,50], [0,100,0],"salmon",[0,0,100,75]] x.plot(data,gm,bg=True) -fnm = 'test_vcs_settings_color_name_rgba_isoline.png' -src = sys.argv[1] -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, 'test_vcs_settings_color_name_rgba_isoline.png') \ No newline at end of file diff --git a/testing/vcs/test_vcs_settings_color_name_rgba_meshfill.py b/testing/vcs/test_vcs_settings_color_name_rgba_meshfill.py index 4a0858d1d..0b3ffc871 100644 --- a/testing/vcs/test_vcs_settings_color_name_rgba_meshfill.py +++ b/testing/vcs/test_vcs_settings_color_name_rgba_meshfill.py @@ -1,17 +1,6 @@ -import vcs -import numpy -import os -import sys -import cdms2 -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage - -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1090,units="pixels") +import vcs, numpy, os, sys, cdms2, testing.regression as regression +x = regression.init() f=cdms2.open(os.path.join(vcs.sample_data,"sampleCurveGrid4.nc")) data=f("sample") gm = x.createmeshfill() @@ -19,10 +8,4 @@ gm.levels = range(0,1501,150) gm.fillareacolors = ["green","red","blue","bisque","yellow","grey", [100,0,0,50], [0,100,0],"salmon",[0,0,100,75]] x.plot(data,gm,bg=True) -fnm = 'test_vcs_settings_color_name_rgba_meshfill.png' -src = sys.argv[1] -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +ret = regression.run(x, 'test_vcs_settings_color_name_rgba_meshfill.png') \ No newline at end of file diff --git a/testing/vcs/test_vcs_star_triangle_markers.py b/testing/vcs/test_vcs_star_triangle_markers.py index 4564e4059..2d75e05d0 100644 --- a/testing/vcs/test_vcs_star_triangle_markers.py +++ b/testing/vcs/test_vcs_star_triangle_markers.py @@ -1,9 +1,5 @@ -import vcs,numpy,cdms2,MV2,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +import vcs, numpy, cdms2, MV2, os, sys, testing.regression as regression x=vcs.init() x.drawlogooff() @@ -16,12 +12,5 @@ m.x = [[.1], [.3], [.5], [.7], [.9]] m.y = [[.1], [.3], [.5], [.7], [.9]] m.color = [200, 150, 160, 175, 125] m.size = [50, 50, 50, 50, 50] -x.plot(m,bg=1) -fnm = "test_star_triangle_markers.png" -x.png(fnm) - -print "fnm:",fnm -print "src:",src - -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +x.plot(m, bg=1) +regression.run(x, "test_star_triangle_markers.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_taylor_2quads.py b/testing/vcs/test_vcs_taylor_2quads.py index 3458acb91..84f102615 100644 --- a/testing/vcs/test_vcs_taylor_2quads.py +++ b/testing/vcs/test_vcs_taylor_2quads.py @@ -1,17 +1,6 @@ -import sys,os -src = sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -import vcs, MV2 +import sys, os, vcs, MV2, testing.regression as regression - -bg=True - -# -# First create some sample data -# data = MV2.array([[-0.50428531,-0.8505522 ,], [ 0.70056821,-0.27235352,], [ 0.05106154, 0.23012322,], @@ -19,20 +8,8 @@ data = MV2.array([[-0.50428531,-0.8505522 ,], [ 0.85760801,-0.08336641,], [ 1.14083397,-0.78326507,]]) -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() - -if bg: - x.setbgoutputdimensions(1200,1091,units="pixels") - -td=x.createtaylordiagram('new') - +x = regression.init() +td = x.createtaylordiagram('new') td.quadrans = 2 -x.plot(data,td,skill = td.defaultSkillFunction,bg=bg) -fnm = "test_vcs_taylor_2quads.png" -x.png(fnm) -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -if not bg: - raw_input("Press Enter") -sys.exit(ret) +x.plot(data, td, skill = td.defaultSkillFunction, bg=1) +regression.run(x, "test_vcs_taylor_2quads.png") diff --git a/testing/vcs/test_vcs_taylor_template_ctl.py b/testing/vcs/test_vcs_taylor_template_ctl.py index 40b78f0dc..b6f610c7d 100644 --- a/testing/vcs/test_vcs_taylor_template_ctl.py +++ b/testing/vcs/test_vcs_taylor_template_ctl.py @@ -1,20 +1,8 @@ -import sys,os -src = sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -import vcs,MV2 +import sys, os, vcs, MV2 +import testing.regression as regression -bg=True - -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -if bg: - x.setbgoutputdimensions(1200,1091,units="pixels") -if not bg: - x.open() +x = regression.init() ## Create a template from the default taylor diagram t=x.createtemplate('mytaylor','deftaylor') @@ -61,12 +49,5 @@ t.xmintic2.priority=1 # Create some dummy data for display purposes data=MV2.array([[1.52,.52,],[.83,.84]]) -x.plot(data,t,td,bg=bg) -fnm="test_vcs_taylor_template_ctl.png" -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -if not bg: - raw_input("Press Enter") -sys.exit(ret) +x.plot(data, t, td, bg=1) +regression.run(x, "test_vcs_taylor_template_ctl.png") diff --git a/testing/vcs/test_vcs_user_passed_date.py b/testing/vcs/test_vcs_user_passed_date.py index 643d2019c..bb5b18a0d 100644 --- a/testing/vcs/test_vcs_user_passed_date.py +++ b/testing/vcs/test_vcs_user_passed_date.py @@ -1,18 +1,9 @@ import vcs,cdms2,os,sys,cdtime -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +import testing.regression as regression + f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) s=f("clt",squeeze=1) -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") +x=regression.init() x.plot(s,bg=1,time=cdtime.comptime(2015)) fnm = os.path.split(__file__)[1][:-3]+".png" -x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, fnm) diff --git a/testing/vcs/test_vcs_user_passed_date_as_string.py b/testing/vcs/test_vcs_user_passed_date_as_string.py index cd5d777f3..e9bdf83e6 100644 --- a/testing/vcs/test_vcs_user_passed_date_as_string.py +++ b/testing/vcs/test_vcs_user_passed_date_as_string.py @@ -1,18 +1,11 @@ import vcs,cdms2,os,sys,cdtime -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +import testing.regression as regression + +x = regression.init() + f=cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) s=f("clt",squeeze=1) -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") x.plot(s,bg=1,time='2015-02-23') fnm = os.path.split(__file__)[1][:-3]+".png" x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, fnm) diff --git a/testing/vcs/test_vcs_vectors_missing.py b/testing/vcs/test_vcs_vectors_missing.py index fd53c97e1..5e8b08e5b 100644 --- a/testing/vcs/test_vcs_vectors_missing.py +++ b/testing/vcs/test_vcs_vectors_missing.py @@ -1,6 +1,6 @@ -import sys,os -import argparse +import sys, os, argparse +import vcs, cdms2, vtk, MV2, numpy, testing.regression as regression p = argparse.ArgumentParser(description="Basic gm testing code for vcs") p.add_argument("--source", dest="src", help="source image file") @@ -14,28 +14,17 @@ if not args.show: src = args.src pth = os.path.join(os.path.dirname(__file__),"..") sys.path.append(pth) - import checkimage - -import vcs -import sys -import cdms2 -import vtk -import os -import MV2 -import numpy - bg = not args.show - -x=vcs.init() +x = vcs.init() x.setantialiasing(0) x.drawlogooff() if bg: x.setbgoutputdimensions(1200,1091,units="pixels") x.setcolormap("rainbow") -gm=vcs.createvector() +gm = vcs.createvector() gm.scale = args.scale -nm_xtra="" +nm_xtra = "" xtra = {} import cdms2 import os @@ -52,14 +41,12 @@ if args.show: pass #x.interact() else: - fnm = "test_vcs_vectors_missing" + fnm = "test_vcs_vectors_missing" if args.scale!=1.: fnm+="_%.1g" % args.scale fnm+=nm_xtra x.png(fnm) - print "fnm:",fnm - print "src:",src - ret = checkimage.check_result_image(fnm+'.png',src,checkimage.defaultThreshold, cleanup=not args.keep) + ret = regression.check_result_image(fnm+'.png', src, regression.defaultThreshold, cleanup=not args.keep) if args.show: raw_input("Press Enter") sys.exit(ret) diff --git a/testing/vcs/test_vcs_vectors_robinson.py b/testing/vcs/test_vcs_vectors_robinson.py index 49052c679..5cde92c82 100644 --- a/testing/vcs/test_vcs_vectors_robinson.py +++ b/testing/vcs/test_vcs_vectors_robinson.py @@ -1,13 +1,7 @@ import vcs, cdms2, numpy, os, sys -src = sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +import testing.regression as regression -x = vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200, 1091, units="pixels") +x = regression.init() f = cdms2.open(os.path.join(vcs.sample_data, "clt.nc")) u = f("u") v = f("v") @@ -16,8 +10,4 @@ p = x.createprojection() p.type = "robinson" V.projection = p x.plot(u,v,V, bg=1) - -fnm = "test_vcs_vectors_robinson.png" -x.png(fnm) -ret = checkimage.check_result_image(fnm, src, checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, "test_vcs_vectors_robinson.png") diff --git a/testing/vcs/test_vcs_vectors_robinson_wrap.py b/testing/vcs/test_vcs_vectors_robinson_wrap.py index 86491cc2f..3cb30f06f 100644 --- a/testing/vcs/test_vcs_vectors_robinson_wrap.py +++ b/testing/vcs/test_vcs_vectors_robinson_wrap.py @@ -1,13 +1,7 @@ import vcs, cdms2, numpy, os, sys -src = sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +import testing.regression as regression -x = vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200, 1091, units="pixels") +x = regression.init() f = cdms2.open(os.path.join(vcs.sample_data, "clt.nc")) lon1 = -180 u = f("clt") @@ -19,8 +13,4 @@ p = x.createprojection() p.type = "robinson" V.projection = p x.plot(u,v,V, bg=1) - -fnm = "test_vcs_vectors_robinson_wrap.png" -x.png(fnm) -ret = checkimage.check_result_image(fnm, src, checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, "test_vcs_vectors_robinson_wrap.png") diff --git a/testing/vcs/test_vcs_verify_boxfill_basics.py b/testing/vcs/test_vcs_verify_boxfill_basics.py index 7d08a2b75..0d7c4c2d0 100644 --- a/testing/vcs/test_vcs_verify_boxfill_basics.py +++ b/testing/vcs/test_vcs_verify_boxfill_basics.py @@ -1,4 +1,3 @@ - import vcs import numpy import cdtime @@ -12,12 +11,12 @@ b=x.createboxfill() assert(b.projection == "linear") assert(b.xticlabels1 == "*") assert(b.xticlabels2 == "*") -assert(b.xmtics1 == "") +assert(b.xmtics1 == "") assert(b.xmtics2 == "") assert(b.yticlabels1 == "*") assert(b.yticlabels2 == "*") -assert(b.ymtics1 == "") -assert(b.ymtics2 == "") +assert(b.ymtics1 == "") +assert(b.ymtics2 == "") assert(numpy.allclose(b.datawc_x1, 1e+20)) assert(numpy.allclose(b.datawc_x2, 1e+20)) assert(numpy.allclose(b.datawc_y1, 1e+20)) @@ -71,12 +70,12 @@ assert(b.name == "test_b_ok") assert(b.projection == "test_bfill") assert(b.xticlabels1 == {23:"Hi"}) assert(b.xticlabels2 == {23:"Hi"}) -assert(b.xmtics1 == {23:"Hi"}) +assert(b.xmtics1 == {23:"Hi"}) assert(b.xmtics2 == {23:"Hi"}) assert(b.yticlabels1 == {23:"Hi"}) assert(b.yticlabels2 == {23:"Hi"}) -assert(b.ymtics1 == {23:"Hi"}) -assert(b.ymtics2 == {23:"Hi"}) +assert(b.ymtics1 == {23:"Hi"}) +assert(b.ymtics2 == {23:"Hi"}) assert(numpy.allclose(b.datawc_x1, 56.7)) assert(numpy.allclose(b.datawc_x2, 56.7)) assert(numpy.allclose(b.datawc_y1, 56.7)) diff --git a/testing/vcs/test_vcs_wmo_marker.py b/testing/vcs/test_vcs_wmo_marker.py index b4478372f..854e4a9be 100644 --- a/testing/vcs/test_vcs_wmo_marker.py +++ b/testing/vcs/test_vcs_wmo_marker.py @@ -1,14 +1,10 @@ import vcs,numpy,cdms2,MV2,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") + +import testing.regression as regression +x = regression.init() + m = x.createmarker() M=1 @@ -22,8 +18,5 @@ x.plot(m,bg=1) fnm = 'wmo_marker.png' x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +regression.run(x, "wmo_marker.png") diff --git a/testing/vcs/test_vcs_wmo_markers.py b/testing/vcs/test_vcs_wmo_markers.py index 5785e0925..5162eeeee 100644 --- a/testing/vcs/test_vcs_wmo_markers.py +++ b/testing/vcs/test_vcs_wmo_markers.py @@ -1,26 +1,20 @@ import vcs,numpy,cdms2,MV2,os,sys -src=sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +import testing.regression as regression wmo = ['w00', 'w01', 'w02', 'w03', 'w04', 'w05', 'w06', 'w07', 'w08', 'w09', 'w10', 'w11', 'w12', 'w13', 'w14', 'w15', 'w16', 'w17', 'w18', 'w19', - 'w20', 'w21', 'w22', 'w23', 'w24', 'w25', 'w26', 'w27', 'w28', 'w29', + 'w20', 'w21', 'w22', 'w23', 'w24', 'w25', 'w26', 'w27', 'w28', 'w29', 'w30', 'w31', 'w32', 'w33', 'w34', 'w35', 'w36', 'w37', 'w38', 'w39', 'w40', 'w41', 'w42', 'w43', 'w44', 'w45', 'w46', 'w47', 'w48', 'w49', 'w50', 'w51', 'w52', 'w53', 'w54', 'w55', 'w56', 'w57', 'w58', 'w59', - 'w60', 'w61', 'w62', 'w63', 'w64', 'w65', 'w66', 'w67', 'w68', 'w69', + 'w60', 'w61', 'w62', 'w63', 'w64', 'w65', 'w66', 'w67', 'w68', 'w69', 'w70', 'w71', 'w72', 'w73', 'w74', 'w75', 'w76', 'w77', 'w78', 'w79', 'w80', 'w81', 'w82', 'w83', 'w84', 'w85', 'w86', 'w87', 'w88', 'w89', 'w90', 'w91', 'w92', 'w93', 'w94', 'w95', 'w96', 'w97', 'w98', 'w99', 'w100', 'w101', 'w102'] -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") +x = regression.init() m = x.createmarker() M=7 @@ -37,13 +31,6 @@ for Y in range(7): m.x = xs m.y = ys m.list() -x.plot(m,bg=1) -fnm = "wmo_markers.png" -x.png(fnm) - - -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) -sys.exit(ret) +x.plot(m, bg=1) +regression.run(x, "wmo_markers.png"); diff --git a/testing/vcs/vtk_ui/vtk_ui_test.py b/testing/vcs/vtk_ui/vtk_ui_test.py index facfd7f45..40bbeaef1 100644 --- a/testing/vcs/vtk_ui/vtk_ui_test.py +++ b/testing/vcs/vtk_ui/vtk_ui_test.py @@ -1,8 +1,4 @@ -import vtk -import vcs.vtk_ui -import os -import sys -import time +import, os, sys, time, vcs.vtk_ui, vtk def init(): @@ -101,15 +97,13 @@ class vtk_ui_test(object): def check_image(self, compare_against): """ Checks the current render window's output against the image specified in the argument, - returns the result of checkimage.check_result_image + returns the result of regression.check_result_image """ generate_png(self.win, self.test_file) pth = os.path.join(os.path.dirname(__file__), "../..") sys.path.append(pth) - import checkimage - print "fnm:", self.test_file - print "src:", compare_against - return checkimage.check_result_image(self.test_file, compare_against, checkimage.defaultThreshold) + import regression + return regression.check_result_image(self.test_file, compare_against) def test(self): self.do_test() diff --git a/testing/vcsaddons/test_12_plot_one_leg_per_row.py b/testing/vcsaddons/test_12_plot_one_leg_per_row.py index b3cfa0fba..0c0298527 100644 --- a/testing/vcsaddons/test_12_plot_one_leg_per_row.py +++ b/testing/vcsaddons/test_12_plot_one_leg_per_row.py @@ -1,14 +1,7 @@ - -import sys,os -src = sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -import EzTemplate,vcs -## 12 plot one legend per row +import os, sys, EzTemplate, vcs, testing.regression as regression ## Initialize VCS -x=vcs.init() +x = vcs.init() x.drawlogooff() bg = True @@ -20,9 +13,7 @@ for i in range(12): t.legend.priority=0 # Turn off legend fnm = "test_12_plot_one_leg_per_row.png" M.preview(fnm,bg=bg) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) +ret = regression.check_result_image(fnm, sys.argv[1]) if not bg: raw_input("Press Enter") sys.exit(ret) diff --git a/testing/vcsaddons/test_12_plot_one_leg_per_row_right.py b/testing/vcsaddons/test_12_plot_one_leg_per_row_right.py index 42e0f64e4..b57b76724 100644 --- a/testing/vcsaddons/test_12_plot_one_leg_per_row_right.py +++ b/testing/vcsaddons/test_12_plot_one_leg_per_row_right.py @@ -1,17 +1,13 @@ +import os, sys, testing.regression as regression -import sys,os -src = sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage import EzTemplate,vcs import cdms,EzTemplate,vcs,sys ## 12 plots 1 legend per row on the right ## Initialize VCS -x=vcs.init() +x = vcs.init() x.drawlogooff() -bg=True -M=EzTemplate.Multi(rows=4,columns=3) +bg = True +M = EzTemplate.Multi(rows=4,columns=3) M.legend.direction='vertical' for i in range(12): t=M.get(legend='local') @@ -19,9 +15,7 @@ for i in range(12): t.legend.priority=0 # Turn off legend fnm = "test_12_plot_one_leg_per_row_right.png" M.preview(fnm,bg=bg) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) +ret = regression.check_result_image(fnm, sys.argv[1]) if not bg: raw_input("Press Enter") sys.exit(ret) diff --git a/testing/vcsaddons/test_EzTemplate_12_plots_legd_direction.py b/testing/vcsaddons/test_EzTemplate_12_plots_legd_direction.py index b6ca9eb34..d46e7b9ac 100644 --- a/testing/vcsaddons/test_EzTemplate_12_plots_legd_direction.py +++ b/testing/vcsaddons/test_EzTemplate_12_plots_legd_direction.py @@ -1,14 +1,7 @@ - -import sys,os -src = sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -import EzTemplate,vcs -## 12 plot one legend per row +import os, sys, EzTemplate, vcs, testing.regression as regression ## Initialize VCS -x=vcs.init() +x = vcs.init() x.drawlogooff() bg = True @@ -26,10 +19,8 @@ for i in range(12): t=M.get() fnm = "test_EzTemplate_12_plots_legd_direction.png" -M.preview(fnm,bg=bg) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) +M.preview(fnm, bg=bg) +ret = regression.check_result_image(fnm, sys.argv[1]) if not bg: raw_input("Press Enter") sys.exit(ret) diff --git a/testing/vcsaddons/test_EzTemplate_12_plots_margins_thickness.py b/testing/vcsaddons/test_EzTemplate_12_plots_margins_thickness.py index 40899f264..73b7c8dbf 100644 --- a/testing/vcsaddons/test_EzTemplate_12_plots_margins_thickness.py +++ b/testing/vcsaddons/test_EzTemplate_12_plots_margins_thickness.py @@ -1,14 +1,7 @@ - -import sys,os -src = sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -import EzTemplate,vcs -## 12 plot one legend per row +import os, sys, EzTemplate, vcs, testing.regression as regression ## Initialize VCS -x=vcs.init() +x = vcs.init() x.drawlogooff() bg = True @@ -25,9 +18,7 @@ for i in range(12): t=M.get() fnm = "test_EzTemplate_12_plots_margins_thickness.png" M.preview(fnm,bg=bg) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) +ret = regression.check_result_image(fnm, sys.argv[1]) if not bg: raw_input("Press Enter") sys.exit(ret) diff --git a/testing/vcsaddons/test_EzTemplate_12_plots_mix_glb_local.py b/testing/vcsaddons/test_EzTemplate_12_plots_mix_glb_local.py index 043e03de4..6e9398fe8 100644 --- a/testing/vcsaddons/test_EzTemplate_12_plots_mix_glb_local.py +++ b/testing/vcsaddons/test_EzTemplate_12_plots_mix_glb_local.py @@ -1,12 +1,4 @@ - -import sys,os -src = sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -import EzTemplate,vcs -## 12 plot one legend per row - +import os, sys, EzTemplate, vcs, testing.regression as regression ## Initialize VCS x=vcs.init() x.drawlogooff() @@ -24,9 +16,7 @@ for i in range(12): fnm = "test_EzTemplate_12_plots_mix_glb_local.png" M.preview(fnm,bg=bg) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) +ret = regression.check_result_image(fnm, sys.argv[1]) if not bg: raw_input("Press Enter") sys.exit(ret) diff --git a/testing/vcsaddons/test_EzTemplate_12_plots_spacing.py b/testing/vcsaddons/test_EzTemplate_12_plots_spacing.py index d17eb1a69..5d4cd293b 100644 --- a/testing/vcsaddons/test_EzTemplate_12_plots_spacing.py +++ b/testing/vcsaddons/test_EzTemplate_12_plots_spacing.py @@ -1,14 +1,6 @@ - -import sys,os -src = sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage -import EzTemplate,vcs -## 12 plot one legend per row - +import os, sys, EzTemplate, vcs, testing.regression as regression ## Initialize VCS -x=vcs.init() +x = vcs.init() x.drawlogooff() bg = True @@ -18,9 +10,7 @@ M.spacing.vertical=.1 fnm = "test_EzTemplate_12_plots_spacing.png" M.preview(fnm,bg=bg) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) +ret = regression.check_result_image(fnm, sys.argv[1]) if not bg: raw_input("Press Enter") sys.exit(ret) diff --git a/testing/vcsaddons/test_vcs_addons_EzTemplate_2x2.py b/testing/vcsaddons/test_vcs_addons_EzTemplate_2x2.py index 2619fe5ef..ee645d16c 100644 --- a/testing/vcsaddons/test_vcs_addons_EzTemplate_2x2.py +++ b/testing/vcsaddons/test_vcs_addons_EzTemplate_2x2.py @@ -1,21 +1,11 @@ +import os, sys, cdms2, testing.regression as regression, vcs, vcsaddons -import sys,os -src = sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage - -import vcs -import vcsaddons -import cdms2 - -f=cdms2.open(os.path.join(vcs.sample_data,'clt.nc')) -s=f("clt",time=slice(0,1),squeeze=1) +f = cdms2.open(os.path.join(vcs.sample_data,'clt.nc')) +s = f("clt",time=slice(0,1),squeeze=1) bg = True - -M=vcsaddons.EzTemplate.Multi(rows=2,columns=2) -x=vcs.init() +M = vcsaddons.EzTemplate.Multi(rows=2,columns=2) +x = vcs.init() x.setantialiasing(0) x.drawlogooff() if bg: @@ -25,9 +15,7 @@ for i in range(4): fnm = "test_vcs_addons_EzTemplate_2x2.png" x.png(fnm) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) +ret = regression.check_result_image(fnm, sys.argv[1]) if not bg: raw_input("Press Enter") sys.exit(ret) diff --git a/testing/vcsaddons/test_vcsaddons_preview_2x2.py b/testing/vcsaddons/test_vcsaddons_preview_2x2.py index 754aa5cea..a0318f25a 100644 --- a/testing/vcsaddons/test_vcsaddons_preview_2x2.py +++ b/testing/vcsaddons/test_vcsaddons_preview_2x2.py @@ -1,22 +1,12 @@ - -import sys,os -src = sys.argv[1] -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage - -import vcsaddons +import os, sys, testing.regression as regression, vcsaddons bg = True - -M=vcsaddons.EzTemplate.Multi(rows=2,columns=2) +M = vcsaddons.EzTemplate.Multi(rows=2,columns=2) if bg: M.x.setbgoutputdimensions(1200,1091,units="pixels") fnm = "test_vcsaddons_preview_2x2.png" M.preview(out=fnm,bg=bg) -print "fnm:",fnm -print "src:",src -ret = checkimage.check_result_image(fnm,src,checkimage.defaultThreshold) +ret = regression.check_result_image(fnm, sys.argv[1]) if not bg: raw_input("Press Enter") sys.exit(ret) -- GitLab From 569843aec62da106d9a7452983f49c999adcf4aa Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Fri, 13 May 2016 07:34:01 -0400 Subject: [PATCH 046/191] Updated to current master --- testing/vcs/test_fewer_colors_than_levels.py | 20 +++-------------- testing/vcs/test_vcs_no_continents.py | 23 +++----------------- 2 files changed, 6 insertions(+), 37 deletions(-) diff --git a/testing/vcs/test_fewer_colors_than_levels.py b/testing/vcs/test_fewer_colors_than_levels.py index 2779d4b6d..c500cf19e 100644 --- a/testing/vcs/test_fewer_colors_than_levels.py +++ b/testing/vcs/test_fewer_colors_than_levels.py @@ -1,18 +1,9 @@ -import vcs,cdms2,sys,os - -baselineImage = sys.argv[1] - -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +import os, sys, cdms2, vcs, testing.regression as regression dataset = cdms2.open(os.path.join(vcs.sample_data,"clt.nc")) data = dataset("clt") -canvas = vcs.init() -canvas.setantialiasing(0) -canvas.setbgoutputdimensions(1200, 1091, units="pixels") -canvas.drawlogooff() +canvas = regression.init() boxfill = canvas.createboxfill() @@ -21,9 +12,4 @@ boxfill.color_2 = 250 canvas.plot(data, boxfill, bg=1) -testImage = os.path.abspath("test_fewer_colors_than_levels.png") -canvas.png(testImage) - -ret = checkimage.check_result_image(testImage, baselineImage, checkimage.defaultThreshold) - -sys.exit(ret) +regression.run(canvas, "test_fewer_colors_than_levels.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_no_continents.py b/testing/vcs/test_vcs_no_continents.py index 03630d457..a5c3e8d04 100644 --- a/testing/vcs/test_vcs_no_continents.py +++ b/testing/vcs/test_vcs_no_continents.py @@ -1,7 +1,4 @@ -import cdms2 -import os -import sys -import vcs +import os, sys, cdms2, vcs, testing.regression as regression # Load the clt data: dataFile = cdms2.open(os.path.join(vcs.sample_data, "clt.nc")) @@ -10,10 +7,7 @@ clt = clt(latitude=(-90.0, 90.0), longitude=(-180., 175.), squeeze=1, time=('1979-1-1 0:0:0.0', '1988-12-1 0:0:0.0')) # Initialize canvas: -canvas = vcs.init() -canvas.setantialiasing(0) -canvas.setbgoutputdimensions(1200,1091,units="pixels") -canvas.drawlogooff() +canvas = regression.init() t1 = vcs.createtemplate() t1.scale(.5, "y") @@ -24,15 +18,4 @@ t2.move(.5, 'y') canvas.plot(clt, t1, continents=0, bg=True) canvas.plot(clt, t2, continents=1, bg=True) -# Load the image testing module: -testingDir = os.path.join(os.path.dirname(__file__), "..") -sys.path.append(testingDir) -import checkimage - -# Create the test image and compare: -baseline = sys.argv[1] -testFile = "test_vcs_no_continents.png" -canvas.png(testFile) -ret = checkimage.check_result_image(testFile, baseline, - checkimage.defaultThreshold) -sys.exit(ret) +regression.run(canvas, "test_vcs_no_continents.png") \ No newline at end of file -- GitLab From 9990b92bbd4c29b95800d8a9feb3f14060158074 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Fri, 13 May 2016 07:36:49 -0400 Subject: [PATCH 047/191] Ported common code to testing common --- Packages/testing/common.py | 22 +++++++++++++++++++ Packages/testing/regression.py | 1 + .../vcs/test_vcs_fillarea_basics_no_plot.py | 8 ++----- testing/vcs/test_vcs_verify_boxfill_basics.py | 7 ++---- testing/vcs/test_vcs_verify_proj_basics.py | 8 ++----- 5 files changed, 29 insertions(+), 17 deletions(-) create mode 100644 Packages/testing/common.py diff --git a/Packages/testing/common.py b/Packages/testing/common.py new file mode 100644 index 000000000..7a32bcec5 --- /dev/null +++ b/Packages/testing/common.py @@ -0,0 +1,22 @@ +def test_values_setting(gm,attributes,good_values=[],bad_values=[]): + if isinstance(attributes,str): + attributes=[attributes,] + for att in attributes: + for val in good_values: + setattr(gm,att,val) + for val in bad_values: + try: + setattr(gm,att,val) + success = True + except: + success = False + else: + if success: + if hasattr(gm,"g_name"): + nm = gm.g_name + elif hasattr(gm,"s_name"): + nm = gm.s_name + else: + nm=gm.p_name + raise Exception,"Should not be able to set %s attribute '%s' to %s" % (nm,att,repr(val)) + sys.exit(1) diff --git a/Packages/testing/regression.py b/Packages/testing/regression.py index 68f381ce4..bcc088202 100644 --- a/Packages/testing/regression.py +++ b/Packages/testing/regression.py @@ -138,6 +138,7 @@ def check_result_image(fname, baselinefname=sys.argv[1], threshold=defaultThresh printDart("ValidImage", "image/png", os.path.abspath(bestFilename), "File") return -1 + def main(): if len(sys.argv) != 4: print "Error:" diff --git a/testing/vcs/test_vcs_fillarea_basics_no_plot.py b/testing/vcs/test_vcs_fillarea_basics_no_plot.py index 870aae9be..9a8e38ce7 100644 --- a/testing/vcs/test_vcs_fillarea_basics_no_plot.py +++ b/testing/vcs/test_vcs_fillarea_basics_no_plot.py @@ -1,9 +1,5 @@ - -import vcs -import numpy -import cdtime - -from vcs_test_common import * +import numpy, cdtime, vcs +from testing.common import test_values_setting x=vcs.init() x.drawlogooff() diff --git a/testing/vcs/test_vcs_verify_boxfill_basics.py b/testing/vcs/test_vcs_verify_boxfill_basics.py index 0d7c4c2d0..0768ff9f9 100644 --- a/testing/vcs/test_vcs_verify_boxfill_basics.py +++ b/testing/vcs/test_vcs_verify_boxfill_basics.py @@ -1,8 +1,5 @@ -import vcs -import numpy -import cdtime - -from vcs_test_common import * +import numpy, cdtime, vcs +from testing.common import test_values_setting x=vcs.init() x.drawlogooff() diff --git a/testing/vcs/test_vcs_verify_proj_basics.py b/testing/vcs/test_vcs_verify_proj_basics.py index f1e1fa0a9..822a6fc0b 100644 --- a/testing/vcs/test_vcs_verify_proj_basics.py +++ b/testing/vcs/test_vcs_verify_proj_basics.py @@ -1,9 +1,5 @@ - -import vcs -import numpy -import cdtime - -from vcs_test_common import * +import numpy, cdtime, vcs +from testing.common import test_values_setting x=vcs.init() x.drawlogooff() -- GitLab From a2ce6ac2f478aae2a184d4f618bbd3542325a1e1 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Fri, 13 May 2016 08:01:52 -0400 Subject: [PATCH 048/191] Added testing to the modules to be built --- Packages/testing/regression.py | 2 ++ Packages/testing/setup.py | 3 +-- installation/control.py | 11 ++++++----- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Packages/testing/regression.py b/Packages/testing/regression.py index bcc088202..b272d592f 100644 --- a/Packages/testing/regression.py +++ b/Packages/testing/regression.py @@ -27,10 +27,12 @@ def init(): return vcsinst def run(vcsinst, fname, baseline=sys.argv[1], threshold=defaultThreshold): + """Export plot to a png and exit after comparsion.""" vcsinst.png(fname) sys.exit(check_result_image(fname, baseline, threshold)) def run_wo_terminate(vcsinst, fname, baseline=sys.argv[1], threshold=defaultThreshold): + """Export plot to a png and return comparison with baseline.""" vcsinst.png(fname) return check_result_image(fname, baseline, threshold) diff --git a/Packages/testing/setup.py b/Packages/testing/setup.py index 70f790d7b..85c270ed8 100755 --- a/Packages/testing/setup.py +++ b/Packages/testing/setup.py @@ -9,6 +9,5 @@ setup(name="testing", description="Testing infrastructure for cdat", url="http://uvcdat.llnl.gov", packages=['testing'], - package_dir={'testing': 'testing',}, - install_requires=['numpy','vcs', 'vtk'], + package_dir = {'testing': '', } ) diff --git a/installation/control.py b/installation/control.py index 7a3a52091..49ed5d9af 100644 --- a/installation/control.py +++ b/installation/control.py @@ -1,7 +1,7 @@ # This file is used to control the behavior of install.py. # The search path is used if the X11 directories aren't configured. -x11search = ['/usr/X11R6', '/usr/X11R6.5.1', +x11search = ['/usr/X11R6', '/usr/X11R6.5.1', '/usr/X11R6.4','/usr','/usr/openwin','/opt'] # Here is where they are on OSF1 and perhaps similar systems x11OSF1lib = ['/usr/lib/X11', '/usr/lib'] @@ -48,14 +48,14 @@ else: make_code = 'make' # List of packages to be built -packages = [ +packages = [ "Packages/pydebug", "Packages/cdtime", "Packages/demo", "Packages/help", "Packages/regrid2", - "Packages/cdms2", - "Packages/esg", + "Packages/cdms2", + "Packages/esg", "Packages/ncml", "Packages/DV3D", "Packages/vcs", @@ -63,9 +63,10 @@ packages = [ "Packages/cdutil", "Packages/unidata", "Packages/xmgrace", - "Packages/genutil", + "Packages/genutil", "Packages/Thermo", "Packages/WK", "Packages/gui_support", "Packages/distarray", + "Packages/testing", ] -- GitLab From 477e09750e554da288341d72ffd1d0cf39bce308 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Fri, 13 May 2016 14:21:05 -0400 Subject: [PATCH 049/191] Marked export to gs as no longer supported --- Packages/vcs/vcs/Canvas.py | 63 ++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/Packages/vcs/vcs/Canvas.py b/Packages/vcs/vcs/Canvas.py index d98270c55..8de655fbc 100644 --- a/Packages/vcs/vcs/Canvas.py +++ b/Packages/vcs/vcs/Canvas.py @@ -5309,47 +5309,42 @@ Options::: def gs(self, filename='noname.gs', device='png256', orientation=None, resolution='792x612'): """ - Function: gs + Function: gs - Description of Function: - This routine allows the user to save the VCS canvas in one of the many - GhostScript (gs) file types (also known as devices). To view other - GhostScript devices, issue the command "gs --help" at the terminal - prompt. Device names include: bmp256, epswrite, jpeg, jpeggray, - pdfwrite, png256, png16m, sgirgb, tiffpack, and tifflzw. By default - the device = 'png256'. - - If no path/file name is given and no previously created gs file has been - designated, then file + Description of Function: + This routine allows the user to save the VCS canvas in one of the many + GhostScript (gs) file types (also known as devices). To view other + GhostScript devices, issue the command "gs --help" at the terminal + prompt. Device names include: bmp256, epswrite, jpeg, jpeggray, + pdfwrite, png256, png16m, sgirgb, tiffpack, and tifflzw. By default + the device = 'png256'. + + If no path/file name is given and no previously created gs file has been + designated, then file /$HOME/%s/default.gs - will be used for storing gs images. However, if a previously created gs - file exist, then this output file will be used for storage. + will be used for storing gs images. However, if a previously created gs + file exist, then this output file will be used for storage. - By default, the page orientation is the canvas' orientation. - To translate the page orientation to portrait mode (p), set the parameter orientation = 'p'. - To translate the page orientation to landscape mode (l), set the parameter orientation = 'l'. + By default, the page orientation is the canvas' orientation. + To translate the page orientation to portrait mode (p), set the parameter orientation = 'p'. + To translate the page orientation to landscape mode (l), set the parameter orientation = 'l'. - The gs command is used to create a single gs file at this point. The user - can use other tools to append separate image files. + The gs command is used to create a single gs file at this point. The user + can use other tools to append separate image files. - Example of Use: - a=vcs.init() - a.plot(array) - a.gs('example') #defaults: device='png256', orientation='l' and resolution='792x612' - a.gs(filename='example.tif', device='tiffpack', orientation='l', resolution='800x600') - a.gs(filename='example.pdf', device='pdfwrite', orientation='l', resolution='200x200') - a.gs(filename='example.jpg', device='jpeg', orientation='p', resolution='1000x1000') -""" % (self._dotdir) - if orientation is None: - orientation = self.orientation()[0] - r = resolution.split('x') - f1 = f1 = float(r[0]) / 1100.0 * 100.0 - f2 = f2 = float(r[1]) / 849.85 * 100.0 - resolution = "%4.1fx%4.1f" % (f2, f1) - nargs = (filename, device, orientation, resolution) - return self.canvas.gs(*nargs) + Example of Use: + a=vcs.init() + a.plot(array) + a.gs('example') #defaults: device='png256', orientation='l' and resolution='792x612' + a.gs(filename='example.tif', device='tiffpack', orientation='l', resolution='800x600') + a.gs(filename='example.pdf', device='pdfwrite', orientation='l', resolution='200x200') + a.gs(filename='example.jpg', device='jpeg', orientation='p', resolution='1000x1000') + + NOTE: This method is marked as deprecated + """ % (self._dotdir) + warnings.warn("Export to GhostScript is no longer supported", Warning) ########################################################################## # # -- GitLab From 3ef4b77b6e8bc3f21b44acb7cad9cfcd3351bfc5 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Fri, 13 May 2016 15:15:07 -0400 Subject: [PATCH 050/191] Cleaned docs --- docs/Legal.htm => LEGAL.htm | 0 docs/Legal.txt => LEGAL.txt | 0 TODO.txt | 5 - docs/ChangeLog.txt | 20 ---- docs/Changes_3.3_to_4.0.sxc | Bin 12334 -> 0 bytes docs/Changes_3.3_to_4.csv | 133 --------------------- docs/Changes_3.3_to_4.pdf | Bin 26249 -> 0 bytes docs/Changes_3.3_to_4.xls | Bin 45056 -> 0 bytes docs/DeveloperHowTo.html | 6 - docs/HELP.html | 6 - docs/README.txt | 2 - docs/ReleaseNotes.txt | 226 ------------------------------------ 12 files changed, 398 deletions(-) rename docs/Legal.htm => LEGAL.htm (100%) rename docs/Legal.txt => LEGAL.txt (100%) delete mode 100644 TODO.txt delete mode 100644 docs/ChangeLog.txt delete mode 100644 docs/Changes_3.3_to_4.0.sxc delete mode 100644 docs/Changes_3.3_to_4.csv delete mode 100644 docs/Changes_3.3_to_4.pdf delete mode 100644 docs/Changes_3.3_to_4.xls delete mode 100644 docs/DeveloperHowTo.html delete mode 100644 docs/HELP.html delete mode 100644 docs/README.txt delete mode 100644 docs/ReleaseNotes.txt diff --git a/docs/Legal.htm b/LEGAL.htm similarity index 100% rename from docs/Legal.htm rename to LEGAL.htm diff --git a/docs/Legal.txt b/LEGAL.txt similarity index 100% rename from docs/Legal.txt rename to LEGAL.txt diff --git a/TODO.txt b/TODO.txt deleted file mode 100644 index fb03af1f8..000000000 --- a/TODO.txt +++ /dev/null @@ -1,5 +0,0 @@ -- Fix ESMF build -- Verify individual packages -- Verify if we can build using system -- Consistent install and build directories -- Install headers and lib under their own package name diff --git a/docs/ChangeLog.txt b/docs/ChangeLog.txt deleted file mode 100644 index 5f7d49505..000000000 --- a/docs/ChangeLog.txt +++ /dev/null @@ -1,20 +0,0 @@ -2011-06-22 : recap (probably forgot many things): - - grib2 support - - restAPI support - - GUI code moved to uv-cdat repo - - forecast support - - gridspec support -2010-06-17 : got Qt to build automatically, (or use the binaries) -2010-06-17 : got --enable-vistrails to work and build SIP and PyQt -2010-06-15 : got the right LDFLAGS going to compile Fortran extensions under mac -2010-04-08 : build system fetches sources, no more gz in repository! -2010-04-08 : preliminary merge with Qt branch. You should be able to build against Qt (which needs to be pre-installed independently for now) -2010-02-11 : added netcdf 4.1 -2010-02-02 : added correct link calls for icc under linux -2010-01-28 : fixed tiny-tiny leak in cdms2 and cdtime (setting dictionary item -w/o decref tmp pyobject for int/string) -2010-01-28 : latest netcdf4 daily from Ed, fixes a LOT of memory leaks. -2010-01-13 : change default cdms2 compress value to no shuffle/deflate 1/defalteLevel 1 -2010-01-13 : newer NetCDF4, daily snapshot that has better chunking parameter, etc.. -2010-01-13 : latest Scientific Python (SP) -2010-01-13 : got vtk to build in framework mode under Mac diff --git a/docs/Changes_3.3_to_4.0.sxc b/docs/Changes_3.3_to_4.0.sxc deleted file mode 100644 index e811c67769e89d740d242f887021e5ac6dfc5dac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12334 zcmWIWW@Zs#0D zacQ1jMQ)B>a$-(0!~_lo4hE13Ad_I2n}LBLIX|x?HLnDu`fcppqT3dm_SyS4K3+Sk zXqC?CNjb;;)NU5N@l;EHd?Z!<=G@h~9W5$89!<;*)3$_v=BwWQyXdpZ^4*SJQ<5z= zG2NWfwsK1DL{$J5Y;o!aVc#doiV2#ufy3G-i^w50wk1wz8-VWY&HN(t)iPBGpvt?7? zna@s_KR@Gl%{2R?4{Xmq^MAkn#gl2*)#dxU$^^L7G=m~+3neEYSv(>f9v~| zC0`3H?#Py{NPYd|$Bv)wS2d?^(^k#m_A7ERlcye%a;akFBkbvrT?4 zo-y;DZPE3V)eiLng~@R_GefxLW;F_2jyCqrY|8jvQ~YTs`+>X`rH(VF_PzLjMARO)Mm&f<^VYvn6eo%!s^{k^bz>Mrl4ya~6~?VQ$f^jVXB z^t0G?sf+c67N#;38&5e_lWlS~dYSV6BgU&6UKwQsh)=FuG~f6zUr6?+c{Mw>d`bA; zvB~15);u56fUsyyp1Qqy6W)0*)@I1>79 zJ8o&qUVM1)-(L4Ckq#7fBU;HqrO$y>R#^KyVVZt+N!rM7XE%vr+n#i!`iDK zwmsazU9j0uV3YlZAJ@L!3v9nv^*zB@SxRfG(X+tCcN(wG+;P6)`GbFQ%z3u98TJnv zp6hg1^ZZ!gaLbwJ#;4ngfiXP~pNQ?6_-S9p4)t>`{pl0;zP){6@_DDsOC9~sdyg3M z9FaENCwKn$wR`u@GAjOmFe~q@-Mr%BA6@IK_9n-6Ro>p+vFMTCDbr8gUmo6$m*HGm z!XbP$RIE=@<#F8V;+B*YH&>&S`kRaE`&QWexO831+vyIsNP&O-%ddR=*0Q_2?>D+{ zn*Si;q4cYyfXmjri;a5MWc&AR^IG5U(r>Wk`c3;epFhobz0ap>TJVCMd?k&CtgBAU zj+$Dx_@SwvKf{kR`+ao|3oHyZV0Qb*z0YZNZ%;sB?u^4bRxkP>SG{&dxr3dSZ+|~O z|7w@Z)@}CQmw)m;zwkwF%ByYjZ^d-$TikM&m_&f8tQCtfvZ?M=6vs}`8CF5S5xD9Fk5+Wo^Cp6|AX zUR$zjZV3Nk)t%Q@3AOKyI~!bgJ}lC))oXqGs^?mQTcuvVPyC|t{YucaCA)e<_!n#J zRA(-#iCG(*dw1I@u2&&UKf<&3?^C;ac!d|tu+X;rZUiS9){-oacm&X)xPKWK6B~R6FXNM zx!c{^w0=Ry%i9NbYo4xCReHASjaxt4i}r~(<*o{C*KCOEJhM&f?Z3s0yPB4z-v2g< zm$4*WHR=AUk`4W=FU}plktH9xdM`*>zz!|nn;>Q9p6n~_pUw0ll%rLyZL5&x8^4pU zW_v%gJ6vD#`1&WV&Z{$*yfbbTH8GhwC7<7LuXgNL(JzbF{`&Ilauee`=b0^8Hxz=i z>}tAJ>C9Ks+C0(c1H;3KGxv&Sr1tpyy7BC2*rG`%b6*waO{vQ}c~?8S=%wWwm*Y0G z=H;awNNm|W_cHH{!i9Ga+}V4NcXGi>bzu!%DYd7K2Al5}7@cD?pQOH-lgG=q;E1cR z`MXcPPGNQ1D{^1%lfEd+o59f7b=jlmo!p@%7w0(oygM&{Y>t}AN+mz`JAu!&v$6y| zFP_f7linE?aBA%@p}qbBcax=61)E<<==llxwGe}iKzSHDeIH37TaI3SsJ50gN@rhhs{+>;=yjuhV=^) z;*IXD`THg8!t3J6%f2VJY)W-@y;fVrFXyHaeNAB7x69Fvnd?%fMgD%dcERBnw|w)9 z^WrZ2aSLyKJl%fRoU$**=kuSdede0Hh3U-Qt)EPiz4p$0{;8#ZyU9|Y#g*4=++`L$ zJrxVk-lV$sC!%tvRL z?-M+8Ht9*GzSq2OC3W|YY4X2eD*m}v&)Z~oL++&St@r)byEHU?_+Eai((3J%hgmc2 zX7j#j3)3AEzdz#rcA9D42E7d{B4@b;wfG#;v=!)K z?ubjf z81g8=e)Gah@jTLA)(SE;-%n?WtYPOm#m+uQEaJ(LuV<^Gj`noTJaBc!@-^ycNjKFj1fVX)|Y#&-iAmRSmmCUY)45b`}-Aj@ZOpp72Ov(?j{3yW`k zb|U_WSAV3+kLk0zP6vMU(N*1j{{4sKw5iiGR!Vm|d}z(A$MHRLxFzQOjFFyp;Bbe)b)gGEQzX_FZdz#ZQ{#~d z(;#4#O+Y!W9uE49O=7Z*0lV3bH7N{Kfc#+bM3g>@<6XRpv zY>sGsB$;h$#2mx^VWknHn)0LMsW+dmxtp;50_1L$!**d*(b2?^oX>WShqSq}tN8N@gzAGfi~Xzu`-t zT4WbD-+#TsBhPh~Qco>nPMe&#q#}K>Y|8Jd6)pxzP1y{(>;?w zeqP$RgG13`?TKSnAul%j-CJ_v$)*y|{V$|=vzyyGm-C-IH0Mm3=}Gf>Puk)ypIXlu zr`WXqM(?BaTTc(){Lnb-%T$HGtzrAuDW#m)dF~7I>_drug?>9;t!GYPz3r~!I9c0g zej-=I!IJ_3H##h`Jgy7K&UJTkzin>iCF{o{FL$8OCf@j-tTm&9+TT|Kbq_Vp&32r1 z+P!dJZ}3uG|2L1_i^|@~p4_=V{I18jX4mU!oWFDVy)*A`_YZ!4U~}~Cy4TO<`RetB zzc|*x7-M~8iND<>nfSEZ>;3fa$8DIgTvLnt`jq9jJu3E0zI(uXd1^;Ymqc0fgqbFn zgHk2#iF1DGOmoU!ntjV&?(J#YAP4>LLh5_s)7TCEIdvUL;xKy6T^$v$zvJSG$sIoH zPRku`+1wy5cw(N&L%rV?4e1Z-89psF5vwZBI&ghMdBXnPOY62@zsMHH=rVU@L#5jk z`}?Pj7M;lHOy|0_dRIn@6u+hia|@$M{jLLrhc$i{_qL{Le0NisIaRLb%2Pl8Ezgo? zwj^y)Id3N~^rBCCwSjZDaKF-nsglRHZ+uj0?epf_{JHyH?AG6Q`gHQayUD*(o`>!& z3}M&VusQnS;o4<9!pGNqi@7d*K;mds!J8E-Qk(7T{`a4o#PTzUPl)Gzw|(9J_k7t~ zqf<`v86}6t9A08%u+!=A=8c!yg%xW?)jrKWSeIP2o|7k%vPymKr#H%nRY zJ@Ni_;j33^Ww_g=zKi~oixw^ro))SzEyQSH+gT%#y4e!k(Yu~6KH=V;x~Jw;GlPrZ zo$2aXi#qJB1%iw(bw*BGzR6(2dya#8^;VYF|1)!)ub7L6`sT+<%Szf?Q5lts z>&nx6lDEr*v!?~IpKE8BX}U}@m^YJi0;@phT}Mg7#Iyz%$pf4Ulj~G&n4W)-KJV`* z9sXA{-P(5r^_iAvG0nXuS-Il3>)H0~h01ov96os@Ez>$Pt9#wK$^!9DA+8S#=N5eGl97V8`c9 zs~b03Td$e>|J{@Q-(Q-0C#FYSzR+>@NRzzynoHsPCPmzxUYdI7>y4#C&iUGB?1H$( zX8Zi`wD5^L$I(^7oWJnZFMKGW-JIYK7Bd#-fSCVSe^2`7(m-F?i+dM1Etg2cVej~69xeU)}> z(toZkr`|>!J@9S4N!q?;H#9}0sv@0)7AM|*vBK!A z^Rf+}x}I*;zB7s8d8_d&MRu?ti2wcv62!;S@LB-;bo& z?j?RGtIWE?%bX&me9_(9EHyYpG52(Api{ey@$(p7_R}ho&a)!jChwTjw}-7mzd>i# z>RmqH%8dk_C6k1vPWoxM+{nsmQlgUo6`{4NuPc6dh}eDbeb{_d^NyyavJ!KL_l>2U zXN+G580n`l{XUd*bBP9zNFl4kOtqbdo@ZCJM}0hyW>YkM6?0=NbI$xK?hSh<{dHM% zI8HX{b@g01-Ccg(58hQogthOh-FM3N*Tgs8?XFzi5@K66f70-+{Gq`vfA2tm<*hZT z_J?nHZEsnu$-@V8dqzf(`^r zG0GU!7i7(xkfLa&@c7}qtvOTDc_#*^bf;X;U%vkK%b=CH&zz5R{$GDveE*vT%?#HZ zlAX02HupWeCc0p^z5V8(<@WRUe)In3#=NU0@Wa;%p9y*fp+*ZGRCaL7)P;XGHD%4w z67b-BA9M0Y$CvHah|X<4*IWLo;Urp8H*6Q79Bx;=ZZkKEEL z`>lhI@T&5d2(D|JBwYOB8UOy&Q+D<U2)4kbTRX=7dA;sc)NEa^&|7d#Wy z4%dWk@Kh_4t$g;_ebJxb`%~txoMiH8qw|yvUslC?_&P7$AJTD-TYFD*^*xh&??tz+ z-g>t#JZbgT7eP92-MmF7?J?|izjyWSQn|k?c6)dK*8R2ds77N#*3@8~348vg$Sz*2 z?Uy**S+LsQeQtUO=e=Re3S-Pe*j&;^=tu@iFK7BsE|L0P(k`vo5UR-mc{j*BB z^M+Lc;cq9*>uLyCw>SH9$b_URO$D95j}#rflC_}X%!$xfU*rqp^=FnB+Qo47Z=E9D zGy842NBIx#uQP-U7%grjwta8m?mHY4Q_!|x_v)}ju?6>vYm6C%cRBUlNswIndsX0; zJNF)Vo;2n5u{RYuEwQWRt{c-$&!uku3L#9F3p$p9)*WWd)A%JX#bmBlUuXH;@$=ENu7N>WcN|V| z6aRdxx8f6PDBJZK-Q+1z+}C-(@U$i0Pq2uyX<51^sV~^qwfRkhQOuLbNvoYt9(`LR zn_srm-0Py{ck`Co+&Q0jKlmmdTcG-UW%K)Z`MI|DkL|oE$NQ#H&g|Z$Z4YWr|Nrs# ze&-?{W9u~+9par%Sw8G}aW!(8>ECdd|8B~GVoP?p9m)0mYR`W)^JM>{70W7*X1v=k zQ$F+0^cbm!uS}nP{b{gNq(C8Z%Kiy^8XEt;+ht&q*TeN>*Q*C+LP~WurTcCPPxxW0 zb93#~P=}4P?s;Fj-LJdv&hqsSE(@KFP1G^jF*{aSXYWDRdGl5u;agJR@+&!%&orL;(^n_x=_Nka@Urpierl80b}0I+`CZoR z3LRJP{CSN}{r*<6O-pF%WTE(i7Yj=n?s9Y=xN&Iq z2Dei|F17MU>Jm0>n7Y8F#;11Hd}Gs})0E~fKf`?AasMK&&puqytGZmCmZ{1xzn-yq z3D=RYPqu}=yX5_&l9Mr?`O6WtxPn~a(CuP=8ZT#F(fz+9@9YPLIvEpwuOB~W3uxXB zn_+&yF0p<&Qy81`_i8D=%uA9BWcO!HT`RWzn_SiAZ}U#GJX>k@`B&^}fAQGWOCLON z=I34=v+Zzy+V(kbt3CH`mwvs4W#43vZ-$&-tS9Wv5qtDA=ibUC{_+w>FY+vv-EjH3 z-fj0y>y9nZdT?;IU;47k7Ehz3rpAbV+MM2D;cLJ?aksx!d#1 zEa6Zh&vjEif@}XlE0!4%8fV|QaCr-zF_Y%zdvid*Sa3GS?c}3Rw)&jewDG{MFB4Z6 zq^&OOnpYB&QC?Ow-R|aMo#o7Hii8sC|9Zv7mDpB%pZ1YK zHt1E5@6Xc)#+Gs>of|UE-9+|G_B1Q9Tv{>VaH8(j1EL3-?QP?C3SI2tn`7>D^iY!1 z#$pS#vIprJl};WzT=MT{`cB?DRYjYDGk#LaO7HyE!qXWQzHi*)UWNp1bDE$z_oU#> ziGP-+=^D4^sPWZk^q&&gQRMf~3r$zXEBfWPg%u! zvg^X#WTW#&H}wU*cdp;Hu;8H0B%Z&_YMh^9PjNUL-C>z@%hsvxoWY{BDa$YI=i^b} z&{p1P$Ck7*MYs1Hck^e$RxW&+{Db~?t;pYS&(`mOFrZG=1TXsUK)@$Mk)0kC-H%ekduRbdmvE1ve zvoOXv!sGf!8S9csJET@C%rm&>+#Z(k=X@A%M;61O;!RyfGRtC_za|EET<{NMnIy1i zLtS+1ADOU*rl5fT6Q2v;-z|GL{K1p!RbF?v+L#%WG~GOtSKQ&Z34OM+ds=b*W`WBy zmGsP_(|0<#tWi(?c~Vt7d12HkvvA>i{~HU=eHCA5d%05od;S3x(<}A9Z?gibTaVYv z=||Qz-clLuS04uw`cY^zb90Gh)l;NuFj}Gs9qS)R8?4 zw0pf+I~Q;Cp1$>F&M_^<$7eH>F0Sa5oV%<;)AU*^TUD0!!}FIpgcr9vbgPJXDi~^? zU-SQrN^+9bHs%R7+d{>S)6IgfpWJcJ=3j`;bM57`7%I0ct1f*}XZTKc=94_TrH02= zakSXniq&#W@O`)SW9N^MkOJLH_ms~!@M`kipOq;&_0GL(C5%5AJJbsFbf%lFIM!Z2 zaY;dZ^vP}Sdm<|J+75_p(Z8BD)z*oxVV?0+m*k+xt;?jeoDX?RpItH~e`^i1UDn5F zHPc%Wx>|dU5R*fJ3i|sT2)^iZGD+*L%8h*ny;q*B zXZsnxf??;crm~9xpA|(z*K)?Q9@1AXoA){XswZT zFC8hadga=kJh5it%pPV0}d>z>&?z=kM_i z7uduSpY)^&NV@-Mk;**0=}P9Ddxt&y4_eK?J@@X}vXThyBRZRPcU(9VDC4^6bx`g@ zzJ@%WMuyBwGgTMN*Hc);&D7`>lasH%S#nvVQfRX8ujApy{``{bRLv}(n@Rk5_FXoH zNmRJ|ziUtXf#7RT;^XW?W=m#StnqnfeUz!w@cV?nuV33TxHf-Zu0Fjd?$Ei)C=Q;8 z_2Hi~%1>o4np(73ccQ6I+&s4?=HdyuS95(|Onp%kCS3SfChp(+>D^6&44Mm98=bEE zp&R_oazme%;fwc^Sdz;-1H1gPeoq&>rD?Y}d*!`7F)8&-_Buo5kDX(~dUp(qFUtO2gGg)55r%Sl*TmYwu1zxB1Wd z?en95Po8xl;&6kv#C?Z?8$OAzA5IjUoS!;n+tdBhcMJb1u&SHinO?JTYxtLT=F{ee z^CDX<&6_lX-o0A%^>6H!{a0N#|5-b0yYJIErwu;(UVVMi!RGa<0-L`gs~T+lr7R|X z`2F-hbAUHH$DGK2Rr<0F3}ID_47lf6xfmE2ic2bUQj0;;tXCs)^KY98{M#45aHaD_ zreqb%OzGv@nAT)&WXu%)!g|BbNJv$9sz>9ZM=AU3j+^g|oOXN5;a$rz4nIEp_-?Vj zO?7EqxY#{iLDQ!>Z{6J&z89SKValeOxAnh%u+9DT{GKp)%M9jQ^ya#=Dz>w zb~jKf*go#bVHs#?YvG3Xc4cArt-Q+rB>HDu&LPOLJ9Mu&IQIGi0I^Fh(UbBm3qRWMpx7VYi zuD7q@RC}>ODfryE2UAjZXy#0`UV6uN(yWl#_w8I6G9l?(UdW;`^TXSsXTEF5$r&lSI zZ{8JsX3Dpdz7KeIJQ4NE)HMuVYh+X97P;wS;!FkGxS4ecw+|@@we2roXy4V7#n1Ml zzpuJ1G^kBuvI={z=Gm1kH(YMDbl#4V^;BlrWBonY&E?_AuX7a3o=+2x2)a6LX-3tv z(pB$IOUGGQx8HoQVQ)`IeWtJ6${UY=y11PydQ?_?aJJX}?YBP2g*u1ro3iHSjJF|^ z*EKgCUj0Gi^n%;1rx>ayR((pkGHdbl|H)Ck?^V~`s!GzFx@+qFM~f8w=h>Zmdb)IW z_KsCt-bPYS9{F^fIeGU$%#2gg$Cq7y+4Q&l{^Y8EYwoVxknvp2WKX%(r(K#i9Xq{Z zE-cAa7s$S{VG4(YLc(@7wcSzD@04acM9u!Uw>ocI%QNYUIK_RL>jh;KPFw7$m~h;A z)2=7)TMPPL-{n*s&cpYRzlgo%sUo6&*Hc# zyfy#vZ7W&Z6WPaaY`Lx}s$%FGcH&y{LDev)me8oRe^Ym4=NQbAej{W)>9C83u!)R@ z*4Mmg278=dzxW+C^`hM6FP*x+S4%3h?w<75wzMV$4b+5x7Z*dZLiU~+y zlMdI`TXNvak=JbM^Fz&(R<0Jgk-T-`CC!z>JUw20SKj`uOw(TAzENhX4QoDE;}hT4 z{{F^aPRuEhDVt~YhV9Umy}N^JR@A+^!`I&zZRe#^bVJKync1kp?yzmbnw{z%fs#N&Qro1UMp zuvO+xkE`jf0`l{1!jslNWA)wZzVKhNwyNoU5eBUq!P53}qkn-ytLCpib4T7fvCd=` z-}2lI+uLvPGRu^PX@|^umNx62Z^rhovm}mbf4w$0^xOX`=Z>EtBJ=0ZU*ELxg4e1* zwVqY3tru;-Z)vj>j9bSe{`J9Q!|8i(ub--2ws4Kv;TV~nzpFOM3eQ=^_z$G zOXIJ}fqP=UHM)J%e;R8L`{Ll2^7S9>L8Y;DZnJ(ED+7aq7z4C42CZ}ft$OiZ7gY9+ znSlX>!RuyHOAt3rNST4r*pRZ4zxX>Mv>iEeIcNuokPsFRPUvx1VYzP^7!YMwt>jb46H zy1u?kh>HS*?*i4LV5n!HukY%oq@V;bOfRJ*Maj+v!a*~+A~z?m*a{+LtCUevQedU8 zpI?xg2N43>VPs%npbz0IDL^z-ZT3YIZWnoHFlHuwKN{e#9 zs#22mQ*%;5{wvlu)HBqFsRel!t{R&wKnj##VT2N@aQ}gn*x7(ctMt^o)S|?a{31Kl zP*X6}Gt@Is(D2F3E3MG9(MMBkqo}KEW@4)0RGOKSVr5}wX{@QM3pFyiC>6X2N;f63 zB-PHyz`#V;z)07?B*f6r%GA`##1Lv4sydsLWGfU6h87`)23AHERt9D^`Y=g|qYH{M z^GZ;SH#841G_^7|vNE)U8jqw1WOhzsUV3R_da7M&o^EI`*hIJx#MIQ3%#zH!blv32 zo06KAnU|WP01nl> z#N1R{CC|LHd<8=#eP|%!Rc1t-GGpSDnZT97b5wCjVo7FkNoF#{g(ZneIjOqI`K5U! zwn~Od5W(csoE(^#sgWtj5NHmt0(r~M2F8P%3KquQLgN9o&{9i4aR6?ky`7m`yvReK zVgLR0AAVF#ZJ3oZeeDrlg?$N&0zXX6XZ9(0WN`SP!mRju=2!2IP2IB~>~5@TXh_S; z%3aITmo1lGw_m?DChCBJ)08_LPm4V@93KUU3%+-g;FC&^Z+*Yje%=2)wHMef$L)2I zm!HVIf9I9XT8|r%ERv5m1+Fv?d0)C#WlrZKXNHr`YUO^;{v!G8+n0X*`*vA$r?$}1 zs&Ea?><2qf$1E(H>-{`z(u>=>e!9&t6sr+-J@xg%{3@+UDxI&Z6E7!r3eNmL!GF>d zo0VysQX{7wT~n(4D&SMcp70x~g}O>PwI2>;+vnV$6|+08JO4m>hoil$f9B^I4D)@V#;qFz|$$vLb`T9`XEN1WVq!};X_01II z{wXAom6`n0dD^lIvexVk)lYPtS-k(b3 ze|kHXbho{jDa5uxGU15TmDb(==3o5KV9Mv*HYfOE`I`GxFJ@GK3IFYXAY7(R%wVx} zLxttLl_JggZ*7b2+)C=*v!F=f`;L#*-l3YwSN=0poIf1j92r+ER(j9+W2DU~&WhIu zia#7HaO&E~d+3kyGjGT9QB!^~pR;^5&2OP{!{gYjw5&+2T^tSUmzkf0{t9*6VY%3I zmBUl@w|m47nUvmqcza3`M@K+4i$&AXs}TlEX8sMF$0T-){lo4lbGh#FTzq%2j-|-! zs>ZU1d{UQ7xTk7|U-f$W=@rN4DyH>Y9FF+**Ct(9!rFLx^RvksCz&|=P1F~>zUX|W zVk5)ZsrkV&GYh^uSab$m|Vrxkk?>XBs3Nd2VfPts~xdWcQD~ znvWJ%7;lT+;t;s*r+d?T^L;NaMLwRY+I2>>FilbQg`^mV3+v`a->qBX8>Vl6uibXt zypZG4$-f?qMo1lKo zCPYU5{$o`wdH3n}pMp<`xwcSl1Hu=I(!0FTHJl zFLL!*-`jANFDEJCc<{fe_0A`Ac{XJA-4m15_G#=bC$#FIL~( zxr^&}Ub!k_6?=B?xyh4Cw*3A3rAm2|>D4n&qHF&CT%7*yf0yaI92?YIAgreBtdNzU%VE_d}OY-kCn}+aa^73bN~CbJ@dKk6$i)6j?L( z=Ch-BWu>av;>{&@-`lAvaiWP~eVZUpJ|pvSj+CGBhEgV5CcbuBbk>1GW}2Eqd)=iS z>_@r}zJFh89w;=aDV`-`&a3ka`OY@!?{@59xam97EaccbAd6CPV>w9Nd=&)7WX~{h8Rg5@r@mKU4=8Fcs zeiOadt)A%S@t5&S^Yu%;%u_TZKJU^x%XaI^HHJb3y#=b<*~IIAyXZcvEm;2-+^O%_ zqrvi%m4QK00oIJfws=~Ufq}u-HN;WZ)6Y#mH!&|WEwvcDjC$>*jai2c1lS(z^^r5UKbQkie$aG+i7PPo_F ziWevCR~g1iI3M`Es%Vr6lIbtW-$eP-~U$kk`{L9OuM)55`j z7#JAdF@b`Qkx7IB_xg2E`y7E`tJwp*A-Z6}jy%c&TCPUIj1 gr7Msg2(H(~k;($RS=m5J*cjLtq8J$%_UVCm0ITAqKmY&$ diff --git a/docs/Changes_3.3_to_4.csv b/docs/Changes_3.3_to_4.csv deleted file mode 100644 index 762b7014b..000000000 --- a/docs/Changes_3.3_to_4.csv +++ /dev/null @@ -1,133 +0,0 @@ -"Impact";"Package";"Section";"Change" -1;"Cdms";"Axis";"Time dimension does not generate bounds automatically anymore – use cdms.setAutoBounds('on') -" -1;"Cdms";"Curvilinear grids";"CurveGrids can be supplied in the axis list." -1;"Cdms";"Curvilinear grids";"Added conversion routines: rect => curve => generic" -1;"Cdms";"Curvilinear grids";"MV works with curvilinear grids" -1;"Cdms";"Curvilinear grids";"Can read grids from scrip remap files" -1;"Cdms";"Curvilinear grids";"getMesh returns a transposed mesh grid if requested." -1;"Cdms";"Curvilinear grids";"On reading grids from files, check for cell convexity. Where that fails by default fix cells that straddle the 0 / 2pi boundary." -1;"Cdms";"Curvilinear grids";"Added routines to write grids to external files in scrip format" -1;"Cdms";"I/O";"Trapped seg faults on closed file objects." -1;"Cdms";;"Fixed memory leaks." -1;"Doc";"Tutorials";"New tutorials" -1;"Exsrc";"DODS";"Now builds by default under Linux, updated to Version 3.4" -1;"Vcdat";"DV";"A number reflecting selection/operation order appears next to selected variable" -1;"Vcdat";"DV";"Templates and Graphic Method Listbox available (on/off) in Variables and Calculator area" -1;"Vcdat";"Editors";"Template editor accessible from VCDAT (click and drag technology)" -1;"Vcdat";"Editors";"Graphic Method Editors updated, preview/reset option added" -1;"Vcdat";"General";"4 mode: 1-user defined layout; 2- Browse Variable; 3- Data Manipulation; 4- Graphics Display" -1;"Vcdat";"GUI";"Layout changed, now has mode for plot edititng, letting you copy/paste and edit existing template and method" -1;"Vcdat";"Plot";"Annotation pop-up available, with preview/reset/apply/cancel" -1;"Vcdat";"Plot";"Page Layout Table to control what is displayed on the VCS Canvas, can turn on/off plots with one click" -1;"Vcs";"Animations";" update to handle two or more on a page" -1;"Vcs";"Animations";"Can read from a file" -1;"Vcs";"Animations";"Can save to a file" -1;"Vcs";"Curvilinear grids";"Handled automatically" -1;"Vcs";"Projection";"Added gctp package to vcs, 28 new types of projection avalaible" -1;"Vcs";"Templates";"Template editor by clicking" -2;"Cdms";"I/O";"Added writeScripGrid, readScripGrid can read from a SCRIP mapping file" -2;"Cdms";"Libcdms";"Removed spurious calendar error" -2;"Cdms";"Time axis";"TransientAxis getCalendar returns DefaultCalendar if none specified. This is consistent with FileAxis.getCalendar()" -2;"Doc ";"Tutorials";"Data can now be anywhere on user's space" -2;"Genutil";"Arrayindexing";"New module, allows array indexing, e.g:C=genutil.arrayindexing.get(A,B)" -2;"Genutil";"Filters";"Added filters module, so far only “running average”, 121 and custom" -2;"Genutil";"Statistics";"fixed a bug in linear regression when trend is 0, probability are not set to missing" -2;"Install";"All";"Updated external Packages to their latest versions, see README files" -2;"Install";"CDAT";"Mac OS X “offically” supported" -2;"Install";"Cdms";"Fix CDMS build for FreeBSD" -2;"Install";"Cdms";"Added --cdms-only option to express_install." -2;"Install";"Exsrc";"Now can build indiviudal package or exclude some" -2;"Install";"Exsrc";"--list option added" -2;"Install";"Exsrc";"--help option in install_script " -2;"Vcdat";"0D (numbers)";"if no dimensions are present, then show the single vaule in the Defined Variables window" -2;"Vcdat";"1D plot";"Overlay applies, use page layout for other types" -2;"Vcdat";"DV";"Different mode of variable selection single/multiple" -2;"Vcdat";"GUI";"Remove the 1-Plot, 2-Plot, 3-Plot, 4-Plot per page" -2;"Vcdat";"I/O";"Simple binary file reader added" -2;"Vcdat";"I/O";"Can read column arranged ascii files" -2;"Vcdat";"I/O";"Save netcdf now has browser to go between directories" -2;"Vcdat";"I/O";"Simple ascii file reader added" -2;"Vcdat";"Menu";"New interface to user menu, more robust and intuitive" -2;"Vcdat";"Scripting";"Added limited recordings of the functions (not available on beta)" -2;"Vcs";"Boxfill";"Now can specify levels just like in isofill" -2;"Vcs";"Isofill";"Now has legend otpion (i.e can specifiy where to put values)" -2;"Vcs";;"Linewidth option added where line are controlled" -2;"Vcs";;"User can click on the plot and get worldcoordinate/index values, and actual value" -3;"Cdms";"I/O";"picker selector, let you pick non contiguous values" -3;"Cdutil";"Times";"Yearly and xDaily Time Bounds setting, plus accept either slab or axis" -3;"Contrib";"F2py";"Added F2PY, fortran wrapper" -3;"Install";"HDF";"--HDF= option let user point to HDF libraries" -3;"Install";"Scrip";"Source code distributed but not installed" -3;"Vcdat";"DV";"Replacing the eval call for the exec call. Now the user can enter any command" -3;"Vcdat";"DV";"Fix for the automatic Numeric and MA conversion to MV. The user now has a choice to convert Numeric and MA to MV. That is, the user will need to select the ""Automatic Conversion to MV"" toggle in the ""Preferences"" menu to turn this feature on or off" -3;"Vcs";"Plot";"Very High Resolution Continent Files generated via GMT are available on the web" -3;"Vcs";"Templates";"Scaling, now can scale fonts" -3;"Vcs";"Text";"Bg option works" -4;"Cdms";"I/O";"Implemented isClose()." -4;"Contrib";"Install";"Automatically built" -4;"Exsrc";"VTK";"VTK (beta version) added to distrib, not built by default this is experimental" -4;"Genutil";"Xmgrace";"Now can pass arguments at init time" -4;"Vcdat";"General";"Retains user settings" -4;"Vcdat";"General";"Predefined Region" -4;"Vcdat";"General";"Can define colors using intensiy" -4;"Vcdat";"Taylordiagram";"GUI updated" -4;"Vcs";"Primitives";"Projection accessible" -4;"Vcs";"Taylordiagram";"standard dev added to xaxis" -4;"Vcs";"Taylordiagram";"taylor control the xtic/ytic/cticks" -4;"Vcs";"Yxvsx, Xyvsy";"Auto now works again (no more blank canvas)" -4;"Vcs";;"Improved thread support" -5;"Cdms";"Cdscan";"Added –nofiles, --execfile option" -5;"Cdms";"Cdscan";"Added --notrim-lat option" -5;"Cdms";"Cdscan";"Added --filesxml option" -5;"Cdms";"Curvilinear grids";"Raise error if nonrectangular grid has no bounds associated" -5;"Cdms";"I/O";"Added gridftp protocol" -5;"Cdutil";"Times";"fixed times.setTimesBoundsMonthly for end of month storage" -5;"Cdutil";"Vertical";"Vertical Interpolation Tools (sigma2pressure)" -5;"Contrib";"IaGraph";"Package of interactive graphing tools. IaGraph will create line plots, scatter plots, and contour plots" -5;"Exsrc";"R";"Added R (statistical package) sources to distrib, not built by default" -5;"Genutil";"Xmgrace";"safe/nosafe problem solved, version controled before passing the argument" -5;"Ncml";;"New Package" -5;"Scrip";;"New module, interface to scrip regridder" -5;"Vcdat";"DV";"Icons tools added" -5;"Vcdat";"General";"Keep (or not) Windows in front of main window" -6;"Cdms";"Axis";"Align isLatitude, isLongitude test with CF convention" -6;"Contrib";"ComparisonStatistics";"fixed a bug for TimeComponent 18, the seasonal weights used in computing the annual means were slightly off" -6;"Contrib";"Rpy";"Added Rpy package, works if you have R on your system" -6;"Exsrc";"Pbm";"Pbmplus replaced with netpbm on Linux and Mac systems" -6;"Genutil";"Statistics";"Geometric Mean, Median and Rank functions added" -6;"Vcdat";"1D plot";"Fixed multiplier annotation for 1D plots." -6;"Vcdat";"DV";"Support for chemistry attributes" -6;"Vcdat";"General";"Exit Popup to retain settings (can be turned off)" -6;"Vcdat";"Menu";"Option pull down from main menu was changed to “Preferences”" -6;"Vcs";"Animations";"bug fix for pan and zoom" -6;"Vcs";"Templates";"Ratio options now supported, let user definean y/x ratio or if lat/lon let vcs find a good one" -7;"Contrib";"ComparisonStatistics";"Handles fortran NaN" -7;"Vcdat";"Annotations";"Changed annotation so a blank text field will print nothing in on the Canvas" -7;"Vcs";"boxfill/isofill";"Extension bug fix, if levels set after ext_1" -7;"Vcs";"Taylordiagram";"Taylordiags single precision ok now" -8;"Cdms";"Cdscan";"Fixed bug when file has 'bounds' dimension." -8;"Contrib";"ComparisonStatistics";"Updated doc" -8;"Vcs";"Markers";"0 means no marker" -8;"Vcs";"Taylordiagram";"fixed taylordiagrams.script and also listelements('taylordiagram') now works (x.show returns None)" -9;"Cdms";"Drs";"Fixed the cycle process for DRS files. Must close DRS files before you open them again." -9;"Cdutil";;"Removed Propertied Class dependencies, replaced with standard python (object/property)" -9;"Contrib";"ComparisonStatistics";"Bug fixing" -9;"Contrib";"Pyfort";"New version 8.4" -9;"Vcdat";"General";"User can defined the name of its default template/graphic methods" -9;"Vcs";"1D plots";"Bug fixes for graphics methods. That is, if the data only has 1 dimensions and 2 or more dimensions are required, then use Yxvsx to plot the data" -9;"Vcs";"Printer";"lanscape/portrait argument bug fix" -9;"Vcs";"Taylordiagram";"Skill drawing, bug fix" -9;"Vcs";;"Major changes to the VCS graphics methods" -9;"Vcs";;"Fixed attribute settings for missing attributes" -10;"Cdms";"I/O";"Fixed bug in dataset.write when time axis is a float. This shows up with Numeric V23.1" -10;"Cdms";;"Added xmllib to ditrib since it'll be abandoned in future python" -10;"Cdutil";"VariableMatcher";"Added comment keyword" -10;"Genutil";;"Removed Propertied Class dependencies, replaced with standard python (object/property)" -10;"Vcs";"Colormap";"Added the NCAR Color Map to the initial.attribute file." -10;"Vcs";"Colormap";"Cleanedup" -10;"Vcs";"Templates";"fixed JYP comments about ""inconsistency"" on comment#1 of UL1of4 template" -10;"Vcs";;"Removed Propertied Class dependencies, replaced with standard python (object/property)" -11;"Cdms";"Curvilinear grids";"auxcoord, gengrid modules" -11;"Esg";;"New Package" -11;"Install";"CDAT";"Building GNU tar on older systems..." -11;"Install";"CDAT";"--psql option added" diff --git a/docs/Changes_3.3_to_4.pdf b/docs/Changes_3.3_to_4.pdf deleted file mode 100644 index 408ca428a82faabccf24180853af8b797fb397aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26249 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 Gc)0+ud-?VN diff --git a/docs/Changes_3.3_to_4.xls b/docs/Changes_3.3_to_4.xls deleted file mode 100644 index aabf7d192034c44d1ff0f6151d443b30e2aba7ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45056 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 - - - - - diff --git a/docs/HELP.html b/docs/HELP.html deleted file mode 100644 index 7430ec110..000000000 --- a/docs/HELP.html +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/docs/README.txt b/docs/README.txt deleted file mode 100644 index 99bf6afef..000000000 --- a/docs/README.txt +++ /dev/null @@ -1,2 +0,0 @@ -The documentation of UV-CDAT has moved to github. Please visit -this page for the latest documentation: https://github.com/UV-CDAT/uvcdat/wiki diff --git a/docs/ReleaseNotes.txt b/docs/ReleaseNotes.txt deleted file mode 100644 index ca81f7443..000000000 --- a/docs/ReleaseNotes.txt +++ /dev/null @@ -1,226 +0,0 @@ -********************* Changes in the next release **** -********************* Release 4.3 ************************************* -New build system, CDAT is now installed under CDAT/VERSION/bin -New Fonts system: most ttf fonts work now! -New direct postscript output -Hatch/pattern output working (see known bug though) -Improved VCDAT -New Package: Thermo -EZTemplate -genutil.filters -going away from pyfort, using f2py instead -pydebug included -mpeg output -generalized grid support -improved web documentation - -!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! -There is a known bug in cairo (the postscript rendering library) that will -cause the output to be wrong if you are using both -pattern/hatches and dashed lines - - -********************* Release 4.0 ************************************* - ----------------------------- -MAJOR CHANGES TO THE RELEASE ----------------------------- - -*- Support for Generalized Grids, regridding possible using the SCRIP regridder -(source code provided but not installed) - -*- Template Editor, let you resize, drag, drop object on your VCS Canvas - -*- Major Overhaull of the VCDAT GUI, with template and graphic methods -editors. Various mode of use (variable browsing, computation mode, graphics -mode). - -*- Page Layout Editor available in VCDAT - -*- More projection available (GCTP package), total of 28 new types of -projection, each with full parameters control - -*- Improved install process - -*- New packages: filter, vertical interpolation, IaGraph, f2py, R/Rpy, VTK -(Linux only, and not supported), thermo (thermodynamic diagrams) - -*- Full list of Changes available in files Changes_3.3_to_4.* (Open Office, csv and -pdf formats) - -------------------------- -KNOWN BUGS -------------------------- - -*- There is apparently a bug on the Mac X server, this forces the user to move -the VCS canvas window in order for the threads to start. If not the -application might hang. - -*- Beta version does not have support for inline scripting from VCDAT, final -version and some future beta wiull have full support. - - -********************* Release 3.3 ************************************* -01. vcs plotting now as at-plotting-time overwritting capabilities, i.e, you can change a graphic method or template attribute as you plot by passing it to the plot command -02. vcs text function let you know draw string on the fly, also accepts colors argument passed a colornames -03 vcs canvas object have a new function "match_color" which allows the user to get the color in the colormap (in use or passed) that is closest from its desirted color -04. rank function now available in genutil.statstics - -********************* Release 3.3 (10/01/2002) ************************ -01. Meshfill support is now complete (for graphical output) - all is done at the C level, projection are authorized as well as - axes transformations. MUCH faster than the old python based support -02. CompasrisonsStatistics contrib package added (PCMDI's compall) -03. VariablesMatcher, VariableConditioner objects added, allows easy regrid/masking - of datasets for comparison, module: cdutil -04. Build changes have removed the need for users to set LD_LIBRARY_PATH. -05. Now available on AIX. -06. genutil.statistics now has percentiles and median functions -07. genutil now has grower function (add dimensions to MV so they have matching shapes) -08. genutil.statistics: fixed a bug when input datasets had different masks - (now uses the union of both masks) -09. pyclimate package added to the contrib, which is a Python package designed - to accomplish some usual tasks during the analysis of climate variability - using Python. It provides functions to perform some simple IO operations, - operations with COARDS-compliant netCDF files, EOF analysis, SVD and CCA - analysis of coupled data sets, some linear digital filters, kernel based - probabilitydensity function estimation and access to DCDFLIB.C library from - Python. -10. Fixed the Read Script File file browser dialog "File of type". The - text said "Search for netCDF" and "Search for GrADS". This has - been replaced with "Search fo VCS file" and "Search for Python files". -11. Sync'ed the continents to work with the Page Editor. In the process, - I fixed the canvas update to work with threads -12. Ran Insure++ on code to clean up memory leaks in XGKS and VCS. -13. Fixed "open" bug. That is, fixed bug for when x.open() called. It no - longer exists out of python from the command line. -14. Can now print a VCS Canvas plot, produced in background mode, - to an output file (i.e., postscript, cgm, gif, or eps.). -15. Reordered the include files to find the VCS include files first. - This solves the problem of VCS not compiling on Solaris 2.8 - platforms. Solaris 2.8 platforms have a project.h file located in - the /usr/lib directory. project.h is also an include file for VCS. - In any case, forcing the VCS include files to be seen first, solves - this problem and should have no effect on other platforms. -16. Bug fixes for the DEC platform. The low-level primative attribute settings - now work for the DEC platform. -17. Fixed the legend label to be positioned at the bottom right corner of - the plot. It will also move with the legend when the legend is - altered by the user. -18. Now the user does not have to specify the DISPLAY variable in order to run - VCS or VCDAT. That is the user can now run the VCS module from the - command-line, script, background mode, or from VCDAT without specifying - the environment variable DISPLAY. That is, XOpenDisplay is now set - to ":0.0" or "localhost:0.0" for VCS and for Tkinter. -19. This function displays graphics segments, which are currently stored in - the frame buffer, on the VCS Canvas. That is, if the plot function - was called with the option bg = 1 (i.e., background mode), then the - plot is produced in the frame buffer and not visible to the user. - In order to view the graphics segments, this function will copy - the contents of the frame buffer to the VCS Canvas, where the - graphics can be viewed by the user. -20. Added outfill and outline to the browser interface. They are now part of the - graphics method pulldown selection. Also add a graphics method attribute - settings interface for the two graphics method so the user can - change their attributes. -21. Added the capability for low-level primatives to accept Numeric arrays for - their list of x and y axis point values. -22. Bug fix for generating more than 140 plots. That is, commented out - Py_DECREF(dict); ---- - This DECREF causes memory problems for Python if the - user chooses to generate more than 140 plots in a Python loop. - That is, needed memory is removed then overwritten, which causes - Python to give the undefined global name error for "range", "len", - or some other globally defined Python key word. -23. vcdat_teaching_script_file.py now work with appropriate graphics methods. - That is, you can now run "python vcdat_teaching_script_file.py" to replay - what was done in the VCDAT session. - - Note: vcdat_recording_script_file.py worked because it did not rely on the - ASD.scr file. -24. Show the index values for 1D axis variables -25. Updated the "Alter Plot" GUI to reflect the minor ticks settings and the - axis type (i.e., Linear or Log10). Currently, the user can only view the - axis representation. Later when time permits, I will change the "View" - text input window to an "Edit" text input window. This will let the user - specify (via a Python dictionary) the location of the axis label and the - label text string. For example, { -90: "south pole", 0: "equator", - 90: "north pole"}. -26. Modified the VCDAT module to track user directory, file, and variable requests. - It also logs the user's wall clock and cpu time. Examples: "vcdat -u", - "vcdat -h". -27. Updated the VCS initial.attributes file to Mike Wehner's initial.attibutes file. -28. The Boxfill legend labels can be set with a list or a dictionary. For - example: [0, 10, 20, 30, 40] or {40:'some text', 50:'some more text'}. -29. boxfill.legend={.5:'hi'} will now work if the legend is vertical - or horizontal. -30. Colormap bug fix. The default colormap can now be changed, - then saved as a new colormap. -31. VCDAT option menu: -h, print out help menu; -n, turn splash screen off, -u, turn - user tracking mode on. See item 17. -32. Corrected the legend when plotting log based boxfill plots. -33. Updated the X and Y axes, so that the user can modify and - change the axes values. -34. The graphics method's data world coordinates (i.e., datawc_x1, datawc_x2, - datawc_y1, and datawc_y2) will override the incoming variable's coordinates. -35. VCDAT has a new icon to bookmark files, works just like the directories -36. Beta DODS support on Linux, build using --dods=/path/to/DODS/directory -37. gplot now builds automatically -38. various utilies necessary to produce GIF output are also now provided as part - of the install process. -39. VCS template object now have scale, reset, move and moveto associated function -40. added cddump utility (ncdump like utility that works on any type of file that - cdms can open) -41. VCDAT has new icon functions: grower, mask, getmask, less, greater, equal, not, standard deviation - -********************* Release 3.2 (4/15/2002) ************************ -1. Revised build system allows for installation into an existing Python. - Please see README.txt to learn the new installation system. - (Paul Dubois). DRS and QL support are not built by default, unless you - use the --PCMDI option. -2. In genutil.statistics, the linearegression now can return std error - and probabilities for regression constant (in addition of the regression coef). - Power users that used this capability should be aware that the syntax slightly - changed, see the doc string. (Charles Doutriaux) -3. Contributed package shgrid, cssgrid, dsgrid added (Clyde Dease) - See "INTRODUCTION TO NGMATH" below for descriptions. - After installation, go to the Test subdirectory of each and run python shgridtest.py; - a documentation file will be produced as a byproduct. -4. Updated averager so it now takes integer for single axis operation. - Updated averager so the weights options are now "unweighted" and "weighted" instead of - "equal" and "generate"; old options still work. - Updated averager so the weights keyword now works. - Updated the doc strings of averager so they reflect the previous 2 changes. - Updated genutil.statistics so weights options are now compatible with cdutil.averager. - -5. Solution to the high CPU usage problem when displaying a VCS Canvas. - Modification to the VCS Canvas event mainloop was done to avoid high CPU - usage while the VCS Canvas sat idle. This modification has no other - effects on the graphics or the VCS Canvas behavior. - -6. Extensive improvements to the VCDAT browser. These are detailed at: - http://esg.llnl.gov/cdat/GUI_Modifications.html - - INTRODUCTION TO NGMATH - - The ngmath library is a collection of interpolators and approximators -for one-dimensional, two-dimensional and three-dimensional data. The packages, -which were obtained from NCAR, are: - - natgrid -- a two-dimensional random data interpolation package based on - Dave Watson's nngridr. NOT built by default in CDAT due to - compile problems on some platforms. Works on linux. - - dsgrid -- a three-dimensional random data interpolator based on a - simple inverse distance weighting algorithm. - - fitgrid -- an interpolation package for one-dimensional and two-dimensional - gridded data based on Alan Cline's Fitpack. Fitpack uses splines - under tension to interpolate in one and two dimensions. - NOT IN CDAT. - - csagrid -- an approximation package for one-dimensional, two-dimensional and - three-dimensional random data based on David Fulker's Splpack. - csagrid uses cubic splines to calculate its approximation function. - -- GitLab From c3ffa3a3423fe8dfab5cce289ca82712217add08 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Fri, 13 May 2016 15:23:36 -0400 Subject: [PATCH 051/191] Initial VCS documentation --- docs/index.rst | 60 ++++++++++++++++++++++++++ docs/user-guide.rst | 103 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 docs/index.rst create mode 100644 docs/user-guide.rst diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 000000000..99c91e62a --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,60 @@ +VCS: Visualization Control System +================================== + +What is VCS? +--------------- + +The PCMDI Visualization Control System (VCS) is expressly designed to meet the needs of scientific community. VCS allows wide-ranging changes to be made to the data display, provides for hardcopy output, and includes a means for recovery of a previous display. + +In the VCS model, the data display is defined by a trio of named object sets, designated the “primary objects” (or “primary elements”). These include: + +* **Data Ingestion**: The data, which drives the visualization is ingested into the system via cdms2 or numeric modules such as numpy;. + +* **Graphics Method**: The graphics method, which specifies the display technique. + +* **Template**: The picture template, which determines the appearance of each segment of the display. Tables for manipulating these primary objects are stored in VCS for later recall and possible use. + +In addition, detailed specification of the primary objects’ attributes is provided by eight “secondary objects” (or secondary elements”): + +* **colormap**: Specification of combinations of 256 available colors +* **fill area**: Style, style index, and color index +* **format**: Specifications for converting numbers to display strings +* **line**: Line type, width and color index +* **list**: A sequence of pairs of numerical and character values +* **marker**: Marker type, size, and color index +* **text**: Text font type, character spacing, expansion and color index +* **text orientation**: Character height, angle, path, and horizontal/vertical alignment + +By combining primary and secondary objects in various ways (either at the command line or in a program), the VCS user can comprehensively diagnose and intercompare climate model simulations. VCS provides capabilities to: + +- View, select and modify attributes of data variables and of their dimensions +- Create and modify existing template attributes and graphics methods +- Save the state-of-the-system as a script to be run interactively or in a program +- Save a display as a Computer Graphics Metafile (CGM), GIF, Postscript, Sun Raster, or Encapsulated Postscript file +- Perform grid transformations and compute new data variables +- Create and modify color maps +- Zoom into a specified portion of a display +- Change the orientation (portrait vs. landscape) or size (partial vs. full-screen) of a display +- Animate a single data variable or more than one data variable simultaneously +- Display data in various geospatial projections + +For an overview of the concepts present in VCS, we recommend checking out the :doc:`user-guide`. + +VCS is published under the Apache 2.0 License. Its source code can be found at +https://github.com/UV-CDAT/uvcdat/Packages/vcs + +Table of contents +----------------- +.. toctree:: + :maxdepth: 2 + + admin-docs + user-docs + developer-docs + plugins + +API index +--------- + +* :ref:`genindex` +* :ref:`modindex`VCS \ No newline at end of file diff --git a/docs/user-guide.rst b/docs/user-guide.rst new file mode 100644 index 000000000..77f300f32 --- /dev/null +++ b/docs/user-guide.rst @@ -0,0 +1,103 @@ +User Guide +********** + +Document Conventions +==================== + +This User Guide is written for end-users of vcs, rather than developers. If you +have suggestions or questions about this documentation, feel free to contact us +`on UV-CDAT `_, +`the mailing list <>`_. + +vcs specific entities will be ``formatted like this``. + +.. _concepts: + +Concepts +======== + +The VCS module can accept data from the CDMS module, the CU module, or the Numeric module. For use on +how to use either of the mentioned modules, see their respective documentation. For examples on the +direct use of these modules, see the VCS API Examples chapter and the examples located throughout this texts. + +VCS Model +--------- + +The VCS model is defined by a trio of named attribute sets, designated the “Primary Objects” (also known as “Primary Elements”). +These include: the data, which specifies what is to be displayed and are obtained from the cdms2 or Numeric modules; +the graphics method, which specifies the display technique; and the picture template, which determines the appearance of +each segment of the display. + +VCS Primary Objects (or Primary Elements) +----------------------------------------- + +A description of each primary object is warranted before showing their use and usefulness in VCS. See descriptions below. + +**Graphics Method Objects** + +A graphics method simply defines how data is to be displayed on the screen. Currently, there are eleven different graphics methods with more on the way. Each graphics method has its own unique set of attributes (or members) and functions. They also have a set of core attributes that are common in all graphics methods. The descriptions of the current set of graphics methods are as follows: + +* **boxfillobject** - The boxfill graphics method draws color grid cells to represent the data on the VCS - Canvas. Its class symbol or alias is “Gfb”. +* **continentsobject** - The continents graphics method draws a predefined, generic set of continental -outlines in a longitude by latitude space. To draw continental outlines, no external data set is required. Its class symbol or alias is “Gcon”. +* **isofillobject** - The isofill graphics method fills the area between selected isolevels (levels of constant value) of a two-dimensional array with a user-specified color. Its class symbol or alias is “Gfi”. +* **isolineobject** - The isoline graphics method draws lines of constant value at specified levels in order to graphically represent a two-dimensional array. It also labels the values of these isolines on the VCS Canvas. Its class symbol or alias is “Gi”. +* **outfillobject** - The outfill graphics method fills a set of integer values in any data array. Its primary purpose is to display continents by filling their area as defined by a surface type array that indicates land, ocean, and sea-ice points. Its class symbol or alias is “Gfo”. +* **outlineobject** - The Outline graphics method outlines a set of integer values in any data array. Its primary purpose is to display continental outlines as defined by a surface type array that indicates land, ocean, and sea-ice points. Its class symbol or alias is “Go”. +* **scatterobject** - The scatter graphics method displays a scatter plot of two 4-dimensional data arrays, e.g. A(x,y,z,t) and B(x,y,z,t). Its class symbol or alias is “GSp”. +* **vectorobject** - The Vector graphics method displays a vector plot of a 2D vector field. Vectors are located at the coordinate locations and point in the direction of the data vector field. Vector magnitudes are the product of data vector field lengths and a scaling factor. Its class symbol or alias is “Gv”. +* **xvsyobject** - The XvsY graphics method displays a line plot from two 1D data arrays, that is X(t) and Y(t), where ‘t’ represents the 1D coordinate values. Its class symbol or alias is “GXY”. +* **xyvsyobject** - The Xyvsy graphics method displays a line plot from a 1D data array, i.e. a plot of X(y) where ‘y’ represents the 1D coordinate values. Its class symbol or alias is “GXy”. +* **Yxvsxobject** - The Yxvsx graphics method displays a line plot from a 1D data array, i.e. a plot of Y(x) where ‘x’ represents the 1D coordinate values. Its class symbol or alias is “GYx”. +* **3dscalarobject** - The 3dscalar graphics method displays an interactive 3D plot of a 4-dimensional (x,y,z,t) data array. Its class symbol or alias is “3d_scalar”. +* **3dvectorobject** - The 3dvector graphics method displays an interactive 3D plot of a 4-dimensional (x,y,z,t) vector field. Its class symbol or alias is “3d_vector”. + +**Picture Template Object** + +A picture template determines the location of each picture segment, the space to be allocated to it, and related properties relevant to its display. The description of the picture template is as follows: + +* **templateobject** - Picture Template attributes describe where and how segments of a picture will be displayed. The segments are graphical representations of: textual identification of the data formatted values of single-valued dimensions and mean, maximum, and minimum data values axes, tick marks, labels, boxes, lines, and a legend that is graphics-method specific the data. Picture templates describe where to display all segments including the data. Its class symbol or alias is “P”. + +**Data Object** + +Array data attribute sets and their associated dimensions are to be modified outside of VCS. See the CDMS2 and Numeric module documentation for data extraction, creation and manipulation. + +VCS Secondary Objects (or Secondary Elements) +--------------------------------------------- +A description of each secondary object is warranted before showing their use and usefulness in VCS. It is these secondary objects that defines the detailed specification of the primary objects’ attributes. Currently, there are five secondary objects with more to follow. + +**Colormap Object** + +The colormap object is used to specify, create, and modify colormaps. There are 256 colors and color indices, but only the first 240 color indices can be modified (indices 240 through 255 are reserved for VCS internal use). The description of the colormap object is as follows: + +*colormapobject* - A colormap contains 240 user-definable colors that are used for graphical displays. The color mixtures are defined in terms of percentages of red, green, and blue colors (0 to 100% for each). The resulting color depends on the specified mixtures of red, green, and blue. Its class symbol or alias is “Cp”. +Note: VCS colormaps are objects, but they are not referenced like other secondary objects. + +**Fillarea Object** + +The fillarea objects allows the user to edit fillarea attributes, including fillarea interior style, style index, and color index. The description of the fillarea object is as follows: + +*fillareaobject* - The fill area attributes are used to display regions defined by closed polygons, which can be filled with a uniform color, a pattern, or a hatch style. Attributes specify the style, color, position, and dimensions of the fill area. Its class symbol or alias is “Tf”. +Line Object + +**Line Object** + +The line object allows the editing of line type, width, and color index. The description of the line object is as follows: + +*lineobject* - The line attributes specify the type, width, and color of the line to be drawn for a graphical display. Its class symbol or alias is “Tl”. +Marker Object + +The marker object allows the editing of the marker type, width, and color index. The description of the marker object is as follows: + +**Marker Object** + +*markerobject* - The marker attribute specifies graphical symbols, symbol sizes, and colors used in appropriate graphics methods. Its class symbol or alias is “Tm”. + +**Text Objects** + +Graphical displays often contain textual inscriptions, which provide further information. The text-table object attributes allow the generation of character strings on the VCS Canvas by defining the character font, precision, expansion, spacing, and color. The text-orientation object attributes allow the appearance of text character strings to be changed by defining the character height, up-angle, path, and horizontal and vertical alignment. The text-combined object is a combination of both text-table and text-orientation objects. The description of the text objects are as follows: + +*textcombinedobject* - The text-combined attributes combine the text-table attributes and a text-orientation attributes together. From combining the two classes, the user is able to set attributes for both classes at once (i.e., define the font, spacing, expansion, color index, height, angle, path, vertical alignment, and horizontal alignment). Its class symbol or alias is “Tc”. + +*textorientationobject* - The text-orientation attributes set names that define the height, angel, path, horizontal alignment and vertical alignment. Its class symbol or alias is “To”. + +*texttableobject* - The text-table attributes set names that define the font, spacing, expansion, and color index. Its class symbol or alias is “Tt”. -- GitLab From eb6017fdb3dc17f4a5287f4c9f45f9bc2eaa66aa Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Fri, 13 May 2016 21:28:46 -0400 Subject: [PATCH 052/191] Added vcs plotting section --- docs/user-guide.rst | 72 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/docs/user-guide.rst b/docs/user-guide.rst index 77f300f32..acf80e490 100644 --- a/docs/user-guide.rst +++ b/docs/user-guide.rst @@ -65,21 +65,24 @@ VCS Secondary Objects (or Secondary Elements) --------------------------------------------- A description of each secondary object is warranted before showing their use and usefulness in VCS. It is these secondary objects that defines the detailed specification of the primary objects’ attributes. Currently, there are five secondary objects with more to follow. -**Colormap Object** +Colormap Object +^^^^^^^^^^^^^^^ The colormap object is used to specify, create, and modify colormaps. There are 256 colors and color indices, but only the first 240 color indices can be modified (indices 240 through 255 are reserved for VCS internal use). The description of the colormap object is as follows: *colormapobject* - A colormap contains 240 user-definable colors that are used for graphical displays. The color mixtures are defined in terms of percentages of red, green, and blue colors (0 to 100% for each). The resulting color depends on the specified mixtures of red, green, and blue. Its class symbol or alias is “Cp”. Note: VCS colormaps are objects, but they are not referenced like other secondary objects. -**Fillarea Object** +Fillarea Object +^^^^^^^^^^^^^^^ The fillarea objects allows the user to edit fillarea attributes, including fillarea interior style, style index, and color index. The description of the fillarea object is as follows: *fillareaobject* - The fill area attributes are used to display regions defined by closed polygons, which can be filled with a uniform color, a pattern, or a hatch style. Attributes specify the style, color, position, and dimensions of the fill area. Its class symbol or alias is “Tf”. Line Object -**Line Object** +Line Object +^^^^^^^^^^^ The line object allows the editing of line type, width, and color index. The description of the line object is as follows: @@ -88,11 +91,13 @@ Marker Object The marker object allows the editing of the marker type, width, and color index. The description of the marker object is as follows: -**Marker Object** +Marker Object +^^^^^^^^^^^^^ *markerobject* - The marker attribute specifies graphical symbols, symbol sizes, and colors used in appropriate graphics methods. Its class symbol or alias is “Tm”. -**Text Objects** +Text Objects +^^^^^^^^^^^^ Graphical displays often contain textual inscriptions, which provide further information. The text-table object attributes allow the generation of character strings on the VCS Canvas by defining the character font, precision, expansion, spacing, and color. The text-orientation object attributes allow the appearance of text character strings to be changed by defining the character height, up-angle, path, and horizontal and vertical alignment. The text-combined object is a combination of both text-table and text-orientation objects. The description of the text objects are as follows: @@ -101,3 +106,60 @@ Graphical displays often contain textual inscriptions, which provide further inf *textorientationobject* - The text-orientation attributes set names that define the height, angel, path, horizontal alignment and vertical alignment. Its class symbol or alias is “To”. *texttableobject* - The text-table attributes set names that define the font, spacing, expansion, and color index. Its class symbol or alias is “Tt”. + + +Getting Started with VCS +------------------------ + +Import VCS +^^^^^^^^^^ + +In Python, before one can start using a module they must first load it. +To load the VCS module, like all other Python modules, either type: + +``from vcs import`` + +or + +``import vcs`` + +If you use ``import vcs``, then you must prepend "vcs" to certain calls +(e.g., ``vcs.help()``). If you use ``from vcs import *``, then you must +be aware of possible name clashes. That is, if two packages are imported +using the form ``from name import *`` and both have a "help" function, +then Python doesn't know which ``help`` function to call. For such +cases, and indeed as an unspoken rule, it is best to use "import name" +to avoid name clashing between packages. + +Create Canvas Object +^^^^^^^^^^^^^^^^^^^^ + +To construct a VCS Canvas object type the following: + +``a = vcs.init()`` + +There can only be at most 8 VCS Canvas objects initialized at any given +time. + +Plotting in VCS +^^^^^^^^^^^^^^^ +There are several different ways to display data on the VCS Canvas. The +most basic way is to use the plot() function. The simple plot() function +command: plot(array1,[array2], [template object], [graphics\_method +object]). The examples below are showing how to plot a simple array +using default values for everything else.:: + + # Import vcs and io (cdms) modules + import vcs + import cdms2 + + # Open sample NetCDF data file + data = cdms2.open('clt.nc') + + # Initialize vcs and then plot the variable + canvas = vcs.init() + clt = data['clt'] + canvas.plot(clt) + + # Close the canvas context + canvas.close() \ No newline at end of file -- GitLab From 5543360ec377d82cde87172c3c6882f472dff238 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Fri, 13 May 2016 21:39:43 -0400 Subject: [PATCH 053/191] Fixed link to user-guide --- docs/index.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 99c91e62a..0bb30b293 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -48,10 +48,8 @@ Table of contents .. toctree:: :maxdepth: 2 - admin-docs - user-docs + user-guide developer-docs - plugins API index --------- -- GitLab From e8300df1a48e3b870bbe7ff96fb4adcc3b2cfeb2 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Fri, 13 May 2016 21:46:12 -0400 Subject: [PATCH 054/191] Added vcs plotting example --- docs/user-guide.rst | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/user-guide.rst b/docs/user-guide.rst index acf80e490..e04e8e9e3 100644 --- a/docs/user-guide.rst +++ b/docs/user-guide.rst @@ -6,8 +6,8 @@ Document Conventions This User Guide is written for end-users of vcs, rather than developers. If you have suggestions or questions about this documentation, feel free to contact us -`on UV-CDAT `_, -`the mailing list <>`_. +on `UV-CDAT `_, +`mailing list `_. vcs specific entities will be ``formatted like this``. @@ -33,7 +33,8 @@ VCS Primary Objects (or Primary Elements) A description of each primary object is warranted before showing their use and usefulness in VCS. See descriptions below. -**Graphics Method Objects** +Graphics Method Objects +^^^^^^^^^^^^^^^^^^^^^^^ A graphics method simply defines how data is to be displayed on the screen. Currently, there are eleven different graphics methods with more on the way. Each graphics method has its own unique set of attributes (or members) and functions. They also have a set of core attributes that are common in all graphics methods. The descriptions of the current set of graphics methods are as follows: @@ -147,7 +148,9 @@ There are several different ways to display data on the VCS Canvas. The most basic way is to use the plot() function. The simple plot() function command: plot(array1,[array2], [template object], [graphics\_method object]). The examples below are showing how to plot a simple array -using default values for everything else.:: +using default values for everything else. + +.. code-block:: python # Import vcs and io (cdms) modules import vcs -- GitLab From 0a2c266c6f97f8b75ba572df4e9ebed837fd042a Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Fri, 13 May 2016 21:52:07 -0400 Subject: [PATCH 055/191] Removed references to Numeric module --- docs/user-guide.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/user-guide.rst b/docs/user-guide.rst index e04e8e9e3..7e2c74437 100644 --- a/docs/user-guide.rst +++ b/docs/user-guide.rst @@ -16,7 +16,7 @@ vcs specific entities will be ``formatted like this``. Concepts ======== -The VCS module can accept data from the CDMS module, the CU module, or the Numeric module. For use on +The VCS module can accept data from the CDMS module or can use the numpy array. For use on how to use either of the mentioned modules, see their respective documentation. For examples on the direct use of these modules, see the VCS API Examples chapter and the examples located throughout this texts. @@ -24,7 +24,7 @@ VCS Model --------- The VCS model is defined by a trio of named attribute sets, designated the “Primary Objects” (also known as “Primary Elements”). -These include: the data, which specifies what is to be displayed and are obtained from the cdms2 or Numeric modules; +These include: the data, which specifies what is to be displayed and are obtained from the cdms2 or numpy array; the graphics method, which specifies the display technique; and the picture template, which determines the appearance of each segment of the display. @@ -60,7 +60,7 @@ A picture template determines the location of each picture segment, the space to **Data Object** -Array data attribute sets and their associated dimensions are to be modified outside of VCS. See the CDMS2 and Numeric module documentation for data extraction, creation and manipulation. +Array data attribute sets and their associated dimensions are to be modified outside of VCS. See the CDMS2 module documentation for data extraction, creation and manipulation. VCS Secondary Objects (or Secondary Elements) --------------------------------------------- -- GitLab From 58eba47ec284ab8638f5ebeadf0935ded32225e3 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Fri, 13 May 2016 23:59:55 -0400 Subject: [PATCH 056/191] Added some more examples for plotting --- docs/user-guide.rst | 69 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/docs/user-guide.rst b/docs/user-guide.rst index 7e2c74437..d894308a1 100644 --- a/docs/user-guide.rst +++ b/docs/user-guide.rst @@ -13,6 +13,17 @@ vcs specific entities will be ``formatted like this``. .. _concepts: +Installation +============ +While there are many ways a user can install vcs, installation using conda is +preferred for the end user. Currently, to install vcs, you need to install entire uvcdat +pacakge. :: + + conda install -c uvcdat + +It is assumed that conda is installed on user's system and is available on the shell. + + Concepts ======== @@ -165,4 +176,60 @@ using default values for everything else. canvas.plot(clt) # Close the canvas context - canvas.close() \ No newline at end of file + canvas.close() + +As mentioned earlier, vcs can use numpy array directly. The example below shows how to plot numpy array data. + +.. code-block:: python + + # Import necessary modules + import vcs + import cdms2 + import numpy + + # Manually create data + data = numpy.sin(numpy.arrange(100)) + + # Reshape to make it useful for vcs + data = numpy.reshape(data, (10, 10)) + + # Initialize vcs and then plot the data + canvas = vcs.init() + canvas.plot(data) + + # Close the canvas context + canvas.close() + +It should be noted that plot can take multiple arguments. For example, plot can take ``bg=1`` option to draw visualization in the background. Below is the plotting climate data example with few new options to plot method. + +.. code-block:: python + + # Import vcs and io (cdms) modules + import vcs + import cdms2 + + # Open sample NetCDF data file + data = cdms2.open('clt.nc') + + # Initialize vcs and then plot the variable + canvas = vcs.init() + + # Create isofill graphics method + iso = canvas.createisofill() + + # Create default template + template = canvas.createtemplate() + + # Scale visualization by factor of 2 + template.scale(2) + + clt = data['clt'] + + # Plot isofill with continents outline and default template + canvas.plot(template, iso, clt, continents=1) + + # Close the canvas context + canvas.close() + + +.. note:: When using the plot() function, keep in mind that all keyword arguments must be last. Note that the order of the objects is not restrictive, just as long as they are before any keyword argument. \ No newline at end of file -- GitLab From 11990623d5935de7a1e6bd426e63b33f26899117 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Sat, 14 May 2016 00:35:59 -0400 Subject: [PATCH 057/191] Moved vcs documentation to vcs directory --- {docs => Packages/vcs/docs}/index.rst | 0 {docs => Packages/vcs/docs}/user-guide.rst | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) rename {docs => Packages/vcs/docs}/index.rst (100%) rename {docs => Packages/vcs/docs}/user-guide.rst (99%) diff --git a/docs/index.rst b/Packages/vcs/docs/index.rst similarity index 100% rename from docs/index.rst rename to Packages/vcs/docs/index.rst diff --git a/docs/user-guide.rst b/Packages/vcs/docs/user-guide.rst similarity index 99% rename from docs/user-guide.rst rename to Packages/vcs/docs/user-guide.rst index d894308a1..476295e3c 100644 --- a/docs/user-guide.rst +++ b/Packages/vcs/docs/user-guide.rst @@ -220,12 +220,12 @@ It should be noted that plot can take multiple arguments. For example, plot can # Create default template template = canvas.createtemplate() - # Scale visualization by factor of 2 - template.scale(2) + # Scale down visualization space + template.scale(0.8) clt = data['clt'] - # Plot isofill with continents outline and default template + # Plot isofill with continents outline and custom template canvas.plot(template, iso, clt, continents=1) # Close the canvas context -- GitLab From 4b51eff646d7c12a37158a724ac59ef332c3e365 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Sat, 14 May 2016 07:51:59 -0400 Subject: [PATCH 058/191] Added list of create and get methods --- Packages/vcs/docs/user-guide.rst | 191 ++++++++++++++++++++++++++++++- 1 file changed, 190 insertions(+), 1 deletion(-) diff --git a/Packages/vcs/docs/user-guide.rst b/Packages/vcs/docs/user-guide.rst index 476295e3c..de96d5e7f 100644 --- a/Packages/vcs/docs/user-guide.rst +++ b/Packages/vcs/docs/user-guide.rst @@ -232,4 +232,193 @@ It should be noted that plot can take multiple arguments. For example, plot can canvas.close() -.. note:: When using the plot() function, keep in mind that all keyword arguments must be last. Note that the order of the objects is not restrictive, just as long as they are before any keyword argument. \ No newline at end of file +.. note:: When using the plot() function, keep in mind that all keyword arguments must be last. The order of the arguments is not restrictive, just as long as they are before any keyword argument. + + +Other Plotting functions in VCS +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There are other ways to plot data in VCS. These additional plotting +routines utilizes the same parameter format as the plot() function. What +makes these plotting functions unique are their direct association with +the graphics methods. That is, each graphics method has its own plot +function. For example, if the user wishes to plot data using the isofill +graphics method, then the function isofill() can be used instead of the +plot() function. If the isofill object is not specified then the default +isofill graphics method will be used. The user can also pass down the +name of the graphics method to be used. In some ways, the graphics +method plot functions can be thought of as short cuts to plotting data. + +Note, if a different graphics method object is specified and passed down +to one of these alternate plot functions, then the alternate plot +function will behave as the plot() function and plot the data in the +specified graphics method format. + +See table below for additional plot functions. + ++--------------------+--------------------------------------------------+ +| Plot Function | Description | ++====================+==================================================+ +| ``boxfill()`` | plot data using the boxfill graphics method | ++--------------------+--------------------------------------------------+ +| ``continents()`` | plot to the screen continental graphics method | ++--------------------+--------------------------------------------------+ +| ``isofill()`` | plot data using the isofill graphics method | ++--------------------+--------------------------------------------------+ +| ``isoline()`` | plot data using the isoline graphics method | ++--------------------+--------------------------------------------------+ +| ``outfill()`` | plot data using the outfill graphics method | ++--------------------+--------------------------------------------------+ +| ``outline()`` | plot data using the outline graphics method | ++--------------------+--------------------------------------------------+ +| ``scatter()`` | plot data using the scatter graphics method | ++--------------------+--------------------------------------------------+ +| ``vector()`` | plot data using the vector graphics method | ++--------------------+--------------------------------------------------+ +| ``xvsy()`` | plot data using the xvsy graphics method | ++--------------------+--------------------------------------------------+ +| ``xyvsy()`` | plot data using the xyvsy graphics method | ++--------------------+--------------------------------------------------+ +| ``yxvsy()`` | plot data using the yxvsy graphics method | ++--------------------+--------------------------------------------------+ +| ``scalar3D()`` | plot data using the 3d\_scalar graphics method | ++--------------------+--------------------------------------------------+ +| ``vector3D()`` | plot data using the 3d\_vector graphics method | ++--------------------+--------------------------------------------------+ + + +Creating VCS Objects +^^^^^^^^^^^^^^^^^^^^ + +The create functions enables the user to create VCS objects which can be +modified directly to produce the desired results. Since the VCS +"default" objects do allow modifications, it is best to either create a +new VCS object or get an existing one. When a VCS object is created, it +is stored in an internal table for later use and/or recall. + +Create the following VCS objects: + ++-------------------------------+---------------------------------------------------+ +| Create Function | Description | ++===============================+===================================================+ +| ``createboxfill()`` | creates a new boxfill graphics method object | ++-------------------------------+---------------------------------------------------+ +| ``createcontinents()`` | creates a new continents graphics method object | ++-------------------------------+---------------------------------------------------+ +| ``createfillarea()`` | creates a new fillarea secondary object | ++-------------------------------+---------------------------------------------------+ +| ``createisofill()`` | creates a new isofill graphics method object | ++-------------------------------+---------------------------------------------------+ +| ``createisoline()`` | creates a new isoline graphics method object | ++-------------------------------+---------------------------------------------------+ +| ``createline()`` | creates a new line secondary object | ++-------------------------------+---------------------------------------------------+ +| ``createmarker()`` | creates a new marker secondary object | ++-------------------------------+---------------------------------------------------+ +| ``createoutfill()`` | creates a new outfill graphics method object | ++-------------------------------+---------------------------------------------------+ +| ``createoutline()`` | creates a new outline graphics method object | ++-------------------------------+---------------------------------------------------+ +| ``createscatter()`` | creates a new scatter graphics method object | ++-------------------------------+---------------------------------------------------+ +| ``createtextcombined()`` | creates a new text-combined secondary object | ++-------------------------------+---------------------------------------------------+ +| ``createtextorientation()`` | creates a new text-orientation secondary object | ++-------------------------------+---------------------------------------------------+ +| ``createtexttable()`` | creates a new text-table secondary object | ++-------------------------------+---------------------------------------------------+ +| ``createvector()`` | creates a new vector graphics method object | ++-------------------------------+---------------------------------------------------+ +| ``createxvsy()`` | creates a new xvsy graphics method object | ++-------------------------------+---------------------------------------------------+ +| ``createxyvsy()`` | creates a new xyvsy graphics method object | ++-------------------------------+---------------------------------------------------+ +| ``createyxvsx()`` | creates a new xyvsy graphics method object | ++-------------------------------+---------------------------------------------------+ +| ``create3d_scalar()`` | creates a new 3d\_scalar graphics method object | ++-------------------------------+---------------------------------------------------+ +| ``create3d_vector()`` | creates a new 3d\_vector graphics method object | ++-------------------------------+---------------------------------------------------+ + + +Get Existing VCS Objects +'''''''''''''''''''''''' + +The get functions are used to obtain VCS objects that exist in the +object memory tables. The get function directly manipulates the object's +attributes in memory. If the object is used to display data on a plot +and is manipulated by the user, then the plot will be automatically +updated. + +Get the following VCS objects: + ++----------------------------+--------------------------------------------------------------------------------------+ +| Get Function | Description | ++============================+======================================================================================+ +| ``getboxfill()`` | get specified boxfill graphics method and create boxfill object | ++----------------------------+--------------------------------------------------------------------------------------+ +| ``getcontinents()`` | get specified continents graphics method and create continents object | ++----------------------------+--------------------------------------------------------------------------------------+ +| ``getfillarea()`` | get specified fillarea secondary object and create fillarea object | ++----------------------------+--------------------------------------------------------------------------------------+ +| ``getisofill()`` | get specified isofill graphics method and create fillarea object | ++----------------------------+--------------------------------------------------------------------------------------+ +| ``getisoline()`` | get specified isoline graphics method and create isoline object | ++----------------------------+--------------------------------------------------------------------------------------+ +| ``getline()`` | get specified line secondary object and create line object | ++----------------------------+--------------------------------------------------------------------------------------+ +| ``getmarker()`` | get specified marker secondary object and create marker object | ++----------------------------+--------------------------------------------------------------------------------------+ +| ``getoutfill()`` | get specified outfill graphics method and create outfill object | ++----------------------------+--------------------------------------------------------------------------------------+ +| ``getoutline()`` | get specifed outline graphics method and create outline object | ++----------------------------+--------------------------------------------------------------------------------------+ +| ``getscatter()`` | get specified scatter graphics method and create scatter object | ++----------------------------+--------------------------------------------------------------------------------------+ +| ``gettextcombined()`` | get specified text-combined secondary object and create text-combined object | ++----------------------------+--------------------------------------------------------------------------------------+ +| ``gettextorientation()`` | get specified text-orientation secondary object and create text-orientation object | ++----------------------------+--------------------------------------------------------------------------------------+ +| ``gettexttable()`` | get specified text-table secondary object and create text-table object | ++----------------------------+--------------------------------------------------------------------------------------+ +| ``getvector()`` | get specified vector graphics method and create vector object | ++----------------------------+--------------------------------------------------------------------------------------+ +| ``getxvsy()`` | get specified xvsy graphics method and create xvsy object | ++----------------------------+--------------------------------------------------------------------------------------+ +| ``getxyvsy()`` | get specified xyvsy graphics method and create xyvsy object | ++----------------------------+--------------------------------------------------------------------------------------+ +| ``getyxvsx()`` | get specified yxvsx graphics method and create yxvsx | ++----------------------------+--------------------------------------------------------------------------------------+ +| ``get3d_scalar()`` | get specified 3d\_scalar graphics method and create 3d\_scalar | ++----------------------------+--------------------------------------------------------------------------------------+ +| ``get3d_vector()`` | get specified 3d\_vector graphics method and create 3d\_vector | ++----------------------------+--------------------------------------------------------------------------------------+ + + +Removing VCS Objects +^^^^^^^^^^^^^^^^^^^^ + +Unwanted VCS objects can be removed from internal memory with the use of +the remove function. The remove function will identify the VCS object +type and remove it from the appropriate object table. + +Remove VCS objects: + ++----------------------+----------------------------------------------------------------------+ +| Remove | Description | ++======================+======================================================================+ +| ``removeobject()`` | allows the user to remove objects from the appropriate object list | ++----------------------+----------------------------------------------------------------------+ + +Show VCS Object List +^^^^^^^^^^^^^^^^^^^^ + +The show function is handy to list VCS objects tables. + +The show function is used to list the VCS objects in memory: + ++-----------------+----------------------------------------------------------+ +| Show Function | Description | ++=================+==========================================================+ +| ``show()`` | list VCS primary and secondary class objects in memory | ++-----------------+----------------------------------------------------------+ -- GitLab From 917e581050bf6a70e04b3a17afaf474cdbba2f21 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Sat, 14 May 2016 14:39:13 -0400 Subject: [PATCH 059/191] Added reference documentation --- Packages/vcs/docs/user-guide.rst | 131 +++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/Packages/vcs/docs/user-guide.rst b/Packages/vcs/docs/user-guide.rst index de96d5e7f..9a9ae40fc 100644 --- a/Packages/vcs/docs/user-guide.rst +++ b/Packages/vcs/docs/user-guide.rst @@ -422,3 +422,134 @@ The show function is used to list the VCS objects in memory: +=================+==========================================================+ | ``show()`` | list VCS primary and secondary class objects in memory | +-----------------+----------------------------------------------------------+ + + +VCS Reference Guide +------------------- + +``init`` +^^^^^^^^ +* Initialize, Construct a VCS Canvas Object + +.. code-block:: python + + import vcs,cdms2 + + file = cdms2.open('clt.nc') + + slab = file.getslab('clt') + + a = vcs.init() + + # This examples constructs 4 VCS Canvas a.plot(slab) + # Plot slab using default settings + b = vcs.init() + + # Construct VCS object + template = b.gettemplate('AMIP') + + # Get 'example' template object + b.plot(slab, template) + + # Plot slab using template 'AMIP' + c = vcs.init() + + # Construct new VCS object + isofill = c.getisofill('quick') + + # Get 'quick' isofill graphics method + c.plot(slab,template,isofill) + + # Plot slab using template and isofill objects + d = vcs.init() + + # Construct new VCS object + isoline = c.getisoline('quick') + + # Get 'quick' isoline graphics method + c.plot(isoline,slab,template) + + # Plot slab using isoline and template objects + +``help`` +^^^^^^^^ +* Print out the object's doc string + +.. code-block:: python + + import vcs + a = vcs.init() + ln = a.getline('red') + + # Get a VCS line object + # This will print out information on how to use ln + a.objecthelp(ln) + +``open`` +^^^^^^^^ +* Open VCS Canvas object. +* This routine really just manages the VCS canvas. It will popup the VCS Canvas for viewing. It can be used to display the VCS Canvas. + +.. code-block:: python + + import vcs + a = vcs.init() + a.open() + +``close`` +^^^^^^^^^ +* Close the VCS Canvas. It will remove the VCS Canvas object from the screen, but not deallocate it. + +.. code-block:: python + + import vcs + a = vcs.init() + a.plot(array, 'default', 'isofill', 'quick') + a.close() + +``mode`` +^^^^^^^^ +* ``Options <0 = manual, 1 = automatic>`` +* Update the VCS Canvas. +* Updating of the graphical displays on the VCS Canvas can be deferred until a later time. This is helpful when generating templates or displaying numerous plots. If a series of commands are given to VCS and the Canvas Mode is set to manual (i.e., 0), then no updating of the VCS Canvas occurs until the 'update' function is executed. + +.. note:: By default the VCS Canvas Mode is set to ``1``, which means VCS will update the VCS Canvas as necessary without prompting from the user. + +.. code-block:: python + + import vcs + a = vcs.init() + a.mode = 0 + # Set updating to manual mode + a.plot(array, 'default', 'boxfill', 'quick') + box = x.getboxfill('quick') + box.color_1 = 100 + box.xticlabels('lon30', 'lon30') + box.xticlabels('','') + box.datawc(1e20, 1e20, 1e20, 1e20) + box.datawc(-45.0, 45.0, -90.0, 90.0) + + # Update the changes manually + a.update() + +``update`` +^^^^^^^^^^ +* Update the VCS Canvas manually when the ``mode`` is set to ``0`` (manual). + +.. code-block:: python + + import vcs + + a = vcs.init() + a.mode = 0 + + # Go to manual mode a.plot(s,'default','boxfill','quick') + box = x.getboxfill('quick') + box.color_1 = 100 + box.xticlabels('lon30', 'lon30') + box.xticlabels('','') + box.datawc(1e20, 1e20, 1e20, 1e20) + box.datawc(-45.0, 45.0, -90.0, 90.0) + + # Update the changes manually + a.update() -- GitLab From 853af67c62c4aa7e5e42400e3027bf497a5c49fd Mon Sep 17 00:00:00 2001 From: Charles Doutriaux Date: Mon, 16 May 2016 09:00:14 -0700 Subject: [PATCH 060/191] Update Canvas.py Allow for deprecation warnings --- Packages/vcs/vcs/Canvas.py | 38 ++------------------------------------ 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/Packages/vcs/vcs/Canvas.py b/Packages/vcs/vcs/Canvas.py index 8de655fbc..79dcd0dcd 100644 --- a/Packages/vcs/vcs/Canvas.py +++ b/Packages/vcs/vcs/Canvas.py @@ -27,6 +27,7 @@ Normally, created by vcs.init() Contains the method plot. """ import warnings +warnings.filterwarnings("default","",DeprecationWarning,"",0) from pauser import pause import numpy.ma import MV2 @@ -5308,43 +5309,8 @@ Options::: ########################################################################## def gs(self, filename='noname.gs', device='png256', orientation=None, resolution='792x612'): - """ - Function: gs - - Description of Function: - This routine allows the user to save the VCS canvas in one of the many - GhostScript (gs) file types (also known as devices). To view other - GhostScript devices, issue the command "gs --help" at the terminal - prompt. Device names include: bmp256, epswrite, jpeg, jpeggray, - pdfwrite, png256, png16m, sgirgb, tiffpack, and tifflzw. By default - the device = 'png256'. - - If no path/file name is given and no previously created gs file has been - designated, then file - - /$HOME/%s/default.gs - - will be used for storing gs images. However, if a previously created gs - file exist, then this output file will be used for storage. - By default, the page orientation is the canvas' orientation. - To translate the page orientation to portrait mode (p), set the parameter orientation = 'p'. - To translate the page orientation to landscape mode (l), set the parameter orientation = 'l'. - - The gs command is used to create a single gs file at this point. The user - can use other tools to append separate image files. - - Example of Use: - a=vcs.init() - a.plot(array) - a.gs('example') #defaults: device='png256', orientation='l' and resolution='792x612' - a.gs(filename='example.tif', device='tiffpack', orientation='l', resolution='800x600') - a.gs(filename='example.pdf', device='pdfwrite', orientation='l', resolution='200x200') - a.gs(filename='example.jpg', device='jpeg', orientation='p', resolution='1000x1000') - - NOTE: This method is marked as deprecated - """ % (self._dotdir) - warnings.warn("Export to GhostScript is no longer supported", Warning) + warnings.warn("Export to GhostScript is no longer supported", DeprecationWarning) ########################################################################## # # -- GitLab From 243863d7c57e1727ef3110610682910ad230026c Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Mon, 16 May 2016 14:36:56 -0400 Subject: [PATCH 061/191] Added note on deprecation warning and moved it further down --- Packages/vcs/vcs/Canvas.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Packages/vcs/vcs/Canvas.py b/Packages/vcs/vcs/Canvas.py index 79dcd0dcd..06a8bebdc 100644 --- a/Packages/vcs/vcs/Canvas.py +++ b/Packages/vcs/vcs/Canvas.py @@ -27,7 +27,6 @@ Normally, created by vcs.init() Contains the method plot. """ import warnings -warnings.filterwarnings("default","",DeprecationWarning,"",0) from pauser import pause import numpy.ma import MV2 @@ -74,6 +73,8 @@ import vcs.manageElements # noqa import configurator # noqa from projection import round_projections # noqa +# Python < 3 DeprecationWarning ignored by default +warnings.filterwarnings("default", "", DeprecationWarning, "", 0) class SIGNAL(object): -- GitLab From 4e5e43d954b7e8fd05c0873bc38df773e02e6743 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Mon, 16 May 2016 14:58:39 -0400 Subject: [PATCH 062/191] Using a simple approach to turn on deprecation warning --- Packages/vcs/vcs/Canvas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/vcs/vcs/Canvas.py b/Packages/vcs/vcs/Canvas.py index 06a8bebdc..1599e0a03 100644 --- a/Packages/vcs/vcs/Canvas.py +++ b/Packages/vcs/vcs/Canvas.py @@ -74,7 +74,7 @@ import configurator # noqa from projection import round_projections # noqa # Python < 3 DeprecationWarning ignored by default -warnings.filterwarnings("default", "", DeprecationWarning, "", 0) +warnings.simplefilter('default') class SIGNAL(object): -- GitLab From ce13552f749e477e8fa55dc81b6b0d945d52497f Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Mon, 16 May 2016 13:18:22 -0700 Subject: [PATCH 063/191] Added some new tests --- Packages/vcsaddons/Lib/__init__.py | 3 + Packages/vcsaddons/Lib/core.py | 9 +- Packages/vcsaddons/Lib/histograms.py | 53 ++- Packages/vcsaddons/Lib/polar.py | 395 ++++++++++++++++++ testing/vcsaddons/CMakeLists.txt | 24 ++ .../vcs_addons_test_convert_arrays.py | 69 +++ .../vcs_addons_test_histogram_defaults.py | 22 + .../vcs_addons_test_histogram_inherit.py | 62 +++ testing/vcsaddons/vcs_addons_test_polar.py | 28 ++ .../vcs_addons_test_polar_inherit.py | 50 +++ 10 files changed, 692 insertions(+), 23 deletions(-) create mode 100644 Packages/vcsaddons/Lib/polar.py create mode 100644 testing/vcsaddons/vcs_addons_test_convert_arrays.py create mode 100644 testing/vcsaddons/vcs_addons_test_histogram_defaults.py create mode 100644 testing/vcsaddons/vcs_addons_test_histogram_inherit.py create mode 100644 testing/vcsaddons/vcs_addons_test_polar.py create mode 100644 testing/vcsaddons/vcs_addons_test_polar_inherit.py diff --git a/Packages/vcsaddons/Lib/__init__.py b/Packages/vcsaddons/Lib/__init__.py index eadaa435c..1ba782945 100644 --- a/Packages/vcsaddons/Lib/__init__.py +++ b/Packages/vcsaddons/Lib/__init__.py @@ -1,5 +1,6 @@ gms = {} import histograms +import polar import EzTemplate import yxvsxfill import continents @@ -10,3 +11,5 @@ def createhistogram(name=None,source='default',x=None,template=None): return histograms.Ghg(name,source=source,x=x,template=template) def createusercontinents(name=None,source="default",x=None,template=None): return continents.Guc(name,source=source,x=x,template=template) +def createpolar(name=None, source="default", x=None, template=None): + return polar.Gpo(name, source=source, x=x, template=template) diff --git a/Packages/vcsaddons/Lib/core.py b/Packages/vcsaddons/Lib/core.py index d1b49bf11..0a75da125 100644 --- a/Packages/vcsaddons/Lib/core.py +++ b/Packages/vcsaddons/Lib/core.py @@ -54,9 +54,12 @@ class VCSaddon(object): self.legend = None self.projection='linear' else: - gm = vcsaddons.gms[self.g_type].get(source,None) - if gm is None: - raise "error could not find graphic method %s (of type %s)" % (source, self.g_type) + if isinstance(source, (str, unicode)): + gm = vcsaddons.gms[self.g_type].get(source,None) + if gm is None: + raise "error could not find graphic method %s (of type %s)" % (source, self.g_type) + else: + gm = source self.datawc_x1=gm.datawc_x1 self.datawc_x2=gm.datawc_x2 self.datawc_y1=gm.datawc_y1 diff --git a/Packages/vcsaddons/Lib/histograms.py b/Packages/vcsaddons/Lib/histograms.py index 452ac671e..0273529cd 100644 --- a/Packages/vcsaddons/Lib/histograms.py +++ b/Packages/vcsaddons/Lib/histograms.py @@ -21,7 +21,10 @@ class Ghg(VCSaddon): self.fillareacolors = [] self.bins = [] else: - gm = vcsaddons.gms[self.g_name][source] + if isinstance(source, (str, unicode)): + gm = vcsaddons.gms[self.g_type][source] + else: + gm = source self.line = gm.line self.linewidth = gm.linewidth self.linecolors = gm.linecolors @@ -31,16 +34,16 @@ class Ghg(VCSaddon): self.bins = gm.bins def list(self): - print '---------- Histogram (Ghg) member (attribute) listings ----------' - print 'Canvas Mode = ', self.x.mode - VCSaddon.list(self) - print 'fillareastyles = ', self.fillareastyles - print 'fillareaindices = ', self.fillareaindices - print 'fillareacolors = ', self.fillareacolors - print 'line = ', self.line - print 'linewidth = ', self.linewidth - print 'linecolors = ', self.linecolors - print 'bins = ', self.bins + print '---------- Histogram (Ghg) member (attribute) listings ----------' # pragma: no cover + print 'Canvas Mode = ', self.x.mode # pragma: no cover + VCSaddon.list(self) # pragma: no cover + print 'fillareastyles = ', self.fillareastyles # pragma: no cover + print 'fillareaindices = ', self.fillareaindices # pragma: no cover + print 'fillareacolors = ', self.fillareacolors # pragma: no cover + print 'line = ', self.line # pragma: no cover + print 'linewidth = ', self.linewidth # pragma: no cover + print 'linecolors = ', self.linecolors # pragma: no cover + print 'bins = ', self.bins # pragma: no cover def plot(self, data, template=None, bg=0, x=None, **kwargs): if x is None: @@ -49,8 +52,8 @@ class Ghg(VCSaddon): template = self.template elif isinstance(template, str): template = x.gettemplate(template) - elif not vcs.istemplate(template): - raise ValueError("Error did not know what to do with template: %s" % template) + elif not vcs.istemplate(template): # pragma: no cover + raise ValueError("Error did not know what to do with template: %s" % template) # pragma: no cover try: data_name = data.title except AttributeError: @@ -198,9 +201,9 @@ class Ghg(VCSaddon): break else: # Shouldn't ever get here since level 0 is 0 - assert False + assert False # pragma: no cover else: - assert False + assert False # pragma: no cover styles.append(self.fillareastyles[lev_ind]) cols.append(self.fillareacolors[lev_ind]) indices.append(self.fillareaindices[lev_ind]) @@ -235,11 +238,21 @@ class Ghg(VCSaddon): for d in dsp: if d is not None: displays.append(d) - - dsp = template.drawColorBar(self.fillareacolors, levels, legend={0: "No Variance", .1:"", .2: "", .3:"", .4:"", .5:"", .6:"", .7:"", .8:"", .9:"", 1: "High Variance"}, x=x) - for d in dsp: - if d is not None: - displays.append(d) + legend_labels = {0: "No Variance", + .1: "", + .2: "", + .3: "", + .4: "", + .5: "", + .6: "", + .7: "", + .8: "", + .9: "", + 1: "High Variance"} + template.drawColorBar(self.fillareacolors, levels, + legend=legend_labels, x=x, + style=self.fillareastyles, + index=self.fillareaindices) displays.append(x.plot(line, bg=bg)) diff --git a/Packages/vcsaddons/Lib/polar.py b/Packages/vcsaddons/Lib/polar.py new file mode 100644 index 000000000..27fb73882 --- /dev/null +++ b/Packages/vcsaddons/Lib/polar.py @@ -0,0 +1,395 @@ +import vcs +import numpy +import vcsaddons + +def circle_points(center, radius, points=75, ratio=1): + """ + Generates the coordinates of a circle in x list and y list. + """ + x = [] + y = [] + if ratio > 1: + ymul = ratio + xmul = 1 + else: + xmul = ratio + ymul = 1 + for i in range(points): + x.append(center[0] + xmul * radius * numpy.cos(float(i) / points * numpy.pi * 2)) + y.append(center[1] + ymul * radius * numpy.sin(float(i) / points * numpy.pi * 2)) + x.append(x[0]) + y.append(y[0]) + return x, y + + +def text_orientation_for_angle(theta, source="default"): + """ + Generates a text orientation that will align text to look good depending on quadrant. + """ + # Normalize to [0, 2*pi) + while 0 > theta: + theta += 2 * numpy.pi + while 2 * numpy.pi <= theta: + theta -= 2 * numpy.pi + + if 0 < theta < numpy.pi: + valign = "bottom" + elif 0 == theta or numpy.pi == theta: + valign = "half" + else: + valign = "top" + + if numpy.pi / 2 > theta or numpy.pi * 3 / 2 < theta: + halign = "left" + elif numpy.allclose(numpy.pi / 2, theta) or numpy.allclose(numpy.pi * 3 / 2, theta): + halign = "center" + else: + halign = "right" + + # Build new text table + to = vcs.createtextorientation(source=source) + to.valign = valign + to.halign = halign + return to + + +def convert_arrays(var, theta): + """ + Normalizes valid input options to two lists of lists of values and a list of names. + + Handles: + list/tuple of list/tuples/arrays + (X,N,2) array + (N,2) array + list/tuple, list/tuple + """ + magnitudes = [] + thetas = [] + names = [] + if theta is None: + # var must be list/tuple of arrays or an array + if isinstance(var, (list, tuple)): + for arr in var: + if isinstance(arr, numpy.ndarray): + if len(arr.shape) == 2 and arr.shape[1] == 2: + magnitudes.append(arr[..., 0].tolist()) + thetas.append(arr[..., 1].tolist()) + try: + names.append(arr.id) + except AttributeError: + names.append(None) + else: + raise ValueError("Array is wrong shape; expected 2d array of 2-long elements, got %dd array of %d-long elements." % (len(arr.shape), arr.shape[-1])) + else: + if len(arr) == 2: + # Might be just a pair + if not isinstance(arr[0], (list, tuple)): + magnitudes.append([arr[0]]) + thetas.append([arr[1]]) + names.append(None) + continue + mag_group = [] + theta_group = [] + for val in arr: + if len(val) != 2: + raise ValueError("List is wrong shape; expected list/tuple of 2 element list/tuples, got %s of %d elements." % (type(val).__name__, len(val))) + mag_group.append(val[0]) + theta_group.append(val[1]) + names.append(None) + magnitudes.append(mag_group) + thetas.append(theta_group) + else: + if len(var.shape) == 3: + for i in range(var.shape[0]): + magnitudes.append(var[i, ..., 0].tolist()) + thetas.append(var[i, ..., 1].tolist()) + try: + names.append(var[i].id) + except AttributeError: + names.append(None) + else: + magnitudes = [var[..., 0].tolist()] + thetas = [var[..., 1].tolist()] + try: + names.append(var.id) + except AttributeError: + names.append(None) + else: + magnitudes = [] + if isinstance(var, (list, tuple)): + if isinstance(var[0], (list, tuple, numpy.ndarray)): + magnitudes = [list(v) for v in var] + else: + magnitudes = [var] + elif isinstance(var, numpy.ndarray): + if len(var.shape) == 1: + magnitudes = [list(var)] + elif len(var.shape) == 2: + magnitudes = [list(var[i]) for i in range(var.shape[0])] + else: + raise ValueError("Array is wrong shape; expected 1d array or 2d array, got %dd array." % len(var.shape)) + + thetas = [] + if isinstance(theta, (list, tuple)): + if isinstance(theta[0], (list, tuple, numpy.ndarray)): + thetas = [list(v) for v in theta] + else: + thetas = [theta] + elif isinstance(theta, numpy.ndarray): + if len(theta.shape) == 1: + thetas = [list(theta)] + elif len(theta.shape) == 2: + thetas = [list(theta[i]) for i in range(theta.shape[0])] + else: + raise ValueError("Array is wrong shape; expected 1d array or 2d array, got %dd array." % len(var.shape)) + names = [None] * len(var) + return magnitudes, thetas, names + + +class Gpo(vcsaddons.core.VCSaddon): + def __init__(self, name=None, source="default", x=None, template=None): + self.g_name = "Gpo" + self.g_type = "polar_oned" + super(Gpo, self).__init__(name, source, x, template) + if source == "default": + self.markersizes = [3] + self.markercolors = ["black"] + self.markers = ["dot"] + self.clockwise = False + self.theta_offset = 0 + self.magnitude_ticks = "*" + self.magnitude_tick_angle = 0 + self.theta_tick_count = 6 + self.group_names = [] + # Nice default labels + self.xticlabels1 = { + 0: "0 (2pi)", + numpy.pi / 4: "pi/4", + numpy.pi / 2: "pi/2", + numpy.pi * 3 / 4.: "3pi/4", + numpy.pi: "pi", + numpy.pi * 5 / 4.: "5pi/4", + numpy.pi * 3 / 2.: "3pi/2", + numpy.pi * 7 / 4.: "7pi/4", + } + else: + if isinstance(source, (str, unicode)): + gm = vcsaddons.gms[self.g_type][source] + else: + gm = source + self.markersizes = gm.markersizes + self.markercolors = gm.markercolors + self.markers = gm.markers + self.clockwise = gm.clockwise + self.theta_offset = gm.theta_offset + self.magnitude_ticks = gm.magnitude_ticks + self.magnitude_tick_angle = gm.magnitude_tick_angle + self.theta_tick_count = gm.theta_tick_count + self.group_names = gm.group_names + + def theta_from_value(self, value): + if numpy.allclose((self.datawc_x1, self.datawc_x2), 1e20): + # No scale specified, just use the value as theta + return value + + minval = self.datawc_x1 + maxval = self.datawc_x2 + + pct_val = (value - minval) / float(maxval - minval) + rad_val = numpy.pi * 2 * pct_val + if self.clockwise: + # Reflect the value + rad_val *= -1 + # Adjust by theta_offset + rad_val += self.theta_offset + return rad_val + + def plot(self, var, theta=None, template=None, bg=0, x=None): + """ + Plots a polar plot of your data. + + If var is an ndarray with the second dimension being 2, it will use the first value + as magnitude and the second as theta. + + Otherwise, if theta is provided, it uses var as magnitude and the theta given. + """ + if x is None: + x = self.x + if template is None: + template = self.template + + magnitudes, thetas, names = convert_arrays(var, theta) + + if self.group_names: + names = self.group_names + while len(names) < len(magnitudes): + names.append(None) + + flat_magnitude = [] + for i in magnitudes: + flat_magnitude.extend(i) + flat_theta = [] + for i in thetas: + flat_theta.extend(i) + + canvas = x + + # Determine aspect ratio for plotting the circle + canvas_info = canvas.canvasinfo() + # Calculate aspect ratio of window + window_aspect = canvas_info["width"] / float(canvas_info["height"]) + if window_aspect > 1: + ymul = window_aspect + xmul = 1 + else: + ymul = 1 + xmul = window_aspect + # Use window_aspect to adjust size of template.data + x0, x1 = template.data.x1, template.data.x2 + y0, y1 = template.data.y1, template.data.y2 + + xdiff = abs(x1 - x0) + ydiff = abs(y1 - y0) + + center = x0 + xdiff / 2., y0 + ydiff / 2. + diameter = min(xdiff, ydiff) + radius = diameter / 2. + + # Outer line + if template.box1.priority > 0: + outer = vcs.createline(source=template.box1.line) + x, y = circle_points(center, radius, ratio=window_aspect) + outer.x = x + outer.y = y + canvas.plot(outer, render=False, bg=bg) + + if numpy.allclose((self.datawc_y1, self.datawc_y2), 1e20): + if self.magnitude_ticks == "*": + m_scale = vcs.mkscale(*vcs.minmax(flat_magnitude)) + else: + if isinstance(self.magnitude_ticks, (str, unicode)): + ticks = vcs.elements["list"][self.magnitude_ticks] + else: + ticks = self.magnitude_ticks + m_scale = ticks + else: + m_scale = vcs.mkscale(self.datawc_y1, self.datawc_y2) + + if template.ytic1.priority > 0: + m_ticks = vcs.createline(source=template.ytic1.line) + m_ticks.x = [] + m_ticks.y = [] + + if template.ylabel1.priority > 0: + to = text_orientation_for_angle(self.magnitude_tick_angle, source=template.ylabel1.textorientation) + m_labels = vcs.createtext(Tt_source=template.ylabel1.texttable, To_source=to) + m_labels.x = [] + m_labels.y = [] + m_labels.string = [] + if self.yticlabels1 == "*": + mag_labels = vcs.mklabels(m_scale) + else: + mag_labels = self.yticlabels1 + else: + m_labels = None + + for lev in m_scale: + lev_radius = radius * float(lev) / m_scale[-1] + x, y = circle_points(center, lev_radius, ratio=window_aspect) + if m_labels is not None: + if lev in mag_labels: + m_labels.string.append(mag_labels[lev]) + m_labels.x.append(xmul * lev_radius * numpy.cos(self.magnitude_tick_angle) + center[0]) + m_labels.y.append(ymul * lev_radius * numpy.sin(self.magnitude_tick_angle) + center[1]) + m_ticks.x.append(x) + m_ticks.y.append(y) + + canvas.plot(m_ticks, render=False, bg=bg) + if m_labels is not None: + canvas.plot(m_labels, render=False, bg=bg) + + if template.xtic1.priority > 0: + t_ticks = vcs.createline(source=template.xtic1.line) + t_ticks.x = [] + t_ticks.y = [] + + if self.xticlabels1 == "*": + if numpy.allclose((self.datawc_x1, self.datawc_x2), 1e20): + tick_thetas = list(numpy.arange(0, numpy.pi * 2, numpy.pi / 4)) + tick_labels = {t: str(t) for t in tick_thetas} + else: + d_theta = (self.datawc_x2 - self.datawc_x1) / float(self.theta_tick_count) + tick_thetas = numpy.arange(self.datawc_x1, self.datawc_x2 + .0001, d_theta) + tick_labels = vcs.mklabels(tick_thetas) + else: + tick_thetas = self.xticlabels1.keys() + tick_labels = self.xticlabels1 + + if template.xlabel1.priority > 0: + t_labels = [] + if self.xticlabels1 == "*": + theta_labels = vcs.mklabels(tick_thetas) + else: + theta_labels = self.xticlabels1 + else: + t_labels = None + + for t in tick_thetas: + angle = self.theta_from_value(t) + x0 = center[0] + (xmul * radius * numpy.cos(angle)) + x1 = center[0] + y0 = center[1] + (ymul * radius * numpy.sin(angle)) + y1 = center[1] + if t_labels is not None: + label = vcs.createtext(Tt_source=template.xlabel1.texttable, + To_source=text_orientation_for_angle(angle, source=template.xlabel1.textorientation)) + label.string = [theta_labels[t]] + label.x = [x0] + label.y = [y0] + t_labels.append(label) + t_ticks.x.append([x0, x1]) + t_ticks.y.append([y0, y1]) + canvas.plot(t_ticks, render=False, bg=bg) + if t_labels is not None: + for l in t_labels: + canvas.plot(l, render=False, bg=bg) + + values = vcs.createmarker() + values.type = self.markers + values.size = self.markersizes + values.color = self.markercolors + values.x = [] + values.y = [] + + if template.legend.priority > 0: + # Only labels that are set will show up in the legend + label_count = len(names) - len([i for i in names if i is None]) + labels = vcs.createtext(Tt_source=template.legend.texttable, To_source=template.legend.textorientation) + labels.x = [] + labels.y = [] + labels.string = [] + + for mag, theta, name in zip(magnitudes, thetas, names): + x = [] + y = [] + for m, t in zip(mag, theta): + t = self.theta_from_value(t) + r = (m - m_scale[0]) / float(m_scale[-1] - m_scale[0]) * radius + x.append(xmul * numpy.cos(t) * r + center[0]) + y.append(ymul * numpy.sin(t) * r + center[1]) + + if template.legend.priority > 0 and name is not None: + lx, ly = template.legend.x1, template.legend.y1 + len(labels.x) / float(label_count) * (template.legend.y2 - template.legend.y1) + x.append(lx) + y.append(ly) + labels.x.append(lx + .01) + labels.y.append(ly) + labels.string.append(name) + values.x.append(x) + values.y.append(y) + + if template.legend.priority > 0: + canvas.plot(labels, bg=bg, render=False) + canvas.plot(values, bg=bg) + + return canvas diff --git a/testing/vcsaddons/CMakeLists.txt b/testing/vcsaddons/CMakeLists.txt index 64b8d1755..06ebff600 100644 --- a/testing/vcsaddons/CMakeLists.txt +++ b/testing/vcsaddons/CMakeLists.txt @@ -35,6 +35,30 @@ cdat_add_test(vcs_addons_test_EzTemplate_12_plots_spacing ${cdat_SOURCE_DIR}/testing/vcsaddons/test_EzTemplate_12_plots_spacing.py ${BASELINE_DIR}/test_EzTemplate_12_plots_spacing.png ) +cdat_add_test(vcs_addons_test_histogram_defaults + "${PYTHON_EXECUTABLE}" + ${cdat_SOURCE_DIR}/testing/vcsaddons/vcs_addons_test_histogram_defaults.py + ${BASELINE_DIR}/vcs_addons_test_histogram_defaults.png +) +cdat_add_test(vcs_addons_test_histogram_inherit + "${PYTHON_EXECUTABLE}" + ${cdat_SOURCE_DIR}/testing/vcsaddons/vcs_addons_test_histogram_inherit.py + ${BASELINE_DIR}/vcs_addons_test_histogram_inherit.png +) +cdat_add_test(vcs_addons_test_polar + "${PYTHON_EXECUTABLE}" + ${cdat_SOURCE_DIR}/testing/vcsaddons/vcs_addons_test_polar.py + ${BASELINE_DIR}/vcs_addons_test_polar.png +) +cdat_add_test(vcs_addons_test_polar_inherit + "${PYTHON_EXECUTABLE}" + ${cdat_SOURCE_DIR}/testing/vcsaddons/vcs_addons_test_polar_inherit.py + ${BASELINE_DIR}/vcs_addons_test_polar_inherit.png +) +cdat_add_test(vcs_addons_test_convert_arrays + "${PYTHON_EXECUTABLE}" + ${cdat_SOURCE_DIR}/testing/vcsaddons/vcs_addons_test_convert_arrays.py +) if (CDAT_DOWNLOAD_SAMPLE_DATA) cdat_add_test(vcs_addons_EzTemplate_2x2 diff --git a/testing/vcsaddons/vcs_addons_test_convert_arrays.py b/testing/vcsaddons/vcs_addons_test_convert_arrays.py new file mode 100644 index 000000000..c39bea513 --- /dev/null +++ b/testing/vcsaddons/vcs_addons_test_convert_arrays.py @@ -0,0 +1,69 @@ +import vcsaddons +import numpy + +magnitudes = [1, 2, 3, 4] +thetas = [5, 6, 7, 8] +zipped_input = zip(magnitudes, thetas) +grouped_zipped = [zipped_input[:2], zipped_input[2:]] + +one_array = numpy.array(zip(magnitudes, thetas)) +three_d_array = numpy.array(grouped_zipped) +two_arrays = numpy.array(magnitudes), numpy.array(thetas) +two_array_groups = numpy.array([magnitudes[:2], magnitudes[2:]]), numpy.array([thetas[:2], thetas[2:]]) +list_and_array = two_arrays[0], thetas +two_lists = magnitudes, thetas +lists_of_arrays = [two_arrays[0]], [two_arrays[1]] +array_and_list = magnitudes, two_arrays[1] +one_list_tuples = zip(magnitudes, thetas) +one_list_grouped_tuples = [zip(magnitudes[:2], thetas[:2]), zip(magnitudes[2:], thetas[2:])] +one_list_of_arrays = [numpy.array(zip(magnitudes[:2], thetas[:2])), numpy.array(zip(magnitudes[2:], thetas[2:]))] + +def compare(input, expected): + result = vcsaddons.polar.convert_arrays(*input) + print "Checking", result[0:2], "vs", expected + assert result[0] == expected[0] + assert result[1] == expected[1] + +grouped = ([magnitudes[:2], magnitudes[2:]],[thetas[:2], thetas[2:]]) + +compare((one_array, None), ([magnitudes],[thetas])) +compare(two_arrays, ([magnitudes],[thetas])) +compare(two_array_groups, grouped) +three_d_expected = ([[1, 2], [3, 4]], [[5, 6], [7, 8]]) +compare((three_d_array, None), three_d_expected) +compare(list_and_array, ([magnitudes],[thetas])) +compare(two_lists, ([magnitudes],[thetas])) +compare(lists_of_arrays, ([magnitudes],[thetas])) +compare(array_and_list, ([magnitudes],[thetas])) +compare((one_list_tuples, None), ([[i] for i in magnitudes], [[i] for i in thetas])) +compare((one_list_grouped_tuples, None), grouped) +compare((one_list_of_arrays, None), grouped) + + +def test_error(input, error): + try: + vcsaddons.polar.convert_arrays(*input) + except: + print "Got", error + else: + assert False, "Should have raised a %s" % error + +# Test error conditions + +# Single arg: + +# List of 3d arrays +test_error(([numpy.array([[[1, 2]]])], None), "ValueError for list of 3d arrays") +# >2 element arrays +test_error(([numpy.array([[1, 2, 3]])], None), "ValueError for list of 3-element arrays") +# <2 element arrays +test_error(([numpy.array([[1]])], None), "ValueError for list of 1-element arrays") +# Wrong-sized lists +test_error(([[(1, 2, 3)]], None), "ValueError for wrong sized lists.") + + +# Two args: + +# Too many dimensions +test_error((numpy.array([[[1, 2]]]), numpy.array([[1, 2]])), "ValueError for too many dimensions for magnitude.") +test_error((numpy.array([[1, 2]]), numpy.array([[[1, 2]]])), "ValueError for too many dimensions for magnitude.") diff --git a/testing/vcsaddons/vcs_addons_test_histogram_defaults.py b/testing/vcsaddons/vcs_addons_test_histogram_defaults.py new file mode 100644 index 000000000..b2b19e499 --- /dev/null +++ b/testing/vcsaddons/vcs_addons_test_histogram_defaults.py @@ -0,0 +1,22 @@ +import sys,os +src = sys.argv[1] +pth = os.path.join(os.path.dirname(__file__),"..") +sys.path.append(pth) +import checkimage +import vcs +import vcsaddons, numpy + +x=vcs.init() +x.setantialiasing(0) +x.drawlogooff() +x.setbgoutputdimensions(1200,1091,units="pixels") + +numpy.random.seed(seed=12345) +vals = numpy.random.random_sample(2000) * 100 +histo = vcsaddons.histograms.Ghg() +histo.plot(vals, bg=True, x=x) + +fnm = "vcs_addons_test_histogram_defaults.png" +x.png(fnm) +ret = checkimage.check_result_image(fnm, src, checkimage.defaultThreshold) +sys.exit(ret) diff --git a/testing/vcsaddons/vcs_addons_test_histogram_inherit.py b/testing/vcsaddons/vcs_addons_test_histogram_inherit.py new file mode 100644 index 000000000..8ce19e0c2 --- /dev/null +++ b/testing/vcsaddons/vcs_addons_test_histogram_inherit.py @@ -0,0 +1,62 @@ +import sys,os +src = sys.argv[1] +pth = os.path.join(os.path.dirname(__file__),"..") +sys.path.append(pth) +import checkimage +import vcs, cdms2 +import vcsaddons, numpy + +x=vcs.init() +x.setantialiasing(0) +x.drawlogooff() +x.setbgoutputdimensions(1200,1091,units="pixels") +cdmsfile = cdms2.open(vcs.sample_data + "/clt.nc") +clt = cdmsfile("clt") + +levels = [10, 20, 30, 40, 60, 70, 80, 90, 100] +histo = vcsaddons.histograms.Ghg() +histo.bins = levels +histo.line = ["solid", "dash", "dash-dot"] +histo.linewidth = [1, 2, 3] +histo.linecolors = ["red", "green", "blue"] +histo.fillareastyles = ["solid", "hatch", "pattern", "solid"] +histo.fillareaindices = [1, 2, 3, 4] +histo.fillareacolors = ["blue", "green", "red", "orange"] + +histo2 = vcsaddons.createhistogram(source=histo) + +print "Checking all inherited attributes..." +assert histo2.bins == histo.bins +assert histo2.line == histo.line +assert histo2.linewidth == histo.linewidth +assert histo2.linecolors == histo.linecolors +assert histo2.fillareastyles == histo.fillareastyles +assert histo2.fillareacolors == histo.fillareacolors +assert histo2.fillareaindices == histo.fillareaindices +print "Inherited all values." + +histo2.levels = [10, 20, 10, 100, 110, 50, 20] +histo3 = vcsaddons.createhistogram(source=histo2.name, x=x) + +print "Checking name-based inheritance" +assert histo3.bins == histo2.bins +assert histo3.line == histo2.line +assert histo3.linewidth == histo2.linewidth +assert histo3.linecolors == histo2.linecolors +assert histo3.fillareastyles == histo2.fillareastyles +assert histo3.fillareacolors == histo2.fillareacolors +assert histo3.fillareaindices == histo2.fillareaindices +print "Inherited all values." + +histo3.datawc_y1 = -1 +histo3.datawc_y2 = 200000 +histo3.datawc_x1 = 0 +histo3.datawc_x2 = 100 + +histo3.bins = None +histo3.plot(clt, template="default", bg=True) + +fnm = "vcs_addons_test_histogram_inherit.png" +x.png(fnm) +ret = checkimage.check_result_image(fnm, src, checkimage.defaultThreshold) +sys.exit(ret) diff --git a/testing/vcsaddons/vcs_addons_test_polar.py b/testing/vcsaddons/vcs_addons_test_polar.py new file mode 100644 index 000000000..8a848e7a1 --- /dev/null +++ b/testing/vcsaddons/vcs_addons_test_polar.py @@ -0,0 +1,28 @@ +import sys,os +src = sys.argv[1] +pth = os.path.join(os.path.dirname(__file__),"..") +sys.path.append(pth) +import checkimage +import vcs +import vcsaddons, numpy + +x=vcs.init() +x.setantialiasing(0) +x.drawlogooff() +x.setbgoutputdimensions(1200,1091,units="pixels") + +polar = vcsaddons.polar.Gpo() +polar.markers = ["dot", "circle"] +polar.markersizes = [3, 5] + +polar.magnitude_tick_angle = numpy.pi / 6 + +theta = list(numpy.arange(0, 4 * numpy.pi + .01, numpy.pi / 24)) +magnitude = list(numpy.sin(theta)) + +polar.plot(magnitude, theta, bg=True, x=x) + +fnm = "vcs_addons_test_polar.png" +x.png(fnm) +ret = checkimage.check_result_image(fnm, src, checkimage.defaultThreshold) +sys.exit(ret) diff --git a/testing/vcsaddons/vcs_addons_test_polar_inherit.py b/testing/vcsaddons/vcs_addons_test_polar_inherit.py new file mode 100644 index 000000000..4eb946359 --- /dev/null +++ b/testing/vcsaddons/vcs_addons_test_polar_inherit.py @@ -0,0 +1,50 @@ +import sys,os +src = sys.argv[1] +pth = os.path.join(os.path.dirname(__file__),"..") +sys.path.append(pth) +import checkimage +import vcs +import vcsaddons, numpy + +x=vcs.init() +x.setantialiasing(0) +x.drawlogooff() +x.setbgoutputdimensions(1200,1091,units="pixels") + +gm = vcsaddons.polar.Gpo() +gm.markers = ["dot", "circle"] +gm.markersizes = [3, 5] +gm.markercolors = ["red", "blue"] +gm.clockwise = True +gm.theta_offset = numpy.pi / 4 +gm.magnitude_ticks = [.2 * i for i in range(6)] +gm.magnitude_tick_angle = numpy.pi / 10 +gm.theta_tick_count = 10 +gm.group_names = ["First", "Second"] + +polar = vcsaddons.polar.Gpo(source=gm) + +assert polar.markersizes == gm.markersizes +assert polar.markercolors == gm.markercolors +assert polar.markers == gm.markers +assert polar.clockwise == gm.clockwise +assert polar.theta_offset == gm.theta_offset +assert polar.magnitude_ticks == gm.magnitude_ticks +assert polar.magnitude_tick_angle == gm.magnitude_tick_angle +assert polar.theta_tick_count == gm.theta_tick_count +assert polar.group_names == gm.group_names + +polar.magnitude_tick_angle = numpy.pi / 6 + +theta = list(numpy.arange(0, 4 * numpy.pi + .01, numpy.pi / 24)) +magnitude = list(numpy.sin(theta)) + +theta = [theta[:len(theta) / 2], theta[len(theta) / 2:]] +magnitude = [magnitude[:len(magnitude)/ 2], magnitude[len(magnitude) / 2:]] + +polar.plot(magnitude, theta, bg=True, x=x) + +fnm = "vcs_addons_test_polar_inherit.png" +x.png(fnm) +ret = checkimage.check_result_image(fnm, src, checkimage.defaultThreshold) +sys.exit(ret) -- GitLab From 2dbbdec142265dc8199f3d990201ad660c551392 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Tue, 17 May 2016 16:34:12 -0400 Subject: [PATCH 064/191] Fixed vtk ui tests --- testing/vcs/vtk_ui/vtk_ui_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/vcs/vtk_ui/vtk_ui_test.py b/testing/vcs/vtk_ui/vtk_ui_test.py index 40bbeaef1..d5cbe18bf 100644 --- a/testing/vcs/vtk_ui/vtk_ui_test.py +++ b/testing/vcs/vtk_ui/vtk_ui_test.py @@ -1,4 +1,4 @@ -import, os, sys, time, vcs.vtk_ui, vtk +import os, sys, time, vtk, vcs.vtk_ui def init(): @@ -102,7 +102,7 @@ class vtk_ui_test(object): generate_png(self.win, self.test_file) pth = os.path.join(os.path.dirname(__file__), "../..") sys.path.append(pth) - import regression + import testing.regression as regression return regression.check_result_image(self.test_file, compare_against) def test(self): -- GitLab From 29d182bd5442ea6b71f95f9856d6ec9a9983a6ac Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Wed, 18 May 2016 07:31:37 -0400 Subject: [PATCH 065/191] Updated test name to match the naming convention --- testing/vcs/test_vcs_boxfill_lev1_lev2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/vcs/test_vcs_boxfill_lev1_lev2.py b/testing/vcs/test_vcs_boxfill_lev1_lev2.py index c5b5cbcbe..6c1d985d7 100644 --- a/testing/vcs/test_vcs_boxfill_lev1_lev2.py +++ b/testing/vcs/test_vcs_boxfill_lev1_lev2.py @@ -7,4 +7,4 @@ b = x.createboxfill() b.level_1 = .5 b.level_2 = 14.5 x.plot(s, b, bg=1) -regression.run(x, "test_boxfill_lev1_lev2.png") +regression.run(x, "test_vcs_boxfill_lev1_lev2.png") -- GitLab From 88df13b95b1a5000db8d5e58c9c3152865dc5baa Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Wed, 18 May 2016 09:57:38 -0400 Subject: [PATCH 066/191] Updated dv3d package to use regression module --- testing/dv3d/TestManager.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/dv3d/TestManager.py b/testing/dv3d/TestManager.py index 51ed57183..94e7e365e 100644 --- a/testing/dv3d/TestManager.py +++ b/testing/dv3d/TestManager.py @@ -10,7 +10,7 @@ import vcs, os, sys, shutil, collections, subprocess TestingDir=os.path.dirname(__file__) pth = os.path.join(TestingDir,"..") sys.path.append(pth) -import checkimage +import testing.regression as regression DefaultSampleFile = "geos5-sample.nc" DefaultSampleVar = "uwnd" @@ -128,8 +128,8 @@ class vcsTest: test_image = '.'.join( [ self.name, 'test', 'png' ] ) self.canvas.png( test_image, width = 900, height = 600 ) - ret = checkimage.check_result_image( test_image, self.image_name,\ - checkimage.defaultThreshold+3. ) + ret = regression.check_result_image( test_image, self.image_name,\ + regression.defaultThreshold+3. ) if interactive: print "Type to continue and update ref image ( type 'n' to skip update )." -- GitLab From 9e86fb3b9be60ea6e08558034a56c2a22bc2c9db Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Wed, 18 May 2016 09:59:10 -0400 Subject: [PATCH 067/191] Fixed flake8 test --- Packages/vcs/vcs/Canvas.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Packages/vcs/vcs/Canvas.py b/Packages/vcs/vcs/Canvas.py index 49fdbf978..0e9d23426 100644 --- a/Packages/vcs/vcs/Canvas.py +++ b/Packages/vcs/vcs/Canvas.py @@ -76,6 +76,7 @@ from projection import round_projections # noqa # Python < 3 DeprecationWarning ignored by default warnings.simplefilter('default') + class SIGNAL(object): def __init__(self, name=None): -- GitLab From dc508774b3b0d886a7908213c73f8ac21b64a55d Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Wed, 18 May 2016 10:01:36 -0400 Subject: [PATCH 068/191] Updated esmf test to use regression module --- .../regrid/testEsmfRegridPeriodictyRegional.py | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/testing/regrid/testEsmfRegridPeriodictyRegional.py b/testing/regrid/testEsmfRegridPeriodictyRegional.py index 2b9279525..53a1a706b 100644 --- a/testing/regrid/testEsmfRegridPeriodictyRegional.py +++ b/testing/regrid/testEsmfRegridPeriodictyRegional.py @@ -1,9 +1,4 @@ -import vcs,cdms2 -import os,sys -import EzTemplate -pth = os.path.join(os.path.dirname(__file__),"..") -sys.path.append(pth) -import checkimage +import os, sys, vcs, cdms2, EzTemplate, testing.regression as regression data = sys.argv[1] png = sys.argv[2] @@ -38,11 +33,7 @@ s_esmf_lin.id = "ESMF Linear" s_esmf_con = s.regrid(grid_dest,regridTool="esmf",regridMethod="conservative") s_esmf_lin.id = "ESMF Conservative" -x=vcs.init() -x.setantialiasing(0) -x.drawlogooff() -x.setbgoutputdimensions(1200,1091,units="pixels") - +x=regression.init() t=x.createtemplate() t.blank() t.data.priority=1 @@ -60,7 +51,5 @@ x.plot(s,M.get(),gm,bg=1) x.plot(s_regrid2,M.get(),gm,bg=1) x.plot(s_esmf_lin,M.get(),gm,bg=1) x.plot(s_esmf_con,M.get(),gm,bg=1) -x.png("esmf_issue_1125") -ret = checkimage.check_result_image("esmf_issue_1125.png",png,checkimage.defaultThreshold) -sys.exit(ret) +ret = regression.run(x, "esmf_issue_1125.png", png) -- GitLab From 395c7459b2a3915c0c7a6eb4f37561ad9af972b8 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Wed, 18 May 2016 10:10:53 -0400 Subject: [PATCH 069/191] Updated diagnostics tests to use regression module --- testing/metrics/diags_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/metrics/diags_test.py b/testing/metrics/diags_test.py index ff71c8d66..2d4131cb8 100755 --- a/testing/metrics/diags_test.py +++ b/testing/metrics/diags_test.py @@ -12,7 +12,7 @@ import sys, os, shutil, tempfile, subprocess import cdms2, numpy pth = os.path.join(os.path.dirname(__file__),"..") sys.path.append(pth) -import checkimage +import testing.regression as regression import argparse, pdb class DiagTest(object): @@ -95,7 +95,7 @@ class DiagTest(object): def execute(self, test_str, imagefilename, imagethreshold, ncfiles, rtol, atol): print test_str if imagethreshold is None: # user didn't specify a value - imagethreshold = checkimage.defaultThreshold + imagethreshold = regression.defaultThreshold # Silence annoying messages about how to set the NetCDF file type. Anything will do. cdms2.setNetcdfShuffleFlag(0) cdms2.setNetcdfDeflateFlag(0) @@ -118,7 +118,7 @@ class DiagTest(object): imagebaselinefname = os.path.join( self.baselinepath, imagefilename ) #pdb.set_trace() print "OK THRESHOLD IS:",imagethreshold - graphics_result = checkimage.check_result_image( imagefname, imagebaselinefname, imagethreshold ) + graphics_result = regression.check_result_image( imagefname, imagebaselinefname, imagethreshold ) print "Graphics file", imagefname, "match difference:", graphics_result #initialize to successful graphics check -- GitLab From 314fc2bf70fb9c410ba7c1200a1fcaec9dfbfdd5 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Wed, 18 May 2016 11:53:42 -0400 Subject: [PATCH 070/191] Fixed numpy test --- testing/vcs/test_vcs_boxfill_10x10_numpy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/vcs/test_vcs_boxfill_10x10_numpy.py b/testing/vcs/test_vcs_boxfill_10x10_numpy.py index a45aa5889..765917942 100644 --- a/testing/vcs/test_vcs_boxfill_10x10_numpy.py +++ b/testing/vcs/test_vcs_boxfill_10x10_numpy.py @@ -3,5 +3,5 @@ import vcs, numpy, os, sys, testing.regression as regression s = numpy.sin(numpy.arange(100)) s = numpy.reshape(s,(10,10)) x = regression.init() -x.plot(s) +x.plot(s, bg=1) regression.run(x, "test_vcs_boxfill_10x10_numpy.png") \ No newline at end of file -- GitLab From f19b372e0ccc187eef150f1ce7af83a56021616b Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Wed, 18 May 2016 11:59:38 -0400 Subject: [PATCH 071/191] Fixed canvas update test --- testing/vcs/test_vcs_boxfill_decreasing_latitude.py | 2 +- testing/vcs/test_vcs_canvas_background_update.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/vcs/test_vcs_boxfill_decreasing_latitude.py b/testing/vcs/test_vcs_boxfill_decreasing_latitude.py index 1f727e3b5..6cbc0f016 100755 --- a/testing/vcs/test_vcs_boxfill_decreasing_latitude.py +++ b/testing/vcs/test_vcs_boxfill_decreasing_latitude.py @@ -51,5 +51,5 @@ gm.fillareacolors = cols gm.datawc_y2 = 30 gm.datawc_y1 = 90 -x.plot(ice, gm, tmpl, bg = 1) +x.plot(ice, gm, tmpl, bg=1) regression.run(x, "test_boxfill_decreasing_latitude.png") \ No newline at end of file diff --git a/testing/vcs/test_vcs_canvas_background_update.py b/testing/vcs/test_vcs_canvas_background_update.py index a28c08713..80f79d2aa 100644 --- a/testing/vcs/test_vcs_canvas_background_update.py +++ b/testing/vcs/test_vcs_canvas_background_update.py @@ -5,4 +5,4 @@ x.backgroundcolor = (255, 255, 255) x.open() x.backgroundcolor = (255, 255, 0) x.update() -regression.run(x, "test_backgroundcolor_yellow.png") \ No newline at end of file +regression.check_result_image(x, "test_backgroundcolor_yellow.png") \ No newline at end of file -- GitLab From a14200869100199487b89ea08dd37ad2b7d97731 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Wed, 18 May 2016 16:06:31 -0400 Subject: [PATCH 072/191] Using a fixed size for click test --- Packages/testing/regression.py | 8 +++++--- testing/vcs/test_vcs_click_info.py | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Packages/testing/regression.py b/Packages/testing/regression.py index b272d592f..68ded76d9 100644 --- a/Packages/testing/regression.py +++ b/Packages/testing/regression.py @@ -16,14 +16,16 @@ import vcs defaultThreshold=10.0 -def init(): +def init(*args, **kwargs): testingDir = os.path.join(os.path.dirname(__file__), "..") sys.path.append(testingDir) - vcsinst = vcs.init() + vcsinst = vcs.init(*args, **kwargs) vcsinst.setantialiasing(0) vcsinst.drawlogooff() - vcsinst.setbgoutputdimensions(1200,1091,units="pixels") + + if ('bg' in kwargs and kwargs['bg']) or ('bg' not in kwargs): + vcsinst.setbgoutputdimensions(1200, 1091, units="pixels") return vcsinst def run(vcsinst, fname, baseline=sys.argv[1], threshold=defaultThreshold): diff --git a/testing/vcs/test_vcs_click_info.py b/testing/vcs/test_vcs_click_info.py index c16a6c0d4..f37ee651a 100644 --- a/testing/vcs/test_vcs_click_info.py +++ b/testing/vcs/test_vcs_click_info.py @@ -8,7 +8,7 @@ testConfig = {'a_boxfill': ('clt.nc', 'clt', (200, 200)), # Tests if the info produced when clicking on a map is correct. src = sys.argv[1] plot = sys.argv[2] -x = regression.init() +x = regression.init(bg=False, geometry=(800, 600)) # data f = cdms2.open(vcs.sample_data + "/" + testConfig[plot][0]) -- GitLab From 9c121a20f2121a0fcca665123d50b27553f176a0 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Wed, 18 May 2016 21:19:46 -0400 Subject: [PATCH 073/191] Fixed failing test because of incorrect capture window size --- testing/vcs/test_vcs_configurator_resize.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/testing/vcs/test_vcs_configurator_resize.py b/testing/vcs/test_vcs_configurator_resize.py index 7692e6218..bd3490afb 100644 --- a/testing/vcs/test_vcs_configurator_resize.py +++ b/testing/vcs/test_vcs_configurator_resize.py @@ -4,15 +4,16 @@ x = vcs.init() x.open() x.configure() -x.backend.renWin.SetSize(814, 303) - fnm = "test_vcs_configurator_resize.png" win = x.backend.renWin -win.Render() +win.SetSize(814, 303) + out_filter = vtk.vtkWindowToImageFilter() out_filter.SetInput(win) +win.Render() + png_writer = vtk.vtkPNGWriter() png_writer.SetFileName(fnm) png_writer.SetInputConnection(out_filter.GetOutputPort()) -- GitLab From 2c3407c4a791c301930ea1c634918f16a163d148 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Wed, 18 May 2016 21:38:46 -0400 Subject: [PATCH 074/191] Set size on render window only if it has been created --- Packages/vcs/vcs/VTKPlots.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Packages/vcs/vcs/VTKPlots.py b/Packages/vcs/vcs/VTKPlots.py index 8cfe83a28..da5810614 100644 --- a/Packages/vcs/vcs/VTKPlots.py +++ b/Packages/vcs/vcs/VTKPlots.py @@ -73,7 +73,7 @@ class VTKVCSBackend(object): # Initially set to 16x Multi-Sampled Anti-Aliasing self.antialiasing = 8 self._rasterPropsInVectorFormats = False - self._initialGeometry = geometry + self._geometry = geometry if renWin is not None: self.renWin = renWin @@ -383,9 +383,9 @@ class VTKVCSBackend(object): # turning off antialiasing by default # mostly so that pngs are same accross platforms self.renWin.SetMultiSamples(self.antialiasing) - if self._initialGeometry is not None: - width = self._initialGeometry["width"] - height = self._initialGeometry["height"] + if self._geometry is not None: + width = self._geometry["width"] + height = self._geometry["height"] else: width = None height = None @@ -444,9 +444,9 @@ class VTKVCSBackend(object): if (self.bg): height = self.canvas.bgY width = self.canvas.bgX - elif (self._initialGeometry): - height = self._initialGeometry['height'] - width = self._initialGeometry['width'] + elif (self._geometry): + height = self._geometry['height'] + width = self._geometry['width'] else: height = self.canvas.bgY width = self.canvas.bgX @@ -554,7 +554,9 @@ class VTKVCSBackend(object): return True def geometry(self, x, y, *args): - self.renWin.SetSize(x, y) + if self.renWin is not None: + self.renWin.SetSize(x, y) + self._geometry = {'width': x, 'height': y} self._lastSize = (x, y) def flush(self): -- GitLab From a36eba425fa8451c4628957e6af434f010736398 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Wed, 18 May 2016 21:48:57 -0400 Subject: [PATCH 075/191] Return geometry object if no argument is given --- Packages/vcs/vcs/Canvas.py | 3 +++ Packages/vcs/vcs/VTKPlots.py | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Packages/vcs/vcs/Canvas.py b/Packages/vcs/vcs/Canvas.py index 0e9d23426..49361248c 100644 --- a/Packages/vcs/vcs/Canvas.py +++ b/Packages/vcs/vcs/Canvas.py @@ -4116,6 +4116,9 @@ Options::: a.geometry(450,337) """ + if len(args) == 0: + return self.backend.geometry() + if (args[0] <= 0) or (args[1] <= 0): raise ValueError( 'Error - The width and height values must be an integer greater than 0.') diff --git a/Packages/vcs/vcs/VTKPlots.py b/Packages/vcs/vcs/VTKPlots.py index da5810614..7e32798d1 100644 --- a/Packages/vcs/vcs/VTKPlots.py +++ b/Packages/vcs/vcs/VTKPlots.py @@ -553,7 +553,15 @@ class VTKVCSBackend(object): else: return True - def geometry(self, x, y, *args): + def geometry(self, *args): + if len(args) == 0: + return self._geometry; + if len(args) < 2: + raise TypeError("Function takes zero or two " \ + "or more than two arguments. Got " + len(*args)) + x = args[0] + y = args[1] + if self.renWin is not None: self.renWin.SetSize(x, y) self._geometry = {'width': x, 'height': y} -- GitLab From a5bc559a3c3e56daafe0a210071ef25a1c87005b Mon Sep 17 00:00:00 2001 From: Sam Fries Date: Thu, 19 May 2016 13:18:50 -0700 Subject: [PATCH 076/191] Fixed some group name retrieval bugs, added colormap support, better secondary management --- Packages/vcsaddons/Lib/polar.py | 57 +++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/Packages/vcsaddons/Lib/polar.py b/Packages/vcsaddons/Lib/polar.py index 27fb73882..8aff589a7 100644 --- a/Packages/vcsaddons/Lib/polar.py +++ b/Packages/vcsaddons/Lib/polar.py @@ -118,14 +118,29 @@ def convert_arrays(var, theta): magnitudes = [] if isinstance(var, (list, tuple)): if isinstance(var[0], (list, tuple, numpy.ndarray)): - magnitudes = [list(v) for v in var] + for v in var: + magnitudes.append(list(v)) + try: + names.append(v.id) + except AttributeError: + names.append(None) else: magnitudes = [var] + names.appned(None) elif isinstance(var, numpy.ndarray): if len(var.shape) == 1: magnitudes = [list(var)] + try: + names.append(var.id) + except AttributeError: + names.append(None) elif len(var.shape) == 2: - magnitudes = [list(var[i]) for i in range(var.shape[0])] + for i in range(var.shape[0]): + magnitudes.append(list(var[i])) + try: + names.append(var[i].id) + except AttributeError: + names.append(None) else: raise ValueError("Array is wrong shape; expected 1d array or 2d array, got %dd array." % len(var.shape)) @@ -142,7 +157,8 @@ def convert_arrays(var, theta): thetas = [list(theta[i]) for i in range(theta.shape[0])] else: raise ValueError("Array is wrong shape; expected 1d array or 2d array, got %dd array." % len(var.shape)) - names = [None] * len(var) + if not names: + names = [None] * len(var) return magnitudes, thetas, names @@ -219,7 +235,6 @@ class Gpo(vcsaddons.core.VCSaddon): template = self.template magnitudes, thetas, names = convert_arrays(var, theta) - if self.group_names: names = self.group_names while len(names) < len(magnitudes): @@ -233,7 +248,6 @@ class Gpo(vcsaddons.core.VCSaddon): flat_theta.extend(i) canvas = x - # Determine aspect ratio for plotting the circle canvas_info = canvas.canvasinfo() # Calculate aspect ratio of window @@ -254,14 +268,15 @@ class Gpo(vcsaddons.core.VCSaddon): center = x0 + xdiff / 2., y0 + ydiff / 2. diameter = min(xdiff, ydiff) radius = diameter / 2. - + plot_kwargs = {"render": False, "bg": bg, "donotstoredisplay": True} # Outer line if template.box1.priority > 0: outer = vcs.createline(source=template.box1.line) x, y = circle_points(center, radius, ratio=window_aspect) outer.x = x outer.y = y - canvas.plot(outer, render=False, bg=bg) + canvas.plot(outer, **plot_kwargs) + del vcs.elements["line"][outer.name] if numpy.allclose((self.datawc_y1, self.datawc_y2), 1e20): if self.magnitude_ticks == "*": @@ -294,7 +309,7 @@ class Gpo(vcsaddons.core.VCSaddon): m_labels = None for lev in m_scale: - lev_radius = radius * float(lev) / m_scale[-1] + lev_radius = radius * float(lev - m_scale[0]) / (m_scale[-1] - m_scale[0]) x, y = circle_points(center, lev_radius, ratio=window_aspect) if m_labels is not None: if lev in mag_labels: @@ -303,10 +318,11 @@ class Gpo(vcsaddons.core.VCSaddon): m_labels.y.append(ymul * lev_radius * numpy.sin(self.magnitude_tick_angle) + center[1]) m_ticks.x.append(x) m_ticks.y.append(y) - - canvas.plot(m_ticks, render=False, bg=bg) + canvas.plot(m_ticks, **plot_kwargs) + del vcs.elements["line"][m_ticks.name] if m_labels is not None: - canvas.plot(m_labels, render=False, bg=bg) + canvas.plot(m_labels, **plot_kwargs) + del vcs.elements["textcombined"][m_labels.name] if template.xtic1.priority > 0: t_ticks = vcs.createline(source=template.xtic1.line) @@ -327,10 +343,7 @@ class Gpo(vcsaddons.core.VCSaddon): if template.xlabel1.priority > 0: t_labels = [] - if self.xticlabels1 == "*": - theta_labels = vcs.mklabels(tick_thetas) - else: - theta_labels = self.xticlabels1 + theta_labels = tick_labels else: t_labels = None @@ -349,15 +362,18 @@ class Gpo(vcsaddons.core.VCSaddon): t_labels.append(label) t_ticks.x.append([x0, x1]) t_ticks.y.append([y0, y1]) - canvas.plot(t_ticks, render=False, bg=bg) + canvas.plot(t_ticks, **plot_kwargs) + del vcs.elements["line"][t_ticks.name] if t_labels is not None: for l in t_labels: - canvas.plot(l, render=False, bg=bg) + canvas.plot(l, **plot_kwargs) + del vcs.elements["textcombined"][l.name] values = vcs.createmarker() values.type = self.markers values.size = self.markersizes values.color = self.markercolors + values.colormap = self.colormap values.x = [] values.y = [] @@ -389,7 +405,8 @@ class Gpo(vcsaddons.core.VCSaddon): values.y.append(y) if template.legend.priority > 0: - canvas.plot(labels, bg=bg, render=False) - canvas.plot(values, bg=bg) - + canvas.plot(labels, **plot_kwargs) + del vcs.elements["textcombined"][labels.name] + canvas.plot(values, bg=bg, donotstoredisplay=True) + del vcs.elements["marker"][values.name] return canvas -- GitLab From dc86269c4bf0eb8fe579234fa7bf386f55e1b242 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Thu, 19 May 2016 11:37:09 -0400 Subject: [PATCH 077/191] Added test to validate geometry function --- testing/vcs/CMakeLists.txt | 4 ++++ testing/vcs/test_vcs_geometry.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 testing/vcs/test_vcs_geometry.py diff --git a/testing/vcs/CMakeLists.txt b/testing/vcs/CMakeLists.txt index 9e8cf78e3..05928a0c8 100644 --- a/testing/vcs/CMakeLists.txt +++ b/testing/vcs/CMakeLists.txt @@ -381,6 +381,10 @@ cdat_add_test(test_vcs_missing_colorname ${cdat_SOURCE_DIR}/testing/vcs/test_vcs_missing_colorname.py "${BASELINE_DIR}/test_vcs_missing_colorname.png" ) +cdat_add_test(test_vcs_geometry + "${PYTHON_EXECUTABLE}" + ${cdat_SOURCE_DIR}/testing/vcs/test_vcs_geometry.py + ) ############################################################################## # # These tests perform plotting and need sample data diff --git a/testing/vcs/test_vcs_geometry.py b/testing/vcs/test_vcs_geometry.py new file mode 100644 index 000000000..578bfb67d --- /dev/null +++ b/testing/vcs/test_vcs_geometry.py @@ -0,0 +1,32 @@ +import sys, vcs + +# This will check if we can set the geometry +# at the initialization of canvas +canvas = vcs.init(geometry=(600, 400)) +canvas.open() + +if dict(width=600, height=400) != canvas.geometry(): + canvas.close() + sys.exit(1) + +canvas.close() + +canvas2 = vcs.init() + +# This will check if we can safely set the geometry even +# though the canvas window has not been created yet +canvas2.geometry(400, 400) +canvas2.open() +if dict(width=400, height=400) != canvas2.geometry(): + canvas2.close() + sys.exit(1) + +# This will check if we can dynamically change the geometry +canvas2.geometry(500, 400) +canvas2.geometry(500, 500) +if dict(width=500, height=500) != canvas2.geometry(): + canvas2.close() + sys.exit(1) + +canvas2.close() +sys.exit(0) \ No newline at end of file -- GitLab From 8d4184228fb68955da38207e85807417d5794794 Mon Sep 17 00:00:00 2001 From: Aashish Chaudhary Date: Thu, 19 May 2016 22:35:11 -0400 Subject: [PATCH 078/191] Added plot script output --- Packages/vcs/docs/static/clt.png | Bin 0 -> 58300 bytes Packages/vcs/docs/user-guide.rst | 12 +++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 Packages/vcs/docs/static/clt.png diff --git a/Packages/vcs/docs/static/clt.png b/Packages/vcs/docs/static/clt.png new file mode 100644 index 0000000000000000000000000000000000000000..3d721ffdb6ef9be9c54cbff606c06497f33adf8d GIT binary patch literal 58300 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