source: trunk/python/asapplotter.py @ 1862

Last change on this file since 1862 was 1862, checked in by Malte Marquarding, 14 years ago

renamed print_log_dec to more explicit asaplog_post_dec

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 52.0 KB
Line 
1from asap.parameters import rcParams
2from asap.selector import selector
3from asap.scantable import scantable
4from asap.logging import asaplog, asaplog_post_dec
5import matplotlib.axes
6from matplotlib.font_manager import FontProperties
7from matplotlib.text import Text
8
9import re
10
11class asapplotter:
12    """
13    The ASAP plotter.
14    By default the plotter is set up to plot polarisations
15    'colour stacked' and scantables across panels.
16
17    .. note::
18
19        Currenly it only plots 'spectra' not Tsys or
20        other variables.
21
22    """
23    def __init__(self, visible=None , **kwargs):
24        self._visible = rcParams['plotter.gui']
25        if visible is not None:
26            self._visible = visible
27        self._plotter = self._newplotter(**kwargs)
28        # additional tool bar
29        self._plotter.figmgr.casabar=self._newcasabar()
30
31        self._panelling = None
32        self._stacking = None
33        self.set_panelling()
34        self.set_stacking()
35        self._rows = None
36        self._cols = None
37        self._autoplot = False
38        self._minmaxx = None
39        self._minmaxy = None
40        self._datamask = None
41        self._data = None
42        self._lmap = None
43        self._title = None
44        self._ordinate = None
45        self._abcissa = None
46        self._abcunit = None
47        self._usermask = []
48        self._maskselection = None
49        self._selection = selector()
50        self._hist = rcParams['plotter.histogram']
51        self._fp = FontProperties()
52        self._panellayout = self.set_panellayout(refresh=False)
53
54    def _translate(self, instr):
55        keys = "s b i p t".split()
56        if isinstance(instr, str):
57            for key in keys:
58                if instr.lower().startswith(key):
59                    return key
60        return None
61
62    def _newplotter(self, **kwargs):
63        backend=matplotlib.get_backend()
64        if not self._visible:
65            from asap.asaplot import asaplot
66        elif backend == 'TkAgg':
67            from asap.asaplotgui import asaplotgui as asaplot
68        elif backend == 'Qt4Agg':
69            from asap.asaplotgui_qt4 import asaplotgui as asaplot
70        elif backend == 'GTkAgg':
71            from asap.asaplotgui_gtk import asaplotgui as asaplot
72        else:
73            from asap.asaplot import asaplot
74        return asaplot(**kwargs)
75
76    def _newcasabar(self):
77        backend=matplotlib.get_backend()
78        if self._visible and backend == "TkAgg":
79            from asap.casatoolbar import CustomToolbarTkAgg
80            return CustomToolbarTkAgg(self)
81        else: return None
82
83    @asaplog_post_dec
84    def plot(self, scan=None):
85        """
86        Plot a scantable.
87        Parameters:
88            scan:   a scantable
89        Note:
90            If a scantable was specified in a previous call
91            to plot, no argument has to be given to 'replot'
92            NO checking is done that the abcissas of the scantable
93            are consistent e.g. all 'channel' or all 'velocity' etc.
94        """
95        if self._plotter.is_dead:
96            if hasattr(self._plotter.figmgr,'casabar'):
97                del self._plotter.figmgr.casabar
98            self._plotter = self._newplotter()
99            self._plotter.figmgr.casabar=self._newcasabar()
100        self._plotter.hold()
101        self._plotter.clear()
102        if not self._data and not scan:
103            msg = "Input is not a scantable"
104            raise TypeError(msg)
105        if scan: self.set_data(scan,refresh=False)
106        self._plot(self._data)
107        if self._minmaxy is not None:
108            self._plotter.set_limits(ylim=self._minmaxy)
109        if self._plotter.figmgr.casabar: self._plotter.figmgr.casabar.enable_button()
110        self._plotter.release()
111        self._plotter.tidy()
112        self._plotter.show(hardrefresh=False)
113        return
114
115    def gca(self):
116        return self._plotter.figure.gca()
117
118    def refresh(self):
119        """Do a soft refresh"""
120        self._plotter.figure.show()
121
122    def create_mask(self, nwin=1, panel=0, color=None):
123        """
124        Interactively define a mask.It retruns a mask that is equivalent to
125        the one created manually with scantable.create_mask.
126        Parameters:
127            nwin:       The number of mask windows to create interactively
128                        default is 1.
129            panel:      Which panel to use for mask selection. This is useful
130                        if different IFs are spread over panels (default 0)
131        """
132        if self._data is None:
133            return []
134        outmask = []
135        self._plotter.subplot(panel)
136        xmin, xmax = self._plotter.axes.get_xlim()
137        marg = 0.05*(xmax-xmin)
138        self._plotter.axes.set_xlim(xmin-marg, xmax+marg)
139        self.refresh()
140
141        def cleanup(lines=False, texts=False, refresh=False):
142            if lines:
143                del self._plotter.axes.lines[-1]
144            if texts:
145                del self._plotter.axes.texts[-1]
146            if refresh:
147                self.refresh()
148
149        for w in xrange(nwin):
150            wpos = []
151            self.text(0.05,1.0, "Add start boundary",
152                      coords="relative", fontsize=10)
153            point = self._plotter.get_point()
154            cleanup(texts=True)
155            if point is None:
156                continue
157            wpos.append(point[0])
158            self.axvline(wpos[0], color=color)
159            self.text(0.05,1.0, "Add end boundary", coords="relative", fontsize=10)
160            point = self._plotter.get_point()
161            cleanup(texts=True, lines=True)
162            if point is None:
163                self.refresh()
164                continue
165            wpos.append(point[0])
166            self.axvspan(wpos[0], wpos[1], alpha=0.1,
167                         edgecolor=color, facecolor=color)
168            ymin, ymax = self._plotter.axes.get_ylim()
169            outmask.append(wpos)
170
171        self._plotter.axes.set_xlim(xmin, xmax)
172        self.refresh()
173        if len(outmask) > 0:
174            return self._data.create_mask(*outmask)
175        return []
176
177    # forwards to matplotlib axes
178    def text(self, *args, **kwargs):
179        if kwargs.has_key("interactive"):
180            if kwargs.pop("interactive"):
181                pos = self._plotter.get_point()
182                args = tuple(pos)+args
183        self._axes_callback("text", *args, **kwargs)
184
185    text.__doc__ = matplotlib.axes.Axes.text.__doc__
186
187    def arrow(self, *args, **kwargs):
188        if kwargs.has_key("interactive"):
189            if kwargs.pop("interactive"):
190                pos = self._plotter.get_region()
191                dpos = (pos[0][0], pos[0][1],
192                        pos[1][0]-pos[0][0],
193                        pos[1][1] - pos[0][1])
194                args = dpos + args
195        self._axes_callback("arrow", *args, **kwargs)
196
197    arrow.__doc__ = matplotlib.axes.Axes.arrow.__doc__
198
199    def annotate(self, text, xy=None, xytext=None, **kwargs):
200        if kwargs.has_key("interactive"):
201            if kwargs.pop("interactive"):
202                xy = self._plotter.get_point()
203                xytext = self._plotter.get_point()
204        if not kwargs.has_key("arrowprops"):
205            kwargs["arrowprops"] = dict(arrowstyle="->")
206        self._axes_callback("annotate", text, xy, xytext, **kwargs)
207
208    annotate.__doc__ = matplotlib.axes.Axes.annotate.__doc__
209
210    def axvline(self, *args, **kwargs):
211        if kwargs.has_key("interactive"):
212            if kwargs.pop("interactive"):
213                pos = self._plotter.get_point()
214                args = (pos[0],)+args
215        self._axes_callback("axvline", *args, **kwargs)
216
217    axvline.__doc__ = matplotlib.axes.Axes.axvline.__doc__
218
219    def axhline(self, *args, **kwargs):
220        if kwargs.has_key("interactive"):
221            if kwargs.pop("interactive"):
222                pos = self._plotter.get_point()
223                args = (pos[1],)+args
224        self._axes_callback("axhline", *args, **kwargs)
225
226    axhline.__doc__ = matplotlib.axes.Axes.axhline.__doc__
227
228    def axvspan(self, *args, **kwargs):
229        if kwargs.has_key("interactive"):
230            if kwargs.pop("interactive"):
231                pos = self._plotter.get_region()
232                dpos = (pos[0][0], pos[1][0])
233                args = dpos + args
234        self._axes_callback("axvspan", *args, **kwargs)
235        # hack to preventy mpl from redrawing the patch
236        # it seem to convert the patch into lines on every draw.
237        # This doesn't happen in a test script???
238        #del self._plotter.axes.patches[-1]
239
240    axvspan.__doc__ = matplotlib.axes.Axes.axvspan.__doc__
241
242    def axhspan(self, *args, **kwargs):
243        if kwargs.has_key("interactive"):
244            if kwargs.pop("interactive"):
245                pos = self._plotter.get_region()
246                dpos = (pos[0][1], pos[1][1])
247                args = dpos + args
248        self._axes_callback("axhspan", *args, **kwargs)
249        # hack to preventy mpl from redrawing the patch
250        # it seem to convert the patch into lines on every draw.
251        # This doesn't happen in a test script???
252        #del self._plotter.axes.patches[-1]
253
254    axhspan.__doc__ = matplotlib.axes.Axes.axhspan.__doc__
255
256    def _axes_callback(self, axesfunc, *args, **kwargs):
257        panel = 0
258        if kwargs.has_key("panel"):
259            panel = kwargs.pop("panel")
260        coords = None
261        if kwargs.has_key("coords"):
262            coords = kwargs.pop("coords")
263            if coords.lower() == 'world':
264                kwargs["transform"] = self._plotter.axes.transData
265            elif coords.lower() == 'relative':
266                kwargs["transform"] = self._plotter.axes.transAxes
267        self._plotter.subplot(panel)
268        self._plotter.axes.set_autoscale_on(False)
269        getattr(self._plotter.axes, axesfunc)(*args, **kwargs)
270        self._plotter.show(False)
271        self._plotter.axes.set_autoscale_on(True)
272    # end matplotlib.axes fowarding functions
273
274    @asaplog_post_dec
275    def set_data(self, scan, refresh=True):
276        """
277        Set a scantable to plot.
278        Parameters:
279            scan:      a scantable
280            refresh:   True (default) or False. If True, the plot is
281                       replotted based on the new parameter setting(s).
282                       Otherwise,the parameter(s) are set without replotting.
283        Note:
284           The user specified masks and data selections will be reset
285           if a new scantable is set. This method should be called before
286           setting data selections (set_selection) and/or masks (set_mask).
287        """
288        from asap import scantable
289        if isinstance(scan, scantable):
290            if self._data is not None:
291                if scan != self._data:
292                    self._data = scan
293                    # reset
294                    self._reset()
295                    msg = "A new scantable is set to the plotter. The masks and data selections are reset."
296                    asaplog.push( msg )
297            else:
298                self._data = scan
299                self._reset()
300        else:
301            msg = "Input is not a scantable"
302            raise TypeError(msg)
303
304        # ranges become invalid when unit changes
305        if self._abcunit and self._abcunit != self._data.get_unit():
306            self._minmaxx = None
307            self._minmaxy = None
308            self._abcunit = self._data.get_unit()
309            self._datamask = None
310        if refresh: self.plot()
311
312    @asaplog_post_dec
313    def set_mode(self, stacking=None, panelling=None, refresh=True):
314        """
315        Set the plots look and feel, i.e. what you want to see on the plot.
316        Parameters:
317            stacking:     tell the plotter which variable to plot
318                          as line colour overlays (default 'pol')
319            panelling:    tell the plotter which variable to plot
320                          across multiple panels (default 'scan'
321            refresh:      True (default) or False. If True, the plot is
322                          replotted based on the new parameter setting(s).
323                          Otherwise,the parameter(s) are set without replotting.
324        Note:
325            Valid modes are:
326                 'beam' 'Beam' 'b':     Beams
327                 'if' 'IF' 'i':         IFs
328                 'pol' 'Pol' 'p':       Polarisations
329                 'scan' 'Scan' 's':     Scans
330                 'time' 'Time' 't':     Times
331        """
332        msg = "Invalid mode"
333        if not self.set_panelling(panelling) or \
334               not self.set_stacking(stacking):
335            raise TypeError(msg)
336        if refresh and self._data: self.plot(self._data)
337        return
338
339    def set_panelling(self, what=None):
340        """Set the 'panelling' mode i.e. which type of spectra should be
341        spread across different panels.
342        """
343
344        mode = what
345        if mode is None:
346             mode = rcParams['plotter.panelling']
347        md = self._translate(mode)
348        if md:
349            self._panelling = md
350            self._title = None
351            return True
352        return False
353
354    def set_layout(self,rows=None,cols=None,refresh=True):
355        """
356        Set the multi-panel layout, i.e. how many rows and columns plots
357        are visible.
358        Parameters:
359             rows:   The number of rows of plots
360             cols:   The number of columns of plots
361             refresh:  True (default) or False. If True, the plot is
362                       replotted based on the new parameter setting(s).
363                       Otherwise,the parameter(s) are set without replotting.
364        Note:
365             If no argument is given, the potter reverts to its auto-plot
366             behaviour.
367        """
368        self._rows = rows
369        self._cols = cols
370        if refresh and self._data: self.plot(self._data)
371        return
372
373    def set_stacking(self, what=None):
374        """Set the 'stacking' mode i.e. which type of spectra should be
375        overlayed.
376        """
377        mode = what
378        if mode is None:
379             mode = rcParams['plotter.stacking']
380        md = self._translate(mode)
381        if md:
382            self._stacking = md
383            self._lmap = None
384            return True
385        return False
386
387    def set_range(self,xstart=None,xend=None,ystart=None,yend=None,refresh=True):
388        """
389        Set the range of interest on the abcissa of the plot
390        Parameters:
391            [x,y]start,[x,y]end:  The start and end points of the 'zoom' window
392            refresh:  True (default) or False. If True, the plot is
393                      replotted based on the new parameter setting(s).
394                      Otherwise,the parameter(s) are set without replotting.
395        Note:
396            These become non-sensical when the unit changes.
397            use plotter.set_range() without parameters to reset
398
399        """
400        if xstart is None and xend is None:
401            self._minmaxx = None
402        else:
403            self._minmaxx = [xstart,xend]
404        if ystart is None and yend is None:
405            self._minmaxy = None
406        else:
407            self._minmaxy = [ystart,yend]
408        if refresh and self._data: self.plot(self._data)
409        return
410
411    def set_legend(self, mp=None, fontsize = None, mode = 0, refresh=True):
412        """
413        Specify a mapping for the legend instead of using the default
414        indices:
415        Parameters:
416            mp:        a list of 'strings'. This should have the same length
417                       as the number of elements on the legend and then maps
418                       to the indeces in order. It is possible to uses latex
419                       math expression. These have to be enclosed in r'',
420                       e.g. r'$x^{2}$'
421            fontsize:  The font size of the label (default None)
422            mode:      where to display the legend
423                       Any other value for loc else disables the legend:
424                        0: auto
425                        1: upper right
426                        2: upper left
427                        3: lower left
428                        4: lower right
429                        5: right
430                        6: center left
431                        7: center right
432                        8: lower center
433                        9: upper center
434                        10: center
435            refresh:    True (default) or False. If True, the plot is
436                        replotted based on the new parameter setting(s).
437                        Otherwise,the parameter(s) are set without replotting.
438
439        Example:
440             If the data has two IFs/rest frequencies with index 0 and 1
441             for CO and SiO:
442             plotter.set_stacking('i')
443             plotter.set_legend(['CO','SiO'])
444             plotter.plot()
445             plotter.set_legend([r'$^{12}CO$', r'SiO'])
446        """
447        self._lmap = mp
448        self._plotter.legend(mode)
449        if isinstance(fontsize, int):
450            from matplotlib import rc as rcp
451            rcp('legend', fontsize=fontsize)
452        if refresh and self._data: self.plot(self._data)
453        return
454
455    def set_title(self, title=None, fontsize=None, refresh=True):
456        """
457        Set the title of the plot. If multiple panels are plotted,
458        multiple titles have to be specified.
459        Parameters:
460            refresh:    True (default) or False. If True, the plot is
461                        replotted based on the new parameter setting(s).
462                        Otherwise,the parameter(s) are set without replotting.
463        Example:
464             # two panels are visible on the plotter
465             plotter.set_title(["First Panel","Second Panel"])
466        """
467        self._title = title
468        if isinstance(fontsize, int):
469            from matplotlib import rc as rcp
470            rcp('axes', titlesize=fontsize)
471        if refresh and self._data: self.plot(self._data)
472        return
473
474    def set_ordinate(self, ordinate=None, fontsize=None, refresh=True):
475        """
476        Set the y-axis label of the plot. If multiple panels are plotted,
477        multiple labels have to be specified.
478        Parameters:
479            ordinate:    a list of ordinate labels. None (default) let
480                         data determine the labels
481            refresh:     True (default) or False. If True, the plot is
482                         replotted based on the new parameter setting(s).
483                         Otherwise,the parameter(s) are set without replotting.
484        Example:
485             # two panels are visible on the plotter
486             plotter.set_ordinate(["First Y-Axis","Second Y-Axis"])
487        """
488        self._ordinate = ordinate
489        if isinstance(fontsize, int):
490            from matplotlib import rc as rcp
491            rcp('axes', labelsize=fontsize)
492            rcp('ytick', labelsize=fontsize)
493        if refresh and self._data: self.plot(self._data)
494        return
495
496    def set_abcissa(self, abcissa=None, fontsize=None, refresh=True):
497        """
498        Set the x-axis label of the plot. If multiple panels are plotted,
499        multiple labels have to be specified.
500        Parameters:
501            abcissa:     a list of abcissa labels. None (default) let
502                         data determine the labels
503            refresh:     True (default) or False. If True, the plot is
504                         replotted based on the new parameter setting(s).
505                         Otherwise,the parameter(s) are set without replotting.
506        Example:
507             # two panels are visible on the plotter
508             plotter.set_ordinate(["First X-Axis","Second X-Axis"])
509        """
510        self._abcissa = abcissa
511        if isinstance(fontsize, int):
512            from matplotlib import rc as rcp
513            rcp('axes', labelsize=fontsize)
514            rcp('xtick', labelsize=fontsize)
515        if refresh and self._data: self.plot(self._data)
516        return
517
518    def set_colors(self, colmap, refresh=True):
519        """
520        Set the colours to be used. The plotter will cycle through
521        these colours when lines are overlaid (stacking mode).
522        Parameters:
523            colmap:     a list of colour names
524            refresh:    True (default) or False. If True, the plot is
525                        replotted based on the new parameter setting(s).
526                        Otherwise,the parameter(s) are set without replotting.
527        Example:
528             plotter.set_colors("red green blue")
529             # If for example four lines are overlaid e.g I Q U V
530             # 'I' will be 'red', 'Q' will be 'green', U will be 'blue'
531             # and 'V' will be 'red' again.
532        """
533        if isinstance(colmap,str):
534            colmap = colmap.split()
535        self._plotter.palette(0, colormap=colmap)
536        if refresh and self._data: self.plot(self._data)
537
538    # alias for english speakers
539    set_colours = set_colors
540
541    def set_histogram(self, hist=True, linewidth=None, refresh=True):
542        """
543        Enable/Disable histogram-like plotting.
544        Parameters:
545            hist:        True (default) or False. The fisrt default
546                         is taken from the .asaprc setting
547                         plotter.histogram
548            refresh:     True (default) or False. If True, the plot is
549                         replotted based on the new parameter setting(s).
550                         Otherwise,the parameter(s) are set without replotting.
551        """
552        self._hist = hist
553        if isinstance(linewidth, float) or isinstance(linewidth, int):
554            from matplotlib import rc as rcp
555            rcp('lines', linewidth=linewidth)
556        if refresh and self._data: self.plot(self._data)
557
558    def set_linestyles(self, linestyles=None, linewidth=None, refresh=True):
559        """
560        Set the linestyles to be used. The plotter will cycle through
561        these linestyles when lines are overlaid (stacking mode) AND
562        only one color has been set.
563        Parameters:
564             linestyles:     a list of linestyles to use.
565                             'line', 'dashed', 'dotted', 'dashdot',
566                             'dashdotdot' and 'dashdashdot' are
567                             possible
568            refresh:         True (default) or False. If True, the plot is
569                             replotted based on the new parameter setting(s).
570                             Otherwise,the parameter(s) are set without replotting.
571        Example:
572             plotter.set_colors("black")
573             plotter.set_linestyles("line dashed dotted dashdot")
574             # If for example four lines are overlaid e.g I Q U V
575             # 'I' will be 'solid', 'Q' will be 'dashed',
576             # U will be 'dotted' and 'V' will be 'dashdot'.
577        """
578        if isinstance(linestyles,str):
579            linestyles = linestyles.split()
580        self._plotter.palette(color=0,linestyle=0,linestyles=linestyles)
581        if isinstance(linewidth, float) or isinstance(linewidth, int):
582            from matplotlib import rc as rcp
583            rcp('lines', linewidth=linewidth)
584        if refresh and self._data: self.plot(self._data)
585
586    def set_font(self, refresh=True,**kwargs):
587        """
588        Set font properties.
589        Parameters:
590            family:    one of 'sans-serif', 'serif', 'cursive', 'fantasy', 'monospace'
591            style:     one of 'normal' (or 'roman'), 'italic'  or 'oblique'
592            weight:    one of 'normal or 'bold'
593            size:      the 'general' font size, individual elements can be adjusted
594                       seperately
595            refresh:   True (default) or False. If True, the plot is
596                       replotted based on the new parameter setting(s).
597                       Otherwise,the parameter(s) are set without replotting.
598        """
599        from matplotlib import rc as rcp
600        fdict = {}
601        for k,v in kwargs.iteritems():
602            if v:
603                fdict[k] = v
604        self._fp = FontProperties(**fdict)
605        if refresh and self._data: self.plot(self._data)
606
607    def set_panellayout(self,layout=[],refresh=True):
608        """
609        Set the layout of subplots.
610        Parameters:
611            layout:   a list of subplots layout in figure coordinate (0-1),
612                      i.e., fraction of the figure width or height.
613                      The order of elements should be:
614                      [left, bottom, right, top, horizontal space btw panels,
615                      vertical space btw panels].
616            refresh:  True (default) or False. If True, the plot is
617                      replotted based on the new parameter setting(s).
618                      Otherwise,the parameter(s) are set without replotting.
619        Note
620        * When layout is not specified, the values are reset to the defaults
621          of matplotlib.
622        * If any element is set to be None, the current value is adopted.
623        """
624        if layout == []: self._panellayout=self._reset_panellayout()
625        else:
626            self._panellayout=[None]*6
627            self._panellayout[0:len(layout)]=layout
628        #print "panel layout set to ",self._panellayout
629        if refresh and self._data: self.plot(self._data)
630
631    def _reset_panellayout(self):
632        ks=map(lambda x: 'figure.subplot.'+x,
633               ['left','bottom','right','top','hspace','wspace'])
634        return map(matplotlib.rcParams.get,ks)
635
636    def plot_lines(self, linecat=None, doppler=0.0, deltachan=10, rotate=90.0,
637                   location=None):
638        """
639        Plot a line catalog.
640        Parameters:
641            linecat:      the linecatalog to plot
642            doppler:      the velocity shift to apply to the frequencies
643            deltachan:    the number of channels to include each side of the
644                          line to determine a local maximum/minimum
645            rotate:       the rotation (in degrees) )for the text label (default 90.0)
646            location:     the location of the line annotation from the 'top',
647                          'bottom' or alternate (None - the default)
648        Notes:
649        If the spectrum is flagged no line will be drawn in that location.
650        """
651        if not self._data:
652            raise RuntimeError("No scantable has been plotted yet.")
653        from asap._asap import linecatalog
654        if not isinstance(linecat, linecatalog):
655            raise ValueError("'linecat' isn't of type linecatalog.")
656        if not self._data.get_unit().endswith("Hz"):
657            raise RuntimeError("Can only overlay linecatalogs when data is in frequency.")
658        from numpy import ma
659        for j in range(len(self._plotter.subplots)):
660            self._plotter.subplot(j)
661            lims = self._plotter.axes.get_xlim()
662            for row in range(linecat.nrow()):
663                # get_frequency returns MHz
664                base = { "GHz": 1000.0, "MHz": 1.0, "Hz": 1.0e-6 }
665                restf = linecat.get_frequency(row)/base[self._data.get_unit()]
666                c = 299792.458
667                freq = restf*(1.0-doppler/c)
668                if lims[0] < freq < lims[1]:
669                    if location is None:
670                        loc = 'bottom'
671                        if row%2: loc='top'
672                    else: loc = location
673                    maxys = []
674                    for line in self._plotter.axes.lines:
675                        v = line._x
676                        asc = v[0] < v[-1]
677
678                        idx = None
679                        if not asc:
680                            if v[len(v)-1] <= freq <= v[0]:
681                                i = len(v)-1
682                                while i>=0 and v[i] < freq:
683                                    idx = i
684                                    i-=1
685                        else:
686                           if v[0] <= freq <= v[len(v)-1]:
687                                i = 0
688                                while  i<len(v) and v[i] < freq:
689                                    idx = i
690                                    i+=1
691                        if idx is not None:
692                            lower = idx - deltachan
693                            upper = idx + deltachan
694                            if lower < 0: lower = 0
695                            if upper > len(v): upper = len(v)
696                            s = slice(lower, upper)
697                            y = line._y[s]
698                            maxy = ma.maximum(y)
699                            if isinstance( maxy, float):
700                                maxys.append(maxy)
701                    if len(maxys):
702                        peak = max(maxys)
703                        if peak > self._plotter.axes.get_ylim()[1]:
704                            loc = 'bottom'
705                    else:
706                        continue
707                    self._plotter.vline_with_label(freq, peak,
708                                                   linecat.get_name(row),
709                                                   location=loc, rotate=rotate)
710        self._plotter.show(hardrefresh=False)
711
712
713    def save(self, filename=None, orientation=None, dpi=None):
714        """
715        Save the plot to a file. The know formats are 'png', 'ps', 'eps'.
716        Parameters:
717             filename:    The name of the output file. This is optional
718                          and autodetects the image format from the file
719                          suffix. If non filename is specified a file
720                          called 'yyyymmdd_hhmmss.png' is created in the
721                          current directory.
722             orientation: optional parameter for postscript only (not eps).
723                          'landscape', 'portrait' or None (default) are valid.
724                          If None is choosen for 'ps' output, the plot is
725                          automatically oriented to fill the page.
726             dpi:         The dpi of the output non-ps plot
727        """
728        self._plotter.save(filename,orientation,dpi)
729        return
730
731    @asaplog_post_dec
732    def set_mask(self, mask=None, selection=None, refresh=True):
733        """
734        Set a plotting mask for a specific polarization.
735        This is useful for masking out "noise" Pangle outside a source.
736        Parameters:
737             mask:           a mask from scantable.create_mask
738             selection:      the spectra to apply the mask to.
739             refresh:        True (default) or False. If True, the plot is
740                             replotted based on the new parameter setting(s).
741                             Otherwise,the parameter(s) are set without replotting.
742        Example:
743             select = selector()
744             select.setpolstrings("Pangle")
745             plotter.set_mask(mymask, select)
746        """
747        if not self._data:
748            msg = "Can only set mask after a first call to plot()"
749            raise RuntimeError(msg)
750        if len(mask):
751            if isinstance(mask, list) or isinstance(mask, tuple):
752                self._usermask = array(mask)
753            else:
754                self._usermask = mask
755        if mask is None and selection is None:
756            self._usermask = []
757            self._maskselection = None
758        if isinstance(selection, selector):
759            self._maskselection = {'b': selection.get_beams(),
760                                   's': selection.get_scans(),
761                                   'i': selection.get_ifs(),
762                                   'p': selection.get_pols(),
763                                   't': [] }
764        else:
765            self._maskselection = None
766        if refresh: self.plot(self._data)
767
768    def _slice_indeces(self, data):
769        mn = self._minmaxx[0]
770        mx = self._minmaxx[1]
771        asc = data[0] < data[-1]
772        start=0
773        end = len(data)-1
774        inc = 1
775        if not asc:
776            start = len(data)-1
777            end = 0
778            inc = -1
779        # find min index
780        #while start > 0 and data[start] < mn:
781        #    start+= inc
782        minind=start
783        for ind in xrange(start,end+inc,inc):
784            if data[ind] > mn: break
785            minind=ind
786        # find max index
787        #while end > 0 and data[end] > mx:
788        #    end-=inc
789        #if end > 0: end +=1
790        maxind=end
791        for ind in xrange(end,start-inc,-inc):
792            if data[ind] < mx: break
793            maxind=ind
794        start=minind
795        end=maxind
796        if start > end:
797            return end,start+1
798        elif start < end:
799            return start,end+1
800        else:
801            return start,end
802
803    def _reset(self):
804        self._usermask = []
805        self._usermaskspectra = None
806        self.set_selection(None, False)
807
808    def _plot(self, scan):
809        savesel = scan.get_selection()
810        sel = savesel +  self._selection
811        d0 = {'s': 'SCANNO', 'b': 'BEAMNO', 'i':'IFNO',
812              'p': 'POLNO', 'c': 'CYCLENO', 't' : 'TIME' }
813        order = [d0[self._panelling],d0[self._stacking]]
814        sel.set_order(order)
815        scan.set_selection(sel)
816        d = {'b': scan.getbeam, 's': scan.getscan,
817             'i': scan.getif, 'p': scan.getpol, 't': scan._gettime }
818
819        polmodes = dict(zip(self._selection.get_pols(),
820                            self._selection.get_poltypes()))
821        # this returns either a tuple of numbers or a length  (ncycles)
822        # convert this into lengths
823        n0,nstack0 = self._get_selected_n(scan)
824        if isinstance(n0, int): n = n0
825        else: n = len(n0)
826        if isinstance(nstack0, int): nstack = nstack0
827        else: nstack = len(nstack0)
828        maxpanel, maxstack = 16,16
829        if n > maxpanel or nstack > maxstack:
830            maxn = 0
831            if nstack > maxstack: maxn = maxstack
832            if n > maxpanel: maxn = maxpanel
833            msg ="Scan to be plotted contains more than %d selections.\n" \
834                  "Selecting first %d selections..." % (maxn, maxn)
835            asaplog.push(msg)
836            asaplog.post('WARN')
837            n = min(n,maxpanel)
838            nstack = min(nstack,maxstack)
839        if n > 1:
840            ganged = rcParams['plotter.ganged']
841            if self._panelling == 'i':
842                ganged = False
843            if self._rows and self._cols:
844                n = min(n,self._rows*self._cols)
845                self._plotter.set_panels(rows=self._rows,cols=self._cols,
846#                                         nplots=n,ganged=ganged)
847                                         nplots=n,layout=self._panellayout,ganged=ganged)
848            else:
849#                self._plotter.set_panels(rows=n,cols=0,nplots=n,ganged=ganged)
850                self._plotter.set_panels(rows=n,cols=0,nplots=n,layout=self._panellayout,ganged=ganged)
851        else:
852#            self._plotter.set_panels()
853            self._plotter.set_panels(layout=self._panellayout)
854        r=0
855        nr = scan.nrow()
856        a0,b0 = -1,-1
857        allxlim = []
858        allylim = []
859        newpanel=True
860        panelcount,stackcount = 0,0
861        while r < nr:
862            a = d[self._panelling](r)
863            b = d[self._stacking](r)
864            if a > a0 and panelcount < n:
865                if n > 1:
866                    self._plotter.subplot(panelcount)
867                self._plotter.palette(0)
868                #title
869                xlab = self._abcissa and self._abcissa[panelcount] \
870                       or scan._getabcissalabel()
871                ylab = self._ordinate and self._ordinate[panelcount] \
872                       or scan._get_ordinate_label()
873                self._plotter.set_axes('xlabel', xlab)
874                self._plotter.set_axes('ylabel', ylab)
875                lbl = self._get_label(scan, r, self._panelling, self._title)
876                if isinstance(lbl, list) or isinstance(lbl, tuple):
877                    if 0 <= panelcount < len(lbl):
878                        lbl = lbl[panelcount]
879                    else:
880                        # get default label
881                        lbl = self._get_label(scan, r, self._panelling, None)
882                self._plotter.set_axes('title',lbl)
883                newpanel = True
884                stackcount =0
885                panelcount += 1
886            if (b > b0 or newpanel) and stackcount < nstack:
887                y = []
888                if len(polmodes):
889                    y = scan._getspectrum(r, polmodes[scan.getpol(r)])
890                else:
891                    y = scan._getspectrum(r)
892                m = scan._getmask(r)
893                from numpy import logical_not, logical_and
894                if self._maskselection and len(self._usermask) == len(m):
895                    if d[self._stacking](r) in self._maskselection[self._stacking]:
896                        m = logical_and(m, self._usermask)
897                x = scan._getabcissa(r)
898                from numpy import ma, array
899                y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
900                if self._minmaxx is not None:
901                    s,e = self._slice_indeces(x)
902                    x = x[s:e]
903                    y = y[s:e]
904                if len(x) > 1024 and rcParams['plotter.decimate']:
905                    fac = len(x)/1024
906                    x = x[::fac]
907                    y = y[::fac]
908                llbl = self._get_label(scan, r, self._stacking, self._lmap)
909                if isinstance(llbl, list) or isinstance(llbl, tuple):
910                    if 0 <= stackcount < len(llbl):
911                        # use user label
912                        llbl = llbl[stackcount]
913                    else:
914                        # get default label
915                        llbl = self._get_label(scan, r, self._stacking, None)
916                self._plotter.set_line(label=llbl)
917                plotit = self._plotter.plot
918                if self._hist: plotit = self._plotter.hist
919                if len(x) > 0:
920                    plotit(x,y)
921                    xlim= self._minmaxx or [min(x),max(x)]
922                    allxlim += xlim
923                    ylim= self._minmaxy or [ma.minimum(y),ma.maximum(y)]
924                    allylim += ylim
925                else:
926                    xlim = self._minmaxx or []
927                    allxlim += xlim
928                    ylim= self._minmaxy or []
929                    allylim += ylim
930                stackcount += 1
931                # last in colour stack -> autoscale x
932                if stackcount == nstack and len(allxlim) > 0:
933                    allxlim.sort()
934                    self._plotter.subplots[panelcount-1]['axes'].set_xlim([allxlim[0],allxlim[-1]])
935                    # clear
936                    allxlim =[]
937
938            newpanel = False
939            a0=a
940            b0=b
941            # ignore following rows
942            if (panelcount == n) and (stackcount == nstack):
943                # last panel -> autoscale y if ganged
944                if rcParams['plotter.ganged'] and len(allylim) > 0:
945                    allylim.sort()
946                    self._plotter.set_limits(ylim=[allylim[0],allylim[-1]])
947                break
948            r+=1 # next row
949        #reset the selector to the scantable's original
950        scan.set_selection(savesel)
951
952        #temporary switch-off for older matplotlib
953        #if self._fp is not None:
954        if self._fp is not None and getattr(self._plotter.figure,'findobj',False):
955            for o in self._plotter.figure.findobj(Text):
956                o.set_fontproperties(self._fp)
957
958    def set_selection(self, selection=None, refresh=True, **kw):
959        """
960        Parameters:
961            selection:  a selector object (default unset the selection)
962            refresh:    True (default) or False. If True, the plot is
963                        replotted based on the new parameter setting(s).
964                        Otherwise,the parameter(s) are set without replotting.
965        """
966        if selection is None:
967            # reset
968            if len(kw) == 0:
969                self._selection = selector()
970            else:
971                # try keywords
972                for k in kw:
973                    if k not in selector.fields:
974                        raise KeyError("Invalid selection key '%s', valid keys are %s" % (k, selector.fields))
975                self._selection = selector(**kw)
976        elif isinstance(selection, selector):
977            self._selection = selection
978        else:
979            raise TypeError("'selection' is not of type selector")
980
981        d0 = {'s': 'SCANNO', 'b': 'BEAMNO', 'i':'IFNO',
982              'p': 'POLNO', 'c': 'CYCLENO', 't' : 'TIME' }
983        order = [d0[self._panelling],d0[self._stacking]]
984        self._selection.set_order(order)
985        if refresh and self._data: self.plot(self._data)
986
987    def _get_selected_n(self, scan):
988        d1 = {'b': scan.getbeamnos, 's': scan.getscannos,
989             'i': scan.getifnos, 'p': scan.getpolnos, 't': scan.ncycle }
990        d2 = { 'b': self._selection.get_beams(),
991               's': self._selection.get_scans(),
992               'i': self._selection.get_ifs(),
993               'p': self._selection.get_pols(),
994               't': self._selection.get_cycles() }
995        n =  d2[self._panelling] or d1[self._panelling]()
996        nstack = d2[self._stacking] or d1[self._stacking]()
997        return n,nstack
998
999    def _get_label(self, scan, row, mode, userlabel=None):
1000        if isinstance(userlabel, list) and len(userlabel) == 0:
1001            userlabel = " "
1002        pms = dict(zip(self._selection.get_pols(),self._selection.get_poltypes()))
1003        if len(pms):
1004            poleval = scan._getpollabel(scan.getpol(row),pms[scan.getpol(row)])
1005        else:
1006            poleval = scan._getpollabel(scan.getpol(row),scan.poltype())
1007        d = {'b': "Beam "+str(scan.getbeam(row)),
1008             #'s': scan._getsourcename(row),
1009             's': "Scan "+str(scan.getscan(row))+\
1010                  " ("+str(scan._getsourcename(row))+")",
1011             'i': "IF"+str(scan.getif(row)),
1012             'p': poleval,
1013             't': str(scan.get_time(row)) }
1014        return userlabel or d[mode]
1015
1016    def plotazel(self, scan=None, outfile=None):
1017    #def plotazel(self):
1018        """
1019        plot azimuth and elevation versus time of a scantable
1020        """
1021        from matplotlib import pylab as PL
1022        from matplotlib.dates import DateFormatter, timezone
1023        from matplotlib.dates import HourLocator, MinuteLocator,SecondLocator, DayLocator
1024        from matplotlib.ticker import MultipleLocator
1025        from numpy import array, pi
1026        self._data = scan
1027        self._outfile = outfile
1028        dates = self._data.get_time(asdatetime=True)
1029        t = PL.date2num(dates)
1030        tz = timezone('UTC')
1031        PL.cla()
1032        PL.ioff()
1033        PL.clf()
1034        # Adjust subplot layouts
1035        if len(self._panellayout) !=6: self.set_panellayout(refresh=False)
1036        lef, bot, rig, top, wsp, hsp = self._panellayout
1037        PL.gcf().subplots_adjust(left=lef,bottom=bot,right=rig,top=top,
1038                                 wspace=wsp,hspace=hsp)
1039
1040        tdel = max(t) - min(t)
1041        ax = PL.subplot(2,1,1)
1042        el = array(self._data.get_elevation())*180./pi
1043        PL.ylabel('El [deg.]')
1044        dstr = dates[0].strftime('%Y/%m/%d')
1045        if tdel > 1.0:
1046            dstr2 = dates[len(dates)-1].strftime('%Y/%m/%d')
1047            dstr = dstr + " - " + dstr2
1048            majloc = DayLocator()
1049            minloc = HourLocator(range(0,23,12))
1050            timefmt = DateFormatter("%b%d")
1051        elif tdel > 24./60.:
1052            timefmt = DateFormatter('%H:%M')
1053            majloc = HourLocator()
1054            minloc = MinuteLocator(30)
1055        else:
1056            timefmt = DateFormatter('%H:%M')
1057            majloc = MinuteLocator(interval=5)
1058            minloc = SecondLocator(30)
1059
1060        PL.title(dstr)
1061        if tdel == 0.0:
1062            th = (t - PL.floor(t))*24.0
1063            PL.plot(th,el,'o',markersize=2, markerfacecolor='b', markeredgecolor='b')
1064        else:
1065            PL.plot_date(t,el,'o', markersize=2, markerfacecolor='b', markeredgecolor='b',tz=tz)
1066            #ax.grid(True)
1067            ax.xaxis.set_major_formatter(timefmt)
1068            ax.xaxis.set_major_locator(majloc)
1069            ax.xaxis.set_minor_locator(minloc)
1070        ax.yaxis.grid(True)
1071        yloc = MultipleLocator(30)
1072        ax.set_ylim(0,90)
1073        ax.yaxis.set_major_locator(yloc)
1074        if tdel > 1.0:
1075            labels = ax.get_xticklabels()
1076        #    PL.setp(labels, fontsize=10, rotation=45)
1077            PL.setp(labels, fontsize=10)
1078
1079        # Az plot
1080        az = array(self._data.get_azimuth())*180./pi
1081        if min(az) < 0:
1082            for irow in range(len(az)):
1083                if az[irow] < 0: az[irow] += 360.0
1084
1085        ax2 = PL.subplot(2,1,2)
1086        #PL.xlabel('Time (UT [hour])')
1087        PL.ylabel('Az [deg.]')
1088        if tdel == 0.0:
1089            PL.plot(th,az,'o',markersize=2, markeredgecolor='b',markerfacecolor='b')
1090        else:
1091            PL.plot_date(t,az,'o', markersize=2,markeredgecolor='b',markerfacecolor='b',tz=tz)
1092            ax2.xaxis.set_major_formatter(timefmt)
1093            ax2.xaxis.set_major_locator(majloc)
1094            ax2.xaxis.set_minor_locator(minloc)
1095        #ax2.grid(True)
1096        ax2.set_ylim(0,360)
1097        ax2.yaxis.grid(True)
1098        #hfmt = DateFormatter('%H')
1099        #hloc = HourLocator()
1100        yloc = MultipleLocator(60)
1101        ax2.yaxis.set_major_locator(yloc)
1102        if tdel > 1.0:
1103            labels = ax2.get_xticklabels()
1104            PL.setp(labels, fontsize=10)
1105            PL.xlabel('Time (UT [day])')
1106        else:
1107            PL.xlabel('Time (UT [hour])')
1108
1109        PL.ion()
1110        PL.draw()
1111        if (self._outfile is not None):
1112           PL.savefig(self._outfile)
1113
1114    def plotpointing(self, scan=None, outfile=None):
1115    #def plotpointing(self):
1116        """
1117        plot telescope pointings
1118        """
1119        from matplotlib import pylab as PL
1120        from numpy import array, pi
1121        self._data = scan
1122        self._outfile = outfile
1123        dir = array(self._data.get_directionval()).transpose()
1124        ra = dir[0]*180./pi
1125        dec = dir[1]*180./pi
1126        PL.cla()
1127        #PL.ioff()
1128        PL.clf()
1129        # Adjust subplot layouts
1130        if len(self._panellayout) !=6: self.set_panellayout(refresh=False)
1131        lef, bot, rig, top, wsp, hsp = self._panellayout
1132        PL.gcf().subplots_adjust(left=lef,bottom=bot,right=rig,top=top,
1133                                 wspace=wsp,hspace=hsp)
1134        ax = PL.gca()
1135        #ax = PL.axes([0.1,0.1,0.8,0.8])
1136        #ax = PL.axes([0.1,0.1,0.8,0.8])
1137        ax.set_aspect('equal')
1138        PL.plot(ra, dec, 'b,')
1139        PL.xlabel('RA [deg.]')
1140        PL.ylabel('Declination [deg.]')
1141        PL.title('Telescope pointings')
1142        [xmin,xmax,ymin,ymax] = PL.axis()
1143        PL.axis([xmax,xmin,ymin,ymax])
1144        #PL.ion()
1145        PL.draw()
1146        if (self._outfile is not None):
1147           PL.savefig(self._outfile)
1148
1149    # plot total power data
1150    # plotting in time is not yet implemented..
1151    @asaplog_post_dec
1152    def plottp(self, scan=None, outfile=None):
1153        if self._plotter.is_dead:
1154            if hasattr(self._plotter.figmgr,'casabar'):
1155                del self._plotter.figmgr.casabar
1156            self._plotter = self._newplotter()
1157            self._plotter.figmgr.casabar=self._newcasabar()
1158        self._plotter.hold()
1159        self._plotter.clear()
1160        from asap import scantable
1161        if not self._data and not scan:
1162            msg = "Input is not a scantable"
1163            raise TypeError(msg)
1164        if isinstance(scan, scantable):
1165            if self._data is not None:
1166                if scan != self._data:
1167                    self._data = scan
1168                    # reset
1169                    self._reset()
1170            else:
1171                self._data = scan
1172                self._reset()
1173        # ranges become invalid when abcissa changes?
1174        #if self._abcunit and self._abcunit != self._data.get_unit():
1175        #    self._minmaxx = None
1176        #    self._minmaxy = None
1177        #    self._abcunit = self._data.get_unit()
1178        #    self._datamask = None
1179
1180        # Adjust subplot layouts
1181        if len(self._panellayout) !=6: self.set_panellayout(refresh=False)
1182        lef, bot, rig, top, wsp, hsp = self._panellayout
1183        self._plotter.figure.subplots_adjust(
1184            left=lef,bottom=bot,right=rig,top=top,wspace=wsp,hspace=hsp)
1185        if self._plotter.figmgr.casabar: self._plotter.figmgr.casabar.disable_button()
1186        self._plottp(self._data)
1187        if self._minmaxy is not None:
1188            self._plotter.set_limits(ylim=self._minmaxy)
1189        self._plotter.release()
1190        self._plotter.tidy()
1191        self._plotter.show(hardrefresh=False)
1192        return
1193
1194    def _plottp(self,scan):
1195        """
1196        private method for plotting total power data
1197        """
1198        from numpy import ma, array, arange, logical_not
1199        r=0
1200        nr = scan.nrow()
1201        a0,b0 = -1,-1
1202        allxlim = []
1203        allylim = []
1204        y=[]
1205        self._plotter.set_panels()
1206        self._plotter.palette(0)
1207        #title
1208        #xlab = self._abcissa and self._abcissa[panelcount] \
1209        #       or scan._getabcissalabel()
1210        #ylab = self._ordinate and self._ordinate[panelcount] \
1211        #       or scan._get_ordinate_label()
1212        xlab = self._abcissa or 'row number' #or Time
1213        ylab = self._ordinate or scan._get_ordinate_label()
1214        self._plotter.set_axes('xlabel',xlab)
1215        self._plotter.set_axes('ylabel',ylab)
1216        lbl = self._get_label(scan, r, 's', self._title)
1217        if isinstance(lbl, list) or isinstance(lbl, tuple):
1218        #    if 0 <= panelcount < len(lbl):
1219        #        lbl = lbl[panelcount]
1220        #    else:
1221                # get default label
1222             lbl = self._get_label(scan, r, self._panelling, None)
1223        self._plotter.set_axes('title',lbl)
1224        y=array(scan._get_column(scan._getspectrum,-1))
1225        m = array(scan._get_column(scan._getmask,-1))
1226        y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
1227        x = arange(len(y))
1228        # try to handle spectral data somewhat...
1229        l,m = y.shape
1230        if m > 1:
1231            y=y.mean(axis=1)
1232        plotit = self._plotter.plot
1233        llbl = self._get_label(scan, r, self._stacking, None)
1234        self._plotter.set_line(label=llbl)
1235        if len(x) > 0:
1236            plotit(x,y)
1237
1238
1239    # forwards to matplotlib.Figure.text
1240    def figtext(self, *args, **kwargs):
1241        """
1242        Add text to figure at location x,y (relative 0-1 coords).
1243        This method forwards *args and **kwargs to a Matplotlib method,
1244        matplotlib.Figure.text.
1245        See the method help for detailed information.
1246        """
1247        self._plotter.text(*args, **kwargs)
1248    # end matplotlib.Figure.text forwarding function
1249
1250
1251    # printing header information
1252    @asaplog_post_dec
1253    def print_header(self, plot=True, fontsize=9, logger=False, selstr='', extrastr=''):
1254        """
1255        print data (scantable) header on the plot and/or logger.
1256        Parameters:
1257            plot:      whether or not print header info on the plot.
1258            fontsize:  header font size (valid only plot=True)
1259            autoscale: whether or not autoscale the plot (valid only plot=True)
1260            logger:    whether or not print header info on the logger.
1261            selstr:    additional selection string (not verified)
1262            extrastr:  additional string to print (not verified)
1263        """
1264        if not plot and not logger:
1265            return
1266        if not self._data:
1267            raise RuntimeError("No scantable has been set yet.")
1268        # Now header will be printed on plot and/or logger.
1269        # Get header information and format it.
1270        ssum=self._data.__str__()
1271        # Print Observation header to the upper-left corner of plot
1272        if plot:
1273            headstr=[ssum[ssum.find('Observer:'):ssum.find('Flux Unit:')]]
1274            headstr.append(ssum[ssum.find('Beams:'):ssum.find('Observer:')]
1275                         +ssum[ssum.find('Rest Freqs:'):ssum.find('Abcissa:')])
1276            if extrastr != '': headstr[0]=extrastr+'\n'+headstr[0]
1277            #headstr[1]='Data File:     '+(filestr or 'unknown')+'\n'+headstr[1]
1278            ssel='***Selections***\n'+(selstr+self._data.get_selection().__str__() or 'none')
1279            headstr.append(ssel)
1280            nstcol=len(headstr)
1281
1282            self._plotter.hold()
1283            for i in range(nstcol):
1284                self._plotter.figure.text(0.03+float(i)/nstcol,0.98,
1285                             headstr[i],
1286                             horizontalalignment='left',
1287                             verticalalignment='top',
1288                             fontsize=fontsize)
1289            import time
1290            self._plotter.figure.text(0.99,0.0,
1291                            time.strftime("%a %d %b %Y  %H:%M:%S %Z"),
1292                            horizontalalignment='right',
1293                            verticalalignment='bottom',fontsize=8)
1294            self._plotter.release()
1295            del headstr, ssel
1296        if logger:
1297            asaplog.push("----------------\n  Plot Summary\n----------------")
1298            asaplog.push(extrastr)
1299            asaplog.push(ssum[ssum.find('Beams:'):])
1300        del ssum
Note: See TracBrowser for help on using the repository browser.