source: trunk/python/asapplotter.py @ 2172

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

New Development: Yes

JIRA Issue: No

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs: Interactive test with PyQt4 backend

Put in Release Notes: Yes

Module(s): asapplotter, asaplotbase, and sdplot

Description: Enabled additional toolbar, casabar, in asapplotter for Qt4Agg bacend


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