source: trunk/python/asapplotter.py @ 1897

Last change on this file since 1897 was 1897, checked in by Malte Marquarding, 14 years ago

Ticket #202: add offset keyword to asapplotter.set_range

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