source: trunk/python/asapplotter.py @ 1995

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

New Development: No

JIRA Issue: Yes (CAS-2775)

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs: plot spectra with FLAGROW=1

Put in Release Notes: No

Module(s): asapplotter, sdplot

Description:

Proper handling of FLAGROW values in sdplot/asapplotter.
Also, proper handling of plotrange for totally flagged spectra.


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