source: trunk/UTIL/PYTHON/planetoplot_v2/ppplot.py @ 928

Last change on this file since 928 was 928, checked in by aslmd, 12 years ago

UTIL PYTHON planetoplot_v2. possibility to draw negative-like plots.

File size: 26.6 KB
Line 
1###############################################
2## PLANETOPLOT                               ##
3## --> PPPLOT                                ##
4###############################################
5## Author: Aymeric Spiga. 02-03/2013         ##
6###############################################
7# python built-in librairies
8import time as timelib
9# added librairies
10import numpy as np
11import matplotlib.pyplot as mpl
12from matplotlib.cm import get_cmap
13from mpl_toolkits.basemap import Basemap
14# personal librairies
15import ppcompute
16###############################################
17
18#################################
19# global variables and settings #
20#################################
21
22# matplotlib settings
23# http://matplotlib.org/users/customizing.html
24# -------------------------------
25mpl.rcParams['font.family'] = "serif"
26mpl.rcParams['axes.color_cycle'] = "r,g,b,k"
27mpl.rcParams['contour.negative_linestyle'] = "dashed" # ou "solid"
28mpl.rcParams['verbose.level'] = "silent"
29mpl.rcParams['lines.linewidth'] = 1.5
30mpl.rcParams['lines.markersize'] = 10
31mpl.rcParams['xtick.major.pad'] = 10
32mpl.rcParams['ytick.major.pad'] = 10
33
34# global variables
35# -------------------------------
36# - where settings files are located
37#   (None means planetoplot_v2 in PYTHONPATH)
38whereset = None
39# - some good default settings.
40# (bounds)
41how_many_sigma = 3.0 
42# (contours)
43ccol = 'black'
44cline = 0.55
45# (vectors)
46widthvec = 0.002
47reducevec = 30.
48# (colorbar)
49zeorientation="vertical"
50zefrac = 0.05
51# (save figures)
52pad_inches_value=0.25
53# (negative mode)
54def_negative = False
55def_negative = True
56###############################################
57
58### settings for 'negative-like' mode
59if def_negative:
60    mpl.rc('figure', facecolor='k', edgecolor='k')
61    mpl.rcParams['text.color'] = 'w'
62    mpl.rc('axes',labelcolor='w',facecolor='k',edgecolor='w')
63    mpl.rcParams['xtick.color'] = 'w'
64    mpl.rcParams['ytick.color'] = 'w'
65    mpl.rcParams['grid.color'] = 'w'
66    mpl.rc('savefig',facecolor='k',edgecolor='k')
67
68##########################
69# executed when imported #
70##########################
71###########################################
72# we load user-defined automatic settings #
73###########################################
74# initialize the warning variable about file not present...
75files_not_present = ""
76# ... and the whereset variable
77whereset = ppcompute.findset(whereset)
78
79# - variable settings
80# -------------------------------
81zefile = "set_var.txt"
82vf = {} ; vc = {} ; vl = {}
83try: 
84    f = open(whereset+zefile, 'r')
85    for line in f:
86        if "#" in line: pass
87        else:
88            var, format, colorb, label = line.strip().split(';')
89            ind = var.strip() 
90            vf[ind] = format.strip()
91            vc[ind] = colorb.strip()
92            vl[ind] = label.strip()
93    f.close()
94except IOError: 
95    files_not_present = files_not_present + zefile + " "
96
97## - file settings
98## -------------------------------
99#zefile = "set_file.txt"
100#prefix_t = {} ; suffix_t = {} ; name_t = {} ; proj_t = {} ; vecx_t = {} ; vecy_t = {}
101#try:
102#    f = open(whereset+zefile, 'r')
103#    for line in f:
104#        if "#" in line: pass
105#        else:
106#            prefix, suffix, name, proj, vecx, vecy = line.strip().split(';')
107#            ind = name.strip()
108#            prefix_t[ind] = prefix.strip()
109#            suffix_t[ind] = suffix.strip()
110#            #name_t[ind] = name.strip()
111#            proj_t[ind] = proj.strip()
112#            vecx_t[ind] = vecx.strip()
113#            vecy_t[ind] = vecy.strip()
114#    f.close()
115#except IOError:
116#    files_not_present = files_not_present + zefile + " "
117
118# - multiplot settings
119# -------------------------------
120zefile = "set_multiplot.txt"
121subv_t = {} ; subh_t = {} ; wspace_t = {} ; hspace_t = {} ; font_t = {}
122try:
123    f = open(whereset+zefile, 'r')
124    for line in f:
125        if "#" in line: pass
126        else:
127            num, subv, subh, wspace, hspace, font = line.strip().split(';')
128            ind = int(num.strip())
129            subv_t[ind] = int(subv.strip())
130            subh_t[ind] = int(subh.strip())
131            wspace_t[ind] = float(wspace.strip())
132            hspace_t[ind] = float(hspace.strip())
133            font_t[ind] = float(font.strip())
134    f.close()
135except IOError:
136    files_not_present = files_not_present + zefile + " "
137
138# - background settings
139# -------------------------------
140zefile = "set_back.txt"
141back = {}
142try:
143    f = open(whereset+zefile, 'r')
144    for line in f:
145        if "#" in line: pass
146        else:
147            name, link = line.strip().split(';')
148            ind = name.strip() 
149            back[ind] = link.strip()
150    f.close()
151except IOError:
152    files_not_present = files_not_present + zefile + " "
153
154# - area settings
155# -------------------------------
156zefile = "set_area.txt"
157area = {}
158try:
159    f = open(whereset+zefile, 'r')
160    for line in f:
161        if "#" in line: pass
162        else:
163            name, wlat1, wlat2, wlon1, wlon2 = line.strip().split(';')
164            area[name.strip()] = [[float(wlon1.strip()),float(wlon2.strip())],\
165                                  [float(wlat1.strip()),float(wlat2.strip())]]
166    f.close()
167except IOError:
168    files_not_present = files_not_present + zefile + " "
169# A note to the user about missing files
170if files_not_present != "":
171    print "warning: files "+files_not_present+" not in "+whereset+" ; those presets will be missing"
172
173# TBD: should change vector color with colormaps
174#"gist_heat":    "white",\
175#"hot":          "white",\
176#"gray":         "red",\
177
178####################
179# useful functions #
180####################
181
182# a function to define subplot
183# ... user can change settings in set_multiplot.txt read above
184# -------------------------------
185def definesubplot(numplot, fig):
186    try: 
187        mpl.rcParams['font.size'] = font_t[numplot]
188    except: 
189        mpl.rcParams['font.size'] = 18
190    try: 
191        fig.subplots_adjust(wspace = wspace_t[numplot], hspace = hspace_t[numplot])
192        subv, subh = subv_t[numplot],subh_t[numplot]
193    except: 
194        print "!! WARNING !! no preset found from set_multiplot.txt, or this setting file was not found."
195        subv = 1 ; subh = numplot
196    return subv,subh
197
198# a function to calculate automatically bounds (or simply prescribe those)
199# -------------------------------
200def calculate_bounds(field,vmin=None,vmax=None):
201    # prescribed cases first
202    zevmin = vmin
203    zevmax = vmax
204    # computed cases
205    if zevmin is None or zevmax is None:
206       # select values
207       ind = np.where(field < 9e+35)
208       fieldcalc = field[ ind ] # field must be a numpy array
209       # calculate stdev and mean
210       dev = np.std(fieldcalc)*how_many_sigma
211       damean = ppcompute.mean(fieldcalc)
212       # fill min/max if needed
213       if vmin is None: zevmin = damean - dev
214       if vmax is None: zevmax = damean + dev
215       # special case: negative values with stddev while field is positive
216       if zevmin < 0. and ppcompute.min(fieldcalc) > 0.: zevmin = 0.
217    # check that bounds are not too tight given the field
218    amin = ppcompute.min(field)
219    amax = ppcompute.max(field)
220    cmin = 100.*np.abs((amin - zevmin)/amin)
221    cmax = 100.*np.abs((amax - zevmax)/amax)
222    if cmin > 150. or cmax > 150.:
223        print "!! WARNING !! Bounds are a bit too tight. Might need to reconsider those."
224        print "!! WARNING !! --> actual",amin,amax,"adopted",zevmin,zevmax
225    return zevmin, zevmax   
226    #### treat vmin = vmax for continuity
227    #if vmin == vmax:  zevmin = damean - dev ; zevmax = damean + dev
228
229# a function to solve the problem with blank bounds !
230# -------------------------------
231def bounds(what_I_plot,zevmin,zevmax,miss=9e+35):
232    small_enough = 1.e-7
233    if zevmin < 0: what_I_plot[ what_I_plot < zevmin*(1.-small_enough) ] = zevmin*(1.-small_enough)
234    else:          what_I_plot[ what_I_plot < zevmin*(1.+small_enough) ] = zevmin*(1.+small_enough)
235    what_I_plot[ what_I_plot > miss  ] = -miss
236    what_I_plot[ what_I_plot > zevmax ] = zevmax*(1.-small_enough)
237    return what_I_plot
238
239# a generic function to show (GUI) or save a plot (PNG,EPS,PDF,...)
240# -------------------------------
241def save(mode="gui",filename="plot",folder="./",includedate=True,res=150,custom=False):
242    # a few settings
243    possiblesave = ['eps','ps','svg','png','jpg','pdf'] 
244    # now the main instructions
245    if mode == "gui": 
246        mpl.show()
247    elif mode in possiblesave:
248        ## name of plot
249        name = folder+'/'+filename
250        if includedate:
251            for ttt in timelib.gmtime():
252                name = name + "_" + str(ttt)
253        name = name +"."+mode
254        ## save file
255        print "**** Saving file in "+mode+" format... Please wait."
256        if not custom:
257            # ... regular plots
258            mpl.savefig(name,dpi=res,pad_inches=pad_inches_value,bbox_inches='tight')
259        else:
260            # ... mapping mode, adapted space for labels etc...
261            mpl.savefig(name,dpi=res)
262    else:
263        print "!! ERROR !! File format not supported. Supported: ",possiblesave
264
265##################################
266# a generic class to make a plot #
267##################################
268class plot():
269
270    # print out a help string when help is invoked on the object
271    # -------------------------------
272    def __repr__(self):
273        whatprint = 'plot object. \"help(plot)\" for more information\n'
274        return whatprint
275
276    # default settings
277    # -- user can define settings by two methods.
278    # -- 1. yeah = plot2d(title="foo")
279    # -- 2. yeah = pp() ; yeah.title = "foo"
280    # -------------------------------
281    def __init__(self,\
282                 var=None,\
283                 field=None,\
284                 absc=None,\
285                 xlabel="",\
286                 ylabel="",\
287                 div=20,\
288                 logx=False,\
289                 logy=False,\
290                 swap=False,\
291                 swaplab=True,\
292                 invert=False,\
293                 xcoeff=1.,\
294                 ycoeff=1.,\
295                 title=""):
296        ## what could be defined by the user
297        self.var = var
298        self.field = field
299        self.absc = absc
300        self.xlabel = xlabel
301        self.ylabel = ylabel
302        self.title = title
303        self.div = div
304        self.logx = logx
305        self.logy = logy
306        self.swap = swap
307        self.swaplab = swaplab # NB: swaplab only used if swap=True
308        self.invert = invert
309        self.xcoeff = xcoeff
310        self.ycoeff = ycoeff
311        ## other useful arguments
312        ## ... not used here in ppplot but need to be attached to plot object
313        self.axisbg = "white"
314        self.superpose = False
315
316    # check
317    # -------------------------------
318    def check(self):
319        if self.field is None: print "!! ERROR !! Please define a field to be plotted" ; exit()
320
321    # define_from_var
322    # ... this uses settings in set_var.txt
323    # -------------------------------
324    def define_from_var(self):
325        if self.var is not None:
326         if self.var.upper() in vl.keys():
327          self.title = vl[self.var.upper()]
328
329    # make
330    # this is generic to all plots
331    # -------------------------------
332    def make(self):
333        self.check()
334        # labels, title, etc...
335        mpl.xlabel(self.xlabel)
336        mpl.ylabel(self.ylabel)
337        if self.swap:
338         if self.swaplab:
339           mpl.xlabel(self.ylabel)
340           mpl.ylabel(self.xlabel)
341        mpl.title(self.title)
342        # if masked array, set masked values to filled values (e.g. np.nan) for plotting purposes
343        if type(self.field).__name__ in 'MaskedArray':
344            self.field[self.field.mask] = self.field.fill_value
345
346################################
347# a subclass to make a 1D plot #
348################################
349class plot1d(plot):
350
351    # print out a help string when help is invoked on the object
352    # -------------------------------
353    def __repr__(self):
354        whatprint = 'plot1d object. \"help(plot1d)\" for more information\n'
355        return whatprint
356
357    # default settings
358    # -- user can define settings by two methods.
359    # -- 1. yeah = plot1d(title="foo")
360    # -- 2. yeah = pp() ; yeah.title = "foo"
361    # -------------------------------
362    def __init__(self,\
363                 lstyle='-',\
364                 color='b',\
365                 marker='x',\
366                 label=None):
367        ## get initialization from parent class
368        plot.__init__(self)
369        ## what could be defined by the user
370        self.lstyle = lstyle
371        self.color = color
372        self.marker = marker
373        self.label = label
374
375    # define_from_var
376    # ... this uses settings in set_var.txt
377    # -------------------------------
378    def define_from_var(self):
379        # get what is done in the parent class
380        plot.define_from_var(self)
381        # add specific stuff
382        if self.var is not None:
383         if self.var.upper() in vl.keys():
384          self.ylabel = vl[self.var.upper()]
385          self.title = ""
386
387    # make
388    # -------------------------------
389    def make(self):
390        # get what is done in the parent class
391        plot.make(self)
392        # add specific stuff
393        mpl.grid(color='grey')
394        if self.lstyle == "": self.lstyle = " " # to allow for no line at all with ""
395        # swapping if requested
396        if self.swap:  x = self.field ; y = self.absc
397        else:          x = self.absc ; y = self.field
398        # coefficients on axis
399        x=x*self.xcoeff ; y=y*self.ycoeff
400        # check axis
401        if x.size != y.size:
402            print "!! ERROR !! x and y sizes don't match on 1D plot.", x.size, y.size
403            exit()
404        # make the 1D plot
405        # either request linestyle or let matplotlib decide
406        if self.lstyle is not None and self.color is not None:
407            mpl.plot(x,y,self.color+self.lstyle,marker=self.marker,label=self.label)
408        else:
409            mpl.plot(x,y,marker=self.marker,label=self.label)
410        # make log axes and/or invert ordinate
411        # ... this must be after plot so that axis bounds are well-defined
412        # ... also inverting must be after making the thing logarithmic
413        if self.logx: mpl.semilogx()
414        if self.logy: mpl.semilogy()
415        if self.invert: ax = mpl.gca() ; ax.set_ylim(ax.get_ylim()[::-1])
416        # add a label for line(s)
417        if self.label is not None:
418            if self.label != "":
419                mpl.legend(loc="best",fancybox=True)
420        ## TBD: set with .div the number of ticks
421        ## TBD: be able to control plot limits
422        #ticks = self.div + 1
423        #ax = mpl.gca()
424        #ax.get_xaxis().set_ticks(np.linspace(ppcompute.min(x),ppcompute.max(x),ticks/2+1))
425
426################################
427# a subclass to make a 2D plot #
428################################
429class plot2d(plot):
430
431    # print out a help string when help is invoked on the object
432    # -------------------------------
433    def __repr__(self):
434        whatprint = 'plot2d object. \"help(plot2d)\" for more information\n'
435        return whatprint
436
437    # default settings
438    # -- user can define settings by two methods.
439    # -- 1. yeah = plot2d(title="foo")
440    # -- 2. yeah = pp() ; yeah.title = "foo"
441    # -------------------------------
442    def __init__(self,\
443                 ordi=None,\
444                 mapmode=False,\
445                 proj="cyl",\
446                 back=None,\
447                 colorb="jet",\
448                 trans=1.0,\
449                 addvecx=None,\
450                 addvecy=None,\
451                 addcontour=None,\
452                 fmt="%.2e",\
453                 blon=None,\
454                 blat=None,\
455                 area=None,\
456                 vmin=None,\
457                 vmax=None,\
458                 colorvec="black"):
459        ## get initialization from parent class
460        plot.__init__(self)
461        ## what could be defined by the user
462        self.ordi = ordi
463        self.mapmode = mapmode
464        self.proj = proj
465        self.back = back
466        self.colorb = colorb
467        self.trans = trans
468        self.addvecx = addvecx
469        self.addvecy = addvecy
470        self.colorvec = colorvec
471        self.addcontour = addcontour
472        self.fmt = fmt
473        self.blon = blon ; self.blat = blat
474        self.area = area
475        self.vmin = vmin ; self.vmax = vmax
476
477    # define_from_var
478    # ... this uses settings in set_var.txt
479    # -------------------------------
480    def define_from_var(self):
481        # get what is done in the parent class
482        plot.define_from_var(self)
483        # add specific stuff
484        if self.var is not None:
485         if self.var.upper() in vl.keys():
486          self.colorb = vc[self.var.upper()]
487          self.fmt = vf[self.var.upper()]
488
489    # make
490    # -------------------------------
491    def make(self):
492        # get what is done in the parent class...
493        plot.make(self)
494        # ... then add specific stuff
495        ############################################################################################
496        ### PRE-SETTINGS
497        ############################################################################################
498        # transposing if necessary
499        shape = self.field.shape
500        if shape[0] != shape[1]:
501         if len(self.absc) == shape[0] and len(self.ordi) == shape[1]:
502            print "!! WARNING !! Transposing axes"
503            self.field = np.transpose(self.field)
504        # bound field
505        zevmin, zevmax = calculate_bounds(self.field,vmin=self.vmin,vmax=self.vmax)
506        what_I_plot = bounds(self.field,zevmin,zevmax)
507        # define contour field levels. define color palette
508        ticks = self.div + 1
509        zelevels = np.linspace(zevmin,zevmax,ticks)
510        palette = get_cmap(name=self.colorb)
511        # do the same thing for possible contourline entries
512        if self.addcontour is not None:
513            # if masked array, set masked values to filled values (e.g. np.nan) for plotting purposes
514            if type(self.addcontour).__name__ in 'MaskedArray':
515               self.addcontour[self.addcontour.mask] = self.addcontour.fill_value
516            zevminc, zevmaxc = calculate_bounds(self.addcontour)
517            what_I_contour = bounds(self.addcontour,zevminc,zevmaxc)
518            ticks = self.div + 1
519            zelevelsc = np.linspace(zevminc,zevmaxc,ticks)
520        ############################################################################################
521        ### MAIN PLOT
522        ### NB: contour lines are done before contour shades otherwise colorar error
523        ############################################################################################
524        if not self.mapmode:
525            ## A SIMPLE 2D PLOT
526            ###################
527            # swapping if requested
528            if self.swap:  x = self.ordi ; y = self.absc
529            else:          x = self.absc ; y = self.ordi
530            # coefficients on axis
531            x=x*self.xcoeff ; y=y*self.ycoeff
532            # make shaded and line contours
533            if self.addcontour is not None: 
534                mpl.contour(x, y, what_I_contour, \
535                            zelevelsc, colors = ccol, linewidths = cline)
536            mpl.contourf(x, y, \
537                         self.field, \
538                         zelevels, cmap=palette)
539            # make log axes and/or invert ordinate
540            if self.logx: mpl.semilogx()
541            if self.logy: mpl.semilogy()
542            if self.invert: ax = mpl.gca() ; ax.set_ylim(ax.get_ylim()[::-1])
543        else:
544            ## A 2D MAP USING PROJECTIONS (basemap)
545            #######################################
546            mpl.xlabel("") ; mpl.ylabel("")
547            # additional security in case self.proj is None here
548            # ... we set cylindrical projection (the simplest one)
549            if self.proj is None: self.proj = "cyl"
550            # get lon and lat in 2D version.
551            # (but first ensure we do have 2D coordinates)
552            if self.absc.ndim == 1:     [self.absc,self.ordi] = np.meshgrid(self.absc,self.ordi)
553            elif self.absc.ndim > 2:    print "!! ERROR !! lon and lat arrays must be 1D or 2D"
554            # get lat lon intervals and associated settings
555            wlon = [np.min(self.absc),np.max(self.absc)]
556            wlat = [np.min(self.ordi),np.max(self.ordi)]
557            # -- area presets are in set_area.txt
558            if self.area is not None:
559             if self.area in area.keys():
560                wlon, wlat = area[self.area]
561            # -- settings for meridians and parallels
562            steplon = abs(wlon[1]-wlon[0])/6.
563            steplat = abs(wlat[1]-wlat[0])/3.
564            mertab = np.r_[wlon[0]:wlon[1]:steplon] ; merlab = [0,0,0,1]
565            partab = np.r_[wlat[0]:wlat[1]:steplat] ; parlab = [1,0,0,0]
566            format = '%.1f'
567            # -- center of domain and bounding lats
568            lon_0 = 0.5*(wlon[0]+wlon[1])
569            lat_0 = 0.5*(wlat[0]+wlat[1])
570            # some tests, bug fixes, and good-looking settings
571            # ... cyl is good for global and regional
572            if self.proj == "cyl":
573                format = '%.0f'
574            # ... global projections
575            elif self.proj in ["ortho","moll","robin"]:
576                wlat[0] = None ; wlat[1] = None ; wlon[0] = None ; wlon[1] = None
577                steplon = 30. ; steplat = 30.
578                if self.proj in ["robin","moll"]: steplon = 60.
579                mertab = np.r_[-360.:360.:steplon]
580                partab = np.r_[-90.:90.:steplat]
581                if self.proj == "ortho": 
582                    merlab = [0,0,0,0] ; parlab = [0,0,0,0]
583                    # in ortho projection, blon and blat can be used to set map center
584                    if self.blon is not None: lon_0 = self.blon
585                    if self.blat is not None: lat_0 = self.blat
586                elif self.proj == "moll":
587                    merlab = [0,0,0,0]
588                format = '%.0f'
589            # ... regional projections
590            elif self.proj in ["lcc","laea","merc"]:
591                if self.proj in ["lcc","laea"] and wlat[0] == -wlat[1]: 
592                    print "!! ERROR !! with Lambert lat1 must be different than lat2" ; exit()
593                if wlat[0] < -80. and wlat[1] > 80.:
594                    print "!! ERROR !! set an area (not global)" ; exit()
595                format = '%.0f'
596            elif self.proj in ["npstere","spstere"]:
597                # in polar projections, blat gives the bounding lat
598                # if not set, set something reasonable
599                if self.blat is None:   self.blat = 60.
600                # help the user who forgets self.blat would better be negative in spstere
601                # (this actually serves for the default setting just above)
602                if self.proj == "spstere" and self.blat > 0: self.blat = -self.blat
603            # ... unsupported projections
604            else:
605                print "!! ERROR !! unsupported projection. supported: "+\
606                      "cyl, npstere, spstere, ortho, moll, robin, lcc, laea, merc"
607            # finally define projection
608            m = Basemap(projection=self.proj,\
609                        lat_0=lat_0,lon_0=lon_0,\
610                        boundinglat=self.blat,\
611                        llcrnrlat=wlat[0],urcrnrlat=wlat[1],\
612                        llcrnrlon=wlon[0],urcrnrlon=wlon[1])
613            # draw meridians and parallels
614            ft = int(mpl.rcParams['font.size']*3./4.)
615            m.drawmeridians(mertab,labels=merlab,color='grey',linewidth=0.75,fontsize=ft,fmt=format)
616            m.drawparallels(partab,labels=parlab,color='grey',linewidth=0.75,fontsize=ft,fmt=format)
617            # define background (see set_back.txt)
618            if self.back is not None:
619              if self.back in back.keys():
620                 print "**** info: loading a background, please wait.",self.back
621                 if back not in ["coast","sea"]:   m.warpimage(back[self.back],scale=0.75)
622                 elif back == "coast":             m.drawcoastlines()
623                 elif back == "sea":               m.drawlsmask(land_color='white',ocean_color='aqua')
624              else:
625                 print "!! ERROR !! requested background not defined. change name or fill in set_back.txt" ; exit()
626            # define x and y given the projection
627            x, y = m(self.absc, self.ordi)
628            # contour field. first line contour then shaded contour.
629            if self.addcontour is not None: 
630                m.contour(x, y, what_I_contour, \
631                            zelevelsc, colors = ccol, linewidths = cline)
632            m.contourf(x, y, what_I_plot, zelevels, cmap = palette, alpha = self.trans)
633        ############################################################################################
634        ### COLORBAR
635        ############################################################################################
636        if self.trans > 0.:
637            ## draw colorbar. settings are different with projections. or if not mapmode.
638            if not self.mapmode: orientation=zeorientation ; frac = 0.075 ; pad = 0.03
639            elif self.proj in ['moll']: orientation="horizontal" ; frac = 0.075 ; pad = 0.03
640            elif self.proj in ['cyl']: orientation="vertical" ; frac = 0.023 ; pad = 0.03
641            else: orientation = zeorientation ; frac = zefrac ; pad = 0.03
642            zelevpal = np.linspace(zevmin,zevmax,num=min([ticks/2+1,21]))
643            zecb = mpl.colorbar(fraction=frac,pad=pad,\
644                                format=self.fmt,orientation=orientation,\
645                                ticks=zelevpal,\
646                                extend='neither',spacing='proportional') 
647            if zeorientation == "horizontal": zecb.ax.set_xlabel(self.title) ; self.title = ""
648        ############################################################################################
649        ### VECTORS. must be after the colorbar. we could also leave possibility for streamlines.
650        ############################################################################################
651        ### not expecting NaN in self.addvecx and self.addvecy. masked arrays is just enough.
652        stride = 3
653        if self.addvecx is not None and self.addvecy is not None and self.mapmode:
654                ## for metwinds only ???
655                [vecx,vecy] = m.rotate_vector(self.addvecx,self.addvecy,self.absc,self.ordi) 
656                # reference vector is scaled
657                zescale = ppcompute.mean(np.sqrt(self.addvecx*self.addvecx+self.addvecy*self.addvecy))
658                # make vector field
659                q = m.quiver( x[::stride,::stride],y[::stride,::stride],\
660                              vecx[::stride,::stride],vecy[::stride,::stride],\
661                              angles='xy',color=self.colorvec,pivot='middle',\
662                              scale=zescale*reducevec,width=widthvec )
663                # make vector key. default is on upper left corner.
664                keyh = 1.025 ; keyv = 1.05
665                #keyh = -0.03 ; keyv = 1.08
666                p = mpl.quiverkey(q,keyh,keyv,\
667                                  zescale,str(int(zescale)),\
668                                  color='black',labelpos='S',labelsep = 0.07)
Note: See TracBrowser for help on using the repository browser.