source: branches/casa-prerelease/pre-asap/python/asapplotter.py @ 2052

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

merged a bug fix in trunk(r2051)

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