source: trunk/python/asapplotter.py @ 1858

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

Adde more API documentation

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