source: trunk/python/asapplotter.py @ 1986

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

New Development: No

JIRA Issue: Yes (CAS-1822/ASAP-204)

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s): asapplotter & sdplot

Description:

for got to commit this. The previous commit of casatoolbar.py depends on this code.


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