source: trunk/UTIL/PYTHON/mcd/mcd.py @ 859

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

UTIL PYTHON MCDonline. Support for MCD5. Added eps figures. Various other informations added (diapo mode, text file with web arborescence).

  • Property svn:executable set to *
File size: 43.6 KB
Line 
1####################################################
2### A Python Class for the Mars Climate Database ###
3### ---------------------------------------------###
4### Aymeric SPIGA 17-21/04/2012                  ###
5### ---------------------------------------------###
6### (see mcdtest.py for examples of use)         ###
7####################################################
8
9import numpy as np
10import matplotlib.pyplot as mpl
11import myplot
12
13
14class mcd():
15 
16    def __repr__(self):
17    # print out a help string when help is invoked on the object
18        whatprint = 'MCD object. \"help(mcd)\" for more information\n'
19        return whatprint
20
21########################
22### Default settings ###
23########################
24
25    def __init__(self):
26    # default settings
27        ## 0. general stuff
28        self.name      = "MCD v4.3"
29        self.ack       = "Mars Climate Database (c) LMD/OU/IAA/ESA/CNES"
30        #self.dset      = '/home/aymeric/Science/MCD_v4.3/data/'
31        self.dset      = '/home/marshttp/MCD_v4.3/data/'
32        ## 1. spatio-temporal coordinates
33        self.lat       = 0.
34        self.lats      = None
35        self.late      = None
36        self.lon       = 0.
37        self.lons      = None
38        self.lone      = None
39        self.loct      = 0.
40        self.locts     = None
41        self.locte     = None
42        self.xdate     = 0.  # see datekey
43        self.xdates    = None
44        self.xdatee    = None
45        self.xz        = 10. # see zkey
46        self.xzs       = None
47        self.xze       = None
48        ## 1bis. related settings
49        self.zkey      = 3  # specify that xz is the altitude above surface (m)
50                            # zkey  : <integer>   type of vertical coordinate xz
51                            # 1 = radius from centre of planet (m)
52                            # 2 = height above areoid (m) (MOLA zero datum)
53                            # 3 = height above surface (m)
54                            # 4 = pressure level (Pa)
55                            # 5 = altitude above mean Mars Radius(=3396000m) (m)
56        self.datekey   = 1  # 0 = "Earth time": xdate is given in Julian days (localtime must be set to zero)
57                            # 1 = "Mars date": xdate is the value of Ls
58        ## 2. climatological options
59        self.dust      = 2  #our best guess MY24 scenario, with solar average conditions
60        self.hrkey     = 1  #set high resolution mode on (hrkey=0 to set high resolution off)
61        ## 3. additional settings for advanced use
62        self.extvarkey = 1  #extra output variables (1: yes, 0: no)
63        self.perturkey = 0  #integer perturkey ! perturbation type (0: none)
64        self.seedin    = 1  #random number generator seed (unused if perturkey=0)
65        self.gwlength  = 0. #gravity Wave wavelength (unused if perturkey=0)
66        ## outputs. just to define attributes.
67        ## --> in update
68        self.pres = None ; self.dens = None ; self.temp = None ; self.zonwind = None ; self.merwind = None ; self.meanvar = None ; self.extvar = None
69        self.seedout = None ; self.ierr = None
70        ## --> in prepare
71        self.xcoord = None ; self.ycoord = None
72        self.prestab = None ; self.denstab = None ; self.temptab = None 
73        self.zonwindtab = None ; self.merwindtab = None ; self.meanvartab = None ; self.extvartab = None
74        ## plot stuff
75        self.xlabel = None ; self.ylabel = None ; self.title = ""
76        self.vertplot = False
77        self.fmt = "%.2e" 
78        self.colorm = "jet"
79        self.fixedlt = False
80        self.zonmean = False
81        self.min2d = None
82        self.max2d = None
83        self.dpi = 80.
84
85    def toversion5(self):
86        self.name      = "MCD v5.0"
87        self.dset      = '/home/marshttp/MCD_v5.0/data/'
88        self.extvarkey = np.ones(100)
89
90    def viking1(self): self.name = "Viking 1 site. MCD v4.3 output" ; self.lat = 22.48 ; self.lon = -49.97 ; self.xdate = 97.
91    def viking2(self): self.name = "Viking 2 site. MCD v4.3 output" ; self.lat = 47.97 ; self.lon = -225.74 ; self.xdate = 117.6
92
93    def getdustlabel(self):
94        if self.dust == 1: self.dustlabel = "climatology minimum solar scenario"
95        elif self.dust == 2: self.dustlabel = "climatology average solar scenario"
96        elif self.dust == 3: self.dustlabel = "climatology maximum solar scenario"
97        elif self.dust == 4: self.dustlabel = "dust storm minimum solar scenario"
98        elif self.dust == 5: self.dustlabel = "dust storm average solar scenario"
99        elif self.dust == 6: self.dustlabel = "dust storm maximum solar scenario"
100        elif self.dust == 7: self.dustlabel = "warm scenario (dusty, maximum solar)"
101        elif self.dust == 8: self.dustlabel = "cold scenario (low dust, minimum solar)"
102
103    def gettitle(self,oneline=False):
104        self.getdustlabel()
105        self.title = self.name + " with " + self.dustlabel + "."
106        if self.datekey == 1:    self.title = self.title + " Ls " + str(self.xdate) + "deg."
107        elif self.datekey == 0:  self.title = self.title + " JD " + str(self.xdate) + "."
108        if not oneline: self.title = self.title + "\n"
109        if self.lats is None:  self.title = self.title + " Latitude " + str(self.lat) + "N"
110        if self.zonmean and self.lats is not None and self.xzs is not None: 
111            self.title = self.title + "Zonal mean over all longitudes."
112        elif self.lons is None: 
113            self.title = self.title + " Longitude " + str(self.lon) + "E"
114        if self.xzs is None:   
115            self.vertunits()
116            self.title = self.title + " Altitude " + str(self.xz) + " " + self.vunits
117        if self.locts is None:
118            self.title = self.title + " Local time " + str(self.loct) + "h"
119            if not self.fixedlt:  self.title = self.title + " (at longitude 0) "
120
121    def getextvarlab(self,num):
122        whichfield = { \
123        91: "Pressure (Pa)", \
124        92: "Density (kg/m3)", \
125        93: "Temperature (K)", \
126        94: "W-E wind component (m/s)", \
127        95: "S-N wind component (m/s)", \
128        1: "Radial distance from planet center (m)",\
129        2: "Altitude above areoid (Mars geoid) (m)",\
130        3: "Altitude above local surface (m)",\
131        4: "orographic height (m) (surf alt above areoid)",\
132        5: "Ls, solar longitude of Mars (deg)",\
133        6: "LST local true solar time (hrs)",\
134        7: "Universal solar time (LST at lon=0) (hrs)",\
135        8: "Air heat capacity Cp (J kg-1 K-1)",\
136        9: "gamma=Cp/Cv Ratio of specific heats",\
137        10: "density RMS day to day variations (kg/m^3)",\
138        11: "[not defined]",\
139        12: "[not defined]",\
140        13: "scale height H(p) (m)",\
141        14: "GCM orography (m)",\
142        15: "surface temperature (K)",\
143        16: "daily max mean surface temperature (K)",\
144        17: "daily min mean surface temperature (K)",\
145        18: "surf. temperature RMS day to day variations (K)",\
146        19: "surface pressure (Pa)",\
147        20: "GCM surface pressure (Pa)",\
148        21: "atmospheric pressure RMS day to day variations (Pa)",\
149        22: "surface pressure RMS day to day variations (Pa)",\
150        23: "temperature RMS day to day variations (K)",\
151        24: "zonal wind RMS day to day variations (m/s)",\
152        25: "meridional wind RMS day to day variations (m/s)",\
153        26: "vertical wind component (m/s) >0 when downwards!",\
154        27: "vertical wind RMS day to day variations (m/s)",\
155        28: "small scale perturbation (gravity wave) (kg/m^3)",\
156        29: "q2: turbulent kinetic energy (m2/s2)",\
157        30: "[not defined]",\
158        31: "thermal IR flux to surface (W/m2)",\
159        32: "solar flux to surface (W/m2)",\
160        33: "thermal IR flux to space (W/m2)",\
161        34: "solar flux reflected to space (W/m2)",\
162        35: "surface CO2 ice layer (kg/m2)",\
163        36: "DOD: Dust column visible optical depth",\
164        37: "Dust mass mixing ratio (kg/kg)",\
165        38: "DOD RMS day to day variations",\
166        39: "DOD total standard deviation over season",\
167        40: "Water vapor column (kg/m2)",\
168        41: "Water vapor vol. mixing ratio (mol/mol)",\
169        42: "Water ice column (kg/m2)",\
170        43: "Water ice mixing ratio (mol/mol)",\
171        44: "O3 ozone vol. mixing ratio (mol/mol)",\
172        45: "[CO2] vol. mixing ratio (mol/mol)",\
173        46: "[O] vol. mixing ratio (mol/mol)",\
174        47: "[N2] vol. mixing ratio (mol/mol)",\
175        48: "[CO] vol. mixing ratio (mol/mol)",\
176        49: "R: Molecular gas constant (J K-1 kg-1)",\
177        50: "Air viscosity estimation (N s m-2)"
178        }
179        ### MCD version 5 new variables. AS 12/2012.
180        if "v5" in self.name:
181          whichfield[29] = "not used (set to zero)"
182          whichfield[30] = "Surface roughness length z0 (m)"
183          whichfield[37] = "DOD RMS day to day variations"
184          whichfield[38] = "Dust mass mixing ratio (kg/kg)"
185          whichfield[39] = "Dust effective radius (m)"
186          whichfield[44] =  whichfield[43]
187          whichfield[43] =  whichfield[42]
188          whichfield[42] =  whichfield[41]
189          whichfield[41] =  whichfield[40]
190          whichfield[40] = "Dust deposition on flat surface (kg m-2 s-1)"
191          whichfield[45] = "Water ice effective radius (m)"
192          whichfield[46] = "Convective PBL height (m)"
193          whichfield[47] = "Max. upward convective wind within the PBL (m/s)"
194          whichfield[48] = "Max. downward convective wind within the PBL (m/s)"
195          whichfield[49] = "Convective vertical wind variance at level z (m2/s2)"
196          whichfield[50] = "Convective eddy vertical heat flux at level z (m/s/K)"
197          whichfield[51] = "Surface wind stress (Kg/m/s2)"
198          whichfield[52] = "Surface sensible heat flux (W/m2) (<0 when flux from surf to atm.)"
199          whichfield[53] = "R: Molecular gas constant (J K-1 kg-1)"
200          whichfield[54] = "Air viscosity estimation (N s m-2)"
201          whichfield[55] = "not used (set to zero)"
202          whichfield[56] = "not used (set to zero)"
203          whichfield[57] = "[CO2] vol. mixing ratio (mol/mol)"
204          whichfield[58] = "[N2] vol. mixing ratio (mol/mol)"
205          whichfield[59] = "[Ar] vol. mixing ratio (mol/mol)"
206          whichfield[60] = "[CO] vol. mixing ratio (mol/mol)"
207          whichfield[61] = "[O] vol. mixing ratio (mol/mol)"
208          whichfield[62] = "[O2] vol. mixing ratio (mol/mol)"
209          whichfield[63] = "[O3] vol. mixing ratio (mol/mol)"
210          whichfield[64] = "[H] vol. mixing ratio (mol/mol)"
211          whichfield[65] = "[H2] vol. mixing ratio (mol/mol)"
212          whichfield[66] = "[electron] vol. mixing ratio (mol/mol)"
213          whichfield[67] = "CO2 column (kg/m2)"
214          whichfield[68] = "N2 column (kg/m2)"
215          whichfield[69] = "Ar column (kg/m2)"
216          whichfield[70] = "CO column (kg/m2)"
217          whichfield[71] = "O column (kg/m2)"
218          whichfield[72] = "O2 column (kg/m2)"
219          whichfield[73] = "O3 column (kg/m2)"
220          whichfield[74] = "H column (kg/m2)"
221          whichfield[75] = "H2 column (kg/m2)"
222          whichfield[76] = "electron column (kg/m2)"
223        if num not in whichfield: myplot.errormess("Incorrect subscript in extvar.")
224        dastuff = whichfield[num]
225        if "(K)" in dastuff:      self.fmt="%.0f"
226        elif "(Pa)" in dastuff:   self.fmt="%.1f"
227        elif "(W/m2)" in dastuff: self.fmt="%.0f"
228        elif "(m/s)" in dastuff:  self.fmt="%.1f"
229        elif "(m)" in dastuff:    self.fmt="%.0f"
230        else:                     self.fmt="%.2e"
231        return dastuff
232
233    def convertlab(self,num):       
234        ## a conversion from text inquiries to extvar numbers. to be completed.
235        if num == "p": num = 91
236        elif num == "rho": num = 92
237        elif num == "t": num = 93
238        elif num == "u": num = 94
239        elif num == "v": num = 95
240        elif num == "tsurf": num = 15
241        elif num == "topo": num = 4
242        elif num == "h": num = 13
243        elif num == "ps": num = 19
244        elif num == "tau": num = 36
245        elif num == "mtot": 
246            if "v5" in self.name:  num = 41 
247            else:                  num = 40
248        elif num == "icetot": 
249            if "v5" in self.name:  num = 43
250            else:                  num = 42
251        elif num == "ps_ddv": num = 22
252        elif num == "h2ovap": 
253            if "v5" in self.name:  num = 42
254            else:                  num = 41
255        elif num == "h2oice": 
256            if "v5" in self.name:  num = 44
257            else:                  num = 43
258        elif num == "cp": num = 8
259        elif num == "rho_ddv": num = 10
260        elif num == "tsurfmx": num = 16
261        elif num == "tsurfmn": num = 17
262        elif num == "lwdown": num = 31
263        elif num == "swdown": num = 32
264        elif num == "lwup": num = 33
265        elif num == "swup": num = 34
266        elif num == "o3": 
267            if "v5" in self.name:  num = 63
268            else:                  num = 44
269        elif num == "o": 
270            if "v5" in self.name:  num = 61
271            else:                  num = 46
272        elif num == "co": 
273            if "v5" in self.name:  num = 60
274            else:                  num = 48
275        elif num == "visc": 
276            if "v5" in self.name:  num = 54
277            else:                  num = 50
278        elif num == "co2ice": num = 35
279        elif num == "pbl":
280            if "v5" in self.name:  num = 46
281            else:                  num = 30 # an undefined variable to avoid misleading output
282        elif num == "updraft":
283            if "v5" in self.name:  num = 47
284            else:                  num = 30 # an undefined variable to avoid misleading output
285        elif num == "downdraft":
286            if "v5" in self.name:  num = 48
287            else:                  num = 30 # an undefined variable to avoid misleading output
288        elif num == "pblwvar":
289            if "v5" in self.name:  num = 49
290            else:                  num = 30 # an undefined variable to avoid misleading output
291        elif num == "pblhvar":
292            if "v5" in self.name:  num = 50
293            else:                  num = 30 # an undefined variable to avoid misleading output
294        elif num == "stress":
295            if "v5" in self.name:  num = 51
296            else:                  num = 30 # an undefined variable to avoid misleading output
297        elif num == "ar":
298            if "v5" in self.name:  num = 59
299            else:                  num = 30 # an undefined variable to avoid misleading output
300        elif not isinstance(num, np.int): myplot.errormess("field reference not found.")
301        return num
302
303###################
304### One request ###
305###################
306
307    def update(self):
308    # retrieve fields from MCD (call_mcd). more info in fmcd.call_mcd.__doc__
309        ## sanity first
310        self.loct = abs(self.loct)%24
311        if self.locts is not None and self.locte is not None: 
312            self.locts = abs(self.locts)%24
313            self.locte = abs(self.locte)%24
314            if self.locts == self.locte: self.locte = self.locts + 24
315        ## now MCD request
316        if "v5" in self.name: from fmcd5 import call_mcd
317        else:                 from fmcd import call_mcd
318        (self.pres, self.dens, self.temp, self.zonwind, self.merwind, \
319         self.meanvar, self.extvar, self.seedout, self.ierr) \
320         = \
321         call_mcd(self.zkey,self.xz,self.lon,self.lat,self.hrkey, \
322             self.datekey,self.xdate,self.loct,self.dset,self.dust, \
323             self.perturkey,self.seedin,self.gwlength,self.extvarkey )
324        ## we use the end of extvar (unused) to store meanvar. this is convenient for getextvar(lab)
325        self.extvar[90] = self.pres ; self.extvar[91] = self.dens
326        self.extvar[92] = self.temp ; self.extvar[93] = self.zonwind ; self.extvar[94] = self.merwind
327        ## treat missing values
328        if self.temp == -999: self.extvar[:] = np.NaN ; self.meanvar[:] = np.NaN
329
330    def printset(self):
331    # print main settings
332        print "zkey",self.zkey,"xz",self.xz,"lon",self.lon,"lat",self.lat,"hrkey",self.hrkey, \
333              "xdate",self.xdate,"loct",self.loct,"dust",self.dust
334
335    def getnameset(self):
336    # set a name referring to settings [convenient for databases]
337        strlat = str(self.lat)+str(self.lats)+str(self.late)
338        strlon = str(self.lon)+str(self.lons)+str(self.lone)
339        strxz = str(self.xz)+str(self.xzs)+str(self.xze)
340        strloct = str(self.loct)+str(self.locts)+str(self.locte)
341        name = str(self.zkey)+strxz+strlon+strlat+str(self.hrkey)+str(self.datekey)+str(self.xdate)+strloct+str(self.dust)
342        if "v5" in self.name: name = "v5beta_" + name
343        return name
344
345    def printcoord(self):
346    # print requested space-time coordinates
347        print "LAT",self.lat,"LON",self.lon,"LOCT",self.loct,"XDATE",self.xdate
348
349    def printmeanvar(self):
350    # print mean MCD variables
351        print "Pressure = %5.3f pascals. " % (self.pres)
352        print "Density = %5.3f kilograms per cubic meter. " % (self.dens)
353        print "Temperature = %3.0f kelvins (%4.0f degrees celsius)." % (self.temp,self.temp-273.15)
354        print "Zonal wind = %5.3f meters per second." % (self.zonwind)
355        print "Meridional wind = %5.3f meters per second." % (self.merwind)
356        print "Total horizontal wind = %5.3f meters per second." % ( np.sqrt(self.zonwind**2 + self.merwind**2) )
357
358    def printextvar(self,num):
359    # print extra MCD variables
360        num = self.convertlab(num)
361        dastr = str(self.extvar[num-1])
362        if dastr == "nan":   print "!!!! There is a problem, probably a value is requested below the surface !!!!"
363        else:                print self.getextvarlab(num) + " ..... " + dastr
364
365    def printallextvar(self):
366    # print all extra MCD variables   
367        if "v5" in self.name:  limit=76
368        else:                  limit=50
369        for i in range(limit): self.printextvar(i+1)
370
371    def htmlprinttabextvar(self,tabtodo):
372        self.fixedlt = True ## local time is real local time
373        self.gettitle()
374        print "<hr>"
375        print self.title
376        print "<hr>"
377        print "<ul>"
378        for i in range(len(tabtodo)): print "<li>" ; self.printextvar(tabtodo[i]) ; print "</li>"
379        print "</ul>"
380        print "<hr>"
381        print self.ack
382        print "<hr>"
383        #print "SETTINGS<br />"
384        #self.printcoord()
385        #self.printset()
386
387    def printmcd(self):
388    # 1. call MCD 2. print settings 3. print mean vars
389        self.update()
390        self.printcoord()
391        print "-------------------------------------------"
392        self.printmeanvar()
393
394########################
395### Several requests ###
396########################
397
398    def prepare(self,ndx=None,ndy=None):
399    ### prepare I/O arrays for 1d slices
400      if ndx is None:  print "No dimension in prepare. Exit. Set at least ndx." ; exit()
401      else:            self.xcoord = np.ones(ndx)
402      if ndy is None:  dashape = (ndx)     ; dashapemean = (ndx,6)     ; dashapeext = (ndx,101)     ; self.ycoord = None
403      else:            dashape = (ndx,ndy) ; dashapemean = (ndx,ndy,6) ; dashapeext = (ndx,ndy,101) ; self.ycoord = np.ones(ndy)
404      self.prestab = np.ones(dashape) ; self.denstab = np.ones(dashape) ; self.temptab = np.ones(dashape)
405      self.zonwindtab = np.ones(dashape) ; self.merwindtab = np.ones(dashape) 
406      self.meanvartab = np.ones(dashapemean) ; self.extvartab = np.ones(dashapeext)
407
408    def getextvar(self,num):
409    ### get a given var in extvartab
410      try: field=self.extvartab[:,:,num] 
411      except: field=self.extvartab[:,num]
412      return field
413
414    def definefield(self,choice):
415    ### for analysis or plot purposes, set field and field label from user-defined choice
416      choice = self.convertlab(choice)
417      field = self.getextvar(choice); fieldlab = self.getextvarlab(choice)
418      ## fix for possibly slightly negative tracers
419      if "(mol/mol)" in fieldlab or "(kg/kg)" in fieldlab or "(kg/m2)" in fieldlab or "(W/m2)" in fieldlab:
420         ind = np.where(field < 1.e-30)
421         if ind != -1: field[ind] = 1.e-30  ## 0 does not work everywhere.
422      return field,fieldlab
423
424    def ininterv(self,dstart,dend,nd,start=None,end=None,yaxis=False,vertcoord=False):
425    ### user-defined start and end are used to create xcoord (or ycoord) vector
426      if start is not None and end is not None:  first, second = self.correctbounds(start,end,vertcoord)
427      else:                                      first, second = self.correctbounds(dstart,dend,vertcoord) 
428      if self.zkey != 4 or not vertcoord:   tabtab = np.linspace(first,second,nd)
429      else:                                 tabtab = np.logspace(first,second,nd)
430      if not yaxis:      self.xcoord = tabtab
431      else:              self.ycoord = tabtab
432
433    def correctbounds(self,start,end,vertcoord):
434      if self.zkey != 4 or not vertcoord:
435        # regular altitudes
436        if start > end: first = end ; second = start
437        else:           first = start ; second = end
438      else:
439        # pressure: reversed avis
440        if start < end: first = np.log10(end) ; second = np.log10(start)
441        else:           first = np.log10(start) ; second = np.log10(end)
442      return first, second
443
444    def vertlabel(self):
445      if self.zkey == 1:   self.xlabel = "radius from centre of planet (m)"
446      elif self.zkey == 2: self.xlabel = "height above areoid (m) (MOLA zero datum)"
447      elif self.zkey == 3: self.xlabel = "height above surface (m)"
448      elif self.zkey == 4: self.xlabel = "pressure level (Pa)"
449      elif self.zkey == 5: self.xlabel = "altitude above mean Mars Radius(=3396000m) (m)"
450
451    def vertunits(self):
452      if self.zkey == 1:   self.vunits = "m CP"
453      elif self.zkey == 2: self.vunits = "m AMR"
454      elif self.zkey == 3: self.vunits = "m ALS"
455      elif self.zkey == 4: self.vunits = "Pa"
456      elif self.zkey == 5: self.vunits = "m AMMRad"
457
458    def vertaxis(self,number,yaxis=False):
459      if self.zkey == 2:   self.ininterv(-5000.,100000.,number,start=self.xzs,end=self.xze,yaxis=yaxis,vertcoord=True)
460      elif self.zkey == 3: self.ininterv(0.,120000.,number,start=self.xzs,end=self.xze,yaxis=yaxis,vertcoord=True)
461      elif self.zkey == 5: self.ininterv(-5000.,100000.,number,start=self.xzs,end=self.xze,yaxis=yaxis,vertcoord=True)
462      elif self.zkey == 4: self.ininterv(1000.,0.001,number,start=self.xzs,end=self.xze,yaxis=yaxis,vertcoord=True)
463      elif self.zkey == 1: self.ininterv(3396000,3596000,number,start=self.xzs,end=self.xze,yaxis=yaxis,vertcoord=True)
464
465###################
466### 1D analysis ###
467###################
468
469    def put1d(self,i):
470    ## fill in subscript i in output arrays
471    ## (arrays must have been correctly defined through prepare)
472      if self.prestab is None:  myplot.errormess("arrays must be prepared first through self.prepare")
473      self.prestab[i] = self.pres ; self.denstab[i] = self.dens ; self.temptab[i] = self.temp
474      self.zonwindtab[i] = self.zonwind ; self.merwindtab[i] = self.merwind
475      self.meanvartab[i,1:5] = self.meanvar[0:4]  ## note: var numbering according to MCD manual is kept
476      self.extvartab[i,1:100] = self.extvar[0:99] ## note: var numbering according to MCD manual is kept
477
478    def diurnal(self,nd=13):
479    ### retrieve a local time slice
480      self.fixedlt = True  ## local time is real local time
481      save = self.loct
482      self.xlabel = "Local time (Martian hour)"
483      self.prepare(ndx=nd) ; self.ininterv(0.,24.,nd,start=self.locts,end=self.locte) 
484      for i in range(nd): self.loct = self.xcoord[i] ; self.update() ; self.put1d(i)
485      self.loct = save
486
487    def zonal(self,nd=37):
488    ### retrieve a longitude slice
489      save = self.lon
490      self.xlabel = "East longitude (degrees)"
491      self.prepare(ndx=nd) ; self.ininterv(-180.,180.,nd,start=self.lons,end=self.lone)
492      if not self.fixedlt: umst = self.loct
493      for i in range(nd): 
494          self.lon = self.xcoord[i]
495          if not self.fixedlt: self.loct = (umst + self.lon/15.) % 24
496          self.update() ; self.put1d(i)
497      self.lon = save
498
499    def meridional(self,nd=19):
500    ### retrieve a latitude slice
501      self.fixedlt = True  ## local time is real local time
502      save = self.lat
503      self.xlabel = "North latitude (degrees)"
504      self.prepare(ndx=nd) ; self.ininterv(-90.,90.,nd,start=self.lats,end=self.late)
505      for i in range(nd): self.lat = self.xcoord[i] ; self.update() ; self.put1d(i)
506      self.lat = save
507
508    def profile(self,nd=20,tabperso=None):
509    ### retrieve an altitude slice (profile)
510      self.fixedlt = True  ## local time is real local time
511      save = self.xz
512      self.vertlabel()
513      self.vertplot = True
514      if tabperso is not None: nd = len(tabperso)
515      correct = False
516      self.prepare(ndx=nd) ; self.vertaxis(nd)
517      if tabperso is not None: self.xcoord = tabperso
518      for i in range(nd): self.xz = self.xcoord[i] ; self.update() ; self.put1d(i)
519      self.xz = save
520
521    def seasonal(self,nd=12):
522    ### retrieve a seasonal slice
523      save = self.xdate
524      self.xlabel = "Areocentric longitude (degrees)"
525      self.prepare(ndx=nd) ; self.ininterv(0.,360.,nd,start=self.xdates,end=self.xdatee)
526      for i in range(nd): self.xdate = self.xcoord[i] ; self.update() ; self.put1d(i)
527      self.xdate = save
528
529    def getascii(self,tabtodo,filename="output.txt"):
530    ### print out values in an ascii file
531      if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
532      if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
533      asciifile = open(filename, "w")
534      for i in range(len(tabtodo)): 
535          (field, fieldlab) = self.definefield(tabtodo[i])
536          self.gettitle(oneline=True)
537          asciifile.write("### " + self.title + "\n")
538          asciifile.write("### " + self.ack + "\n")
539          asciifile.write("### Column 1 is " + self.xlabel + "\n")
540          asciifile.write("### Column 2 is " + fieldlab + "\n")
541          for ix in range(len(self.xcoord)):
542              asciifile.write("%15.5e%15.5e\n" % ( self.xcoord[ix], field[ix] ) )
543      asciifile.close()
544      return 
545
546    def makeplot1d(self,choice):
547    ### one 1D plot is created for the user-defined variable in choice.
548      (field, fieldlab) = self.definefield(choice)
549      if not self.vertplot:  absc = self.xcoord ; ordo = field ; ordolab = fieldlab ; absclab = self.xlabel
550      else:                  ordo = self.xcoord ; absc = field ; absclab = fieldlab ; ordolab = self.xlabel
551      mpl.plot(absc,ordo,'-bo') ; mpl.ylabel(ordolab) ; mpl.xlabel(absclab) #; mpl.xticks(query.xcoord)
552      if self.zkey == 4: mpl.semilogy() ; ax = mpl.gca() ; ax.set_ylim(ax.get_ylim()[::-1])
553      mpl.figtext(0.5, 0.01, self.ack, ha='center')
554
555    def plot1d(self,tabtodo):
556    ### complete 1D figure with possible multiplots
557      if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
558      if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
559      fig = mpl.figure() ; subv,subh = myplot.definesubplot( len(tabtodo) , fig ) 
560      for i in range(len(tabtodo)): mpl.subplot(subv,subh,i+1).grid(True, linestyle=':', color='grey') ; self.makeplot1d(tabtodo[i])
561
562    def htmlplot1d(self,tabtodo,figname="temp.png",title=""):
563    ### complete 1D figure with possible multiplots
564    ### added in 09/2012 for online MCD
565    ### see http://www.dalkescientific.com/writings/diary/archive/2005/04/23/matplotlib_without_gui.html
566      from matplotlib.figure import Figure
567      from matplotlib.backends.backend_agg import FigureCanvasAgg
568      if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
569      if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
570
571      howmanyplots = len(tabtodo)
572      if howmanyplots == 1: fig = Figure(figsize=(16,8))
573      elif howmanyplots == 2: fig = Figure(figsize=(8,8))
574      elif howmanyplots == 3: fig = Figure(figsize=(8,16))
575      elif howmanyplots == 4: fig = Figure(figsize=(16,8))
576
577      subv,subh = myplot.definesubplot( len(tabtodo) , fig )
578      for i in range(len(tabtodo)):
579        yeah = fig.add_subplot(subv,subh,i+1) #.grid(True, linestyle=':', color='grey')
580        choice = tabtodo[i]
581        (field, fieldlab) = self.definefield(choice)
582        if not self.vertplot:  absc = self.xcoord ; ordo = field ; ordolab = fieldlab ; absclab = self.xlabel
583        else:                  ordo = self.xcoord ; absc = field ; absclab = fieldlab ; ordolab = self.xlabel
584        yeah.plot(absc,ordo,'-bo') #; mpl.xticks(query.xcoord)
585        ax = fig.gca() ; ax.set_ylabel(ordolab) ; ax.set_xlabel(absclab)
586
587        if self.xzs is not None and self.zkey == 4: ax.set_yscale('log') ; ax.set_ylim(ax.get_ylim()[::-1])
588
589        if self.lats is not None:      ax.set_xticks(np.arange(-90,91,15)) ; ax.set_xbound(lower=self.lats, upper=self.late)
590        elif self.lons is not None:    ax.set_xticks(np.arange(-360,361,30)) ; ax.set_xbound(lower=self.lons, upper=self.lone)
591        elif self.locts is not None:   ax.set_xticks(np.arange(0,26,2)) ; ax.set_xbound(lower=self.locts, upper=self.locte)
592
593        ax.grid(True, linestyle=':', color='grey')
594
595      self.gettitle()
596      fig.text(0.5, 0.95, self.title, ha='center')
597      fig.text(0.5, 0.01, self.ack, ha='center')
598      canvas = FigureCanvasAgg(fig)
599      # The size * the dpi gives the final image size
600      #   a4"x4" image * 80 dpi ==> 320x320 pixel image
601      canvas.print_figure(figname, dpi=self.dpi)
602
603###################
604### 2D analysis ###
605###################
606
607    def latlon(self,ndx=37,ndy=19):
608    ### retrieve a latitude/longitude slice
609    ### default is: local time is not fixed. user-defined local time is at longitude 0.
610      save1 = self.lon ; save2 = self.lat ; save3 = self.loct
611      self.xlabel = "East longitude (degrees)" ; self.ylabel = "North latitude (degrees)"
612      self.prepare(ndx=ndx,ndy=ndy)
613      self.ininterv(-180.,180.,ndx,start=self.lons,end=self.lone)
614      self.ininterv(-90.,  90.,ndy,start=self.lats,end=self.late,yaxis=True)
615      if not self.fixedlt: umst = self.loct
616      for i in range(ndx):
617       for j in range(ndy):
618         self.lon = self.xcoord[i] ; self.lat = self.ycoord[j]
619         if not self.fixedlt: self.loct = (umst + self.lon/15.) % 24
620         self.update() ; self.put2d(i,j)
621      if not self.fixedlt: self.loct = umst
622      self.lon = save1 ; self.lat = save2 ; self.loct = save3
623
624    def secalt(self,ndx=37,ndy=20,typex="lat"):
625    ### retrieve a coordinate/altitude slice
626      save1 = self.lon ; save2 = self.xz ; save3 = self.loct ; save4 = self.lat
627      self.prepare(ndx=ndx,ndy=ndy)
628      self.vertlabel() ; self.ylabel = self.xlabel
629      self.vertaxis(ndy,yaxis=True)
630      if "lat" in typex:
631          self.xlabel = "North latitude (degrees)"
632          self.ininterv(-90.,90.,ndx,start=self.lats,end=self.late)
633      elif typex == "lon":
634          self.xlabel = "East longitude (degrees)"
635          self.ininterv(-180.,180.,ndx,start=self.lons,end=self.lone)
636      if not self.fixedlt: umst = self.loct
637      for i in range(ndx):
638       for j in range(ndy):
639         if typex == "lat":   self.lat = self.xcoord[i]
640         elif typex == "lon": self.lon = self.xcoord[i]
641         self.xz = self.ycoord[j]
642         if not self.fixedlt: self.loct = (umst + self.lon/15.) % 24
643         self.update() ; self.put2d(i,j)
644      if not self.fixedlt: self.loct = umst
645      self.lon = save1 ; self.xz = save2 ; self.loct = save3 ; self.lat = save4
646
647    def zonalmean(self,ndx=37,ndy=20,ndmean=32):
648    ### retrieve a zonalmean lat/altitude slice
649      self.fixedlt = False
650      save1 = self.lon ; save2 = self.xz ; save3 = self.loct ; save4 = self.lat
651      self.prepare(ndx=ndx,ndy=ndy)
652      self.vertlabel() ; self.ylabel = self.xlabel
653      self.vertaxis(ndy,yaxis=True)
654      self.xlabel = "North latitude (degrees)"
655      self.ininterv(-180.,180.,ndmean)
656      coordmean = self.xcoord
657      self.ininterv(-90.,90.,ndx,start=self.lats,end=self.late)
658      umst = self.loct #fixedlt false for this case
659      for i in range(ndx):
660       self.lat = self.xcoord[i]
661       for j in range(ndy):
662        self.xz = self.ycoord[j]
663        meanpres = 0. ; meandens = 0. ; meantemp = 0. ; meanzonwind = 0. ; meanmerwind = 0. ; meanmeanvar = np.zeros(5) ; meanextvar = np.zeros(100)       
664        for m in range(ndmean):
665           self.lon = coordmean[m]
666           self.loct = (umst + self.lon/15.) % 24 #fixedlt false for this case
667           self.update() 
668           meanpres = meanpres + self.pres/float(ndmean) ; meandens = meandens + self.dens/float(ndmean) ; meantemp = meantemp + self.temp/float(ndmean)
669           meanzonwind = meanzonwind + self.zonwind/float(ndmean) ; meanmerwind = meanmerwind + self.merwind/float(ndmean)
670           meanmeanvar = meanmeanvar + self.meanvar/float(ndmean) ; meanextvar = meanextvar + self.extvar/float(ndmean)
671        self.pres=meanpres ; self.dens=meandens ; self.temp=meantemp ; self.zonwind=meanzonwind ; self.merwind=meanmerwind
672        self.meanvar=meanmeanvar ; self.extvar=meanextvar
673        self.put2d(i,j)
674      self.loct = umst #fixedlt false for this case
675      self.lon = save1 ; self.xz = save2 ; self.loct = save3 ; self.lat = save4
676
677    def hovmoller(self,ndtime=25,ndcoord=20,typex="lat"):
678    ### retrieve a time/other coordinate slice
679      save1 = self.lat ; save2 = self.xz ; save3 = self.loct ; save4 = self.lon
680      if typex == "lat": 
681          ndx = ndcoord ; self.xlabel = "North latitude (degrees)" 
682          ndy = ndtime ; self.ylabel = "Local time (Martian hour)"
683          self.prepare(ndx=ndx,ndy=ndy)
684          self.ininterv(-90.,90.,ndx,start=self.lats,end=self.late)
685          self.ininterv(0.,24.,ndy,start=self.locts,end=self.locte,yaxis=True)
686      elif typex == "lon":
687          ndx = ndcoord ; self.xlabel = "East longitude (degrees)"
688          ndy = ndtime ; self.ylabel = "Local time (Martian hour)"
689          self.prepare(ndx=ndx,ndy=ndy)
690          self.ininterv(-180.,180.,ndx,start=self.lons,end=self.lone)
691          self.ininterv(0.,24.,ndy,start=self.locts,end=self.locte,yaxis=True)
692      elif typex == "alt":
693          ndy = ndcoord ; self.vertlabel() ; self.ylabel = self.xlabel
694          ndx = ndtime ; self.xlabel = "Local time (Martian hour)"
695          self.prepare(ndx=ndx,ndy=ndy)
696          self.vertaxis(ndy,yaxis=True)
697          self.ininterv(0.,24.,ndx,start=self.locts,end=self.locte)
698      for i in range(ndx):
699       for j in range(ndy):
700         if typex == "lat":   self.lat = self.xcoord[i] ; self.loct = self.ycoord[j]
701         elif typex == "lon": self.lon = self.xcoord[i] ; self.loct = self.ycoord[j]
702         elif typex == "alt": self.xz = self.ycoord[j] ; self.loct = self.xcoord[i]
703         self.update() ; self.put2d(i,j)
704      self.lat = save1 ; self.xz = save2 ; self.loct = save3 ; self.lon = save4
705
706    def put2d(self,i,j):
707    ## fill in subscript i,j in output arrays
708    ## (arrays must have been correctly defined through prepare)
709      if self.prestab is None:  myplot.errormess("arrays must be prepared first through self.prepare")
710      self.prestab[i,j] = self.pres ; self.denstab[i,j] = self.dens ; self.temptab[i,j] = self.temp
711      self.zonwindtab[i,j] = self.zonwind ; self.merwindtab[i,j] = self.merwind
712      self.meanvartab[i,j,1:5] = self.meanvar[0:4]  ## note: var numbering according to MCD manual is kept
713      self.extvartab[i,j,1:100] = self.extvar[0:99] ## note: var numbering according to MCD manual is kept
714
715    def makemap2d(self,choice,incwind=False,proj="cyl"):
716    ### one 2D map is created for the user-defined variable in choice.
717      self.latlon() ## a map is implicitely a lat-lon plot. otherwise it is a plot (cf. makeplot2d)
718      if choice == "wind" or incwind:
719          (windx, fieldlabwx) = self.definefield("u")
720          (windy, fieldlabwy) = self.definefield("v")
721      if choice == "wind":
722          field = np.sqrt(windx*windx + windy*windy)
723          fieldlab = "Horizontal wind speed (m/s)"
724      else:   
725          (field, fieldlab) = self.definefield(choice)
726      if incwind:   myplot.maplatlon(self.xcoord,self.ycoord,field,title=fieldlab,proj=proj,vecx=windx,vecy=windy) #,stride=1)
727      else:         myplot.maplatlon(self.xcoord,self.ycoord,field,title=fieldlab,proj=proj)
728      mpl.figtext(0.5, 0.0, self.ack, ha='center')
729
730    def map2d(self,tabtodo,incwind=False,proj="cyl"):
731    ### complete 2D figure with possible multiplots
732      if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
733      if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
734      fig = mpl.figure()
735      subv,subh = myplot.definesubplot( len(tabtodo) , fig ) 
736      for i in range(len(tabtodo)): mpl.subplot(subv,subh,i+1) ; self.makemap2d(tabtodo[i],incwind=incwind,proj=proj)
737
738    def htmlmap2d(self,tabtodo,incwind=False,figname="temp.png",back="zMOL"):
739    ### complete 2D figure with possible multiplots
740    ### added in 09/2012 for online MCD
741    ### see http://www.dalkescientific.com/writings/diary/archive/2005/04/23/matplotlib_without_gui.html
742      from matplotlib.figure import Figure
743      from matplotlib.backends.backend_agg import FigureCanvasAgg
744      from matplotlib.cm import get_cmap
745      from matplotlib import rcParams
746      #from mpl_toolkits.basemap import Basemap # does not work
747      from Scientific.IO import NetCDF
748
749      filename = "/home/marshttp/surface.nc"
750      zefile = NetCDF.NetCDFFile(filename, 'r') 
751      fieldc = zefile.variables[back]
752      yc = zefile.variables['latitude']
753      xc = zefile.variables['longitude']
754
755      if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
756      if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
757
758      howmanyplots = len(tabtodo)
759      if howmanyplots == 1: fig = Figure(figsize=(16,8)) 
760      elif howmanyplots == 2: fig = Figure(figsize=(8,8)) 
761      elif howmanyplots == 3: fig = Figure(figsize=(8,16)) 
762      elif howmanyplots == 4: fig = Figure(figsize=(16,8)) 
763
764      subv,subh = myplot.definesubplot( len(tabtodo) , fig )
765
766      for i in range(len(tabtodo)):
767        yeah = fig.add_subplot(subv,subh,i+1)
768        choice = tabtodo[i]
769        self.latlon(ndx=64,ndy=48) 
770        ## a map is implicitely a lat-lon plot. otherwise it is a plot (cf. makeplot2d)
771        (field, fieldlab) = self.definefield(choice)
772        if incwind: (windx, fieldlabwx) = self.definefield("u") ; (windy, fieldlabwy) = self.definefield("v")
773
774        proj="moll" ; colorb= self.colorm ; ndiv=20 ; zeback="molabw" ; trans=1.0 #0.6
775        vecx=None ; vecy=None ; stride=2
776        lon = self.xcoord
777        lat = self.ycoord
778       
779        #[lon2d,lat2d] = np.meshgrid(lon,lat)
780        ##### define projection and background. define x and y given the projection
781        ##[wlon,wlat] = myplot.latinterv()
782        ##yeahm = myplot.define_proj(proj,wlon,wlat,back=zeback,blat=None,blon=None)
783        ##x, y = yeahm(lon2d, lat2d)
784        #map = Basemap(projection='ortho',lat_0=45,lon_0=-100)
785        #x, y = map(lon2d, lat2d)
786
787        #### TEMP
788        x = lon ; y = lat
789
790        ## define field. bound field.
791        what_I_plot = np.transpose(field)
792        zevmin, zevmax = myplot.calculate_bounds(what_I_plot,vmin=self.min2d,vmax=self.max2d) 
793        what_I_plot = myplot.bounds(what_I_plot,zevmin,zevmax)
794        ## define contour field levels. define color palette
795        ticks = ndiv + 1
796        zelevels = np.linspace(zevmin,zevmax,ticks)
797        palette = get_cmap(name=colorb)
798
799        # You can set negative contours to be solid instead of dashed:
800        rcParams['contour.negative_linestyle'] = 'solid'
801        ## contours topo
802        zelevc = np.linspace(-9.,20.,11)
803        yeah.contour( xc, yc, fieldc, zelevc, colors='black',linewidths = 0.4)
804        yeah.contour( np.array(xc) + 360., yc, fieldc, zelevc, colors='black',linewidths = 0.4)
805        yeah.contour( np.array(xc) - 360., yc, fieldc, zelevc, colors='black',linewidths = 0.4)
806        # contour field
807        c = yeah.contourf( x, y, what_I_plot, zelevels, cmap = palette, alpha = trans )
808        clb = Figure.colorbar(fig,c,orientation='vertical',format=self.fmt,ticks=np.linspace(zevmin,zevmax,num=min([ticks/2+1,21])))
809        clb.set_label(fieldlab)
810        if incwind:
811          [x2d,y2d] = np.meshgrid(x,y)
812          yeah.quiver(x2d,y2d,np.transpose(windx),np.transpose(windy))
813        ax = fig.gca() ; ax.set_ylabel("Latitude") ; ax.set_xlabel("Longitude")
814        ax.set_xticks(np.arange(-360,361,45)) ; ax.set_xbound(lower=self.lons, upper=self.lone)
815        ax.set_yticks(np.arange(-90,91,30)) ; ax.set_ybound(lower=self.lats, upper=self.late)
816      self.gettitle()
817      fig.text(0.5, 0.95, self.title, ha='center')
818      fig.text(0.5, 0.01, self.ack, ha='center')
819      canvas = FigureCanvasAgg(fig)
820      # The size * the dpi gives the final image size
821      #   a4"x4" image * 80 dpi ==> 320x320 pixel image
822      canvas.print_figure(figname, dpi=self.dpi)
823
824    def htmlplot2d(self,tabtodo,figname="temp.png"):
825    ### complete 2D figure with possible multiplots
826    ### added in 10/2012 for online MCD
827    ### see http://www.dalkescientific.com/writings/diary/archive/2005/04/23/matplotlib_without_gui.html
828      from matplotlib.figure import Figure
829      from matplotlib.backends.backend_agg import FigureCanvasAgg
830      from matplotlib.cm import get_cmap
831      if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
832      if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
833
834      howmanyplots = len(tabtodo)
835      if howmanyplots == 1: fig = Figure(figsize=(16,8))
836      elif howmanyplots == 2: fig = Figure(figsize=(8,8))
837      elif howmanyplots == 3: fig = Figure(figsize=(8,16))
838      elif howmanyplots == 4: fig = Figure(figsize=(16,8))
839
840      subv,subh = myplot.definesubplot( len(tabtodo) , fig )
841
842      for i in range(len(tabtodo)):
843        yeah = fig.add_subplot(subv,subh,i+1)
844        choice = tabtodo[i]
845
846        if self.lons is not None:   
847           if self.locts is None:  self.secalt(ndx=64,ndy=35,typex="lon")
848           else:                   self.hovmoller(ndcoord=64,typex="lon")
849        elif self.lats is not None: 
850           if self.locts is None: 
851               if self.zonmean:   self.zonalmean()
852               else:         self.secalt(ndx=48,ndy=35,typex="lat")
853           else:                   self.hovmoller(ndcoord=48,typex="lat")
854        else:
855           self.hovmoller(ndcoord=35,typex="alt")
856
857        (field, fieldlab) = self.definefield(choice)
858
859        colorb=self.colorm ; ndiv=20 
860
861        ## define field. bound field.
862        what_I_plot = np.transpose(field)
863        zevmin, zevmax = myplot.calculate_bounds(what_I_plot,vmin=self.min2d,vmax=self.max2d) 
864        what_I_plot = myplot.bounds(what_I_plot,zevmin,zevmax)
865        ## define contour field levels. define color palette
866        ticks = ndiv + 1
867        zelevels = np.linspace(zevmin,zevmax,ticks)
868        palette = get_cmap(name=colorb)
869        # contour field
870        c = yeah.contourf( self.xcoord, self.ycoord, what_I_plot, zelevels, cmap = palette )
871        clb = Figure.colorbar(fig,c,orientation='vertical',format=self.fmt,ticks=np.linspace(zevmin,zevmax,num=min([ticks/2+1,21])))
872        clb.set_label(fieldlab)
873        ax = fig.gca() ; ax.set_ylabel(self.ylabel) ; ax.set_xlabel(self.xlabel)
874
875        if self.lons is not None:   ax.set_xticks(np.arange(-360,361,45)) ; ax.set_xbound(lower=self.lons, upper=self.lone)
876        elif self.lats is not None: ax.set_xticks(np.arange(-90,91,30)) ; ax.set_xbound(lower=self.lats, upper=self.late)
877
878        if self.locts is not None: 
879            if self.xzs is not None: ax.set_xticks(np.arange(0,26,2)) ; ax.set_xbound(lower=self.locts, upper=self.locte)
880            else:                    ax.set_yticks(np.arange(0,26,2)) ; ax.set_ybound(lower=self.locts, upper=self.locte)
881
882        if self.zkey == 4 and self.xzs is not None: 
883            ax.set_yscale('log') ; ax.set_ylim(ax.get_ylim()[::-1])
884        else:
885            #ax.set_yticks(np.arange(self.xzs,self.xze,10000.)) ;
886            ax.set_ybound(lower=self.xzs, upper=self.xze)
887
888      self.gettitle()
889      fig.text(0.5, 0.95, self.title, ha='center')
890      fig.text(0.5, 0.01, self.ack, ha='center')
891      canvas = FigureCanvasAgg(fig)
892      # The size * the dpi gives the final image size
893      #   a4"x4" image * 80 dpi ==> 320x320 pixel image
894      canvas.print_figure(figname, dpi=self.dpi)
895
896    ### TODO: makeplot2d, plot2d, passer plot settings
897
Note: See TracBrowser for help on using the repository browser.