source: trunk/python/asapplotter.py @ 1949

Last change on this file since 1949 was 1949, checked in by Kana Sugimoto, 13 years ago

New Development: No

JIRA Issue: No (a bug fix)

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s): asapplotter and sdplot

Description:

Fixed a bug that empty panel is created for data with short integration time (<1s).
modified asapplotter._plot to get time stamp calling scantable.get_time instead
of scantable._gettime.

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