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

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

merged a bug fix in trunk(r2053)

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