diff --git a/tests/share/template_test_associated_dump.json b/tests/share/template_test_associated_dump.json index ba89c65fa..7534fd602 100644 --- a/tests/share/template_test_associated_dump.json +++ b/tests/share/template_test_associated_dump.json @@ -240,19 +240,19 @@ "priority": 0, "textorientation": "defcenter", "texttable": "default", - "y": 0.870000004768 + "y": 0.880000004768 }, "xmintic1": { "line": "default", "priority": 0, "y1": 0.259999990463, - "y2": 0.256999999285 + "y2": 0.248999999285 }, "xmintic2": { "line": "default", "priority": 0, "y1": 0.860000014305, - "y2": 0.860000014305 + "y2": 0.868000014305 }, "xname": { "priority": 1, diff --git a/tests/test_vcs_axisconvert.py b/tests/test_vcs_axisconvert.py new file mode 100644 index 000000000..c46d8b55f --- /dev/null +++ b/tests/test_vcs_axisconvert.py @@ -0,0 +1,115 @@ +import basevcstest +import vcs + +import numpy + + +class TestVCSAxisConvert(basevcstest.VCSBaseTest): + def testAxisConvert(self): + gm = vcs.create1d() + gm.yaxisconvert = "log10" + data = numpy.arange(10) + self.x.plot(numpy.power(10,data), gm, bg=self.bg) + self.checkImage("test_vcs_yaxisconvert_log10.png") + + self.x.clear() + gm.flip = True + gm.yaxisconvert = "linear" + gm.xaxisconvert="log10" + self.x.plot(numpy.power(10,data), gm, bg=self.bg) + self.checkImage("test_vcs_xaxisconvert_log10_flip.png") + + self.x.clear() + gm.flip = False + gm.xaxisconvert = "linear" + gm.yaxisconvert="ln" + self.x.plot(numpy.exp(data), gm, bg=self.bg) + self.checkImage("test_vcs_yaxisconvert_ln.png") + + self.x.clear() + gm.flip = False + gm.xaxisconvert="area_wt" + gm.yaxisconvert = "linear" + data2 = self.clt("clt",time=slice(0,1), longitude=slice(23,24), squeeze=1) + self.x.plot(data2, gm, bg=self.bg) + self.checkImage("test_vcs_xaxisconvert_areawt.png") + + self.x.clear() + gm.flip = True + gm.yaxisconvert="area_wt" + gm.xaxisconvert = "linear" + self.x.plot(data2, gm, bg=self.bg) + self.checkImage("test_vcs_yaxisconvert_areawt_flip.png") + + + self.x.clear() + gm.flip = False + gm.xaxisconvert="log10" + gm.yaxisconvert = "ln" + self.x.plot(numpy.power(10,data), numpy.exp(data), gm, bg=self.bg) + self.checkImage("test_vcs_axisconvert_log10_ln.png") + + self.x.clear() + #gm.flip = True + data2[:] = numpy.power(10,numpy.arange(1, data2.shape[0]+1)) + data2 = data2[:10] + gm.xaxisconvert = "area_wt" + gm.yaxisconvert="log10" + self.x.plot(data2 , gm, bg=self.bg) + self.checkImage("test_vcs_axisconvert_area_log10.png") + + self.x.clear() + gm.flip = True + gm.yaxisconvert = "area_wt" + gm.xaxisconvert="log10" + self.x.plot(data2 , gm, bg=self.bg) + self.checkImage("test_vcs_axisconvert_area_log10_flip.png") + + self.x.clear() + gm.flip = False + gm.xaxisconvert = "area_wt" + gm.yaxisconvert="log10" + self.x.plot(data2.getAxis(0)[:], data2 , gm, bg=self.bg) + self.checkImage("test_vcs_axisconvert_area_log10_2arrays.png") + + with self.assertRaises(RuntimeError): + self.x.clear() + gm.flip = True + self.x.plot(data2.getAxis(0)[:], data2 , gm, bg=self.bg) + + self.x.clear() + gm.flip = False + gm.xaxisconvert = "area_wt" + gm.yaxisconvert="log10" + gm.xticlabels1 = { -90:"90S", -80:"80S", -70:"70S", -60:"60S"} + gm.xticlabels2 = { -85:"85S", -75:"75S", -65:"65S", -55:"55S"} + mtics = {} + def func(x): + mtics[x]="" + + map(func, range(-90,-40,10)) + gm.xmtics2 = mtics + mtics = {} + map(func, range(-85,-40,10)) + gm.xmtics1 = mtics + + gm.yticlabels1 = {100:"hun"} + gm.yticlabels2 = {1000:"thou"} + gm.ymtics1 = {10:"",1000:""} + gm.ymtics2 = {10000:"",1000:""} + gm.list() + tmpl = vcs.createtemplate() + for num in ["1", "2"]: + for loc in ["x", "y"]: + for attr in ["mintic", "tic"]: + filled_attr = "{}{}{}".format(loc,attr,num) + print("PRIO FOR ATT:",filled_attr) + obj = getattr(tmpl,filled_attr) + obj.priority=1 + obj.list() + tmpl.xlabel1.priority=1 + tmpl.xlabel2.priority=1 + tmpl.ylabel1.priority=1 + tmpl.ylabel2.priority=1 + self.x.plot(data2.getAxis(0)[:], data2 , gm, tmpl, bg=self.bg) + self.checkImage("test_vcs_axisconvert_area_log10_user_labels.png") diff --git a/tests/test_vcs_axisconvert_2d.py b/tests/test_vcs_axisconvert_2d.py new file mode 100644 index 000000000..94c839647 --- /dev/null +++ b/tests/test_vcs_axisconvert_2d.py @@ -0,0 +1,63 @@ +import basevcstest +import os +import vcs +import cdms2 +import numpy + + +class TestVCSAxisConvert(basevcstest.VCSBaseTest): + def axisConvertGmLog10Areawt(self, method): + method = method() + f = cdms2.open(vcs.sample_data+"/ta_ncep_87-6-88-4.nc") + data = f("ta", time=slice(0,1), longitude=(12,12,'cob'), squeeze=1) + if isinstance(method, vcs.vector.Gv): + data2 = data + else: + data2 = None + self.axisConvertGm(data, data2, method, 'area_wt', 'log10') + + def axisConvertGmLog10(self, method): + method = method() + f = cdms2.open(vcs.sample_data+"/ta_ncep_87-6-88-4.nc") + data = f("ta", longitude=(12,12,'cob'), latitude=(12, 12, 'cob'), squeeze=1) + if isinstance(method, vcs.vector.Gv): + data2 = data + else: + data2 = None + self.axisConvertGm(data, data2, method, 'log10', 'linear') + + def axisConvertGmAreaWt(self, method): + method = method() + if isinstance(method, vcs.vector.Gv): + data = self.clt("u") + data2 = self.clt("v") + elif isinstance(method, vcs.meshfill.Gfm): + data = cdms2.open(os.path.join(vcs.sample_data,"sampleCurveGrid4.nc"))("sample") + data2 = None + else: + data = self.clt("clt") + data2 = None + self.axisConvertGm(data, data2, method, 'linear', 'area_wt') + + def axisConvertGm(self, data, data2, gm, xconvert, yconvert): + gm.xaxisconvert = xconvert + gm.yaxisconvert = yconvert + self.x.clear() + if data2 is None: + self.x.plot(data, gm) + else: + self.x.plot(data, data2, gm) + self.checkImage("test_vcs_axisconvert_{}_{}_{}.png".format(gm.g_name, xconvert, yconvert)) + + def test_areawt(self): + for method in [ + vcs.createboxfill, + vcs.createisofill, + vcs.createisoline, + vcs.createmeshfill, + # vcs.createvector, + ]: + self.axisConvertGmAreaWt(method) + if not method in [vcs.createmeshfill,]: + self.axisConvertGmLog10(method) + self.axisConvertGmLog10Areawt(method) diff --git a/tests/test_vcs_continents.py b/tests/test_vcs_continents.py index c22b1e26b..e35bb30e6 100644 --- a/tests/test_vcs_continents.py +++ b/tests/test_vcs_continents.py @@ -53,10 +53,8 @@ def testContinents(self): bg=self.bg) elif cont_index == 3: self.x.setcontinentsline(cont_line) - self.x.setcontinentstype(3) - self.x.plot(clt, template, boxfill, bg=self.bg) + self.x.plot(clt, template, boxfill, continents=3, bg=self.bg) elif i == 4: - self.x.setcontinentstype(0) # Make sure absolute path works path = os.path.join( vcs.prefix, "share", "vcs", "data_continent_political") diff --git a/tests/test_vcs_dump_json.py b/tests/test_vcs_dump_json.py index b1b4f634d..03649c44e 100644 --- a/tests/test_vcs_dump_json.py +++ b/tests/test_vcs_dump_json.py @@ -1,3 +1,4 @@ +from __future__ import print_function import basevcstest import filecmp import os diff --git a/tests/test_vcs_isofill_masked_bounds.py b/tests/test_vcs_isofill_masked_bounds.py index 00bee180a..6a615173b 100644 --- a/tests/test_vcs_isofill_masked_bounds.py +++ b/tests/test_vcs_isofill_masked_bounds.py @@ -8,10 +8,9 @@ def testIsofill(self): data = os.path.join(self.basedatadir, "coads_climatology.nc") f = cdms2.open(data) - s = f["SST"] + s = f("SST") t = s.getTime() - tc = t.asComponentTime() - print("TC:",tc[:3]) + t.units = "hours since 1" iso = self.x.getisofill('a_robinson_isofill') self.x.plot(s, iso, bg=self.bg) self.checkImage("test_vcs_isofill_masked_bounds.png") diff --git a/tests/test_vcs_no_continents.py b/tests/test_vcs_no_continents.py index 7dcf3bac6..a14e48460 100644 --- a/tests/test_vcs_no_continents.py +++ b/tests/test_vcs_no_continents.py @@ -9,13 +9,13 @@ def testNoContinents(self): 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')) - t1 = self.x.createtemplate() - t1.scale(.5, "y") - t1.move(-.15, "y") - t2 = self.x.createtemplate(source=t1.name) - t2.move(.5, 'y') + template_bottom = self.x.createtemplate() + template_bottom.scale(.5, "y") + template_bottom.move(-.15, "y") + template_top = self.x.createtemplate(source=template_bottom.name) + template_top.move(.5, 'y') - self.x.plot(clt, t1, continents=0, bg=self.bg) - self.x.plot(clt, t2, continents=1, bg=self.bg) + self.x.plot(clt, template_bottom, continents=0, bg=self.bg) + self.x.plot(clt, template_top, continents=1, bg=self.bg) self.checkImage("test_vcs_no_continents.png") diff --git a/vcs/Canvas.py b/vcs/Canvas.py index 5d451c351..4af549363 100644 --- a/vcs/Canvas.py +++ b/vcs/Canvas.py @@ -20,7 +20,6 @@ import numpy.ma import MV2 import numpy -import cdutil from .queries import * # noqa from . import boxfill from . import isofill @@ -70,7 +69,7 @@ def rotate(x, y, xorigin, yorigin, angle): # translate xtr = x - xorigin ytr = y - yorigin - angle = angle/180.*numpy.pi + angle = angle / 180. * numpy.pi xout = xtr * numpy.cos(angle) - ytr * numpy.sin(angle) yout = xtr * numpy.sin(angle) + ytr * numpy.cos(angle) @@ -80,7 +79,8 @@ def rotate(x, y, xorigin, yorigin, angle): class JupyterFFMPEG(object): - def __init__(self, source, ffmpeg_result, width=640, height=420, controls=True): + def __init__(self, source, ffmpeg_result, + width=640, height=420, controls=True): self.source = source self.width = width self.height = height @@ -269,7 +269,8 @@ def _determine_arg_list(g_name, actual_args): "Error in argument list for vcs %s command." % g_name) - if hasVCSAddons and isinstance(arglist[igraphics_method], vcsaddons.core.VCSaddon): + if hasVCSAddons and isinstance( + arglist[igraphics_method], vcsaddons.core.VCSaddon): if found_slabs != arglist[igraphics_method].g_nslabs: raise vcsError( "%s requires %i slab(s)" % @@ -370,7 +371,6 @@ class Canvas(vcs.bestMatch): '_Canvas__last_plot_keyargs', '__last_plot_actual_args', '__last_plot_keyargs', - '_continents', '_continents_line', '_savedcontinentstype', ] @@ -602,9 +602,6 @@ def _datawc_tv(self, tv, arglist): return tv - def savecontinentstype(self, value): - self._savedcontinentstype = value - def onClosing(self, cell): if self.configurator: self.endconfigure() @@ -797,23 +794,6 @@ def _reconstruct_tv(self, arglist, keyargs): tv, 'date') and not hasattr(tv, 'time'): change_date_time(tv, 0) - # Draw continental outlines if specified. - contout = keyargs.get('continents', None) - if contout is None: - if (xdim >= 0 and ydim >= 0 and tv.getAxis(xdim).isLongitude() and tv.getAxis(ydim).isLatitude()) or\ - (self.isplottinggridded): - contout = self.getcontinentstype() - else: - contout = 0 - - if (isinstance(arglist[GRAPHICS_METHOD], str) and (arglist[GRAPHICS_METHOD]) == 'meshfill') or ( - (xdim >= 0 and ydim >= 0 and (isinstance(contout, str) or contout >= 1))): - self.setcontinentstype(contout) - self.savecontinentstype(contout) - else: - self.setcontinentstype(0) - self.savecontinentstype(0) - # Reverse axis direction if necessary xrev = keyargs.get('xrev', 0) if xrev == 1 and xdim >= 0: @@ -902,7 +882,7 @@ def __init__(self, mode=1, pause_time=0, call_from_gui=0, size=None, if geometry is not None: # Extract width and height, create dict - if type(geometry) == dict: + if isinstance(geometry, dict): for key in geometry: if key not in ("width", "height"): raise ValueError("Unexpected key %s in geometry" % key) @@ -947,7 +927,6 @@ def __init__(self, mode=1, pause_time=0, call_from_gui=0, size=None, self.configurator = None self.setcontinentsline("default") - self.setcontinentstype(1) # Initial.attributes is being called in main.c, so it is not needed here! # Actually it is for taylordiagram graphic methods.... @@ -2416,9 +2395,13 @@ def gettextbox(self, textobject): raise vcsError('You must pass a text object') # for rotation we need to normalize coordinates - text2 = vcs.createtext(Tt_source=textobject.Tt_name, To_source=textobject.To_name) - xs = numpy.array(textobject.x) / (text2.worldcoordinate[1] - text2.worldcoordinate[0]) - ys = numpy.array(textobject.y) / (text2.worldcoordinate[3] - text2.worldcoordinate[2]) + text2 = vcs.createtext( + Tt_source=textobject.Tt_name, + To_source=textobject.To_name) + xs = numpy.array(textobject.x) / \ + (text2.worldcoordinate[1] - text2.worldcoordinate[0]) + ys = numpy.array(textobject.y) / \ + (text2.worldcoordinate[3] - text2.worldcoordinate[2]) text2.x = xs.tolist() text2.y = ys.tolist() @@ -2428,26 +2411,42 @@ def gettextbox(self, textobject): noangles = self.gettextextent(text2, 0.) out = [] for bounding, noangle in zip(boundings, noangles): - bxmid = (bounding[0] + bounding[1])/2. + bxmid = (bounding[0] + bounding[1]) / 2. bymid = (bounding[2] + bounding[3]) / 2. - xmid = (noangle[0] + noangle[1])/2. - ymid = (noangle[2] + noangle[3])/2. + xmid = (noangle[0] + noangle[1]) / 2. + ymid = (noangle[2] + noangle[3]) / 2. slim = [] # first corner - slim.append(rotate(noangle[0], noangle[2], xmid, ymid, -textobject.angle)) + slim.append( + rotate( + noangle[0], noangle[2], xmid, ymid, -textobject.angle)) # second corner - slim.append(rotate(noangle[1], noangle[2], xmid, ymid, -textobject.angle)) + slim.append( + rotate( + noangle[1], noangle[2], xmid, ymid, -textobject.angle)) # third corner - slim.append(rotate(noangle[1], noangle[3], xmid, ymid, -textobject.angle)) + slim.append( + rotate( + noangle[1], noangle[3], xmid, ymid, -textobject.angle)) # fourth corner - slim.append(rotate(noangle[0], noangle[3], xmid, ymid, -textobject.angle)) + slim.append( + rotate( + noangle[0], noangle[3], xmid, ymid, -textobject.angle)) # Ok now we need to translte in the middle of the bounding box xs = [p[0] for p in slim] ys = [p[1] for p in slim] - outx = [bxmid + (x - xmid)*(textobject.worldcoordinate[1]-textobject.worldcoordinate[0]) for x in xs] - outy = [bymid + (y - ymid)*(textobject.worldcoordinate[3]-textobject.worldcoordinate[2]) for y in ys] + outx = [bxmid + + (x - + xmid) * + (textobject.worldcoordinate[1] - + textobject.worldcoordinate[0]) for x in xs] + outy = [bymid + + (y - + ymid) * + (textobject.worldcoordinate[3] - + textobject.worldcoordinate[2]) for y in ys] out.append([outx, outy]) return out @@ -2540,7 +2539,7 @@ def drawtextcombined(self, Tt_name=None, To_name=None, string=None, drawtextcombined.__doc__ = drawtextcombined.__doc__ % (xmldocs.color, xmldocs.viewport, xmldocs.worldcoordinate, xmldocs.x_y_coords, xmldocs.bg) - _plot_keywords_ = ['variable', 'grid', 'xaxis', 'xarray', 'xrev', 'yaxis', 'yarray', 'yrev', 'continents', + _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"] @@ -2793,38 +2792,6 @@ def plot(self, *actual_args, **keyargs): plot_2_1D_input, plot_output) - def plot_filledcontinents( - self, slab, template_name, g_type, g_name, bg, ratio): - cf = cdutil.continent_fill.Gcf() - if g_type.lower() == 'boxfill': - g = self.getboxfill(g_name) - lons = slab.getLongitude() - lats = slab.getLatitude() - - if lons is None or lats is None: - return - if g.datawc_x1 > 9.9E19: - cf.datawc_x1 = lons[0] - else: - cf.datawc_x1 = g.datawc_x1 - if g.datawc_x2 > 9.9E19: - cf.datawc_x2 = lons[-1] - else: - cf.datawc_x2 = g.datawc_x2 - if g.datawc_y1 > 9.9E19: - cf.datawc_y1 = lats[0] - else: - cf.datawc_y1 = g.datawc_y1 - if g.datawc_y2 > 9.9E19: - cf.datawc_y2 = lats[-1] - else: - cf.datawc_y2 = g.datawc_y2 - try: - self.gettemplate(template_name) - cf.plot(x=self, template=template_name, ratio=ratio) - except Exception as err: - print(err) - def __new_elts(self, original, new): for e in list(vcs.elements.keys()): for k in list(vcs.elements[e].keys()): @@ -2857,7 +2824,8 @@ def __plot(self, arglist, keyargs): assert arglist[0] is None or cdms2.isVariable(arglist[0]) assert arglist[1] is None or cdms2.isVariable(arglist[1]) assert isinstance(arglist[2], str) - if hasVCSAddons and not isinstance(arglist[3], vcsaddons.core.VCSaddon): + if hasVCSAddons and not isinstance( + arglist[3], vcsaddons.core.VCSaddon): assert isinstance(arglist[3], str) assert isinstance(arglist[4], str) @@ -3650,100 +3618,6 @@ def __plot(self, arglist, keyargs): except Exception: pass - def clean_val(value): - if numpy.allclose(value, 0.): - return 0. - elif value < 0: - sign = -1 - value = -value - else: - sign = 1 - i = int(numpy.log10(value)) - if i > 0: - j = i - k = 10. - else: - j = i - 1 - k = 10. - v = int(value / numpy.power(k, j)) * numpy.power(k, j) - return v * sign - - def mkdic(method, values): - if method == 'area_wt': - func = numpy.sin - func2 = numpy.arcsin - elif method == 'exp': - func = numpy.exp - func2 = numpy.log - elif method == 'ln': - func = numpy.log - func2 = numpy.exp - elif method == 'log10': - func = numpy.log10 - vals = [] - for v in values: - if method == 'area_wt': - vals.append(func(v * numpy.pi / 180.)) - else: - vals.append(func(v)) - min, max = vcs.minmax(vals) - levs = vcs.mkscale(min, max) -# levs=vcs.mkevenlevels(min,max) - vals = [] - for l in levs: - if method == 'log10': - v = numpy.power(10, l) - elif method == 'area_wt': - v = func2(l) / numpy.pi * 180. - else: - v = func2(l) - vals.append(clean_val(v)) - dic = vcs.mklabels(vals) - dic2 = {} - for k in list(dic.keys()): - try: - if method == 'area_wt': - dic2[func(k * numpy.pi / 180.)] = dic[k] - else: - dic2[func(k)] = dic[k] - except Exception: - pass - return dic2 - - def set_convert_labels(copy_mthd, test=0): - did_something = False - for axc in ['x', 'y']: - try: - mthd = getattr(copy_mthd, axc + 'axisconvert') - if mthd != 'linear': - for num in ['1', '2']: - if getattr( - copy_mthd, axc + 'ticlabels' + num) == '*': - if axc == 'x': - axn = -1 - else: - axn = -2 - dic = mkdic(mthd, arglist[0].getAxis(axn)[:]) - if test == 0: - setattr( - copy_mthd, - axc + - 'ticlabels' + - num, - dic) - did_something = True - except Exception: - pass - return did_something - - if set_convert_labels(check_mthd, test=1): - if copy_mthd is None: - try: - copy_mthd = vcs.creategraphicsmethod(arglist[3], arglist[4]) - except Exception: - pass - check_mthd = copy_mthd - set_convert_labels(copy_mthd) if copy_mthd is None: try: copy_mthd = vcs.creategraphicsmethod(arglist[3], arglist[4]) @@ -3864,7 +3738,6 @@ def set_convert_labels(copy_mthd, test=0): else: nm, src = self.check_name_source(None, "default", "display") dn = displayplot.Dp(nm) - dn.continents = self.getcontinentstype() dn.continents_line = self.getcontinentsline() dn.template = arglist[2] dn.g_type = arglist[3] @@ -3880,9 +3753,16 @@ def set_convert_labels(copy_mthd, test=0): dn.newelements = self.__new_elts(original_elts, new_elts) dn._parent = self + """ + try: + self.setcontinentstype(self._savedcontinentstype) + except Exception: + pass + """ return dn else: # not taylor diagram - if hasVCSAddons and isinstance(arglist[3], vcsaddons.core.VCSaddon): + if hasVCSAddons and isinstance( + arglist[3], vcsaddons.core.VCSaddon): gm = arglist[3] else: tp = arglist[3] @@ -3894,6 +3774,12 @@ def set_convert_labels(copy_mthd, test=0): tp = "1d" gm = vcs.elements[tp][arglist[4]] if hasattr(gm, "priority") and gm.priority == 0: + """ + try: # not always saved + self.setcontinentstype(self._savedcontinentstype) + except Exception: + pass + """ return p = self.getprojection(gm.projection) if p.type in no_deformation_projections and ( @@ -4001,7 +3887,8 @@ def set_convert_labels(copy_mthd, test=0): if doratio[-1] == 't' or template_origin == 'default': box_and_ticks = 1 - if hasVCSAddons and isinstance(arglist[3], vcsaddons.core.VCSaddon): + if hasVCSAddons and isinstance( + arglist[3], vcsaddons.core.VCSaddon): gm = arglist[3] else: tp = arglist[3] @@ -4088,7 +3975,7 @@ def set_convert_labels(copy_mthd, test=0): if hasattr(self, '_isplottinggridded'): del(self._isplottinggridded) # Get the continents for animation generation - self.animate.continents_value = self._continentspath() + # self.animate.continents_value = self._continentspath() # Get the option for doing graphics in the background. if bg: @@ -4107,7 +3994,8 @@ def set_convert_labels(copy_mthd, test=0): 'Error - VECTOR components must be on the same grid.') if "bg" in keyargs: del(keyargs["bg"]) - if hasVCSAddons and isinstance(arglist[3], vcsaddons.core.VCSaddon): + if hasVCSAddons and isinstance( + arglist[3], vcsaddons.core.VCSaddon): if arglist[1] is None: dn = arglist[3].plot( arglist[0], @@ -4144,7 +4032,6 @@ def set_convert_labels(copy_mthd, test=0): if dn is not None: dn._template_origin = template_origin dn.ratio = keyargs.get("ratio", None) - dn.continents = self.getcontinentstype() dn.continents_line = self.getcontinentsline() dn.newelements = self.__new_elts(original_elts, new_elts) @@ -4466,27 +4353,6 @@ def canvasinfo(self, *args, **kargs): """ return self.backend.canvasinfo(*args, **kargs) - def getcontinentstype(self, *args): - """Retrieve continents type from VCS; either an integer between 0 and 6 or the - path to a custom continentstype. - - :Example: - - .. doctest:: canvas_getcontinentstype - - >>> a=vcs.init() - >>> a.setcontinentstype(6) - >>> a.getcontinentstype() # Get the continents type - 6 - - :returns An int between 0 and 6, or the path to a custom continentstype - :rtype: `int`_ or system filepath - """ - try: - return self._continents - except Exception: - return None - def landscape(self, width=-99, height=-99, x=-99, y=-99, clear=0): """Change the VCS Canvas orientation to Landscape. @@ -4556,7 +4422,8 @@ def landscape(self, width=-99, height=-99, x=-99, y=-99, clear=0): args = (width, height, x, y, clear) return self.backend.landscape(*args) - landscape.__doc__ = landscape.__doc__ % (xmldocs.canvas_width, xmldocs.canvas_height, xmldocs.canvas_clear) + landscape.__doc__ = landscape.__doc__ % ( + xmldocs.canvas_width, xmldocs.canvas_height, xmldocs.canvas_clear) def listelements(self, *args): """Returns a sorted Python list of all VCS object names, or a list of @@ -4702,7 +4569,8 @@ def portrait(self, width=-99, height=-99, x=-99, y=-99, clear=0): return p - portrait.__doc__ = portrait.__doc__ % (xmldocs.canvas_width, xmldocs.canvas_height, xmldocs.canvas_clear) + portrait.__doc__ = portrait.__doc__ % ( + xmldocs.canvas_width, xmldocs.canvas_height, xmldocs.canvas_clear) def ffmpeg(self, movie, files, bitrate=1024, rate=None, options=None): """MPEG output from a list of valid files. @@ -4995,7 +4863,10 @@ def png(self, file, width=None, height=None, width, height, units, background=True) return self.backend.png( file, W, H, units, draw_white_background, **args) - png.__doc__ = png.__doc__ % (xmldocs.output_file, xmldocs.output_width, xmldocs.output_height, xmldocs.output_units) + png.__doc__ = png.__doc__ % (xmldocs.output_file, + xmldocs.output_width, + xmldocs.output_height, + xmldocs.output_units) def pdf(self, file, width=None, height=None, units='inches', textAsPaths=True): @@ -5035,8 +4906,12 @@ def pdf(self, file, width=None, height=None, units='inches', if not file.split('.')[-1].lower() in ['pdf']: file += '.pdf' - return self.backend.pdf(file, width=W, height=H, units=units, textAsPaths=textAsPaths) - pdf.__doc__ = pdf.__doc__ % (xmldocs.output_file, xmldocs.output_width, xmldocs.output_height, xmldocs.output_units) + return self.backend.pdf(file, width=W, height=H, + units=units, textAsPaths=textAsPaths) + pdf.__doc__ = pdf.__doc__ % (xmldocs.output_file, + xmldocs.output_width, + xmldocs.output_height, + xmldocs.output_units) def svg(self, file, width=None, height=None, units='inches', textAsPaths=True): @@ -5076,8 +4951,12 @@ def svg(self, file, width=None, height=None, units='inches', if not file.split('.')[-1].lower() in ['svg']: file += '.svg' - return self.backend.svg(file, width=W, height=H, units=units, textAsPaths=textAsPaths) - svg.__doc__ = svg.__doc__ % (xmldocs.output_file, xmldocs.output_width, xmldocs.output_height, xmldocs.output_units) + return self.backend.svg(file, width=W, height=H, + units=units, textAsPaths=textAsPaths) + svg.__doc__ = svg.__doc__ % (xmldocs.output_file, + xmldocs.output_width, + xmldocs.output_height, + xmldocs.output_units) def _compute_margins( self, W, H, top_margin, bottom_margin, right_margin, left_margin, dpi): @@ -5197,7 +5076,8 @@ def isopened(self): """ return self.backend.isopened() - def _compute_width_height(self, width, height, units, ps=False, background=False): + def _compute_width_height( + self, width, height, units, ps=False, background=False): dpi = 72. # dot per inches if units in ["in", "inches"]: factor = 1. @@ -5269,7 +5149,8 @@ def _compute_width_height(self, width, height, units, ps=False, background=False H = tmp return W, H - def postscript(self, file, mode='r', orientation=None, width=None, height=None, units='inches', textAsPaths=True): + def postscript(self, file, mode='r', orientation=None, + width=None, height=None, units='inches', textAsPaths=True): """Postscript output is another form of vector graphics. It is larger than its CGM output counter part, because it is stored out in ASCII format. @@ -5324,7 +5205,8 @@ def postscript(self, file, mode='r', orientation=None, width=None, height=None, if not file.split('.')[-1].lower() in ['ps', 'eps']: file += '.ps' if mode == 'r': - return self.backend.postscript(file, W, H, units="pixels", textAsPaths=textAsPaths) + return self.backend.postscript( + file, W, H, units="pixels", textAsPaths=textAsPaths) else: n = random.randint(0, 10000000000000) psnm = '/tmp/' + '__VCS__tmp__' + str(n) + '.ps' @@ -5462,7 +5344,8 @@ def setcontinentsline(self, line="default"): :param line: Line to use for drawing continents. Can be a string name of a line, or a VCS line object :type line: `str`_ or :py:class:`vcs.line.Tl` """ - linename = VCS_validation_functions.checkLine(self, "continentsline", line) + linename = VCS_validation_functions.checkLine( + self, "continentsline", line) line = vcs.getline(linename) self._continents_line = line @@ -5487,59 +5370,11 @@ def getcontinentsline(self): else: return self._continents_line - def setcontinentstype(self, value): - """One has the option of using continental maps that are predefined or that - are user-defined. Predefined continental maps are either internal to VCS - or are specified by external files. User-defined continental maps are - specified by additional external files that must be read as input. - - The continents-type values are integers ranging from 0 to 11, where: - - * 0 signifies "No Continents" - - * 1 signifies "Fine Continents" - - * 2 signifies "Coarse Continents" - - * 3 signifies "United States" (with "Fine Continents") - - * 4 signifies "Political Borders" (with "Fine Continents") - - * 5 signifies "Rivers" (with "Fine Continents") - - * 6 uses a custom continent set - - You can also pass a file by path. - - :Example: - - .. doctest:: canvas_setcontinentstype - - >>> a=vcs.init() - >>> a.setcontinentstype(4) # "Political Borders" - >>> import cdms2 # We need cdms2 to create a slab - >>> f = cdms2.open(vcs.sample_data+'/clt.nc') # open data file - >>> v = f('v') # use the data file to create a slab - >>> a.plot(v,'default','isofill','quick') # map with borders - - - :param value: Integer representing continent type, as specified in function description - :type value: `int`_ - """ - continent_path = VCS_validation_functions.checkContinents(self, value) - self._continents = value - if continent_path is not None and not os.path.exists( - continent_path): - warnings.warn( - "Continents file not found: %s, substituing with fine continents" % - continent_path) - self._continents = 1 - return - - def _continentspath(self): + def _continentspath(self, continentsPath): try: - path = VCS_validation_functions.checkContinents(self, self._continents) - if path is None and self._continents != 0: + path = VCS_validation_functions.checkContinents( + self, continentsPath) + if path is None and continentsPath != 0: return VCS_validation_functions.checkContinents(self, 1) else: return path @@ -5580,9 +5415,12 @@ def gif(self, filename='noname.gif', merge='r', orientation=None, def gs(self, filename='noname.gs', device='png256', orientation=None, resolution='792x612'): - warnings.warn("Export to GhostScript is no longer supported", vcs.VCSDeprecationWarning) + warnings.warn( + "Export to GhostScript is no longer supported", + vcs.VCSDeprecationWarning) - def eps(self, file, mode='r', orientation=None, width=None, height=None, units='inches', textAsPaths=True): + def eps(self, file, mode='r', orientation=None, width=None, + height=None, units='inches', textAsPaths=True): """In some cases, the user may want to save the plot out as an Encapsulated PostScript image. This routine allows the user to save the VCS canvas output as an Encapsulated PostScript file. @@ -5631,7 +5469,10 @@ def eps(self, file, mode='r', orientation=None, width=None, height=None, units=' os.popen("ps2epsi %s %s" % (tmpfile, file)).readlines() os.remove(tmpfile) - eps.__doc__ = eps.__doc__ % (xmldocs.output_file, xmldocs.output_width, xmldocs.output_height, xmldocs.output_units) + eps.__doc__ = eps.__doc__ % (xmldocs.output_file, + xmldocs.output_width, + xmldocs.output_height, + xmldocs.output_units) def show(self, *args): return vcs.show(*args) diff --git a/vcs/Pxlabels.py b/vcs/Pxlabels.py index 07513901f..70d69bea0 100755 --- a/vcs/Pxlabels.py +++ b/vcs/Pxlabels.py @@ -132,7 +132,7 @@ def __init__(self, member): if member == "xlabel1": self.y = 0.234999999404 elif member == "xlabel2": - self.y = 0.870000004768 + self.y = 0.880000004768 self.priority = 0 ########################################################################## diff --git a/vcs/Pxtickmarks.py b/vcs/Pxtickmarks.py index 81168d2a1..ac333c5f6 100755 --- a/vcs/Pxtickmarks.py +++ b/vcs/Pxtickmarks.py @@ -137,11 +137,11 @@ def __init__(self, member): elif member == "xmintic1": self.priority = 0 self.y1 = 0.259999990463 - self.y2 = 0.256999999285 + self.y2 = 0.248999999285 elif member == "xmintic2": self.priority = 0 self.y1 = 0.860000014305 - self.y2 = 0.860000014305 + self.y2 = 0.868000014305 self.line = "default" ########################################################################## diff --git a/vcs/VTKPlots.py b/vcs/VTKPlots.py index 3f7a32ee0..fa5c55d30 100644 --- a/vcs/VTKPlots.py +++ b/vcs/VTKPlots.py @@ -672,7 +672,7 @@ def plot(self, data1, data2, template, gtype, gname, bg, *args, **kargs): vtk_backend_geo = kargs.get("vtk_backend_geo", None) bounds = vtk_dataset_bounds_no_mask if vtk_dataset_bounds_no_mask else None - pipeline = vcsvtk.createPipeline(gm, self) + pipeline = vcsvtk.createPipeline(gm, self, kargs) if pipeline is not None: returned.update(pipeline.plot(data1, data2, tpl, vtk_backend_grid, vtk_backend_geo, **kargs)) @@ -801,11 +801,15 @@ def onClosing(self, cell): if hasattr(plot, 'onClosing'): plot.onClosing(cell) - def plotContinents(self, wc, projection, wrap, vp, priority, **kargs): - continents_path = self.canvas._continentspath() + def plotContinents(self, continentType, wc, projection, wrap, vp, priority, **kargs): + if continentType in [0, None]: + return + continents_path = self.canvas._continentspath(continentType) if continents_path is None: return (None, 1, 1) - contData = vcs2vtk.prepContinents(continents_path) + xforward = vcs.utils.axisConvertFunctions[kargs.get('xaxisconvert', 'linear')]['forward'] + yforward = vcs.utils.axisConvertFunctions[kargs.get('yaxisconvert', 'linear')]['forward'] + contData = vcs2vtk.prepContinents(continents_path, xforward, yforward) contData = vcs2vtk.doWrapData(contData, wc, fastClip=False) contMapper = vtk.vtkPolyDataMapper() contMapper.SetInputData(contData) diff --git a/vcs/__init__.py b/vcs/__init__.py index dc3a4f0b6..63306bef6 100755 --- a/vcs/__init__.py +++ b/vcs/__init__.py @@ -183,6 +183,9 @@ class VCSDeprecationWarning(DeprecationWarning): dic[-90] = "90S" dic[90] = "90N" elements["list"]["Lat20"] = dic +elements["list"]["Lat_wt"] = {-90.: "90S", -60: "60S", -45: "45S", -30: "30S", -15: "15S", + 0: "Eq", + 15: "15N", 30: "30S", 45: "45N", 60: "60N", 90: "90N"} i = 1 for nm, fnt in [ diff --git a/vcs/utils.py b/vcs/utils.py index b2263a52c..d308079c3 100644 --- a/vcs/utils.py +++ b/vcs/utils.py @@ -1856,6 +1856,30 @@ def prettifyAxisLabels(ticks, axis): return ticks +axisConvertFunctions = { + "linear": {"forward": lambda x: x, "invert": lambda x: x}, + "area_wt": {"forward": lambda x: numpy.sin(x / 180. * numpy.pi), + "invert": lambda x: numpy.arcsin(x) / numpy.pi * 180.}, + "ln": {"forward": numpy.log, "invert": numpy.exp}, + "log10": {"forward": numpy.log10, "invert": lambda x: numpy.power(10, x)}, + "exp": {"forward": numpy.exp, "invert": numpy.log} +} + + +def transformTicks(ticks_in, transform): + ticks_out = {} + for key in ticks_in: + ticks_out[transform(key)] = ticks_in[key] + return ticks_out + + +def transformTicksLabels(ticks_in, transform): + ticks_out = {} + for key in ticks_in: + ticks_out[key] = "{:g}".format(transform(key)) + return ticks_out + + def setTicksandLabels(gm, copy_gm, datawc_x1, datawc_x2, datawc_y1, datawc_y2, x=None, y=None): """Sets the labels and ticks for a graphics method made in python @@ -1887,138 +1911,122 @@ def setTicksandLabels(gm, copy_gm, datawc_x1, datawc_x2, :returns: A VCS graphics method object :rtype: A VCS graphics method object """ + # Ok axisconvertion functions + x_forward = axisConvertFunctions[gm.xaxisconvert]["forward"] + x_invert = axisConvertFunctions[gm.xaxisconvert]["invert"] + y_forward = axisConvertFunctions[gm.yaxisconvert]["forward"] + y_invert = axisConvertFunctions[gm.yaxisconvert]["invert"] + + # Convert + datawc_x1 = x_forward(datawc_x1) + datawc_x2 = x_forward(datawc_x2) + datawc_y1 = y_forward(datawc_y1) + datawc_y2 = y_forward(datawc_y2) # Ok all this is nice but if user specified datawc we need to use it! for a in ["x1", "x2", "y1", "y2"]: nm = "datawc_%s" % a - if not numpy.allclose(getattr(gm, nm), 1.e20): + dwc = getattr(gm, nm) + if not isinstance(dwc, (float, int, numpy.int, numpy.float)) or not numpy.allclose(dwc, 1.e20): loc = locals() exec("%s = gm.%s" % (nm, nm)) if nm == "datawc_x1": - datawc_x1 = loc[nm] + datawc_x1 = x_forward(loc[nm]) elif nm == "datawc_x2": - datawc_x2 = loc[nm] + datawc_x2 = x_forward(loc[nm]) elif nm == "datawc_y1": - datawc_y1 = loc[nm] + datawc_y1 = y_forward(loc[nm]) elif nm == "datawc_y2": - datawc_y2 = loc[nm] + datawc_y2 = y_forward(loc[nm]) if isinstance(gm, vcs.taylor.Gtd): return - # Now the template stuff - # first create the dictionary to remember which ones are changed - dic = {} - for key in ('xticlabels1', 'xmtics1', 'xticlabels2', 'xmtics2', - 'yticlabels1', 'ymtics1', 'yticlabels2', 'ymtics2'): - dic[key] = False - # xticklabels1 - if gm.xticlabels1 is None or gm.xticlabels1 == '*': - if copy_gm is None: - copy_gm = creategraphicsmethod(gm.g_name, gm.name) - gm = copy_gm - if x == "longitude" and abs(datawc_x2 - datawc_x1) > 30: - ticks = "Lon30" - else: - ticks = vcs.mkscale(datawc_x1, datawc_x2) - ticks = prettifyAxisLabels(vcs.mklabels(ticks), x) - setattr(gm, 'xticlabels1', ticks) - dic['xticlabels1'] = True - # xmtics1 - if gm.xmtics1 is None or gm.xmtics1 == '*': - if copy_gm is None: - copy_gm = creategraphicsmethod(gm.g_name, gm.name) - gm = copy_gm - if x == "longitude" and abs(datawc_x2 - datawc_x1) > 30: - ticks = list(gm.xticlabels1.keys()) - else: - ticks = vcs.mkscale(datawc_x1, datawc_x2) - tick2 = [] - for i in range(len(ticks) - 1): - tick2.append((ticks[i] + ticks[i + 1]) / 2.) - ticks = prettifyAxisLabels(vcs.mklabels(tick2), x) - setattr(gm, 'xmtics1', ticks) - dic['xmtics1'] = True - # xticklabels2 - if hasattr(gm, "xticlabels2") and ( - gm.xticlabels2 is None or gm.xticlabels2 == '*'): - if copy_gm is None: - copy_gm = creategraphicsmethod(gm.g_name, gm.name) - gm = copy_gm - if x == "longitude" and abs(datawc_x2 - datawc_x1) > 30: - ticks = "Lon30" - else: - ticks = vcs.mkscale(datawc_x1, datawc_x2) - ticks = prettifyAxisLabels(vcs.mklabels(ticks), x) - setattr(gm, 'xticlabels2', ticks) - dic['xticlabels2'] = True - # xmtics2 - if hasattr(gm, "xmtics2") and (gm.xmtics2 is None or gm.xmtics2 == '*'): - if copy_gm is None: - copy_gm = creategraphicsmethod(gm.g_name, gm.name) - gm = copy_gm - if x == "longitude" and abs(datawc_x2 - datawc_x1) > 30: - ticks = list(gm.xticlabels2.keys()) - else: - ticks = vcs.mkscale(datawc_x1, datawc_x2) - tick2 = [] - for i in range(len(ticks) - 1): - tick2.append((ticks[i] + ticks[i + 1]) / 2.) - ticks = prettifyAxisLabels(vcs.mklabels(tick2), x) - setattr(gm, 'xmtics2', ticks) - dic['xmtics2'] = True - # yticklabels1 - if gm.yticlabels1 is None or gm.yticlabels1 == '*': - if copy_gm is None: - copy_gm = creategraphicsmethod(gm.g_name, gm.name) - gm = copy_gm - if y == "latitude" and abs(datawc_y2 - datawc_y1) > 20: - ticks = "Lat20" - else: - ticks = vcs.mkscale(datawc_y1, datawc_y2) - ticks = prettifyAxisLabels(vcs.mklabels(ticks), y) - setattr(gm, 'yticlabels1', ticks) - dic['yticlabels1'] = True - # ymtics1 - if gm.ymtics1 is None or gm.ymtics1 == '*': - if copy_gm is None: - copy_gm = creategraphicsmethod(gm.g_name, gm.name) - gm = copy_gm - if y == "latitude" and abs(datawc_y2 - datawc_y1) > 20: - ticks = list(gm.yticlabels1.keys()) - else: - ticks = vcs.mkscale(datawc_y1, datawc_y2) - tick2 = [] - for i in range(len(ticks) - 1): - tick2.append((ticks[i] + ticks[i + 1]) / 2.) - ticks = prettifyAxisLabels(vcs.mklabels(tick2), y) - setattr(gm, 'ymtics1', ticks) - dic['ymtics1'] = True - # yticklabels2 - if hasattr(gm, "yticlabels2") and ( - gm.yticlabels2 is None or gm.yticlabels2 == '*'): - if copy_gm is None: - copy_gm = creategraphicsmethod(gm.g_name, gm.name) - gm = copy_gm - if y == "latitude" and abs(datawc_y2 - datawc_y1) > 20: - ticks = "Lat20" - else: - ticks = vcs.mkscale(datawc_y1, datawc_y2) - ticks = prettifyAxisLabels(vcs.mklabels(ticks), y) - setattr(gm, 'yticlabels2', ticks) - dic['yticlabels2'] = True - # ymtics2 - if hasattr(gm, "ymtics2") and (gm.ymtics2 is None or gm.ymtics2 == '*'): - if copy_gm is None: - copy_gm = creategraphicsmethod(gm.g_name, gm.name) - gm = copy_gm - if y == "latitude" and abs(datawc_y2 - datawc_y1) > 20: - ticks = list(gm.yticlabels2.keys()) - else: - ticks = vcs.mkscale(datawc_y1, datawc_y2) - tick2 = [] - for i in range(len(ticks) - 1): - tick2.append((ticks[i] + ticks[i + 1]) / 2.) - ticks = prettifyAxisLabels(vcs.mklabels(tick2), y) - setattr(gm, 'ymtics2', ticks) - dic['ymtics2'] = True + if copy_gm is None: + copy_gm = creategraphicsmethod(gm.g_name, gm.name) + gm = copy_gm + for location in ["x", "y"]: + for number in ["1", "2"]: + # ticklabels + lbls = getattr(gm, "{}ticlabels{}".format(location, number)) + if isinstance(lbls, basestring) and lbls != "*": + mticks = vcs.elements["list"][lbls] + if lbls is None or lbls == "*": + if location is "x" and x == "longitude" and abs( + datawc_x2 - datawc_x1) > 30: + ticks = transformTicks( + vcs.elements["list"]["Lon30"], x_forward) + elif location == "x" and x == "latitude" and abs(datawc_x2 - datawc_x1) > x_forward(20): + if gm.xaxisconvert == 'area_wt': + lats = vcs.elements["list"]["Lat_wt"] + else: + lats = vcs.elements["list"]["Lat20"] + ticks = transformTicks(lats, x_forward) + elif location == "y" and y == "latitude" and abs(datawc_y2 - datawc_y1) > y_forward(20): + if gm.yaxisconvert == 'area_wt': + lats = vcs.elements["list"]["Lat_wt"] + else: + lats = vcs.elements["list"]["Lat20"] + ticks = transformTicks(lats, y_forward) + else: + if location == "x": + ticks = vcs.mkscale(datawc_x1, datawc_x2) + ticks = vcs.mklabels(ticks) + if gm.xaxisconvert != "linear": + ticks = transformTicksLabels(ticks, x_invert) + ticks = prettifyAxisLabels(ticks, x) + else: + ticks = vcs.mkscale(datawc_y1, datawc_y2) + ticks = vcs.mklabels(ticks) + if gm.yaxisconvert != "linear": + ticks = transformTicksLabels(ticks, y_invert) + ticks = prettifyAxisLabels(ticks, y) + else: + if location == "x": + ticks = transformTicks(lbls, x_forward) + else: + ticks = transformTicks(lbls, y_forward) + setattr(copy_gm, '{}ticlabels{}'.format(location, number), ticks) + # mtics + mtics = getattr(gm, "{}mtics{}".format(location, number)) + if isinstance(mtics, basestring) and mtics not in ["*", ""]: + mtics = vcs.elements["list"][mtics] + if mtics is None or mtics in ['*', ""]: + if copy_gm is None: + copy_gm = creategraphicsmethod(gm.g_name, gm.name) + gm = copy_gm + if x == "longitude" and abs(datawc_x2 - datawc_x1) > 30: + ticks = transformTicks( + vcs.elements["list"]["lon5"], x_forward) + elif location == "x" and x == "latitude" and abs(datawc_x2 - datawc_x1) > x_forward(20): + lats = vcs.elements["list"]["lat5"] + ticks = transformTicks(lats, x_forward) + elif location == "y" and y == "latitude" and abs(datawc_y2 - datawc_y1) > y_forward(20): + lats = vcs.elements["list"]["lat5"] + ticks = transformTicks(lats, y_forward) + else: + rclass = type(cdtime.reltime(0, "days since 2020")) + if location == "x": + if isinstance(datawc_x1, rclass) or isinstance(datawc_x2, rclass): + ticks = mkscale(datawc_x1.value, datawc_x2.value) + else: + ticks = vcs.mkscale(datawc_x1, datawc_x2) + else: + if isinstance(datawc_y1, rclass) or isinstance(datawc_y2, rclass): + ticks = mkscale(datawc_y1.value, datawc_y2.value) + else: + ticks = vcs.mkscale(datawc_y1, datawc_y2) + tick2 = [] + for i in range(len(ticks) - 1): + tick2.append((ticks[i] + ticks[i + 1]) / 2.) + if location == "x": + ticks = prettifyAxisLabels(vcs.mklabels(tick2), x) + else: + ticks = prettifyAxisLabels(vcs.mklabels(tick2), y) + else: + if location == "x": + ticks = transformTicks(mtics, x_forward) + else: + ticks = transformTicks(mtics, y_forward) + setattr(copy_gm, '{}mtics{}'.format(location, number), ticks) + # Now we need to take care of user defined tics return copy_gm @@ -2654,8 +2662,16 @@ def drawLinesAndMarkersLegend(canvas, templateLegend, if backgroundcolor is not None: # Adding a fill area above the legends fa = canvas.createfillarea() - fa.x = [[templateLegend.x1, templateLegend.x2, templateLegend.x2, templateLegend.x1, templateLegend.x1]] - fa.y = [[templateLegend.y1, templateLegend.y1, templateLegend.y2, templateLegend.y2, templateLegend.y1]] + fa.x = [[templateLegend.x1, + templateLegend.x2, + templateLegend.x2, + templateLegend.x1, + templateLegend.x1]] + fa.y = [[templateLegend.y1, + templateLegend.y1, + templateLegend.y2, + templateLegend.y2, + templateLegend.y1]] fa.style = ["solid"] fa.color = backgroundcolor canvas.plot(fa) diff --git a/vcs/vcs2vtk.py b/vcs/vcs2vtk.py index 652a78b59..c924e72ed 100644 --- a/vcs/vcs2vtk.py +++ b/vcs/vcs2vtk.py @@ -599,13 +599,11 @@ def genGrid(data1, data2, gm, deep=True, grid=None, geo=None, genVectors=False, vcsContinents = {} -def prepContinents(fnm): +def prepContinents(fnm, xConvertFunction=lambda x: x, yConvertFunction=lambda y: y): """ This converts vcs continents files to vtkpolydata Author: Charles Doutriaux Input: vcs continent file name """ - if fnm in vcsContinents: - return vcsContinents[fnm] poly = vtk.vtkPolyData() cells = vtk.vtkCellArray() pts = vtk.vtkPoints() @@ -629,7 +627,9 @@ def prepContinents(fnm): l, L = float(sp[i * 2]), float(sp[i * 2 + 1]) spts.append([l, L]) for p in spts: - pts.InsertNextPoint(p[1], p[0], 0.) + x = xConvertFunction(p[1]) + y = yConvertFunction(p[0]) + pts.InsertNextPoint(x, y, 0.) n += sn didIt = True except Exception: @@ -637,7 +637,9 @@ def prepContinents(fnm): if didIt is False: while len(ln) > 2: l, L = float(ln[:8]), float(ln[8:16]) - pts.InsertNextPoint(L, l, 0.) + x = xConvertFunction(L) + y = yConvertFunction(l) + pts.InsertNextPoint(x, y, 0.) ln = ln[16:] n += 2 ln = vtk.vtkPolyLine() @@ -664,7 +666,6 @@ def prepContinents(fnm): clipper.Update() poly = clipper.GetOutput() - vcsContinents[fnm] = poly return poly diff --git a/vcs/vcsvtk/boxfillpipeline.py b/vcs/vcsvtk/boxfillpipeline.py index 38ef7baa1..6da55557c 100644 --- a/vcs/vcsvtk/boxfillpipeline.py +++ b/vcs/vcsvtk/boxfillpipeline.py @@ -17,8 +17,8 @@ class BoxfillPipeline(Pipeline2D): set of ivars (at minimum, identify what the mappers are rendering). """ - def __init__(self, gm, context_): - super(BoxfillPipeline, self).__init__(gm, context_) + def __init__(self, gm, context_, plot_keyargs): + super(BoxfillPipeline, self).__init__(gm, context_, plot_keyargs) self._contourLabels = None self._mappers = None @@ -28,7 +28,11 @@ def __init__(self, gm, context_): def _updateScalarData(self): """Overrides baseclass implementation.""" # Update data1 if this is a log10 boxfill: - data = self._originalData1 + data = self._originalData1.clone() + X = self.convertAxis(data.getAxis(-1), "x") + Y = self.convertAxis(data.getAxis(-2), "y") + data.setAxis(-1, X) + data.setAxis(-2, Y) if self._gm.boxfill_type == "log10": data = numpy.ma.log10(data) @@ -201,14 +205,14 @@ def _plotInternal(self): self.getColorMap(), **patternArgs)) - if self._context().canvas._continents is None: - self._useContinents = False - if self._useContinents: - projection = vcs.elements["projection"][self._gm.projection] - continents_renderer, xScale, yScale = self._context().plotContinents( - plotting_dataset_bounds, projection, - self._dataWrapModulo, - vp, self._template.data.priority, **kwargs) + projection = vcs.elements["projection"][self._gm.projection] + kwargs['xaxisconvert'] = self._gm.xaxisconvert + kwargs['yaxisconvert'] = self._gm.yaxisconvert + if self._data1.getAxis(-1).isLongitude() and self._data1.getAxis(-2).isLatitude(): + self._context().plotContinents(self._plot_kargs.get("continents", 1), + plotting_dataset_bounds, projection, + self._dataWrapModulo, + vp, self._template.data.priority, **kwargs) def _plotInternalBoxfill(self): """Implements the logic to render a non-custom boxfill.""" diff --git a/vcs/vcsvtk/isofillpipeline.py b/vcs/vcsvtk/isofillpipeline.py index 7667c14ed..4e0da88ac 100644 --- a/vcs/vcsvtk/isofillpipeline.py +++ b/vcs/vcsvtk/isofillpipeline.py @@ -10,8 +10,8 @@ class IsofillPipeline(Pipeline2D): """Implementation of the Pipeline interface for VCS isofill plots.""" - def __init__(self, gm, context_): - super(IsofillPipeline, self).__init__(gm, context_) + def __init__(self, gm, context_, plot_keyargs): + super(IsofillPipeline, self).__init__(gm, context_, plot_keyargs) self._needsCellData = False def _updateContourLevelsAndColors(self): @@ -227,11 +227,11 @@ def _plotInternal(self): pixelspacing=legendpixspacing, pixelscale=legendpixscale)) - if self._context().canvas._continents is None: - self._useContinents = False - if self._useContinents: - projection = vcs.elements["projection"][self._gm.projection] - continents_renderer, xScale, yScale = self._context().plotContinents( - plotting_dataset_bounds, projection, - self._dataWrapModulo, - vp, self._template.data.priority, **kwargs) + projection = vcs.elements["projection"][self._gm.projection] + kwargs['xaxisconvert'] = self._gm.xaxisconvert + kwargs['yaxisconvert'] = self._gm.yaxisconvert + if self._data1.getAxis(-1).isLongitude() and self._data1.getAxis(-2).isLatitude(): + self._context().plotContinents(self._plot_kargs.get("continents", 1), + plotting_dataset_bounds, projection, + self._dataWrapModulo, + vp, self._template.data.priority, **kwargs) diff --git a/vcs/vcsvtk/isolinepipeline.py b/vcs/vcsvtk/isolinepipeline.py index e85611b7e..213f17333 100644 --- a/vcs/vcsvtk/isolinepipeline.py +++ b/vcs/vcsvtk/isolinepipeline.py @@ -10,8 +10,8 @@ class IsolinePipeline(Pipeline2D): """Implementation of the Pipeline interface for VCS isoline plots.""" - def __init__(self, gm, context_): - super(IsolinePipeline, self).__init__(gm, context_) + def __init__(self, gm, context_, plot_keyargs): + super(IsolinePipeline, self).__init__(gm, context_, plot_keyargs) self._needsCellData = False def extendAttribute(self, attributes, default): @@ -307,11 +307,11 @@ def _plotInternal(self): self._data1, self._gm, t, z, **kwargs)) - if self._context().canvas._continents is None: - self._useContinents = False - if self._useContinents: - projection = vcs.elements["projection"][self._gm.projection] - continents_renderer, xScale, yScale = self._context().plotContinents( - plotting_dataset_bounds, projection, - self._dataWrapModulo, - vp, self._template.data.priority, **kwargs) + projection = vcs.elements["projection"][self._gm.projection] + kwargs['xaxisconvert'] = self._gm.xaxisconvert + kwargs['yaxisconvert'] = self._gm.yaxisconvert + if self._data1.getAxis(-1).isLongitude() and self._data1.getAxis(-2).isLatitude(): + self._context().plotContinents(self._plot_kargs.get("continents", 1), + plotting_dataset_bounds, projection, + self._dataWrapModulo, + vp, self._template.data.priority, **kwargs) diff --git a/vcs/vcsvtk/meshfillpipeline.py b/vcs/vcsvtk/meshfillpipeline.py index fff3d1148..d551c794f 100644 --- a/vcs/vcsvtk/meshfillpipeline.py +++ b/vcs/vcsvtk/meshfillpipeline.py @@ -11,8 +11,8 @@ class MeshfillPipeline(Pipeline2D): """Implementation of the Pipeline interface for VCS meshfill plots.""" - def __init__(self, gm, context_): - super(MeshfillPipeline, self).__init__(gm, context_) + def __init__(self, gm, context_, plot_keyargs): + super(MeshfillPipeline, self).__init__(gm, context_, plot_keyargs) self._needsCellData = True @@ -20,7 +20,13 @@ def _updateScalarData(self): """Overrides baseclass implementation.""" # We don't trim _data2 for meshfill: self._data1 = self._context().trimData2D(self._originalData1) + _convert = self._gm.yaxisconvert + _func = vcs.utils.axisConvertFunctions[_convert]["forward"] self._data2 = self._originalData2 + self._data2[..., 0, :] = _func(self._data2[..., 0, :]) + _convert = self._gm.xaxisconvert + _func = vcs.utils.axisConvertFunctions[_convert]["forward"] + self._data2[..., 1, :] = _func(self._data2[..., 1, :]) def _updateContourLevelsAndColors(self): self._updateContourLevelsAndColorsGeneric() @@ -42,6 +48,15 @@ def _plotInternal(self): wholeDataMin, wholeDataMax = vcs.minmax(self._originalData1) plotting_dataset_bounds = self.getPlottingBounds() x1, x2, y1, y2 = plotting_dataset_bounds + # We need to do the convertion thing + _convert = self._gm.yaxisconvert + _func = vcs.utils.axisConvertFunctions[_convert]["forward"] + y1 = _func(y1) + y2 = _func(y2) + _convert = self._gm.xaxisconvert + _func = vcs.utils.axisConvertFunctions[_convert]["forward"] + x1 = _func(x1) + x2 = _func(x2) _colorMap = self.getColorMap() for i, l in enumerate(tmpLevels): # Ok here we are trying to group together levels can be, a join @@ -272,14 +287,13 @@ def _plotInternal(self): self.getColorMap(), **patternArgs)) - if self._context().canvas._continents is None: - self._useContinents = False - if self._useContinents: - projection = vcs.elements["projection"][self._gm.projection] - continents_renderer, xScale, yScale = self._context().plotContinents( - plotting_dataset_bounds, projection, - self._dataWrapModulo, - vp, self._template.data.priority, **kwargs) + projection = vcs.elements["projection"][self._gm.projection] + kwargs['xaxisconvert'] = self._gm.xaxisconvert + kwargs['yaxisconvert'] = self._gm.yaxisconvert + self._context().plotContinents(self._plot_kargs.get("continents", 1), + plotting_dataset_bounds, projection, + self._dataWrapModulo, + vp, self._template.data.priority, **kwargs) def getPlottingBounds(self): """gm.datawc if it is set or dataset_bounds diff --git a/vcs/vcsvtk/pipeline.py b/vcs/vcsvtk/pipeline.py index 0954fa79d..4cd87c698 100644 --- a/vcs/vcsvtk/pipeline.py +++ b/vcs/vcsvtk/pipeline.py @@ -1,5 +1,6 @@ import weakref import vcs +import cdms2 class Pipeline(object): @@ -10,7 +11,7 @@ class Pipeline(object): VTK plot command. Refer to the method documentation for details. """ - def __init__(self, graphics_method, context_): + def __init__(self, graphics_method, context_, plot_keyargs): """Initialize the pipeline object. _gm is a vcs graphics method @@ -19,12 +20,31 @@ def __init__(self, graphics_method, context_): """ self._context = weakref.ref(context_) self._gm = graphics_method + self._plot_kargs = plot_keyargs # For now, we'll just throw everything at plot. This might need to be # broken up into set_data, set_template, etc methods... def plot(self, data1, data2, template, grid, transform, **kargs): raise NotImplementedError("Missing override.") + def convertAxis(self, axis, location): + """Convert axis to log/area_wgt, etc...""" + _convert = getattr( + self._gm, + "{}axisconvert".format(location), + "linear") + _bounds = axis.getBounds() + _func = vcs.utils.axisConvertFunctions[_convert]["forward"] + _axis = _func(axis[:]) + _axis = cdms2.createAxis(_axis, id=axis.id) + if _bounds is not None: + _bounds = _func(_bounds) + _axis.setBounds(_bounds) + if hasattr(axis, "units"): + _axis.units = axis.units + + return _axis + def getColorMap(self): _colorMap = self._gm.colormap if _colorMap is None: @@ -47,17 +67,22 @@ def _processRatioAutot(self, template, dataset): datasetBounds = dataset.GetBounds() windowSize = self._context().renWin.GetSize() - ratio = (datasetBounds[1] - datasetBounds[0]) / (datasetBounds[3] - datasetBounds[2]) + ratio = (datasetBounds[1] - datasetBounds[0]) / \ + (datasetBounds[3] - datasetBounds[2]) ratioWindow = (viewportBounds[1] - viewportBounds[0]) * windowSize[0] /\ (viewportBounds[3] - viewportBounds[2]) / windowSize[1] if (ratio > ratioWindow): - yMiddle = (viewportBounds[2] + viewportBounds[3]) * windowSize[1] / 2 - ySizeHalf = (viewportBounds[1] - viewportBounds[0]) * windowSize[0] / ratio / 2 + yMiddle = (viewportBounds[2] + + viewportBounds[3]) * windowSize[1] / 2 + ySizeHalf = ( + viewportBounds[1] - viewportBounds[0]) * windowSize[0] / ratio / 2 viewportBounds[2] = (yMiddle - ySizeHalf) / windowSize[1] viewportBounds[3] = (yMiddle + ySizeHalf) / windowSize[1] elif (ratio < ratioWindow): - xMiddle = (viewportBounds[0] + viewportBounds[1]) * windowSize[0] / 2 - xSizeHalf = (viewportBounds[3] - viewportBounds[2]) * windowSize[1] * ratio / 2 + xMiddle = (viewportBounds[0] + + viewportBounds[1]) * windowSize[0] / 2 + xSizeHalf = ( + viewportBounds[3] - viewportBounds[2]) * windowSize[1] * ratio / 2 viewportBounds[0] = (xMiddle - xSizeHalf) / windowSize[0] viewportBounds[1] = (xMiddle + xSizeHalf) / windowSize[0] return viewportBounds diff --git a/vcs/vcsvtk/pipeline1d.py b/vcs/vcsvtk/pipeline1d.py index 5f758fc80..e53980528 100644 --- a/vcs/vcsvtk/pipeline1d.py +++ b/vcs/vcsvtk/pipeline1d.py @@ -2,6 +2,7 @@ import numpy import vcs +import cdms2 def smooth(x, beta, window_len=11): @@ -18,15 +19,20 @@ class Pipeline1D(Pipeline): """Implementation of the Pipeline interface for 1D VCS plots.""" - def __init__(self, gm, context_): - super(Pipeline1D, self).__init__(gm, context_) + def __init__(self, gm, context_, plot_keyargs): + super(Pipeline1D, self).__init__(gm, context_, plot_keyargs) def plot(self, data1, data2, tmpl, grid, transform, **kargs): """Overrides baseclass implementation.""" Y = self._context().trimData1D(data1) + data = data1 # For template if data2 is None: X = Y.getAxis(0) else: + data = data2 + if self._gm.flip: + raise RuntimeError("You cannot use the flip option on 1D graphic methods" + + " if you are passing 2 arrays, please reverse order of arrays") X = Y data1._yname = data2.id Y = self._context().trimData1D(data2) @@ -36,8 +42,10 @@ def plot(self, data1, data2, tmpl, grid, transform, **kargs): Y = X X = tmp + X = self.convertAxis(cdms2.createAxis(X), "x") if self._gm.smooth is not None: Y = smooth(Y, self._gm.smooth) + Y = self.convertAxis(cdms2.createAxis(Y), "y") ln_tmp = self._context().canvas.createline() Xs = X[:].tolist() @@ -76,12 +84,22 @@ def plot(self, data1, data2, tmpl, grid, transform, **kargs): # Also need to make sure it fills the whole space x1, x2, y1, y2 = vcs.utils.getworldcoordinates(self._gm, X, Y) + if (y1 > y2) and numpy.allclose(self._gm.datawc_y1, 1.E20): + tmp = y1 + y1 = y2 + y2 = tmp + + self._gm.datawc_x1 = x1 + self._gm.datawc_x2 = x2 + self._gm.datawc_y1 = y1 + self._gm.datawc_y2 = y2 if numpy.allclose(y1, y2): y1 -= .0001 y2 += .0001 if numpy.allclose(x1, x2): x1 -= .0001 x2 += .0001 + ln_tmp._worldcoordinate = [x1, x2, y1, y2] if self._gm.marker is not None: m = self._context().canvas.createmarker() @@ -106,7 +124,7 @@ def plot(self, data1, data2, tmpl, grid, transform, **kargs): ren2 = self._context().createRenderer() self._context().setLayer(ren2, ln_tmp.priority) self._context().renWin.AddRenderer(ren2) - tmpl.plot(self._context().canvas, data1, self._gm, bg=self._context().bg, + tmpl.plot(self._context().canvas, data, self._gm, bg=self._context().bg, renderer=ren2, X=X, Y=Y) if hasattr(data1, "_yname"): del(data1._yname) diff --git a/vcs/vcsvtk/pipeline2d.py b/vcs/vcsvtk/pipeline2d.py index 83f2196d9..54f1a9ed1 100644 --- a/vcs/vcsvtk/pipeline2d.py +++ b/vcs/vcsvtk/pipeline2d.py @@ -60,8 +60,8 @@ class IPipeline2D(Pipeline): - _maskedDataMapper: The mapper used to render masked data. """ - def __init__(self, gm, context_): - super(IPipeline2D, self).__init__(gm, context_) + def __init__(self, gm, context_, plot_keyargs): + super(IPipeline2D, self).__init__(gm, context_, plot_keyargs) # TODO This should be replaced by getters that retrieve the info # needed, or document the members of the map somewhere. Much of this @@ -173,8 +173,8 @@ class Pipeline2D(IPipeline2D): """Common VTK pipeline functionality for 2D VCS plot.""" - def __init__(self, gm, context_): - super(Pipeline2D, self).__init__(gm, context_) + def __init__(self, gm, context_, plot_keyargs): + super(Pipeline2D, self).__init__(gm, context_, plot_keyargs) def _patternCreation(self, vtkFilter, color, style, index, opacity): """ Creates pattern things """ @@ -329,7 +329,12 @@ def plot(self, data1, data2, tmpl, grid, transform, **kargs): def _updateScalarData(self): """Overrides baseclass implementation.""" - self._data1 = self._context().trimData2D(self._originalData1) + data1 = self._originalData1.clone() + X = self.convertAxis(data1.getAxis(-1), "x") + Y = self.convertAxis(data1.getAxis(-2), "y") + data1.setAxis(-1, X) + data1.setAxis(-2, Y) + self._data1 = self._context().trimData2D(data1) self._data2 = self._context().trimData2D(self._originalData2) def _updateVTKDataSet(self, plotBasedDualGrid): diff --git a/vcs/vcsvtk/pipelinefactory.py b/vcs/vcsvtk/pipelinefactory.py index 27055f996..8edc05779 100644 --- a/vcs/vcsvtk/pipelinefactory.py +++ b/vcs/vcsvtk/pipelinefactory.py @@ -1,7 +1,7 @@ import vcs -def createPipeline(graphics_method, context): +def createPipeline(graphics_method, context, plot_keyargs): """Create and initialize a Pipeline subclass from a graphics method. Returns None if the graphics method is not recognized. @@ -11,24 +11,24 @@ def createPipeline(graphics_method, context): if graphics_method.g_name == "Gfb": from .boxfillpipeline import BoxfillPipeline - return BoxfillPipeline(graphics_method, context) + return BoxfillPipeline(graphics_method, context, plot_keyargs) elif graphics_method.g_name == "Gfi": from .isofillpipeline import IsofillPipeline - return IsofillPipeline(graphics_method, context) + return IsofillPipeline(graphics_method, context, plot_keyargs) elif graphics_method.g_name == "Gi": from .isolinepipeline import IsolinePipeline - return IsolinePipeline(graphics_method, context) + return IsolinePipeline(graphics_method, context, plot_keyargs) elif graphics_method.g_name == "Gfm": from .meshfillpipeline import MeshfillPipeline - return MeshfillPipeline(graphics_method, context) + return MeshfillPipeline(graphics_method, context, plot_keyargs) elif graphics_method.g_name == "G1d": from .pipeline1d import Pipeline1D - return Pipeline1D(graphics_method, context) + return Pipeline1D(graphics_method, context, plot_keyargs) elif graphics_method.g_name == "Gv": from .vectorpipeline import VectorPipeline - return VectorPipeline(graphics_method, context) + return VectorPipeline(graphics_method, context, plot_keyargs) elif graphics_method.g_name == "Gs": from .streamlinepipeline import StreamlinePipeline - return StreamlinePipeline(graphics_method, context) + return StreamlinePipeline(graphics_method, context, plot_keyargs) return None diff --git a/vcs/vcsvtk/streamlinepipeline.py b/vcs/vcsvtk/streamlinepipeline.py index 10beaa77f..68d9e8193 100644 --- a/vcs/vcsvtk/streamlinepipeline.py +++ b/vcs/vcsvtk/streamlinepipeline.py @@ -10,8 +10,8 @@ class StreamlinePipeline(Pipeline2D): """Implementation of the Pipeline interface for VCS streamline plots.""" - def __init__(self, gm, context_): - super(StreamlinePipeline, self).__init__(gm, context_) + def __init__(self, gm, context_, plot_keyargs): + super(StreamlinePipeline, self).__init__(gm, context_, plot_keyargs) self._needsCellData = False self._needsVectors = True @@ -255,11 +255,10 @@ def _plotInternal(self): None, self.getColorMap())) - if self._context().canvas._continents is None: - self._useContinents = False - if self._useContinents: - continents_renderer, xScale, yScale = self._context().plotContinents( - plotting_dataset_bounds, projection, - self._dataWrapModulo, vp, self._template.data.priority, **kwargs) + if self._data1.getAxis(-1).isLongitude() and self._data1.getAxis(-2).isLatitude(): + self._context().plotContinents(self._plot_kargs.get("continents", 1), + plotting_dataset_bounds, projection, + self._dataWrapModulo, vp, + self._template.data.priority, **kwargs) self._resultDict["vtk_backend_actors"] = [[act, plotting_dataset_bounds]] self._resultDict["vtk_backend_luts"] = [[None, None]] diff --git a/vcs/vcsvtk/vectorpipeline.py b/vcs/vcsvtk/vectorpipeline.py index d3fd442aa..32b09d15b 100644 --- a/vcs/vcsvtk/vectorpipeline.py +++ b/vcs/vcsvtk/vectorpipeline.py @@ -9,8 +9,8 @@ class VectorPipeline(Pipeline2D): """Implementation of the Pipeline interface for VCS vector plots.""" - def __init__(self, gm, context_): - super(VectorPipeline, self).__init__(gm, context_) + def __init__(self, gm, context_, plot_keyargs): + super(VectorPipeline, self).__init__(gm, context_, plot_keyargs) self._needsCellData = False self._needsVectors = True @@ -205,12 +205,13 @@ def _plotInternal(self): self._context().canvas, self._template.legend, lcolor, lstyle, lwidth, unitString, maxNormInVp, maxNorm, minNormInVp, minNorm) - if self._context().canvas._continents is None: - self._useContinents = False - if self._useContinents: - continents_renderer, xScale, yScale = self._context().plotContinents( - plotting_dataset_bounds, projection, - self._dataWrapModulo, vp, self._template.data.priority, **kwargs) + kwargs['xaxisconvert'] = self._gm.xaxisconvert + kwargs['yaxisconvert'] = self._gm.yaxisconvert + if self._data1.getAxis(-1).isLongitude() and self._data1.getAxis(-2).isLatitude(): + self._context().plotContinents(self._plot_kargs.get("continents", 1), + plotting_dataset_bounds, projection, + self._dataWrapModulo, vp, + self._template.data.priority, **kwargs) self._resultDict["vtk_backend_actors"] = [[act, plotting_dataset_bounds]] self._resultDict["vtk_backend_glyphfilters"] = [glyphFilter] self._resultDict["vtk_backend_luts"] = [[None, None]]