source: trunk/python/asapplotter.py @ 2011

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

New Development: No

JIRA Issue: No (a bug fix)

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs: plot 1 panel plot

Put in Release Notes: No

Module(s): asapplotter and sdplot

Description: Fixed a bug which causes Error when plotting a single panel plot.


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