source: trunk/python/asapplotter.py @ 2276

Last change on this file since 2276 was 2276, checked in by Malte Marquarding, 13 years ago

Created 3.1.0 release tag

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