source: trunk/python/asapplotter.py @ 2038

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

New Development: Yes

JIRA Issue: Yes (CAS-2894/ASAP-237)

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes: Yes

Module(s): asapplotter, sdplot

Description: discarded 16 panels limit when column and row numbers of subplots are set by asapplotter.set_layout.


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