source: trunk/python/asapplotter.py @ 2106

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

New Development: No

JIRA Issue: No (a minor improvement)

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs: sdplot with header = True

Put in Release Notes: No

Module(s): asapplotter, sdplot

Description:

moved time stamp a little bit so that it's clearly seen on the plot.


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