source: trunk/python/asapplotter.py @ 1927

Last change on this file since 1927 was 1927, checked in by Takeshi Nakazato, 14 years ago

New Development: No

JIRA Issue: No

Ready for Test: No

Interface Changes: No

What Interface Changed: Please list interface changes

Test Programs: List test programs

Put in Release Notes: Yes/No?

Module(s): Module Names change impacts.

Description: Describe your changes here...

Fixed typo in help text.


  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 54.2 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             'r': int, '_r': int}
836
837        polmodes = dict(zip(self._selection.get_pols(),
838                            self._selection.get_poltypes()))
839        # this returns either a tuple of numbers or a length  (ncycles)
840        # convert this into lengths
841        n0,nstack0 = self._get_selected_n(scan)
842        if isinstance(n0, int): n = n0
843        else: n = len(n0)
844        if isinstance(nstack0, int): nstack = nstack0
845        else: nstack = len(nstack0)
846        nptot = n
847        maxpanel, maxstack = 16,16
848        if nstack > maxstack:
849            msg ="Scan to be overlayed contains more than %d selections.\n" \
850                  "Selecting first %d selections..." % (maxstack, maxstack)
851            asaplog.push(msg)
852            asaplog.post('WARN')
853            nstack = min(nstack,maxstack)
854        n = min(n,maxpanel)
855           
856        if n > 1:
857            ganged = rcParams['plotter.ganged']
858            if self._panelling == 'i':
859                ganged = False
860            if self._rows and self._cols:
861                n = min(n,self._rows*self._cols)
862                self._plotter.set_panels(rows=self._rows,cols=self._cols,
863#                                         nplots=n,ganged=ganged)
864                                         nplots=n,layout=self._panellayout,ganged=ganged)
865            else:
866#                self._plotter.set_panels(rows=n,cols=0,nplots=n,ganged=ganged)
867                self._plotter.set_panels(rows=n,cols=0,nplots=n,layout=self._panellayout,ganged=ganged)
868        else:
869#            self._plotter.set_panels()
870            self._plotter.set_panels(layout=self._panellayout)
871        #r = 0
872        r = self._rowcount
873        nr = scan.nrow()
874        a0,b0 = -1,-1
875        allxlim = []
876        allylim = []
877        newpanel=True
878        panelcount,stackcount = 0,0
879        while r < nr:
880            a = d[self._panelling](r)
881            b = d[self._stacking](r)
882            if a > a0 and panelcount < n:
883                if n > 1:
884                    self._plotter.subplot(panelcount)
885                self._plotter.palette(0)
886                #title
887                xlab = self._abcissa and self._abcissa[panelcount] \
888                       or scan._getabcissalabel()
889                if self._offset and not self._abcissa:
890                    xlab += " (relative)"
891                ylab = self._ordinate and self._ordinate[panelcount] \
892                       or scan._get_ordinate_label()
893                self._plotter.set_axes('xlabel', xlab)
894                self._plotter.set_axes('ylabel', ylab)
895                lbl = self._get_label(scan, r, self._panelling, self._title)
896                #if self._panelling == 'r': lbl = ''
897                if isinstance(lbl, list) or isinstance(lbl, tuple):
898                    if 0 <= panelcount < len(lbl):
899                        lbl = lbl[panelcount]
900                    else:
901                        # get default label
902                        lbl = self._get_label(scan, r, self._panelling, None)
903                self._plotter.set_axes('title',lbl)
904                newpanel = True
905                stackcount = 0
906                panelcount += 1
907            if (b > b0 or newpanel) and stackcount < nstack:
908                y = []
909                if len(polmodes):
910                    y = scan._getspectrum(r, polmodes[scan.getpol(r)])
911                else:
912                    y = scan._getspectrum(r)
913                m = scan._getmask(r)
914                from numpy import logical_not, logical_and
915                if self._maskselection and len(self._usermask) == len(m):
916                    if d[self._stacking](r) in self._maskselection[self._stacking]:
917                        m = logical_and(m, self._usermask)
918                from numpy import ma, array
919                x = array(scan._getabcissa(r))
920                if self._offset:
921                    x += self._offset
922                y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
923                if self._minmaxx is not None:
924                    s,e = self._slice_indeces(x)
925                    x = x[s:e]
926                    y = y[s:e]
927                if len(x) > 1024 and rcParams['plotter.decimate']:
928                    fac = len(x)/1024
929                    x = x[::fac]
930                    y = y[::fac]
931                llbl = self._get_label(scan, r, self._stacking, self._lmap)
932                if isinstance(llbl, list) or isinstance(llbl, tuple):
933                    if 0 <= stackcount < len(llbl):
934                        # use user label
935                        llbl = llbl[stackcount]
936                    else:
937                        # get default label
938                        llbl = self._get_label(scan, r, self._stacking, None)
939                self._plotter.set_line(label=llbl)
940                plotit = self._plotter.plot
941                if self._hist: plotit = self._plotter.hist
942                if len(x) > 0:
943                    plotit(x,y)
944                    xlim= self._minmaxx or [min(x),max(x)]
945                    allxlim += xlim
946                    ylim= self._minmaxy or [ma.minimum(y),ma.maximum(y)]
947                    allylim += ylim
948                else:
949                    xlim = self._minmaxx or []
950                    allxlim += xlim
951                    ylim= self._minmaxy or []
952                    allylim += ylim
953                stackcount += 1
954                # last in colour stack -> autoscale x
955                if stackcount == nstack and len(allxlim) > 0:
956                    allxlim.sort()
957                    self._plotter.subplots[panelcount-1]['axes'].set_xlim([allxlim[0],allxlim[-1]])
958                    # clear
959                    allxlim =[]
960
961            newpanel = False
962            a0=a
963            b0=b
964            # ignore following rows
965            if (panelcount == n) and (stackcount == nstack):
966                # last panel -> autoscale y if ganged
967                if rcParams['plotter.ganged'] and len(allylim) > 0:
968                    allylim.sort()
969                    self._plotter.set_limits(ylim=[allylim[0],allylim[-1]])
970                break
971            r+=1 # next row
972        ###-S
973        self._rowcount = r+1
974        self._panelcnt += panelcount
975        if self._plotter.figmgr.casabar:
976            if self._panelcnt >= nptot-1:
977                self._plotter.figmgr.casabar.disable_next()
978            else:
979                self._plotter.figmgr.casabar.enable_next()
980            #if self._panelcnt - panelcount > 0:
981            #    self._plotter.figmgr.casabar.enable_prev()
982            #else:
983            #    self._plotter.figmgr.casabar.disable_prev()
984        ###-E
985        #reset the selector to the scantable's original
986        scan.set_selection(savesel)
987
988        #temporary switch-off for older matplotlib
989        #if self._fp is not None:
990        if self._fp is not None and getattr(self._plotter.figure,'findobj',False):
991            for o in self._plotter.figure.findobj(Text):
992                o.set_fontproperties(self._fp)
993
994    def _get_sortstring(self, lorders):
995        d0 = {'s': 'SCANNO', 'b': 'BEAMNO', 'i':'IFNO',
996              'p': 'POLNO', 'c': 'CYCLENO', 't' : 'TIME', 'r':None, '_r':None }
997        if not (type(lorders) == list) or not (type(lorders) == tuple):
998            return None
999        if len(lorders) > 0:
1000            lsorts = []
1001            for order in lorders:
1002                ssort = d0[order]
1003                if ssort:
1004                    lsorts.append(ssort)
1005            return lsorts
1006        return None
1007
1008    def set_selection(self, selection=None, refresh=True, **kw):
1009        """
1010        Parameters:
1011            selection:  a selector object (default unset the selection)
1012            refresh:    True (default) or False. If True, the plot is
1013                        replotted based on the new parameter setting(s).
1014                        Otherwise,the parameter(s) are set without replotting.
1015        """
1016        if selection is None:
1017            # reset
1018            if len(kw) == 0:
1019                self._selection = selector()
1020            else:
1021                # try keywords
1022                for k in kw:
1023                    if k not in selector.fields:
1024                        raise KeyError("Invalid selection key '%s', valid keys are %s" % (k, selector.fields))
1025                self._selection = selector(**kw)
1026        elif isinstance(selection, selector):
1027            self._selection = selection
1028        else:
1029            raise TypeError("'selection' is not of type selector")
1030
1031        order = self._get_sortstring([self._panelling,self._stacking])
1032        if order:
1033            self._selection.set_order(order)
1034        if refresh and self._data: self.plot(self._data)
1035
1036    def _get_selected_n(self, scan):
1037        d1 = {'b': scan.getbeamnos, 's': scan.getscannos,
1038             'i': scan.getifnos, 'p': scan.getpolnos, 't': scan.ncycle,
1039             'r': scan.nrow, '_r': False}
1040        d2 = { 'b': self._selection.get_beams(),
1041               's': self._selection.get_scans(),
1042               'i': self._selection.get_ifs(),
1043               'p': self._selection.get_pols(),
1044               't': self._selection.get_cycles(),
1045               'r': False, '_r': 1}
1046        n =  d2[self._panelling] or d1[self._panelling]()
1047        nstack = d2[self._stacking] or d1[self._stacking]()
1048        return n,nstack
1049
1050    def _get_label(self, scan, row, mode, userlabel=None):
1051        if isinstance(userlabel, list) and len(userlabel) == 0:
1052            userlabel = " "
1053        pms = dict(zip(self._selection.get_pols(),self._selection.get_poltypes()))
1054        if len(pms):
1055            poleval = scan._getpollabel(scan.getpol(row),pms[scan.getpol(row)])
1056        else:
1057            poleval = scan._getpollabel(scan.getpol(row),scan.poltype())
1058        d = {'b': "Beam "+str(scan.getbeam(row)),
1059             #'s': scan._getsourcename(row),
1060             's': "Scan "+str(scan.getscan(row))+\
1061                  " ("+str(scan._getsourcename(row))+")",
1062             'i': "IF"+str(scan.getif(row)),
1063             'p': poleval,
1064             't': str(scan.get_time(row)),
1065             'r': "row "+str(row),
1066             #'_r': str(scan.get_time(row))+",\nIF"+str(scan.getif(row))+", "+poleval+", Beam"+str(scan.getbeam(row)) }
1067             '_r': "" }
1068        return userlabel or d[mode]
1069
1070    def plotazel(self, scan=None, outfile=None):
1071        """
1072        plot azimuth and elevation versus time of a scantable
1073        """
1074        visible = rcParams['plotter.gui']
1075        from matplotlib import pylab as PL
1076        from matplotlib.dates import DateFormatter, timezone
1077        from matplotlib.dates import HourLocator, MinuteLocator,SecondLocator, DayLocator
1078        from matplotlib.ticker import MultipleLocator
1079        from numpy import array, pi
1080        if not visible or not self._visible:
1081            PL.ioff()
1082            from matplotlib.backends.backend_agg import FigureCanvasAgg
1083            PL.gcf().canvas.switch_backends(FigureCanvasAgg)
1084        self._data = scan
1085        self._outfile = outfile
1086        dates = self._data.get_time(asdatetime=True)
1087        t = PL.date2num(dates)
1088        tz = timezone('UTC')
1089        PL.cla()
1090        PL.ioff()
1091        PL.clf()
1092        # Adjust subplot layouts
1093        if len(self._panellayout) != 6:
1094            self.set_panellayout(refresh=False)
1095        lef, bot, rig, top, wsp, hsp = self._panellayout
1096        PL.gcf().subplots_adjust(left=lef,bottom=bot,right=rig,top=top,
1097                                 wspace=wsp,hspace=hsp)
1098
1099        tdel = max(t) - min(t)
1100        ax = PL.subplot(2,1,1)
1101        el = array(self._data.get_elevation())*180./pi
1102        PL.ylabel('El [deg.]')
1103        dstr = dates[0].strftime('%Y/%m/%d')
1104        if tdel > 1.0:
1105            dstr2 = dates[len(dates)-1].strftime('%Y/%m/%d')
1106            dstr = dstr + " - " + dstr2
1107            majloc = DayLocator()
1108            minloc = HourLocator(range(0,23,12))
1109            timefmt = DateFormatter("%b%d")
1110        elif tdel > 24./60.:
1111            timefmt = DateFormatter('%H:%M')
1112            majloc = HourLocator()
1113            minloc = MinuteLocator(30)
1114        else:
1115            timefmt = DateFormatter('%H:%M')
1116            majloc = MinuteLocator(interval=5)
1117            minloc = SecondLocator(30)
1118
1119        PL.title(dstr)
1120        if tdel == 0.0:
1121            th = (t - PL.floor(t))*24.0
1122            PL.plot(th,el,'o',markersize=2, markerfacecolor='b', markeredgecolor='b')
1123        else:
1124            PL.plot_date(t,el,'o', markersize=2, markerfacecolor='b', markeredgecolor='b',tz=tz)
1125            #ax.grid(True)
1126            ax.xaxis.set_major_formatter(timefmt)
1127            ax.xaxis.set_major_locator(majloc)
1128            ax.xaxis.set_minor_locator(minloc)
1129        ax.yaxis.grid(True)
1130        yloc = MultipleLocator(30)
1131        ax.set_ylim(0,90)
1132        ax.yaxis.set_major_locator(yloc)
1133        if tdel > 1.0:
1134            labels = ax.get_xticklabels()
1135        #    PL.setp(labels, fontsize=10, rotation=45)
1136            PL.setp(labels, fontsize=10)
1137
1138        # Az plot
1139        az = array(self._data.get_azimuth())*180./pi
1140        if min(az) < 0:
1141            for irow in range(len(az)):
1142                if az[irow] < 0: az[irow] += 360.0
1143
1144        ax2 = PL.subplot(2,1,2)
1145        #PL.xlabel('Time (UT [hour])')
1146        PL.ylabel('Az [deg.]')
1147        if tdel == 0.0:
1148            PL.plot(th,az,'o',markersize=2, markeredgecolor='b',markerfacecolor='b')
1149        else:
1150            PL.plot_date(t,az,'o', markersize=2,markeredgecolor='b',markerfacecolor='b',tz=tz)
1151            ax2.xaxis.set_major_formatter(timefmt)
1152            ax2.xaxis.set_major_locator(majloc)
1153            ax2.xaxis.set_minor_locator(minloc)
1154        #ax2.grid(True)
1155        ax2.set_ylim(0,360)
1156        ax2.yaxis.grid(True)
1157        #hfmt = DateFormatter('%H')
1158        #hloc = HourLocator()
1159        yloc = MultipleLocator(60)
1160        ax2.yaxis.set_major_locator(yloc)
1161        if tdel > 1.0:
1162            labels = ax2.get_xticklabels()
1163            PL.setp(labels, fontsize=10)
1164            PL.xlabel('Time (UT [day])')
1165        else:
1166            PL.xlabel('Time (UT [hour])')
1167
1168        PL.ion()
1169        PL.draw()
1170        if (self._outfile is not None):
1171           PL.savefig(self._outfile)
1172
1173    def plotpointing(self, scan=None, outfile=None):
1174        """
1175        plot telescope pointings
1176        """
1177        visible = rcParams['plotter.gui']
1178        from matplotlib import pylab as PL
1179        from numpy import array, pi
1180        if not visible or not self._visible:
1181            PL.ioff()
1182            from matplotlib.backends.backend_agg import FigureCanvasAgg
1183            PL.gcf().canvas.switch_backends(FigureCanvasAgg)
1184        self._data = scan
1185        self._outfile = outfile
1186        dir = array(self._data.get_directionval()).transpose()
1187        ra = dir[0]*180./pi
1188        dec = dir[1]*180./pi
1189        PL.cla()
1190        #PL.ioff()
1191        PL.clf()
1192        # Adjust subplot layouts
1193        if len(self._panellayout) != 6:
1194            self.set_panellayout(refresh=False)
1195        lef, bot, rig, top, wsp, hsp = self._panellayout
1196        PL.gcf().subplots_adjust(left=lef,bottom=bot,right=rig,top=top,
1197                                 wspace=wsp,hspace=hsp)
1198        ax = PL.gca()
1199        #ax = PL.axes([0.1,0.1,0.8,0.8])
1200        #ax = PL.axes([0.1,0.1,0.8,0.8])
1201        ax.set_aspect('equal')
1202        PL.plot(ra, dec, 'b,')
1203        PL.xlabel('RA [deg.]')
1204        PL.ylabel('Declination [deg.]')
1205        PL.title('Telescope pointings')
1206        [xmin,xmax,ymin,ymax] = PL.axis()
1207        PL.axis([xmax,xmin,ymin,ymax])
1208        #PL.ion()
1209        PL.draw()
1210        if (self._outfile is not None):
1211           PL.savefig(self._outfile)
1212
1213    # plot total power data
1214    # plotting in time is not yet implemented..
1215    @asaplog_post_dec
1216    def plottp(self, scan=None, outfile=None):
1217        if self._plotter.is_dead:
1218            if hasattr(self._plotter.figmgr,'casabar'):
1219                del self._plotter.figmgr.casabar
1220            self._plotter = self._newplotter()
1221            self._plotter.figmgr.casabar=self._newcasabar()
1222        self._plotter.hold()
1223        self._plotter.clear()
1224        from asap import scantable
1225        if not self._data and not scan:
1226            msg = "Input is not a scantable"
1227            raise TypeError(msg)
1228        if isinstance(scan, scantable):
1229            if self._data is not None:
1230                if scan != self._data:
1231                    self._data = scan
1232                    # reset
1233                    self._reset()
1234            else:
1235                self._data = scan
1236                self._reset()
1237        # ranges become invalid when abcissa changes?
1238        #if self._abcunit and self._abcunit != self._data.get_unit():
1239        #    self._minmaxx = None
1240        #    self._minmaxy = None
1241        #    self._abcunit = self._data.get_unit()
1242        #    self._datamask = None
1243
1244        # Adjust subplot layouts
1245        if len(self._panellayout) !=6: self.set_panellayout(refresh=False)
1246        lef, bot, rig, top, wsp, hsp = self._panellayout
1247        self._plotter.figure.subplots_adjust(
1248            left=lef,bottom=bot,right=rig,top=top,wspace=wsp,hspace=hsp)
1249        if self._plotter.figmgr.casabar: self._plotter.figmgr.casabar.disable_button()
1250        self._plottp(self._data)
1251        if self._minmaxy is not None:
1252            self._plotter.set_limits(ylim=self._minmaxy)
1253        self._plotter.release()
1254        self._plotter.tidy()
1255        self._plotter.show(hardrefresh=False)
1256        return
1257
1258    def _plottp(self,scan):
1259        """
1260        private method for plotting total power data
1261        """
1262        from numpy import ma, array, arange, logical_not
1263        r=0
1264        nr = scan.nrow()
1265        a0,b0 = -1,-1
1266        allxlim = []
1267        allylim = []
1268        y=[]
1269        self._plotter.set_panels()
1270        self._plotter.palette(0)
1271        #title
1272        #xlab = self._abcissa and self._abcissa[panelcount] \
1273        #       or scan._getabcissalabel()
1274        #ylab = self._ordinate and self._ordinate[panelcount] \
1275        #       or scan._get_ordinate_label()
1276        xlab = self._abcissa or 'row number' #or Time
1277        ylab = self._ordinate or scan._get_ordinate_label()
1278        self._plotter.set_axes('xlabel',xlab)
1279        self._plotter.set_axes('ylabel',ylab)
1280        lbl = self._get_label(scan, r, 's', self._title)
1281        if isinstance(lbl, list) or isinstance(lbl, tuple):
1282        #    if 0 <= panelcount < len(lbl):
1283        #        lbl = lbl[panelcount]
1284        #    else:
1285                # get default label
1286             lbl = self._get_label(scan, r, self._panelling, None)
1287        self._plotter.set_axes('title',lbl)
1288        y=array(scan._get_column(scan._getspectrum,-1))
1289        m = array(scan._get_column(scan._getmask,-1))
1290        y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
1291        x = arange(len(y))
1292        # try to handle spectral data somewhat...
1293        l,m = y.shape
1294        if m > 1:
1295            y=y.mean(axis=1)
1296        plotit = self._plotter.plot
1297        llbl = self._get_label(scan, r, self._stacking, None)
1298        self._plotter.set_line(label=llbl)
1299        if len(x) > 0:
1300            plotit(x,y)
1301
1302
1303    # forwards to matplotlib.Figure.text
1304    def figtext(self, *args, **kwargs):
1305        """
1306        Add text to figure at location x,y (relative 0-1 coords).
1307        This method forwards *args and **kwargs to a Matplotlib method,
1308        matplotlib.Figure.text.
1309        See the method help for detailed information.
1310        """
1311        self._plotter.text(*args, **kwargs)
1312    # end matplotlib.Figure.text forwarding function
1313
1314
1315    # printing header information
1316    @asaplog_post_dec
1317    def print_header(self, plot=True, fontsize=9, logger=False, selstr='', extrastr=''):
1318        """
1319        print data (scantable) header on the plot and/or logger.
1320        Parameters:
1321            plot:      whether or not print header info on the plot.
1322            fontsize:  header font size (valid only plot=True)
1323            logger:    whether or not print header info on the logger.
1324            selstr:    additional selection string (not verified)
1325            extrastr:  additional string to print (not verified)
1326        """
1327        if not plot and not logger:
1328            return
1329        if not self._data:
1330            raise RuntimeError("No scantable has been set yet.")
1331        # Now header will be printed on plot and/or logger.
1332        # Get header information and format it.
1333        ssum=self._data.__str__()
1334        # Print Observation header to the upper-left corner of plot
1335        if plot:
1336            headstr=[ssum[ssum.find('Observer:'):ssum.find('Flux Unit:')]]
1337            headstr.append(ssum[ssum.find('Beams:'):ssum.find('Observer:')]
1338                         +ssum[ssum.find('Rest Freqs:'):ssum.find('Abcissa:')])
1339            if extrastr != '': headstr[0]=extrastr+'\n'+headstr[0]
1340            #headstr[1]='Data File:     '+(filestr or 'unknown')+'\n'+headstr[1]
1341            ssel='***Selections***\n'+(selstr+self._data.get_selection().__str__() or 'none')
1342            headstr.append(ssel)
1343            nstcol=len(headstr)
1344
1345            self._plotter.hold()
1346            for i in range(nstcol):
1347                self._plotter.figure.text(0.03+float(i)/nstcol,0.98,
1348                             headstr[i],
1349                             horizontalalignment='left',
1350                             verticalalignment='top',
1351                             fontsize=fontsize)
1352            import time
1353            self._plotter.figure.text(0.99,0.0,
1354                            time.strftime("%a %d %b %Y  %H:%M:%S %Z"),
1355                            horizontalalignment='right',
1356                            verticalalignment='bottom',fontsize=8)
1357            self._plotter.release()
1358            del headstr, ssel
1359        if logger:
1360            asaplog.push("----------------\n  Plot Summary\n----------------")
1361            asaplog.push(extrastr)
1362            asaplog.push(ssum[ssum.find('Beams:'):])
1363        del ssum
Note: See TracBrowser for help on using the repository browser.